Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
sqliteicu.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2020 Philippe Weyland.
4 Copyright (C) 2022 Martin Baƙinka.
5
6 darktable is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 darktable is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with darktable. If not, see <http://www.gnu.org/licenses/>.
18*/
19/*
20** 2007 May 6
21**
22** The author disclaims copyright to this source code. In place of
23** a legal notice, here is a blessing:
24**
25** May you do good and not evil.
26** May you find forgiveness for yourself and forgive others.
27** May you share freely, never taking more than you give.
28**
29*************************************************************************
30** $Id: icu.c,v 1.7 2007/12/13 21:54:11 drh Exp $
31**
32** This file implements an integration between the ICU library
33** ("International Components for Unicode", an open-source library
34** for handling unicode data) and SQLite. The integration uses
35** ICU to provide the following to SQLite:
36**
37** * An implementation of the SQL regexp() function (and hence REGEXP
38** operator) using the ICU uregex_XX() APIs.
39**
40** * Implementations of the SQL scalar upper() and lower() functions
41** for case mapping.
42**
43** * Integration of ICU and SQLite collation sequences.
44**
45** * An implementation of the LIKE operator that uses ICU to
46** provide case-independent matching.
47*/
48
49#include "darktable.h"
50
51#if !defined(SQLITE_CORE) \
52 || defined(SQLITE_ENABLE_ICU) \
53 || defined(SQLITE_ENABLE_ICU_COLLATIONS)
54
55/* Include ICU headers */
56#include <unicode/utypes.h>
57#include <unicode/uregex.h>
58#include <unicode/ustring.h>
59#include <unicode/ucol.h>
60
61#include <assert.h>
62
63#ifndef SQLITE_CORE
64 #include "sqlite3ext.h"
65 SQLITE_EXTENSION_INIT1
66#else
67 #include "sqlite3.h"
68#endif
69
70// make travis happy
71#define SQLITE_DIRECTONLY 0x000080000
72#define SQLITE_INNOCUOUS 0x000200000
73
74/*
75** This function is called when an ICU function called from within
76** the implementation of an SQL scalar function returns an error.
77**
78** The scalar function context passed as the first argument is
79** loaded with an error message based on the following two args.
80*/
81static void icuFunctionError(
82 sqlite3_context *pCtx, /* SQLite scalar function context */
83 const char *zName, /* Name of ICU function that failed */
84 UErrorCode e /* Error code returned by ICU function */
85){
86 char zBuf[128];
87 sqlite3_snprintf(128, zBuf, "ICU error: %s(): %s", zName, u_errorName(e));
88 zBuf[127] = '\0';
89 sqlite3_result_error(pCtx, zBuf, -1);
90}
91
92#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU)
93
94/*
95** Maximum length (in bytes) of the pattern in a LIKE or GLOB
96** operator.
97*/
98#ifndef SQLITE_MAX_LIKE_PATTERN_LENGTH
99# define SQLITE_MAX_LIKE_PATTERN_LENGTH 50000
100#endif
101
102/*
103** Version of sqlite3_free() that is always a function, never a macro.
104*/
105static void xFree(void *p){
106 sqlite3_free(p);
107}
108
109/*
110** This lookup table is used to help decode the first byte of
111** a multi-byte UTF8 character. It is copied here from SQLite source
112** code file utf8.c.
113*/
114static const unsigned char icuUtf8Trans1[] = {
115 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
116 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
117 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
118 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
119 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
120 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
121 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
122 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00,
123};
124
125#define SQLITE_ICU_READ_UTF8(zIn, c) \
126 c = *(zIn++); \
127 if( c>=0xc0 ){ \
128 c = icuUtf8Trans1[c-0xc0]; \
129 while( (*zIn & 0xc0)==0x80 ){ \
130 c = (c<<6) + (0x3f & *(zIn++)); \
131 } \
132 }
133
134#define SQLITE_ICU_SKIP_UTF8(zIn) \
135 assert( *zIn ); \
136 if( *(zIn++)>=0xc0 ){ \
137 while( (*zIn & 0xc0)==0x80 ){zIn++;} \
138 }
139
140
141/*
142** Compare two UTF-8 strings for equality where the first string is
143** a "LIKE" expression. Return true (1) if they are the same and
144** false (0) if they are different.
145*/
146static int icuLikeCompare(
147 const uint8_t *zPattern, /* LIKE pattern */
148 const uint8_t *zString, /* The UTF-8 string to compare against */
149 const UChar32 uEsc /* The escape character */
150){
151 static const uint32_t MATCH_ONE = (uint32_t)'_';
152 static const uint32_t MATCH_ALL = (uint32_t)'%';
153
154 int prevEscape = 0; /* True if the previous character was uEsc */
155
156 while( 1 ){
157
158 /* Read (and consume) the next character from the input pattern. */
159 uint32_t uPattern;
160 SQLITE_ICU_READ_UTF8(zPattern, uPattern);
161 if( uPattern==0 ) break;
162
163 /* There are now 4 possibilities:
164 **
165 ** 1. uPattern is an unescaped match-all character "%",
166 ** 2. uPattern is an unescaped match-one character "_",
167 ** 3. uPattern is an unescaped escape character, or
168 ** 4. uPattern is to be handled as an ordinary character
169 */
170 if( uPattern==MATCH_ALL && !prevEscape && uPattern!=(uint32_t)uEsc ){
171 /* Case 1. */
172 uint8_t c;
173
174 /* Skip any MATCH_ALL or MATCH_ONE characters that follow a
175 ** MATCH_ALL. For each MATCH_ONE, skip one character in the
176 ** test string.
177 */
178 while( (c=*zPattern) == MATCH_ALL || c == MATCH_ONE ){
179 if( c==MATCH_ONE ){
180 if( *zString==0 ) return 0;
181 SQLITE_ICU_SKIP_UTF8(zString);
182 }
183 zPattern++;
184 }
185
186 if( *zPattern==0 ) return 1;
187
188 while( *zString ){
189 if( icuLikeCompare(zPattern, zString, uEsc) ){
190 return 1;
191 }
192 SQLITE_ICU_SKIP_UTF8(zString);
193 }
194 return 0;
195
196 }else if( uPattern==MATCH_ONE && !prevEscape && uPattern!=(uint32_t)uEsc ){
197 /* Case 2. */
198 if( *zString==0 ) return 0;
199 SQLITE_ICU_SKIP_UTF8(zString);
200
201 }else if( uPattern==(uint32_t)uEsc && !prevEscape ){
202 /* Case 3. */
203 prevEscape = 1;
204
205 }else{
206 /* Case 4. */
207 uint32_t uString;
208 SQLITE_ICU_READ_UTF8(zString, uString);
209 uString = (uint32_t)u_foldCase((UChar32)uString, U_FOLD_CASE_DEFAULT);
210 uPattern = (uint32_t)u_foldCase((UChar32)uPattern, U_FOLD_CASE_DEFAULT);
211 if( uString!=uPattern ){
212 return 0;
213 }
214 prevEscape = 0;
215 }
216 }
217
218 return *zString==0;
219}
220
221/*
222** Implementation of the like() SQL function. This function implements
223** the build-in LIKE operator. The first argument to the function is the
224** pattern and the second argument is the string. So, the SQL statements:
225**
226** A LIKE B
227**
228** is implemented as like(B, A). If there is an escape character E,
229**
230** A LIKE B ESCAPE E
231**
232** is mapped to like(B, A, E).
233*/
234static void icuLikeFunc(
235 sqlite3_context *context,
236 int argc,
237 sqlite3_value **argv
238){
239 const unsigned char *zA = sqlite3_value_text(argv[0]);
240 const unsigned char *zB = sqlite3_value_text(argv[1]);
241 UChar32 uEsc = 0;
242
243 /* Limit the length of the LIKE or GLOB pattern to avoid problems
244 ** of deep recursion and N*N behavior in patternCompare().
245 */
246 if( sqlite3_value_bytes(argv[0])>SQLITE_MAX_LIKE_PATTERN_LENGTH ){
247 sqlite3_result_error(context, "LIKE or GLOB pattern too complex", -1);
248 return;
249 }
250
251
252 if( argc==3 ){
253 /* The escape character string must consist of a single UTF-8 character.
254 ** Otherwise, return an error.
255 */
256 int nE= sqlite3_value_bytes(argv[2]);
257 const unsigned char *zE = sqlite3_value_text(argv[2]);
258 int i = 0;
259 if( zE==0 ) return;
260 U8_NEXT(zE, i, nE, uEsc);
261 if( i!=nE){
262 sqlite3_result_error(context,
263 "ESCAPE expression must be a single character", -1);
264 return;
265 }
266 }
267
268 if( zA && zB ){
269 sqlite3_result_int(context, icuLikeCompare(zA, zB, uEsc));
270 }
271}
272
273/*
274** Function to delete compiled regexp objects. Registered as
275** a destructor function with sqlite3_set_auxdata().
276*/
277static void icuRegexpDelete(void *p){
278 URegularExpression *pExpr = (URegularExpression *)p;
279 uregex_close(pExpr);
280}
281
282/*
283** Implementation of SQLite REGEXP operator. This scalar function takes
284** two arguments. The first is a regular expression pattern to compile
285** the second is a string to match against that pattern. If either
286** argument is an SQL NULL, then NULL Is returned. Otherwise, the result
287** is 1 if the string matches the pattern, or 0 otherwise.
288**
289** SQLite maps the regexp() function to the regexp() operator such
290** that the following two are equivalent:
291**
292** zString REGEXP zPattern
293** regexp(zPattern, zString)
294**
295** Uses the following ICU regexp APIs:
296**
297** uregex_open()
298** uregex_matches()
299** uregex_close()
300*/
301static void icuRegexpFunc(sqlite3_context *p, int nArg, sqlite3_value **apArg){
302 UErrorCode status = U_ZERO_ERROR;
303 URegularExpression *pExpr;
304 UBool res;
305 const UChar *zString = sqlite3_value_text16(apArg[1]);
306
307 (void)nArg; /* Unused parameter */
308
309 /* If the left hand side of the regexp operator is NULL,
310 ** then the result is also NULL.
311 */
312 if( IS_NULL_PTR(zString) ){
313 return;
314 }
315
316 pExpr = sqlite3_get_auxdata(p, 0);
317 if( IS_NULL_PTR(pExpr) ){
318 const UChar *zPattern = sqlite3_value_text16(apArg[0]);
319 if( IS_NULL_PTR(zPattern) ){
320 return;
321 }
322 pExpr = uregex_open(zPattern, -1, 0, 0, &status);
323
324 if( U_SUCCESS(status) ){
325 sqlite3_set_auxdata(p, 0, pExpr, icuRegexpDelete);
326 }else{
327 assert(!pExpr);
328 icuFunctionError(p, "uregex_open", status);
329 return;
330 }
331 }
332
333 /* Configure the text that the regular expression operates on. */
334 uregex_setText(pExpr, zString, -1, &status);
335 if( !U_SUCCESS(status) ){
336 icuFunctionError(p, "uregex_setText", status);
337 return;
338 }
339
340 /* Attempt the match */
341 res = uregex_matches(pExpr, 0, &status);
342 if( !U_SUCCESS(status) ){
343 icuFunctionError(p, "uregex_matches", status);
344 return;
345 }
346
347 /* Set the text that the regular expression operates on to a NULL
348 ** pointer. This is not really necessary, but it is tidier than
349 ** leaving the regular expression object configured with an invalid
350 ** pointer after this function returns.
351 */
352 uregex_setText(pExpr, 0, 0, &status);
353
354 /* Return 1 or 0. */
355 sqlite3_result_int(p, res ? 1 : 0);
356}
357
358/*
359** Implementations of scalar functions for case mapping - upper() and
360** lower(). Function upper() converts its input to upper-case (ABC).
361** Function lower() converts to lower-case (abc).
362**
363** ICU provides two types of case mapping, "general" case mapping and
364** "language specific". Refer to ICU documentation for the differences
365** between the two.
366**
367** To utilise "general" case mapping, the upper() or lower() scalar
368** functions are invoked with one argument:
369**
370** upper('ABC') -> 'abc'
371** lower('abc') -> 'ABC'
372**
373** To access ICU "language specific" case mapping, upper() or lower()
374** should be invoked with two arguments. The second argument is the name
375** of the locale to use. Passing an empty string ("") or SQL NULL value
376** as the second argument is the same as invoking the 1 argument version
377** of upper() or lower().
378**
379** lower('I', 'en_us') -> 'i'
380** lower('I', 'tr_tr') -> '\u131' (small dotless i)
381**
382** http://www.icu-project.org/userguide/posix.html#case_mappings
383*/
384static void icuCaseFunc16(sqlite3_context *p, int nArg, sqlite3_value **apArg){
385 const UChar *zInput; /* Pointer to input string */
386 UChar *zOutput = 0; /* Pointer to output buffer */
387 int nInput; /* Size of utf-16 input string in bytes */
388 int nOut; /* Size of output buffer in bytes */
389 int cnt;
390 int bToUpper; /* True for toupper(), false for tolower() */
391 UErrorCode status;
392 const char *zLocale = 0;
393
394 assert(nArg==1 || nArg==2);
395 bToUpper = (sqlite3_user_data(p)!=0);
396 if( nArg==2 ){
397 zLocale = (const char *)sqlite3_value_text(apArg[1]);
398 }
399
400 zInput = sqlite3_value_text16(apArg[0]);
401 if( IS_NULL_PTR(zInput) ){
402 return;
403 }
404 nOut = nInput = sqlite3_value_bytes16(apArg[0]);
405 if( nOut==0 ){
406 sqlite3_result_text16(p, "", 0, SQLITE_STATIC);
407 return;
408 }
409
410 for(cnt=0; cnt<2; cnt++){
411 UChar *zNew = sqlite3_realloc(zOutput, nOut);
412 if( zNew==0 ){
413 sqlite3_free(zOutput);
414 sqlite3_result_error_nomem(p);
415 return;
416 }
417 zOutput = zNew;
418 status = U_ZERO_ERROR;
419 if( bToUpper ){
420 nOut = 2*u_strToUpper(zOutput,nOut/2,zInput,nInput/2,zLocale,&status);
421 }else{
422 nOut = 2*u_strToLower(zOutput,nOut/2,zInput,nInput/2,zLocale,&status);
423 }
424
425 if( U_SUCCESS(status) ){
426 sqlite3_result_text16(p, zOutput, nOut, xFree);
427 }else if( status==U_BUFFER_OVERFLOW_ERROR ){
428 assert( cnt==0 );
429 continue;
430 }else{
431 icuFunctionError(p, bToUpper ? "u_strToUpper" : "u_strToLower", status);
432 }
433 return;
434 }
435 assert( 0 ); /* Unreachable */
436}
437
438#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) */
439
440/*
441** Collation sequence destructor function. The pCtx argument points to
442** a UCollator structure previously allocated using ucol_open().
443*/
444static void icuCollationDel(void *pCtx){
445 UCollator *p = (UCollator *)pCtx;
446 ucol_close(p);
447}
448
449/*
450** Collation sequence comparison function. The pCtx argument points to
451** a UCollator structure previously allocated using ucol_open().
452*/
454 void *pCtx,
455 int nLeft,
456 const void *zLeft,
457 int nRight,
458 const void *zRight
459){
460 UCollationResult res;
461 UCollator *p = (UCollator *)pCtx;
462 res = ucol_strcoll(p, (UChar *)zLeft, nLeft/2, (UChar *)zRight, nRight/2);
463 switch( res ){
464 case UCOL_LESS: return -1;
465 case UCOL_GREATER: return +1;
466 case UCOL_EQUAL: return 0;
467 }
468 assert(!"Unexpected return value from ucol_strcoll()");
469 return 0;
470}
471
472/*
473** Implementation of the scalar function icu_load_collation().
474**
475** This scalar function is used to add ICU collation based collation
476** types to an SQLite database connection. It is intended to be called
477** as follows:
478**
479** SELECT icu_load_collation(<locale>, <collation-name>);
480**
481** Where <locale> is a string containing an ICU locale identifier (i.e.
482** "en_AU", "tr_TR" etc.) and <collation-name> is the name of the
483** collation sequence to create.
484*/
486 sqlite3_context *p,
487 int nArg,
488 sqlite3_value **apArg
489){
490 sqlite3 *db = (sqlite3 *)sqlite3_user_data(p);
491 UErrorCode status = U_ZERO_ERROR;
492 const char *zLocale; /* Locale identifier - (eg. "jp_JP") */
493 const char *zName; /* SQL Collation sequence name (eg. "japanese") */
494 UCollator *pUCollator; /* ICU library collation object */
495 int rc; /* Return code from sqlite3_create_collation_x() */
496
497 assert(nArg==2);
498 (void)nArg; /* Unused parameter */
499 zLocale = (const char *)sqlite3_value_text(apArg[0]);
500 zName = (const char *)sqlite3_value_text(apArg[1]);
501
502 if( IS_NULL_PTR(zLocale) || IS_NULL_PTR(zName) ){
503 return;
504 }
505
506 pUCollator = ucol_open(zLocale, &status);
507 if( !U_SUCCESS(status) ){
508 icuFunctionError(p, "ucol_open", status);
509 return;
510 }
511 assert(p);
512
513 rc = sqlite3_create_collation_v2(db, zName, SQLITE_UTF16, (void *)pUCollator,
515 );
516 if( rc!=SQLITE_OK ){
517 ucol_close(pUCollator);
518 sqlite3_result_error(p, "Error registering collation function", -1);
519 }
520}
521
522/*
523** Register the ICU extension functions with database db.
524*/
525int sqlite3IcuInit(sqlite3 *db){
526# define SQLITEICU_EXTRAFLAGS (SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS)
527 static const struct IcuScalar {
528 const char *zName; /* Function name */
529 unsigned char nArg; /* Number of arguments */
530 unsigned int enc; /* Optimal text encoding */
531 unsigned char iContext; /* sqlite3_user_data() context */
532 void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
533 } scalars[] = {
534 {"icu_load_collation",2,SQLITE_UTF8|SQLITE_DIRECTONLY,1, icuLoadCollation},
535#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU)
536 {"regexp", 2, SQLITE_ANY|SQLITEICU_EXTRAFLAGS, 0, icuRegexpFunc},
537 {"lower", 1, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16},
538 {"lower", 2, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16},
539 {"upper", 1, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16},
540 {"upper", 2, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16},
541 {"lower", 1, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16},
542 {"lower", 2, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16},
543 {"upper", 1, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16},
544 {"upper", 2, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16},
545 {"like", 2, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuLikeFunc},
546 {"like", 3, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuLikeFunc},
547#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) */
548 };
549 int rc = SQLITE_OK;
550 int i;
551
552 for(i=0; rc==SQLITE_OK && i<(int)(sizeof(scalars)/sizeof(scalars[0])); i++){
553 const struct IcuScalar *p = &scalars[i];
554 rc = sqlite3_create_function(
555 db, p->zName, p->nArg, p->enc,
556 p->iContext ? (void*)db : (void*)0,
557 p->xFunc, 0, 0
558 );
559 }
560
561 return rc;
562}
563
564#if !SQLITE_CORE
565#ifdef _WIN32
566__declspec(dllexport)
567#endif
569 sqlite3 *db,
570 char **pzErrMsg,
571 const sqlite3_api_routines *pApi
572){
573 SQLITE_EXTENSION_INIT2(pApi)
574 return sqlite3IcuInit(db);
575}
576#endif
577
578#endif
579// clang-format off
580// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
581// vim: shiftwidth=2 expandtab tabstop=2 cindent
582// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
583// clang-format on
584
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
Definition darktable.h:281
static void icuFunctionError(sqlite3_context *pCtx, const char *zName, UErrorCode e)
Definition sqliteicu.c:81
int sqlite3IcuInit(sqlite3 *db)
Definition sqliteicu.c:525
static void icuCaseFunc16(sqlite3_context *p, int nArg, sqlite3_value **apArg)
Definition sqliteicu.c:384
static void icuLikeFunc(sqlite3_context *context, int argc, sqlite3_value **argv)
Definition sqliteicu.c:234
#define SQLITE_MAX_LIKE_PATTERN_LENGTH
Definition sqliteicu.c:99
static void xFree(void *p)
Definition sqliteicu.c:105
#define SQLITE_DIRECTONLY
Definition sqliteicu.c:71
#define SQLITEICU_EXTRAFLAGS
static int icuLikeCompare(const uint8_t *zPattern, const uint8_t *zString, const UChar32 uEsc)
Definition sqliteicu.c:146
static void icuRegexpFunc(sqlite3_context *p, int nArg, sqlite3_value **apArg)
Definition sqliteicu.c:301
int sqlite3_icu_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi)
Definition sqliteicu.c:568
#define SQLITE_ICU_SKIP_UTF8(zIn)
Definition sqliteicu.c:134
static const unsigned char icuUtf8Trans1[]
Definition sqliteicu.c:114
static void icuCollationDel(void *pCtx)
Definition sqliteicu.c:444
static void icuLoadCollation(sqlite3_context *p, int nArg, sqlite3_value **apArg)
Definition sqliteicu.c:485
static void icuRegexpDelete(void *p)
Definition sqliteicu.c:277
static int icuCollationColl(void *pCtx, int nLeft, const void *zLeft, int nRight, const void *zRight)
Definition sqliteicu.c:453
#define SQLITE_ICU_READ_UTF8(zIn, c)
Definition sqliteicu.c:125