| OLD | NEW |
| 1 /* | 1 /* |
| 2 ** 2007 June 22 | 2 ** 2007 June 22 |
| 3 ** | 3 ** |
| 4 ** The author disclaims copyright to this source code. In place of | 4 ** The author disclaims copyright to this source code. In place of |
| 5 ** a legal notice, here is a blessing: | 5 ** a legal notice, here is a blessing: |
| 6 ** | 6 ** |
| 7 ** May you do good and not evil. | 7 ** May you do good and not evil. |
| 8 ** May you find forgiveness for yourself and forgive others. | 8 ** May you find forgiveness for yourself and forgive others. |
| 9 ** May you share freely, never taking more than you give. | 9 ** May you share freely, never taking more than you give. |
| 10 ** | 10 ** |
| (...skipping 12 matching lines...) Expand all Loading... |
| 23 ** * The FTS3 module is being built into the core of | 23 ** * The FTS3 module is being built into the core of |
| 24 ** SQLite (in which case SQLITE_ENABLE_FTS3 is defined). | 24 ** SQLite (in which case SQLITE_ENABLE_FTS3 is defined). |
| 25 */ | 25 */ |
| 26 #include "fts3Int.h" | 26 #include "fts3Int.h" |
| 27 #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) | 27 #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) |
| 28 | 28 |
| 29 #include <assert.h> | 29 #include <assert.h> |
| 30 #include <string.h> | 30 #include <string.h> |
| 31 | 31 |
| 32 /* | 32 /* |
| 33 ** Return true if the two-argument version of fts3_tokenizer() |
| 34 ** has been activated via a prior call to sqlite3_db_config(db, |
| 35 ** SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, 1, 0); |
| 36 */ |
| 37 static int fts3TokenizerEnabled(sqlite3_context *context){ |
| 38 sqlite3 *db = sqlite3_context_db_handle(context); |
| 39 int isEnabled = 0; |
| 40 sqlite3_db_config(db,SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER,-1,&isEnabled); |
| 41 return isEnabled; |
| 42 } |
| 43 |
| 44 /* |
| 33 ** Implementation of the SQL scalar function for accessing the underlying | 45 ** Implementation of the SQL scalar function for accessing the underlying |
| 34 ** hash table. This function may be called as follows: | 46 ** hash table. This function may be called as follows: |
| 35 ** | 47 ** |
| 36 ** SELECT <function-name>(<key-name>); | 48 ** SELECT <function-name>(<key-name>); |
| 37 ** SELECT <function-name>(<key-name>, <pointer>); | 49 ** SELECT <function-name>(<key-name>, <pointer>); |
| 38 ** | 50 ** |
| 39 ** where <function-name> is the name passed as the second argument | 51 ** where <function-name> is the name passed as the second argument |
| 40 ** to the sqlite3Fts3InitHashTable() function (e.g. 'fts3_tokenizer'). | 52 ** to the sqlite3Fts3InitHashTable() function (e.g. 'fts3_tokenizer'). |
| 41 ** | 53 ** |
| 42 ** If the <pointer> argument is specified, it must be a blob value | 54 ** If the <pointer> argument is specified, it must be a blob value |
| 43 ** containing a pointer to be stored as the hash data corresponding | 55 ** containing a pointer to be stored as the hash data corresponding |
| 44 ** to the string <key-name>. If <pointer> is not specified, then | 56 ** to the string <key-name>. If <pointer> is not specified, then |
| 45 ** the string <key-name> must already exist in the has table. Otherwise, | 57 ** the string <key-name> must already exist in the has table. Otherwise, |
| 46 ** an error is returned. | 58 ** an error is returned. |
| 47 ** | 59 ** |
| 48 ** Whether or not the <pointer> argument is specified, the value returned | 60 ** Whether or not the <pointer> argument is specified, the value returned |
| 49 ** is a blob containing the pointer stored as the hash data corresponding | 61 ** is a blob containing the pointer stored as the hash data corresponding |
| 50 ** to string <key-name> (after the hash-table is updated, if applicable). | 62 ** to string <key-name> (after the hash-table is updated, if applicable). |
| 51 */ | 63 */ |
| 52 static void scalarFunc( | 64 static void fts3TokenizerFunc( |
| 53 sqlite3_context *context, | 65 sqlite3_context *context, |
| 54 int argc, | 66 int argc, |
| 55 sqlite3_value **argv | 67 sqlite3_value **argv |
| 56 ){ | 68 ){ |
| 57 Fts3Hash *pHash; | 69 Fts3Hash *pHash; |
| 58 void *pPtr = 0; | 70 void *pPtr = 0; |
| 59 const unsigned char *zName; | 71 const unsigned char *zName; |
| 60 int nName; | 72 int nName; |
| 61 | 73 |
| 62 assert( argc==1 || argc==2 ); | 74 assert( argc==1 || argc==2 ); |
| 63 | 75 |
| 64 pHash = (Fts3Hash *)sqlite3_user_data(context); | 76 pHash = (Fts3Hash *)sqlite3_user_data(context); |
| 65 | 77 |
| 66 zName = sqlite3_value_text(argv[0]); | 78 zName = sqlite3_value_text(argv[0]); |
| 67 nName = sqlite3_value_bytes(argv[0])+1; | 79 nName = sqlite3_value_bytes(argv[0])+1; |
| 68 | 80 |
| 69 if( argc==2 ){ | 81 if( argc==2 ){ |
| 70 void *pOld; | 82 if( fts3TokenizerEnabled(context) ){ |
| 71 int n = sqlite3_value_bytes(argv[1]); | 83 void *pOld; |
| 72 if( zName==0 || n!=sizeof(pPtr) ){ | 84 int n = sqlite3_value_bytes(argv[1]); |
| 73 sqlite3_result_error(context, "argument type mismatch", -1); | 85 if( zName==0 || n!=sizeof(pPtr) ){ |
| 74 return; | 86 sqlite3_result_error(context, "argument type mismatch", -1); |
| 75 } | 87 return; |
| 76 pPtr = *(void **)sqlite3_value_blob(argv[1]); | 88 } |
| 77 pOld = sqlite3Fts3HashInsert(pHash, (void *)zName, nName, pPtr); | 89 pPtr = *(void **)sqlite3_value_blob(argv[1]); |
| 78 if( pOld==pPtr ){ | 90 pOld = sqlite3Fts3HashInsert(pHash, (void *)zName, nName, pPtr); |
| 79 sqlite3_result_error(context, "out of memory", -1); | 91 if( pOld==pPtr ){ |
| 92 sqlite3_result_error(context, "out of memory", -1); |
| 93 } |
| 94 }else{ |
| 95 sqlite3_result_error(context, "fts3tokenize disabled", -1); |
| 80 return; | 96 return; |
| 81 } | 97 } |
| 82 }else{ | 98 }else{ |
| 83 if( zName ){ | 99 if( zName ){ |
| 84 pPtr = sqlite3Fts3HashFind(pHash, zName, nName); | 100 pPtr = sqlite3Fts3HashFind(pHash, zName, nName); |
| 85 } | 101 } |
| 86 if( !pPtr ){ | 102 if( !pPtr ){ |
| 87 char *zErr = sqlite3_mprintf("unknown tokenizer: %s", zName); | 103 char *zErr = sqlite3_mprintf("unknown tokenizer: %s", zName); |
| 88 sqlite3_result_error(context, zErr, -1); | 104 sqlite3_result_error(context, zErr, -1); |
| 89 sqlite3_free(zErr); | 105 sqlite3_free(zErr); |
| 90 return; | 106 return; |
| 91 } | 107 } |
| 92 } | 108 } |
| 93 | |
| 94 sqlite3_result_blob(context, (void *)&pPtr, sizeof(pPtr), SQLITE_TRANSIENT); | 109 sqlite3_result_blob(context, (void *)&pPtr, sizeof(pPtr), SQLITE_TRANSIENT); |
| 95 } | 110 } |
| 96 | 111 |
| 97 int sqlite3Fts3IsIdChar(char c){ | 112 int sqlite3Fts3IsIdChar(char c){ |
| 98 static const char isFtsIdChar[] = { | 113 static const char isFtsIdChar[] = { |
| 99 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x */ | 114 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x */ |
| 100 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1x */ | 115 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1x */ |
| 101 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2x */ | 116 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2x */ |
| 102 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 3x */ | 117 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 3x */ |
| 103 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 4x */ | 118 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 4x */ |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 202 sqlite3_free((void *)aArg); | 217 sqlite3_free((void *)aArg); |
| 203 } | 218 } |
| 204 | 219 |
| 205 sqlite3_free(zCopy); | 220 sqlite3_free(zCopy); |
| 206 return rc; | 221 return rc; |
| 207 } | 222 } |
| 208 | 223 |
| 209 | 224 |
| 210 #ifdef SQLITE_TEST | 225 #ifdef SQLITE_TEST |
| 211 | 226 |
| 212 #include <tcl.h> | 227 #if defined(INCLUDE_SQLITE_TCL_H) |
| 228 # include "sqlite_tcl.h" |
| 229 #else |
| 230 # include "tcl.h" |
| 231 #endif |
| 213 #include <string.h> | 232 #include <string.h> |
| 214 | 233 |
| 215 /* | 234 /* |
| 216 ** Implementation of a special SQL scalar function for testing tokenizers | 235 ** Implementation of a special SQL scalar function for testing tokenizers |
| 217 ** designed to be used in concert with the Tcl testing framework. This | 236 ** designed to be used in concert with the Tcl testing framework. This |
| 218 ** function must be called with two or more arguments: | 237 ** function must be called with two or more arguments: |
| 219 ** | 238 ** |
| 220 ** SELECT <function-name>(<key-name>, ..., <input-string>); | 239 ** SELECT <function-name>(<key-name>, ..., <input-string>); |
| 221 ** | 240 ** |
| 222 ** where <function-name> is the name passed as the second argument | 241 ** where <function-name> is the name passed as the second argument |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 343 return rc; | 362 return rc; |
| 344 } | 363 } |
| 345 | 364 |
| 346 sqlite3_bind_text(pStmt, 1, zName, -1, SQLITE_STATIC); | 365 sqlite3_bind_text(pStmt, 1, zName, -1, SQLITE_STATIC); |
| 347 sqlite3_bind_blob(pStmt, 2, &p, sizeof(p), SQLITE_STATIC); | 366 sqlite3_bind_blob(pStmt, 2, &p, sizeof(p), SQLITE_STATIC); |
| 348 sqlite3_step(pStmt); | 367 sqlite3_step(pStmt); |
| 349 | 368 |
| 350 return sqlite3_finalize(pStmt); | 369 return sqlite3_finalize(pStmt); |
| 351 } | 370 } |
| 352 | 371 |
| 372 |
| 353 static | 373 static |
| 354 int queryTokenizer( | 374 int queryTokenizer( |
| 355 sqlite3 *db, | 375 sqlite3 *db, |
| 356 char *zName, | 376 char *zName, |
| 357 const sqlite3_tokenizer_module **pp | 377 const sqlite3_tokenizer_module **pp |
| 358 ){ | 378 ){ |
| 359 int rc; | 379 int rc; |
| 360 sqlite3_stmt *pStmt; | 380 sqlite3_stmt *pStmt; |
| 361 const char zSql[] = "SELECT fts3_tokenizer(?)"; | 381 const char zSql[] = "SELECT fts3_tokenizer(?)"; |
| 362 | 382 |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 413 sqlite3Fts3SimpleTokenizerModule(&p1); | 433 sqlite3Fts3SimpleTokenizerModule(&p1); |
| 414 rc = queryTokenizer(db, "simple", &p2); | 434 rc = queryTokenizer(db, "simple", &p2); |
| 415 assert( rc==SQLITE_OK ); | 435 assert( rc==SQLITE_OK ); |
| 416 assert( p1==p2 ); | 436 assert( p1==p2 ); |
| 417 rc = queryTokenizer(db, "nosuchtokenizer", &p2); | 437 rc = queryTokenizer(db, "nosuchtokenizer", &p2); |
| 418 assert( rc==SQLITE_ERROR ); | 438 assert( rc==SQLITE_ERROR ); |
| 419 assert( p2==0 ); | 439 assert( p2==0 ); |
| 420 assert( 0==strcmp(sqlite3_errmsg(db), "unknown tokenizer: nosuchtokenizer") ); | 440 assert( 0==strcmp(sqlite3_errmsg(db), "unknown tokenizer: nosuchtokenizer") ); |
| 421 | 441 |
| 422 /* Test the storage function */ | 442 /* Test the storage function */ |
| 423 rc = registerTokenizer(db, "nosuchtokenizer", p1); | 443 if( fts3TokenizerEnabled(context) ){ |
| 424 assert( rc==SQLITE_OK ); | 444 rc = registerTokenizer(db, "nosuchtokenizer", p1); |
| 425 rc = queryTokenizer(db, "nosuchtokenizer", &p2); | 445 assert( rc==SQLITE_OK ); |
| 426 assert( rc==SQLITE_OK ); | 446 rc = queryTokenizer(db, "nosuchtokenizer", &p2); |
| 427 assert( p2==p1 ); | 447 assert( rc==SQLITE_OK ); |
| 448 assert( p2==p1 ); |
| 449 } |
| 428 | 450 |
| 429 sqlite3_result_text(context, "ok", -1, SQLITE_STATIC); | 451 sqlite3_result_text(context, "ok", -1, SQLITE_STATIC); |
| 430 } | 452 } |
| 431 | 453 |
| 432 #endif | 454 #endif |
| 433 | 455 |
| 434 /* | 456 /* |
| 435 ** Set up SQL objects in database db used to access the contents of | 457 ** Set up SQL objects in database db used to access the contents of |
| 436 ** the hash table pointed to by argument pHash. The hash table must | 458 ** the hash table pointed to by argument pHash. The hash table must |
| 437 ** been initialized to use string keys, and to take a private copy | 459 ** been initialized to use string keys, and to take a private copy |
| 438 ** of the key when a value is inserted. i.e. by a call similar to: | 460 ** of the key when a value is inserted. i.e. by a call similar to: |
| 439 ** | 461 ** |
| 440 ** sqlite3Fts3HashInit(pHash, FTS3_HASH_STRING, 1); | 462 ** sqlite3Fts3HashInit(pHash, FTS3_HASH_STRING, 1); |
| 441 ** | 463 ** |
| 442 ** This function adds a scalar function (see header comment above | 464 ** This function adds a scalar function (see header comment above |
| 443 ** scalarFunc() in this file for details) and, if ENABLE_TABLE is | 465 ** fts3TokenizerFunc() in this file for details) and, if ENABLE_TABLE is |
| 444 ** defined at compilation time, a temporary virtual table (see header | 466 ** defined at compilation time, a temporary virtual table (see header |
| 445 ** comment above struct HashTableVtab) to the database schema. Both | 467 ** comment above struct HashTableVtab) to the database schema. Both |
| 446 ** provide read/write access to the contents of *pHash. | 468 ** provide read/write access to the contents of *pHash. |
| 447 ** | 469 ** |
| 448 ** The third argument to this function, zName, is used as the name | 470 ** The third argument to this function, zName, is used as the name |
| 449 ** of both the scalar and, if created, the virtual table. | 471 ** of both the scalar and, if created, the virtual table. |
| 450 */ | 472 */ |
| 451 int sqlite3Fts3InitHashTable( | 473 int sqlite3Fts3InitHashTable( |
| 452 sqlite3 *db, | 474 sqlite3 *db, |
| 453 Fts3Hash *pHash, | 475 Fts3Hash *pHash, |
| 454 const char *zName | 476 const char *zName |
| 455 ){ | 477 ){ |
| 456 int rc = SQLITE_OK; | 478 int rc = SQLITE_OK; |
| 457 void *p = (void *)pHash; | 479 void *p = (void *)pHash; |
| 458 const int any = SQLITE_ANY; | 480 const int any = SQLITE_ANY; |
| 459 | 481 |
| 460 #ifdef SQLITE_TEST | 482 #ifdef SQLITE_TEST |
| 461 char *zTest = 0; | 483 char *zTest = 0; |
| 462 char *zTest2 = 0; | 484 char *zTest2 = 0; |
| 463 void *pdb = (void *)db; | 485 void *pdb = (void *)db; |
| 464 zTest = sqlite3_mprintf("%s_test", zName); | 486 zTest = sqlite3_mprintf("%s_test", zName); |
| 465 zTest2 = sqlite3_mprintf("%s_internal_test", zName); | 487 zTest2 = sqlite3_mprintf("%s_internal_test", zName); |
| 466 if( !zTest || !zTest2 ){ | 488 if( !zTest || !zTest2 ){ |
| 467 rc = SQLITE_NOMEM; | 489 rc = SQLITE_NOMEM; |
| 468 } | 490 } |
| 469 #endif | 491 #endif |
| 470 | 492 |
| 471 if( SQLITE_OK==rc ){ | 493 if( SQLITE_OK==rc ){ |
| 472 rc = sqlite3_create_function(db, zName, 1, any, p, scalarFunc, 0, 0); | 494 rc = sqlite3_create_function(db, zName, 1, any, p, fts3TokenizerFunc, 0, 0); |
| 473 } | 495 } |
| 474 if( SQLITE_OK==rc ){ | 496 if( SQLITE_OK==rc ){ |
| 475 rc = sqlite3_create_function(db, zName, 2, any, p, scalarFunc, 0, 0); | 497 rc = sqlite3_create_function(db, zName, 2, any, p, fts3TokenizerFunc, 0, 0); |
| 476 } | 498 } |
| 477 #ifdef SQLITE_TEST | 499 #ifdef SQLITE_TEST |
| 478 if( SQLITE_OK==rc ){ | 500 if( SQLITE_OK==rc ){ |
| 479 rc = sqlite3_create_function(db, zTest, -1, any, p, testFunc, 0, 0); | 501 rc = sqlite3_create_function(db, zTest, -1, any, p, testFunc, 0, 0); |
| 480 } | 502 } |
| 481 if( SQLITE_OK==rc ){ | 503 if( SQLITE_OK==rc ){ |
| 482 rc = sqlite3_create_function(db, zTest2, 0, any, pdb, intTestFunc, 0, 0); | 504 rc = sqlite3_create_function(db, zTest2, 0, any, pdb, intTestFunc, 0, 0); |
| 483 } | 505 } |
| 484 #endif | 506 #endif |
| 485 | 507 |
| 486 #ifdef SQLITE_TEST | 508 #ifdef SQLITE_TEST |
| 487 sqlite3_free(zTest); | 509 sqlite3_free(zTest); |
| 488 sqlite3_free(zTest2); | 510 sqlite3_free(zTest2); |
| 489 #endif | 511 #endif |
| 490 | 512 |
| 491 return rc; | 513 return rc; |
| 492 } | 514 } |
| 493 | 515 |
| 494 #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ | 516 #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ |
| OLD | NEW |