- add sources.
[platform/framework/web/crosswalk.git] / src / third_party / sqlite / src / ext / fts3 / fts3_tokenizer.c
1 /*
2 ** 2007 June 22
3 **
4 ** The author disclaims copyright to this source code.  In place of
5 ** a legal notice, here is a blessing:
6 **
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.
10 **
11 ******************************************************************************
12 **
13 ** This is part of an SQLite module implementing full-text search.
14 ** This particular file implements the generic tokenizer interface.
15 */
16
17 /*
18 ** The code in this file is only compiled if:
19 **
20 **     * The FTS3 module is being built as an extension
21 **       (in which case SQLITE_CORE is not defined), or
22 **
23 **     * The FTS3 module is being built into the core of
24 **       SQLite (in which case SQLITE_ENABLE_FTS3 is defined).
25 */
26 #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
27
28 #include "sqlite3ext.h"
29 #ifndef SQLITE_CORE
30   SQLITE_EXTENSION_INIT1
31 #endif
32
33 #include "fts3Int.h"
34 #include <assert.h>
35 #include <string.h>
36
37 /*
38 ** Implementation of the SQL scalar function for accessing the underlying 
39 ** hash table. This function may be called as follows:
40 **
41 **   SELECT <function-name>(<key-name>);
42 **   SELECT <function-name>(<key-name>, <pointer>);
43 **
44 ** where <function-name> is the name passed as the second argument
45 ** to the sqlite3Fts3InitHashTable() function (e.g. 'fts3_tokenizer').
46 **
47 ** If the <pointer> argument is specified, it must be a blob value
48 ** containing a pointer to be stored as the hash data corresponding
49 ** to the string <key-name>. If <pointer> is not specified, then
50 ** the string <key-name> must already exist in the has table. Otherwise,
51 ** an error is returned.
52 **
53 ** Whether or not the <pointer> argument is specified, the value returned
54 ** is a blob containing the pointer stored as the hash data corresponding
55 ** to string <key-name> (after the hash-table is updated, if applicable).
56 */
57 static void scalarFunc(
58   sqlite3_context *context,
59   int argc,
60   sqlite3_value **argv
61 ){
62   Fts3Hash *pHash;
63   void *pPtr = 0;
64   const unsigned char *zName;
65   int nName;
66
67   assert( argc==1 || argc==2 );
68
69   pHash = (Fts3Hash *)sqlite3_user_data(context);
70
71   zName = sqlite3_value_text(argv[0]);
72   nName = sqlite3_value_bytes(argv[0])+1;
73
74   if( argc==2 ){
75     void *pOld;
76     int n = sqlite3_value_bytes(argv[1]);
77     if( n!=sizeof(pPtr) ){
78       sqlite3_result_error(context, "argument type mismatch", -1);
79       return;
80     }
81     pPtr = *(void **)sqlite3_value_blob(argv[1]);
82     pOld = sqlite3Fts3HashInsert(pHash, (void *)zName, nName, pPtr);
83     if( pOld==pPtr ){
84       sqlite3_result_error(context, "out of memory", -1);
85       return;
86     }
87   }else{
88     pPtr = sqlite3Fts3HashFind(pHash, zName, nName);
89     if( !pPtr ){
90       char *zErr = sqlite3_mprintf("unknown tokenizer: %s", zName);
91       sqlite3_result_error(context, zErr, -1);
92       sqlite3_free(zErr);
93       return;
94     }
95   }
96
97   sqlite3_result_blob(context, (void *)&pPtr, sizeof(pPtr), SQLITE_TRANSIENT);
98 }
99
100 int sqlite3Fts3IsIdChar(char c){
101   static const char isFtsIdChar[] = {
102       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x */
103       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 1x */
104       0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 2x */
105       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,  /* 3x */
106       0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /* 4x */
107       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,  /* 5x */
108       0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /* 6x */
109       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,  /* 7x */
110   };
111   return (c&0x80 || isFtsIdChar[(int)(c)]);
112 }
113
114 const char *sqlite3Fts3NextToken(const char *zStr, int *pn){
115   const char *z1;
116   const char *z2 = 0;
117
118   /* Find the start of the next token. */
119   z1 = zStr;
120   while( z2==0 ){
121     char c = *z1;
122     switch( c ){
123       case '\0': return 0;        /* No more tokens here */
124       case '\'':
125       case '"':
126       case '`': {
127         z2 = z1;
128         while( *++z2 && (*z2!=c || *++z2==c) );
129         break;
130       }
131       case '[':
132         z2 = &z1[1];
133         while( *z2 && z2[0]!=']' ) z2++;
134         if( *z2 ) z2++;
135         break;
136
137       default:
138         if( sqlite3Fts3IsIdChar(*z1) ){
139           z2 = &z1[1];
140           while( sqlite3Fts3IsIdChar(*z2) ) z2++;
141         }else{
142           z1++;
143         }
144     }
145   }
146
147   *pn = (int)(z2-z1);
148   return z1;
149 }
150
151 int sqlite3Fts3InitTokenizer(
152   Fts3Hash *pHash,                /* Tokenizer hash table */
153   const char *zArg,               /* Tokenizer name */
154   sqlite3_tokenizer **ppTok,      /* OUT: Tokenizer (if applicable) */
155   char **pzErr                    /* OUT: Set to malloced error message */
156 ){
157   int rc;
158   char *z = (char *)zArg;
159   int n;
160   char *zCopy;
161   char *zEnd;                     /* Pointer to nul-term of zCopy */
162   sqlite3_tokenizer_module *m;
163
164   zCopy = sqlite3_mprintf("%s", zArg);
165   if( !zCopy ) return SQLITE_NOMEM;
166   zEnd = &zCopy[strlen(zCopy)];
167
168   z = (char *)sqlite3Fts3NextToken(zCopy, &n);
169   z[n] = '\0';
170   sqlite3Fts3Dequote(z);
171
172   m = (sqlite3_tokenizer_module *)sqlite3Fts3HashFind(pHash,z,(int)strlen(z)+1);
173   if( !m ){
174     *pzErr = sqlite3_mprintf("unknown tokenizer: %s", z);
175     rc = SQLITE_ERROR;
176   }else{
177     char const **aArg = 0;
178     int iArg = 0;
179     z = &z[n+1];
180     while( z<zEnd && (NULL!=(z = (char *)sqlite3Fts3NextToken(z, &n))) ){
181       int nNew = sizeof(char *)*(iArg+1);
182       char const **aNew = (const char **)sqlite3_realloc((void *)aArg, nNew);
183       if( !aNew ){
184         sqlite3_free(zCopy);
185         sqlite3_free((void *)aArg);
186         return SQLITE_NOMEM;
187       }
188       aArg = aNew;
189       aArg[iArg++] = z;
190       z[n] = '\0';
191       sqlite3Fts3Dequote(z);
192       z = &z[n+1];
193     }
194     rc = m->xCreate(iArg, aArg, ppTok);
195     assert( rc!=SQLITE_OK || *ppTok );
196     if( rc!=SQLITE_OK ){
197       *pzErr = sqlite3_mprintf("unknown tokenizer");
198     }else{
199       (*ppTok)->pModule = m; 
200     }
201     sqlite3_free((void *)aArg);
202   }
203
204   sqlite3_free(zCopy);
205   return rc;
206 }
207
208
209 #ifdef SQLITE_TEST
210
211 #include <tcl.h>
212 #include <string.h>
213
214 /*
215 ** Implementation of a special SQL scalar function for testing tokenizers 
216 ** designed to be used in concert with the Tcl testing framework. This
217 ** function must be called with two arguments:
218 **
219 **   SELECT <function-name>(<key-name>, <input-string>);
220 **   SELECT <function-name>(<key-name>, <pointer>);
221 **
222 ** where <function-name> is the name passed as the second argument
223 ** to the sqlite3Fts3InitHashTable() function (e.g. 'fts3_tokenizer')
224 ** concatenated with the string '_test' (e.g. 'fts3_tokenizer_test').
225 **
226 ** The return value is a string that may be interpreted as a Tcl
227 ** list. For each token in the <input-string>, three elements are
228 ** added to the returned list. The first is the token position, the 
229 ** second is the token text (folded, stemmed, etc.) and the third is the
230 ** substring of <input-string> associated with the token. For example, 
231 ** using the built-in "simple" tokenizer:
232 **
233 **   SELECT fts_tokenizer_test('simple', 'I don't see how');
234 **
235 ** will return the string:
236 **
237 **   "{0 i I 1 dont don't 2 see see 3 how how}"
238 **   
239 */
240 static void testFunc(
241   sqlite3_context *context,
242   int argc,
243   sqlite3_value **argv
244 ){
245   Fts3Hash *pHash;
246   sqlite3_tokenizer_module *p;
247   sqlite3_tokenizer *pTokenizer = 0;
248   sqlite3_tokenizer_cursor *pCsr = 0;
249
250   const char *zErr = 0;
251
252   const char *zName;
253   int nName;
254   const char *zInput;
255   int nInput;
256
257   const char *zArg = 0;
258
259   const char *zToken;
260   int nToken;
261   int iStart;
262   int iEnd;
263   int iPos;
264
265   Tcl_Obj *pRet;
266
267   assert( argc==2 || argc==3 );
268
269   nName = sqlite3_value_bytes(argv[0]);
270   zName = (const char *)sqlite3_value_text(argv[0]);
271   nInput = sqlite3_value_bytes(argv[argc-1]);
272   zInput = (const char *)sqlite3_value_text(argv[argc-1]);
273
274   if( argc==3 ){
275     zArg = (const char *)sqlite3_value_text(argv[1]);
276   }
277
278   pHash = (Fts3Hash *)sqlite3_user_data(context);
279   p = (sqlite3_tokenizer_module *)sqlite3Fts3HashFind(pHash, zName, nName+1);
280
281   if( !p ){
282     char *zErr = sqlite3_mprintf("unknown tokenizer: %s", zName);
283     sqlite3_result_error(context, zErr, -1);
284     sqlite3_free(zErr);
285     return;
286   }
287
288   pRet = Tcl_NewObj();
289   Tcl_IncrRefCount(pRet);
290
291   if( SQLITE_OK!=p->xCreate(zArg ? 1 : 0, &zArg, &pTokenizer) ){
292     zErr = "error in xCreate()";
293     goto finish;
294   }
295   pTokenizer->pModule = p;
296   if( SQLITE_OK!=p->xOpen(pTokenizer, zInput, nInput, &pCsr) ){
297     zErr = "error in xOpen()";
298     goto finish;
299   }
300   pCsr->pTokenizer = pTokenizer;
301
302   while( SQLITE_OK==p->xNext(pCsr, &zToken, &nToken, &iStart, &iEnd, &iPos) ){
303     Tcl_ListObjAppendElement(0, pRet, Tcl_NewIntObj(iPos));
304     Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj(zToken, nToken));
305     zToken = &zInput[iStart];
306     nToken = iEnd-iStart;
307     Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj(zToken, nToken));
308   }
309
310   if( SQLITE_OK!=p->xClose(pCsr) ){
311     zErr = "error in xClose()";
312     goto finish;
313   }
314   if( SQLITE_OK!=p->xDestroy(pTokenizer) ){
315     zErr = "error in xDestroy()";
316     goto finish;
317   }
318
319 finish:
320   if( zErr ){
321     sqlite3_result_error(context, zErr, -1);
322   }else{
323     sqlite3_result_text(context, Tcl_GetString(pRet), -1, SQLITE_TRANSIENT);
324   }
325   Tcl_DecrRefCount(pRet);
326 }
327
328 static
329 int registerTokenizer(
330   sqlite3 *db, 
331   char *zName, 
332   const sqlite3_tokenizer_module *p
333 ){
334   int rc;
335   sqlite3_stmt *pStmt;
336   const char zSql[] = "SELECT fts3_tokenizer(?, ?)";
337
338   rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
339   if( rc!=SQLITE_OK ){
340     return rc;
341   }
342
343   sqlite3_bind_text(pStmt, 1, zName, -1, SQLITE_STATIC);
344   sqlite3_bind_blob(pStmt, 2, &p, sizeof(p), SQLITE_STATIC);
345   sqlite3_step(pStmt);
346
347   return sqlite3_finalize(pStmt);
348 }
349
350 static
351 int queryTokenizer(
352   sqlite3 *db, 
353   char *zName,  
354   const sqlite3_tokenizer_module **pp
355 ){
356   int rc;
357   sqlite3_stmt *pStmt;
358   const char zSql[] = "SELECT fts3_tokenizer(?)";
359
360   *pp = 0;
361   rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
362   if( rc!=SQLITE_OK ){
363     return rc;
364   }
365
366   sqlite3_bind_text(pStmt, 1, zName, -1, SQLITE_STATIC);
367   if( SQLITE_ROW==sqlite3_step(pStmt) ){
368     if( sqlite3_column_type(pStmt, 0)==SQLITE_BLOB ){
369       memcpy((void *)pp, sqlite3_column_blob(pStmt, 0), sizeof(*pp));
370     }
371   }
372
373   return sqlite3_finalize(pStmt);
374 }
375
376 void sqlite3Fts3SimpleTokenizerModule(sqlite3_tokenizer_module const**ppModule);
377
378 /*
379 ** Implementation of the scalar function fts3_tokenizer_internal_test().
380 ** This function is used for testing only, it is not included in the
381 ** build unless SQLITE_TEST is defined.
382 **
383 ** The purpose of this is to test that the fts3_tokenizer() function
384 ** can be used as designed by the C-code in the queryTokenizer and
385 ** registerTokenizer() functions above. These two functions are repeated
386 ** in the README.tokenizer file as an example, so it is important to
387 ** test them.
388 **
389 ** To run the tests, evaluate the fts3_tokenizer_internal_test() scalar
390 ** function with no arguments. An assert() will fail if a problem is
391 ** detected. i.e.:
392 **
393 **     SELECT fts3_tokenizer_internal_test();
394 **
395 */
396 static void intTestFunc(
397   sqlite3_context *context,
398   int argc,
399   sqlite3_value **argv
400 ){
401   int rc;
402   const sqlite3_tokenizer_module *p1;
403   const sqlite3_tokenizer_module *p2;
404   sqlite3 *db = (sqlite3 *)sqlite3_user_data(context);
405
406   UNUSED_PARAMETER(argc);
407   UNUSED_PARAMETER(argv);
408
409   /* Test the query function */
410   sqlite3Fts3SimpleTokenizerModule(&p1);
411   rc = queryTokenizer(db, "simple", &p2);
412   assert( rc==SQLITE_OK );
413   assert( p1==p2 );
414   rc = queryTokenizer(db, "nosuchtokenizer", &p2);
415   assert( rc==SQLITE_ERROR );
416   assert( p2==0 );
417   assert( 0==strcmp(sqlite3_errmsg(db), "unknown tokenizer: nosuchtokenizer") );
418
419   /* Test the storage function */
420   rc = registerTokenizer(db, "nosuchtokenizer", p1);
421   assert( rc==SQLITE_OK );
422   rc = queryTokenizer(db, "nosuchtokenizer", &p2);
423   assert( rc==SQLITE_OK );
424   assert( p2==p1 );
425
426   sqlite3_result_text(context, "ok", -1, SQLITE_STATIC);
427 }
428
429 #endif
430
431 /*
432 ** Set up SQL objects in database db used to access the contents of
433 ** the hash table pointed to by argument pHash. The hash table must
434 ** been initialised to use string keys, and to take a private copy 
435 ** of the key when a value is inserted. i.e. by a call similar to:
436 **
437 **    sqlite3Fts3HashInit(pHash, FTS3_HASH_STRING, 1);
438 **
439 ** This function adds a scalar function (see header comment above
440 ** scalarFunc() in this file for details) and, if ENABLE_TABLE is
441 ** defined at compilation time, a temporary virtual table (see header 
442 ** comment above struct HashTableVtab) to the database schema. Both 
443 ** provide read/write access to the contents of *pHash.
444 **
445 ** The third argument to this function, zName, is used as the name
446 ** of both the scalar and, if created, the virtual table.
447 */
448 int sqlite3Fts3InitHashTable(
449   sqlite3 *db, 
450   Fts3Hash *pHash, 
451   const char *zName
452 ){
453   int rc = SQLITE_OK;
454   void *p = (void *)pHash;
455   const int any = SQLITE_ANY;
456
457 #ifdef SQLITE_TEST
458   char *zTest = 0;
459   char *zTest2 = 0;
460   void *pdb = (void *)db;
461   zTest = sqlite3_mprintf("%s_test", zName);
462   zTest2 = sqlite3_mprintf("%s_internal_test", zName);
463   if( !zTest || !zTest2 ){
464     rc = SQLITE_NOMEM;
465   }
466 #endif
467
468   if( SQLITE_OK==rc ){
469     rc = sqlite3_create_function(db, zName, 1, any, p, scalarFunc, 0, 0);
470   }
471   if( SQLITE_OK==rc ){
472     rc = sqlite3_create_function(db, zName, 2, any, p, scalarFunc, 0, 0);
473   }
474 #ifdef SQLITE_TEST
475   if( SQLITE_OK==rc ){
476     rc = sqlite3_create_function(db, zTest, 2, any, p, testFunc, 0, 0);
477   }
478   if( SQLITE_OK==rc ){
479     rc = sqlite3_create_function(db, zTest, 3, any, p, testFunc, 0, 0);
480   }
481   if( SQLITE_OK==rc ){
482     rc = sqlite3_create_function(db, zTest2, 0, any, pdb, intTestFunc, 0, 0);
483   }
484 #endif
485
486 #ifdef SQLITE_TEST
487   sqlite3_free(zTest);
488   sqlite3_free(zTest2);
489 #endif
490
491   return rc;
492 }
493
494 #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */