4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing:
7 ** May you do good and not evil.
8 ** May you find forgiveness for yourself and forgive others.
9 ** May you share freely, never taking more than you give.
11 ******************************************************************************
13 ** This file contains code to implement the next_char(A,T,F,W,C) SQL function.
15 ** The next_char(A,T,F,W,C) function finds all valid "next" characters for
16 ** string A given the vocabulary in T.F. If the W value exists and is a
17 ** non-empty string, then it is an SQL expression that limits the entries
18 ** in T.F that will be considered. If C exists and is a non-empty string,
19 ** then it is the name of the collating sequence to use for comparison. If
21 ** Only the first three arguments are required. If the C parameter is
22 ** omitted or is NULL or is an empty string, then the default collating
23 ** sequence of T.F is used for comparision. If the W parameter is omitted
24 ** or is NULL or is an empty string, then no filtering of the output is
27 ** The T.F column should be indexed using collation C or else this routine
28 ** will be quite slow.
30 ** For example, suppose an application has a dictionary like this:
32 ** CREATE TABLE dictionary(word TEXT UNIQUE);
34 ** Further suppose that for user keypad entry, it is desired to disable
35 ** (gray out) keys that are not valid as the next character. If the
36 ** the user has previously entered (say) 'cha' then to find all allowed
37 ** next characters (and thereby determine when keys should not be grayed
38 ** out) run the following query:
40 ** SELECT next_char('cha','dictionary','word');
42 ** IMPLEMENTATION NOTES:
44 ** The next_char function is implemented using recursive SQL that makes
45 ** use of the table name and column name as part of a query. If either
46 ** the table name or column name are keywords or contain special characters,
47 ** then they should be escaped. For example:
49 ** SELECT next_char('cha','[dictionary]','[word]');
51 ** This also means that the table name can be a subquery:
53 ** SELECT next_char('cha','(SELECT word AS w FROM dictionary)','w');
55 #include "sqlite3ext.h"
56 SQLITE_EXTENSION_INIT1
60 ** A structure to hold context of the next_char() computation across
61 ** nested function calls.
63 typedef struct nextCharContext nextCharContext
;
64 struct nextCharContext
{
65 sqlite3
*db
; /* Database connection */
66 sqlite3_stmt
*pStmt
; /* Prepared statement used to query */
67 const unsigned char *zPrefix
; /* Prefix to scan */
68 int nPrefix
; /* Size of zPrefix in bytes */
69 int nAlloc
; /* Space allocated to aResult */
70 int nUsed
; /* Space used in aResult */
71 unsigned int *aResult
; /* Array of next characters */
72 int mallocFailed
; /* True if malloc fails */
73 int otherError
; /* True for any other failure */
77 ** Append a result character if the character is not already in the
80 static void nextCharAppend(nextCharContext
*p
, unsigned c
){
82 for(i
=0; i
<p
->nUsed
; i
++){
83 if( p
->aResult
[i
]==c
) return;
85 if( p
->nUsed
+1 > p
->nAlloc
){
87 int n
= p
->nAlloc
*2 + 30;
88 aNew
= sqlite3_realloc(p
->aResult
, n
*sizeof(unsigned int));
97 p
->aResult
[p
->nUsed
++] = c
;
101 ** Write a character into z[] as UTF8. Return the number of bytes needed
102 ** to hold the character
104 static int writeUtf8(unsigned char *z
, unsigned c
){
106 z
[0] = (unsigned char)(c
&0xff);
110 z
[0] = 0xC0 + (unsigned char)((c
>>6)&0x1F);
111 z
[1] = 0x80 + (unsigned char)(c
& 0x3F);
115 z
[0] = 0xE0 + (unsigned char)((c
>>12)&0x0F);
116 z
[1] = 0x80 + (unsigned char)((c
>>6) & 0x3F);
117 z
[2] = 0x80 + (unsigned char)(c
& 0x3F);
120 z
[0] = 0xF0 + (unsigned char)((c
>>18) & 0x07);
121 z
[1] = 0x80 + (unsigned char)((c
>>12) & 0x3F);
122 z
[2] = 0x80 + (unsigned char)((c
>>6) & 0x3F);
123 z
[3] = 0x80 + (unsigned char)(c
& 0x3F);
128 ** Read a UTF8 character out of z[] and write it into *pOut. Return
129 ** the number of bytes in z[] that were used to construct the character.
131 static int readUtf8(const unsigned char *z
, unsigned *pOut
){
132 static const unsigned char validBits
[] = {
133 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
134 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
135 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
136 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
137 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
138 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
139 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
140 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00,
148 c
= validBits
[c
-0xc0];
149 while( (z
[n
] & 0xc0)==0x80 ){
150 c
= (c
<<6) + (0x3f & z
[n
++]);
152 if( c
<0x80 || (c
&0xFFFFF800)==0xD800 || (c
&0xFFFFFFFE)==0xFFFE ){
161 ** The nextCharContext structure has been set up. Add all "next" characters
162 ** to the result set.
164 static void findNextChars(nextCharContext
*p
){
166 unsigned char zPrev
[8];
170 sqlite3_bind_text(p
->pStmt
, 1, (char*)p
->zPrefix
, p
->nPrefix
,
172 n
= writeUtf8(zPrev
, cPrev
+1);
173 sqlite3_bind_text(p
->pStmt
, 2, (char*)zPrev
, n
, SQLITE_STATIC
);
174 rc
= sqlite3_step(p
->pStmt
);
175 if( rc
==SQLITE_DONE
){
176 sqlite3_reset(p
->pStmt
);
178 }else if( rc
!=SQLITE_ROW
){
182 const unsigned char *zOut
= sqlite3_column_text(p
->pStmt
, 0);
184 n
= readUtf8(zOut
+p
->nPrefix
, &cNext
);
185 sqlite3_reset(p
->pStmt
);
186 nextCharAppend(p
, cNext
);
188 if( p
->mallocFailed
) return;
195 ** next_character(A,T,F,W)
197 ** Return a string composted of all next possible characters after
198 ** A for elements of T.F. If W is supplied, then it is an SQL expression
199 ** that limits the elements in T.F that are considered.
201 static void nextCharFunc(
202 sqlite3_context
*context
,
207 const unsigned char *zTable
= sqlite3_value_text(argv
[1]);
208 const unsigned char *zField
= sqlite3_value_text(argv
[2]);
209 const unsigned char *zWhere
;
210 const unsigned char *zCollName
;
211 char *zWhereClause
= 0;
216 memset(&c
, 0, sizeof(c
));
217 c
.db
= sqlite3_context_db_handle(context
);
218 c
.zPrefix
= sqlite3_value_text(argv
[0]);
219 c
.nPrefix
= sqlite3_value_bytes(argv
[0]);
220 if( zTable
==0 || zField
==0 || c
.zPrefix
==0 ) return;
222 && (zWhere
= sqlite3_value_text(argv
[3]))!=0
225 zWhereClause
= sqlite3_mprintf("AND (%s)", zWhere
);
226 if( zWhereClause
==0 ){
227 sqlite3_result_error_nomem(context
);
234 && (zCollName
= sqlite3_value_text(argv
[4]))!=0
237 zColl
= sqlite3_mprintf("collate \"%w\"", zCollName
);
239 sqlite3_result_error_nomem(context
);
240 if( zWhereClause
[0] ) sqlite3_free(zWhereClause
);
246 zSql
= sqlite3_mprintf(
248 " WHERE %s>=(?1 || ?2) %s"
249 " AND %s<=(?1 || char(1114111)) %s" /* 1114111 == 0x10ffff */
251 " ORDER BY 1 %s ASC LIMIT 1",
252 zField
, zTable
, zField
, zColl
, zField
, zColl
, zWhereClause
, zColl
254 if( zWhereClause
[0] ) sqlite3_free(zWhereClause
);
255 if( zColl
[0] ) sqlite3_free(zColl
);
257 sqlite3_result_error_nomem(context
);
261 rc
= sqlite3_prepare_v2(c
.db
, zSql
, -1, &c
.pStmt
, 0);
264 sqlite3_result_error(context
, sqlite3_errmsg(c
.db
), -1);
268 if( c
.mallocFailed
){
269 sqlite3_result_error_nomem(context
);
272 pRes
= sqlite3_malloc( c
.nUsed
*4 + 1 );
274 sqlite3_result_error_nomem(context
);
278 for(i
=0; i
<c
.nUsed
; i
++){
279 n
+= writeUtf8(pRes
+n
, c
.aResult
[i
]);
282 sqlite3_result_text(context
, (const char*)pRes
, n
, sqlite3_free
);
285 sqlite3_finalize(c
.pStmt
);
286 sqlite3_free(c
.aResult
);
290 __declspec(dllexport
)
292 int sqlite3_nextchar_init(
295 const sqlite3_api_routines
*pApi
298 SQLITE_EXTENSION_INIT2(pApi
);
299 (void)pzErrMsg
; /* Unused parameter */
300 rc
= sqlite3_create_function(db
, "next_char", 3, SQLITE_UTF8
, 0,
303 rc
= sqlite3_create_function(db
, "next_char", 4, SQLITE_UTF8
, 0,
307 rc
= sqlite3_create_function(db
, "next_char", 5, SQLITE_UTF8
, 0,