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