| | @@ -1,8 +1,8 @@ |
| 1 | 1 | /****************************************************************************** |
| 2 | 2 | ** This file is an amalgamation of many separate C source files from SQLite |
| 3 | | -** version 3.10.0. By combining all the individual C code files into this |
| 3 | +** version 3.11.0. By combining all the individual C code files into this |
| 4 | 4 | ** single large file, the entire code can be compiled as a single translation |
| 5 | 5 | ** unit. This allows many compilers to do optimizations that would not be |
| 6 | 6 | ** possible if the files were compiled separately. Performance improvements |
| 7 | 7 | ** of 5% or more are commonly seen when SQLite is compiled as a single |
| 8 | 8 | ** translation unit. |
| | @@ -119,10 +119,12 @@ |
| 119 | 119 | #define SQLITE_ENABLE_LOCKING_STYLE 0 |
| 120 | 120 | #define HAVE_UTIME 1 |
| 121 | 121 | #else |
| 122 | 122 | /* This is not VxWorks. */ |
| 123 | 123 | #define OS_VXWORKS 0 |
| 124 | +#define HAVE_FCHOWN 1 |
| 125 | +#define HAVE_READLINK 1 |
| 124 | 126 | #endif /* defined(_WRS_KERNEL) */ |
| 125 | 127 | |
| 126 | 128 | /************** End of vxworks.h *********************************************/ |
| 127 | 129 | /************** Continuing where we left off in sqliteInt.h ******************/ |
| 128 | 130 | |
| | @@ -323,13 +325,13 @@ |
| 323 | 325 | ** |
| 324 | 326 | ** See also: [sqlite3_libversion()], |
| 325 | 327 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 326 | 328 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 327 | 329 | */ |
| 328 | | -#define SQLITE_VERSION "3.10.0" |
| 329 | | -#define SQLITE_VERSION_NUMBER 3010000 |
| 330 | | -#define SQLITE_SOURCE_ID "2016-01-06 11:01:07 fd0a50f0797d154fefff724624f00548b5320566" |
| 330 | +#define SQLITE_VERSION "3.11.0" |
| 331 | +#define SQLITE_VERSION_NUMBER 3011000 |
| 332 | +#define SQLITE_SOURCE_ID "2016-01-20 14:22:41 204432ee72fda8e82d244c4aa18de7ec4811b8e1" |
| 331 | 333 | |
| 332 | 334 | /* |
| 333 | 335 | ** CAPI3REF: Run-Time Library Version Numbers |
| 334 | 336 | ** KEYWORDS: sqlite3_version, sqlite3_sourceid |
| 335 | 337 | ** |
| | @@ -1006,12 +1008,17 @@ |
| 1006 | 1008 | ** improve performance on some systems. |
| 1007 | 1009 | ** |
| 1008 | 1010 | ** <li>[[SQLITE_FCNTL_FILE_POINTER]] |
| 1009 | 1011 | ** The [SQLITE_FCNTL_FILE_POINTER] opcode is used to obtain a pointer |
| 1010 | 1012 | ** to the [sqlite3_file] object associated with a particular database |
| 1011 | | -** connection. See the [sqlite3_file_control()] documentation for |
| 1012 | | -** additional information. |
| 1013 | +** connection. See also [SQLITE_FCNTL_JOURNAL_POINTER]. |
| 1014 | +** |
| 1015 | +** <li>[[SQLITE_FCNTL_JOURNAL_POINTER]] |
| 1016 | +** The [SQLITE_FCNTL_JOURNAL_POINTER] opcode is used to obtain a pointer |
| 1017 | +** to the [sqlite3_file] object associated with the journal file (either |
| 1018 | +** the [rollback journal] or the [write-ahead log]) for a particular database |
| 1019 | +** connection. See also [SQLITE_FCNTL_FILE_POINTER]. |
| 1013 | 1020 | ** |
| 1014 | 1021 | ** <li>[[SQLITE_FCNTL_SYNC_OMITTED]] |
| 1015 | 1022 | ** No longer in use. |
| 1016 | 1023 | ** |
| 1017 | 1024 | ** <li>[[SQLITE_FCNTL_SYNC]] |
| | @@ -1222,10 +1229,11 @@ |
| 1222 | 1229 | #define SQLITE_FCNTL_WIN32_SET_HANDLE 23 |
| 1223 | 1230 | #define SQLITE_FCNTL_WAL_BLOCK 24 |
| 1224 | 1231 | #define SQLITE_FCNTL_ZIPVFS 25 |
| 1225 | 1232 | #define SQLITE_FCNTL_RBU 26 |
| 1226 | 1233 | #define SQLITE_FCNTL_VFS_POINTER 27 |
| 1234 | +#define SQLITE_FCNTL_JOURNAL_POINTER 28 |
| 1227 | 1235 | |
| 1228 | 1236 | /* deprecated names */ |
| 1229 | 1237 | #define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE |
| 1230 | 1238 | #define SQLITE_SET_LOCKPROXYFILE SQLITE_FCNTL_SET_LOCKPROXYFILE |
| 1231 | 1239 | #define SQLITE_LAST_ERRNO SQLITE_FCNTL_LAST_ERRNO |
| | @@ -8399,10 +8407,13 @@ |
| 8399 | 8407 | ** If parameter iCol is greater than or equal to the number of columns |
| 8400 | 8408 | ** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g. |
| 8401 | 8409 | ** an OOM condition or IO error), an appropriate SQLite error code is |
| 8402 | 8410 | ** returned. |
| 8403 | 8411 | ** |
| 8412 | +** This function may be quite inefficient if used with an FTS5 table |
| 8413 | +** created with the "columnsize=0" option. |
| 8414 | +** |
| 8404 | 8415 | ** xColumnText: |
| 8405 | 8416 | ** This function attempts to retrieve the text of column iCol of the |
| 8406 | 8417 | ** current document. If successful, (*pz) is set to point to a buffer |
| 8407 | 8418 | ** containing the text in utf-8 encoding, (*pn) is set to the size in bytes |
| 8408 | 8419 | ** (not characters) of the buffer and SQLITE_OK is returned. Otherwise, |
| | @@ -8419,18 +8430,32 @@ |
| 8419 | 8430 | ** xInstCount: |
| 8420 | 8431 | ** Set *pnInst to the total number of occurrences of all phrases within |
| 8421 | 8432 | ** the query within the current row. Return SQLITE_OK if successful, or |
| 8422 | 8433 | ** an error code (i.e. SQLITE_NOMEM) if an error occurs. |
| 8423 | 8434 | ** |
| 8435 | +** This API can be quite slow if used with an FTS5 table created with the |
| 8436 | +** "detail=none" or "detail=column" option. If the FTS5 table is created |
| 8437 | +** with either "detail=none" or "detail=column" and "content=" option |
| 8438 | +** (i.e. if it is a contentless table), then this API always returns 0. |
| 8439 | +** |
| 8424 | 8440 | ** xInst: |
| 8425 | 8441 | ** Query for the details of phrase match iIdx within the current row. |
| 8426 | 8442 | ** Phrase matches are numbered starting from zero, so the iIdx argument |
| 8427 | 8443 | ** should be greater than or equal to zero and smaller than the value |
| 8428 | 8444 | ** output by xInstCount(). |
| 8445 | +** |
| 8446 | +** Usually, output parameter *piPhrase is set to the phrase number, *piCol |
| 8447 | +** to the column in which it occurs and *piOff the token offset of the |
| 8448 | +** first token of the phrase. The exception is if the table was created |
| 8449 | +** with the offsets=0 option specified. In this case *piOff is always |
| 8450 | +** set to -1. |
| 8429 | 8451 | ** |
| 8430 | 8452 | ** Returns SQLITE_OK if successful, or an error code (i.e. SQLITE_NOMEM) |
| 8431 | 8453 | ** if an error occurs. |
| 8454 | +** |
| 8455 | +** This API can be quite slow if used with an FTS5 table created with the |
| 8456 | +** "detail=none" or "detail=column" option. |
| 8432 | 8457 | ** |
| 8433 | 8458 | ** xRowid: |
| 8434 | 8459 | ** Returns the rowid of the current row. |
| 8435 | 8460 | ** |
| 8436 | 8461 | ** xTokenize: |
| | @@ -8511,25 +8536,63 @@ |
| 8511 | 8536 | ** through instances of phrase iPhrase, use the following code: |
| 8512 | 8537 | ** |
| 8513 | 8538 | ** Fts5PhraseIter iter; |
| 8514 | 8539 | ** int iCol, iOff; |
| 8515 | 8540 | ** for(pApi->xPhraseFirst(pFts, iPhrase, &iter, &iCol, &iOff); |
| 8516 | | -** iOff>=0; |
| 8541 | +** iCol>=0; |
| 8517 | 8542 | ** pApi->xPhraseNext(pFts, &iter, &iCol, &iOff) |
| 8518 | 8543 | ** ){ |
| 8519 | 8544 | ** // An instance of phrase iPhrase at offset iOff of column iCol |
| 8520 | 8545 | ** } |
| 8521 | 8546 | ** |
| 8522 | 8547 | ** The Fts5PhraseIter structure is defined above. Applications should not |
| 8523 | 8548 | ** modify this structure directly - it should only be used as shown above |
| 8524 | | -** with the xPhraseFirst() and xPhraseNext() API methods. |
| 8549 | +** with the xPhraseFirst() and xPhraseNext() API methods (and by |
| 8550 | +** xPhraseFirstColumn() and xPhraseNextColumn() as illustrated below). |
| 8551 | +** |
| 8552 | +** This API can be quite slow if used with an FTS5 table created with the |
| 8553 | +** "detail=none" or "detail=column" option. If the FTS5 table is created |
| 8554 | +** with either "detail=none" or "detail=column" and "content=" option |
| 8555 | +** (i.e. if it is a contentless table), then this API always iterates |
| 8556 | +** through an empty set (all calls to xPhraseFirst() set iCol to -1). |
| 8525 | 8557 | ** |
| 8526 | 8558 | ** xPhraseNext() |
| 8527 | 8559 | ** See xPhraseFirst above. |
| 8560 | +** |
| 8561 | +** xPhraseFirstColumn() |
| 8562 | +** This function and xPhraseNextColumn() are similar to the xPhraseFirst() |
| 8563 | +** and xPhraseNext() APIs described above. The difference is that instead |
| 8564 | +** of iterating through all instances of a phrase in the current row, these |
| 8565 | +** APIs are used to iterate through the set of columns in the current row |
| 8566 | +** that contain one or more instances of a specified phrase. For example: |
| 8567 | +** |
| 8568 | +** Fts5PhraseIter iter; |
| 8569 | +** int iCol; |
| 8570 | +** for(pApi->xPhraseFirstColumn(pFts, iPhrase, &iter, &iCol); |
| 8571 | +** iCol>=0; |
| 8572 | +** pApi->xPhraseNextColumn(pFts, &iter, &iCol) |
| 8573 | +** ){ |
| 8574 | +** // Column iCol contains at least one instance of phrase iPhrase |
| 8575 | +** } |
| 8576 | +** |
| 8577 | +** This API can be quite slow if used with an FTS5 table created with the |
| 8578 | +** "detail=none" option. If the FTS5 table is created with either |
| 8579 | +** "detail=none" "content=" option (i.e. if it is a contentless table), |
| 8580 | +** then this API always iterates through an empty set (all calls to |
| 8581 | +** xPhraseFirstColumn() set iCol to -1). |
| 8582 | +** |
| 8583 | +** The information accessed using this API and its companion |
| 8584 | +** xPhraseFirstColumn() may also be obtained using xPhraseFirst/xPhraseNext |
| 8585 | +** (or xInst/xInstCount). The chief advantage of this API is that it is |
| 8586 | +** significantly more efficient than those alternatives when used with |
| 8587 | +** "detail=column" tables. |
| 8588 | +** |
| 8589 | +** xPhraseNextColumn() |
| 8590 | +** See xPhraseFirstColumn above. |
| 8528 | 8591 | */ |
| 8529 | 8592 | struct Fts5ExtensionApi { |
| 8530 | | - int iVersion; /* Currently always set to 1 */ |
| 8593 | + int iVersion; /* Currently always set to 3 */ |
| 8531 | 8594 | |
| 8532 | 8595 | void *(*xUserData)(Fts5Context*); |
| 8533 | 8596 | |
| 8534 | 8597 | int (*xColumnCount)(Fts5Context*); |
| 8535 | 8598 | int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow); |
| | @@ -8555,12 +8618,15 @@ |
| 8555 | 8618 | int(*)(const Fts5ExtensionApi*,Fts5Context*,void*) |
| 8556 | 8619 | ); |
| 8557 | 8620 | int (*xSetAuxdata)(Fts5Context*, void *pAux, void(*xDelete)(void*)); |
| 8558 | 8621 | void *(*xGetAuxdata)(Fts5Context*, int bClear); |
| 8559 | 8622 | |
| 8560 | | - void (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*); |
| 8623 | + int (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*); |
| 8561 | 8624 | void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff); |
| 8625 | + |
| 8626 | + int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*); |
| 8627 | + void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol); |
| 8562 | 8628 | }; |
| 8563 | 8629 | |
| 8564 | 8630 | /* |
| 8565 | 8631 | ** CUSTOM AUXILIARY FUNCTIONS |
| 8566 | 8632 | *************************************************************************/ |
| | @@ -9340,10 +9406,25 @@ |
| 9340 | 9406 | #else |
| 9341 | 9407 | # define ALWAYS(X) (X) |
| 9342 | 9408 | # define NEVER(X) (X) |
| 9343 | 9409 | #endif |
| 9344 | 9410 | |
| 9411 | +/* |
| 9412 | +** Some malloc failures are only possible if SQLITE_TEST_REALLOC_STRESS is |
| 9413 | +** defined. We need to defend against those failures when testing with |
| 9414 | +** SQLITE_TEST_REALLOC_STRESS, but we don't want the unreachable branches |
| 9415 | +** during a normal build. The following macro can be used to disable tests |
| 9416 | +** that are always false except when SQLITE_TEST_REALLOC_STRESS is set. |
| 9417 | +*/ |
| 9418 | +#if defined(SQLITE_TEST_REALLOC_STRESS) |
| 9419 | +# define ONLY_IF_REALLOC_STRESS(X) (X) |
| 9420 | +#elif !defined(NDEBUG) |
| 9421 | +# define ONLY_IF_REALLOC_STRESS(X) ((X)?(assert(0),1):0) |
| 9422 | +#else |
| 9423 | +# define ONLY_IF_REALLOC_STRESS(X) (0) |
| 9424 | +#endif |
| 9425 | + |
| 9345 | 9426 | /* |
| 9346 | 9427 | ** Declarations used for tracing the operating system interfaces. |
| 9347 | 9428 | */ |
| 9348 | 9429 | #if defined(SQLITE_FORCE_OS_TRACE) || defined(SQLITE_TEST) || \ |
| 9349 | 9430 | (defined(SQLITE_DEBUG) && SQLITE_OS_WIN) |
| | @@ -9976,14 +10057,10 @@ |
| 9976 | 10057 | /* |
| 9977 | 10058 | ** Default maximum size of memory used by memory-mapped I/O in the VFS |
| 9978 | 10059 | */ |
| 9979 | 10060 | #ifdef __APPLE__ |
| 9980 | 10061 | # include <TargetConditionals.h> |
| 9981 | | -# if TARGET_OS_IPHONE |
| 9982 | | -# undef SQLITE_MAX_MMAP_SIZE |
| 9983 | | -# define SQLITE_MAX_MMAP_SIZE 0 |
| 9984 | | -# endif |
| 9985 | 10062 | #endif |
| 9986 | 10063 | #ifndef SQLITE_MAX_MMAP_SIZE |
| 9987 | 10064 | # if defined(__linux__) \ |
| 9988 | 10065 | || defined(_WIN32) \ |
| 9989 | 10066 | || (defined(__APPLE__) && defined(__MACH__)) \ |
| | @@ -10479,19 +10556,21 @@ |
| 10479 | 10556 | ** Enter and Leave procedures no-ops. |
| 10480 | 10557 | */ |
| 10481 | 10558 | #ifndef SQLITE_OMIT_SHARED_CACHE |
| 10482 | 10559 | SQLITE_PRIVATE void sqlite3BtreeEnter(Btree*); |
| 10483 | 10560 | SQLITE_PRIVATE void sqlite3BtreeEnterAll(sqlite3*); |
| 10561 | +SQLITE_PRIVATE int sqlite3BtreeSharable(Btree*); |
| 10562 | +SQLITE_PRIVATE void sqlite3BtreeEnterCursor(BtCursor*); |
| 10484 | 10563 | #else |
| 10485 | 10564 | # define sqlite3BtreeEnter(X) |
| 10486 | 10565 | # define sqlite3BtreeEnterAll(X) |
| 10566 | +# define sqlite3BtreeSharable(X) 0 |
| 10567 | +# define sqlite3BtreeEnterCursor(X) |
| 10487 | 10568 | #endif |
| 10488 | 10569 | |
| 10489 | 10570 | #if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE |
| 10490 | | -SQLITE_PRIVATE int sqlite3BtreeSharable(Btree*); |
| 10491 | 10571 | SQLITE_PRIVATE void sqlite3BtreeLeave(Btree*); |
| 10492 | | -SQLITE_PRIVATE void sqlite3BtreeEnterCursor(BtCursor*); |
| 10493 | 10572 | SQLITE_PRIVATE void sqlite3BtreeLeaveCursor(BtCursor*); |
| 10494 | 10573 | SQLITE_PRIVATE void sqlite3BtreeLeaveAll(sqlite3*); |
| 10495 | 10574 | #ifndef NDEBUG |
| 10496 | 10575 | /* These routines are used inside assert() statements only. */ |
| 10497 | 10576 | SQLITE_PRIVATE int sqlite3BtreeHoldsMutex(Btree*); |
| | @@ -10498,13 +10577,11 @@ |
| 10498 | 10577 | SQLITE_PRIVATE int sqlite3BtreeHoldsAllMutexes(sqlite3*); |
| 10499 | 10578 | SQLITE_PRIVATE int sqlite3SchemaMutexHeld(sqlite3*,int,Schema*); |
| 10500 | 10579 | #endif |
| 10501 | 10580 | #else |
| 10502 | 10581 | |
| 10503 | | -# define sqlite3BtreeSharable(X) 0 |
| 10504 | 10582 | # define sqlite3BtreeLeave(X) |
| 10505 | | -# define sqlite3BtreeEnterCursor(X) |
| 10506 | 10583 | # define sqlite3BtreeLeaveCursor(X) |
| 10507 | 10584 | # define sqlite3BtreeLeaveAll(X) |
| 10508 | 10585 | |
| 10509 | 10586 | # define sqlite3BtreeHoldsMutex(X) 1 |
| 10510 | 10587 | # define sqlite3BtreeHoldsAllMutexes(X) 1 |
| | @@ -10899,19 +10976,24 @@ |
| 10899 | 10976 | SQLITE_PRIVATE void sqlite3VdbeMultiLoad(Vdbe*,int,const char*,...); |
| 10900 | 10977 | SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe*,int,int,int,int); |
| 10901 | 10978 | SQLITE_PRIVATE int sqlite3VdbeAddOp4(Vdbe*,int,int,int,int,const char *zP4,int); |
| 10902 | 10979 | SQLITE_PRIVATE int sqlite3VdbeAddOp4Dup8(Vdbe*,int,int,int,int,const u8*,int); |
| 10903 | 10980 | SQLITE_PRIVATE int sqlite3VdbeAddOp4Int(Vdbe*,int,int,int,int,int); |
| 10904 | | -SQLITE_PRIVATE int sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp, int iLineno); |
| 10981 | +#if defined(SQLITE_DEBUG) && !defined(SQLITE_TEST_REALLOC_STRESS) |
| 10982 | +SQLITE_PRIVATE void sqlite3VdbeVerifyNoMallocRequired(Vdbe *p, int N); |
| 10983 | +#else |
| 10984 | +# define sqlite3VdbeVerifyNoMallocRequired(A,B) |
| 10985 | +#endif |
| 10986 | +SQLITE_PRIVATE VdbeOp *sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp, int iLineno); |
| 10905 | 10987 | SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe*,int,char*); |
| 10906 | 10988 | SQLITE_PRIVATE void sqlite3VdbeChangeOpcode(Vdbe*, u32 addr, u8); |
| 10907 | 10989 | SQLITE_PRIVATE void sqlite3VdbeChangeP1(Vdbe*, u32 addr, int P1); |
| 10908 | 10990 | SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe*, u32 addr, int P2); |
| 10909 | 10991 | SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe*, u32 addr, int P3); |
| 10910 | 10992 | SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe*, u8 P5); |
| 10911 | 10993 | SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe*, int addr); |
| 10912 | | -SQLITE_PRIVATE void sqlite3VdbeChangeToNoop(Vdbe*, int addr); |
| 10994 | +SQLITE_PRIVATE int sqlite3VdbeChangeToNoop(Vdbe*, int addr); |
| 10913 | 10995 | SQLITE_PRIVATE int sqlite3VdbeDeletePriorOpcode(Vdbe*, u8 op); |
| 10914 | 10996 | SQLITE_PRIVATE void sqlite3VdbeChangeP4(Vdbe*, int addr, const char *zP4, int N); |
| 10915 | 10997 | SQLITE_PRIVATE void sqlite3VdbeSetP4KeyInfo(Parse*, Index*); |
| 10916 | 10998 | SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe*, int); |
| 10917 | 10999 | SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe*, int); |
| | @@ -11215,10 +11297,11 @@ |
| 11215 | 11297 | #endif |
| 11216 | 11298 | SQLITE_PRIVATE int sqlite3PagerMemUsed(Pager*); |
| 11217 | 11299 | SQLITE_PRIVATE const char *sqlite3PagerFilename(Pager*, int); |
| 11218 | 11300 | SQLITE_PRIVATE sqlite3_vfs *sqlite3PagerVfs(Pager*); |
| 11219 | 11301 | SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager*); |
| 11302 | +SQLITE_PRIVATE sqlite3_file *sqlite3PagerJrnlFile(Pager*); |
| 11220 | 11303 | SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager*); |
| 11221 | 11304 | SQLITE_PRIVATE int sqlite3PagerNosync(Pager*); |
| 11222 | 11305 | SQLITE_PRIVATE void *sqlite3PagerTempSpace(Pager*); |
| 11223 | 11306 | SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager*); |
| 11224 | 11307 | SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *, int, int, int *); |
| | @@ -11309,10 +11392,12 @@ |
| 11309 | 11392 | #define PGHDR_NEED_SYNC 0x008 /* Fsync the rollback journal before |
| 11310 | 11393 | ** writing this page to the database */ |
| 11311 | 11394 | #define PGHDR_NEED_READ 0x010 /* Content is unread */ |
| 11312 | 11395 | #define PGHDR_DONT_WRITE 0x020 /* Do not write content to disk */ |
| 11313 | 11396 | #define PGHDR_MMAP 0x040 /* This is an mmap page object */ |
| 11397 | + |
| 11398 | +#define PGHDR_WAL_APPEND 0x080 /* Appended to wal file */ |
| 11314 | 11399 | |
| 11315 | 11400 | /* Initialize and shutdown the page cache subsystem */ |
| 11316 | 11401 | SQLITE_PRIVATE int sqlite3PcacheInitialize(void); |
| 11317 | 11402 | SQLITE_PRIVATE void sqlite3PcacheShutdown(void); |
| 11318 | 11403 | |
| | @@ -12162,13 +12247,12 @@ |
| 12162 | 12247 | struct FuncDef { |
| 12163 | 12248 | i16 nArg; /* Number of arguments. -1 means unlimited */ |
| 12164 | 12249 | u16 funcFlags; /* Some combination of SQLITE_FUNC_* */ |
| 12165 | 12250 | void *pUserData; /* User data parameter */ |
| 12166 | 12251 | FuncDef *pNext; /* Next function with same name */ |
| 12167 | | - void (*xFunc)(sqlite3_context*,int,sqlite3_value**); /* Regular function */ |
| 12168 | | - void (*xStep)(sqlite3_context*,int,sqlite3_value**); /* Aggregate step */ |
| 12169 | | - void (*xFinalize)(sqlite3_context*); /* Aggregate finalizer */ |
| 12252 | + void (*xSFunc)(sqlite3_context*,int,sqlite3_value**); /* func or agg-step */ |
| 12253 | + void (*xFinalize)(sqlite3_context*); /* Agg finalizer */ |
| 12170 | 12254 | char *zName; /* SQL name of the function. */ |
| 12171 | 12255 | FuncDef *pHash; /* Next with a different name but the same hash */ |
| 12172 | 12256 | FuncDestructor *pDestructor; /* Reference counted destructor function */ |
| 12173 | 12257 | }; |
| 12174 | 12258 | |
| | @@ -12247,32 +12331,32 @@ |
| 12247 | 12331 | ** FuncDef.flags variable is set to the value passed as the flags |
| 12248 | 12332 | ** parameter. |
| 12249 | 12333 | */ |
| 12250 | 12334 | #define FUNCTION(zName, nArg, iArg, bNC, xFunc) \ |
| 12251 | 12335 | {nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ |
| 12252 | | - SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0} |
| 12336 | + SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, 0, 0} |
| 12253 | 12337 | #define VFUNCTION(zName, nArg, iArg, bNC, xFunc) \ |
| 12254 | 12338 | {nArg, SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ |
| 12255 | | - SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0} |
| 12339 | + SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, 0, 0} |
| 12256 | 12340 | #define DFUNCTION(zName, nArg, iArg, bNC, xFunc) \ |
| 12257 | 12341 | {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ |
| 12258 | | - SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0} |
| 12342 | + SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, 0, 0} |
| 12259 | 12343 | #define FUNCTION2(zName, nArg, iArg, bNC, xFunc, extraFlags) \ |
| 12260 | 12344 | {nArg,SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL)|extraFlags,\ |
| 12261 | | - SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0} |
| 12345 | + SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, 0, 0} |
| 12262 | 12346 | #define STR_FUNCTION(zName, nArg, pArg, bNC, xFunc) \ |
| 12263 | 12347 | {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ |
| 12264 | | - pArg, 0, xFunc, 0, 0, #zName, 0, 0} |
| 12348 | + pArg, 0, xFunc, 0, #zName, 0, 0} |
| 12265 | 12349 | #define LIKEFUNC(zName, nArg, arg, flags) \ |
| 12266 | 12350 | {nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|flags, \ |
| 12267 | | - (void *)arg, 0, likeFunc, 0, 0, #zName, 0, 0} |
| 12351 | + (void *)arg, 0, likeFunc, 0, #zName, 0, 0} |
| 12268 | 12352 | #define AGGREGATE(zName, nArg, arg, nc, xStep, xFinal) \ |
| 12269 | 12353 | {nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL), \ |
| 12270 | | - SQLITE_INT_TO_PTR(arg), 0, 0, xStep,xFinal,#zName,0,0} |
| 12354 | + SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,#zName,0,0} |
| 12271 | 12355 | #define AGGREGATE2(zName, nArg, arg, nc, xStep, xFinal, extraFlags) \ |
| 12272 | 12356 | {nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL)|extraFlags, \ |
| 12273 | | - SQLITE_INT_TO_PTR(arg), 0, 0, xStep,xFinal,#zName,0,0} |
| 12357 | + SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,#zName,0,0} |
| 12274 | 12358 | |
| 12275 | 12359 | /* |
| 12276 | 12360 | ** All current savepoints are stored in a linked list starting at |
| 12277 | 12361 | ** sqlite3.pSavepoint. The first element in the list is the most recently |
| 12278 | 12362 | ** opened savepoint. Savepoints are added to the list by the vdbe |
| | @@ -13579,11 +13663,11 @@ |
| 13579 | 13663 | ** each recursion. The boundary between these two regions is determined |
| 13580 | 13664 | ** using offsetof(Parse,nVar) so the nVar field must be the first field |
| 13581 | 13665 | ** in the recursive region. |
| 13582 | 13666 | ************************************************************************/ |
| 13583 | 13667 | |
| 13584 | | - int nVar; /* Number of '?' variables seen in the SQL so far */ |
| 13668 | + ynVar nVar; /* Number of '?' variables seen in the SQL so far */ |
| 13585 | 13669 | int nzVar; /* Number of available slots in azVar[] */ |
| 13586 | 13670 | u8 iPkSortOrder; /* ASC or DESC for INTEGER PRIMARY KEY */ |
| 13587 | 13671 | u8 explain; /* True if the EXPLAIN flag is found on the query */ |
| 13588 | 13672 | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| 13589 | 13673 | u8 declareVtab; /* True if inside sqlite3_declare_vtab() */ |
| | @@ -13861,14 +13945,14 @@ |
| 13861 | 13945 | |
| 13862 | 13946 | /* |
| 13863 | 13947 | ** Context pointer passed down through the tree-walk. |
| 13864 | 13948 | */ |
| 13865 | 13949 | struct Walker { |
| 13950 | + Parse *pParse; /* Parser context. */ |
| 13866 | 13951 | int (*xExprCallback)(Walker*, Expr*); /* Callback for expressions */ |
| 13867 | 13952 | int (*xSelectCallback)(Walker*,Select*); /* Callback for SELECTs */ |
| 13868 | 13953 | void (*xSelectCallback2)(Walker*,Select*);/* Second callback for SELECTs */ |
| 13869 | | - Parse *pParse; /* Parser context. */ |
| 13870 | 13954 | int walkerDepth; /* Number of subqueries */ |
| 13871 | 13955 | u8 eCode; /* A small processing code */ |
| 13872 | 13956 | union { /* Extra data for callback */ |
| 13873 | 13957 | NameContext *pNC; /* Naming context */ |
| 13874 | 13958 | int n; /* A counter */ |
| | @@ -14135,11 +14219,10 @@ |
| 14135 | 14219 | SQLITE_PRIVATE int sqlite3InitCallback(void*, int, char**, char**); |
| 14136 | 14220 | SQLITE_PRIVATE void sqlite3Pragma(Parse*,Token*,Token*,Token*,int); |
| 14137 | 14221 | SQLITE_PRIVATE void sqlite3ResetAllSchemasOfConnection(sqlite3*); |
| 14138 | 14222 | SQLITE_PRIVATE void sqlite3ResetOneSchema(sqlite3*,int); |
| 14139 | 14223 | SQLITE_PRIVATE void sqlite3CollapseDatabaseArray(sqlite3*); |
| 14140 | | -SQLITE_PRIVATE void sqlite3BeginParse(Parse*,int); |
| 14141 | 14224 | SQLITE_PRIVATE void sqlite3CommitInternalChanges(sqlite3*); |
| 14142 | 14225 | SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3*,Table*); |
| 14143 | 14226 | SQLITE_PRIVATE int sqlite3ColumnsFromExprList(Parse*,ExprList*,i16*,Column**); |
| 14144 | 14227 | SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse*,Select*); |
| 14145 | 14228 | SQLITE_PRIVATE void sqlite3OpenMasterTable(Parse *, int); |
| | @@ -16066,15 +16149,19 @@ |
| 16066 | 16149 | SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *, const VdbeCursor *, int *); |
| 16067 | 16150 | SQLITE_PRIVATE int sqlite3VdbeSorterRewind(const VdbeCursor *, int *); |
| 16068 | 16151 | SQLITE_PRIVATE int sqlite3VdbeSorterWrite(const VdbeCursor *, Mem *); |
| 16069 | 16152 | SQLITE_PRIVATE int sqlite3VdbeSorterCompare(const VdbeCursor *, Mem *, int, int *); |
| 16070 | 16153 | |
| 16071 | | -#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0 |
| 16154 | +#if !defined(SQLITE_OMIT_SHARED_CACHE) |
| 16072 | 16155 | SQLITE_PRIVATE void sqlite3VdbeEnter(Vdbe*); |
| 16073 | | -SQLITE_PRIVATE void sqlite3VdbeLeave(Vdbe*); |
| 16074 | 16156 | #else |
| 16075 | 16157 | # define sqlite3VdbeEnter(X) |
| 16158 | +#endif |
| 16159 | + |
| 16160 | +#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0 |
| 16161 | +SQLITE_PRIVATE void sqlite3VdbeLeave(Vdbe*); |
| 16162 | +#else |
| 16076 | 16163 | # define sqlite3VdbeLeave(X) |
| 16077 | 16164 | #endif |
| 16078 | 16165 | |
| 16079 | 16166 | #ifdef SQLITE_DEBUG |
| 16080 | 16167 | SQLITE_PRIVATE void sqlite3VdbeMemAboutToChange(Vdbe*,Mem*); |
| | @@ -16508,52 +16595,68 @@ |
| 16508 | 16595 | char tzSet; /* Timezone was set explicitly */ |
| 16509 | 16596 | }; |
| 16510 | 16597 | |
| 16511 | 16598 | |
| 16512 | 16599 | /* |
| 16513 | | -** Convert zDate into one or more integers. Additional arguments |
| 16514 | | -** come in groups of 5 as follows: |
| 16515 | | -** |
| 16516 | | -** N number of digits in the integer |
| 16517 | | -** min minimum allowed value of the integer |
| 16518 | | -** max maximum allowed value of the integer |
| 16519 | | -** nextC first character after the integer |
| 16520 | | -** pVal where to write the integers value. |
| 16521 | | -** |
| 16522 | | -** Conversions continue until one with nextC==0 is encountered. |
| 16600 | +** Convert zDate into one or more integers according to the conversion |
| 16601 | +** specifier zFormat. |
| 16602 | +** |
| 16603 | +** zFormat[] contains 4 characters for each integer converted, except for |
| 16604 | +** the last integer which is specified by three characters. The meaning |
| 16605 | +** of a four-character format specifiers ABCD is: |
| 16606 | +** |
| 16607 | +** A: number of digits to convert. Always "2" or "4". |
| 16608 | +** B: minimum value. Always "0" or "1". |
| 16609 | +** C: maximum value, decoded as: |
| 16610 | +** a: 12 |
| 16611 | +** b: 14 |
| 16612 | +** c: 24 |
| 16613 | +** d: 31 |
| 16614 | +** e: 59 |
| 16615 | +** f: 9999 |
| 16616 | +** D: the separator character, or \000 to indicate this is the |
| 16617 | +** last number to convert. |
| 16618 | +** |
| 16619 | +** Example: To translate an ISO-8601 date YYYY-MM-DD, the format would |
| 16620 | +** be "40f-21a-20c". The "40f-" indicates the 4-digit year followed by "-". |
| 16621 | +** The "21a-" indicates the 2-digit month followed by "-". The "20c" indicates |
| 16622 | +** the 2-digit day which is the last integer in the set. |
| 16623 | +** |
| 16523 | 16624 | ** The function returns the number of successful conversions. |
| 16524 | 16625 | */ |
| 16525 | | -static int getDigits(const char *zDate, ...){ |
| 16626 | +static int getDigits(const char *zDate, const char *zFormat, ...){ |
| 16627 | + /* The aMx[] array translates the 3rd character of each format |
| 16628 | + ** spec into a max size: a b c d e f */ |
| 16629 | + static const u16 aMx[] = { 12, 14, 24, 31, 59, 9999 }; |
| 16526 | 16630 | va_list ap; |
| 16527 | | - int val; |
| 16528 | | - int N; |
| 16529 | | - int min; |
| 16530 | | - int max; |
| 16531 | | - int nextC; |
| 16532 | | - int *pVal; |
| 16533 | 16631 | int cnt = 0; |
| 16534 | | - va_start(ap, zDate); |
| 16632 | + char nextC; |
| 16633 | + va_start(ap, zFormat); |
| 16535 | 16634 | do{ |
| 16536 | | - N = va_arg(ap, int); |
| 16537 | | - min = va_arg(ap, int); |
| 16538 | | - max = va_arg(ap, int); |
| 16539 | | - nextC = va_arg(ap, int); |
| 16540 | | - pVal = va_arg(ap, int*); |
| 16635 | + char N = zFormat[0] - '0'; |
| 16636 | + char min = zFormat[1] - '0'; |
| 16637 | + int val = 0; |
| 16638 | + u16 max; |
| 16639 | + |
| 16640 | + assert( zFormat[2]>='a' && zFormat[2]<='f' ); |
| 16641 | + max = aMx[zFormat[2] - 'a']; |
| 16642 | + nextC = zFormat[3]; |
| 16541 | 16643 | val = 0; |
| 16542 | 16644 | while( N-- ){ |
| 16543 | 16645 | if( !sqlite3Isdigit(*zDate) ){ |
| 16544 | 16646 | goto end_getDigits; |
| 16545 | 16647 | } |
| 16546 | 16648 | val = val*10 + *zDate - '0'; |
| 16547 | 16649 | zDate++; |
| 16548 | 16650 | } |
| 16549 | | - if( val<min || val>max || (nextC!=0 && nextC!=*zDate) ){ |
| 16651 | + if( val<(int)min || val>(int)max || (nextC!=0 && nextC!=*zDate) ){ |
| 16550 | 16652 | goto end_getDigits; |
| 16551 | 16653 | } |
| 16552 | | - *pVal = val; |
| 16654 | + *va_arg(ap,int*) = val; |
| 16553 | 16655 | zDate++; |
| 16554 | 16656 | cnt++; |
| 16657 | + zFormat += 4; |
| 16555 | 16658 | }while( nextC ); |
| 16556 | 16659 | end_getDigits: |
| 16557 | 16660 | va_end(ap); |
| 16558 | 16661 | return cnt; |
| 16559 | 16662 | } |
| | @@ -16590,11 +16693,11 @@ |
| 16590 | 16693 | goto zulu_time; |
| 16591 | 16694 | }else{ |
| 16592 | 16695 | return c!=0; |
| 16593 | 16696 | } |
| 16594 | 16697 | zDate++; |
| 16595 | | - if( getDigits(zDate, 2, 0, 14, ':', &nHr, 2, 0, 59, 0, &nMn)!=2 ){ |
| 16698 | + if( getDigits(zDate, "20b:20e", &nHr, &nMn)!=2 ){ |
| 16596 | 16699 | return 1; |
| 16597 | 16700 | } |
| 16598 | 16701 | zDate += 5; |
| 16599 | 16702 | p->tz = sgn*(nMn + nHr*60); |
| 16600 | 16703 | zulu_time: |
| | @@ -16611,17 +16714,17 @@ |
| 16611 | 16714 | ** Return 1 if there is a parsing error and 0 on success. |
| 16612 | 16715 | */ |
| 16613 | 16716 | static int parseHhMmSs(const char *zDate, DateTime *p){ |
| 16614 | 16717 | int h, m, s; |
| 16615 | 16718 | double ms = 0.0; |
| 16616 | | - if( getDigits(zDate, 2, 0, 24, ':', &h, 2, 0, 59, 0, &m)!=2 ){ |
| 16719 | + if( getDigits(zDate, "20c:20e", &h, &m)!=2 ){ |
| 16617 | 16720 | return 1; |
| 16618 | 16721 | } |
| 16619 | 16722 | zDate += 5; |
| 16620 | 16723 | if( *zDate==':' ){ |
| 16621 | 16724 | zDate++; |
| 16622 | | - if( getDigits(zDate, 2, 0, 59, 0, &s)!=1 ){ |
| 16725 | + if( getDigits(zDate, "20e", &s)!=1 ){ |
| 16623 | 16726 | return 1; |
| 16624 | 16727 | } |
| 16625 | 16728 | zDate += 2; |
| 16626 | 16729 | if( *zDate=='.' && sqlite3Isdigit(zDate[1]) ){ |
| 16627 | 16730 | double rScale = 1.0; |
| | @@ -16705,11 +16808,11 @@ |
| 16705 | 16808 | zDate++; |
| 16706 | 16809 | neg = 1; |
| 16707 | 16810 | }else{ |
| 16708 | 16811 | neg = 0; |
| 16709 | 16812 | } |
| 16710 | | - if( getDigits(zDate,4,0,9999,'-',&Y,2,1,12,'-',&M,2,1,31,0,&D)!=3 ){ |
| 16813 | + if( getDigits(zDate, "40f-21a-21d", &Y, &M, &D)!=3 ){ |
| 16711 | 16814 | return 1; |
| 16712 | 16815 | } |
| 16713 | 16816 | zDate += 10; |
| 16714 | 16817 | while( sqlite3Isspace(*zDate) || 'T'==*(u8*)zDate ){ zDate++; } |
| 16715 | 16818 | if( parseHhMmSs(zDate, p)==0 ){ |
| | @@ -19758,10 +19861,11 @@ |
| 19758 | 19861 | /* |
| 19759 | 19862 | ** Mutex to control access to the memory allocation subsystem. |
| 19760 | 19863 | */ |
| 19761 | 19864 | sqlite3_mutex *mutex; |
| 19762 | 19865 | |
| 19866 | +#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) |
| 19763 | 19867 | /* |
| 19764 | 19868 | ** Performance statistics |
| 19765 | 19869 | */ |
| 19766 | 19870 | u64 nAlloc; /* Total number of calls to malloc */ |
| 19767 | 19871 | u64 totalAlloc; /* Total of all malloc calls - includes internal frag */ |
| | @@ -19769,10 +19873,11 @@ |
| 19769 | 19873 | u32 currentOut; /* Current checkout, including internal fragmentation */ |
| 19770 | 19874 | u32 currentCount; /* Current number of distinct checkouts */ |
| 19771 | 19875 | u32 maxOut; /* Maximum instantaneous currentOut */ |
| 19772 | 19876 | u32 maxCount; /* Maximum instantaneous currentCount */ |
| 19773 | 19877 | u32 maxRequest; /* Largest allocation (exclusive of internal frag) */ |
| 19878 | +#endif |
| 19774 | 19879 | |
| 19775 | 19880 | /* |
| 19776 | 19881 | ** Lists of free blocks. aiFreelist[0] is a list of free blocks of |
| 19777 | 19882 | ** size mem5.szAtom. aiFreelist[1] holds blocks of size szAtom*2. |
| 19778 | 19883 | ** aiFreelist[2] holds free blocks of size szAtom*4. And so forth. |
| | @@ -19880,18 +19985,21 @@ |
| 19880 | 19985 | int iLogsize; /* Log2 of iFullSz/POW2_MIN */ |
| 19881 | 19986 | |
| 19882 | 19987 | /* nByte must be a positive */ |
| 19883 | 19988 | assert( nByte>0 ); |
| 19884 | 19989 | |
| 19990 | + /* No more than 1GiB per allocation */ |
| 19991 | + if( nByte > 0x40000000 ) return 0; |
| 19992 | + |
| 19993 | +#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) |
| 19885 | 19994 | /* Keep track of the maximum allocation request. Even unfulfilled |
| 19886 | 19995 | ** requests are counted */ |
| 19887 | 19996 | if( (u32)nByte>mem5.maxRequest ){ |
| 19888 | | - /* Abort if the requested allocation size is larger than the largest |
| 19889 | | - ** power of two that we can represent using 32-bit signed integers. */ |
| 19890 | | - if( nByte > 0x40000000 ) return 0; |
| 19891 | 19997 | mem5.maxRequest = nByte; |
| 19892 | 19998 | } |
| 19999 | +#endif |
| 20000 | + |
| 19893 | 20001 | |
| 19894 | 20002 | /* Round nByte up to the next valid power of two */ |
| 19895 | 20003 | for(iFullSz=mem5.szAtom,iLogsize=0; iFullSz<nByte; iFullSz*=2,iLogsize++){} |
| 19896 | 20004 | |
| 19897 | 20005 | /* Make sure mem5.aiFreelist[iLogsize] contains at least one free |
| | @@ -19914,18 +20022,20 @@ |
| 19914 | 20022 | mem5.aCtrl[i+newSize] = CTRL_FREE | iBin; |
| 19915 | 20023 | memsys5Link(i+newSize, iBin); |
| 19916 | 20024 | } |
| 19917 | 20025 | mem5.aCtrl[i] = iLogsize; |
| 19918 | 20026 | |
| 20027 | +#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) |
| 19919 | 20028 | /* Update allocator performance statistics. */ |
| 19920 | 20029 | mem5.nAlloc++; |
| 19921 | 20030 | mem5.totalAlloc += iFullSz; |
| 19922 | 20031 | mem5.totalExcess += iFullSz - nByte; |
| 19923 | 20032 | mem5.currentCount++; |
| 19924 | 20033 | mem5.currentOut += iFullSz; |
| 19925 | 20034 | if( mem5.maxCount<mem5.currentCount ) mem5.maxCount = mem5.currentCount; |
| 19926 | 20035 | if( mem5.maxOut<mem5.currentOut ) mem5.maxOut = mem5.currentOut; |
| 20036 | +#endif |
| 19927 | 20037 | |
| 19928 | 20038 | #ifdef SQLITE_DEBUG |
| 19929 | 20039 | /* Make sure the allocated memory does not assume that it is set to zero |
| 19930 | 20040 | ** or retains a value from a previous allocation */ |
| 19931 | 20041 | memset(&mem5.zPool[i*mem5.szAtom], 0xAA, iFullSz); |
| | @@ -19956,16 +20066,19 @@ |
| 19956 | 20066 | size = 1<<iLogsize; |
| 19957 | 20067 | assert( iBlock+size-1<(u32)mem5.nBlock ); |
| 19958 | 20068 | |
| 19959 | 20069 | mem5.aCtrl[iBlock] |= CTRL_FREE; |
| 19960 | 20070 | mem5.aCtrl[iBlock+size-1] |= CTRL_FREE; |
| 20071 | + |
| 20072 | +#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) |
| 19961 | 20073 | assert( mem5.currentCount>0 ); |
| 19962 | 20074 | assert( mem5.currentOut>=(size*mem5.szAtom) ); |
| 19963 | 20075 | mem5.currentCount--; |
| 19964 | 20076 | mem5.currentOut -= size*mem5.szAtom; |
| 19965 | 20077 | assert( mem5.currentOut>0 || mem5.currentCount==0 ); |
| 19966 | 20078 | assert( mem5.currentCount>0 || mem5.currentOut==0 ); |
| 20079 | +#endif |
| 19967 | 20080 | |
| 19968 | 20081 | mem5.aCtrl[iBlock] = CTRL_FREE | iLogsize; |
| 19969 | 20082 | while( ALWAYS(iLogsize<LOGMAX) ){ |
| 19970 | 20083 | int iBuddy; |
| 19971 | 20084 | if( (iBlock>>iLogsize) & 1 ){ |
| | @@ -22281,12 +22394,13 @@ |
| 22281 | 22394 | } |
| 22282 | 22395 | return p; |
| 22283 | 22396 | } |
| 22284 | 22397 | |
| 22285 | 22398 | /* |
| 22286 | | -** Allocate and zero memory. If the allocation fails, make |
| 22287 | | -** the mallocFailed flag in the connection pointer. |
| 22399 | +** Allocate memory, either lookaside (if possible) or heap. |
| 22400 | +** If the allocation fails, set the mallocFailed flag in |
| 22401 | +** the connection pointer. |
| 22288 | 22402 | ** |
| 22289 | 22403 | ** If db!=0 and db->mallocFailed is true (indicating a prior malloc |
| 22290 | 22404 | ** failure on the same database connection) then always return 0. |
| 22291 | 22405 | ** Hence for a particular database connection, once malloc starts |
| 22292 | 22406 | ** failing, it fails consistently until mallocFailed is reset. |
| | @@ -22298,12 +22412,12 @@ |
| 22298 | 22412 | ** if( b ) a[10] = 9; |
| 22299 | 22413 | ** |
| 22300 | 22414 | ** In other words, if a subsequent malloc (ex: "b") worked, it is assumed |
| 22301 | 22415 | ** that all prior mallocs (ex: "a") worked too. |
| 22302 | 22416 | */ |
| 22417 | +static SQLITE_NOINLINE void *dbMallocRawFinish(sqlite3 *db, u64 n); |
| 22303 | 22418 | SQLITE_PRIVATE void *sqlite3DbMallocRaw(sqlite3 *db, u64 n){ |
| 22304 | | - void *p; |
| 22305 | 22419 | assert( db==0 || sqlite3_mutex_held(db->mutex) ); |
| 22306 | 22420 | assert( db==0 || db->pnBytesFreed==0 ); |
| 22307 | 22421 | #ifndef SQLITE_OMIT_LOOKASIDE |
| 22308 | 22422 | if( db ){ |
| 22309 | 22423 | LookasideSlot *pBuf; |
| | @@ -22329,11 +22443,14 @@ |
| 22329 | 22443 | #else |
| 22330 | 22444 | if( db && db->mallocFailed ){ |
| 22331 | 22445 | return 0; |
| 22332 | 22446 | } |
| 22333 | 22447 | #endif |
| 22334 | | - p = sqlite3Malloc(n); |
| 22448 | + return dbMallocRawFinish(db, n); |
| 22449 | +} |
| 22450 | +static SQLITE_NOINLINE void *dbMallocRawFinish(sqlite3 *db, u64 n){ |
| 22451 | + void *p = sqlite3Malloc(n); |
| 22335 | 22452 | if( !p && db ){ |
| 22336 | 22453 | db->mallocFailed = 1; |
| 22337 | 22454 | } |
| 22338 | 22455 | sqlite3MemdebugSetType(p, |
| 22339 | 22456 | (db && db->lookaside.bEnabled) ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP); |
| | @@ -27479,37 +27596,55 @@ |
| 27479 | 27596 | #define osMkdir ((int(*)(const char*,mode_t))aSyscall[18].pCurrent) |
| 27480 | 27597 | |
| 27481 | 27598 | { "rmdir", (sqlite3_syscall_ptr)rmdir, 0 }, |
| 27482 | 27599 | #define osRmdir ((int(*)(const char*))aSyscall[19].pCurrent) |
| 27483 | 27600 | |
| 27601 | +#if defined(HAVE_FCHOWN) |
| 27484 | 27602 | { "fchown", (sqlite3_syscall_ptr)fchown, 0 }, |
| 27603 | +#else |
| 27604 | + { "fchown", (sqlite3_syscall_ptr)0, 0 }, |
| 27605 | +#endif |
| 27485 | 27606 | #define osFchown ((int(*)(int,uid_t,gid_t))aSyscall[20].pCurrent) |
| 27486 | 27607 | |
| 27487 | 27608 | { "geteuid", (sqlite3_syscall_ptr)geteuid, 0 }, |
| 27488 | 27609 | #define osGeteuid ((uid_t(*)(void))aSyscall[21].pCurrent) |
| 27489 | 27610 | |
| 27490 | 27611 | #if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 |
| 27491 | | - { "mmap", (sqlite3_syscall_ptr)mmap, 0 }, |
| 27612 | + { "mmap", (sqlite3_syscall_ptr)mmap, 0 }, |
| 27613 | +#else |
| 27614 | + { "mmap", (sqlite3_syscall_ptr)0, 0 }, |
| 27615 | +#endif |
| 27492 | 27616 | #define osMmap ((void*(*)(void*,size_t,int,int,int,off_t))aSyscall[22].pCurrent) |
| 27493 | 27617 | |
| 27618 | +#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 |
| 27494 | 27619 | { "munmap", (sqlite3_syscall_ptr)munmap, 0 }, |
| 27620 | +#else |
| 27621 | + { "munmap", (sqlite3_syscall_ptr)0, 0 }, |
| 27622 | +#endif |
| 27495 | 27623 | #define osMunmap ((void*(*)(void*,size_t))aSyscall[23].pCurrent) |
| 27496 | 27624 | |
| 27497 | | -#if HAVE_MREMAP |
| 27625 | +#if HAVE_MREMAP && (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) |
| 27498 | 27626 | { "mremap", (sqlite3_syscall_ptr)mremap, 0 }, |
| 27499 | 27627 | #else |
| 27500 | 27628 | { "mremap", (sqlite3_syscall_ptr)0, 0 }, |
| 27501 | 27629 | #endif |
| 27502 | 27630 | #define osMremap ((void*(*)(void*,size_t,size_t,int,...))aSyscall[24].pCurrent) |
| 27503 | 27631 | |
| 27632 | +#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 |
| 27504 | 27633 | { "getpagesize", (sqlite3_syscall_ptr)unixGetpagesize, 0 }, |
| 27634 | +#else |
| 27635 | + { "getpagesize", (sqlite3_syscall_ptr)0, 0 }, |
| 27636 | +#endif |
| 27505 | 27637 | #define osGetpagesize ((int(*)(void))aSyscall[25].pCurrent) |
| 27506 | 27638 | |
| 27639 | +#if defined(HAVE_READLINK) |
| 27507 | 27640 | { "readlink", (sqlite3_syscall_ptr)readlink, 0 }, |
| 27641 | +#else |
| 27642 | + { "readlink", (sqlite3_syscall_ptr)0, 0 }, |
| 27643 | +#endif |
| 27508 | 27644 | #define osReadlink ((ssize_t(*)(const char*,char*,size_t))aSyscall[26].pCurrent) |
| 27509 | 27645 | |
| 27510 | | -#endif |
| 27511 | 27646 | |
| 27512 | 27647 | }; /* End of the overrideable system calls */ |
| 27513 | 27648 | |
| 27514 | 27649 | |
| 27515 | 27650 | /* |
| | @@ -27516,14 +27651,14 @@ |
| 27516 | 27651 | ** On some systems, calls to fchown() will trigger a message in a security |
| 27517 | 27652 | ** log if they come from non-root processes. So avoid calling fchown() if |
| 27518 | 27653 | ** we are not running as root. |
| 27519 | 27654 | */ |
| 27520 | 27655 | static int robustFchown(int fd, uid_t uid, gid_t gid){ |
| 27521 | | -#if OS_VXWORKS |
| 27522 | | - return 0; |
| 27523 | | -#else |
| 27656 | +#if defined(HAVE_FCHOWN) |
| 27524 | 27657 | return osGeteuid() ? 0 : osFchown(fd,uid,gid); |
| 27658 | +#else |
| 27659 | + return 0; |
| 27525 | 27660 | #endif |
| 27526 | 27661 | } |
| 27527 | 27662 | |
| 27528 | 27663 | /* |
| 27529 | 27664 | ** This is the xSetSystemCall() method of sqlite3_vfs for all of the |
| | @@ -32986,10 +33121,11 @@ |
| 32986 | 33121 | SimulateIOError( return SQLITE_ERROR ); |
| 32987 | 33122 | |
| 32988 | 33123 | assert( pVfs->mxPathname==MAX_PATHNAME ); |
| 32989 | 33124 | UNUSED_PARAMETER(pVfs); |
| 32990 | 33125 | |
| 33126 | +#if defined(HAVE_READLINK) |
| 32991 | 33127 | /* Attempt to resolve the path as if it were a symbolic link. If it is |
| 32992 | 33128 | ** a symbolic link, the resolved path is stored in buffer zOut[]. Or, if |
| 32993 | 33129 | ** the identified file is not a symbolic link or does not exist, then |
| 32994 | 33130 | ** zPath is copied directly into zOut. Either way, nByte is left set to |
| 32995 | 33131 | ** the size of the string copied into zOut[] in bytes. */ |
| | @@ -33001,10 +33137,11 @@ |
| 33001 | 33137 | sqlite3_snprintf(nOut, zOut, "%s", zPath); |
| 33002 | 33138 | nByte = sqlite3Strlen30(zOut); |
| 33003 | 33139 | }else{ |
| 33004 | 33140 | zOut[nByte] = '\0'; |
| 33005 | 33141 | } |
| 33142 | +#endif |
| 33006 | 33143 | |
| 33007 | 33144 | /* If buffer zOut[] now contains an absolute path there is nothing more |
| 33008 | 33145 | ** to do. If it contains a relative path, do the following: |
| 33009 | 33146 | ** |
| 33010 | 33147 | ** * move the relative path string so that it is at the end of th |
| | @@ -43327,10 +43464,11 @@ |
| 43327 | 43464 | # define sqlite3WalCallback(z) 0 |
| 43328 | 43465 | # define sqlite3WalExclusiveMode(y,z) 0 |
| 43329 | 43466 | # define sqlite3WalHeapMemory(z) 0 |
| 43330 | 43467 | # define sqlite3WalFramesize(z) 0 |
| 43331 | 43468 | # define sqlite3WalFindFrame(x,y,z) 0 |
| 43469 | +# define sqlite3WalFile(x) 0 |
| 43332 | 43470 | #else |
| 43333 | 43471 | |
| 43334 | 43472 | #define WAL_SAVEPOINT_NDATA 4 |
| 43335 | 43473 | |
| 43336 | 43474 | /* Connection to a write-ahead log (WAL) file. |
| | @@ -43421,10 +43559,13 @@ |
| 43421 | 43559 | ** stored in each frame (i.e. the db page-size when the WAL was created). |
| 43422 | 43560 | */ |
| 43423 | 43561 | SQLITE_PRIVATE int sqlite3WalFramesize(Wal *pWal); |
| 43424 | 43562 | #endif |
| 43425 | 43563 | |
| 43564 | +/* Return the sqlite3_file object for the WAL file */ |
| 43565 | +SQLITE_PRIVATE sqlite3_file *sqlite3WalFile(Wal *pWal); |
| 43566 | + |
| 43426 | 43567 | #endif /* ifndef SQLITE_OMIT_WAL */ |
| 43427 | 43568 | #endif /* _WAL_H_ */ |
| 43428 | 43569 | |
| 43429 | 43570 | /************** End of wal.h *************************************************/ |
| 43430 | 43571 | /************** Continuing where we left off in pager.c **********************/ |
| | @@ -49032,11 +49173,11 @@ |
| 49032 | 49173 | if( pPager->exclusiveMode && sqlite3WalExclusiveMode(pPager->pWal, -1) ){ |
| 49033 | 49174 | rc = pagerLockDb(pPager, EXCLUSIVE_LOCK); |
| 49034 | 49175 | if( rc!=SQLITE_OK ){ |
| 49035 | 49176 | return rc; |
| 49036 | 49177 | } |
| 49037 | | - sqlite3WalExclusiveMode(pPager->pWal, 1); |
| 49178 | + (void)sqlite3WalExclusiveMode(pPager->pWal, 1); |
| 49038 | 49179 | } |
| 49039 | 49180 | |
| 49040 | 49181 | /* Grab the write lock on the log file. If successful, upgrade to |
| 49041 | 49182 | ** PAGER_RESERVED state. Otherwise, return an error code to the caller. |
| 49042 | 49183 | ** The busy-handler is not invoked if another connection already |
| | @@ -50096,10 +50237,22 @@ |
| 50096 | 50237 | ** not yet been opened. |
| 50097 | 50238 | */ |
| 50098 | 50239 | SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager *pPager){ |
| 50099 | 50240 | return pPager->fd; |
| 50100 | 50241 | } |
| 50242 | + |
| 50243 | +/* |
| 50244 | +** Return the file handle for the journal file (if it exists). |
| 50245 | +** This will be either the rollback journal or the WAL file. |
| 50246 | +*/ |
| 50247 | +SQLITE_PRIVATE sqlite3_file *sqlite3PagerJrnlFile(Pager *pPager){ |
| 50248 | +#if SQLITE_OMIT_WAL |
| 50249 | + return pPager->jfd; |
| 50250 | +#else |
| 50251 | + return pPager->pWal ? sqlite3WalFile(pPager->pWal) : pPager->jfd; |
| 50252 | +#endif |
| 50253 | +} |
| 50101 | 50254 | |
| 50102 | 50255 | /* |
| 50103 | 50256 | ** Return the full pathname of the journal file. |
| 50104 | 50257 | */ |
| 50105 | 50258 | SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager *pPager){ |
| | @@ -51202,10 +51355,11 @@ |
| 51202 | 51355 | u8 truncateOnCommit; /* True to truncate WAL file on commit */ |
| 51203 | 51356 | u8 syncHeader; /* Fsync the WAL header if true */ |
| 51204 | 51357 | u8 padToSectorBoundary; /* Pad transactions out to the next sector */ |
| 51205 | 51358 | WalIndexHdr hdr; /* Wal-index header for current transaction */ |
| 51206 | 51359 | u32 minFrame; /* Ignore wal frames before this one */ |
| 51360 | + u32 iReCksum; /* On commit, recalculate checksums from here */ |
| 51207 | 51361 | const char *zWalName; /* Name of WAL file */ |
| 51208 | 51362 | u32 nCkpt; /* Checkpoint sequence counter in the wal-header */ |
| 51209 | 51363 | #ifdef SQLITE_DEBUG |
| 51210 | 51364 | u8 lockError; /* True if a locking error has occurred */ |
| 51211 | 51365 | #endif |
| | @@ -51455,18 +51609,22 @@ |
| 51455 | 51609 | int nativeCksum; /* True for native byte-order checksums */ |
| 51456 | 51610 | u32 *aCksum = pWal->hdr.aFrameCksum; |
| 51457 | 51611 | assert( WAL_FRAME_HDRSIZE==24 ); |
| 51458 | 51612 | sqlite3Put4byte(&aFrame[0], iPage); |
| 51459 | 51613 | sqlite3Put4byte(&aFrame[4], nTruncate); |
| 51460 | | - memcpy(&aFrame[8], pWal->hdr.aSalt, 8); |
| 51461 | | - |
| 51462 | | - nativeCksum = (pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN); |
| 51463 | | - walChecksumBytes(nativeCksum, aFrame, 8, aCksum, aCksum); |
| 51464 | | - walChecksumBytes(nativeCksum, aData, pWal->szPage, aCksum, aCksum); |
| 51465 | | - |
| 51466 | | - sqlite3Put4byte(&aFrame[16], aCksum[0]); |
| 51467 | | - sqlite3Put4byte(&aFrame[20], aCksum[1]); |
| 51614 | + if( pWal->iReCksum==0 ){ |
| 51615 | + memcpy(&aFrame[8], pWal->hdr.aSalt, 8); |
| 51616 | + |
| 51617 | + nativeCksum = (pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN); |
| 51618 | + walChecksumBytes(nativeCksum, aFrame, 8, aCksum, aCksum); |
| 51619 | + walChecksumBytes(nativeCksum, aData, pWal->szPage, aCksum, aCksum); |
| 51620 | + |
| 51621 | + sqlite3Put4byte(&aFrame[16], aCksum[0]); |
| 51622 | + sqlite3Put4byte(&aFrame[20], aCksum[1]); |
| 51623 | + }else{ |
| 51624 | + memset(&aFrame[8], 0, 16); |
| 51625 | + } |
| 51468 | 51626 | } |
| 51469 | 51627 | |
| 51470 | 51628 | /* |
| 51471 | 51629 | ** Check to see if the frame with header in aFrame[] and content |
| 51472 | 51630 | ** in aData[] is valid. If it is a valid frame, fill *piPage and |
| | @@ -53389,10 +53547,11 @@ |
| 53389 | 53547 | int rc; |
| 53390 | 53548 | |
| 53391 | 53549 | /* Cannot start a write transaction without first holding a read |
| 53392 | 53550 | ** transaction. */ |
| 53393 | 53551 | assert( pWal->readLock>=0 ); |
| 53552 | + assert( pWal->writeLock==0 && pWal->iReCksum==0 ); |
| 53394 | 53553 | |
| 53395 | 53554 | if( pWal->readOnly ){ |
| 53396 | 53555 | return SQLITE_READONLY; |
| 53397 | 53556 | } |
| 53398 | 53557 | |
| | @@ -53424,10 +53583,11 @@ |
| 53424 | 53583 | */ |
| 53425 | 53584 | SQLITE_PRIVATE int sqlite3WalEndWriteTransaction(Wal *pWal){ |
| 53426 | 53585 | if( pWal->writeLock ){ |
| 53427 | 53586 | walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1); |
| 53428 | 53587 | pWal->writeLock = 0; |
| 53588 | + pWal->iReCksum = 0; |
| 53429 | 53589 | pWal->truncateOnCommit = 0; |
| 53430 | 53590 | } |
| 53431 | 53591 | return SQLITE_OK; |
| 53432 | 53592 | } |
| 53433 | 53593 | |
| | @@ -53641,10 +53801,63 @@ |
| 53641 | 53801 | if( rc ) return rc; |
| 53642 | 53802 | /* Write the page data */ |
| 53643 | 53803 | rc = walWriteToLog(p, pData, p->szPage, iOffset+sizeof(aFrame)); |
| 53644 | 53804 | return rc; |
| 53645 | 53805 | } |
| 53806 | + |
| 53807 | +/* |
| 53808 | +** This function is called as part of committing a transaction within which |
| 53809 | +** one or more frames have been overwritten. It updates the checksums for |
| 53810 | +** all frames written to the wal file by the current transaction starting |
| 53811 | +** with the earliest to have been overwritten. |
| 53812 | +** |
| 53813 | +** SQLITE_OK is returned if successful, or an SQLite error code otherwise. |
| 53814 | +*/ |
| 53815 | +static int walRewriteChecksums(Wal *pWal, u32 iLast){ |
| 53816 | + const int szPage = pWal->szPage;/* Database page size */ |
| 53817 | + int rc = SQLITE_OK; /* Return code */ |
| 53818 | + u8 *aBuf; /* Buffer to load data from wal file into */ |
| 53819 | + u8 aFrame[WAL_FRAME_HDRSIZE]; /* Buffer to assemble frame-headers in */ |
| 53820 | + u32 iRead; /* Next frame to read from wal file */ |
| 53821 | + i64 iCksumOff; |
| 53822 | + |
| 53823 | + aBuf = sqlite3_malloc(szPage + WAL_FRAME_HDRSIZE); |
| 53824 | + if( aBuf==0 ) return SQLITE_NOMEM; |
| 53825 | + |
| 53826 | + /* Find the checksum values to use as input for the recalculating the |
| 53827 | + ** first checksum. If the first frame is frame 1 (implying that the current |
| 53828 | + ** transaction restarted the wal file), these values must be read from the |
| 53829 | + ** wal-file header. Otherwise, read them from the frame header of the |
| 53830 | + ** previous frame. */ |
| 53831 | + assert( pWal->iReCksum>0 ); |
| 53832 | + if( pWal->iReCksum==1 ){ |
| 53833 | + iCksumOff = 24; |
| 53834 | + }else{ |
| 53835 | + iCksumOff = walFrameOffset(pWal->iReCksum-1, szPage) + 16; |
| 53836 | + } |
| 53837 | + rc = sqlite3OsRead(pWal->pWalFd, aBuf, sizeof(u32)*2, iCksumOff); |
| 53838 | + pWal->hdr.aFrameCksum[0] = sqlite3Get4byte(aBuf); |
| 53839 | + pWal->hdr.aFrameCksum[1] = sqlite3Get4byte(&aBuf[sizeof(u32)]); |
| 53840 | + |
| 53841 | + iRead = pWal->iReCksum; |
| 53842 | + pWal->iReCksum = 0; |
| 53843 | + for(; rc==SQLITE_OK && iRead<=iLast; iRead++){ |
| 53844 | + i64 iOff = walFrameOffset(iRead, szPage); |
| 53845 | + rc = sqlite3OsRead(pWal->pWalFd, aBuf, szPage+WAL_FRAME_HDRSIZE, iOff); |
| 53846 | + if( rc==SQLITE_OK ){ |
| 53847 | + u32 iPgno, nDbSize; |
| 53848 | + iPgno = sqlite3Get4byte(aBuf); |
| 53849 | + nDbSize = sqlite3Get4byte(&aBuf[4]); |
| 53850 | + |
| 53851 | + walEncodeFrame(pWal, iPgno, nDbSize, &aBuf[WAL_FRAME_HDRSIZE], aFrame); |
| 53852 | + rc = sqlite3OsWrite(pWal->pWalFd, aFrame, sizeof(aFrame), iOff); |
| 53853 | + } |
| 53854 | + } |
| 53855 | + |
| 53856 | + sqlite3_free(aBuf); |
| 53857 | + return rc; |
| 53858 | +} |
| 53646 | 53859 | |
| 53647 | 53860 | /* |
| 53648 | 53861 | ** Write a set of frames to the log. The caller must hold the write-lock |
| 53649 | 53862 | ** on the log file (obtained using sqlite3WalBeginWriteTransaction()). |
| 53650 | 53863 | */ |
| | @@ -53662,10 +53875,12 @@ |
| 53662 | 53875 | PgHdr *pLast = 0; /* Last frame in list */ |
| 53663 | 53876 | int nExtra = 0; /* Number of extra copies of last page */ |
| 53664 | 53877 | int szFrame; /* The size of a single frame */ |
| 53665 | 53878 | i64 iOffset; /* Next byte to write in WAL file */ |
| 53666 | 53879 | WalWriter w; /* The writer */ |
| 53880 | + u32 iFirst = 0; /* First frame that may be overwritten */ |
| 53881 | + WalIndexHdr *pLive; /* Pointer to shared header */ |
| 53667 | 53882 | |
| 53668 | 53883 | assert( pList ); |
| 53669 | 53884 | assert( pWal->writeLock ); |
| 53670 | 53885 | |
| 53671 | 53886 | /* If this frame set completes a transaction, then nTruncate>0. If |
| | @@ -53676,10 +53891,15 @@ |
| 53676 | 53891 | { int cnt; for(cnt=0, p=pList; p; p=p->pDirty, cnt++){} |
| 53677 | 53892 | WALTRACE(("WAL%p: frame write begin. %d frames. mxFrame=%d. %s\n", |
| 53678 | 53893 | pWal, cnt, pWal->hdr.mxFrame, isCommit ? "Commit" : "Spill")); |
| 53679 | 53894 | } |
| 53680 | 53895 | #endif |
| 53896 | + |
| 53897 | + pLive = (WalIndexHdr*)walIndexHdr(pWal); |
| 53898 | + if( memcmp(&pWal->hdr, (void *)pLive, sizeof(WalIndexHdr))!=0 ){ |
| 53899 | + iFirst = pLive->mxFrame+1; |
| 53900 | + } |
| 53681 | 53901 | |
| 53682 | 53902 | /* See if it is possible to write these frames into the start of the |
| 53683 | 53903 | ** log file, instead of appending to it at pWal->hdr.mxFrame. |
| 53684 | 53904 | */ |
| 53685 | 53905 | if( SQLITE_OK!=(rc = walRestartLog(pWal)) ){ |
| | @@ -53741,17 +53961,45 @@ |
| 53741 | 53961 | szFrame = szPage + WAL_FRAME_HDRSIZE; |
| 53742 | 53962 | |
| 53743 | 53963 | /* Write all frames into the log file exactly once */ |
| 53744 | 53964 | for(p=pList; p; p=p->pDirty){ |
| 53745 | 53965 | int nDbSize; /* 0 normally. Positive == commit flag */ |
| 53966 | + |
| 53967 | + /* Check if this page has already been written into the wal file by |
| 53968 | + ** the current transaction. If so, overwrite the existing frame and |
| 53969 | + ** set Wal.writeLock to WAL_WRITELOCK_RECKSUM - indicating that |
| 53970 | + ** checksums must be recomputed when the transaction is committed. */ |
| 53971 | + if( iFirst && (p->pDirty || isCommit==0) ){ |
| 53972 | + u32 iWrite = 0; |
| 53973 | + VVA_ONLY(rc =) sqlite3WalFindFrame(pWal, p->pgno, &iWrite); |
| 53974 | + assert( rc==SQLITE_OK || iWrite==0 ); |
| 53975 | + if( iWrite>=iFirst ){ |
| 53976 | + i64 iOff = walFrameOffset(iWrite, szPage) + WAL_FRAME_HDRSIZE; |
| 53977 | + if( pWal->iReCksum==0 || iWrite<pWal->iReCksum ){ |
| 53978 | + pWal->iReCksum = iWrite; |
| 53979 | + } |
| 53980 | + rc = sqlite3OsWrite(pWal->pWalFd, p->pData, szPage, iOff); |
| 53981 | + if( rc ) return rc; |
| 53982 | + p->flags &= ~PGHDR_WAL_APPEND; |
| 53983 | + continue; |
| 53984 | + } |
| 53985 | + } |
| 53986 | + |
| 53746 | 53987 | iFrame++; |
| 53747 | 53988 | assert( iOffset==walFrameOffset(iFrame, szPage) ); |
| 53748 | 53989 | nDbSize = (isCommit && p->pDirty==0) ? nTruncate : 0; |
| 53749 | 53990 | rc = walWriteOneFrame(&w, p, nDbSize, iOffset); |
| 53750 | 53991 | if( rc ) return rc; |
| 53751 | 53992 | pLast = p; |
| 53752 | 53993 | iOffset += szFrame; |
| 53994 | + p->flags |= PGHDR_WAL_APPEND; |
| 53995 | + } |
| 53996 | + |
| 53997 | + /* Recalculate checksums within the wal file if required. */ |
| 53998 | + if( isCommit && pWal->iReCksum ){ |
| 53999 | + rc = walRewriteChecksums(pWal, iFrame); |
| 54000 | + if( rc ) return rc; |
| 53753 | 54001 | } |
| 53754 | 54002 | |
| 53755 | 54003 | /* If this is the end of a transaction, then we might need to pad |
| 53756 | 54004 | ** the transaction and/or sync the WAL file. |
| 53757 | 54005 | ** |
| | @@ -53799,10 +54047,11 @@ |
| 53799 | 54047 | ** guarantees that there are no other writers, and no data that may |
| 53800 | 54048 | ** be in use by existing readers is being overwritten. |
| 53801 | 54049 | */ |
| 53802 | 54050 | iFrame = pWal->hdr.mxFrame; |
| 53803 | 54051 | for(p=pList; p && rc==SQLITE_OK; p=p->pDirty){ |
| 54052 | + if( (p->flags & PGHDR_WAL_APPEND)==0 ) continue; |
| 53804 | 54053 | iFrame++; |
| 53805 | 54054 | rc = walIndexAppend(pWal, iFrame, p->pgno); |
| 53806 | 54055 | } |
| 53807 | 54056 | while( rc==SQLITE_OK && nExtra>0 ){ |
| 53808 | 54057 | iFrame++; |
| | @@ -53911,10 +54160,11 @@ |
| 53911 | 54160 | } |
| 53912 | 54161 | } |
| 53913 | 54162 | |
| 53914 | 54163 | /* Copy data from the log to the database file. */ |
| 53915 | 54164 | if( rc==SQLITE_OK ){ |
| 54165 | + |
| 53916 | 54166 | if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){ |
| 53917 | 54167 | rc = SQLITE_CORRUPT_BKPT; |
| 53918 | 54168 | }else{ |
| 53919 | 54169 | rc = walCheckpoint(pWal, eMode2, xBusy2, pBusyArg, sync_flags, zBuf); |
| 53920 | 54170 | } |
| | @@ -54066,10 +54316,16 @@ |
| 54066 | 54316 | SQLITE_PRIVATE int sqlite3WalFramesize(Wal *pWal){ |
| 54067 | 54317 | assert( pWal==0 || pWal->readLock>=0 ); |
| 54068 | 54318 | return (pWal ? pWal->szPage : 0); |
| 54069 | 54319 | } |
| 54070 | 54320 | #endif |
| 54321 | + |
| 54322 | +/* Return the sqlite3_file object for the WAL file |
| 54323 | +*/ |
| 54324 | +SQLITE_PRIVATE sqlite3_file *sqlite3WalFile(Wal *pWal){ |
| 54325 | + return pWal->pWalFd; |
| 54326 | +} |
| 54071 | 54327 | |
| 54072 | 54328 | #endif /* #ifndef SQLITE_OMIT_WAL */ |
| 54073 | 54329 | |
| 54074 | 54330 | /************** End of wal.c *************************************************/ |
| 54075 | 54331 | /************** Begin file btmutex.c *****************************************/ |
| | @@ -54368,11 +54624,10 @@ |
| 54368 | 54624 | struct MemPage { |
| 54369 | 54625 | u8 isInit; /* True if previously initialized. MUST BE FIRST! */ |
| 54370 | 54626 | u8 nOverflow; /* Number of overflow cell bodies in aCell[] */ |
| 54371 | 54627 | u8 intKey; /* True if table b-trees. False for index b-trees */ |
| 54372 | 54628 | u8 intKeyLeaf; /* True if the leaf of an intKey table */ |
| 54373 | | - u8 noPayload; /* True if internal intKey page (thus w/o data) */ |
| 54374 | 54629 | u8 leaf; /* True if a leaf page */ |
| 54375 | 54630 | u8 hdrOffset; /* 100 for page 1. 0 otherwise */ |
| 54376 | 54631 | u8 childPtrSize; /* 0 if leaf==1. 4 if leaf==0 */ |
| 54377 | 54632 | u8 max1bytePayload; /* min(maxLocal,127) */ |
| 54378 | 54633 | u8 bBusy; /* Prevent endless loops on corrupt database files */ |
| | @@ -54955,25 +55210,10 @@ |
| 54955 | 55210 | |
| 54956 | 55211 | return (p->sharable==0 || p->locked); |
| 54957 | 55212 | } |
| 54958 | 55213 | #endif |
| 54959 | 55214 | |
| 54960 | | - |
| 54961 | | -#ifndef SQLITE_OMIT_INCRBLOB |
| 54962 | | -/* |
| 54963 | | -** Enter and leave a mutex on a Btree given a cursor owned by that |
| 54964 | | -** Btree. These entry points are used by incremental I/O and can be |
| 54965 | | -** omitted if that module is not used. |
| 54966 | | -*/ |
| 54967 | | -SQLITE_PRIVATE void sqlite3BtreeEnterCursor(BtCursor *pCur){ |
| 54968 | | - sqlite3BtreeEnter(pCur->pBtree); |
| 54969 | | -} |
| 54970 | | -SQLITE_PRIVATE void sqlite3BtreeLeaveCursor(BtCursor *pCur){ |
| 54971 | | - sqlite3BtreeLeave(pCur->pBtree); |
| 54972 | | -} |
| 54973 | | -#endif /* SQLITE_OMIT_INCRBLOB */ |
| 54974 | | - |
| 54975 | 55215 | |
| 54976 | 55216 | /* |
| 54977 | 55217 | ** Enter the mutex on every Btree associated with a database |
| 54978 | 55218 | ** connection. This is needed (for example) prior to parsing |
| 54979 | 55219 | ** a statement since we will be comparing table and column names |
| | @@ -55004,18 +55244,10 @@ |
| 55004 | 55244 | p = db->aDb[i].pBt; |
| 55005 | 55245 | if( p ) sqlite3BtreeLeave(p); |
| 55006 | 55246 | } |
| 55007 | 55247 | } |
| 55008 | 55248 | |
| 55009 | | -/* |
| 55010 | | -** Return true if a particular Btree requires a lock. Return FALSE if |
| 55011 | | -** no lock is ever required since it is not sharable. |
| 55012 | | -*/ |
| 55013 | | -SQLITE_PRIVATE int sqlite3BtreeSharable(Btree *p){ |
| 55014 | | - return p->sharable; |
| 55015 | | -} |
| 55016 | | - |
| 55017 | 55249 | #ifndef NDEBUG |
| 55018 | 55250 | /* |
| 55019 | 55251 | ** Return true if the current thread holds the database connection |
| 55020 | 55252 | ** mutex and all required BtShared mutexes. |
| 55021 | 55253 | ** |
| | @@ -55085,10 +55317,29 @@ |
| 55085 | 55317 | p->pBt->db = p->db; |
| 55086 | 55318 | } |
| 55087 | 55319 | } |
| 55088 | 55320 | } |
| 55089 | 55321 | #endif /* if SQLITE_THREADSAFE */ |
| 55322 | + |
| 55323 | +#ifndef SQLITE_OMIT_INCRBLOB |
| 55324 | +/* |
| 55325 | +** Enter a mutex on a Btree given a cursor owned by that Btree. |
| 55326 | +** |
| 55327 | +** These entry points are used by incremental I/O only. Enter() is required |
| 55328 | +** any time OMIT_SHARED_CACHE is not defined, regardless of whether or not |
| 55329 | +** the build is threadsafe. Leave() is only required by threadsafe builds. |
| 55330 | +*/ |
| 55331 | +SQLITE_PRIVATE void sqlite3BtreeEnterCursor(BtCursor *pCur){ |
| 55332 | + sqlite3BtreeEnter(pCur->pBtree); |
| 55333 | +} |
| 55334 | +# if SQLITE_THREADSAFE |
| 55335 | +SQLITE_PRIVATE void sqlite3BtreeLeaveCursor(BtCursor *pCur){ |
| 55336 | + sqlite3BtreeLeave(pCur->pBtree); |
| 55337 | +} |
| 55338 | +# endif |
| 55339 | +#endif /* ifndef SQLITE_OMIT_INCRBLOB */ |
| 55340 | + |
| 55090 | 55341 | #endif /* ifndef SQLITE_OMIT_SHARED_CACHE */ |
| 55091 | 55342 | |
| 55092 | 55343 | /************** End of btmutex.c *********************************************/ |
| 55093 | 55344 | /************** Begin file btree.c *******************************************/ |
| 55094 | 55345 | /* |
| | @@ -55541,10 +55792,14 @@ |
| 55541 | 55792 | */ |
| 55542 | 55793 | #ifdef SQLITE_DEBUG |
| 55543 | 55794 | static int cursorHoldsMutex(BtCursor *p){ |
| 55544 | 55795 | return sqlite3_mutex_held(p->pBt->mutex); |
| 55545 | 55796 | } |
| 55797 | +static int cursorOwnsBtShared(BtCursor *p){ |
| 55798 | + assert( cursorHoldsMutex(p) ); |
| 55799 | + return (p->pBtree->db==p->pBt->db); |
| 55800 | +} |
| 55546 | 55801 | #endif |
| 55547 | 55802 | |
| 55548 | 55803 | /* |
| 55549 | 55804 | ** Invalidate the overflow cache of the cursor passed as the first argument. |
| 55550 | 55805 | ** on the shared btree structure pBt. |
| | @@ -55877,11 +56132,11 @@ |
| 55877 | 56132 | ** saveCursorPosition(). |
| 55878 | 56133 | */ |
| 55879 | 56134 | static int btreeRestoreCursorPosition(BtCursor *pCur){ |
| 55880 | 56135 | int rc; |
| 55881 | 56136 | int skipNext; |
| 55882 | | - assert( cursorHoldsMutex(pCur) ); |
| 56137 | + assert( cursorOwnsBtShared(pCur) ); |
| 55883 | 56138 | assert( pCur->eState>=CURSOR_REQUIRESEEK ); |
| 55884 | 56139 | if( pCur->eState==CURSOR_FAULT ){ |
| 55885 | 56140 | return pCur->skipNext; |
| 55886 | 56141 | } |
| 55887 | 56142 | pCur->eState = CURSOR_INVALID; |
| | @@ -56166,11 +56421,10 @@ |
| 56166 | 56421 | u8 *pCell, /* Pointer to the cell text. */ |
| 56167 | 56422 | CellInfo *pInfo /* Fill in this structure */ |
| 56168 | 56423 | ){ |
| 56169 | 56424 | assert( sqlite3_mutex_held(pPage->pBt->mutex) ); |
| 56170 | 56425 | assert( pPage->leaf==0 ); |
| 56171 | | - assert( pPage->noPayload ); |
| 56172 | 56426 | assert( pPage->childPtrSize==4 ); |
| 56173 | 56427 | #ifndef SQLITE_DEBUG |
| 56174 | 56428 | UNUSED_PARAMETER(pPage); |
| 56175 | 56429 | #endif |
| 56176 | 56430 | pInfo->nSize = 4 + getVarint(&pCell[4], (u64*)&pInfo->nKey); |
| | @@ -56188,12 +56442,10 @@ |
| 56188 | 56442 | u32 nPayload; /* Number of bytes of cell payload */ |
| 56189 | 56443 | u64 iKey; /* Extracted Key value */ |
| 56190 | 56444 | |
| 56191 | 56445 | assert( sqlite3_mutex_held(pPage->pBt->mutex) ); |
| 56192 | 56446 | assert( pPage->leaf==0 || pPage->leaf==1 ); |
| 56193 | | - assert( pPage->intKeyLeaf || pPage->noPayload ); |
| 56194 | | - assert( pPage->noPayload==0 ); |
| 56195 | 56447 | assert( pPage->intKeyLeaf ); |
| 56196 | 56448 | assert( pPage->childPtrSize==0 ); |
| 56197 | 56449 | pIter = pCell; |
| 56198 | 56450 | |
| 56199 | 56451 | /* The next block of code is equivalent to: |
| | @@ -56258,11 +56510,10 @@ |
| 56258 | 56510 | u32 nPayload; /* Number of bytes of cell payload */ |
| 56259 | 56511 | |
| 56260 | 56512 | assert( sqlite3_mutex_held(pPage->pBt->mutex) ); |
| 56261 | 56513 | assert( pPage->leaf==0 || pPage->leaf==1 ); |
| 56262 | 56514 | assert( pPage->intKeyLeaf==0 ); |
| 56263 | | - assert( pPage->noPayload==0 ); |
| 56264 | 56515 | pIter = pCell + pPage->childPtrSize; |
| 56265 | 56516 | nPayload = *pIter; |
| 56266 | 56517 | if( nPayload>=0x80 ){ |
| 56267 | 56518 | u8 *pEnd = &pIter[8]; |
| 56268 | 56519 | nPayload &= 0x7f; |
| | @@ -56319,11 +56570,10 @@ |
| 56319 | 56570 | ** this function verifies that this invariant is not violated. */ |
| 56320 | 56571 | CellInfo debuginfo; |
| 56321 | 56572 | pPage->xParseCell(pPage, pCell, &debuginfo); |
| 56322 | 56573 | #endif |
| 56323 | 56574 | |
| 56324 | | - assert( pPage->noPayload==0 ); |
| 56325 | 56575 | nSize = *pIter; |
| 56326 | 56576 | if( nSize>=0x80 ){ |
| 56327 | 56577 | pEnd = &pIter[8]; |
| 56328 | 56578 | nSize &= 0x7f; |
| 56329 | 56579 | do{ |
| | @@ -56777,15 +57027,13 @@ |
| 56777 | 57027 | ** table b-tree page. */ |
| 56778 | 57028 | assert( (PTF_LEAFDATA|PTF_INTKEY|PTF_LEAF)==13 ); |
| 56779 | 57029 | pPage->intKey = 1; |
| 56780 | 57030 | if( pPage->leaf ){ |
| 56781 | 57031 | pPage->intKeyLeaf = 1; |
| 56782 | | - pPage->noPayload = 0; |
| 56783 | 57032 | pPage->xParseCell = btreeParseCellPtr; |
| 56784 | 57033 | }else{ |
| 56785 | 57034 | pPage->intKeyLeaf = 0; |
| 56786 | | - pPage->noPayload = 1; |
| 56787 | 57035 | pPage->xCellSize = cellSizePtrNoPayload; |
| 56788 | 57036 | pPage->xParseCell = btreeParseCellPtrNoPayload; |
| 56789 | 57037 | } |
| 56790 | 57038 | pPage->maxLocal = pBt->maxLeaf; |
| 56791 | 57039 | pPage->minLocal = pBt->minLeaf; |
| | @@ -56796,11 +57044,10 @@ |
| 56796 | 57044 | /* EVIDENCE-OF: R-16571-11615 A value of 10 means the page is a leaf |
| 56797 | 57045 | ** index b-tree page. */ |
| 56798 | 57046 | assert( (PTF_ZERODATA|PTF_LEAF)==10 ); |
| 56799 | 57047 | pPage->intKey = 0; |
| 56800 | 57048 | pPage->intKeyLeaf = 0; |
| 56801 | | - pPage->noPayload = 0; |
| 56802 | 57049 | pPage->xParseCell = btreeParseCellPtrIndex; |
| 56803 | 57050 | pPage->maxLocal = pBt->maxLocal; |
| 56804 | 57051 | pPage->minLocal = pBt->minLocal; |
| 56805 | 57052 | }else{ |
| 56806 | 57053 | /* EVIDENCE-OF: R-47608-56469 Any other value for the b-tree page type is |
| | @@ -58217,11 +58464,10 @@ |
| 58217 | 58464 | ** no progress. By returning SQLITE_BUSY and not invoking the busy callback |
| 58218 | 58465 | ** when A already has a read lock, we encourage A to give up and let B |
| 58219 | 58466 | ** proceed. |
| 58220 | 58467 | */ |
| 58221 | 58468 | SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag){ |
| 58222 | | - sqlite3 *pBlock = 0; |
| 58223 | 58469 | BtShared *pBt = p->pBt; |
| 58224 | 58470 | int rc = SQLITE_OK; |
| 58225 | 58471 | |
| 58226 | 58472 | sqlite3BtreeEnter(p); |
| 58227 | 58473 | btreeIntegrity(p); |
| | @@ -58240,31 +58486,34 @@ |
| 58240 | 58486 | rc = SQLITE_READONLY; |
| 58241 | 58487 | goto trans_begun; |
| 58242 | 58488 | } |
| 58243 | 58489 | |
| 58244 | 58490 | #ifndef SQLITE_OMIT_SHARED_CACHE |
| 58245 | | - /* If another database handle has already opened a write transaction |
| 58246 | | - ** on this shared-btree structure and a second write transaction is |
| 58247 | | - ** requested, return SQLITE_LOCKED. |
| 58248 | | - */ |
| 58249 | | - if( (wrflag && pBt->inTransaction==TRANS_WRITE) |
| 58250 | | - || (pBt->btsFlags & BTS_PENDING)!=0 |
| 58251 | | - ){ |
| 58252 | | - pBlock = pBt->pWriter->db; |
| 58253 | | - }else if( wrflag>1 ){ |
| 58254 | | - BtLock *pIter; |
| 58255 | | - for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){ |
| 58256 | | - if( pIter->pBtree!=p ){ |
| 58257 | | - pBlock = pIter->pBtree->db; |
| 58258 | | - break; |
| 58259 | | - } |
| 58260 | | - } |
| 58261 | | - } |
| 58262 | | - if( pBlock ){ |
| 58263 | | - sqlite3ConnectionBlocked(p->db, pBlock); |
| 58264 | | - rc = SQLITE_LOCKED_SHAREDCACHE; |
| 58265 | | - goto trans_begun; |
| 58491 | + { |
| 58492 | + sqlite3 *pBlock = 0; |
| 58493 | + /* If another database handle has already opened a write transaction |
| 58494 | + ** on this shared-btree structure and a second write transaction is |
| 58495 | + ** requested, return SQLITE_LOCKED. |
| 58496 | + */ |
| 58497 | + if( (wrflag && pBt->inTransaction==TRANS_WRITE) |
| 58498 | + || (pBt->btsFlags & BTS_PENDING)!=0 |
| 58499 | + ){ |
| 58500 | + pBlock = pBt->pWriter->db; |
| 58501 | + }else if( wrflag>1 ){ |
| 58502 | + BtLock *pIter; |
| 58503 | + for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){ |
| 58504 | + if( pIter->pBtree!=p ){ |
| 58505 | + pBlock = pIter->pBtree->db; |
| 58506 | + break; |
| 58507 | + } |
| 58508 | + } |
| 58509 | + } |
| 58510 | + if( pBlock ){ |
| 58511 | + sqlite3ConnectionBlocked(p->db, pBlock); |
| 58512 | + rc = SQLITE_LOCKED_SHAREDCACHE; |
| 58513 | + goto trans_begun; |
| 58514 | + } |
| 58266 | 58515 | } |
| 58267 | 58516 | #endif |
| 58268 | 58517 | |
| 58269 | 58518 | /* Any read-only or read-write transaction implies a read-lock on |
| 58270 | 58519 | ** page 1. So if some other shared-cache client already has a write-lock |
| | @@ -59377,11 +59626,11 @@ |
| 59377 | 59626 | ** Failure is not possible. This function always returns SQLITE_OK. |
| 59378 | 59627 | ** It might just as well be a procedure (returning void) but we continue |
| 59379 | 59628 | ** to return an integer result code for historical reasons. |
| 59380 | 59629 | */ |
| 59381 | 59630 | SQLITE_PRIVATE int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){ |
| 59382 | | - assert( cursorHoldsMutex(pCur) ); |
| 59631 | + assert( cursorOwnsBtShared(pCur) ); |
| 59383 | 59632 | assert( pCur->eState==CURSOR_VALID ); |
| 59384 | 59633 | assert( pCur->iPage>=0 ); |
| 59385 | 59634 | assert( pCur->iPage<BTCURSOR_MAX_DEPTH ); |
| 59386 | 59635 | assert( pCur->apPage[pCur->iPage]->intKeyLeaf==1 ); |
| 59387 | 59636 | getCellInfo(pCur); |
| | @@ -59757,11 +60006,11 @@ |
| 59757 | 60006 | if ( pCur->eState==CURSOR_INVALID ){ |
| 59758 | 60007 | return SQLITE_ABORT; |
| 59759 | 60008 | } |
| 59760 | 60009 | #endif |
| 59761 | 60010 | |
| 59762 | | - assert( cursorHoldsMutex(pCur) ); |
| 60011 | + assert( cursorOwnsBtShared(pCur) ); |
| 59763 | 60012 | rc = restoreCursorPosition(pCur); |
| 59764 | 60013 | if( rc==SQLITE_OK ){ |
| 59765 | 60014 | assert( pCur->eState==CURSOR_VALID ); |
| 59766 | 60015 | assert( pCur->iPage>=0 && pCur->apPage[pCur->iPage] ); |
| 59767 | 60016 | assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell ); |
| | @@ -59795,11 +60044,11 @@ |
| 59795 | 60044 | ){ |
| 59796 | 60045 | u32 amt; |
| 59797 | 60046 | assert( pCur!=0 && pCur->iPage>=0 && pCur->apPage[pCur->iPage]); |
| 59798 | 60047 | assert( pCur->eState==CURSOR_VALID ); |
| 59799 | 60048 | assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); |
| 59800 | | - assert( cursorHoldsMutex(pCur) ); |
| 60049 | + assert( cursorOwnsBtShared(pCur) ); |
| 59801 | 60050 | assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell ); |
| 59802 | 60051 | assert( pCur->info.nSize>0 ); |
| 59803 | 60052 | assert( pCur->info.pPayload>pCur->apPage[pCur->iPage]->aData || CORRUPT_DB ); |
| 59804 | 60053 | assert( pCur->info.pPayload<pCur->apPage[pCur->iPage]->aDataEnd ||CORRUPT_DB); |
| 59805 | 60054 | amt = (int)(pCur->apPage[pCur->iPage]->aDataEnd - pCur->info.pPayload); |
| | @@ -59841,11 +60090,11 @@ |
| 59841 | 60090 | ** vice-versa). |
| 59842 | 60091 | */ |
| 59843 | 60092 | static int moveToChild(BtCursor *pCur, u32 newPgno){ |
| 59844 | 60093 | BtShared *pBt = pCur->pBt; |
| 59845 | 60094 | |
| 59846 | | - assert( cursorHoldsMutex(pCur) ); |
| 60095 | + assert( cursorOwnsBtShared(pCur) ); |
| 59847 | 60096 | assert( pCur->eState==CURSOR_VALID ); |
| 59848 | 60097 | assert( pCur->iPage<BTCURSOR_MAX_DEPTH ); |
| 59849 | 60098 | assert( pCur->iPage>=0 ); |
| 59850 | 60099 | if( pCur->iPage>=(BTCURSOR_MAX_DEPTH-1) ){ |
| 59851 | 60100 | return SQLITE_CORRUPT_BKPT; |
| | @@ -59887,11 +60136,11 @@ |
| 59887 | 60136 | ** to the page we are coming from. If we are coming from the |
| 59888 | 60137 | ** right-most child page then pCur->idx is set to one more than |
| 59889 | 60138 | ** the largest cell index. |
| 59890 | 60139 | */ |
| 59891 | 60140 | static void moveToParent(BtCursor *pCur){ |
| 59892 | | - assert( cursorHoldsMutex(pCur) ); |
| 60141 | + assert( cursorOwnsBtShared(pCur) ); |
| 59893 | 60142 | assert( pCur->eState==CURSOR_VALID ); |
| 59894 | 60143 | assert( pCur->iPage>0 ); |
| 59895 | 60144 | assert( pCur->apPage[pCur->iPage] ); |
| 59896 | 60145 | assertParentIndex( |
| 59897 | 60146 | pCur->apPage[pCur->iPage-1], |
| | @@ -59927,11 +60176,11 @@ |
| 59927 | 60176 | */ |
| 59928 | 60177 | static int moveToRoot(BtCursor *pCur){ |
| 59929 | 60178 | MemPage *pRoot; |
| 59930 | 60179 | int rc = SQLITE_OK; |
| 59931 | 60180 | |
| 59932 | | - assert( cursorHoldsMutex(pCur) ); |
| 60181 | + assert( cursorOwnsBtShared(pCur) ); |
| 59933 | 60182 | assert( CURSOR_INVALID < CURSOR_REQUIRESEEK ); |
| 59934 | 60183 | assert( CURSOR_VALID < CURSOR_REQUIRESEEK ); |
| 59935 | 60184 | assert( CURSOR_FAULT > CURSOR_REQUIRESEEK ); |
| 59936 | 60185 | if( pCur->eState>=CURSOR_REQUIRESEEK ){ |
| 59937 | 60186 | if( pCur->eState==CURSOR_FAULT ){ |
| | @@ -60006,11 +60255,11 @@ |
| 60006 | 60255 | static int moveToLeftmost(BtCursor *pCur){ |
| 60007 | 60256 | Pgno pgno; |
| 60008 | 60257 | int rc = SQLITE_OK; |
| 60009 | 60258 | MemPage *pPage; |
| 60010 | 60259 | |
| 60011 | | - assert( cursorHoldsMutex(pCur) ); |
| 60260 | + assert( cursorOwnsBtShared(pCur) ); |
| 60012 | 60261 | assert( pCur->eState==CURSOR_VALID ); |
| 60013 | 60262 | while( rc==SQLITE_OK && !(pPage = pCur->apPage[pCur->iPage])->leaf ){ |
| 60014 | 60263 | assert( pCur->aiIdx[pCur->iPage]<pPage->nCell ); |
| 60015 | 60264 | pgno = get4byte(findCell(pPage, pCur->aiIdx[pCur->iPage])); |
| 60016 | 60265 | rc = moveToChild(pCur, pgno); |
| | @@ -60031,11 +60280,11 @@ |
| 60031 | 60280 | static int moveToRightmost(BtCursor *pCur){ |
| 60032 | 60281 | Pgno pgno; |
| 60033 | 60282 | int rc = SQLITE_OK; |
| 60034 | 60283 | MemPage *pPage = 0; |
| 60035 | 60284 | |
| 60036 | | - assert( cursorHoldsMutex(pCur) ); |
| 60285 | + assert( cursorOwnsBtShared(pCur) ); |
| 60037 | 60286 | assert( pCur->eState==CURSOR_VALID ); |
| 60038 | 60287 | while( !(pPage = pCur->apPage[pCur->iPage])->leaf ){ |
| 60039 | 60288 | pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]); |
| 60040 | 60289 | pCur->aiIdx[pCur->iPage] = pPage->nCell; |
| 60041 | 60290 | rc = moveToChild(pCur, pgno); |
| | @@ -60052,11 +60301,11 @@ |
| 60052 | 60301 | ** or set *pRes to 1 if the table is empty. |
| 60053 | 60302 | */ |
| 60054 | 60303 | SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){ |
| 60055 | 60304 | int rc; |
| 60056 | 60305 | |
| 60057 | | - assert( cursorHoldsMutex(pCur) ); |
| 60306 | + assert( cursorOwnsBtShared(pCur) ); |
| 60058 | 60307 | assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); |
| 60059 | 60308 | rc = moveToRoot(pCur); |
| 60060 | 60309 | if( rc==SQLITE_OK ){ |
| 60061 | 60310 | if( pCur->eState==CURSOR_INVALID ){ |
| 60062 | 60311 | assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 ); |
| | @@ -60075,11 +60324,11 @@ |
| 60075 | 60324 | ** or set *pRes to 1 if the table is empty. |
| 60076 | 60325 | */ |
| 60077 | 60326 | SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor *pCur, int *pRes){ |
| 60078 | 60327 | int rc; |
| 60079 | 60328 | |
| 60080 | | - assert( cursorHoldsMutex(pCur) ); |
| 60329 | + assert( cursorOwnsBtShared(pCur) ); |
| 60081 | 60330 | assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); |
| 60082 | 60331 | |
| 60083 | 60332 | /* If the cursor already points to the last entry, this is a no-op. */ |
| 60084 | 60333 | if( CURSOR_VALID==pCur->eState && (pCur->curFlags & BTCF_AtLast)!=0 ){ |
| 60085 | 60334 | #ifdef SQLITE_DEBUG |
| | @@ -60153,11 +60402,11 @@ |
| 60153 | 60402 | int *pRes /* Write search results here */ |
| 60154 | 60403 | ){ |
| 60155 | 60404 | int rc; |
| 60156 | 60405 | RecordCompare xRecordCompare; |
| 60157 | 60406 | |
| 60158 | | - assert( cursorHoldsMutex(pCur) ); |
| 60407 | + assert( cursorOwnsBtShared(pCur) ); |
| 60159 | 60408 | assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); |
| 60160 | 60409 | assert( pRes ); |
| 60161 | 60410 | assert( (pIdxKey==0)==(pCur->pKeyInfo==0) ); |
| 60162 | 60411 | |
| 60163 | 60412 | /* If the cursor is already positioned at the point we are trying |
| | @@ -60401,11 +60650,11 @@ |
| 60401 | 60650 | static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){ |
| 60402 | 60651 | int rc; |
| 60403 | 60652 | int idx; |
| 60404 | 60653 | MemPage *pPage; |
| 60405 | 60654 | |
| 60406 | | - assert( cursorHoldsMutex(pCur) ); |
| 60655 | + assert( cursorOwnsBtShared(pCur) ); |
| 60407 | 60656 | assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID ); |
| 60408 | 60657 | assert( *pRes==0 ); |
| 60409 | 60658 | if( pCur->eState!=CURSOR_VALID ){ |
| 60410 | 60659 | assert( (pCur->curFlags & BTCF_ValidOvfl)==0 ); |
| 60411 | 60660 | rc = restoreCursorPosition(pCur); |
| | @@ -60465,11 +60714,11 @@ |
| 60465 | 60714 | return moveToLeftmost(pCur); |
| 60466 | 60715 | } |
| 60467 | 60716 | } |
| 60468 | 60717 | SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int *pRes){ |
| 60469 | 60718 | MemPage *pPage; |
| 60470 | | - assert( cursorHoldsMutex(pCur) ); |
| 60719 | + assert( cursorOwnsBtShared(pCur) ); |
| 60471 | 60720 | assert( pRes!=0 ); |
| 60472 | 60721 | assert( *pRes==0 || *pRes==1 ); |
| 60473 | 60722 | assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID ); |
| 60474 | 60723 | pCur->info.nSize = 0; |
| 60475 | 60724 | pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); |
| | @@ -60510,11 +60759,11 @@ |
| 60510 | 60759 | */ |
| 60511 | 60760 | static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int *pRes){ |
| 60512 | 60761 | int rc; |
| 60513 | 60762 | MemPage *pPage; |
| 60514 | 60763 | |
| 60515 | | - assert( cursorHoldsMutex(pCur) ); |
| 60764 | + assert( cursorOwnsBtShared(pCur) ); |
| 60516 | 60765 | assert( pRes!=0 ); |
| 60517 | 60766 | assert( *pRes==0 ); |
| 60518 | 60767 | assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID ); |
| 60519 | 60768 | assert( (pCur->curFlags & (BTCF_AtLast|BTCF_ValidOvfl|BTCF_ValidNKey))==0 ); |
| 60520 | 60769 | assert( pCur->info.nSize==0 ); |
| | @@ -60566,11 +60815,11 @@ |
| 60566 | 60815 | } |
| 60567 | 60816 | } |
| 60568 | 60817 | return rc; |
| 60569 | 60818 | } |
| 60570 | 60819 | SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){ |
| 60571 | | - assert( cursorHoldsMutex(pCur) ); |
| 60820 | + assert( cursorOwnsBtShared(pCur) ); |
| 60572 | 60821 | assert( pRes!=0 ); |
| 60573 | 60822 | assert( *pRes==0 || *pRes==1 ); |
| 60574 | 60823 | assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID ); |
| 60575 | 60824 | *pRes = 0; |
| 60576 | 60825 | pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidOvfl|BTCF_ValidNKey); |
| | @@ -62279,13 +62528,12 @@ |
| 62279 | 62528 | ** This must be done in advance. Once the balance starts, the cell |
| 62280 | 62529 | ** offset section of the btree page will be overwritten and we will no |
| 62281 | 62530 | ** long be able to find the cells if a pointer to each cell is not saved |
| 62282 | 62531 | ** first. |
| 62283 | 62532 | */ |
| 62284 | | - memset(&b.szCell[b.nCell], 0, sizeof(b.szCell[0])*limit); |
| 62533 | + memset(&b.szCell[b.nCell], 0, sizeof(b.szCell[0])*(limit+pOld->nOverflow)); |
| 62285 | 62534 | if( pOld->nOverflow>0 ){ |
| 62286 | | - memset(&b.szCell[b.nCell+limit], 0, sizeof(b.szCell[0])*pOld->nOverflow); |
| 62287 | 62535 | limit = pOld->aiOvfl[0]; |
| 62288 | 62536 | for(j=0; j<limit; j++){ |
| 62289 | 62537 | b.apCell[b.nCell] = aData + (maskPage & get2byteAligned(piCell)); |
| 62290 | 62538 | piCell += 2; |
| 62291 | 62539 | b.nCell++; |
| | @@ -63046,11 +63294,11 @@ |
| 63046 | 63294 | if( pCur->eState==CURSOR_FAULT ){ |
| 63047 | 63295 | assert( pCur->skipNext!=SQLITE_OK ); |
| 63048 | 63296 | return pCur->skipNext; |
| 63049 | 63297 | } |
| 63050 | 63298 | |
| 63051 | | - assert( cursorHoldsMutex(pCur) ); |
| 63299 | + assert( cursorOwnsBtShared(pCur) ); |
| 63052 | 63300 | assert( (pCur->curFlags & BTCF_WriteFlag)!=0 |
| 63053 | 63301 | && pBt->inTransaction==TRANS_WRITE |
| 63054 | 63302 | && (pBt->btsFlags & BTS_READ_ONLY)==0 ); |
| 63055 | 63303 | assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) ); |
| 63056 | 63304 | |
| | @@ -63193,11 +63441,11 @@ |
| 63193 | 63441 | int iCellIdx; /* Index of cell to delete */ |
| 63194 | 63442 | int iCellDepth; /* Depth of node containing pCell */ |
| 63195 | 63443 | u16 szCell; /* Size of the cell being deleted */ |
| 63196 | 63444 | int bSkipnext = 0; /* Leaf cursor in SKIPNEXT state */ |
| 63197 | 63445 | |
| 63198 | | - assert( cursorHoldsMutex(pCur) ); |
| 63446 | + assert( cursorOwnsBtShared(pCur) ); |
| 63199 | 63447 | assert( pBt->inTransaction==TRANS_WRITE ); |
| 63200 | 63448 | assert( (pBt->btsFlags & BTS_READ_ONLY)==0 ); |
| 63201 | 63449 | assert( pCur->curFlags & BTCF_WriteFlag ); |
| 63202 | 63450 | assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) ); |
| 63203 | 63451 | assert( !hasReadConflicts(p, pCur->pgnoRoot) ); |
| | @@ -63633,10 +63881,18 @@ |
| 63633 | 63881 | */ |
| 63634 | 63882 | if( NEVER(pBt->pCursor) ){ |
| 63635 | 63883 | sqlite3ConnectionBlocked(p->db, pBt->pCursor->pBtree->db); |
| 63636 | 63884 | return SQLITE_LOCKED_SHAREDCACHE; |
| 63637 | 63885 | } |
| 63886 | + |
| 63887 | + /* |
| 63888 | + ** It is illegal to drop the sqlite_master table on page 1. But again, |
| 63889 | + ** this error is caught long before reaching this point. |
| 63890 | + */ |
| 63891 | + if( NEVER(iTable<2) ){ |
| 63892 | + return SQLITE_CORRUPT_BKPT; |
| 63893 | + } |
| 63638 | 63894 | |
| 63639 | 63895 | rc = btreeGetPage(pBt, (Pgno)iTable, &pPage, 0); |
| 63640 | 63896 | if( rc ) return rc; |
| 63641 | 63897 | rc = sqlite3BtreeClearTable(p, iTable, 0); |
| 63642 | 63898 | if( rc ){ |
| | @@ -63644,80 +63900,71 @@ |
| 63644 | 63900 | return rc; |
| 63645 | 63901 | } |
| 63646 | 63902 | |
| 63647 | 63903 | *piMoved = 0; |
| 63648 | 63904 | |
| 63649 | | - if( iTable>1 ){ |
| 63650 | | -#ifdef SQLITE_OMIT_AUTOVACUUM |
| 63651 | | - freePage(pPage, &rc); |
| 63652 | | - releasePage(pPage); |
| 63653 | | -#else |
| 63654 | | - if( pBt->autoVacuum ){ |
| 63655 | | - Pgno maxRootPgno; |
| 63656 | | - sqlite3BtreeGetMeta(p, BTREE_LARGEST_ROOT_PAGE, &maxRootPgno); |
| 63657 | | - |
| 63658 | | - if( iTable==maxRootPgno ){ |
| 63659 | | - /* If the table being dropped is the table with the largest root-page |
| 63660 | | - ** number in the database, put the root page on the free list. |
| 63661 | | - */ |
| 63662 | | - freePage(pPage, &rc); |
| 63663 | | - releasePage(pPage); |
| 63664 | | - if( rc!=SQLITE_OK ){ |
| 63665 | | - return rc; |
| 63666 | | - } |
| 63667 | | - }else{ |
| 63668 | | - /* The table being dropped does not have the largest root-page |
| 63669 | | - ** number in the database. So move the page that does into the |
| 63670 | | - ** gap left by the deleted root-page. |
| 63671 | | - */ |
| 63672 | | - MemPage *pMove; |
| 63673 | | - releasePage(pPage); |
| 63674 | | - rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0); |
| 63675 | | - if( rc!=SQLITE_OK ){ |
| 63676 | | - return rc; |
| 63677 | | - } |
| 63678 | | - rc = relocatePage(pBt, pMove, PTRMAP_ROOTPAGE, 0, iTable, 0); |
| 63679 | | - releasePage(pMove); |
| 63680 | | - if( rc!=SQLITE_OK ){ |
| 63681 | | - return rc; |
| 63682 | | - } |
| 63683 | | - pMove = 0; |
| 63684 | | - rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0); |
| 63685 | | - freePage(pMove, &rc); |
| 63686 | | - releasePage(pMove); |
| 63687 | | - if( rc!=SQLITE_OK ){ |
| 63688 | | - return rc; |
| 63689 | | - } |
| 63690 | | - *piMoved = maxRootPgno; |
| 63691 | | - } |
| 63692 | | - |
| 63693 | | - /* Set the new 'max-root-page' value in the database header. This |
| 63694 | | - ** is the old value less one, less one more if that happens to |
| 63695 | | - ** be a root-page number, less one again if that is the |
| 63696 | | - ** PENDING_BYTE_PAGE. |
| 63697 | | - */ |
| 63698 | | - maxRootPgno--; |
| 63699 | | - while( maxRootPgno==PENDING_BYTE_PAGE(pBt) |
| 63700 | | - || PTRMAP_ISPAGE(pBt, maxRootPgno) ){ |
| 63701 | | - maxRootPgno--; |
| 63702 | | - } |
| 63703 | | - assert( maxRootPgno!=PENDING_BYTE_PAGE(pBt) ); |
| 63704 | | - |
| 63705 | | - rc = sqlite3BtreeUpdateMeta(p, 4, maxRootPgno); |
| 63706 | | - }else{ |
| 63707 | | - freePage(pPage, &rc); |
| 63708 | | - releasePage(pPage); |
| 63709 | | - } |
| 63710 | | -#endif |
| 63711 | | - }else{ |
| 63712 | | - /* If sqlite3BtreeDropTable was called on page 1. |
| 63713 | | - ** This really never should happen except in a corrupt |
| 63714 | | - ** database. |
| 63715 | | - */ |
| 63716 | | - zeroPage(pPage, PTF_INTKEY|PTF_LEAF ); |
| 63717 | | - releasePage(pPage); |
| 63718 | | - } |
| 63905 | +#ifdef SQLITE_OMIT_AUTOVACUUM |
| 63906 | + freePage(pPage, &rc); |
| 63907 | + releasePage(pPage); |
| 63908 | +#else |
| 63909 | + if( pBt->autoVacuum ){ |
| 63910 | + Pgno maxRootPgno; |
| 63911 | + sqlite3BtreeGetMeta(p, BTREE_LARGEST_ROOT_PAGE, &maxRootPgno); |
| 63912 | + |
| 63913 | + if( iTable==maxRootPgno ){ |
| 63914 | + /* If the table being dropped is the table with the largest root-page |
| 63915 | + ** number in the database, put the root page on the free list. |
| 63916 | + */ |
| 63917 | + freePage(pPage, &rc); |
| 63918 | + releasePage(pPage); |
| 63919 | + if( rc!=SQLITE_OK ){ |
| 63920 | + return rc; |
| 63921 | + } |
| 63922 | + }else{ |
| 63923 | + /* The table being dropped does not have the largest root-page |
| 63924 | + ** number in the database. So move the page that does into the |
| 63925 | + ** gap left by the deleted root-page. |
| 63926 | + */ |
| 63927 | + MemPage *pMove; |
| 63928 | + releasePage(pPage); |
| 63929 | + rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0); |
| 63930 | + if( rc!=SQLITE_OK ){ |
| 63931 | + return rc; |
| 63932 | + } |
| 63933 | + rc = relocatePage(pBt, pMove, PTRMAP_ROOTPAGE, 0, iTable, 0); |
| 63934 | + releasePage(pMove); |
| 63935 | + if( rc!=SQLITE_OK ){ |
| 63936 | + return rc; |
| 63937 | + } |
| 63938 | + pMove = 0; |
| 63939 | + rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0); |
| 63940 | + freePage(pMove, &rc); |
| 63941 | + releasePage(pMove); |
| 63942 | + if( rc!=SQLITE_OK ){ |
| 63943 | + return rc; |
| 63944 | + } |
| 63945 | + *piMoved = maxRootPgno; |
| 63946 | + } |
| 63947 | + |
| 63948 | + /* Set the new 'max-root-page' value in the database header. This |
| 63949 | + ** is the old value less one, less one more if that happens to |
| 63950 | + ** be a root-page number, less one again if that is the |
| 63951 | + ** PENDING_BYTE_PAGE. |
| 63952 | + */ |
| 63953 | + maxRootPgno--; |
| 63954 | + while( maxRootPgno==PENDING_BYTE_PAGE(pBt) |
| 63955 | + || PTRMAP_ISPAGE(pBt, maxRootPgno) ){ |
| 63956 | + maxRootPgno--; |
| 63957 | + } |
| 63958 | + assert( maxRootPgno!=PENDING_BYTE_PAGE(pBt) ); |
| 63959 | + |
| 63960 | + rc = sqlite3BtreeUpdateMeta(p, 4, maxRootPgno); |
| 63961 | + }else{ |
| 63962 | + freePage(pPage, &rc); |
| 63963 | + releasePage(pPage); |
| 63964 | + } |
| 63965 | +#endif |
| 63719 | 63966 | return rc; |
| 63720 | 63967 | } |
| 63721 | 63968 | SQLITE_PRIVATE int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){ |
| 63722 | 63969 | int rc; |
| 63723 | 63970 | sqlite3BtreeEnter(p); |
| | @@ -64655,11 +64902,11 @@ |
| 64655 | 64902 | ** parameters that attempt to write past the end of the existing data, |
| 64656 | 64903 | ** no modifications are made and SQLITE_CORRUPT is returned. |
| 64657 | 64904 | */ |
| 64658 | 64905 | SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){ |
| 64659 | 64906 | int rc; |
| 64660 | | - assert( cursorHoldsMutex(pCsr) ); |
| 64907 | + assert( cursorOwnsBtShared(pCsr) ); |
| 64661 | 64908 | assert( sqlite3_mutex_held(pCsr->pBtree->db->mutex) ); |
| 64662 | 64909 | assert( pCsr->curFlags & BTCF_Incrblob ); |
| 64663 | 64910 | |
| 64664 | 64911 | rc = restoreCursorPosition(pCsr); |
| 64665 | 64912 | if( rc!=SQLITE_OK ){ |
| | @@ -64762,10 +65009,19 @@ |
| 64762 | 65009 | |
| 64763 | 65010 | /* |
| 64764 | 65011 | ** Return the size of the header added to each page by this module. |
| 64765 | 65012 | */ |
| 64766 | 65013 | SQLITE_PRIVATE int sqlite3HeaderSizeBtree(void){ return ROUND8(sizeof(MemPage)); } |
| 65014 | + |
| 65015 | +#if !defined(SQLITE_OMIT_SHARED_CACHE) |
| 65016 | +/* |
| 65017 | +** Return true if the Btree passed as the only argument is sharable. |
| 65018 | +*/ |
| 65019 | +SQLITE_PRIVATE int sqlite3BtreeSharable(Btree *p){ |
| 65020 | + return p->sharable; |
| 65021 | +} |
| 65022 | +#endif |
| 64767 | 65023 | |
| 64768 | 65024 | /************** End of btree.c ***********************************************/ |
| 64769 | 65025 | /************** Begin file backup.c ******************************************/ |
| 64770 | 65026 | /* |
| 64771 | 65027 | ** 2009 January 28 |
| | @@ -66791,11 +67047,11 @@ |
| 66791 | 67047 | |
| 66792 | 67048 | assert( pCtx->pParse->rc==SQLITE_OK ); |
| 66793 | 67049 | memset(&ctx, 0, sizeof(ctx)); |
| 66794 | 67050 | ctx.pOut = pVal; |
| 66795 | 67051 | ctx.pFunc = pFunc; |
| 66796 | | - pFunc->xFunc(&ctx, nVal, apVal); |
| 67052 | + pFunc->xSFunc(&ctx, nVal, apVal); |
| 66797 | 67053 | if( ctx.isError ){ |
| 66798 | 67054 | rc = ctx.isError; |
| 66799 | 67055 | sqlite3ErrorMsg(pCtx->pParse, "%s", sqlite3_value_text(pVal)); |
| 66800 | 67056 | }else{ |
| 66801 | 67057 | sqlite3ValueApplyAffinity(pVal, aff, SQLITE_UTF8); |
| | @@ -67538,12 +67794,11 @@ |
| 67538 | 67794 | char c; |
| 67539 | 67795 | va_start(ap, zTypes); |
| 67540 | 67796 | for(i=0; (c = zTypes[i])!=0; i++){ |
| 67541 | 67797 | if( c=='s' ){ |
| 67542 | 67798 | const char *z = va_arg(ap, const char*); |
| 67543 | | - int addr = sqlite3VdbeAddOp2(p, z==0 ? OP_Null : OP_String8, 0, iDest++); |
| 67544 | | - if( z ) sqlite3VdbeChangeP4(p, addr, z, 0); |
| 67799 | + sqlite3VdbeAddOp4(p, z==0 ? OP_Null : OP_String8, 0, iDest++, 0, z, 0); |
| 67545 | 67800 | }else{ |
| 67546 | 67801 | assert( c=='i' ); |
| 67547 | 67802 | sqlite3VdbeAddOp2(p, OP_Integer, va_arg(ap, int), iDest++); |
| 67548 | 67803 | } |
| 67549 | 67804 | } |
| | @@ -67593,12 +67848,11 @@ |
| 67593 | 67848 | ** The zWhere string must have been obtained from sqlite3_malloc(). |
| 67594 | 67849 | ** This routine will take ownership of the allocated memory. |
| 67595 | 67850 | */ |
| 67596 | 67851 | SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe *p, int iDb, char *zWhere){ |
| 67597 | 67852 | int j; |
| 67598 | | - int addr = sqlite3VdbeAddOp3(p, OP_ParseSchema, iDb, 0, 0); |
| 67599 | | - sqlite3VdbeChangeP4(p, addr, zWhere, P4_DYNAMIC); |
| 67853 | + sqlite3VdbeAddOp4(p, OP_ParseSchema, iDb, 0, 0, zWhere, P4_DYNAMIC); |
| 67600 | 67854 | for(j=0; j<p->db->nDb; j++) sqlite3VdbeUsesBtree(p, j); |
| 67601 | 67855 | } |
| 67602 | 67856 | |
| 67603 | 67857 | /* |
| 67604 | 67858 | ** Add an opcode that includes the p4 value as an integer. |
| | @@ -67895,10 +68149,24 @@ |
| 67895 | 68149 | SQLITE_PRIVATE int sqlite3VdbeCurrentAddr(Vdbe *p){ |
| 67896 | 68150 | assert( p->magic==VDBE_MAGIC_INIT ); |
| 67897 | 68151 | return p->nOp; |
| 67898 | 68152 | } |
| 67899 | 68153 | |
| 68154 | +/* |
| 68155 | +** Verify that at least N opcode slots are available in p without |
| 68156 | +** having to malloc for more space (except when compiled using |
| 68157 | +** SQLITE_TEST_REALLOC_STRESS). This interface is used during testing |
| 68158 | +** to verify that certain calls to sqlite3VdbeAddOpList() can never |
| 68159 | +** fail due to a OOM fault and hence that the return value from |
| 68160 | +** sqlite3VdbeAddOpList() will always be non-NULL. |
| 68161 | +*/ |
| 68162 | +#if defined(SQLITE_DEBUG) && !defined(SQLITE_TEST_REALLOC_STRESS) |
| 68163 | +SQLITE_PRIVATE void sqlite3VdbeVerifyNoMallocRequired(Vdbe *p, int N){ |
| 68164 | + assert( p->nOp + N <= p->pParse->nOpAlloc ); |
| 68165 | +} |
| 68166 | +#endif |
| 68167 | + |
| 67900 | 68168 | /* |
| 67901 | 68169 | ** This function returns a pointer to the array of opcodes associated with |
| 67902 | 68170 | ** the Vdbe passed as the first argument. It is the callers responsibility |
| 67903 | 68171 | ** to arrange for the returned array to be eventually freed using the |
| 67904 | 68172 | ** vdbeFreeOpArray() function. |
| | @@ -67920,23 +68188,27 @@ |
| 67920 | 68188 | p->aOp = 0; |
| 67921 | 68189 | return aOp; |
| 67922 | 68190 | } |
| 67923 | 68191 | |
| 67924 | 68192 | /* |
| 67925 | | -** Add a whole list of operations to the operation stack. Return the |
| 67926 | | -** address of the first operation added. |
| 68193 | +** Add a whole list of operations to the operation stack. Return a |
| 68194 | +** pointer to the first operation inserted. |
| 67927 | 68195 | */ |
| 67928 | | -SQLITE_PRIVATE int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp, int iLineno){ |
| 67929 | | - int addr, i; |
| 67930 | | - VdbeOp *pOut; |
| 68196 | +SQLITE_PRIVATE VdbeOp *sqlite3VdbeAddOpList( |
| 68197 | + Vdbe *p, /* Add opcodes to the prepared statement */ |
| 68198 | + int nOp, /* Number of opcodes to add */ |
| 68199 | + VdbeOpList const *aOp, /* The opcodes to be added */ |
| 68200 | + int iLineno /* Source-file line number of first opcode */ |
| 68201 | +){ |
| 68202 | + int i; |
| 68203 | + VdbeOp *pOut, *pFirst; |
| 67931 | 68204 | assert( nOp>0 ); |
| 67932 | 68205 | assert( p->magic==VDBE_MAGIC_INIT ); |
| 67933 | 68206 | if( p->nOp + nOp > p->pParse->nOpAlloc && growOpArray(p, nOp) ){ |
| 67934 | 68207 | return 0; |
| 67935 | 68208 | } |
| 67936 | | - addr = p->nOp; |
| 67937 | | - pOut = &p->aOp[addr]; |
| 68209 | + pFirst = pOut = &p->aOp[p->nOp]; |
| 67938 | 68210 | for(i=0; i<nOp; i++, aOp++, pOut++){ |
| 67939 | 68211 | pOut->opcode = aOp->opcode; |
| 67940 | 68212 | pOut->p1 = aOp->p1; |
| 67941 | 68213 | pOut->p2 = aOp->p2; |
| 67942 | 68214 | assert( aOp->p2>=0 ); |
| | @@ -67952,16 +68224,16 @@ |
| 67952 | 68224 | #else |
| 67953 | 68225 | (void)iLineno; |
| 67954 | 68226 | #endif |
| 67955 | 68227 | #ifdef SQLITE_DEBUG |
| 67956 | 68228 | if( p->db->flags & SQLITE_VdbeAddopTrace ){ |
| 67957 | | - sqlite3VdbePrintOp(0, i+addr, &p->aOp[i+addr]); |
| 68229 | + sqlite3VdbePrintOp(0, i+p->nOp, &p->aOp[i+p->nOp]); |
| 67958 | 68230 | } |
| 67959 | 68231 | #endif |
| 67960 | 68232 | } |
| 67961 | 68233 | p->nOp += nOp; |
| 67962 | | - return addr; |
| 68234 | + return pFirst; |
| 67963 | 68235 | } |
| 67964 | 68236 | |
| 67965 | 68237 | #if defined(SQLITE_ENABLE_STMT_SCANSTATUS) |
| 67966 | 68238 | /* |
| 67967 | 68239 | ** Add an entry to the array of counters managed by sqlite3_stmt_scanstatus(). |
| | @@ -68005,11 +68277,11 @@ |
| 68005 | 68277 | } |
| 68006 | 68278 | SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe *p, u32 addr, int val){ |
| 68007 | 68279 | sqlite3VdbeGetOp(p,addr)->p3 = val; |
| 68008 | 68280 | } |
| 68009 | 68281 | SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe *p, u8 p5){ |
| 68010 | | - sqlite3VdbeGetOp(p,-1)->p5 = p5; |
| 68282 | + if( !p->db->mallocFailed ) p->aOp[p->nOp-1].p5 = p5; |
| 68011 | 68283 | } |
| 68012 | 68284 | |
| 68013 | 68285 | /* |
| 68014 | 68286 | ** Change the P2 operand of instruction addr so that it points to |
| 68015 | 68287 | ** the address of the next instruction to be coded. |
| | @@ -68093,11 +68365,11 @@ |
| 68093 | 68365 | */ |
| 68094 | 68366 | static void vdbeFreeOpArray(sqlite3 *db, Op *aOp, int nOp){ |
| 68095 | 68367 | if( aOp ){ |
| 68096 | 68368 | Op *pOp; |
| 68097 | 68369 | for(pOp=aOp; pOp<&aOp[nOp]; pOp++){ |
| 68098 | | - freeP4(db, pOp->p4type, pOp->p4.p); |
| 68370 | + if( pOp->p4type ) freeP4(db, pOp->p4type, pOp->p4.p); |
| 68099 | 68371 | #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS |
| 68100 | 68372 | sqlite3DbFree(db, pOp->zComment); |
| 68101 | 68373 | #endif |
| 68102 | 68374 | } |
| 68103 | 68375 | } |
| | @@ -68115,28 +68387,29 @@ |
| 68115 | 68387 | } |
| 68116 | 68388 | |
| 68117 | 68389 | /* |
| 68118 | 68390 | ** Change the opcode at addr into OP_Noop |
| 68119 | 68391 | */ |
| 68120 | | -SQLITE_PRIVATE void sqlite3VdbeChangeToNoop(Vdbe *p, int addr){ |
| 68121 | | - if( addr<p->nOp ){ |
| 68122 | | - VdbeOp *pOp = &p->aOp[addr]; |
| 68123 | | - sqlite3 *db = p->db; |
| 68124 | | - freeP4(db, pOp->p4type, pOp->p4.p); |
| 68125 | | - memset(pOp, 0, sizeof(pOp[0])); |
| 68126 | | - pOp->opcode = OP_Noop; |
| 68127 | | - } |
| 68392 | +SQLITE_PRIVATE int sqlite3VdbeChangeToNoop(Vdbe *p, int addr){ |
| 68393 | + VdbeOp *pOp; |
| 68394 | + if( p->db->mallocFailed ) return 0; |
| 68395 | + assert( addr>=0 && addr<p->nOp ); |
| 68396 | + pOp = &p->aOp[addr]; |
| 68397 | + freeP4(p->db, pOp->p4type, pOp->p4.p); |
| 68398 | + pOp->p4type = P4_NOTUSED; |
| 68399 | + pOp->p4.z = 0; |
| 68400 | + pOp->opcode = OP_Noop; |
| 68401 | + return 1; |
| 68128 | 68402 | } |
| 68129 | 68403 | |
| 68130 | 68404 | /* |
| 68131 | 68405 | ** If the last opcode is "op" and it is not a jump destination, |
| 68132 | 68406 | ** then remove it. Return true if and only if an opcode was removed. |
| 68133 | 68407 | */ |
| 68134 | 68408 | SQLITE_PRIVATE int sqlite3VdbeDeletePriorOpcode(Vdbe *p, u8 op){ |
| 68135 | 68409 | if( (p->nOp-1)>(p->pParse->iFixedOp) && p->aOp[p->nOp-1].opcode==op ){ |
| 68136 | | - sqlite3VdbeChangeToNoop(p, p->nOp-1); |
| 68137 | | - return 1; |
| 68410 | + return sqlite3VdbeChangeToNoop(p, p->nOp-1); |
| 68138 | 68411 | }else{ |
| 68139 | 68412 | return 0; |
| 68140 | 68413 | } |
| 68141 | 68414 | } |
| 68142 | 68415 | |
| | @@ -68155,65 +68428,60 @@ |
| 68155 | 68428 | ** to a string or structure that is guaranteed to exist for the lifetime of |
| 68156 | 68429 | ** the Vdbe. In these cases we can just copy the pointer. |
| 68157 | 68430 | ** |
| 68158 | 68431 | ** If addr<0 then change P4 on the most recently inserted instruction. |
| 68159 | 68432 | */ |
| 68433 | +static void SQLITE_NOINLINE vdbeChangeP4Full( |
| 68434 | + Vdbe *p, |
| 68435 | + Op *pOp, |
| 68436 | + const char *zP4, |
| 68437 | + int n |
| 68438 | +){ |
| 68439 | + if( pOp->p4type ){ |
| 68440 | + freeP4(p->db, pOp->p4type, pOp->p4.p); |
| 68441 | + pOp->p4type = 0; |
| 68442 | + pOp->p4.p = 0; |
| 68443 | + } |
| 68444 | + if( n<0 ){ |
| 68445 | + sqlite3VdbeChangeP4(p, (int)(pOp - p->aOp), zP4, n); |
| 68446 | + }else{ |
| 68447 | + if( n==0 ) n = sqlite3Strlen30(zP4); |
| 68448 | + pOp->p4.z = sqlite3DbStrNDup(p->db, zP4, n); |
| 68449 | + pOp->p4type = P4_DYNAMIC; |
| 68450 | + } |
| 68451 | +} |
| 68160 | 68452 | SQLITE_PRIVATE void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){ |
| 68161 | 68453 | Op *pOp; |
| 68162 | 68454 | sqlite3 *db; |
| 68163 | 68455 | assert( p!=0 ); |
| 68164 | 68456 | db = p->db; |
| 68165 | 68457 | assert( p->magic==VDBE_MAGIC_INIT ); |
| 68166 | | - if( p->aOp==0 || db->mallocFailed ){ |
| 68167 | | - if( n!=P4_VTAB ){ |
| 68168 | | - freeP4(db, n, (void*)*(char**)&zP4); |
| 68169 | | - } |
| 68458 | + assert( p->aOp!=0 || db->mallocFailed ); |
| 68459 | + if( db->mallocFailed ){ |
| 68460 | + if( n!=P4_VTAB ) freeP4(db, n, (void*)*(char**)&zP4); |
| 68170 | 68461 | return; |
| 68171 | 68462 | } |
| 68172 | 68463 | assert( p->nOp>0 ); |
| 68173 | 68464 | assert( addr<p->nOp ); |
| 68174 | 68465 | if( addr<0 ){ |
| 68175 | 68466 | addr = p->nOp - 1; |
| 68176 | 68467 | } |
| 68177 | 68468 | pOp = &p->aOp[addr]; |
| 68178 | | - assert( pOp->p4type==P4_NOTUSED |
| 68179 | | - || pOp->p4type==P4_INT32 |
| 68180 | | - || pOp->p4type==P4_KEYINFO ); |
| 68181 | | - freeP4(db, pOp->p4type, pOp->p4.p); |
| 68182 | | - pOp->p4.p = 0; |
| 68469 | + if( n>=0 || pOp->p4type ){ |
| 68470 | + vdbeChangeP4Full(p, pOp, zP4, n); |
| 68471 | + return; |
| 68472 | + } |
| 68183 | 68473 | if( n==P4_INT32 ){ |
| 68184 | 68474 | /* Note: this cast is safe, because the origin data point was an int |
| 68185 | 68475 | ** that was cast to a (const char *). */ |
| 68186 | 68476 | pOp->p4.i = SQLITE_PTR_TO_INT(zP4); |
| 68187 | 68477 | pOp->p4type = P4_INT32; |
| 68188 | | - }else if( zP4==0 ){ |
| 68189 | | - pOp->p4.p = 0; |
| 68190 | | - pOp->p4type = P4_NOTUSED; |
| 68191 | | - }else if( n==P4_KEYINFO ){ |
| 68192 | | - pOp->p4.p = (void*)zP4; |
| 68193 | | - pOp->p4type = P4_KEYINFO; |
| 68194 | | -#ifdef SQLITE_ENABLE_CURSOR_HINTS |
| 68195 | | - }else if( n==P4_EXPR ){ |
| 68196 | | - /* Responsibility for deleting the Expr tree is handed over to the |
| 68197 | | - ** VDBE by this operation. The caller should have already invoked |
| 68198 | | - ** sqlite3ExprDup() or whatever other routine is needed to make a |
| 68199 | | - ** private copy of the tree. */ |
| 68200 | | - pOp->p4.pExpr = (Expr*)zP4; |
| 68201 | | - pOp->p4type = P4_EXPR; |
| 68202 | | -#endif |
| 68203 | | - }else if( n==P4_VTAB ){ |
| 68204 | | - pOp->p4.p = (void*)zP4; |
| 68205 | | - pOp->p4type = P4_VTAB; |
| 68206 | | - sqlite3VtabLock((VTable *)zP4); |
| 68207 | | - assert( ((VTable *)zP4)->db==p->db ); |
| 68208 | | - }else if( n<0 ){ |
| 68478 | + }else if( zP4!=0 ){ |
| 68479 | + assert( n<0 ); |
| 68209 | 68480 | pOp->p4.p = (void*)zP4; |
| 68210 | 68481 | pOp->p4type = (signed char)n; |
| 68211 | | - }else{ |
| 68212 | | - if( n==0 ) n = sqlite3Strlen30(zP4); |
| 68213 | | - pOp->p4.z = sqlite3DbStrNDup(p->db, zP4, n); |
| 68214 | | - pOp->p4type = P4_DYNAMIC; |
| 68482 | + if( n==P4_VTAB ) sqlite3VtabLock((VTable*)zP4); |
| 68215 | 68483 | } |
| 68216 | 68484 | } |
| 68217 | 68485 | |
| 68218 | 68486 | /* |
| 68219 | 68487 | ** Set the P4 on the most recently added opcode to the KeyInfo for the |
| | @@ -68605,11 +68873,11 @@ |
| 68605 | 68873 | if( i!=1 && sqlite3BtreeSharable(p->db->aDb[i].pBt) ){ |
| 68606 | 68874 | DbMaskSet(p->lockMask, i); |
| 68607 | 68875 | } |
| 68608 | 68876 | } |
| 68609 | 68877 | |
| 68610 | | -#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0 |
| 68878 | +#if !defined(SQLITE_OMIT_SHARED_CACHE) |
| 68611 | 68879 | /* |
| 68612 | 68880 | ** If SQLite is compiled to support shared-cache mode and to be threadsafe, |
| 68613 | 68881 | ** this routine obtains the mutex associated with each BtShared structure |
| 68614 | 68882 | ** that may be accessed by the VM passed as an argument. In doing so it also |
| 68615 | 68883 | ** sets the BtShared.db member of each of the BtShared structures, ensuring |
| | @@ -69174,11 +69442,10 @@ |
| 69174 | 69442 | do { |
| 69175 | 69443 | nByte = 0; |
| 69176 | 69444 | p->aMem = allocSpace(p->aMem, nMem*sizeof(Mem), zCsr, &nFree, &nByte); |
| 69177 | 69445 | p->aVar = allocSpace(p->aVar, nVar*sizeof(Mem), zCsr, &nFree, &nByte); |
| 69178 | 69446 | p->apArg = allocSpace(p->apArg, nArg*sizeof(Mem*), zCsr, &nFree, &nByte); |
| 69179 | | - p->azVar = allocSpace(p->azVar, nVar*sizeof(char*), zCsr, &nFree, &nByte); |
| 69180 | 69447 | p->apCsr = allocSpace(p->apCsr, nCursor*sizeof(VdbeCursor*), |
| 69181 | 69448 | zCsr, &nFree, &nByte); |
| 69182 | 69449 | p->aOnceFlag = allocSpace(p->aOnceFlag, nOnce, zCsr, &nFree, &nByte); |
| 69183 | 69450 | #ifdef SQLITE_ENABLE_STMT_SCANSTATUS |
| 69184 | 69451 | p->anExec = allocSpace(p->anExec, p->nOp*sizeof(i64), zCsr, &nFree, &nByte); |
| | @@ -69197,15 +69464,14 @@ |
| 69197 | 69464 | for(n=0; n<nVar; n++){ |
| 69198 | 69465 | p->aVar[n].flags = MEM_Null; |
| 69199 | 69466 | p->aVar[n].db = db; |
| 69200 | 69467 | } |
| 69201 | 69468 | } |
| 69202 | | - if( p->azVar && pParse->nzVar>0 ){ |
| 69203 | | - p->nzVar = pParse->nzVar; |
| 69204 | | - memcpy(p->azVar, pParse->azVar, p->nzVar*sizeof(p->azVar[0])); |
| 69205 | | - memset(pParse->azVar, 0, pParse->nzVar*sizeof(pParse->azVar[0])); |
| 69206 | | - } |
| 69469 | + p->nzVar = pParse->nzVar; |
| 69470 | + p->azVar = pParse->azVar; |
| 69471 | + pParse->nzVar = 0; |
| 69472 | + pParse->azVar = 0; |
| 69207 | 69473 | if( p->aMem ){ |
| 69208 | 69474 | p->aMem--; /* aMem[] goes from 1..nMem */ |
| 69209 | 69475 | p->nMem = nMem; /* not from 0..nMem-1 */ |
| 69210 | 69476 | for(n=1; n<=nMem; n++){ |
| 69211 | 69477 | p->aMem[n].flags = MEM_Undefined; |
| | @@ -70188,10 +70454,11 @@ |
| 70188 | 70454 | pNext = pSub->pNext; |
| 70189 | 70455 | vdbeFreeOpArray(db, pSub->aOp, pSub->nOp); |
| 70190 | 70456 | sqlite3DbFree(db, pSub); |
| 70191 | 70457 | } |
| 70192 | 70458 | for(i=p->nzVar-1; i>=0; i--) sqlite3DbFree(db, p->azVar[i]); |
| 70459 | + sqlite3DbFree(db, p->azVar); |
| 70193 | 70460 | vdbeFreeOpArray(db, p->aOp, p->nOp); |
| 70194 | 70461 | sqlite3DbFree(db, p->aColName); |
| 70195 | 70462 | sqlite3DbFree(db, p->zSql); |
| 70196 | 70463 | sqlite3DbFree(db, p->pFree); |
| 70197 | 70464 | #ifdef SQLITE_ENABLE_STMT_SCANSTATUS |
| | @@ -70932,13 +71199,13 @@ |
| 70932 | 71199 | v1 = sqlite3ValueText((sqlite3_value*)&c1, pColl->enc); |
| 70933 | 71200 | n1 = v1==0 ? 0 : c1.n; |
| 70934 | 71201 | v2 = sqlite3ValueText((sqlite3_value*)&c2, pColl->enc); |
| 70935 | 71202 | n2 = v2==0 ? 0 : c2.n; |
| 70936 | 71203 | rc = pColl->xCmp(pColl->pUser, n1, v1, n2, v2); |
| 71204 | + if( (v1==0 || v2==0) && prcErr ) *prcErr = SQLITE_NOMEM; |
| 70937 | 71205 | sqlite3VdbeMemRelease(&c1); |
| 70938 | 71206 | sqlite3VdbeMemRelease(&c2); |
| 70939 | | - if( (v1==0 || v2==0) && prcErr ) *prcErr = SQLITE_NOMEM; |
| 70940 | 71207 | return rc; |
| 70941 | 71208 | } |
| 70942 | 71209 | } |
| 70943 | 71210 | |
| 70944 | 71211 | /* |
| | @@ -71722,15 +71989,17 @@ |
| 71722 | 71989 | ** Transfer error message text from an sqlite3_vtab.zErrMsg (text stored |
| 71723 | 71990 | ** in memory obtained from sqlite3_malloc) into a Vdbe.zErrMsg (text stored |
| 71724 | 71991 | ** in memory obtained from sqlite3DbMalloc). |
| 71725 | 71992 | */ |
| 71726 | 71993 | SQLITE_PRIVATE void sqlite3VtabImportErrmsg(Vdbe *p, sqlite3_vtab *pVtab){ |
| 71727 | | - sqlite3 *db = p->db; |
| 71728 | | - sqlite3DbFree(db, p->zErrMsg); |
| 71729 | | - p->zErrMsg = sqlite3DbStrDup(db, pVtab->zErrMsg); |
| 71730 | | - sqlite3_free(pVtab->zErrMsg); |
| 71731 | | - pVtab->zErrMsg = 0; |
| 71994 | + if( pVtab->zErrMsg ){ |
| 71995 | + sqlite3 *db = p->db; |
| 71996 | + sqlite3DbFree(db, p->zErrMsg); |
| 71997 | + p->zErrMsg = sqlite3DbStrDup(db, pVtab->zErrMsg); |
| 71998 | + sqlite3_free(pVtab->zErrMsg); |
| 71999 | + pVtab->zErrMsg = 0; |
| 72000 | + } |
| 71732 | 72001 | } |
| 71733 | 72002 | #endif /* SQLITE_OMIT_VIRTUALTABLE */ |
| 71734 | 72003 | |
| 71735 | 72004 | /************** End of vdbeaux.c *********************************************/ |
| 71736 | 72005 | /************** Begin file vdbeapi.c *****************************************/ |
| | @@ -72513,11 +72782,11 @@ |
| 72513 | 72782 | ** Allocate or return the aggregate context for a user function. A new |
| 72514 | 72783 | ** context is allocated on the first call. Subsequent calls return the |
| 72515 | 72784 | ** same context that was returned on prior calls. |
| 72516 | 72785 | */ |
| 72517 | 72786 | SQLITE_API void *SQLITE_STDCALL sqlite3_aggregate_context(sqlite3_context *p, int nByte){ |
| 72518 | | - assert( p && p->pFunc && p->pFunc->xStep ); |
| 72787 | + assert( p && p->pFunc && p->pFunc->xFinalize ); |
| 72519 | 72788 | assert( sqlite3_mutex_held(p->pOut->db->mutex) ); |
| 72520 | 72789 | testcase( nByte<0 ); |
| 72521 | 72790 | if( (p->pMem->flags & MEM_Agg)==0 ){ |
| 72522 | 72791 | return createAggContext(p, nByte); |
| 72523 | 72792 | }else{ |
| | @@ -72604,11 +72873,11 @@ |
| 72604 | 72873 | ** provide only to avoid breaking legacy code. New aggregate function |
| 72605 | 72874 | ** implementations should keep their own counts within their aggregate |
| 72606 | 72875 | ** context. |
| 72607 | 72876 | */ |
| 72608 | 72877 | SQLITE_API int SQLITE_STDCALL sqlite3_aggregate_count(sqlite3_context *p){ |
| 72609 | | - assert( p && p->pMem && p->pFunc && p->pFunc->xStep ); |
| 72878 | + assert( p && p->pMem && p->pFunc && p->pFunc->xFinalize ); |
| 72610 | 72879 | return p->pMem->n; |
| 72611 | 72880 | } |
| 72612 | 72881 | #endif |
| 72613 | 72882 | |
| 72614 | 72883 | /* |
| | @@ -75347,12 +75616,12 @@ |
| 75347 | 75616 | } |
| 75348 | 75617 | #endif |
| 75349 | 75618 | MemSetTypeFlag(pCtx->pOut, MEM_Null); |
| 75350 | 75619 | pCtx->fErrorOrAux = 0; |
| 75351 | 75620 | db->lastRowid = lastRowid; |
| 75352 | | - (*pCtx->pFunc->xFunc)(pCtx, pCtx->argc, pCtx->argv); /* IMP: R-24505-23230 */ |
| 75353 | | - lastRowid = db->lastRowid; /* Remember rowid changes made by xFunc */ |
| 75621 | + (*pCtx->pFunc->xSFunc)(pCtx, pCtx->argc, pCtx->argv);/* IMP: R-24505-23230 */ |
| 75622 | + lastRowid = db->lastRowid; /* Remember rowid changes made by xSFunc */ |
| 75354 | 75623 | |
| 75355 | 75624 | /* If the function returned an error, throw an exception */ |
| 75356 | 75625 | if( pCtx->fErrorOrAux ){ |
| 75357 | 75626 | if( pCtx->isError ){ |
| 75358 | 75627 | sqlite3VdbeError(p, "%s", sqlite3_value_text(pCtx->pOut)); |
| | @@ -76059,11 +76328,10 @@ |
| 76059 | 76328 | const u8 *zEndHdr; /* Pointer to first byte after the header */ |
| 76060 | 76329 | u32 offset; /* Offset into the data */ |
| 76061 | 76330 | u64 offset64; /* 64-bit offset */ |
| 76062 | 76331 | u32 avail; /* Number of bytes of available data */ |
| 76063 | 76332 | u32 t; /* A type code from the record header */ |
| 76064 | | - u16 fx; /* pDest->flags value */ |
| 76065 | 76333 | Mem *pReg; /* PseudoTable input register */ |
| 76066 | 76334 | |
| 76067 | 76335 | p2 = pOp->p2; |
| 76068 | 76336 | assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) ); |
| 76069 | 76337 | pDest = &aMem[pOp->p3]; |
| | @@ -76237,14 +76505,35 @@ |
| 76237 | 76505 | assert( p2<pC->nHdrParsed ); |
| 76238 | 76506 | assert( rc==SQLITE_OK ); |
| 76239 | 76507 | assert( sqlite3VdbeCheckMemInvariants(pDest) ); |
| 76240 | 76508 | if( VdbeMemDynamic(pDest) ) sqlite3VdbeMemSetNull(pDest); |
| 76241 | 76509 | assert( t==pC->aType[p2] ); |
| 76510 | + pDest->enc = encoding; |
| 76242 | 76511 | if( pC->szRow>=aOffset[p2+1] ){ |
| 76243 | 76512 | /* This is the common case where the desired content fits on the original |
| 76244 | 76513 | ** page - where the content is not on an overflow page */ |
| 76245 | | - sqlite3VdbeSerialGet(pC->aRow+aOffset[p2], t, pDest); |
| 76514 | + zData = pC->aRow + aOffset[p2]; |
| 76515 | + if( t<12 ){ |
| 76516 | + sqlite3VdbeSerialGet(zData, t, pDest); |
| 76517 | + }else{ |
| 76518 | + /* If the column value is a string, we need a persistent value, not |
| 76519 | + ** a MEM_Ephem value. This branch is a fast short-cut that is equivalent |
| 76520 | + ** to calling sqlite3VdbeSerialGet() and sqlite3VdbeDeephemeralize(). |
| 76521 | + */ |
| 76522 | + static const u16 aFlag[] = { MEM_Blob, MEM_Str|MEM_Term }; |
| 76523 | + pDest->n = len = (t-12)/2; |
| 76524 | + if( pDest->szMalloc < len+2 ){ |
| 76525 | + pDest->flags = MEM_Null; |
| 76526 | + if( sqlite3VdbeMemGrow(pDest, len+2, 0) ) goto no_mem; |
| 76527 | + }else{ |
| 76528 | + pDest->z = pDest->zMalloc; |
| 76529 | + } |
| 76530 | + memcpy(pDest->z, zData, len); |
| 76531 | + pDest->z[len] = 0; |
| 76532 | + pDest->z[len+1] = 0; |
| 76533 | + pDest->flags = aFlag[t&1]; |
| 76534 | + } |
| 76246 | 76535 | }else{ |
| 76247 | 76536 | /* This branch happens only when content is on overflow pages */ |
| 76248 | 76537 | if( ((pOp->p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0 |
| 76249 | 76538 | && ((t>=12 && (t&1)==0) || (pOp->p5 & OPFLAG_TYPEOFARG)!=0)) |
| 76250 | 76539 | || (len = sqlite3VdbeSerialTypeLen(t))==0 |
| | @@ -76252,42 +76541,24 @@ |
| 76252 | 76541 | /* Content is irrelevant for |
| 76253 | 76542 | ** 1. the typeof() function, |
| 76254 | 76543 | ** 2. the length(X) function if X is a blob, and |
| 76255 | 76544 | ** 3. if the content length is zero. |
| 76256 | 76545 | ** So we might as well use bogus content rather than reading |
| 76257 | | - ** content from disk. NULL will work for the value for strings |
| 76258 | | - ** and blobs and whatever is in the payloadSize64 variable |
| 76259 | | - ** will work for everything else. */ |
| 76260 | | - sqlite3VdbeSerialGet(t<=13 ? (u8*)&payloadSize64 : 0, t, pDest); |
| 76546 | + ** content from disk. */ |
| 76547 | + static u8 aZero[8]; /* This is the bogus content */ |
| 76548 | + sqlite3VdbeSerialGet(aZero, t, pDest); |
| 76261 | 76549 | }else{ |
| 76262 | 76550 | rc = sqlite3VdbeMemFromBtree(pCrsr, aOffset[p2], len, !pC->isTable, |
| 76263 | 76551 | pDest); |
| 76264 | | - if( rc!=SQLITE_OK ){ |
| 76265 | | - goto op_column_error; |
| 76266 | | - } |
| 76267 | | - sqlite3VdbeSerialGet((const u8*)pDest->z, t, pDest); |
| 76268 | | - pDest->flags &= ~MEM_Ephem; |
| 76269 | | - } |
| 76270 | | - } |
| 76271 | | - pDest->enc = encoding; |
| 76272 | | - |
| 76273 | | -op_column_out: |
| 76274 | | - /* If the column value is an ephemeral string, go ahead and persist |
| 76275 | | - ** that string in case the cursor moves before the column value is |
| 76276 | | - ** used. The following code does the equivalent of Deephemeralize() |
| 76277 | | - ** but does it faster. */ |
| 76278 | | - if( (pDest->flags & MEM_Ephem)!=0 && pDest->z ){ |
| 76279 | | - fx = pDest->flags & (MEM_Str|MEM_Blob); |
| 76280 | | - assert( fx!=0 ); |
| 76281 | | - zData = (const u8*)pDest->z; |
| 76282 | | - len = pDest->n; |
| 76283 | | - if( sqlite3VdbeMemClearAndResize(pDest, len+2) ) goto no_mem; |
| 76284 | | - memcpy(pDest->z, zData, len); |
| 76285 | | - pDest->z[len] = 0; |
| 76286 | | - pDest->z[len+1] = 0; |
| 76287 | | - pDest->flags = fx|MEM_Term; |
| 76288 | | - } |
| 76552 | + if( rc==SQLITE_OK ){ |
| 76553 | + sqlite3VdbeSerialGet((const u8*)pDest->z, t, pDest); |
| 76554 | + pDest->flags &= ~MEM_Ephem; |
| 76555 | + } |
| 76556 | + } |
| 76557 | + } |
| 76558 | + |
| 76559 | +op_column_out: |
| 76289 | 76560 | op_column_error: |
| 76290 | 76561 | UPDATE_MAX_BLOBSIZE(pDest); |
| 76291 | 76562 | REGISTER_TRACE(pOp->p3, pDest); |
| 76292 | 76563 | break; |
| 76293 | 76564 | } |
| | @@ -78782,10 +79053,11 @@ |
| 78782 | 79053 | case OP_Destroy: { /* out2 */ |
| 78783 | 79054 | int iMoved; |
| 78784 | 79055 | int iDb; |
| 78785 | 79056 | |
| 78786 | 79057 | assert( p->readOnly==0 ); |
| 79058 | + assert( pOp->p1>1 ); |
| 78787 | 79059 | pOut = out2Prerelease(p, pOp); |
| 78788 | 79060 | pOut->flags = MEM_Null; |
| 78789 | 79061 | if( db->nVdbeRead > db->nVDestroy+1 ){ |
| 78790 | 79062 | rc = SQLITE_LOCKED; |
| 78791 | 79063 | p->errorAction = OE_Abort; |
| | @@ -79586,11 +79858,11 @@ |
| 79586 | 79858 | pMem->n++; |
| 79587 | 79859 | sqlite3VdbeMemInit(&t, db, MEM_Null); |
| 79588 | 79860 | pCtx->pOut = &t; |
| 79589 | 79861 | pCtx->fErrorOrAux = 0; |
| 79590 | 79862 | pCtx->skipFlag = 0; |
| 79591 | | - (pCtx->pFunc->xStep)(pCtx,pCtx->argc,pCtx->argv); /* IMP: R-24505-23230 */ |
| 79863 | + (pCtx->pFunc->xSFunc)(pCtx,pCtx->argc,pCtx->argv); /* IMP: R-24505-23230 */ |
| 79592 | 79864 | if( pCtx->fErrorOrAux ){ |
| 79593 | 79865 | if( pCtx->isError ){ |
| 79594 | 79866 | sqlite3VdbeError(p, "%s", sqlite3_value_text(&t)); |
| 79595 | 79867 | rc = pCtx->isError; |
| 79596 | 79868 | } |
| | @@ -80584,42 +80856,10 @@ |
| 80584 | 80856 | int flags, /* True -> read/write access, false -> read-only */ |
| 80585 | 80857 | sqlite3_blob **ppBlob /* Handle for accessing the blob returned here */ |
| 80586 | 80858 | ){ |
| 80587 | 80859 | int nAttempt = 0; |
| 80588 | 80860 | int iCol; /* Index of zColumn in row-record */ |
| 80589 | | - |
| 80590 | | - /* This VDBE program seeks a btree cursor to the identified |
| 80591 | | - ** db/table/row entry. The reason for using a vdbe program instead |
| 80592 | | - ** of writing code to use the b-tree layer directly is that the |
| 80593 | | - ** vdbe program will take advantage of the various transaction, |
| 80594 | | - ** locking and error handling infrastructure built into the vdbe. |
| 80595 | | - ** |
| 80596 | | - ** After seeking the cursor, the vdbe executes an OP_ResultRow. |
| 80597 | | - ** Code external to the Vdbe then "borrows" the b-tree cursor and |
| 80598 | | - ** uses it to implement the blob_read(), blob_write() and |
| 80599 | | - ** blob_bytes() functions. |
| 80600 | | - ** |
| 80601 | | - ** The sqlite3_blob_close() function finalizes the vdbe program, |
| 80602 | | - ** which closes the b-tree cursor and (possibly) commits the |
| 80603 | | - ** transaction. |
| 80604 | | - */ |
| 80605 | | - static const int iLn = VDBE_OFFSET_LINENO(4); |
| 80606 | | - static const VdbeOpList openBlob[] = { |
| 80607 | | - /* {OP_Transaction, 0, 0, 0}, // 0: Inserted separately */ |
| 80608 | | - {OP_TableLock, 0, 0, 0}, /* 1: Acquire a read or write lock */ |
| 80609 | | - /* One of the following two instructions is replaced by an OP_Noop. */ |
| 80610 | | - {OP_OpenRead, 0, 0, 0}, /* 2: Open cursor 0 for reading */ |
| 80611 | | - {OP_OpenWrite, 0, 0, 0}, /* 3: Open cursor 0 for read/write */ |
| 80612 | | - {OP_Variable, 1, 1, 1}, /* 4: Push the rowid to the stack */ |
| 80613 | | - {OP_NotExists, 0, 10, 1}, /* 5: Seek the cursor */ |
| 80614 | | - {OP_Column, 0, 0, 1}, /* 6 */ |
| 80615 | | - {OP_ResultRow, 1, 0, 0}, /* 7 */ |
| 80616 | | - {OP_Goto, 0, 4, 0}, /* 8 */ |
| 80617 | | - {OP_Close, 0, 0, 0}, /* 9 */ |
| 80618 | | - {OP_Halt, 0, 0, 0}, /* 10 */ |
| 80619 | | - }; |
| 80620 | | - |
| 80621 | 80861 | int rc = SQLITE_OK; |
| 80622 | 80862 | char *zErr = 0; |
| 80623 | 80863 | Table *pTab; |
| 80624 | 80864 | Parse *pParse = 0; |
| 80625 | 80865 | Incrblob *pBlob = 0; |
| | @@ -80734,49 +80974,84 @@ |
| 80734 | 80974 | } |
| 80735 | 80975 | |
| 80736 | 80976 | pBlob->pStmt = (sqlite3_stmt *)sqlite3VdbeCreate(pParse); |
| 80737 | 80977 | assert( pBlob->pStmt || db->mallocFailed ); |
| 80738 | 80978 | if( pBlob->pStmt ){ |
| 80979 | + |
| 80980 | + /* This VDBE program seeks a btree cursor to the identified |
| 80981 | + ** db/table/row entry. The reason for using a vdbe program instead |
| 80982 | + ** of writing code to use the b-tree layer directly is that the |
| 80983 | + ** vdbe program will take advantage of the various transaction, |
| 80984 | + ** locking and error handling infrastructure built into the vdbe. |
| 80985 | + ** |
| 80986 | + ** After seeking the cursor, the vdbe executes an OP_ResultRow. |
| 80987 | + ** Code external to the Vdbe then "borrows" the b-tree cursor and |
| 80988 | + ** uses it to implement the blob_read(), blob_write() and |
| 80989 | + ** blob_bytes() functions. |
| 80990 | + ** |
| 80991 | + ** The sqlite3_blob_close() function finalizes the vdbe program, |
| 80992 | + ** which closes the b-tree cursor and (possibly) commits the |
| 80993 | + ** transaction. |
| 80994 | + */ |
| 80995 | + static const int iLn = VDBE_OFFSET_LINENO(4); |
| 80996 | + static const VdbeOpList openBlob[] = { |
| 80997 | + /* addr/ofst */ |
| 80998 | + /* {OP_Transaction, 0, 0, 0}, // 0/ inserted separately */ |
| 80999 | + {OP_TableLock, 0, 0, 0}, /* 1/0: Acquire a read or write lock */ |
| 81000 | + {OP_OpenRead, 0, 0, 0}, /* 2/1: Open a cursor */ |
| 81001 | + {OP_Variable, 1, 1, 0}, /* 3/2: Move ?1 into reg[1] */ |
| 81002 | + {OP_NotExists, 0, 8, 1}, /* 4/3: Seek the cursor */ |
| 81003 | + {OP_Column, 0, 0, 1}, /* 5/4 */ |
| 81004 | + {OP_ResultRow, 1, 0, 0}, /* 6/5 */ |
| 81005 | + {OP_Goto, 0, 3, 0}, /* 7/6 */ |
| 81006 | + {OP_Close, 0, 0, 0}, /* 8/7 */ |
| 81007 | + {OP_Halt, 0, 0, 0}, /* 9/8 */ |
| 81008 | + }; |
| 80739 | 81009 | Vdbe *v = (Vdbe *)pBlob->pStmt; |
| 80740 | 81010 | int iDb = sqlite3SchemaToIndex(db, pTab->pSchema); |
| 80741 | | - |
| 81011 | + VdbeOp *aOp; |
| 80742 | 81012 | |
| 80743 | 81013 | sqlite3VdbeAddOp4Int(v, OP_Transaction, iDb, flags, |
| 80744 | 81014 | pTab->pSchema->schema_cookie, |
| 80745 | 81015 | pTab->pSchema->iGeneration); |
| 80746 | 81016 | sqlite3VdbeChangeP5(v, 1); |
| 80747 | | - sqlite3VdbeAddOpList(v, ArraySize(openBlob), openBlob, iLn); |
| 81017 | + aOp = sqlite3VdbeAddOpList(v, ArraySize(openBlob), openBlob, iLn); |
| 80748 | 81018 | |
| 80749 | 81019 | /* Make sure a mutex is held on the table to be accessed */ |
| 80750 | 81020 | sqlite3VdbeUsesBtree(v, iDb); |
| 80751 | 81021 | |
| 80752 | | - /* Configure the OP_TableLock instruction */ |
| 81022 | + if( db->mallocFailed==0 ){ |
| 81023 | + assert( aOp!=0 ); |
| 81024 | + /* Configure the OP_TableLock instruction */ |
| 80753 | 81025 | #ifdef SQLITE_OMIT_SHARED_CACHE |
| 80754 | | - sqlite3VdbeChangeToNoop(v, 1); |
| 81026 | + aOp[0].opcode = OP_Noop; |
| 80755 | 81027 | #else |
| 80756 | | - sqlite3VdbeChangeP1(v, 1, iDb); |
| 80757 | | - sqlite3VdbeChangeP2(v, 1, pTab->tnum); |
| 80758 | | - sqlite3VdbeChangeP3(v, 1, flags); |
| 80759 | | - sqlite3VdbeChangeP4(v, 1, pTab->zName, P4_TRANSIENT); |
| 81028 | + aOp[0].p1 = iDb; |
| 81029 | + aOp[0].p2 = pTab->tnum; |
| 81030 | + aOp[0].p3 = flags; |
| 81031 | + sqlite3VdbeChangeP4(v, 1, pTab->zName, P4_TRANSIENT); |
| 81032 | + } |
| 81033 | + if( db->mallocFailed==0 ){ |
| 80760 | 81034 | #endif |
| 80761 | 81035 | |
| 80762 | | - /* Remove either the OP_OpenWrite or OpenRead. Set the P2 |
| 80763 | | - ** parameter of the other to pTab->tnum. */ |
| 80764 | | - sqlite3VdbeChangeToNoop(v, 3 - flags); |
| 80765 | | - sqlite3VdbeChangeP2(v, 2 + flags, pTab->tnum); |
| 80766 | | - sqlite3VdbeChangeP3(v, 2 + flags, iDb); |
| 80767 | | - |
| 80768 | | - /* Configure the number of columns. Configure the cursor to |
| 80769 | | - ** think that the table has one more column than it really |
| 80770 | | - ** does. An OP_Column to retrieve this imaginary column will |
| 80771 | | - ** always return an SQL NULL. This is useful because it means |
| 80772 | | - ** we can invoke OP_Column to fill in the vdbe cursors type |
| 80773 | | - ** and offset cache without causing any IO. |
| 80774 | | - */ |
| 80775 | | - sqlite3VdbeChangeP4(v, 2+flags, SQLITE_INT_TO_PTR(pTab->nCol+1),P4_INT32); |
| 80776 | | - sqlite3VdbeChangeP2(v, 6, pTab->nCol); |
| 80777 | | - if( !db->mallocFailed ){ |
| 81036 | + /* Remove either the OP_OpenWrite or OpenRead. Set the P2 |
| 81037 | + ** parameter of the other to pTab->tnum. */ |
| 81038 | + if( flags ) aOp[1].opcode = OP_OpenWrite; |
| 81039 | + aOp[1].p2 = pTab->tnum; |
| 81040 | + aOp[1].p3 = iDb; |
| 81041 | + |
| 81042 | + /* Configure the number of columns. Configure the cursor to |
| 81043 | + ** think that the table has one more column than it really |
| 81044 | + ** does. An OP_Column to retrieve this imaginary column will |
| 81045 | + ** always return an SQL NULL. This is useful because it means |
| 81046 | + ** we can invoke OP_Column to fill in the vdbe cursors type |
| 81047 | + ** and offset cache without causing any IO. |
| 81048 | + */ |
| 81049 | + aOp[1].p4type = P4_INT32; |
| 81050 | + aOp[1].p4.i = pTab->nCol+1; |
| 81051 | + aOp[4].p2 = pTab->nCol; |
| 81052 | + |
| 80778 | 81053 | pParse->nVar = 1; |
| 80779 | 81054 | pParse->nMem = 1; |
| 80780 | 81055 | pParse->nTab = 1; |
| 80781 | 81056 | sqlite3VdbeMakeReady(v, pParse); |
| 80782 | 81057 | } |
| | @@ -81685,11 +81960,11 @@ |
| 81685 | 81960 | assert( pReadr->aBuffer==0 ); |
| 81686 | 81961 | assert( pReadr->aMap==0 ); |
| 81687 | 81962 | |
| 81688 | 81963 | rc = vdbePmaReaderSeek(pTask, pReadr, pFile, iStart); |
| 81689 | 81964 | if( rc==SQLITE_OK ){ |
| 81690 | | - u64 nByte; /* Size of PMA in bytes */ |
| 81965 | + u64 nByte = 0; /* Size of PMA in bytes */ |
| 81691 | 81966 | rc = vdbePmaReadVarint(pReadr, &nByte); |
| 81692 | 81967 | pReadr->iEof = pReadr->iReadOff + nByte; |
| 81693 | 81968 | *pnByte += nByte; |
| 81694 | 81969 | } |
| 81695 | 81970 | |
| | @@ -84243,13 +84518,12 @@ |
| 84243 | 84518 | ** return the top-level walk call. |
| 84244 | 84519 | ** |
| 84245 | 84520 | ** The return value from this routine is WRC_Abort to abandon the tree walk |
| 84246 | 84521 | ** and WRC_Continue to continue. |
| 84247 | 84522 | */ |
| 84248 | | -SQLITE_PRIVATE int sqlite3WalkExpr(Walker *pWalker, Expr *pExpr){ |
| 84523 | +static SQLITE_NOINLINE int walkExpr(Walker *pWalker, Expr *pExpr){ |
| 84249 | 84524 | int rc; |
| 84250 | | - if( pExpr==0 ) return WRC_Continue; |
| 84251 | 84525 | testcase( ExprHasProperty(pExpr, EP_TokenOnly) ); |
| 84252 | 84526 | testcase( ExprHasProperty(pExpr, EP_Reduced) ); |
| 84253 | 84527 | rc = pWalker->xExprCallback(pWalker, pExpr); |
| 84254 | 84528 | if( rc==WRC_Continue |
| 84255 | 84529 | && !ExprHasProperty(pExpr,EP_TokenOnly) ){ |
| | @@ -84260,10 +84534,13 @@ |
| 84260 | 84534 | }else{ |
| 84261 | 84535 | if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort; |
| 84262 | 84536 | } |
| 84263 | 84537 | } |
| 84264 | 84538 | return rc & WRC_Abort; |
| 84539 | +} |
| 84540 | +SQLITE_PRIVATE int sqlite3WalkExpr(Walker *pWalker, Expr *pExpr){ |
| 84541 | + return pExpr ? walkExpr(pWalker,pExpr) : WRC_Continue; |
| 84265 | 84542 | } |
| 84266 | 84543 | |
| 84267 | 84544 | /* |
| 84268 | 84545 | ** Call sqlite3WalkExpr() for every expression in list p or until |
| 84269 | 84546 | ** an abort request is seen. |
| | @@ -85034,11 +85311,11 @@ |
| 85034 | 85311 | no_such_func = 1; |
| 85035 | 85312 | }else{ |
| 85036 | 85313 | wrong_num_args = 1; |
| 85037 | 85314 | } |
| 85038 | 85315 | }else{ |
| 85039 | | - is_agg = pDef->xFunc==0; |
| 85316 | + is_agg = pDef->xFinalize!=0; |
| 85040 | 85317 | if( pDef->funcFlags & SQLITE_FUNC_UNLIKELY ){ |
| 85041 | 85318 | ExprSetProperty(pExpr, EP_Unlikely|EP_Skip); |
| 85042 | 85319 | if( n==2 ){ |
| 85043 | 85320 | pExpr->iTable = exprProbability(pList->a[1].pExpr); |
| 85044 | 85321 | if( pExpr->iTable<0 ){ |
| | @@ -85762,14 +86039,16 @@ |
| 85762 | 86039 | pParse->nHeight += pExpr->nHeight; |
| 85763 | 86040 | } |
| 85764 | 86041 | #endif |
| 85765 | 86042 | savedHasAgg = pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg); |
| 85766 | 86043 | pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg); |
| 85767 | | - memset(&w, 0, sizeof(w)); |
| 86044 | + w.pParse = pNC->pParse; |
| 85768 | 86045 | w.xExprCallback = resolveExprStep; |
| 85769 | 86046 | w.xSelectCallback = resolveSelectStep; |
| 85770 | | - w.pParse = pNC->pParse; |
| 86047 | + w.xSelectCallback2 = 0; |
| 86048 | + w.walkerDepth = 0; |
| 86049 | + w.eCode = 0; |
| 85771 | 86050 | w.u.pNC = pNC; |
| 85772 | 86051 | sqlite3WalkExpr(&w, pExpr); |
| 85773 | 86052 | #if SQLITE_MAX_EXPR_DEPTH>0 |
| 85774 | 86053 | pNC->pParse->nHeight -= pExpr->nHeight; |
| 85775 | 86054 | #endif |
| | @@ -86327,12 +86606,13 @@ |
| 86327 | 86606 | || sqlite3GetInt32(pToken->z, &iValue)==0 ){ |
| 86328 | 86607 | nExtra = pToken->n+1; |
| 86329 | 86608 | assert( iValue>=0 ); |
| 86330 | 86609 | } |
| 86331 | 86610 | } |
| 86332 | | - pNew = sqlite3DbMallocZero(db, sizeof(Expr)+nExtra); |
| 86611 | + pNew = sqlite3DbMallocRaw(db, sizeof(Expr)+nExtra); |
| 86333 | 86612 | if( pNew ){ |
| 86613 | + memset(pNew, 0, sizeof(Expr)); |
| 86334 | 86614 | pNew->op = (u8)op; |
| 86335 | 86615 | pNew->iAgg = -1; |
| 86336 | 86616 | if( pToken ){ |
| 86337 | 86617 | if( nExtra==0 ){ |
| 86338 | 86618 | pNew->flags |= EP_IntValue; |
| | @@ -87000,14 +87280,15 @@ |
| 87000 | 87280 | ExprList *pList, /* List to which to append. Might be NULL */ |
| 87001 | 87281 | Expr *pExpr /* Expression to be appended. Might be NULL */ |
| 87002 | 87282 | ){ |
| 87003 | 87283 | sqlite3 *db = pParse->db; |
| 87004 | 87284 | if( pList==0 ){ |
| 87005 | | - pList = sqlite3DbMallocZero(db, sizeof(ExprList) ); |
| 87285 | + pList = sqlite3DbMallocRaw(db, sizeof(ExprList) ); |
| 87006 | 87286 | if( pList==0 ){ |
| 87007 | 87287 | goto no_mem; |
| 87008 | 87288 | } |
| 87289 | + pList->nExpr = 0; |
| 87009 | 87290 | pList->a = sqlite3DbMallocRaw(db, sizeof(pList->a[0])); |
| 87010 | 87291 | if( pList->a==0 ) goto no_mem; |
| 87011 | 87292 | }else if( (pList->nExpr & (pList->nExpr-1))==0 ){ |
| 87012 | 87293 | struct ExprList_item *a; |
| 87013 | 87294 | assert( pList->nExpr>0 ); |
| | @@ -88761,11 +89042,11 @@ |
| 88761 | 89042 | nFarg = pFarg ? pFarg->nExpr : 0; |
| 88762 | 89043 | assert( !ExprHasProperty(pExpr, EP_IntValue) ); |
| 88763 | 89044 | zId = pExpr->u.zToken; |
| 88764 | 89045 | nId = sqlite3Strlen30(zId); |
| 88765 | 89046 | pDef = sqlite3FindFunction(db, zId, nId, nFarg, enc, 0); |
| 88766 | | - if( pDef==0 || pDef->xFunc==0 ){ |
| 89047 | + if( pDef==0 || pDef->xFinalize!=0 ){ |
| 88767 | 89048 | sqlite3ErrorMsg(pParse, "unknown function: %.*s()", nId, zId); |
| 88768 | 89049 | break; |
| 88769 | 89050 | } |
| 88770 | 89051 | |
| 88771 | 89052 | /* Attempt a direct implementation of the built-in COALESCE() and |
| | @@ -91433,12 +91714,11 @@ |
| 91433 | 91714 | static const FuncDef statInitFuncdef = { |
| 91434 | 91715 | 2+IsStat34, /* nArg */ |
| 91435 | 91716 | SQLITE_UTF8, /* funcFlags */ |
| 91436 | 91717 | 0, /* pUserData */ |
| 91437 | 91718 | 0, /* pNext */ |
| 91438 | | - statInit, /* xFunc */ |
| 91439 | | - 0, /* xStep */ |
| 91719 | + statInit, /* xSFunc */ |
| 91440 | 91720 | 0, /* xFinalize */ |
| 91441 | 91721 | "stat_init", /* zName */ |
| 91442 | 91722 | 0, /* pHash */ |
| 91443 | 91723 | 0 /* pDestructor */ |
| 91444 | 91724 | }; |
| | @@ -91734,12 +92014,11 @@ |
| 91734 | 92014 | static const FuncDef statPushFuncdef = { |
| 91735 | 92015 | 2+IsStat34, /* nArg */ |
| 91736 | 92016 | SQLITE_UTF8, /* funcFlags */ |
| 91737 | 92017 | 0, /* pUserData */ |
| 91738 | 92018 | 0, /* pNext */ |
| 91739 | | - statPush, /* xFunc */ |
| 91740 | | - 0, /* xStep */ |
| 92019 | + statPush, /* xSFunc */ |
| 91741 | 92020 | 0, /* xFinalize */ |
| 91742 | 92021 | "stat_push", /* zName */ |
| 91743 | 92022 | 0, /* pHash */ |
| 91744 | 92023 | 0 /* pDestructor */ |
| 91745 | 92024 | }; |
| | @@ -91881,12 +92160,11 @@ |
| 91881 | 92160 | static const FuncDef statGetFuncdef = { |
| 91882 | 92161 | 1+IsStat34, /* nArg */ |
| 91883 | 92162 | SQLITE_UTF8, /* funcFlags */ |
| 91884 | 92163 | 0, /* pUserData */ |
| 91885 | 92164 | 0, /* pNext */ |
| 91886 | | - statGet, /* xFunc */ |
| 91887 | | - 0, /* xStep */ |
| 92165 | + statGet, /* xSFunc */ |
| 91888 | 92166 | 0, /* xFinalize */ |
| 91889 | 92167 | "stat_get", /* zName */ |
| 91890 | 92168 | 0, /* pHash */ |
| 91891 | 92169 | 0 /* pDestructor */ |
| 91892 | 92170 | }; |
| | @@ -91898,12 +92176,12 @@ |
| 91898 | 92176 | #elif SQLITE_DEBUG |
| 91899 | 92177 | assert( iParam==STAT_GET_STAT1 ); |
| 91900 | 92178 | #else |
| 91901 | 92179 | UNUSED_PARAMETER( iParam ); |
| 91902 | 92180 | #endif |
| 91903 | | - sqlite3VdbeAddOp3(v, OP_Function0, 0, regStat4, regOut); |
| 91904 | | - sqlite3VdbeChangeP4(v, -1, (char*)&statGetFuncdef, P4_FUNCDEF); |
| 92181 | + sqlite3VdbeAddOp4(v, OP_Function0, 0, regStat4, regOut, |
| 92182 | + (char*)&statGetFuncdef, P4_FUNCDEF); |
| 91905 | 92183 | sqlite3VdbeChangeP5(v, 1 + IsStat34); |
| 91906 | 92184 | } |
| 91907 | 92185 | |
| 91908 | 92186 | /* |
| 91909 | 92187 | ** Generate code to do an analysis of all indices associated with |
| | @@ -92053,12 +92331,12 @@ |
| 92053 | 92331 | #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 |
| 92054 | 92332 | sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regStat4+3); |
| 92055 | 92333 | #endif |
| 92056 | 92334 | sqlite3VdbeAddOp2(v, OP_Integer, nCol, regStat4+1); |
| 92057 | 92335 | sqlite3VdbeAddOp2(v, OP_Integer, pIdx->nKeyCol, regStat4+2); |
| 92058 | | - sqlite3VdbeAddOp3(v, OP_Function0, 0, regStat4+1, regStat4); |
| 92059 | | - sqlite3VdbeChangeP4(v, -1, (char*)&statInitFuncdef, P4_FUNCDEF); |
| 92336 | + sqlite3VdbeAddOp4(v, OP_Function0, 0, regStat4+1, regStat4, |
| 92337 | + (char*)&statInitFuncdef, P4_FUNCDEF); |
| 92060 | 92338 | sqlite3VdbeChangeP5(v, 2+IsStat34); |
| 92061 | 92339 | |
| 92062 | 92340 | /* Implementation of the following: |
| 92063 | 92341 | ** |
| 92064 | 92342 | ** Rewind csr |
| | @@ -92150,12 +92428,12 @@ |
| 92150 | 92428 | sqlite3VdbeAddOp3(v, OP_MakeRecord, regKey, pPk->nKeyCol, regRowid); |
| 92151 | 92429 | sqlite3ReleaseTempRange(pParse, regKey, pPk->nKeyCol); |
| 92152 | 92430 | } |
| 92153 | 92431 | #endif |
| 92154 | 92432 | assert( regChng==(regStat4+1) ); |
| 92155 | | - sqlite3VdbeAddOp3(v, OP_Function0, 1, regStat4, regTemp); |
| 92156 | | - sqlite3VdbeChangeP4(v, -1, (char*)&statPushFuncdef, P4_FUNCDEF); |
| 92433 | + sqlite3VdbeAddOp4(v, OP_Function0, 1, regStat4, regTemp, |
| 92434 | + (char*)&statPushFuncdef, P4_FUNCDEF); |
| 92157 | 92435 | sqlite3VdbeChangeP5(v, 2+IsStat34); |
| 92158 | 92436 | sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, addrNextRow); VdbeCoverage(v); |
| 92159 | 92437 | |
| 92160 | 92438 | /* Add the entry to the stat1 table. */ |
| 92161 | 92439 | callStatGet(v, regStat4, STAT_GET_STAT1, regStat1); |
| | @@ -93208,15 +93486,15 @@ |
| 93208 | 93486 | sqlite3ExprCode(pParse, pDbname, regArgs+1); |
| 93209 | 93487 | sqlite3ExprCode(pParse, pKey, regArgs+2); |
| 93210 | 93488 | |
| 93211 | 93489 | assert( v || db->mallocFailed ); |
| 93212 | 93490 | if( v ){ |
| 93213 | | - sqlite3VdbeAddOp3(v, OP_Function0, 0, regArgs+3-pFunc->nArg, regArgs+3); |
| 93491 | + sqlite3VdbeAddOp4(v, OP_Function0, 0, regArgs+3-pFunc->nArg, regArgs+3, |
| 93492 | + (char *)pFunc, P4_FUNCDEF); |
| 93214 | 93493 | assert( pFunc->nArg==-1 || (pFunc->nArg&0xff)==pFunc->nArg ); |
| 93215 | 93494 | sqlite3VdbeChangeP5(v, (u8)(pFunc->nArg)); |
| 93216 | | - sqlite3VdbeChangeP4(v, -1, (char *)pFunc, P4_FUNCDEF); |
| 93217 | | - |
| 93495 | + |
| 93218 | 93496 | /* Code an OP_Expire. For an ATTACH statement, set P1 to true (expire this |
| 93219 | 93497 | ** statement only). For DETACH, set it to false (expire all existing |
| 93220 | 93498 | ** statements). |
| 93221 | 93499 | */ |
| 93222 | 93500 | sqlite3VdbeAddOp1(v, OP_Expire, (type==SQLITE_ATTACH)); |
| | @@ -93237,12 +93515,11 @@ |
| 93237 | 93515 | static const FuncDef detach_func = { |
| 93238 | 93516 | 1, /* nArg */ |
| 93239 | 93517 | SQLITE_UTF8, /* funcFlags */ |
| 93240 | 93518 | 0, /* pUserData */ |
| 93241 | 93519 | 0, /* pNext */ |
| 93242 | | - detachFunc, /* xFunc */ |
| 93243 | | - 0, /* xStep */ |
| 93520 | + detachFunc, /* xSFunc */ |
| 93244 | 93521 | 0, /* xFinalize */ |
| 93245 | 93522 | "sqlite_detach", /* zName */ |
| 93246 | 93523 | 0, /* pHash */ |
| 93247 | 93524 | 0 /* pDestructor */ |
| 93248 | 93525 | }; |
| | @@ -93258,12 +93535,11 @@ |
| 93258 | 93535 | static const FuncDef attach_func = { |
| 93259 | 93536 | 3, /* nArg */ |
| 93260 | 93537 | SQLITE_UTF8, /* funcFlags */ |
| 93261 | 93538 | 0, /* pUserData */ |
| 93262 | 93539 | 0, /* pNext */ |
| 93263 | | - attachFunc, /* xFunc */ |
| 93264 | | - 0, /* xStep */ |
| 93540 | + attachFunc, /* xSFunc */ |
| 93265 | 93541 | 0, /* xFinalize */ |
| 93266 | 93542 | "sqlite_attach", /* zName */ |
| 93267 | 93543 | 0, /* pHash */ |
| 93268 | 93544 | 0 /* pDestructor */ |
| 93269 | 93545 | }; |
| | @@ -93723,19 +93999,10 @@ |
| 93723 | 93999 | ** COMMIT |
| 93724 | 94000 | ** ROLLBACK |
| 93725 | 94001 | */ |
| 93726 | 94002 | /* #include "sqliteInt.h" */ |
| 93727 | 94003 | |
| 93728 | | -/* |
| 93729 | | -** This routine is called when a new SQL statement is beginning to |
| 93730 | | -** be parsed. Initialize the pParse structure as needed. |
| 93731 | | -*/ |
| 93732 | | -SQLITE_PRIVATE void sqlite3BeginParse(Parse *pParse, int explainFlag){ |
| 93733 | | - pParse->explain = (u8)explainFlag; |
| 93734 | | - pParse->nVar = 0; |
| 93735 | | -} |
| 93736 | | - |
| 93737 | 94004 | #ifndef SQLITE_OMIT_SHARED_CACHE |
| 93738 | 94005 | /* |
| 93739 | 94006 | ** The TableLock structure is only used by the sqlite3TableLock() and |
| 93740 | 94007 | ** codeTableLocks() functions. |
| 93741 | 94008 | */ |
| | @@ -93936,19 +94203,23 @@ |
| 93936 | 94203 | /* A minimum of one cursor is required if autoincrement is used |
| 93937 | 94204 | * See ticket [a696379c1f08866] */ |
| 93938 | 94205 | if( pParse->pAinc!=0 && pParse->nTab==0 ) pParse->nTab = 1; |
| 93939 | 94206 | sqlite3VdbeMakeReady(v, pParse); |
| 93940 | 94207 | pParse->rc = SQLITE_DONE; |
| 93941 | | - pParse->colNamesSet = 0; |
| 93942 | 94208 | }else{ |
| 93943 | 94209 | pParse->rc = SQLITE_ERROR; |
| 93944 | 94210 | } |
| 94211 | + |
| 94212 | + /* We are done with this Parse object. There is no need to de-initialize it */ |
| 94213 | +#if 0 |
| 94214 | + pParse->colNamesSet = 0; |
| 93945 | 94215 | pParse->nTab = 0; |
| 93946 | 94216 | pParse->nMem = 0; |
| 93947 | 94217 | pParse->nSet = 0; |
| 93948 | 94218 | pParse->nVar = 0; |
| 93949 | 94219 | DbMaskZero(pParse->cookieMask); |
| 94220 | +#endif |
| 93950 | 94221 | } |
| 93951 | 94222 | |
| 93952 | 94223 | /* |
| 93953 | 94224 | ** Run the parser and code generator recursively in order to generate |
| 93954 | 94225 | ** code for the SQL statement given onto the end of the pParse context |
| | @@ -94203,11 +94474,10 @@ |
| 94203 | 94474 | if( j<i ){ |
| 94204 | 94475 | db->aDb[j] = db->aDb[i]; |
| 94205 | 94476 | } |
| 94206 | 94477 | j++; |
| 94207 | 94478 | } |
| 94208 | | - memset(&db->aDb[j], 0, (db->nDb-j)*sizeof(db->aDb[j])); |
| 94209 | 94479 | db->nDb = j; |
| 94210 | 94480 | if( db->nDb<=2 && db->aDb!=db->aDbStatic ){ |
| 94211 | 94481 | memcpy(db->aDbStatic, db->aDb, 2*sizeof(db->aDb[0])); |
| 94212 | 94482 | sqlite3DbFree(db, db->aDb); |
| 94213 | 94483 | db->aDb = db->aDbStatic; |
| | @@ -94466,11 +94736,12 @@ |
| 94466 | 94736 | Token **pUnqual /* Write the unqualified object name here */ |
| 94467 | 94737 | ){ |
| 94468 | 94738 | int iDb; /* Database holding the object */ |
| 94469 | 94739 | sqlite3 *db = pParse->db; |
| 94470 | 94740 | |
| 94471 | | - if( ALWAYS(pName2!=0) && pName2->n>0 ){ |
| 94741 | + assert( pName2!=0 ); |
| 94742 | + if( pName2->n>0 ){ |
| 94472 | 94743 | if( db->init.busy ) { |
| 94473 | 94744 | sqlite3ErrorMsg(pParse, "corrupt database"); |
| 94474 | 94745 | return -1; |
| 94475 | 94746 | } |
| 94476 | 94747 | *pUnqual = pName2; |
| | @@ -94555,66 +94826,50 @@ |
| 94555 | 94826 | sqlite3 *db = pParse->db; |
| 94556 | 94827 | Vdbe *v; |
| 94557 | 94828 | int iDb; /* Database number to create the table in */ |
| 94558 | 94829 | Token *pName; /* Unqualified name of the table to create */ |
| 94559 | 94830 | |
| 94560 | | - /* The table or view name to create is passed to this routine via tokens |
| 94561 | | - ** pName1 and pName2. If the table name was fully qualified, for example: |
| 94562 | | - ** |
| 94563 | | - ** CREATE TABLE xxx.yyy (...); |
| 94564 | | - ** |
| 94565 | | - ** Then pName1 is set to "xxx" and pName2 "yyy". On the other hand if |
| 94566 | | - ** the table name is not fully qualified, i.e.: |
| 94567 | | - ** |
| 94568 | | - ** CREATE TABLE yyy(...); |
| 94569 | | - ** |
| 94570 | | - ** Then pName1 is set to "yyy" and pName2 is "". |
| 94571 | | - ** |
| 94572 | | - ** The call below sets the pName pointer to point at the token (pName1 or |
| 94573 | | - ** pName2) that stores the unqualified table name. The variable iDb is |
| 94574 | | - ** set to the index of the database that the table or view is to be |
| 94575 | | - ** created in. |
| 94576 | | - */ |
| 94577 | | - iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pName); |
| 94578 | | - if( iDb<0 ) return; |
| 94579 | | - if( !OMIT_TEMPDB && isTemp && pName2->n>0 && iDb!=1 ){ |
| 94580 | | - /* If creating a temp table, the name may not be qualified. Unless |
| 94581 | | - ** the database name is "temp" anyway. */ |
| 94582 | | - sqlite3ErrorMsg(pParse, "temporary table name must be unqualified"); |
| 94583 | | - return; |
| 94584 | | - } |
| 94585 | | - if( !OMIT_TEMPDB && isTemp ) iDb = 1; |
| 94586 | | - |
| 94587 | | - pParse->sNameToken = *pName; |
| 94588 | | - zName = sqlite3NameFromToken(db, pName); |
| 94831 | + if( db->init.busy && db->init.newTnum==1 ){ |
| 94832 | + /* Special case: Parsing the sqlite_master or sqlite_temp_master schema */ |
| 94833 | + iDb = db->init.iDb; |
| 94834 | + zName = sqlite3DbStrDup(db, SCHEMA_TABLE(iDb)); |
| 94835 | + pName = pName1; |
| 94836 | + }else{ |
| 94837 | + /* The common case */ |
| 94838 | + iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pName); |
| 94839 | + if( iDb<0 ) return; |
| 94840 | + if( !OMIT_TEMPDB && isTemp && pName2->n>0 && iDb!=1 ){ |
| 94841 | + /* If creating a temp table, the name may not be qualified. Unless |
| 94842 | + ** the database name is "temp" anyway. */ |
| 94843 | + sqlite3ErrorMsg(pParse, "temporary table name must be unqualified"); |
| 94844 | + return; |
| 94845 | + } |
| 94846 | + if( !OMIT_TEMPDB && isTemp ) iDb = 1; |
| 94847 | + zName = sqlite3NameFromToken(db, pName); |
| 94848 | + } |
| 94849 | + pParse->sNameToken = *pName; |
| 94589 | 94850 | if( zName==0 ) return; |
| 94590 | 94851 | if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){ |
| 94591 | 94852 | goto begin_table_error; |
| 94592 | 94853 | } |
| 94593 | 94854 | if( db->init.iDb==1 ) isTemp = 1; |
| 94594 | 94855 | #ifndef SQLITE_OMIT_AUTHORIZATION |
| 94595 | | - assert( (isTemp & 1)==isTemp ); |
| 94856 | + assert( isTemp==0 || isTemp==1 ); |
| 94857 | + assert( isView==0 || isView==1 ); |
| 94596 | 94858 | { |
| 94597 | | - int code; |
| 94859 | + static const u8 aCode[] = { |
| 94860 | + SQLITE_CREATE_TABLE, |
| 94861 | + SQLITE_CREATE_TEMP_TABLE, |
| 94862 | + SQLITE_CREATE_VIEW, |
| 94863 | + SQLITE_CREATE_TEMP_VIEW |
| 94864 | + }; |
| 94598 | 94865 | char *zDb = db->aDb[iDb].zName; |
| 94599 | 94866 | if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(isTemp), 0, zDb) ){ |
| 94600 | 94867 | goto begin_table_error; |
| 94601 | 94868 | } |
| 94602 | | - if( isView ){ |
| 94603 | | - if( !OMIT_TEMPDB && isTemp ){ |
| 94604 | | - code = SQLITE_CREATE_TEMP_VIEW; |
| 94605 | | - }else{ |
| 94606 | | - code = SQLITE_CREATE_VIEW; |
| 94607 | | - } |
| 94608 | | - }else{ |
| 94609 | | - if( !OMIT_TEMPDB && isTemp ){ |
| 94610 | | - code = SQLITE_CREATE_TEMP_TABLE; |
| 94611 | | - }else{ |
| 94612 | | - code = SQLITE_CREATE_TABLE; |
| 94613 | | - } |
| 94614 | | - } |
| 94615 | | - if( !isVirtual && sqlite3AuthCheck(pParse, code, zName, 0, zDb) ){ |
| 94869 | + if( !isVirtual && sqlite3AuthCheck(pParse, (int)aCode[isTemp+2*isView], |
| 94870 | + zName, 0, zDb) ){ |
| 94616 | 94871 | goto begin_table_error; |
| 94617 | 94872 | } |
| 94618 | 94873 | } |
| 94619 | 94874 | #endif |
| 94620 | 94875 | |
| | @@ -95572,13 +95827,17 @@ |
| 95572 | 95827 | /* If the db->init.busy is 1 it means we are reading the SQL off the |
| 95573 | 95828 | ** "sqlite_master" or "sqlite_temp_master" table on the disk. |
| 95574 | 95829 | ** So do not write to the disk again. Extract the root page number |
| 95575 | 95830 | ** for the table from the db->init.newTnum field. (The page number |
| 95576 | 95831 | ** should have been put there by the sqliteOpenCb routine.) |
| 95832 | + ** |
| 95833 | + ** If the root page number is 1, that means this is the sqlite_master |
| 95834 | + ** table itself. So mark it read-only. |
| 95577 | 95835 | */ |
| 95578 | 95836 | if( db->init.busy ){ |
| 95579 | 95837 | p->tnum = db->init.newTnum; |
| 95838 | + if( p->tnum==1 ) p->tabFlags |= TF_Readonly; |
| 95580 | 95839 | } |
| 95581 | 95840 | |
| 95582 | 95841 | /* Special processing for WITHOUT ROWID Tables */ |
| 95583 | 95842 | if( tabOpts & TF_WithoutRowid ){ |
| 95584 | 95843 | if( (p->tabFlags & TF_Autoincrement) ){ |
| | @@ -96027,10 +96286,11 @@ |
| 96027 | 96286 | ** erasing iTable (this can happen with an auto-vacuum database). |
| 96028 | 96287 | */ |
| 96029 | 96288 | static void destroyRootPage(Parse *pParse, int iTable, int iDb){ |
| 96030 | 96289 | Vdbe *v = sqlite3GetVdbe(pParse); |
| 96031 | 96290 | int r1 = sqlite3GetTempReg(pParse); |
| 96291 | + assert( iTable>1 ); |
| 96032 | 96292 | sqlite3VdbeAddOp3(v, OP_Destroy, iTable, r1, iDb); |
| 96033 | 96293 | sqlite3MayAbort(pParse); |
| 96034 | 96294 | #ifndef SQLITE_OMIT_AUTOVACUUM |
| 96035 | 96295 | /* OP_Destroy stores an in integer r1. If this integer |
| 96036 | 96296 | ** is non-zero, then it is the root page number of a table moved to |
| | @@ -97425,13 +97685,14 @@ |
| 97425 | 97685 | Token *pDatabase /* Database of the table */ |
| 97426 | 97686 | ){ |
| 97427 | 97687 | struct SrcList_item *pItem; |
| 97428 | 97688 | assert( pDatabase==0 || pTable!=0 ); /* Cannot have C without B */ |
| 97429 | 97689 | if( pList==0 ){ |
| 97430 | | - pList = sqlite3DbMallocZero(db, sizeof(SrcList) ); |
| 97690 | + pList = sqlite3DbMallocRaw(db, sizeof(SrcList) ); |
| 97431 | 97691 | if( pList==0 ) return 0; |
| 97432 | 97692 | pList->nAlloc = 1; |
| 97693 | + pList->nSrc = 0; |
| 97433 | 97694 | } |
| 97434 | 97695 | pList = sqlite3SrcListEnlarge(db, pList, 1, pList->nSrc); |
| 97435 | 97696 | if( db->mallocFailed ){ |
| 97436 | 97697 | sqlite3SrcListDelete(db, pList); |
| 97437 | 97698 | return 0; |
| | @@ -97830,11 +98091,11 @@ |
| 97830 | 98091 | assert( (errCode&0xff)==SQLITE_CONSTRAINT ); |
| 97831 | 98092 | if( onError==OE_Abort ){ |
| 97832 | 98093 | sqlite3MayAbort(pParse); |
| 97833 | 98094 | } |
| 97834 | 98095 | sqlite3VdbeAddOp4(v, OP_Halt, errCode, onError, 0, p4, p4type); |
| 97835 | | - if( p5Errmsg ) sqlite3VdbeChangeP5(v, p5Errmsg); |
| 98096 | + sqlite3VdbeChangeP5(v, p5Errmsg); |
| 97836 | 98097 | } |
| 97837 | 98098 | |
| 97838 | 98099 | /* |
| 97839 | 98100 | ** Code an OP_Halt due to UNIQUE or PRIMARY KEY constraint violation. |
| 97840 | 98101 | */ |
| | @@ -98371,12 +98632,12 @@ |
| 98371 | 98632 | ** 3: encoding matches and function takes any number of arguments |
| 98372 | 98633 | ** 4: UTF8/16 conversion required - argument count matches exactly |
| 98373 | 98634 | ** 5: UTF16 byte order conversion required - argument count matches exactly |
| 98374 | 98635 | ** 6: Perfect match: encoding and argument count match exactly. |
| 98375 | 98636 | ** |
| 98376 | | -** If nArg==(-2) then any function with a non-null xStep or xFunc is |
| 98377 | | -** a perfect match and any function with both xStep and xFunc NULL is |
| 98637 | +** If nArg==(-2) then any function with a non-null xSFunc is |
| 98638 | +** a perfect match and any function with xSFunc NULL is |
| 98378 | 98639 | ** a non-match. |
| 98379 | 98640 | */ |
| 98380 | 98641 | #define FUNC_PERFECT_MATCH 6 /* The score for a perfect match */ |
| 98381 | 98642 | static int matchQuality( |
| 98382 | 98643 | FuncDef *p, /* The function we are evaluating for match quality */ |
| | @@ -98384,11 +98645,11 @@ |
| 98384 | 98645 | u8 enc /* Desired text encoding */ |
| 98385 | 98646 | ){ |
| 98386 | 98647 | int match; |
| 98387 | 98648 | |
| 98388 | 98649 | /* nArg of -2 is a special case */ |
| 98389 | | - if( nArg==(-2) ) return (p->xFunc==0 && p->xStep==0) ? 0 : FUNC_PERFECT_MATCH; |
| 98650 | + if( nArg==(-2) ) return (p->xSFunc==0) ? 0 : FUNC_PERFECT_MATCH; |
| 98390 | 98651 | |
| 98391 | 98652 | /* Wrong number of arguments means "no match" */ |
| 98392 | 98653 | if( p->nArg!=nArg && p->nArg>=0 ) return 0; |
| 98393 | 98654 | |
| 98394 | 98655 | /* Give a better score to a function with a specific number of arguments |
| | @@ -98462,11 +98723,11 @@ |
| 98462 | 98723 | ** If the createFlag argument is true, then a new (blank) FuncDef |
| 98463 | 98724 | ** structure is created and liked into the "db" structure if a |
| 98464 | 98725 | ** no matching function previously existed. |
| 98465 | 98726 | ** |
| 98466 | 98727 | ** If nArg is -2, then the first valid function found is returned. A |
| 98467 | | -** function is valid if either xFunc or xStep is non-zero. The nArg==(-2) |
| 98728 | +** function is valid if xSFunc is non-zero. The nArg==(-2) |
| 98468 | 98729 | ** case is used to see if zName is a valid function name for some number |
| 98469 | 98730 | ** of arguments. If nArg is -2, then createFlag must be 0. |
| 98470 | 98731 | ** |
| 98471 | 98732 | ** If createFlag is false, then a function with the required name and |
| 98472 | 98733 | ** number of arguments may be returned even if the eTextRep flag does not |
| | @@ -98539,11 +98800,11 @@ |
| 98539 | 98800 | memcpy(pBest->zName, zName, nName); |
| 98540 | 98801 | pBest->zName[nName] = 0; |
| 98541 | 98802 | sqlite3FuncDefInsert(&db->aFunc, pBest); |
| 98542 | 98803 | } |
| 98543 | 98804 | |
| 98544 | | - if( pBest && (pBest->xStep || pBest->xFunc || createFlag) ){ |
| 98805 | + if( pBest && (pBest->xSFunc || createFlag) ){ |
| 98545 | 98806 | return pBest; |
| 98546 | 98807 | } |
| 98547 | 98808 | return 0; |
| 98548 | 98809 | } |
| 98549 | 98810 | |
| | @@ -100072,14 +100333,14 @@ |
| 100072 | 100333 | |
| 100073 | 100334 | /* |
| 100074 | 100335 | ** A structure defining how to do GLOB-style comparisons. |
| 100075 | 100336 | */ |
| 100076 | 100337 | struct compareInfo { |
| 100077 | | - u8 matchAll; |
| 100078 | | - u8 matchOne; |
| 100079 | | - u8 matchSet; |
| 100080 | | - u8 noCase; |
| 100338 | + u8 matchAll; /* "*" or "%" */ |
| 100339 | + u8 matchOne; /* "?" or "_" */ |
| 100340 | + u8 matchSet; /* "[" or 0 */ |
| 100341 | + u8 noCase; /* true to ignore case differences */ |
| 100081 | 100342 | }; |
| 100082 | 100343 | |
| 100083 | 100344 | /* |
| 100084 | 100345 | ** For LIKE and GLOB matching on EBCDIC machines, assume that every |
| 100085 | 100346 | ** character is exactly one byte in size. Also, provde the Utf8Read() |
| | @@ -100138,26 +100399,18 @@ |
| 100138 | 100399 | */ |
| 100139 | 100400 | static int patternCompare( |
| 100140 | 100401 | const u8 *zPattern, /* The glob pattern */ |
| 100141 | 100402 | const u8 *zString, /* The string to compare against the glob */ |
| 100142 | 100403 | const struct compareInfo *pInfo, /* Information about how to do the compare */ |
| 100143 | | - u32 esc /* The escape character */ |
| 100404 | + u32 matchOther /* The escape char (LIKE) or '[' (GLOB) */ |
| 100144 | 100405 | ){ |
| 100145 | 100406 | u32 c, c2; /* Next pattern and input string chars */ |
| 100146 | 100407 | u32 matchOne = pInfo->matchOne; /* "?" or "_" */ |
| 100147 | 100408 | u32 matchAll = pInfo->matchAll; /* "*" or "%" */ |
| 100148 | | - u32 matchOther; /* "[" or the escape character */ |
| 100149 | 100409 | u8 noCase = pInfo->noCase; /* True if uppercase==lowercase */ |
| 100150 | 100410 | const u8 *zEscaped = 0; /* One past the last escaped input char */ |
| 100151 | 100411 | |
| 100152 | | - /* The GLOB operator does not have an ESCAPE clause. And LIKE does not |
| 100153 | | - ** have the matchSet operator. So we either have to look for one or |
| 100154 | | - ** the other, never both. Hence the single variable matchOther is used |
| 100155 | | - ** to store the one we have to look for. |
| 100156 | | - */ |
| 100157 | | - matchOther = esc ? esc : pInfo->matchSet; |
| 100158 | | - |
| 100159 | 100412 | while( (c = Utf8Read(zPattern))!=0 ){ |
| 100160 | 100413 | if( c==matchAll ){ /* Match "*" */ |
| 100161 | 100414 | /* Skip over multiple "*" characters in the pattern. If there |
| 100162 | 100415 | ** are also "?" characters, skip those as well, but consume a |
| 100163 | 100416 | ** single character of the input string for each "?" skipped */ |
| | @@ -100167,19 +100420,19 @@ |
| 100167 | 100420 | } |
| 100168 | 100421 | } |
| 100169 | 100422 | if( c==0 ){ |
| 100170 | 100423 | return 1; /* "*" at the end of the pattern matches */ |
| 100171 | 100424 | }else if( c==matchOther ){ |
| 100172 | | - if( esc ){ |
| 100425 | + if( pInfo->matchSet==0 ){ |
| 100173 | 100426 | c = sqlite3Utf8Read(&zPattern); |
| 100174 | 100427 | if( c==0 ) return 0; |
| 100175 | 100428 | }else{ |
| 100176 | 100429 | /* "[...]" immediately follows the "*". We have to do a slow |
| 100177 | 100430 | ** recursive search in this case, but it is an unusual case. */ |
| 100178 | 100431 | assert( matchOther<0x80 ); /* '[' is a single-byte character */ |
| 100179 | 100432 | while( *zString |
| 100180 | | - && patternCompare(&zPattern[-1],zString,pInfo,esc)==0 ){ |
| 100433 | + && patternCompare(&zPattern[-1],zString,pInfo,matchOther)==0 ){ |
| 100181 | 100434 | SQLITE_SKIP_UTF8(zString); |
| 100182 | 100435 | } |
| 100183 | 100436 | return *zString!=0; |
| 100184 | 100437 | } |
| 100185 | 100438 | } |
| | @@ -100201,22 +100454,22 @@ |
| 100201 | 100454 | }else{ |
| 100202 | 100455 | cx = c; |
| 100203 | 100456 | } |
| 100204 | 100457 | while( (c2 = *(zString++))!=0 ){ |
| 100205 | 100458 | if( c2!=c && c2!=cx ) continue; |
| 100206 | | - if( patternCompare(zPattern,zString,pInfo,esc) ) return 1; |
| 100459 | + if( patternCompare(zPattern,zString,pInfo,matchOther) ) return 1; |
| 100207 | 100460 | } |
| 100208 | 100461 | }else{ |
| 100209 | 100462 | while( (c2 = Utf8Read(zString))!=0 ){ |
| 100210 | 100463 | if( c2!=c ) continue; |
| 100211 | | - if( patternCompare(zPattern,zString,pInfo,esc) ) return 1; |
| 100464 | + if( patternCompare(zPattern,zString,pInfo,matchOther) ) return 1; |
| 100212 | 100465 | } |
| 100213 | 100466 | } |
| 100214 | 100467 | return 0; |
| 100215 | 100468 | } |
| 100216 | 100469 | if( c==matchOther ){ |
| 100217 | | - if( esc ){ |
| 100470 | + if( pInfo->matchSet==0 ){ |
| 100218 | 100471 | c = sqlite3Utf8Read(&zPattern); |
| 100219 | 100472 | if( c==0 ) return 0; |
| 100220 | 100473 | zEscaped = zPattern; |
| 100221 | 100474 | }else{ |
| 100222 | 100475 | u32 prior_c = 0; |
| | @@ -100252,11 +100505,11 @@ |
| 100252 | 100505 | continue; |
| 100253 | 100506 | } |
| 100254 | 100507 | } |
| 100255 | 100508 | c2 = Utf8Read(zString); |
| 100256 | 100509 | if( c==c2 ) continue; |
| 100257 | | - if( noCase && sqlite3Tolower(c)==sqlite3Tolower(c2) ){ |
| 100510 | + if( noCase && c<0x80 && c2<0x80 && sqlite3Tolower(c)==sqlite3Tolower(c2) ){ |
| 100258 | 100511 | continue; |
| 100259 | 100512 | } |
| 100260 | 100513 | if( c==matchOne && zPattern!=zEscaped && c2!=0 ) continue; |
| 100261 | 100514 | return 0; |
| 100262 | 100515 | } |
| | @@ -100265,11 +100518,11 @@ |
| 100265 | 100518 | |
| 100266 | 100519 | /* |
| 100267 | 100520 | ** The sqlite3_strglob() interface. |
| 100268 | 100521 | */ |
| 100269 | 100522 | SQLITE_API int SQLITE_STDCALL sqlite3_strglob(const char *zGlobPattern, const char *zString){ |
| 100270 | | - return patternCompare((u8*)zGlobPattern, (u8*)zString, &globInfo, 0)==0; |
| 100523 | + return patternCompare((u8*)zGlobPattern, (u8*)zString, &globInfo, '[')==0; |
| 100271 | 100524 | } |
| 100272 | 100525 | |
| 100273 | 100526 | /* |
| 100274 | 100527 | ** The sqlite3_strlike() interface. |
| 100275 | 100528 | */ |
| | @@ -100303,13 +100556,14 @@ |
| 100303 | 100556 | sqlite3_context *context, |
| 100304 | 100557 | int argc, |
| 100305 | 100558 | sqlite3_value **argv |
| 100306 | 100559 | ){ |
| 100307 | 100560 | const unsigned char *zA, *zB; |
| 100308 | | - u32 escape = 0; |
| 100561 | + u32 escape; |
| 100309 | 100562 | int nPat; |
| 100310 | 100563 | sqlite3 *db = sqlite3_context_db_handle(context); |
| 100564 | + struct compareInfo *pInfo = sqlite3_user_data(context); |
| 100311 | 100565 | |
| 100312 | 100566 | #ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS |
| 100313 | 100567 | if( sqlite3_value_type(argv[0])==SQLITE_BLOB |
| 100314 | 100568 | || sqlite3_value_type(argv[1])==SQLITE_BLOB |
| 100315 | 100569 | ){ |
| | @@ -100345,17 +100599,17 @@ |
| 100345 | 100599 | sqlite3_result_error(context, |
| 100346 | 100600 | "ESCAPE expression must be a single character", -1); |
| 100347 | 100601 | return; |
| 100348 | 100602 | } |
| 100349 | 100603 | escape = sqlite3Utf8Read(&zEsc); |
| 100604 | + }else{ |
| 100605 | + escape = pInfo->matchSet; |
| 100350 | 100606 | } |
| 100351 | 100607 | if( zA && zB ){ |
| 100352 | | - struct compareInfo *pInfo = sqlite3_user_data(context); |
| 100353 | 100608 | #ifdef SQLITE_TEST |
| 100354 | 100609 | sqlite3_like_count++; |
| 100355 | 100610 | #endif |
| 100356 | | - |
| 100357 | 100611 | sqlite3_result_int(context, patternCompare(zB, zA, pInfo, escape)); |
| 100358 | 100612 | } |
| 100359 | 100613 | } |
| 100360 | 100614 | |
| 100361 | 100615 | /* |
| | @@ -104328,11 +104582,11 @@ |
| 104328 | 104582 | if( useSeekResult ) pik_flags = OPFLAG_USESEEKRESULT; |
| 104329 | 104583 | if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){ |
| 104330 | 104584 | assert( pParse->nested==0 ); |
| 104331 | 104585 | pik_flags |= OPFLAG_NCHANGE; |
| 104332 | 104586 | } |
| 104333 | | - if( pik_flags ) sqlite3VdbeChangeP5(v, pik_flags); |
| 104587 | + sqlite3VdbeChangeP5(v, pik_flags); |
| 104334 | 104588 | } |
| 104335 | 104589 | if( !HasRowid(pTab) ) return; |
| 104336 | 104590 | regData = regNewData + 1; |
| 104337 | 104591 | regRec = sqlite3GetTempReg(pParse); |
| 104338 | 104592 | sqlite3VdbeAddOp3(v, OP_MakeRecord, regData, pTab->nCol, regRec); |
| | @@ -104744,13 +104998,13 @@ |
| 104744 | 104998 | }else{ |
| 104745 | 104999 | addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid); |
| 104746 | 105000 | assert( (pDest->tabFlags & TF_Autoincrement)==0 ); |
| 104747 | 105001 | } |
| 104748 | 105002 | sqlite3VdbeAddOp2(v, OP_RowData, iSrc, regData); |
| 104749 | | - sqlite3VdbeAddOp3(v, OP_Insert, iDest, regData, regRowid); |
| 105003 | + sqlite3VdbeAddOp4(v, OP_Insert, iDest, regData, regRowid, |
| 105004 | + pDest->zName, 0); |
| 104750 | 105005 | sqlite3VdbeChangeP5(v, OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND); |
| 104751 | | - sqlite3VdbeChangeP4(v, -1, pDest->zName, 0); |
| 104752 | 105006 | sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1); VdbeCoverage(v); |
| 104753 | 105007 | sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0); |
| 104754 | 105008 | sqlite3VdbeAddOp2(v, OP_Close, iDest, 0); |
| 104755 | 105009 | }else{ |
| 104756 | 105010 | sqlite3TableLock(pParse, iDbDest, pDest->tnum, 1, pDest->zName); |
| | @@ -107199,19 +107453,21 @@ |
| 107199 | 107453 | { OP_IfPos, 1, 8, 0}, |
| 107200 | 107454 | { OP_Integer, 0, 1, 0}, /* 6 */ |
| 107201 | 107455 | { OP_Noop, 0, 0, 0}, |
| 107202 | 107456 | { OP_ResultRow, 1, 1, 0}, |
| 107203 | 107457 | }; |
| 107204 | | - int addr; |
| 107458 | + VdbeOp *aOp; |
| 107205 | 107459 | sqlite3VdbeUsesBtree(v, iDb); |
| 107206 | 107460 | if( !zRight ){ |
| 107207 | 107461 | setOneColumnName(v, "cache_size"); |
| 107208 | 107462 | pParse->nMem += 2; |
| 107209 | | - addr = sqlite3VdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize,iLn); |
| 107210 | | - sqlite3VdbeChangeP1(v, addr, iDb); |
| 107211 | | - sqlite3VdbeChangeP1(v, addr+1, iDb); |
| 107212 | | - sqlite3VdbeChangeP1(v, addr+6, SQLITE_DEFAULT_CACHE_SIZE); |
| 107463 | + sqlite3VdbeVerifyNoMallocRequired(v, ArraySize(getCacheSize)); |
| 107464 | + aOp = sqlite3VdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize, iLn); |
| 107465 | + if( ONLY_IF_REALLOC_STRESS(aOp==0) ) break; |
| 107466 | + aOp[0].p1 = iDb; |
| 107467 | + aOp[1].p1 = iDb; |
| 107468 | + aOp[6].p1 = SQLITE_DEFAULT_CACHE_SIZE; |
| 107213 | 107469 | }else{ |
| 107214 | 107470 | int size = sqlite3AbsInt32(sqlite3Atoi(zRight)); |
| 107215 | 107471 | sqlite3BeginWriteOperation(pParse, 0, iDb); |
| 107216 | 107472 | sqlite3VdbeAddOp2(v, OP_Integer, size, 1); |
| 107217 | 107473 | sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_DEFAULT_CACHE_SIZE, 1); |
| | @@ -107453,17 +107709,20 @@ |
| 107453 | 107709 | { OP_If, 1, 0, 0}, /* 2 */ |
| 107454 | 107710 | { OP_Halt, SQLITE_OK, OE_Abort, 0}, /* 3 */ |
| 107455 | 107711 | { OP_Integer, 0, 1, 0}, /* 4 */ |
| 107456 | 107712 | { OP_SetCookie, 0, BTREE_INCR_VACUUM, 1}, /* 5 */ |
| 107457 | 107713 | }; |
| 107458 | | - int iAddr; |
| 107459 | | - iAddr = sqlite3VdbeAddOpList(v, ArraySize(setMeta6), setMeta6, iLn); |
| 107460 | | - sqlite3VdbeChangeP1(v, iAddr, iDb); |
| 107461 | | - sqlite3VdbeChangeP1(v, iAddr+1, iDb); |
| 107462 | | - sqlite3VdbeChangeP2(v, iAddr+2, iAddr+4); |
| 107463 | | - sqlite3VdbeChangeP1(v, iAddr+4, eAuto-1); |
| 107464 | | - sqlite3VdbeChangeP1(v, iAddr+5, iDb); |
| 107714 | + VdbeOp *aOp; |
| 107715 | + int iAddr = sqlite3VdbeCurrentAddr(v); |
| 107716 | + sqlite3VdbeVerifyNoMallocRequired(v, ArraySize(setMeta6)); |
| 107717 | + aOp = sqlite3VdbeAddOpList(v, ArraySize(setMeta6), setMeta6, iLn); |
| 107718 | + if( ONLY_IF_REALLOC_STRESS(aOp==0) ) break; |
| 107719 | + aOp[0].p1 = iDb; |
| 107720 | + aOp[1].p1 = iDb; |
| 107721 | + aOp[2].p2 = iAddr+4; |
| 107722 | + aOp[4].p1 = eAuto - 1; |
| 107723 | + aOp[5].p1 = iDb; |
| 107465 | 107724 | sqlite3VdbeUsesBtree(v, iDb); |
| 107466 | 107725 | } |
| 107467 | 107726 | } |
| 107468 | 107727 | break; |
| 107469 | 107728 | } |
| | @@ -108165,22 +108424,10 @@ |
| 108165 | 108424 | ** without most of the overhead of a full integrity-check. |
| 108166 | 108425 | */ |
| 108167 | 108426 | case PragTyp_INTEGRITY_CHECK: { |
| 108168 | 108427 | int i, j, addr, mxErr; |
| 108169 | 108428 | |
| 108170 | | - /* Code that appears at the end of the integrity check. If no error |
| 108171 | | - ** messages have been generated, output OK. Otherwise output the |
| 108172 | | - ** error message |
| 108173 | | - */ |
| 108174 | | - static const int iLn = VDBE_OFFSET_LINENO(2); |
| 108175 | | - static const VdbeOpList endCode[] = { |
| 108176 | | - { OP_AddImm, 1, 0, 0}, /* 0 */ |
| 108177 | | - { OP_If, 1, 0, 0}, /* 1 */ |
| 108178 | | - { OP_String8, 0, 3, 0}, /* 2 */ |
| 108179 | | - { OP_ResultRow, 3, 1, 0}, |
| 108180 | | - }; |
| 108181 | | - |
| 108182 | 108429 | int isQuick = (sqlite3Tolower(zLeft[0])=='q'); |
| 108183 | 108430 | |
| 108184 | 108431 | /* If the PRAGMA command was of the form "PRAGMA <db>.integrity_check", |
| 108185 | 108432 | ** then iDb is set to the index of the database identified by <db>. |
| 108186 | 108433 | ** In this case, the integrity of database iDb only is verified by |
| | @@ -108373,14 +108620,28 @@ |
| 108373 | 108620 | sqlite3VdbeAddOp2(v, OP_ResultRow, 7, 1); |
| 108374 | 108621 | } |
| 108375 | 108622 | #endif /* SQLITE_OMIT_BTREECOUNT */ |
| 108376 | 108623 | } |
| 108377 | 108624 | } |
| 108378 | | - addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode, iLn); |
| 108379 | | - sqlite3VdbeChangeP2(v, addr, -mxErr); |
| 108380 | | - sqlite3VdbeJumpHere(v, addr+1); |
| 108381 | | - sqlite3VdbeChangeP4(v, addr+2, "ok", P4_STATIC); |
| 108625 | + { |
| 108626 | + static const int iLn = VDBE_OFFSET_LINENO(2); |
| 108627 | + static const VdbeOpList endCode[] = { |
| 108628 | + { OP_AddImm, 1, 0, 0}, /* 0 */ |
| 108629 | + { OP_If, 1, 0, 0}, /* 1 */ |
| 108630 | + { OP_String8, 0, 3, 0}, /* 2 */ |
| 108631 | + { OP_ResultRow, 3, 1, 0}, |
| 108632 | + }; |
| 108633 | + VdbeOp *aOp; |
| 108634 | + |
| 108635 | + aOp = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode, iLn); |
| 108636 | + if( aOp ){ |
| 108637 | + aOp[0].p2 = -mxErr; |
| 108638 | + aOp[1].p2 = sqlite3VdbeCurrentAddr(v); |
| 108639 | + aOp[2].p4type = P4_STATIC; |
| 108640 | + aOp[2].p4.z = "ok"; |
| 108641 | + } |
| 108642 | + } |
| 108382 | 108643 | } |
| 108383 | 108644 | break; |
| 108384 | 108645 | #endif /* SQLITE_OMIT_INTEGRITY_CHECK */ |
| 108385 | 108646 | |
| 108386 | 108647 | #ifndef SQLITE_OMIT_UTF16 |
| | @@ -108493,26 +108754,32 @@ |
| 108493 | 108754 | static const VdbeOpList setCookie[] = { |
| 108494 | 108755 | { OP_Transaction, 0, 1, 0}, /* 0 */ |
| 108495 | 108756 | { OP_Integer, 0, 1, 0}, /* 1 */ |
| 108496 | 108757 | { OP_SetCookie, 0, 0, 1}, /* 2 */ |
| 108497 | 108758 | }; |
| 108498 | | - int addr = sqlite3VdbeAddOpList(v, ArraySize(setCookie), setCookie, 0); |
| 108499 | | - sqlite3VdbeChangeP1(v, addr, iDb); |
| 108500 | | - sqlite3VdbeChangeP1(v, addr+1, sqlite3Atoi(zRight)); |
| 108501 | | - sqlite3VdbeChangeP1(v, addr+2, iDb); |
| 108502 | | - sqlite3VdbeChangeP2(v, addr+2, iCookie); |
| 108759 | + VdbeOp *aOp; |
| 108760 | + sqlite3VdbeVerifyNoMallocRequired(v, ArraySize(setCookie)); |
| 108761 | + aOp = sqlite3VdbeAddOpList(v, ArraySize(setCookie), setCookie, 0); |
| 108762 | + if( ONLY_IF_REALLOC_STRESS(aOp==0) ) break; |
| 108763 | + aOp[0].p1 = iDb; |
| 108764 | + aOp[1].p1 = sqlite3Atoi(zRight); |
| 108765 | + aOp[2].p1 = iDb; |
| 108766 | + aOp[2].p2 = iCookie; |
| 108503 | 108767 | }else{ |
| 108504 | 108768 | /* Read the specified cookie value */ |
| 108505 | 108769 | static const VdbeOpList readCookie[] = { |
| 108506 | 108770 | { OP_Transaction, 0, 0, 0}, /* 0 */ |
| 108507 | 108771 | { OP_ReadCookie, 0, 1, 0}, /* 1 */ |
| 108508 | 108772 | { OP_ResultRow, 1, 1, 0} |
| 108509 | 108773 | }; |
| 108510 | | - int addr = sqlite3VdbeAddOpList(v, ArraySize(readCookie), readCookie, 0); |
| 108511 | | - sqlite3VdbeChangeP1(v, addr, iDb); |
| 108512 | | - sqlite3VdbeChangeP1(v, addr+1, iDb); |
| 108513 | | - sqlite3VdbeChangeP3(v, addr+1, iCookie); |
| 108774 | + VdbeOp *aOp; |
| 108775 | + sqlite3VdbeVerifyNoMallocRequired(v, ArraySize(readCookie)); |
| 108776 | + aOp = sqlite3VdbeAddOpList(v, ArraySize(readCookie),readCookie,0); |
| 108777 | + if( ONLY_IF_REALLOC_STRESS(aOp==0) ) break; |
| 108778 | + aOp[0].p1 = iDb; |
| 108779 | + aOp[1].p1 = iDb; |
| 108780 | + aOp[1].p3 = iCookie; |
| 108514 | 108781 | sqlite3VdbeSetNumCols(v, 1); |
| 108515 | 108782 | sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLeft, SQLITE_TRANSIENT); |
| 108516 | 108783 | } |
| 108517 | 108784 | } |
| 108518 | 108785 | break; |
| | @@ -108875,65 +109142,31 @@ |
| 108875 | 109142 | int rc; |
| 108876 | 109143 | int i; |
| 108877 | 109144 | #ifndef SQLITE_OMIT_DEPRECATED |
| 108878 | 109145 | int size; |
| 108879 | 109146 | #endif |
| 108880 | | - Table *pTab; |
| 108881 | 109147 | Db *pDb; |
| 108882 | 109148 | char const *azArg[4]; |
| 108883 | 109149 | int meta[5]; |
| 108884 | 109150 | InitData initData; |
| 108885 | | - char const *zMasterSchema; |
| 108886 | | - char const *zMasterName; |
| 109151 | + const char *zMasterName; |
| 108887 | 109152 | int openedTransaction = 0; |
| 108888 | 109153 | |
| 108889 | | - /* |
| 108890 | | - ** The master database table has a structure like this |
| 108891 | | - */ |
| 108892 | | - static const char master_schema[] = |
| 108893 | | - "CREATE TABLE sqlite_master(\n" |
| 108894 | | - " type text,\n" |
| 108895 | | - " name text,\n" |
| 108896 | | - " tbl_name text,\n" |
| 108897 | | - " rootpage integer,\n" |
| 108898 | | - " sql text\n" |
| 108899 | | - ")" |
| 108900 | | - ; |
| 108901 | | -#ifndef SQLITE_OMIT_TEMPDB |
| 108902 | | - static const char temp_master_schema[] = |
| 108903 | | - "CREATE TEMP TABLE sqlite_temp_master(\n" |
| 108904 | | - " type text,\n" |
| 108905 | | - " name text,\n" |
| 108906 | | - " tbl_name text,\n" |
| 108907 | | - " rootpage integer,\n" |
| 108908 | | - " sql text\n" |
| 108909 | | - ")" |
| 108910 | | - ; |
| 108911 | | -#else |
| 108912 | | - #define temp_master_schema 0 |
| 108913 | | -#endif |
| 108914 | | - |
| 108915 | 109154 | assert( iDb>=0 && iDb<db->nDb ); |
| 108916 | 109155 | assert( db->aDb[iDb].pSchema ); |
| 108917 | 109156 | assert( sqlite3_mutex_held(db->mutex) ); |
| 108918 | 109157 | assert( iDb==1 || sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) ); |
| 108919 | 109158 | |
| 108920 | | - /* zMasterSchema and zInitScript are set to point at the master schema |
| 108921 | | - ** and initialisation script appropriate for the database being |
| 108922 | | - ** initialized. zMasterName is the name of the master table. |
| 108923 | | - */ |
| 108924 | | - if( !OMIT_TEMPDB && iDb==1 ){ |
| 108925 | | - zMasterSchema = temp_master_schema; |
| 108926 | | - }else{ |
| 108927 | | - zMasterSchema = master_schema; |
| 108928 | | - } |
| 108929 | | - zMasterName = SCHEMA_TABLE(iDb); |
| 108930 | | - |
| 108931 | | - /* Construct the schema tables. */ |
| 108932 | | - azArg[0] = zMasterName; |
| 109159 | + /* Construct the in-memory representation schema tables (sqlite_master or |
| 109160 | + ** sqlite_temp_master) by invoking the parser directly. The appropriate |
| 109161 | + ** table name will be inserted automatically by the parser so we can just |
| 109162 | + ** use the abbreviation "x" here. The parser will also automatically tag |
| 109163 | + ** the schema table as read-only. */ |
| 109164 | + azArg[0] = zMasterName = SCHEMA_TABLE(iDb); |
| 108933 | 109165 | azArg[1] = "1"; |
| 108934 | | - azArg[2] = zMasterSchema; |
| 109166 | + azArg[2] = "CREATE TABLE x(type text,name text,tbl_name text," |
| 109167 | + "rootpage integer,sql text)"; |
| 108935 | 109168 | azArg[3] = 0; |
| 108936 | 109169 | initData.db = db; |
| 108937 | 109170 | initData.iDb = iDb; |
| 108938 | 109171 | initData.rc = SQLITE_OK; |
| 108939 | 109172 | initData.pzErrMsg = pzErrMsg; |
| | @@ -108940,14 +109173,10 @@ |
| 108940 | 109173 | sqlite3InitCallback(&initData, 3, (char **)azArg, 0); |
| 108941 | 109174 | if( initData.rc ){ |
| 108942 | 109175 | rc = initData.rc; |
| 108943 | 109176 | goto error_out; |
| 108944 | 109177 | } |
| 108945 | | - pTab = sqlite3FindTable(db, zMasterName, db->aDb[iDb].zName); |
| 108946 | | - if( ALWAYS(pTab) ){ |
| 108947 | | - pTab->tabFlags |= TF_Readonly; |
| 108948 | | - } |
| 108949 | 109178 | |
| 108950 | 109179 | /* Create a cursor to hold the database open |
| 108951 | 109180 | */ |
| 108952 | 109181 | pDb = &db->aDb[iDb]; |
| 108953 | 109182 | if( pDb->pBt==0 ){ |
| | @@ -109062,11 +109291,11 @@ |
| 109062 | 109291 | */ |
| 109063 | 109292 | assert( db->init.busy ); |
| 109064 | 109293 | { |
| 109065 | 109294 | char *zSql; |
| 109066 | 109295 | zSql = sqlite3MPrintf(db, |
| 109067 | | - "SELECT name, rootpage, sql FROM '%q'.%s ORDER BY rowid", |
| 109296 | + "SELECT name, rootpage, sql FROM \"%w\".%s ORDER BY rowid", |
| 109068 | 109297 | db->aDb[iDb].zName, zMasterName); |
| 109069 | 109298 | #ifndef SQLITE_OMIT_AUTHORIZATION |
| 109070 | 109299 | { |
| 109071 | 109300 | sqlite3_xauth xAuth; |
| 109072 | 109301 | xAuth = db->xAuth; |
| | @@ -109688,10 +109917,11 @@ |
| 109688 | 109917 | int nOBSat; /* Number of ORDER BY terms satisfied by indices */ |
| 109689 | 109918 | int iECursor; /* Cursor number for the sorter */ |
| 109690 | 109919 | int regReturn; /* Register holding block-output return address */ |
| 109691 | 109920 | int labelBkOut; /* Start label for the block-output subroutine */ |
| 109692 | 109921 | int addrSortIndex; /* Address of the OP_SorterOpen or OP_OpenEphemeral */ |
| 109922 | + int labelDone; /* Jump here when done, ex: LIMIT reached */ |
| 109693 | 109923 | u8 sortFlags; /* Zero or more SORTFLAG_* bits */ |
| 109694 | 109924 | }; |
| 109695 | 109925 | #define SORTFLAG_UseSorter 0x01 /* Use SorterOpen instead of OpenEphemeral */ |
| 109696 | 109926 | |
| 109697 | 109927 | /* |
| | @@ -109745,33 +109975,41 @@ |
| 109745 | 109975 | Expr *pOffset /* OFFSET value. NULL means no offset */ |
| 109746 | 109976 | ){ |
| 109747 | 109977 | Select *pNew; |
| 109748 | 109978 | Select standin; |
| 109749 | 109979 | sqlite3 *db = pParse->db; |
| 109750 | | - pNew = sqlite3DbMallocZero(db, sizeof(*pNew) ); |
| 109980 | + pNew = sqlite3DbMallocRaw(db, sizeof(*pNew) ); |
| 109751 | 109981 | if( pNew==0 ){ |
| 109752 | 109982 | assert( db->mallocFailed ); |
| 109753 | 109983 | pNew = &standin; |
| 109754 | | - memset(pNew, 0, sizeof(*pNew)); |
| 109755 | 109984 | } |
| 109756 | 109985 | if( pEList==0 ){ |
| 109757 | 109986 | pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db,TK_ASTERISK,0)); |
| 109758 | 109987 | } |
| 109759 | 109988 | pNew->pEList = pEList; |
| 109989 | + pNew->op = TK_SELECT; |
| 109990 | + pNew->selFlags = selFlags; |
| 109991 | + pNew->iLimit = 0; |
| 109992 | + pNew->iOffset = 0; |
| 109993 | +#if SELECTTRACE_ENABLED |
| 109994 | + pNew->zSelName[0] = 0; |
| 109995 | +#endif |
| 109996 | + pNew->addrOpenEphm[0] = -1; |
| 109997 | + pNew->addrOpenEphm[1] = -1; |
| 109998 | + pNew->nSelectRow = 0; |
| 109760 | 109999 | if( pSrc==0 ) pSrc = sqlite3DbMallocZero(db, sizeof(*pSrc)); |
| 109761 | 110000 | pNew->pSrc = pSrc; |
| 109762 | 110001 | pNew->pWhere = pWhere; |
| 109763 | 110002 | pNew->pGroupBy = pGroupBy; |
| 109764 | 110003 | pNew->pHaving = pHaving; |
| 109765 | 110004 | pNew->pOrderBy = pOrderBy; |
| 109766 | | - pNew->selFlags = selFlags; |
| 109767 | | - pNew->op = TK_SELECT; |
| 110005 | + pNew->pPrior = 0; |
| 110006 | + pNew->pNext = 0; |
| 109768 | 110007 | pNew->pLimit = pLimit; |
| 109769 | 110008 | pNew->pOffset = pOffset; |
| 110009 | + pNew->pWith = 0; |
| 109770 | 110010 | assert( pOffset==0 || pLimit!=0 || pParse->nErr>0 || db->mallocFailed!=0 ); |
| 109771 | | - pNew->addrOpenEphm[0] = -1; |
| 109772 | | - pNew->addrOpenEphm[1] = -1; |
| 109773 | 110011 | if( db->mallocFailed ) { |
| 109774 | 110012 | clearSelect(db, pNew, pNew!=&standin); |
| 109775 | 110013 | pNew = 0; |
| 109776 | 110014 | }else{ |
| 109777 | 110015 | assert( pNew->pSrc!=0 || pParse->nErr>0 ); |
| | @@ -110142,10 +110380,11 @@ |
| 110142 | 110380 | int nBase = nExpr + bSeq + nData; /* Fields in sorter record */ |
| 110143 | 110381 | int regBase; /* Regs for sorter record */ |
| 110144 | 110382 | int regRecord = ++pParse->nMem; /* Assembled sorter record */ |
| 110145 | 110383 | int nOBSat = pSort->nOBSat; /* ORDER BY terms to skip */ |
| 110146 | 110384 | int op; /* Opcode to add sorter record to sorter */ |
| 110385 | + int iLimit; /* LIMIT counter */ |
| 110147 | 110386 | |
| 110148 | 110387 | assert( bSeq==0 || bSeq==1 ); |
| 110149 | 110388 | assert( nData==1 || regData==regOrigData ); |
| 110150 | 110389 | if( nPrefixReg ){ |
| 110151 | 110390 | assert( nPrefixReg==nExpr+bSeq ); |
| | @@ -110152,19 +110391,21 @@ |
| 110152 | 110391 | regBase = regData - nExpr - bSeq; |
| 110153 | 110392 | }else{ |
| 110154 | 110393 | regBase = pParse->nMem + 1; |
| 110155 | 110394 | pParse->nMem += nBase; |
| 110156 | 110395 | } |
| 110396 | + assert( pSelect->iOffset==0 || pSelect->iLimit!=0 ); |
| 110397 | + iLimit = pSelect->iOffset ? pSelect->iOffset+1 : pSelect->iLimit; |
| 110398 | + pSort->labelDone = sqlite3VdbeMakeLabel(v); |
| 110157 | 110399 | sqlite3ExprCodeExprList(pParse, pSort->pOrderBy, regBase, regOrigData, |
| 110158 | 110400 | SQLITE_ECEL_DUP|SQLITE_ECEL_REF); |
| 110159 | 110401 | if( bSeq ){ |
| 110160 | 110402 | sqlite3VdbeAddOp2(v, OP_Sequence, pSort->iECursor, regBase+nExpr); |
| 110161 | 110403 | } |
| 110162 | 110404 | if( nPrefixReg==0 ){ |
| 110163 | 110405 | sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+bSeq, nData); |
| 110164 | 110406 | } |
| 110165 | | - |
| 110166 | 110407 | sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase+nOBSat, nBase-nOBSat, regRecord); |
| 110167 | 110408 | if( nOBSat>0 ){ |
| 110168 | 110409 | int regPrevKey; /* The first nOBSat columns of the previous row */ |
| 110169 | 110410 | int addrFirst; /* Address of the OP_IfNot opcode */ |
| 110170 | 110411 | int addrJmp; /* Address of the OP_Jump opcode */ |
| | @@ -110195,10 +110436,14 @@ |
| 110195 | 110436 | sqlite3VdbeAddOp3(v, OP_Jump, addrJmp+1, 0, addrJmp+1); VdbeCoverage(v); |
| 110196 | 110437 | pSort->labelBkOut = sqlite3VdbeMakeLabel(v); |
| 110197 | 110438 | pSort->regReturn = ++pParse->nMem; |
| 110198 | 110439 | sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut); |
| 110199 | 110440 | sqlite3VdbeAddOp1(v, OP_ResetSorter, pSort->iECursor); |
| 110441 | + if( iLimit ){ |
| 110442 | + sqlite3VdbeAddOp2(v, OP_IfNot, iLimit, pSort->labelDone); |
| 110443 | + VdbeCoverage(v); |
| 110444 | + } |
| 110200 | 110445 | sqlite3VdbeJumpHere(v, addrFirst); |
| 110201 | 110446 | sqlite3ExprCodeMove(pParse, regBase, regPrevKey, pSort->nOBSat); |
| 110202 | 110447 | sqlite3VdbeJumpHere(v, addrJmp); |
| 110203 | 110448 | } |
| 110204 | 110449 | if( pSort->sortFlags & SORTFLAG_UseSorter ){ |
| | @@ -110205,18 +110450,12 @@ |
| 110205 | 110450 | op = OP_SorterInsert; |
| 110206 | 110451 | }else{ |
| 110207 | 110452 | op = OP_IdxInsert; |
| 110208 | 110453 | } |
| 110209 | 110454 | sqlite3VdbeAddOp2(v, op, pSort->iECursor, regRecord); |
| 110210 | | - if( pSelect->iLimit ){ |
| 110455 | + if( iLimit ){ |
| 110211 | 110456 | int addr; |
| 110212 | | - int iLimit; |
| 110213 | | - if( pSelect->iOffset ){ |
| 110214 | | - iLimit = pSelect->iOffset+1; |
| 110215 | | - }else{ |
| 110216 | | - iLimit = pSelect->iLimit; |
| 110217 | | - } |
| 110218 | 110457 | addr = sqlite3VdbeAddOp3(v, OP_IfNotZero, iLimit, 0, 1); VdbeCoverage(v); |
| 110219 | 110458 | sqlite3VdbeAddOp1(v, OP_Last, pSort->iECursor); |
| 110220 | 110459 | sqlite3VdbeAddOp1(v, OP_Delete, pSort->iECursor); |
| 110221 | 110460 | sqlite3VdbeJumpHere(v, addr); |
| 110222 | 110461 | } |
| | @@ -110629,19 +110868,20 @@ |
| 110629 | 110868 | /* |
| 110630 | 110869 | ** Allocate a KeyInfo object sufficient for an index of N key columns and |
| 110631 | 110870 | ** X extra columns. |
| 110632 | 110871 | */ |
| 110633 | 110872 | SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){ |
| 110634 | | - KeyInfo *p = sqlite3DbMallocZero(0, |
| 110635 | | - sizeof(KeyInfo) + (N+X)*(sizeof(CollSeq*)+1)); |
| 110873 | + int nExtra = (N+X)*(sizeof(CollSeq*)+1); |
| 110874 | + KeyInfo *p = sqlite3Malloc(sizeof(KeyInfo) + nExtra); |
| 110636 | 110875 | if( p ){ |
| 110637 | 110876 | p->aSortOrder = (u8*)&p->aColl[N+X]; |
| 110638 | 110877 | p->nField = (u16)N; |
| 110639 | 110878 | p->nXField = (u16)X; |
| 110640 | 110879 | p->enc = ENC(db); |
| 110641 | 110880 | p->db = db; |
| 110642 | 110881 | p->nRef = 1; |
| 110882 | + memset(&p[1], 0, nExtra); |
| 110643 | 110883 | }else{ |
| 110644 | 110884 | db->mallocFailed = 1; |
| 110645 | 110885 | } |
| 110646 | 110886 | return p; |
| 110647 | 110887 | } |
| | @@ -110816,11 +111056,11 @@ |
| 110816 | 111056 | SortCtx *pSort, /* Information on the ORDER BY clause */ |
| 110817 | 111057 | int nColumn, /* Number of columns of data */ |
| 110818 | 111058 | SelectDest *pDest /* Write the sorted results here */ |
| 110819 | 111059 | ){ |
| 110820 | 111060 | Vdbe *v = pParse->pVdbe; /* The prepared statement */ |
| 110821 | | - int addrBreak = sqlite3VdbeMakeLabel(v); /* Jump here to exit loop */ |
| 111061 | + int addrBreak = pSort->labelDone; /* Jump here to exit loop */ |
| 110822 | 111062 | int addrContinue = sqlite3VdbeMakeLabel(v); /* Jump here for next cycle */ |
| 110823 | 111063 | int addr; |
| 110824 | 111064 | int addrOnce = 0; |
| 110825 | 111065 | int iTab; |
| 110826 | 111066 | ExprList *pOrderBy = pSort->pOrderBy; |
| | @@ -110835,10 +111075,11 @@ |
| 110835 | 111075 | int bSeq; /* True if sorter record includes seq. no. */ |
| 110836 | 111076 | #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS |
| 110837 | 111077 | struct ExprList_item *aOutEx = p->pEList->a; |
| 110838 | 111078 | #endif |
| 110839 | 111079 | |
| 111080 | + assert( addrBreak<0 ); |
| 110840 | 111081 | if( pSort->labelBkOut ){ |
| 110841 | 111082 | sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut); |
| 110842 | 111083 | sqlite3VdbeGoto(v, addrBreak); |
| 110843 | 111084 | sqlite3VdbeResolveLabel(v, pSort->labelBkOut); |
| 110844 | 111085 | } |
| | @@ -116425,12 +116666,12 @@ |
| 116425 | 116666 | /* Code the OP_Program opcode in the parent VDBE. P4 of the OP_Program |
| 116426 | 116667 | ** is a pointer to the sub-vdbe containing the trigger program. */ |
| 116427 | 116668 | if( pPrg ){ |
| 116428 | 116669 | int bRecursive = (p->zName && 0==(pParse->db->flags&SQLITE_RecTriggers)); |
| 116429 | 116670 | |
| 116430 | | - sqlite3VdbeAddOp3(v, OP_Program, reg, ignoreJump, ++pParse->nMem); |
| 116431 | | - sqlite3VdbeChangeP4(v, -1, (const char *)pPrg->pProgram, P4_SUBPROGRAM); |
| 116671 | + sqlite3VdbeAddOp4(v, OP_Program, reg, ignoreJump, ++pParse->nMem, |
| 116672 | + (const char *)pPrg->pProgram, P4_SUBPROGRAM); |
| 116432 | 116673 | VdbeComment( |
| 116433 | 116674 | (v, "Call: %s.%s", (p->zName?p->zName:"fkey"), onErrorText(orconf))); |
| 116434 | 116675 | |
| 116435 | 116676 | /* Set the P5 operand of the OP_Program instruction to non-zero if |
| 116436 | 116677 | ** recursive invocation of this trigger program is disallowed. Recursive |
| | @@ -118780,11 +119021,11 @@ |
| 118780 | 119021 | Expr *pExpr /* First argument to the function */ |
| 118781 | 119022 | ){ |
| 118782 | 119023 | Table *pTab; |
| 118783 | 119024 | sqlite3_vtab *pVtab; |
| 118784 | 119025 | sqlite3_module *pMod; |
| 118785 | | - void (*xFunc)(sqlite3_context*,int,sqlite3_value**) = 0; |
| 119026 | + void (*xSFunc)(sqlite3_context*,int,sqlite3_value**) = 0; |
| 118786 | 119027 | void *pArg = 0; |
| 118787 | 119028 | FuncDef *pNew; |
| 118788 | 119029 | int rc = 0; |
| 118789 | 119030 | char *zLowerName; |
| 118790 | 119031 | unsigned char *z; |
| | @@ -118808,11 +119049,11 @@ |
| 118808 | 119049 | zLowerName = sqlite3DbStrDup(db, pDef->zName); |
| 118809 | 119050 | if( zLowerName ){ |
| 118810 | 119051 | for(z=(unsigned char*)zLowerName; *z; z++){ |
| 118811 | 119052 | *z = sqlite3UpperToLower[*z]; |
| 118812 | 119053 | } |
| 118813 | | - rc = pMod->xFindFunction(pVtab, nArg, zLowerName, &xFunc, &pArg); |
| 119054 | + rc = pMod->xFindFunction(pVtab, nArg, zLowerName, &xSFunc, &pArg); |
| 118814 | 119055 | sqlite3DbFree(db, zLowerName); |
| 118815 | 119056 | } |
| 118816 | 119057 | if( rc==0 ){ |
| 118817 | 119058 | return pDef; |
| 118818 | 119059 | } |
| | @@ -118825,11 +119066,11 @@ |
| 118825 | 119066 | return pDef; |
| 118826 | 119067 | } |
| 118827 | 119068 | *pNew = *pDef; |
| 118828 | 119069 | pNew->zName = (char *)&pNew[1]; |
| 118829 | 119070 | memcpy(pNew->zName, pDef->zName, sqlite3Strlen30(pDef->zName)+1); |
| 118830 | | - pNew->xFunc = xFunc; |
| 119071 | + pNew->xSFunc = xSFunc; |
| 118831 | 119072 | pNew->pUserData = pArg; |
| 118832 | 119073 | pNew->funcFlags |= SQLITE_FUNC_EPHEM; |
| 118833 | 119074 | return pNew; |
| 118834 | 119075 | } |
| 118835 | 119076 | |
| | @@ -119845,12 +120086,11 @@ |
| 119845 | 120086 | n--; |
| 119846 | 120087 | } |
| 119847 | 120088 | |
| 119848 | 120089 | /* Code the OP_Affinity opcode if there is anything left to do. */ |
| 119849 | 120090 | if( n>0 ){ |
| 119850 | | - sqlite3VdbeAddOp2(v, OP_Affinity, base, n); |
| 119851 | | - sqlite3VdbeChangeP4(v, -1, zAff, n); |
| 120091 | + sqlite3VdbeAddOp4(v, OP_Affinity, base, n, 0, zAff, n); |
| 119852 | 120092 | sqlite3ExprCacheAffinityChange(pParse, base, n); |
| 119853 | 120093 | } |
| 119854 | 120094 | } |
| 119855 | 120095 | |
| 119856 | 120096 | |
| | @@ -121398,10 +121638,11 @@ |
| 121398 | 121638 | int cnt; /* Number of non-wildcard prefix characters */ |
| 121399 | 121639 | char wc[3]; /* Wildcard characters */ |
| 121400 | 121640 | sqlite3 *db = pParse->db; /* Database connection */ |
| 121401 | 121641 | sqlite3_value *pVal = 0; |
| 121402 | 121642 | int op; /* Opcode of pRight */ |
| 121643 | + int rc; /* Result code to return */ |
| 121403 | 121644 | |
| 121404 | 121645 | if( !sqlite3IsLikeFunction(db, pExpr, pnoCase, wc) ){ |
| 121405 | 121646 | return 0; |
| 121406 | 121647 | } |
| 121407 | 121648 | #ifdef SQLITE_EBCDIC |
| | @@ -121463,12 +121704,13 @@ |
| 121463 | 121704 | }else{ |
| 121464 | 121705 | z = 0; |
| 121465 | 121706 | } |
| 121466 | 121707 | } |
| 121467 | 121708 | |
| 121709 | + rc = (z!=0); |
| 121468 | 121710 | sqlite3ValueFree(pVal); |
| 121469 | | - return (z!=0); |
| 121711 | + return rc; |
| 121470 | 121712 | } |
| 121471 | 121713 | #endif /* SQLITE_OMIT_LIKE_OPTIMIZATION */ |
| 121472 | 121714 | |
| 121473 | 121715 | |
| 121474 | 121716 | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| | @@ -126875,12 +127117,11 @@ |
| 126875 | 127117 | testcase( pWInfo->eOnePass==ONEPASS_OFF && pTab->nCol==BMS ); |
| 126876 | 127118 | if( pWInfo->eOnePass==ONEPASS_OFF && pTab->nCol<BMS && HasRowid(pTab) ){ |
| 126877 | 127119 | Bitmask b = pTabItem->colUsed; |
| 126878 | 127120 | int n = 0; |
| 126879 | 127121 | for(; b; b=b>>1, n++){} |
| 126880 | | - sqlite3VdbeChangeP4(v, sqlite3VdbeCurrentAddr(v)-1, |
| 126881 | | - SQLITE_INT_TO_PTR(n), P4_INT32); |
| 127122 | + sqlite3VdbeChangeP4(v, -1, SQLITE_INT_TO_PTR(n), P4_INT32); |
| 126882 | 127123 | assert( n<=pTab->nCol ); |
| 126883 | 127124 | } |
| 126884 | 127125 | #ifdef SQLITE_ENABLE_CURSOR_HINTS |
| 126885 | 127126 | if( pLoop->u.btree.pIndex!=0 ){ |
| 126886 | 127127 | sqlite3VdbeChangeP5(v, OPFLAG_SEEKEQ|bFordelete); |
| | @@ -129343,18 +129584,15 @@ |
| 129343 | 129584 | ** { ... } // User supplied code |
| 129344 | 129585 | ** #line <lineno> <thisfile> |
| 129345 | 129586 | ** break; |
| 129346 | 129587 | */ |
| 129347 | 129588 | /********** Begin reduce actions **********************************************/ |
| 129348 | | - case 5: /* explain ::= */ |
| 129349 | | -{ sqlite3BeginParse(pParse, 0); } |
| 129350 | | - break; |
| 129351 | 129589 | case 6: /* explain ::= EXPLAIN */ |
| 129352 | | -{ sqlite3BeginParse(pParse, 1); } |
| 129590 | +{ pParse->explain = 1; } |
| 129353 | 129591 | break; |
| 129354 | 129592 | case 7: /* explain ::= EXPLAIN QUERY PLAN */ |
| 129355 | | -{ sqlite3BeginParse(pParse, 2); } |
| 129593 | +{ pParse->explain = 2; } |
| 129356 | 129594 | break; |
| 129357 | 129595 | case 8: /* cmdx ::= cmd */ |
| 129358 | 129596 | { sqlite3FinishCoding(pParse); } |
| 129359 | 129597 | break; |
| 129360 | 129598 | case 9: /* cmd ::= BEGIN transtype trans_opt */ |
| | @@ -130525,10 +130763,11 @@ |
| 130525 | 130763 | /* (0) input ::= cmdlist */ yytestcase(yyruleno==0); |
| 130526 | 130764 | /* (1) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==1); |
| 130527 | 130765 | /* (2) cmdlist ::= ecmd */ yytestcase(yyruleno==2); |
| 130528 | 130766 | /* (3) ecmd ::= SEMI */ yytestcase(yyruleno==3); |
| 130529 | 130767 | /* (4) ecmd ::= explain cmdx SEMI */ yytestcase(yyruleno==4); |
| 130768 | + /* (5) explain ::= */ yytestcase(yyruleno==5); |
| 130530 | 130769 | /* (10) trans_opt ::= */ yytestcase(yyruleno==10); |
| 130531 | 130770 | /* (11) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==11); |
| 130532 | 130771 | /* (12) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==12); |
| 130533 | 130772 | /* (20) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==20); |
| 130534 | 130773 | /* (21) savepoint_opt ::= */ yytestcase(yyruleno==21); |
| | @@ -133601,11 +133840,11 @@ |
| 133601 | 133840 | sqlite3 *db, |
| 133602 | 133841 | const char *zFunctionName, |
| 133603 | 133842 | int nArg, |
| 133604 | 133843 | int enc, |
| 133605 | 133844 | void *pUserData, |
| 133606 | | - void (*xFunc)(sqlite3_context*,int,sqlite3_value **), |
| 133845 | + void (*xSFunc)(sqlite3_context*,int,sqlite3_value **), |
| 133607 | 133846 | void (*xStep)(sqlite3_context*,int,sqlite3_value **), |
| 133608 | 133847 | void (*xFinal)(sqlite3_context*), |
| 133609 | 133848 | FuncDestructor *pDestructor |
| 133610 | 133849 | ){ |
| 133611 | 133850 | FuncDef *p; |
| | @@ -133612,13 +133851,13 @@ |
| 133612 | 133851 | int nName; |
| 133613 | 133852 | int extraFlags; |
| 133614 | 133853 | |
| 133615 | 133854 | assert( sqlite3_mutex_held(db->mutex) ); |
| 133616 | 133855 | if( zFunctionName==0 || |
| 133617 | | - (xFunc && (xFinal || xStep)) || |
| 133618 | | - (!xFunc && (xFinal && !xStep)) || |
| 133619 | | - (!xFunc && (!xFinal && xStep)) || |
| 133856 | + (xSFunc && (xFinal || xStep)) || |
| 133857 | + (!xSFunc && (xFinal && !xStep)) || |
| 133858 | + (!xSFunc && (!xFinal && xStep)) || |
| 133620 | 133859 | (nArg<-1 || nArg>SQLITE_MAX_FUNCTION_ARG) || |
| 133621 | 133860 | (255<(nName = sqlite3Strlen30( zFunctionName))) ){ |
| 133622 | 133861 | return SQLITE_MISUSE_BKPT; |
| 133623 | 133862 | } |
| 133624 | 133863 | |
| | @@ -133637,14 +133876,14 @@ |
| 133637 | 133876 | if( enc==SQLITE_UTF16 ){ |
| 133638 | 133877 | enc = SQLITE_UTF16NATIVE; |
| 133639 | 133878 | }else if( enc==SQLITE_ANY ){ |
| 133640 | 133879 | int rc; |
| 133641 | 133880 | rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF8|extraFlags, |
| 133642 | | - pUserData, xFunc, xStep, xFinal, pDestructor); |
| 133881 | + pUserData, xSFunc, xStep, xFinal, pDestructor); |
| 133643 | 133882 | if( rc==SQLITE_OK ){ |
| 133644 | 133883 | rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF16LE|extraFlags, |
| 133645 | | - pUserData, xFunc, xStep, xFinal, pDestructor); |
| 133884 | + pUserData, xSFunc, xStep, xFinal, pDestructor); |
| 133646 | 133885 | } |
| 133647 | 133886 | if( rc!=SQLITE_OK ){ |
| 133648 | 133887 | return rc; |
| 133649 | 133888 | } |
| 133650 | 133889 | enc = SQLITE_UTF16BE; |
| | @@ -133684,12 +133923,11 @@ |
| 133684 | 133923 | pDestructor->nRef++; |
| 133685 | 133924 | } |
| 133686 | 133925 | p->pDestructor = pDestructor; |
| 133687 | 133926 | p->funcFlags = (p->funcFlags & SQLITE_FUNC_ENCMASK) | extraFlags; |
| 133688 | 133927 | testcase( p->funcFlags & SQLITE_DETERMINISTIC ); |
| 133689 | | - p->xFunc = xFunc; |
| 133690 | | - p->xStep = xStep; |
| 133928 | + p->xSFunc = xSFunc ? xSFunc : xStep; |
| 133691 | 133929 | p->xFinalize = xFinal; |
| 133692 | 133930 | p->pUserData = pUserData; |
| 133693 | 133931 | p->nArg = (u16)nArg; |
| 133694 | 133932 | return SQLITE_OK; |
| 133695 | 133933 | } |
| | @@ -133701,25 +133939,25 @@ |
| 133701 | 133939 | sqlite3 *db, |
| 133702 | 133940 | const char *zFunc, |
| 133703 | 133941 | int nArg, |
| 133704 | 133942 | int enc, |
| 133705 | 133943 | void *p, |
| 133706 | | - void (*xFunc)(sqlite3_context*,int,sqlite3_value **), |
| 133944 | + void (*xSFunc)(sqlite3_context*,int,sqlite3_value **), |
| 133707 | 133945 | void (*xStep)(sqlite3_context*,int,sqlite3_value **), |
| 133708 | 133946 | void (*xFinal)(sqlite3_context*) |
| 133709 | 133947 | ){ |
| 133710 | | - return sqlite3_create_function_v2(db, zFunc, nArg, enc, p, xFunc, xStep, |
| 133948 | + return sqlite3_create_function_v2(db, zFunc, nArg, enc, p, xSFunc, xStep, |
| 133711 | 133949 | xFinal, 0); |
| 133712 | 133950 | } |
| 133713 | 133951 | |
| 133714 | 133952 | SQLITE_API int SQLITE_STDCALL sqlite3_create_function_v2( |
| 133715 | 133953 | sqlite3 *db, |
| 133716 | 133954 | const char *zFunc, |
| 133717 | 133955 | int nArg, |
| 133718 | 133956 | int enc, |
| 133719 | 133957 | void *p, |
| 133720 | | - void (*xFunc)(sqlite3_context*,int,sqlite3_value **), |
| 133958 | + void (*xSFunc)(sqlite3_context*,int,sqlite3_value **), |
| 133721 | 133959 | void (*xStep)(sqlite3_context*,int,sqlite3_value **), |
| 133722 | 133960 | void (*xFinal)(sqlite3_context*), |
| 133723 | 133961 | void (*xDestroy)(void *) |
| 133724 | 133962 | ){ |
| 133725 | 133963 | int rc = SQLITE_ERROR; |
| | @@ -133738,11 +133976,11 @@ |
| 133738 | 133976 | goto out; |
| 133739 | 133977 | } |
| 133740 | 133978 | pArg->xDestroy = xDestroy; |
| 133741 | 133979 | pArg->pUserData = p; |
| 133742 | 133980 | } |
| 133743 | | - rc = sqlite3CreateFunc(db, zFunc, nArg, enc, p, xFunc, xStep, xFinal, pArg); |
| 133981 | + rc = sqlite3CreateFunc(db, zFunc, nArg, enc, p, xSFunc, xStep, xFinal, pArg); |
| 133744 | 133982 | if( pArg && pArg->nRef==0 ){ |
| 133745 | 133983 | assert( rc!=SQLITE_OK ); |
| 133746 | 133984 | xDestroy(p); |
| 133747 | 133985 | sqlite3DbFree(db, pArg); |
| 133748 | 133986 | } |
| | @@ -133758,11 +133996,11 @@ |
| 133758 | 133996 | sqlite3 *db, |
| 133759 | 133997 | const void *zFunctionName, |
| 133760 | 133998 | int nArg, |
| 133761 | 133999 | int eTextRep, |
| 133762 | 134000 | void *p, |
| 133763 | | - void (*xFunc)(sqlite3_context*,int,sqlite3_value**), |
| 134001 | + void (*xSFunc)(sqlite3_context*,int,sqlite3_value**), |
| 133764 | 134002 | void (*xStep)(sqlite3_context*,int,sqlite3_value**), |
| 133765 | 134003 | void (*xFinal)(sqlite3_context*) |
| 133766 | 134004 | ){ |
| 133767 | 134005 | int rc; |
| 133768 | 134006 | char *zFunc8; |
| | @@ -133771,11 +134009,11 @@ |
| 133771 | 134009 | if( !sqlite3SafetyCheckOk(db) || zFunctionName==0 ) return SQLITE_MISUSE_BKPT; |
| 133772 | 134010 | #endif |
| 133773 | 134011 | sqlite3_mutex_enter(db->mutex); |
| 133774 | 134012 | assert( !db->mallocFailed ); |
| 133775 | 134013 | zFunc8 = sqlite3Utf16to8(db, zFunctionName, -1, SQLITE_UTF16NATIVE); |
| 133776 | | - rc = sqlite3CreateFunc(db, zFunc8, nArg, eTextRep, p, xFunc, xStep, xFinal,0); |
| 134014 | + rc = sqlite3CreateFunc(db, zFunc8, nArg, eTextRep, p, xSFunc,xStep,xFinal,0); |
| 133777 | 134015 | sqlite3DbFree(db, zFunc8); |
| 133778 | 134016 | rc = sqlite3ApiExit(db, rc); |
| 133779 | 134017 | sqlite3_mutex_leave(db->mutex); |
| 133780 | 134018 | return rc; |
| 133781 | 134019 | } |
| | @@ -134996,11 +135234,10 @@ |
| 134996 | 135234 | sqlite3GlobalConfig.nLookaside); |
| 134997 | 135235 | |
| 134998 | 135236 | sqlite3_wal_autocheckpoint(db, SQLITE_DEFAULT_WAL_AUTOCHECKPOINT); |
| 134999 | 135237 | |
| 135000 | 135238 | opendb_out: |
| 135001 | | - sqlite3_free(zOpen); |
| 135002 | 135239 | if( db ){ |
| 135003 | 135240 | assert( db->mutex!=0 || isThreadsafe==0 |
| 135004 | 135241 | || sqlite3GlobalConfig.bFullMutex==0 ); |
| 135005 | 135242 | sqlite3_mutex_leave(db->mutex); |
| 135006 | 135243 | } |
| | @@ -135033,10 +135270,11 @@ |
| 135033 | 135270 | } |
| 135034 | 135271 | sqlite3_key_v2(db, 0, zKey, i/2); |
| 135035 | 135272 | } |
| 135036 | 135273 | } |
| 135037 | 135274 | #endif |
| 135275 | + sqlite3_free(zOpen); |
| 135038 | 135276 | return rc & 0xff; |
| 135039 | 135277 | } |
| 135040 | 135278 | |
| 135041 | 135279 | /* |
| 135042 | 135280 | ** Open a new database handle. |
| | @@ -135450,10 +135688,13 @@ |
| 135450 | 135688 | *(sqlite3_file**)pArg = fd; |
| 135451 | 135689 | rc = SQLITE_OK; |
| 135452 | 135690 | }else if( op==SQLITE_FCNTL_VFS_POINTER ){ |
| 135453 | 135691 | *(sqlite3_vfs**)pArg = sqlite3PagerVfs(pPager); |
| 135454 | 135692 | rc = SQLITE_OK; |
| 135693 | + }else if( op==SQLITE_FCNTL_JOURNAL_POINTER ){ |
| 135694 | + *(sqlite3_file**)pArg = sqlite3PagerJrnlFile(pPager); |
| 135695 | + rc = SQLITE_OK; |
| 135455 | 135696 | }else if( fd->pMethods ){ |
| 135456 | 135697 | rc = sqlite3OsFileControl(fd, op, pArg); |
| 135457 | 135698 | }else{ |
| 135458 | 135699 | rc = SQLITE_NOTFOUND; |
| 135459 | 135700 | } |
| | @@ -161083,11 +161324,11 @@ |
| 161083 | 161324 | */ |
| 161084 | 161325 | static void *rbuMalloc(sqlite3rbu *p, int nByte){ |
| 161085 | 161326 | void *pRet = 0; |
| 161086 | 161327 | if( p->rc==SQLITE_OK ){ |
| 161087 | 161328 | assert( nByte>0 ); |
| 161088 | | - pRet = sqlite3_malloc(nByte); |
| 161329 | + pRet = sqlite3_malloc64(nByte); |
| 161089 | 161330 | if( pRet==0 ){ |
| 161090 | 161331 | p->rc = SQLITE_NOMEM; |
| 161091 | 161332 | }else{ |
| 161092 | 161333 | memset(pRet, 0, nByte); |
| 161093 | 161334 | } |
| | @@ -161129,12 +161370,12 @@ |
| 161129 | 161370 | static char *rbuStrndup(const char *zStr, int *pRc){ |
| 161130 | 161371 | char *zRet = 0; |
| 161131 | 161372 | |
| 161132 | 161373 | assert( *pRc==SQLITE_OK ); |
| 161133 | 161374 | if( zStr ){ |
| 161134 | | - int nCopy = strlen(zStr) + 1; |
| 161135 | | - zRet = (char*)sqlite3_malloc(nCopy); |
| 161375 | + size_t nCopy = strlen(zStr) + 1; |
| 161376 | + zRet = (char*)sqlite3_malloc64(nCopy); |
| 161136 | 161377 | if( zRet ){ |
| 161137 | 161378 | memcpy(zRet, zStr, nCopy); |
| 161138 | 161379 | }else{ |
| 161139 | 161380 | *pRc = SQLITE_NOMEM; |
| 161140 | 161381 | } |
| | @@ -162478,11 +162719,11 @@ |
| 162478 | 162719 | |
| 162479 | 162720 | pRbu->pgsz = iAmt; |
| 162480 | 162721 | if( pRbu->nFrame==pRbu->nFrameAlloc ){ |
| 162481 | 162722 | int nNew = (pRbu->nFrameAlloc ? pRbu->nFrameAlloc : 64) * 2; |
| 162482 | 162723 | RbuFrame *aNew; |
| 162483 | | - aNew = (RbuFrame*)sqlite3_realloc(pRbu->aFrame, nNew * sizeof(RbuFrame)); |
| 162724 | + aNew = (RbuFrame*)sqlite3_realloc64(pRbu->aFrame, nNew * sizeof(RbuFrame)); |
| 162484 | 162725 | if( aNew==0 ) return SQLITE_NOMEM; |
| 162485 | 162726 | pRbu->aFrame = aNew; |
| 162486 | 162727 | pRbu->nFrameAlloc = nNew; |
| 162487 | 162728 | } |
| 162488 | 162729 | |
| | @@ -162543,11 +162784,11 @@ |
| 162543 | 162784 | |
| 162544 | 162785 | nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0); |
| 162545 | 162786 | if( nChar==0 ){ |
| 162546 | 162787 | return 0; |
| 162547 | 162788 | } |
| 162548 | | - zWideFilename = sqlite3_malloc( nChar*sizeof(zWideFilename[0]) ); |
| 162789 | + zWideFilename = sqlite3_malloc64( nChar*sizeof(zWideFilename[0]) ); |
| 162549 | 162790 | if( zWideFilename==0 ){ |
| 162550 | 162791 | return 0; |
| 162551 | 162792 | } |
| 162552 | 162793 | memset(zWideFilename, 0, nChar*sizeof(zWideFilename[0])); |
| 162553 | 162794 | nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename, |
| | @@ -163177,15 +163418,16 @@ |
| 163177 | 163418 | const char *zTarget, |
| 163178 | 163419 | const char *zRbu, |
| 163179 | 163420 | const char *zState |
| 163180 | 163421 | ){ |
| 163181 | 163422 | sqlite3rbu *p; |
| 163182 | | - int nTarget = strlen(zTarget); |
| 163183 | | - int nRbu = strlen(zRbu); |
| 163184 | | - int nState = zState ? strlen(zState) : 0; |
| 163423 | + size_t nTarget = strlen(zTarget); |
| 163424 | + size_t nRbu = strlen(zRbu); |
| 163425 | + size_t nState = zState ? strlen(zState) : 0; |
| 163426 | + size_t nByte = sizeof(sqlite3rbu) + nTarget+1 + nRbu+1+ nState+1; |
| 163185 | 163427 | |
| 163186 | | - p = (sqlite3rbu*)sqlite3_malloc(sizeof(sqlite3rbu)+nTarget+1+nRbu+1+nState+1); |
| 163428 | + p = (sqlite3rbu*)sqlite3_malloc64(nByte); |
| 163187 | 163429 | if( p ){ |
| 163188 | 163430 | RbuState *pState = 0; |
| 163189 | 163431 | |
| 163190 | 163432 | /* Create the custom VFS. */ |
| 163191 | 163433 | memset(p, 0, sizeof(sqlite3rbu)); |
| | @@ -163318,11 +163560,11 @@ |
| 163318 | 163560 | ** the pattern "rbu_imp_[0-9]*". |
| 163319 | 163561 | */ |
| 163320 | 163562 | static void rbuEditErrmsg(sqlite3rbu *p){ |
| 163321 | 163563 | if( p->rc==SQLITE_CONSTRAINT && p->zErrmsg ){ |
| 163322 | 163564 | int i; |
| 163323 | | - int nErrmsg = strlen(p->zErrmsg); |
| 163565 | + size_t nErrmsg = strlen(p->zErrmsg); |
| 163324 | 163566 | for(i=0; i<(nErrmsg-8); i++){ |
| 163325 | 163567 | if( memcmp(&p->zErrmsg[i], "rbu_imp_", 8)==0 ){ |
| 163326 | 163568 | int nDel = 8; |
| 163327 | 163569 | while( p->zErrmsg[i+nDel]>='0' && p->zErrmsg[i+nDel]<='9' ) nDel++; |
| 163328 | 163570 | memmove(&p->zErrmsg[i], &p->zErrmsg[i+nDel], nErrmsg + 1 - i - nDel); |
| | @@ -163782,11 +164024,11 @@ |
| 163782 | 164024 | ** instead of a file on disk. */ |
| 163783 | 164025 | assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) ); |
| 163784 | 164026 | if( eStage==RBU_STAGE_OAL || eStage==RBU_STAGE_MOVE ){ |
| 163785 | 164027 | if( iRegion<=p->nShm ){ |
| 163786 | 164028 | int nByte = (iRegion+1) * sizeof(char*); |
| 163787 | | - char **apNew = (char**)sqlite3_realloc(p->apShm, nByte); |
| 164029 | + char **apNew = (char**)sqlite3_realloc64(p->apShm, nByte); |
| 163788 | 164030 | if( apNew==0 ){ |
| 163789 | 164031 | rc = SQLITE_NOMEM; |
| 163790 | 164032 | }else{ |
| 163791 | 164033 | memset(&apNew[p->nShm], 0, sizeof(char*) * (1 + iRegion - p->nShm)); |
| 163792 | 164034 | p->apShm = apNew; |
| | @@ -163793,11 +164035,11 @@ |
| 163793 | 164035 | p->nShm = iRegion+1; |
| 163794 | 164036 | } |
| 163795 | 164037 | } |
| 163796 | 164038 | |
| 163797 | 164039 | if( rc==SQLITE_OK && p->apShm[iRegion]==0 ){ |
| 163798 | | - char *pNew = (char*)sqlite3_malloc(szRegion); |
| 164040 | + char *pNew = (char*)sqlite3_malloc64(szRegion); |
| 163799 | 164041 | if( pNew==0 ){ |
| 163800 | 164042 | rc = SQLITE_NOMEM; |
| 163801 | 164043 | }else{ |
| 163802 | 164044 | memset(pNew, 0, szRegion); |
| 163803 | 164045 | p->apShm[iRegion] = pNew; |
| | @@ -163903,11 +164145,11 @@ |
| 163903 | 164145 | /* A main database has just been opened. The following block sets |
| 163904 | 164146 | ** (pFd->zWal) to point to a buffer owned by SQLite that contains |
| 163905 | 164147 | ** the name of the *-wal file this db connection will use. SQLite |
| 163906 | 164148 | ** happens to pass a pointer to this buffer when using xAccess() |
| 163907 | 164149 | ** or xOpen() to operate on the *-wal file. */ |
| 163908 | | - int n = strlen(zName); |
| 164150 | + int n = (int)strlen(zName); |
| 163909 | 164151 | const char *z = &zName[n]; |
| 163910 | 164152 | if( flags & SQLITE_OPEN_URI ){ |
| 163911 | 164153 | int odd = 0; |
| 163912 | 164154 | while( 1 ){ |
| 163913 | 164155 | if( z[0]==0 ){ |
| | @@ -163929,12 +164171,12 @@ |
| 163929 | 164171 | if( pDb->pRbu && pDb->pRbu->eStage==RBU_STAGE_OAL ){ |
| 163930 | 164172 | /* This call is to open a *-wal file. Intead, open the *-oal. This |
| 163931 | 164173 | ** code ensures that the string passed to xOpen() is terminated by a |
| 163932 | 164174 | ** pair of '\0' bytes in case the VFS attempts to extract a URI |
| 163933 | 164175 | ** parameter from it. */ |
| 163934 | | - int nCopy = strlen(zName); |
| 163935 | | - char *zCopy = sqlite3_malloc(nCopy+2); |
| 164176 | + size_t nCopy = strlen(zName); |
| 164177 | + char *zCopy = sqlite3_malloc64(nCopy+2); |
| 163936 | 164178 | if( zCopy ){ |
| 163937 | 164179 | memcpy(zCopy, zName, nCopy); |
| 163938 | 164180 | zCopy[nCopy-3] = 'o'; |
| 163939 | 164181 | zCopy[nCopy] = '\0'; |
| 163940 | 164182 | zCopy[nCopy+1] = '\0'; |
| | @@ -164159,17 +164401,17 @@ |
| 164159 | 164401 | 0, /* xCurrentTimeInt64 (version 2) */ |
| 164160 | 164402 | 0, 0, 0 /* Unimplemented version 3 methods */ |
| 164161 | 164403 | }; |
| 164162 | 164404 | |
| 164163 | 164405 | rbu_vfs *pNew = 0; /* Newly allocated VFS */ |
| 164164 | | - int nName; |
| 164165 | 164406 | int rc = SQLITE_OK; |
| 164407 | + size_t nName; |
| 164408 | + size_t nByte; |
| 164166 | 164409 | |
| 164167 | | - int nByte; |
| 164168 | 164410 | nName = strlen(zName); |
| 164169 | 164411 | nByte = sizeof(rbu_vfs) + nName + 1; |
| 164170 | | - pNew = (rbu_vfs*)sqlite3_malloc(nByte); |
| 164412 | + pNew = (rbu_vfs*)sqlite3_malloc64(nByte); |
| 164171 | 164413 | if( pNew==0 ){ |
| 164172 | 164414 | rc = SQLITE_NOMEM; |
| 164173 | 164415 | }else{ |
| 164174 | 164416 | sqlite3_vfs *pParent; /* Parent VFS */ |
| 164175 | 164417 | memset(pNew, 0, nByte); |
| | @@ -167174,10 +167416,13 @@ |
| 167174 | 167416 | ** If parameter iCol is greater than or equal to the number of columns |
| 167175 | 167417 | ** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g. |
| 167176 | 167418 | ** an OOM condition or IO error), an appropriate SQLite error code is |
| 167177 | 167419 | ** returned. |
| 167178 | 167420 | ** |
| 167421 | +** This function may be quite inefficient if used with an FTS5 table |
| 167422 | +** created with the "columnsize=0" option. |
| 167423 | +** |
| 167179 | 167424 | ** xColumnText: |
| 167180 | 167425 | ** This function attempts to retrieve the text of column iCol of the |
| 167181 | 167426 | ** current document. If successful, (*pz) is set to point to a buffer |
| 167182 | 167427 | ** containing the text in utf-8 encoding, (*pn) is set to the size in bytes |
| 167183 | 167428 | ** (not characters) of the buffer and SQLITE_OK is returned. Otherwise, |
| | @@ -167194,18 +167439,32 @@ |
| 167194 | 167439 | ** xInstCount: |
| 167195 | 167440 | ** Set *pnInst to the total number of occurrences of all phrases within |
| 167196 | 167441 | ** the query within the current row. Return SQLITE_OK if successful, or |
| 167197 | 167442 | ** an error code (i.e. SQLITE_NOMEM) if an error occurs. |
| 167198 | 167443 | ** |
| 167444 | +** This API can be quite slow if used with an FTS5 table created with the |
| 167445 | +** "detail=none" or "detail=column" option. If the FTS5 table is created |
| 167446 | +** with either "detail=none" or "detail=column" and "content=" option |
| 167447 | +** (i.e. if it is a contentless table), then this API always returns 0. |
| 167448 | +** |
| 167199 | 167449 | ** xInst: |
| 167200 | 167450 | ** Query for the details of phrase match iIdx within the current row. |
| 167201 | 167451 | ** Phrase matches are numbered starting from zero, so the iIdx argument |
| 167202 | 167452 | ** should be greater than or equal to zero and smaller than the value |
| 167203 | 167453 | ** output by xInstCount(). |
| 167454 | +** |
| 167455 | +** Usually, output parameter *piPhrase is set to the phrase number, *piCol |
| 167456 | +** to the column in which it occurs and *piOff the token offset of the |
| 167457 | +** first token of the phrase. The exception is if the table was created |
| 167458 | +** with the offsets=0 option specified. In this case *piOff is always |
| 167459 | +** set to -1. |
| 167204 | 167460 | ** |
| 167205 | 167461 | ** Returns SQLITE_OK if successful, or an error code (i.e. SQLITE_NOMEM) |
| 167206 | 167462 | ** if an error occurs. |
| 167463 | +** |
| 167464 | +** This API can be quite slow if used with an FTS5 table created with the |
| 167465 | +** "detail=none" or "detail=column" option. |
| 167207 | 167466 | ** |
| 167208 | 167467 | ** xRowid: |
| 167209 | 167468 | ** Returns the rowid of the current row. |
| 167210 | 167469 | ** |
| 167211 | 167470 | ** xTokenize: |
| | @@ -167286,25 +167545,63 @@ |
| 167286 | 167545 | ** through instances of phrase iPhrase, use the following code: |
| 167287 | 167546 | ** |
| 167288 | 167547 | ** Fts5PhraseIter iter; |
| 167289 | 167548 | ** int iCol, iOff; |
| 167290 | 167549 | ** for(pApi->xPhraseFirst(pFts, iPhrase, &iter, &iCol, &iOff); |
| 167291 | | -** iOff>=0; |
| 167550 | +** iCol>=0; |
| 167292 | 167551 | ** pApi->xPhraseNext(pFts, &iter, &iCol, &iOff) |
| 167293 | 167552 | ** ){ |
| 167294 | 167553 | ** // An instance of phrase iPhrase at offset iOff of column iCol |
| 167295 | 167554 | ** } |
| 167296 | 167555 | ** |
| 167297 | 167556 | ** The Fts5PhraseIter structure is defined above. Applications should not |
| 167298 | 167557 | ** modify this structure directly - it should only be used as shown above |
| 167299 | | -** with the xPhraseFirst() and xPhraseNext() API methods. |
| 167558 | +** with the xPhraseFirst() and xPhraseNext() API methods (and by |
| 167559 | +** xPhraseFirstColumn() and xPhraseNextColumn() as illustrated below). |
| 167560 | +** |
| 167561 | +** This API can be quite slow if used with an FTS5 table created with the |
| 167562 | +** "detail=none" or "detail=column" option. If the FTS5 table is created |
| 167563 | +** with either "detail=none" or "detail=column" and "content=" option |
| 167564 | +** (i.e. if it is a contentless table), then this API always iterates |
| 167565 | +** through an empty set (all calls to xPhraseFirst() set iCol to -1). |
| 167300 | 167566 | ** |
| 167301 | 167567 | ** xPhraseNext() |
| 167302 | 167568 | ** See xPhraseFirst above. |
| 167569 | +** |
| 167570 | +** xPhraseFirstColumn() |
| 167571 | +** This function and xPhraseNextColumn() are similar to the xPhraseFirst() |
| 167572 | +** and xPhraseNext() APIs described above. The difference is that instead |
| 167573 | +** of iterating through all instances of a phrase in the current row, these |
| 167574 | +** APIs are used to iterate through the set of columns in the current row |
| 167575 | +** that contain one or more instances of a specified phrase. For example: |
| 167576 | +** |
| 167577 | +** Fts5PhraseIter iter; |
| 167578 | +** int iCol; |
| 167579 | +** for(pApi->xPhraseFirstColumn(pFts, iPhrase, &iter, &iCol); |
| 167580 | +** iCol>=0; |
| 167581 | +** pApi->xPhraseNextColumn(pFts, &iter, &iCol) |
| 167582 | +** ){ |
| 167583 | +** // Column iCol contains at least one instance of phrase iPhrase |
| 167584 | +** } |
| 167585 | +** |
| 167586 | +** This API can be quite slow if used with an FTS5 table created with the |
| 167587 | +** "detail=none" option. If the FTS5 table is created with either |
| 167588 | +** "detail=none" "content=" option (i.e. if it is a contentless table), |
| 167589 | +** then this API always iterates through an empty set (all calls to |
| 167590 | +** xPhraseFirstColumn() set iCol to -1). |
| 167591 | +** |
| 167592 | +** The information accessed using this API and its companion |
| 167593 | +** xPhraseFirstColumn() may also be obtained using xPhraseFirst/xPhraseNext |
| 167594 | +** (or xInst/xInstCount). The chief advantage of this API is that it is |
| 167595 | +** significantly more efficient than those alternatives when used with |
| 167596 | +** "detail=column" tables. |
| 167597 | +** |
| 167598 | +** xPhraseNextColumn() |
| 167599 | +** See xPhraseFirstColumn above. |
| 167303 | 167600 | */ |
| 167304 | 167601 | struct Fts5ExtensionApi { |
| 167305 | | - int iVersion; /* Currently always set to 1 */ |
| 167602 | + int iVersion; /* Currently always set to 3 */ |
| 167306 | 167603 | |
| 167307 | 167604 | void *(*xUserData)(Fts5Context*); |
| 167308 | 167605 | |
| 167309 | 167606 | int (*xColumnCount)(Fts5Context*); |
| 167310 | 167607 | int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow); |
| | @@ -167330,12 +167627,15 @@ |
| 167330 | 167627 | int(*)(const Fts5ExtensionApi*,Fts5Context*,void*) |
| 167331 | 167628 | ); |
| 167332 | 167629 | int (*xSetAuxdata)(Fts5Context*, void *pAux, void(*xDelete)(void*)); |
| 167333 | 167630 | void *(*xGetAuxdata)(Fts5Context*, int bClear); |
| 167334 | 167631 | |
| 167335 | | - void (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*); |
| 167632 | + int (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*); |
| 167336 | 167633 | void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff); |
| 167634 | + |
| 167635 | + int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*); |
| 167636 | + void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol); |
| 167337 | 167637 | }; |
| 167338 | 167638 | |
| 167339 | 167639 | /* |
| 167340 | 167640 | ** CUSTOM AUXILIARY FUNCTIONS |
| 167341 | 167641 | *************************************************************************/ |
| | @@ -167762,10 +168062,11 @@ |
| 167762 | 168062 | int *aPrefix; /* Sizes in bytes of nPrefix prefix indexes */ |
| 167763 | 168063 | int eContent; /* An FTS5_CONTENT value */ |
| 167764 | 168064 | char *zContent; /* content table */ |
| 167765 | 168065 | char *zContentRowid; /* "content_rowid=" option value */ |
| 167766 | 168066 | int bColumnsize; /* "columnsize=" option value (dflt==1) */ |
| 168067 | + int eDetail; /* FTS5_DETAIL_XXX value */ |
| 167767 | 168068 | char *zContentExprlist; |
| 167768 | 168069 | Fts5Tokenizer *pTok; |
| 167769 | 168070 | fts5_tokenizer *pTokApi; |
| 167770 | 168071 | |
| 167771 | 168072 | /* Values loaded from the %_config table */ |
| | @@ -167790,10 +168091,13 @@ |
| 167790 | 168091 | |
| 167791 | 168092 | #define FTS5_CONTENT_NORMAL 0 |
| 167792 | 168093 | #define FTS5_CONTENT_NONE 1 |
| 167793 | 168094 | #define FTS5_CONTENT_EXTERNAL 2 |
| 167794 | 168095 | |
| 168096 | +#define FTS5_DETAIL_FULL 0 |
| 168097 | +#define FTS5_DETAIL_NONE 1 |
| 168098 | +#define FTS5_DETAIL_COLUMNS 2 |
| 167795 | 168099 | |
| 167796 | 168100 | |
| 167797 | 168101 | |
| 167798 | 168102 | static int sqlite3Fts5ConfigParse( |
| 167799 | 168103 | Fts5Global*, sqlite3*, int, const char **, Fts5Config**, char** |
| | @@ -167832,17 +168136,17 @@ |
| 167832 | 168136 | ** Buffer object for the incremental building of string data. |
| 167833 | 168137 | */ |
| 167834 | 168138 | typedef struct Fts5Buffer Fts5Buffer; |
| 167835 | 168139 | struct Fts5Buffer { |
| 167836 | 168140 | u8 *p; |
| 167837 | | - int n; |
| 167838 | | - int nSpace; |
| 168141 | + u32 n; |
| 168142 | + u32 nSpace; |
| 167839 | 168143 | }; |
| 167840 | 168144 | |
| 167841 | | -static int sqlite3Fts5BufferSize(int*, Fts5Buffer*, int); |
| 168145 | +static int sqlite3Fts5BufferSize(int*, Fts5Buffer*, u32); |
| 167842 | 168146 | static void sqlite3Fts5BufferAppendVarint(int*, Fts5Buffer*, i64); |
| 167843 | | -static void sqlite3Fts5BufferAppendBlob(int*, Fts5Buffer*, int, const u8*); |
| 168147 | +static void sqlite3Fts5BufferAppendBlob(int*, Fts5Buffer*, u32, const u8*); |
| 167844 | 168148 | static void sqlite3Fts5BufferAppendString(int *, Fts5Buffer*, const char*); |
| 167845 | 168149 | static void sqlite3Fts5BufferFree(Fts5Buffer*); |
| 167846 | 168150 | static void sqlite3Fts5BufferZero(Fts5Buffer*); |
| 167847 | 168151 | static void sqlite3Fts5BufferSet(int*, Fts5Buffer*, int, const u8*); |
| 167848 | 168152 | static void sqlite3Fts5BufferAppendPrintf(int *, Fts5Buffer*, char *zFmt, ...); |
| | @@ -167903,10 +168207,17 @@ |
| 167903 | 168207 | static char *sqlite3Fts5Strndup(int *pRc, const char *pIn, int nIn); |
| 167904 | 168208 | |
| 167905 | 168209 | /* Character set tests (like isspace(), isalpha() etc.) */ |
| 167906 | 168210 | static int sqlite3Fts5IsBareword(char t); |
| 167907 | 168211 | |
| 168212 | + |
| 168213 | +/* Bucket of terms object used by the integrity-check in offsets=0 mode. */ |
| 168214 | +typedef struct Fts5Termset Fts5Termset; |
| 168215 | +static int sqlite3Fts5TermsetNew(Fts5Termset**); |
| 168216 | +static int sqlite3Fts5TermsetAdd(Fts5Termset*, int, const char*, int, int *pbPresent); |
| 168217 | +static void sqlite3Fts5TermsetFree(Fts5Termset*); |
| 168218 | + |
| 167908 | 168219 | /* |
| 167909 | 168220 | ** End of interface to code in fts5_buffer.c. |
| 167910 | 168221 | **************************************************************************/ |
| 167911 | 168222 | |
| 167912 | 168223 | /************************************************************************** |
| | @@ -167938,10 +168249,33 @@ |
| 167938 | 168249 | ** sqlite3Fts5IterNext(pIter) |
| 167939 | 168250 | ** ){ |
| 167940 | 168251 | ** i64 iRowid = sqlite3Fts5IterRowid(pIter); |
| 167941 | 168252 | ** } |
| 167942 | 168253 | */ |
| 168254 | + |
| 168255 | +/* |
| 168256 | +** Return a simple checksum value based on the arguments. |
| 168257 | +*/ |
| 168258 | +static u64 sqlite3Fts5IndexEntryCksum( |
| 168259 | + i64 iRowid, |
| 168260 | + int iCol, |
| 168261 | + int iPos, |
| 168262 | + int iIdx, |
| 168263 | + const char *pTerm, |
| 168264 | + int nTerm |
| 168265 | +); |
| 168266 | + |
| 168267 | +/* |
| 168268 | +** Argument p points to a buffer containing utf-8 text that is n bytes in |
| 168269 | +** size. Return the number of bytes in the nChar character prefix of the |
| 168270 | +** buffer, or 0 if there are less than nChar characters in total. |
| 168271 | +*/ |
| 168272 | +static int sqlite3Fts5IndexCharlenToBytelen( |
| 168273 | + const char *p, |
| 168274 | + int nByte, |
| 168275 | + int nChar |
| 168276 | +); |
| 167943 | 168277 | |
| 167944 | 168278 | /* |
| 167945 | 168279 | ** Open a new iterator to iterate though all rowids that match the |
| 167946 | 168280 | ** specified token or token prefix. |
| 167947 | 168281 | */ |
| | @@ -168024,11 +168358,10 @@ |
| 168024 | 168358 | static int sqlite3Fts5IndexSetAverages(Fts5Index *p, const u8*, int); |
| 168025 | 168359 | |
| 168026 | 168360 | /* |
| 168027 | 168361 | ** Functions called by the storage module as part of integrity-check. |
| 168028 | 168362 | */ |
| 168029 | | -static u64 sqlite3Fts5IndexCksum(Fts5Config*,i64,int,int,const char*,int); |
| 168030 | 168363 | static int sqlite3Fts5IndexIntegrityCheck(Fts5Index*, u64 cksum); |
| 168031 | 168364 | |
| 168032 | 168365 | /* |
| 168033 | 168366 | ** Called during virtual module initialization to register UDF |
| 168034 | 168367 | ** fts5_decode() with SQLite |
| | @@ -168046,10 +168379,12 @@ |
| 168046 | 168379 | static int sqlite3Fts5IndexReinit(Fts5Index *p); |
| 168047 | 168380 | static int sqlite3Fts5IndexOptimize(Fts5Index *p); |
| 168048 | 168381 | static int sqlite3Fts5IndexMerge(Fts5Index *p, int nMerge); |
| 168049 | 168382 | |
| 168050 | 168383 | static int sqlite3Fts5IndexLoadConfig(Fts5Index *p); |
| 168384 | + |
| 168385 | +static int sqlite3Fts5IterCollist(Fts5IndexIter*, const u8 **, int*); |
| 168051 | 168386 | |
| 168052 | 168387 | /* |
| 168053 | 168388 | ** End of interface to code in fts5_index.c. |
| 168054 | 168389 | **************************************************************************/ |
| 168055 | 168390 | |
| | @@ -168103,11 +168438,11 @@ |
| 168103 | 168438 | typedef struct Fts5Hash Fts5Hash; |
| 168104 | 168439 | |
| 168105 | 168440 | /* |
| 168106 | 168441 | ** Create a hash table, free a hash table. |
| 168107 | 168442 | */ |
| 168108 | | -static int sqlite3Fts5HashNew(Fts5Hash**, int *pnSize); |
| 168443 | +static int sqlite3Fts5HashNew(Fts5Config*, Fts5Hash**, int *pnSize); |
| 168109 | 168444 | static void sqlite3Fts5HashFree(Fts5Hash*); |
| 168110 | 168445 | |
| 168111 | 168446 | static int sqlite3Fts5HashWrite( |
| 168112 | 168447 | Fts5Hash*, |
| 168113 | 168448 | i64 iRowid, /* Rowid for this entry */ |
| | @@ -168162,11 +168497,11 @@ |
| 168162 | 168497 | static int sqlite3Fts5StorageRename(Fts5Storage*, const char *zName); |
| 168163 | 168498 | |
| 168164 | 168499 | static int sqlite3Fts5DropAll(Fts5Config*); |
| 168165 | 168500 | static int sqlite3Fts5CreateTable(Fts5Config*, const char*, const char*, int, char **); |
| 168166 | 168501 | |
| 168167 | | -static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64); |
| 168502 | +static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64, sqlite3_value**); |
| 168168 | 168503 | static int sqlite3Fts5StorageContentInsert(Fts5Storage *p, sqlite3_value**, i64*); |
| 168169 | 168504 | static int sqlite3Fts5StorageIndexInsert(Fts5Storage *p, sqlite3_value**, i64); |
| 168170 | 168505 | |
| 168171 | 168506 | static int sqlite3Fts5StorageIntegrity(Fts5Storage *p); |
| 168172 | 168507 | |
| | @@ -168182,12 +168517,10 @@ |
| 168182 | 168517 | |
| 168183 | 168518 | static int sqlite3Fts5StorageConfigValue( |
| 168184 | 168519 | Fts5Storage *p, const char*, sqlite3_value*, int |
| 168185 | 168520 | ); |
| 168186 | 168521 | |
| 168187 | | -static int sqlite3Fts5StorageSpecialDelete(Fts5Storage *p, i64 iDel, sqlite3_value**); |
| 168188 | | - |
| 168189 | 168522 | static int sqlite3Fts5StorageDeleteAll(Fts5Storage *p); |
| 168190 | 168523 | static int sqlite3Fts5StorageRebuild(Fts5Storage *p); |
| 168191 | 168524 | static int sqlite3Fts5StorageOptimize(Fts5Storage *p); |
| 168192 | 168525 | static int sqlite3Fts5StorageMerge(Fts5Storage *p, int nMerge); |
| 168193 | 168526 | |
| | @@ -168239,12 +168572,22 @@ |
| 168239 | 168572 | static int sqlite3Fts5ExprInit(Fts5Global*, sqlite3*); |
| 168240 | 168573 | |
| 168241 | 168574 | static int sqlite3Fts5ExprPhraseCount(Fts5Expr*); |
| 168242 | 168575 | static int sqlite3Fts5ExprPhraseSize(Fts5Expr*, int iPhrase); |
| 168243 | 168576 | static int sqlite3Fts5ExprPoslist(Fts5Expr*, int, const u8 **); |
| 168577 | + |
| 168578 | +typedef struct Fts5PoslistPopulator Fts5PoslistPopulator; |
| 168579 | +static Fts5PoslistPopulator *sqlite3Fts5ExprClearPoslists(Fts5Expr*, int); |
| 168580 | +static int sqlite3Fts5ExprPopulatePoslists( |
| 168581 | + Fts5Config*, Fts5Expr*, Fts5PoslistPopulator*, int, const char*, int |
| 168582 | +); |
| 168583 | +static void sqlite3Fts5ExprCheckPoslists(Fts5Expr*, i64); |
| 168584 | +static void sqlite3Fts5ExprClearEof(Fts5Expr*); |
| 168244 | 168585 | |
| 168245 | 168586 | static int sqlite3Fts5ExprClonePhrase(Fts5Config*, Fts5Expr*, int, Fts5Expr**); |
| 168587 | + |
| 168588 | +static int sqlite3Fts5ExprPhraseCollist(Fts5Expr *, int, const u8 **, int *); |
| 168246 | 168589 | |
| 168247 | 168590 | /******************************************* |
| 168248 | 168591 | ** The fts5_expr.c API above this point is used by the other hand-written |
| 168249 | 168592 | ** C code in this module. The interfaces below this point are called by |
| 168250 | 168593 | ** the parser code in fts5parse.y. */ |
| | @@ -170120,12 +170463,12 @@ |
| 170120 | 170463 | |
| 170121 | 170464 | |
| 170122 | 170465 | |
| 170123 | 170466 | /* #include "fts5Int.h" */ |
| 170124 | 170467 | |
| 170125 | | -static int sqlite3Fts5BufferSize(int *pRc, Fts5Buffer *pBuf, int nByte){ |
| 170126 | | - int nNew = pBuf->nSpace ? pBuf->nSpace*2 : 64; |
| 170468 | +static int sqlite3Fts5BufferSize(int *pRc, Fts5Buffer *pBuf, u32 nByte){ |
| 170469 | + u32 nNew = pBuf->nSpace ? pBuf->nSpace*2 : 64; |
| 170127 | 170470 | u8 *pNew; |
| 170128 | 170471 | while( nNew<nByte ){ |
| 170129 | 170472 | nNew = nNew * 2; |
| 170130 | 170473 | } |
| 170131 | 170474 | pNew = sqlite3_realloc(pBuf->p, nNew); |
| | @@ -170166,14 +170509,14 @@ |
| 170166 | 170509 | ** is called, it is a no-op. |
| 170167 | 170510 | */ |
| 170168 | 170511 | static void sqlite3Fts5BufferAppendBlob( |
| 170169 | 170512 | int *pRc, |
| 170170 | 170513 | Fts5Buffer *pBuf, |
| 170171 | | - int nData, |
| 170514 | + u32 nData, |
| 170172 | 170515 | const u8 *pData |
| 170173 | 170516 | ){ |
| 170174 | | - assert( *pRc || nData>=0 ); |
| 170517 | + assert_nc( *pRc || nData>=0 ); |
| 170175 | 170518 | if( fts5BufferGrow(pRc, pBuf, nData) ) return; |
| 170176 | 170519 | memcpy(&pBuf->p[pBuf->n], pData, nData); |
| 170177 | 170520 | pBuf->n += nData; |
| 170178 | 170521 | } |
| 170179 | 170522 | |
| | @@ -170397,10 +170740,96 @@ |
| 170397 | 170740 | |
| 170398 | 170741 | return (t & 0x80) || aBareword[(int)t]; |
| 170399 | 170742 | } |
| 170400 | 170743 | |
| 170401 | 170744 | |
| 170745 | +/************************************************************************* |
| 170746 | +*/ |
| 170747 | +typedef struct Fts5TermsetEntry Fts5TermsetEntry; |
| 170748 | +struct Fts5TermsetEntry { |
| 170749 | + char *pTerm; |
| 170750 | + int nTerm; |
| 170751 | + int iIdx; /* Index (main or aPrefix[] entry) */ |
| 170752 | + Fts5TermsetEntry *pNext; |
| 170753 | +}; |
| 170754 | + |
| 170755 | +struct Fts5Termset { |
| 170756 | + Fts5TermsetEntry *apHash[512]; |
| 170757 | +}; |
| 170758 | + |
| 170759 | +static int sqlite3Fts5TermsetNew(Fts5Termset **pp){ |
| 170760 | + int rc = SQLITE_OK; |
| 170761 | + *pp = sqlite3Fts5MallocZero(&rc, sizeof(Fts5Termset)); |
| 170762 | + return rc; |
| 170763 | +} |
| 170764 | + |
| 170765 | +static int sqlite3Fts5TermsetAdd( |
| 170766 | + Fts5Termset *p, |
| 170767 | + int iIdx, |
| 170768 | + const char *pTerm, int nTerm, |
| 170769 | + int *pbPresent |
| 170770 | +){ |
| 170771 | + int rc = SQLITE_OK; |
| 170772 | + *pbPresent = 0; |
| 170773 | + if( p ){ |
| 170774 | + int i; |
| 170775 | + int hash = 13; |
| 170776 | + Fts5TermsetEntry *pEntry; |
| 170777 | + |
| 170778 | + /* Calculate a hash value for this term. This is the same hash checksum |
| 170779 | + ** used by the fts5_hash.c module. This is not important for correct |
| 170780 | + ** operation of the module, but is necessary to ensure that some tests |
| 170781 | + ** designed to produce hash table collisions really do work. */ |
| 170782 | + for(i=nTerm-1; i>=0; i--){ |
| 170783 | + hash = (hash << 3) ^ hash ^ pTerm[i]; |
| 170784 | + } |
| 170785 | + hash = (hash << 3) ^ hash ^ iIdx; |
| 170786 | + hash = hash % ArraySize(p->apHash); |
| 170787 | + |
| 170788 | + for(pEntry=p->apHash[hash]; pEntry; pEntry=pEntry->pNext){ |
| 170789 | + if( pEntry->iIdx==iIdx |
| 170790 | + && pEntry->nTerm==nTerm |
| 170791 | + && memcmp(pEntry->pTerm, pTerm, nTerm)==0 |
| 170792 | + ){ |
| 170793 | + *pbPresent = 1; |
| 170794 | + break; |
| 170795 | + } |
| 170796 | + } |
| 170797 | + |
| 170798 | + if( pEntry==0 ){ |
| 170799 | + pEntry = sqlite3Fts5MallocZero(&rc, sizeof(Fts5TermsetEntry) + nTerm); |
| 170800 | + if( pEntry ){ |
| 170801 | + pEntry->pTerm = (char*)&pEntry[1]; |
| 170802 | + pEntry->nTerm = nTerm; |
| 170803 | + pEntry->iIdx = iIdx; |
| 170804 | + memcpy(pEntry->pTerm, pTerm, nTerm); |
| 170805 | + pEntry->pNext = p->apHash[hash]; |
| 170806 | + p->apHash[hash] = pEntry; |
| 170807 | + } |
| 170808 | + } |
| 170809 | + } |
| 170810 | + |
| 170811 | + return rc; |
| 170812 | +} |
| 170813 | + |
| 170814 | +static void sqlite3Fts5TermsetFree(Fts5Termset *p){ |
| 170815 | + if( p ){ |
| 170816 | + int i; |
| 170817 | + for(i=0; i<ArraySize(p->apHash); i++){ |
| 170818 | + Fts5TermsetEntry *pEntry = p->apHash[i]; |
| 170819 | + while( pEntry ){ |
| 170820 | + Fts5TermsetEntry *pDel = pEntry; |
| 170821 | + pEntry = pEntry->pNext; |
| 170822 | + sqlite3_free(pDel); |
| 170823 | + } |
| 170824 | + } |
| 170825 | + sqlite3_free(p); |
| 170826 | + } |
| 170827 | +} |
| 170828 | + |
| 170829 | + |
| 170830 | + |
| 170402 | 170831 | |
| 170403 | 170832 | /* |
| 170404 | 170833 | ** 2014 Jun 09 |
| 170405 | 170834 | ** |
| 170406 | 170835 | ** The author disclaims copyright to this source code. In place of |
| | @@ -170412,11 +170841,10 @@ |
| 170412 | 170841 | ** |
| 170413 | 170842 | ****************************************************************************** |
| 170414 | 170843 | ** |
| 170415 | 170844 | ** This is an SQLite module implementing full-text search. |
| 170416 | 170845 | */ |
| 170417 | | - |
| 170418 | 170846 | |
| 170419 | 170847 | |
| 170420 | 170848 | /* #include "fts5Int.h" */ |
| 170421 | 170849 | |
| 170422 | 170850 | #define FTS5_DEFAULT_PAGE_SIZE 4050 |
| | @@ -170595,10 +171023,37 @@ |
| 170595 | 171023 | if( quote=='[' || quote=='\'' || quote=='"' || quote=='`' ){ |
| 170596 | 171024 | fts5Dequote(z); |
| 170597 | 171025 | } |
| 170598 | 171026 | } |
| 170599 | 171027 | |
| 171028 | + |
| 171029 | +struct Fts5Enum { |
| 171030 | + const char *zName; |
| 171031 | + int eVal; |
| 171032 | +}; |
| 171033 | +typedef struct Fts5Enum Fts5Enum; |
| 171034 | + |
| 171035 | +static int fts5ConfigSetEnum( |
| 171036 | + const Fts5Enum *aEnum, |
| 171037 | + const char *zEnum, |
| 171038 | + int *peVal |
| 171039 | +){ |
| 171040 | + int nEnum = strlen(zEnum); |
| 171041 | + int i; |
| 171042 | + int iVal = -1; |
| 171043 | + |
| 171044 | + for(i=0; aEnum[i].zName; i++){ |
| 171045 | + if( sqlite3_strnicmp(aEnum[i].zName, zEnum, nEnum)==0 ){ |
| 171046 | + if( iVal>=0 ) return SQLITE_ERROR; |
| 171047 | + iVal = aEnum[i].eVal; |
| 171048 | + } |
| 171049 | + } |
| 171050 | + |
| 171051 | + *peVal = iVal; |
| 171052 | + return iVal<0 ? SQLITE_ERROR : SQLITE_OK; |
| 171053 | +} |
| 171054 | + |
| 170600 | 171055 | /* |
| 170601 | 171056 | ** Parse a "special" CREATE VIRTUAL TABLE directive and update |
| 170602 | 171057 | ** configuration object pConfig as appropriate. |
| 170603 | 171058 | ** |
| 170604 | 171059 | ** If successful, object pConfig is updated and SQLITE_OK returned. If |
| | @@ -170652,11 +171107,11 @@ |
| 170652 | 171107 | while( p[0]>='0' && p[0]<='9' && nPre<1000 ){ |
| 170653 | 171108 | nPre = nPre*10 + (p[0] - '0'); |
| 170654 | 171109 | p++; |
| 170655 | 171110 | } |
| 170656 | 171111 | |
| 170657 | | - if( rc==SQLITE_OK && (nPre<=0 || nPre>=1000) ){ |
| 171112 | + if( nPre<=0 || nPre>=1000 ){ |
| 170658 | 171113 | *pzErr = sqlite3_mprintf("prefix length out of range (max 999)"); |
| 170659 | 171114 | rc = SQLITE_ERROR; |
| 170660 | 171115 | break; |
| 170661 | 171116 | } |
| 170662 | 171117 | |
| | @@ -170744,10 +171199,24 @@ |
| 170744 | 171199 | }else{ |
| 170745 | 171200 | pConfig->bColumnsize = (zArg[0]=='1'); |
| 170746 | 171201 | } |
| 170747 | 171202 | return rc; |
| 170748 | 171203 | } |
| 171204 | + |
| 171205 | + if( sqlite3_strnicmp("detail", zCmd, nCmd)==0 ){ |
| 171206 | + const Fts5Enum aDetail[] = { |
| 171207 | + { "none", FTS5_DETAIL_NONE }, |
| 171208 | + { "full", FTS5_DETAIL_FULL }, |
| 171209 | + { "columns", FTS5_DETAIL_COLUMNS }, |
| 171210 | + { 0, 0 } |
| 171211 | + }; |
| 171212 | + |
| 171213 | + if( (rc = fts5ConfigSetEnum(aDetail, zArg, &pConfig->eDetail)) ){ |
| 171214 | + *pzErr = sqlite3_mprintf("malformed detail=... directive"); |
| 171215 | + } |
| 171216 | + return rc; |
| 171217 | + } |
| 170749 | 171218 | |
| 170750 | 171219 | *pzErr = sqlite3_mprintf("unrecognized option: \"%.*s\"", nCmd, zCmd); |
| 170751 | 171220 | return SQLITE_ERROR; |
| 170752 | 171221 | } |
| 170753 | 171222 | |
| | @@ -170900,10 +171369,11 @@ |
| 170900 | 171369 | pRet->azCol = (char**)sqlite3Fts5MallocZero(&rc, nByte); |
| 170901 | 171370 | pRet->abUnindexed = (u8*)&pRet->azCol[nArg]; |
| 170902 | 171371 | pRet->zDb = sqlite3Fts5Strndup(&rc, azArg[1], -1); |
| 170903 | 171372 | pRet->zName = sqlite3Fts5Strndup(&rc, azArg[2], -1); |
| 170904 | 171373 | pRet->bColumnsize = 1; |
| 171374 | + pRet->eDetail = FTS5_DETAIL_FULL; |
| 170905 | 171375 | #ifdef SQLITE_DEBUG |
| 170906 | 171376 | pRet->bPrefixIndex = 1; |
| 170907 | 171377 | #endif |
| 170908 | 171378 | if( rc==SQLITE_OK && sqlite3_stricmp(pRet->zName, FTS5_RANK_NAME)==0 ){ |
| 170909 | 171379 | *pzErr = sqlite3_mprintf("reserved fts5 table name: %s", pRet->zName); |
| | @@ -171346,10 +171816,11 @@ |
| 171346 | 171816 | #endif |
| 171347 | 171817 | |
| 171348 | 171818 | |
| 171349 | 171819 | struct Fts5Expr { |
| 171350 | 171820 | Fts5Index *pIndex; |
| 171821 | + Fts5Config *pConfig; |
| 171351 | 171822 | Fts5ExprNode *pRoot; |
| 171352 | 171823 | int bDesc; /* Iterate in descending rowid order */ |
| 171353 | 171824 | int nPhrase; /* Number of phrases in expression */ |
| 171354 | 171825 | Fts5ExprPhrase **apExprPhrase; /* Pointers to phrase objects */ |
| 171355 | 171826 | }; |
| | @@ -171541,10 +172012,11 @@ |
| 171541 | 172012 | sParse.rc = SQLITE_NOMEM; |
| 171542 | 172013 | sqlite3Fts5ParseNodeFree(sParse.pExpr); |
| 171543 | 172014 | }else{ |
| 171544 | 172015 | pNew->pRoot = sParse.pExpr; |
| 171545 | 172016 | pNew->pIndex = 0; |
| 172017 | + pNew->pConfig = pConfig; |
| 171546 | 172018 | pNew->apExprPhrase = sParse.apPhrase; |
| 171547 | 172019 | pNew->nPhrase = sParse.nPhrase; |
| 171548 | 172020 | sParse.apPhrase = 0; |
| 171549 | 172021 | } |
| 171550 | 172022 | } |
| | @@ -171605,12 +172077,13 @@ |
| 171605 | 172077 | } |
| 171606 | 172078 | |
| 171607 | 172079 | /* |
| 171608 | 172080 | ** Argument pTerm must be a synonym iterator. |
| 171609 | 172081 | */ |
| 171610 | | -static int fts5ExprSynonymPoslist( |
| 172082 | +static int fts5ExprSynonymList( |
| 171611 | 172083 | Fts5ExprTerm *pTerm, |
| 172084 | + int bCollist, |
| 171612 | 172085 | Fts5Colset *pColset, |
| 171613 | 172086 | i64 iRowid, |
| 171614 | 172087 | int *pbDel, /* OUT: Caller should sqlite3_free(*pa) */ |
| 171615 | 172088 | u8 **pa, int *pn |
| 171616 | 172089 | ){ |
| | @@ -171625,13 +172098,20 @@ |
| 171625 | 172098 | for(p=pTerm; p; p=p->pSynonym){ |
| 171626 | 172099 | Fts5IndexIter *pIter = p->pIter; |
| 171627 | 172100 | if( sqlite3Fts5IterEof(pIter)==0 && sqlite3Fts5IterRowid(pIter)==iRowid ){ |
| 171628 | 172101 | const u8 *a; |
| 171629 | 172102 | int n; |
| 171630 | | - i64 dummy; |
| 171631 | | - rc = sqlite3Fts5IterPoslist(pIter, pColset, &a, &n, &dummy); |
| 172103 | + |
| 172104 | + if( bCollist ){ |
| 172105 | + rc = sqlite3Fts5IterCollist(pIter, &a, &n); |
| 172106 | + }else{ |
| 172107 | + i64 dummy; |
| 172108 | + rc = sqlite3Fts5IterPoslist(pIter, pColset, &a, &n, &dummy); |
| 172109 | + } |
| 172110 | + |
| 171632 | 172111 | if( rc!=SQLITE_OK ) goto synonym_poslist_out; |
| 172112 | + if( n==0 ) continue; |
| 171633 | 172113 | if( nIter==nAlloc ){ |
| 171634 | 172114 | int nByte = sizeof(Fts5PoslistReader) * nAlloc * 2; |
| 171635 | 172115 | Fts5PoslistReader *aNew = (Fts5PoslistReader*)sqlite3_malloc(nByte); |
| 171636 | 172116 | if( aNew==0 ){ |
| 171637 | 172117 | rc = SQLITE_NOMEM; |
| | @@ -171728,12 +172208,12 @@ |
| 171728 | 172208 | i64 dummy; |
| 171729 | 172209 | int n = 0; |
| 171730 | 172210 | int bFlag = 0; |
| 171731 | 172211 | const u8 *a = 0; |
| 171732 | 172212 | if( pTerm->pSynonym ){ |
| 171733 | | - rc = fts5ExprSynonymPoslist( |
| 171734 | | - pTerm, pColset, pNode->iRowid, &bFlag, (u8**)&a, &n |
| 172213 | + rc = fts5ExprSynonymList( |
| 172214 | + pTerm, 0, pColset, pNode->iRowid, &bFlag, (u8**)&a, &n |
| 171735 | 172215 | ); |
| 171736 | 172216 | }else{ |
| 171737 | 172217 | rc = sqlite3Fts5IterPoslist(pTerm->pIter, pColset, &a, &n, &dummy); |
| 171738 | 172218 | } |
| 171739 | 172219 | if( rc!=SQLITE_OK ) goto ismatch_out; |
| | @@ -172063,34 +172543,55 @@ |
| 172063 | 172543 | Fts5Expr *pExpr, /* Expression that pNear is a part of */ |
| 172064 | 172544 | Fts5ExprNode *pNode /* The "NEAR" node (FTS5_STRING) */ |
| 172065 | 172545 | ){ |
| 172066 | 172546 | Fts5ExprNearset *pNear = pNode->pNear; |
| 172067 | 172547 | int rc = *pRc; |
| 172068 | | - int i; |
| 172069 | | - |
| 172070 | | - /* Check that each phrase in the nearset matches the current row. |
| 172071 | | - ** Populate the pPhrase->poslist buffers at the same time. If any |
| 172072 | | - ** phrase is not a match, break out of the loop early. */ |
| 172073 | | - for(i=0; rc==SQLITE_OK && i<pNear->nPhrase; i++){ |
| 172074 | | - Fts5ExprPhrase *pPhrase = pNear->apPhrase[i]; |
| 172075 | | - if( pPhrase->nTerm>1 || pPhrase->aTerm[0].pSynonym || pNear->pColset ){ |
| 172076 | | - int bMatch = 0; |
| 172077 | | - rc = fts5ExprPhraseIsMatch(pNode, pNear->pColset, pPhrase, &bMatch); |
| 172078 | | - if( bMatch==0 ) break; |
| 172079 | | - }else{ |
| 172080 | | - rc = sqlite3Fts5IterPoslistBuffer( |
| 172081 | | - pPhrase->aTerm[0].pIter, &pPhrase->poslist |
| 172082 | | - ); |
| 172083 | | - } |
| 172084 | | - } |
| 172085 | | - |
| 172086 | | - *pRc = rc; |
| 172087 | | - if( i==pNear->nPhrase && (i==1 || fts5ExprNearIsMatch(pRc, pNear)) ){ |
| 172088 | | - return 1; |
| 172089 | | - } |
| 172090 | | - |
| 172091 | | - return 0; |
| 172548 | + |
| 172549 | + if( pExpr->pConfig->eDetail!=FTS5_DETAIL_FULL ){ |
| 172550 | + Fts5ExprTerm *pTerm; |
| 172551 | + Fts5ExprPhrase *pPhrase = pNear->apPhrase[0]; |
| 172552 | + pPhrase->poslist.n = 0; |
| 172553 | + for(pTerm=&pPhrase->aTerm[0]; pTerm; pTerm=pTerm->pSynonym){ |
| 172554 | + Fts5IndexIter *pIter = pTerm->pIter; |
| 172555 | + if( sqlite3Fts5IterEof(pIter)==0 ){ |
| 172556 | + int n; |
| 172557 | + i64 iRowid; |
| 172558 | + rc = sqlite3Fts5IterPoslist(pIter, pNear->pColset, 0, &n, &iRowid); |
| 172559 | + if( rc!=SQLITE_OK ){ |
| 172560 | + *pRc = rc; |
| 172561 | + return 0; |
| 172562 | + }else if( iRowid==pNode->iRowid && n>0 ){ |
| 172563 | + pPhrase->poslist.n = 1; |
| 172564 | + } |
| 172565 | + } |
| 172566 | + } |
| 172567 | + return pPhrase->poslist.n; |
| 172568 | + }else{ |
| 172569 | + int i; |
| 172570 | + |
| 172571 | + /* Check that each phrase in the nearset matches the current row. |
| 172572 | + ** Populate the pPhrase->poslist buffers at the same time. If any |
| 172573 | + ** phrase is not a match, break out of the loop early. */ |
| 172574 | + for(i=0; rc==SQLITE_OK && i<pNear->nPhrase; i++){ |
| 172575 | + Fts5ExprPhrase *pPhrase = pNear->apPhrase[i]; |
| 172576 | + if( pPhrase->nTerm>1 || pPhrase->aTerm[0].pSynonym || pNear->pColset ){ |
| 172577 | + int bMatch = 0; |
| 172578 | + rc = fts5ExprPhraseIsMatch(pNode, pNear->pColset, pPhrase, &bMatch); |
| 172579 | + if( bMatch==0 ) break; |
| 172580 | + }else{ |
| 172581 | + rc = sqlite3Fts5IterPoslistBuffer( |
| 172582 | + pPhrase->aTerm[0].pIter, &pPhrase->poslist |
| 172583 | + ); |
| 172584 | + } |
| 172585 | + } |
| 172586 | + |
| 172587 | + *pRc = rc; |
| 172588 | + if( i==pNear->nPhrase && (i==1 || fts5ExprNearIsMatch(pRc, pNear)) ){ |
| 172589 | + return 1; |
| 172590 | + } |
| 172591 | + return 0; |
| 172592 | + } |
| 172092 | 172593 | } |
| 172093 | 172594 | |
| 172094 | 172595 | static int fts5ExprTokenTest( |
| 172095 | 172596 | Fts5Expr *pExpr, /* Expression that pNear is a part of */ |
| 172096 | 172597 | Fts5ExprNode *pNode /* The "NEAR" node (FTS5_TERM) */ |
| | @@ -172109,11 +172610,11 @@ |
| 172109 | 172610 | assert( pNode->eType==FTS5_TERM ); |
| 172110 | 172611 | assert( pNear->nPhrase==1 && pPhrase->nTerm==1 ); |
| 172111 | 172612 | assert( pPhrase->aTerm[0].pSynonym==0 ); |
| 172112 | 172613 | |
| 172113 | 172614 | rc = sqlite3Fts5IterPoslist(pIter, pColset, |
| 172114 | | - (const u8**)&pPhrase->poslist.p, &pPhrase->poslist.n, &pNode->iRowid |
| 172615 | + (const u8**)&pPhrase->poslist.p, (int*)&pPhrase->poslist.n, &pNode->iRowid |
| 172115 | 172616 | ); |
| 172116 | 172617 | pNode->bNomatch = (pPhrase->poslist.n==0); |
| 172117 | 172618 | return rc; |
| 172118 | 172619 | } |
| 172119 | 172620 | |
| | @@ -172524,10 +173025,13 @@ |
| 172524 | 173025 | if( cmp || p2->bNomatch ) break; |
| 172525 | 173026 | rc = fts5ExprNodeNext(pExpr, p1, 0, 0); |
| 172526 | 173027 | } |
| 172527 | 173028 | pNode->bEof = p1->bEof; |
| 172528 | 173029 | pNode->iRowid = p1->iRowid; |
| 173030 | + if( p1->bEof ){ |
| 173031 | + fts5ExprNodeZeroPoslist(p2); |
| 173032 | + } |
| 172529 | 173033 | break; |
| 172530 | 173034 | } |
| 172531 | 173035 | } |
| 172532 | 173036 | } |
| 172533 | 173037 | return rc; |
| | @@ -172909,10 +173413,11 @@ |
| 172909 | 173413 | } |
| 172910 | 173414 | |
| 172911 | 173415 | if( rc==SQLITE_OK ){ |
| 172912 | 173416 | /* All the allocations succeeded. Put the expression object together. */ |
| 172913 | 173417 | pNew->pIndex = pExpr->pIndex; |
| 173418 | + pNew->pConfig = pExpr->pConfig; |
| 172914 | 173419 | pNew->nPhrase = 1; |
| 172915 | 173420 | pNew->apExprPhrase[0] = sCtx.pPhrase; |
| 172916 | 173421 | pNew->pRoot->pNear->apPhrase[0] = sCtx.pPhrase; |
| 172917 | 173422 | pNew->pRoot->pNear->nPhrase = 1; |
| 172918 | 173423 | sCtx.pPhrase->pNode = pNew->pRoot; |
| | @@ -173050,10 +173555,19 @@ |
| 173050 | 173555 | static void sqlite3Fts5ParseSetColset( |
| 173051 | 173556 | Fts5Parse *pParse, |
| 173052 | 173557 | Fts5ExprNearset *pNear, |
| 173053 | 173558 | Fts5Colset *pColset |
| 173054 | 173559 | ){ |
| 173560 | + if( pParse->pConfig->eDetail==FTS5_DETAIL_NONE ){ |
| 173561 | + pParse->rc = SQLITE_ERROR; |
| 173562 | + pParse->zErr = sqlite3_mprintf( |
| 173563 | + "fts5: column queries are not supported (detail=none)" |
| 173564 | + ); |
| 173565 | + sqlite3_free(pColset); |
| 173566 | + return; |
| 173567 | + } |
| 173568 | + |
| 173055 | 173569 | if( pNear ){ |
| 173056 | 173570 | pNear->pColset = pColset; |
| 173057 | 173571 | }else{ |
| 173058 | 173572 | sqlite3_free(pColset); |
| 173059 | 173573 | } |
| | @@ -173111,15 +173625,24 @@ |
| 173111 | 173625 | if( eType==FTS5_STRING ){ |
| 173112 | 173626 | int iPhrase; |
| 173113 | 173627 | for(iPhrase=0; iPhrase<pNear->nPhrase; iPhrase++){ |
| 173114 | 173628 | pNear->apPhrase[iPhrase]->pNode = pRet; |
| 173115 | 173629 | } |
| 173116 | | - if( pNear->nPhrase==1 |
| 173117 | | - && pNear->apPhrase[0]->nTerm==1 |
| 173118 | | - && pNear->apPhrase[0]->aTerm[0].pSynonym==0 |
| 173119 | | - ){ |
| 173120 | | - pRet->eType = FTS5_TERM; |
| 173630 | + if( pNear->nPhrase==1 && pNear->apPhrase[0]->nTerm==1 ){ |
| 173631 | + if( pNear->apPhrase[0]->aTerm[0].pSynonym==0 ){ |
| 173632 | + pRet->eType = FTS5_TERM; |
| 173633 | + } |
| 173634 | + }else if( pParse->pConfig->eDetail!=FTS5_DETAIL_FULL ){ |
| 173635 | + assert( pParse->rc==SQLITE_OK ); |
| 173636 | + pParse->rc = SQLITE_ERROR; |
| 173637 | + assert( pParse->zErr==0 ); |
| 173638 | + pParse->zErr = sqlite3_mprintf( |
| 173639 | + "fts5: %s queries are not supported (detail!=full)", |
| 173640 | + pNear->nPhrase==1 ? "phrase": "NEAR" |
| 173641 | + ); |
| 173642 | + sqlite3_free(pRet); |
| 173643 | + pRet = 0; |
| 173121 | 173644 | } |
| 173122 | 173645 | }else{ |
| 173123 | 173646 | fts5ExprAddChildren(pRet, pLeft); |
| 173124 | 173647 | fts5ExprAddChildren(pRet, pRight); |
| 173125 | 173648 | } |
| | @@ -173229,10 +173752,13 @@ |
| 173229 | 173752 | |
| 173230 | 173753 | zRet = fts5PrintfAppend(zRet, " {"); |
| 173231 | 173754 | for(iTerm=0; zRet && iTerm<pPhrase->nTerm; iTerm++){ |
| 173232 | 173755 | char *zTerm = pPhrase->aTerm[iTerm].zTerm; |
| 173233 | 173756 | zRet = fts5PrintfAppend(zRet, "%s%s", iTerm==0?"":" ", zTerm); |
| 173757 | + if( pPhrase->aTerm[iTerm].bPrefix ){ |
| 173758 | + zRet = fts5PrintfAppend(zRet, "*"); |
| 173759 | + } |
| 173234 | 173760 | } |
| 173235 | 173761 | |
| 173236 | 173762 | if( zRet ) zRet = fts5PrintfAppend(zRet, "}"); |
| 173237 | 173763 | if( zRet==0 ) return 0; |
| 173238 | 173764 | } |
| | @@ -173541,10 +174067,232 @@ |
| 173541 | 174067 | *pa = 0; |
| 173542 | 174068 | nRet = 0; |
| 173543 | 174069 | } |
| 173544 | 174070 | return nRet; |
| 173545 | 174071 | } |
| 174072 | + |
| 174073 | +struct Fts5PoslistPopulator { |
| 174074 | + Fts5PoslistWriter writer; |
| 174075 | + int bOk; /* True if ok to populate */ |
| 174076 | + int bMiss; |
| 174077 | +}; |
| 174078 | + |
| 174079 | +static Fts5PoslistPopulator *sqlite3Fts5ExprClearPoslists(Fts5Expr *pExpr, int bLive){ |
| 174080 | + Fts5PoslistPopulator *pRet; |
| 174081 | + pRet = sqlite3_malloc(sizeof(Fts5PoslistPopulator)*pExpr->nPhrase); |
| 174082 | + if( pRet ){ |
| 174083 | + int i; |
| 174084 | + memset(pRet, 0, sizeof(Fts5PoslistPopulator)*pExpr->nPhrase); |
| 174085 | + for(i=0; i<pExpr->nPhrase; i++){ |
| 174086 | + Fts5Buffer *pBuf = &pExpr->apExprPhrase[i]->poslist; |
| 174087 | + Fts5ExprNode *pNode = pExpr->apExprPhrase[i]->pNode; |
| 174088 | + assert( pExpr->apExprPhrase[i]->nTerm==1 ); |
| 174089 | + if( bLive && |
| 174090 | + (pBuf->n==0 || pNode->iRowid!=pExpr->pRoot->iRowid || pNode->bEof) |
| 174091 | + ){ |
| 174092 | + pRet[i].bMiss = 1; |
| 174093 | + }else{ |
| 174094 | + pBuf->n = 0; |
| 174095 | + } |
| 174096 | + } |
| 174097 | + } |
| 174098 | + return pRet; |
| 174099 | +} |
| 174100 | + |
| 174101 | +struct Fts5ExprCtx { |
| 174102 | + Fts5Expr *pExpr; |
| 174103 | + Fts5PoslistPopulator *aPopulator; |
| 174104 | + i64 iOff; |
| 174105 | +}; |
| 174106 | +typedef struct Fts5ExprCtx Fts5ExprCtx; |
| 174107 | + |
| 174108 | +/* |
| 174109 | +** TODO: Make this more efficient! |
| 174110 | +*/ |
| 174111 | +static int fts5ExprColsetTest(Fts5Colset *pColset, int iCol){ |
| 174112 | + int i; |
| 174113 | + for(i=0; i<pColset->nCol; i++){ |
| 174114 | + if( pColset->aiCol[i]==iCol ) return 1; |
| 174115 | + } |
| 174116 | + return 0; |
| 174117 | +} |
| 174118 | + |
| 174119 | +static int fts5ExprPopulatePoslistsCb( |
| 174120 | + void *pCtx, /* Copy of 2nd argument to xTokenize() */ |
| 174121 | + int tflags, /* Mask of FTS5_TOKEN_* flags */ |
| 174122 | + const char *pToken, /* Pointer to buffer containing token */ |
| 174123 | + int nToken, /* Size of token in bytes */ |
| 174124 | + int iStart, /* Byte offset of token within input text */ |
| 174125 | + int iEnd /* Byte offset of end of token within input text */ |
| 174126 | +){ |
| 174127 | + Fts5ExprCtx *p = (Fts5ExprCtx*)pCtx; |
| 174128 | + Fts5Expr *pExpr = p->pExpr; |
| 174129 | + int i; |
| 174130 | + |
| 174131 | + if( (tflags & FTS5_TOKEN_COLOCATED)==0 ) p->iOff++; |
| 174132 | + for(i=0; i<pExpr->nPhrase; i++){ |
| 174133 | + Fts5ExprTerm *pTerm; |
| 174134 | + if( p->aPopulator[i].bOk==0 ) continue; |
| 174135 | + for(pTerm=&pExpr->apExprPhrase[i]->aTerm[0]; pTerm; pTerm=pTerm->pSynonym){ |
| 174136 | + int nTerm = strlen(pTerm->zTerm); |
| 174137 | + if( (nTerm==nToken || (nTerm<nToken && pTerm->bPrefix)) |
| 174138 | + && memcmp(pTerm->zTerm, pToken, nTerm)==0 |
| 174139 | + ){ |
| 174140 | + int rc = sqlite3Fts5PoslistWriterAppend( |
| 174141 | + &pExpr->apExprPhrase[i]->poslist, &p->aPopulator[i].writer, p->iOff |
| 174142 | + ); |
| 174143 | + if( rc ) return rc; |
| 174144 | + break; |
| 174145 | + } |
| 174146 | + } |
| 174147 | + } |
| 174148 | + return SQLITE_OK; |
| 174149 | +} |
| 174150 | + |
| 174151 | +static int sqlite3Fts5ExprPopulatePoslists( |
| 174152 | + Fts5Config *pConfig, |
| 174153 | + Fts5Expr *pExpr, |
| 174154 | + Fts5PoslistPopulator *aPopulator, |
| 174155 | + int iCol, |
| 174156 | + const char *z, int n |
| 174157 | +){ |
| 174158 | + int i; |
| 174159 | + Fts5ExprCtx sCtx; |
| 174160 | + sCtx.pExpr = pExpr; |
| 174161 | + sCtx.aPopulator = aPopulator; |
| 174162 | + sCtx.iOff = (((i64)iCol) << 32) - 1; |
| 174163 | + |
| 174164 | + for(i=0; i<pExpr->nPhrase; i++){ |
| 174165 | + Fts5ExprNode *pNode = pExpr->apExprPhrase[i]->pNode; |
| 174166 | + Fts5Colset *pColset = pNode->pNear->pColset; |
| 174167 | + if( (pColset && 0==fts5ExprColsetTest(pColset, iCol)) |
| 174168 | + || aPopulator[i].bMiss |
| 174169 | + ){ |
| 174170 | + aPopulator[i].bOk = 0; |
| 174171 | + }else{ |
| 174172 | + aPopulator[i].bOk = 1; |
| 174173 | + } |
| 174174 | + } |
| 174175 | + |
| 174176 | + return sqlite3Fts5Tokenize(pConfig, |
| 174177 | + FTS5_TOKENIZE_DOCUMENT, z, n, (void*)&sCtx, fts5ExprPopulatePoslistsCb |
| 174178 | + ); |
| 174179 | +} |
| 174180 | + |
| 174181 | +static void fts5ExprClearPoslists(Fts5ExprNode *pNode){ |
| 174182 | + if( pNode->eType==FTS5_TERM || pNode->eType==FTS5_STRING ){ |
| 174183 | + pNode->pNear->apPhrase[0]->poslist.n = 0; |
| 174184 | + }else{ |
| 174185 | + int i; |
| 174186 | + for(i=0; i<pNode->nChild; i++){ |
| 174187 | + fts5ExprClearPoslists(pNode->apChild[i]); |
| 174188 | + } |
| 174189 | + } |
| 174190 | +} |
| 174191 | + |
| 174192 | +static int fts5ExprCheckPoslists(Fts5ExprNode *pNode, i64 iRowid){ |
| 174193 | + pNode->iRowid = iRowid; |
| 174194 | + pNode->bEof = 0; |
| 174195 | + switch( pNode->eType ){ |
| 174196 | + case FTS5_TERM: |
| 174197 | + case FTS5_STRING: |
| 174198 | + return (pNode->pNear->apPhrase[0]->poslist.n>0); |
| 174199 | + |
| 174200 | + case FTS5_AND: { |
| 174201 | + int i; |
| 174202 | + for(i=0; i<pNode->nChild; i++){ |
| 174203 | + if( fts5ExprCheckPoslists(pNode->apChild[i], iRowid)==0 ){ |
| 174204 | + fts5ExprClearPoslists(pNode); |
| 174205 | + return 0; |
| 174206 | + } |
| 174207 | + } |
| 174208 | + break; |
| 174209 | + } |
| 174210 | + |
| 174211 | + case FTS5_OR: { |
| 174212 | + int i; |
| 174213 | + int bRet = 0; |
| 174214 | + for(i=0; i<pNode->nChild; i++){ |
| 174215 | + if( fts5ExprCheckPoslists(pNode->apChild[i], iRowid) ){ |
| 174216 | + bRet = 1; |
| 174217 | + } |
| 174218 | + } |
| 174219 | + return bRet; |
| 174220 | + } |
| 174221 | + |
| 174222 | + default: { |
| 174223 | + assert( pNode->eType==FTS5_NOT ); |
| 174224 | + if( 0==fts5ExprCheckPoslists(pNode->apChild[0], iRowid) |
| 174225 | + || 0!=fts5ExprCheckPoslists(pNode->apChild[1], iRowid) |
| 174226 | + ){ |
| 174227 | + fts5ExprClearPoslists(pNode); |
| 174228 | + return 0; |
| 174229 | + } |
| 174230 | + break; |
| 174231 | + } |
| 174232 | + } |
| 174233 | + return 1; |
| 174234 | +} |
| 174235 | + |
| 174236 | +static void sqlite3Fts5ExprCheckPoslists(Fts5Expr *pExpr, i64 iRowid){ |
| 174237 | + fts5ExprCheckPoslists(pExpr->pRoot, iRowid); |
| 174238 | +} |
| 174239 | + |
| 174240 | +static void fts5ExprClearEof(Fts5ExprNode *pNode){ |
| 174241 | + int i; |
| 174242 | + for(i=0; i<pNode->nChild; i++){ |
| 174243 | + fts5ExprClearEof(pNode->apChild[i]); |
| 174244 | + } |
| 174245 | + pNode->bEof = 0; |
| 174246 | +} |
| 174247 | +static void sqlite3Fts5ExprClearEof(Fts5Expr *pExpr){ |
| 174248 | + fts5ExprClearEof(pExpr->pRoot); |
| 174249 | +} |
| 174250 | + |
| 174251 | +/* |
| 174252 | +** This function is only called for detail=columns tables. |
| 174253 | +*/ |
| 174254 | +static int sqlite3Fts5ExprPhraseCollist( |
| 174255 | + Fts5Expr *pExpr, |
| 174256 | + int iPhrase, |
| 174257 | + const u8 **ppCollist, |
| 174258 | + int *pnCollist |
| 174259 | +){ |
| 174260 | + Fts5ExprPhrase *pPhrase = pExpr->apExprPhrase[iPhrase]; |
| 174261 | + Fts5ExprNode *pNode = pPhrase->pNode; |
| 174262 | + int rc = SQLITE_OK; |
| 174263 | + |
| 174264 | + assert( iPhrase>=0 && iPhrase<pExpr->nPhrase ); |
| 174265 | + if( pNode->bEof==0 |
| 174266 | + && pNode->iRowid==pExpr->pRoot->iRowid |
| 174267 | + && pPhrase->poslist.n>0 |
| 174268 | + ){ |
| 174269 | + Fts5ExprTerm *pTerm = &pPhrase->aTerm[0]; |
| 174270 | + if( pTerm->pSynonym ){ |
| 174271 | + int bDel = 0; |
| 174272 | + u8 *a; |
| 174273 | + rc = fts5ExprSynonymList( |
| 174274 | + pTerm, 1, 0, pNode->iRowid, &bDel, &a, pnCollist |
| 174275 | + ); |
| 174276 | + if( bDel ){ |
| 174277 | + sqlite3Fts5BufferSet(&rc, &pPhrase->poslist, *pnCollist, a); |
| 174278 | + *ppCollist = pPhrase->poslist.p; |
| 174279 | + sqlite3_free(a); |
| 174280 | + }else{ |
| 174281 | + *ppCollist = a; |
| 174282 | + } |
| 174283 | + }else{ |
| 174284 | + sqlite3Fts5IterCollist(pPhrase->aTerm[0].pIter, ppCollist, pnCollist); |
| 174285 | + } |
| 174286 | + }else{ |
| 174287 | + *ppCollist = 0; |
| 174288 | + *pnCollist = 0; |
| 174289 | + } |
| 174290 | + |
| 174291 | + return rc; |
| 174292 | +} |
| 174293 | + |
| 173546 | 174294 | |
| 173547 | 174295 | /* |
| 173548 | 174296 | ** 2014 August 11 |
| 173549 | 174297 | ** |
| 173550 | 174298 | ** The author disclaims copyright to this source code. In place of |
| | @@ -173570,10 +174318,11 @@ |
| 173570 | 174318 | ** segment. |
| 173571 | 174319 | */ |
| 173572 | 174320 | |
| 173573 | 174321 | |
| 173574 | 174322 | struct Fts5Hash { |
| 174323 | + int eDetail; /* Copy of Fts5Config.eDetail */ |
| 173575 | 174324 | int *pnByte; /* Pointer to bytes counter */ |
| 173576 | 174325 | int nEntry; /* Number of entries currently in hash */ |
| 173577 | 174326 | int nSlot; /* Size of aSlot[] array */ |
| 173578 | 174327 | Fts5HashEntry *pScan; /* Current ordered scan item */ |
| 173579 | 174328 | Fts5HashEntry **aSlot; /* Array of hash slots */ |
| | @@ -173606,10 +174355,11 @@ |
| 173606 | 174355 | |
| 173607 | 174356 | int nAlloc; /* Total size of allocation */ |
| 173608 | 174357 | int iSzPoslist; /* Offset of space for 4-byte poslist size */ |
| 173609 | 174358 | int nData; /* Total bytes of data (incl. structure) */ |
| 173610 | 174359 | u8 bDel; /* Set delete-flag @ iSzPoslist */ |
| 174360 | + u8 bContent; /* Set content-flag (detail=none mode) */ |
| 173611 | 174361 | |
| 173612 | 174362 | int iCol; /* Column of last value written */ |
| 173613 | 174363 | int iPos; /* Position of last value written */ |
| 173614 | 174364 | i64 iRowid; /* Rowid of last value written */ |
| 173615 | 174365 | char zKey[8]; /* Nul-terminated entry key */ |
| | @@ -173623,11 +174373,11 @@ |
| 173623 | 174373 | |
| 173624 | 174374 | |
| 173625 | 174375 | /* |
| 173626 | 174376 | ** Allocate a new hash table. |
| 173627 | 174377 | */ |
| 173628 | | -static int sqlite3Fts5HashNew(Fts5Hash **ppNew, int *pnByte){ |
| 174378 | +static int sqlite3Fts5HashNew(Fts5Config *pConfig, Fts5Hash **ppNew, int *pnByte){ |
| 173629 | 174379 | int rc = SQLITE_OK; |
| 173630 | 174380 | Fts5Hash *pNew; |
| 173631 | 174381 | |
| 173632 | 174382 | *ppNew = pNew = (Fts5Hash*)sqlite3_malloc(sizeof(Fts5Hash)); |
| 173633 | 174383 | if( pNew==0 ){ |
| | @@ -173634,10 +174384,11 @@ |
| 173634 | 174384 | rc = SQLITE_NOMEM; |
| 173635 | 174385 | }else{ |
| 173636 | 174386 | int nByte; |
| 173637 | 174387 | memset(pNew, 0, sizeof(Fts5Hash)); |
| 173638 | 174388 | pNew->pnByte = pnByte; |
| 174389 | + pNew->eDetail = pConfig->eDetail; |
| 173639 | 174390 | |
| 173640 | 174391 | pNew->nSlot = 1024; |
| 173641 | 174392 | nByte = sizeof(Fts5HashEntry*) * pNew->nSlot; |
| 173642 | 174393 | pNew->aSlot = (Fts5HashEntry**)sqlite3_malloc(nByte); |
| 173643 | 174394 | if( pNew->aSlot==0 ){ |
| | @@ -173726,30 +174477,50 @@ |
| 173726 | 174477 | pHash->nSlot = nNew; |
| 173727 | 174478 | pHash->aSlot = apNew; |
| 173728 | 174479 | return SQLITE_OK; |
| 173729 | 174480 | } |
| 173730 | 174481 | |
| 173731 | | -static void fts5HashAddPoslistSize(Fts5HashEntry *p){ |
| 174482 | +static void fts5HashAddPoslistSize(Fts5Hash *pHash, Fts5HashEntry *p){ |
| 173732 | 174483 | if( p->iSzPoslist ){ |
| 173733 | 174484 | u8 *pPtr = (u8*)p; |
| 173734 | | - int nSz = (p->nData - p->iSzPoslist - 1); /* Size in bytes */ |
| 173735 | | - int nPos = nSz*2 + p->bDel; /* Value of nPos field */ |
| 173736 | | - |
| 173737 | | - assert( p->bDel==0 || p->bDel==1 ); |
| 173738 | | - if( nPos<=127 ){ |
| 173739 | | - pPtr[p->iSzPoslist] = (u8)nPos; |
| 173740 | | - }else{ |
| 173741 | | - int nByte = sqlite3Fts5GetVarintLen((u32)nPos); |
| 173742 | | - memmove(&pPtr[p->iSzPoslist + nByte], &pPtr[p->iSzPoslist + 1], nSz); |
| 173743 | | - sqlite3Fts5PutVarint(&pPtr[p->iSzPoslist], nPos); |
| 173744 | | - p->nData += (nByte-1); |
| 173745 | | - } |
| 173746 | | - p->bDel = 0; |
| 174485 | + if( pHash->eDetail==FTS5_DETAIL_NONE ){ |
| 174486 | + assert( p->nData==p->iSzPoslist ); |
| 174487 | + if( p->bDel ){ |
| 174488 | + pPtr[p->nData++] = 0x00; |
| 174489 | + if( p->bContent ){ |
| 174490 | + pPtr[p->nData++] = 0x00; |
| 174491 | + } |
| 174492 | + } |
| 174493 | + }else{ |
| 174494 | + int nSz = (p->nData - p->iSzPoslist - 1); /* Size in bytes */ |
| 174495 | + int nPos = nSz*2 + p->bDel; /* Value of nPos field */ |
| 174496 | + |
| 174497 | + assert( p->bDel==0 || p->bDel==1 ); |
| 174498 | + if( nPos<=127 ){ |
| 174499 | + pPtr[p->iSzPoslist] = (u8)nPos; |
| 174500 | + }else{ |
| 174501 | + int nByte = sqlite3Fts5GetVarintLen((u32)nPos); |
| 174502 | + memmove(&pPtr[p->iSzPoslist + nByte], &pPtr[p->iSzPoslist + 1], nSz); |
| 174503 | + sqlite3Fts5PutVarint(&pPtr[p->iSzPoslist], nPos); |
| 174504 | + p->nData += (nByte-1); |
| 174505 | + } |
| 174506 | + } |
| 174507 | + |
| 173747 | 174508 | p->iSzPoslist = 0; |
| 174509 | + p->bDel = 0; |
| 174510 | + p->bContent = 0; |
| 173748 | 174511 | } |
| 173749 | 174512 | } |
| 173750 | 174513 | |
| 174514 | +/* |
| 174515 | +** Add an entry to the in-memory hash table. The key is the concatenation |
| 174516 | +** of bByte and (pToken/nToken). The value is (iRowid/iCol/iPos). |
| 174517 | +** |
| 174518 | +** (bByte || pToken) -> (iRowid,iCol,iPos) |
| 174519 | +** |
| 174520 | +** Or, if iCol is negative, then the value is a delete marker. |
| 174521 | +*/ |
| 173751 | 174522 | static int sqlite3Fts5HashWrite( |
| 173752 | 174523 | Fts5Hash *pHash, |
| 173753 | 174524 | i64 iRowid, /* Rowid for this entry */ |
| 173754 | 174525 | int iCol, /* Column token appears in (-ve -> delete) */ |
| 173755 | 174526 | int iPos, /* Position of token within column */ |
| | @@ -173758,10 +174529,13 @@ |
| 173758 | 174529 | ){ |
| 173759 | 174530 | unsigned int iHash; |
| 173760 | 174531 | Fts5HashEntry *p; |
| 173761 | 174532 | u8 *pPtr; |
| 173762 | 174533 | int nIncr = 0; /* Amount to increment (*pHash->pnByte) by */ |
| 174534 | + int bNew; /* If non-delete entry should be written */ |
| 174535 | + |
| 174536 | + bNew = (pHash->eDetail==FTS5_DETAIL_FULL); |
| 173763 | 174537 | |
| 173764 | 174538 | /* Attempt to locate an existing hash entry */ |
| 173765 | 174539 | iHash = fts5HashKey2(pHash->nSlot, (u8)bByte, (const u8*)pToken, nToken); |
| 173766 | 174540 | for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){ |
| 173767 | 174541 | if( p->zKey[0]==bByte |
| | @@ -173772,92 +174546,120 @@ |
| 173772 | 174546 | } |
| 173773 | 174547 | } |
| 173774 | 174548 | |
| 173775 | 174549 | /* If an existing hash entry cannot be found, create a new one. */ |
| 173776 | 174550 | if( p==0 ){ |
| 174551 | + /* Figure out how much space to allocate */ |
| 173777 | 174552 | int nByte = FTS5_HASHENTRYSIZE + (nToken+1) + 1 + 64; |
| 173778 | 174553 | if( nByte<128 ) nByte = 128; |
| 173779 | 174554 | |
| 174555 | + /* Grow the Fts5Hash.aSlot[] array if necessary. */ |
| 173780 | 174556 | if( (pHash->nEntry*2)>=pHash->nSlot ){ |
| 173781 | 174557 | int rc = fts5HashResize(pHash); |
| 173782 | 174558 | if( rc!=SQLITE_OK ) return rc; |
| 173783 | 174559 | iHash = fts5HashKey2(pHash->nSlot, (u8)bByte, (const u8*)pToken, nToken); |
| 173784 | 174560 | } |
| 173785 | 174561 | |
| 174562 | + /* Allocate new Fts5HashEntry and add it to the hash table. */ |
| 173786 | 174563 | p = (Fts5HashEntry*)sqlite3_malloc(nByte); |
| 173787 | 174564 | if( !p ) return SQLITE_NOMEM; |
| 173788 | 174565 | memset(p, 0, FTS5_HASHENTRYSIZE); |
| 173789 | 174566 | p->nAlloc = nByte; |
| 173790 | 174567 | p->zKey[0] = bByte; |
| 173791 | 174568 | memcpy(&p->zKey[1], pToken, nToken); |
| 173792 | 174569 | assert( iHash==fts5HashKey(pHash->nSlot, (u8*)p->zKey, nToken+1) ); |
| 173793 | 174570 | p->zKey[nToken+1] = '\0'; |
| 173794 | 174571 | p->nData = nToken+1 + 1 + FTS5_HASHENTRYSIZE; |
| 173795 | | - p->nData += sqlite3Fts5PutVarint(&((u8*)p)[p->nData], iRowid); |
| 173796 | | - p->iSzPoslist = p->nData; |
| 173797 | | - p->nData += 1; |
| 173798 | | - p->iRowid = iRowid; |
| 173799 | 174572 | p->pHashNext = pHash->aSlot[iHash]; |
| 173800 | 174573 | pHash->aSlot[iHash] = p; |
| 173801 | 174574 | pHash->nEntry++; |
| 174575 | + |
| 174576 | + /* Add the first rowid field to the hash-entry */ |
| 174577 | + p->nData += sqlite3Fts5PutVarint(&((u8*)p)[p->nData], iRowid); |
| 174578 | + p->iRowid = iRowid; |
| 174579 | + |
| 174580 | + p->iSzPoslist = p->nData; |
| 174581 | + if( pHash->eDetail!=FTS5_DETAIL_NONE ){ |
| 174582 | + p->nData += 1; |
| 174583 | + p->iCol = (pHash->eDetail==FTS5_DETAIL_FULL ? 0 : -1); |
| 174584 | + } |
| 174585 | + |
| 173802 | 174586 | nIncr += p->nData; |
| 173803 | | - } |
| 173804 | | - |
| 173805 | | - /* Check there is enough space to append a new entry. Worst case scenario |
| 173806 | | - ** is: |
| 173807 | | - ** |
| 173808 | | - ** + 9 bytes for a new rowid, |
| 173809 | | - ** + 4 byte reserved for the "poslist size" varint. |
| 173810 | | - ** + 1 byte for a "new column" byte, |
| 173811 | | - ** + 3 bytes for a new column number (16-bit max) as a varint, |
| 173812 | | - ** + 5 bytes for the new position offset (32-bit max). |
| 173813 | | - */ |
| 173814 | | - if( (p->nAlloc - p->nData) < (9 + 4 + 1 + 3 + 5) ){ |
| 173815 | | - int nNew = p->nAlloc * 2; |
| 173816 | | - Fts5HashEntry *pNew; |
| 173817 | | - Fts5HashEntry **pp; |
| 173818 | | - pNew = (Fts5HashEntry*)sqlite3_realloc(p, nNew); |
| 173819 | | - if( pNew==0 ) return SQLITE_NOMEM; |
| 173820 | | - pNew->nAlloc = nNew; |
| 173821 | | - for(pp=&pHash->aSlot[iHash]; *pp!=p; pp=&(*pp)->pHashNext); |
| 173822 | | - *pp = pNew; |
| 173823 | | - p = pNew; |
| 173824 | | - } |
| 173825 | | - pPtr = (u8*)p; |
| 173826 | | - nIncr -= p->nData; |
| 174587 | + }else{ |
| 174588 | + |
| 174589 | + /* Appending to an existing hash-entry. Check that there is enough |
| 174590 | + ** space to append the largest possible new entry. Worst case scenario |
| 174591 | + ** is: |
| 174592 | + ** |
| 174593 | + ** + 9 bytes for a new rowid, |
| 174594 | + ** + 4 byte reserved for the "poslist size" varint. |
| 174595 | + ** + 1 byte for a "new column" byte, |
| 174596 | + ** + 3 bytes for a new column number (16-bit max) as a varint, |
| 174597 | + ** + 5 bytes for the new position offset (32-bit max). |
| 174598 | + */ |
| 174599 | + if( (p->nAlloc - p->nData) < (9 + 4 + 1 + 3 + 5) ){ |
| 174600 | + int nNew = p->nAlloc * 2; |
| 174601 | + Fts5HashEntry *pNew; |
| 174602 | + Fts5HashEntry **pp; |
| 174603 | + pNew = (Fts5HashEntry*)sqlite3_realloc(p, nNew); |
| 174604 | + if( pNew==0 ) return SQLITE_NOMEM; |
| 174605 | + pNew->nAlloc = nNew; |
| 174606 | + for(pp=&pHash->aSlot[iHash]; *pp!=p; pp=&(*pp)->pHashNext); |
| 174607 | + *pp = pNew; |
| 174608 | + p = pNew; |
| 174609 | + } |
| 174610 | + nIncr -= p->nData; |
| 174611 | + } |
| 174612 | + assert( (p->nAlloc - p->nData) >= (9 + 4 + 1 + 3 + 5) ); |
| 174613 | + |
| 174614 | + pPtr = (u8*)p; |
| 173827 | 174615 | |
| 173828 | 174616 | /* If this is a new rowid, append the 4-byte size field for the previous |
| 173829 | 174617 | ** entry, and the new rowid for this entry. */ |
| 173830 | 174618 | if( iRowid!=p->iRowid ){ |
| 173831 | | - fts5HashAddPoslistSize(p); |
| 174619 | + fts5HashAddPoslistSize(pHash, p); |
| 173832 | 174620 | p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iRowid - p->iRowid); |
| 174621 | + p->iRowid = iRowid; |
| 174622 | + bNew = 1; |
| 173833 | 174623 | p->iSzPoslist = p->nData; |
| 173834 | | - p->nData += 1; |
| 173835 | | - p->iCol = 0; |
| 173836 | | - p->iPos = 0; |
| 173837 | | - p->iRowid = iRowid; |
| 174624 | + if( pHash->eDetail!=FTS5_DETAIL_NONE ){ |
| 174625 | + p->nData += 1; |
| 174626 | + p->iCol = (pHash->eDetail==FTS5_DETAIL_FULL ? 0 : -1); |
| 174627 | + p->iPos = 0; |
| 174628 | + } |
| 173838 | 174629 | } |
| 173839 | 174630 | |
| 173840 | 174631 | if( iCol>=0 ){ |
| 173841 | | - /* Append a new column value, if necessary */ |
| 173842 | | - assert( iCol>=p->iCol ); |
| 173843 | | - if( iCol!=p->iCol ){ |
| 173844 | | - pPtr[p->nData++] = 0x01; |
| 173845 | | - p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iCol); |
| 173846 | | - p->iCol = iCol; |
| 173847 | | - p->iPos = 0; |
| 173848 | | - } |
| 173849 | | - |
| 173850 | | - /* Append the new position offset */ |
| 173851 | | - p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iPos - p->iPos + 2); |
| 173852 | | - p->iPos = iPos; |
| 174632 | + if( pHash->eDetail==FTS5_DETAIL_NONE ){ |
| 174633 | + p->bContent = 1; |
| 174634 | + }else{ |
| 174635 | + /* Append a new column value, if necessary */ |
| 174636 | + assert( iCol>=p->iCol ); |
| 174637 | + if( iCol!=p->iCol ){ |
| 174638 | + if( pHash->eDetail==FTS5_DETAIL_FULL ){ |
| 174639 | + pPtr[p->nData++] = 0x01; |
| 174640 | + p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iCol); |
| 174641 | + p->iCol = iCol; |
| 174642 | + p->iPos = 0; |
| 174643 | + }else{ |
| 174644 | + bNew = 1; |
| 174645 | + p->iCol = iPos = iCol; |
| 174646 | + } |
| 174647 | + } |
| 174648 | + |
| 174649 | + /* Append the new position offset, if necessary */ |
| 174650 | + if( bNew ){ |
| 174651 | + p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iPos - p->iPos + 2); |
| 174652 | + p->iPos = iPos; |
| 174653 | + } |
| 174654 | + } |
| 173853 | 174655 | }else{ |
| 173854 | 174656 | /* This is a delete. Set the delete flag. */ |
| 173855 | 174657 | p->bDel = 1; |
| 173856 | 174658 | } |
| 174659 | + |
| 173857 | 174660 | nIncr += p->nData; |
| 173858 | | - |
| 173859 | 174661 | *pHash->pnByte += nIncr; |
| 173860 | 174662 | return SQLITE_OK; |
| 173861 | 174663 | } |
| 173862 | 174664 | |
| 173863 | 174665 | |
| | @@ -173967,11 +174769,11 @@ |
| 173967 | 174769 | for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){ |
| 173968 | 174770 | if( memcmp(p->zKey, pTerm, nTerm)==0 && p->zKey[nTerm]==0 ) break; |
| 173969 | 174771 | } |
| 173970 | 174772 | |
| 173971 | 174773 | if( p ){ |
| 173972 | | - fts5HashAddPoslistSize(p); |
| 174774 | + fts5HashAddPoslistSize(pHash, p); |
| 173973 | 174775 | *ppDoclist = (const u8*)&p->zKey[nTerm+1]; |
| 173974 | 174776 | *pnDoclist = p->nData - (FTS5_HASHENTRYSIZE + nTerm + 1); |
| 173975 | 174777 | }else{ |
| 173976 | 174778 | *ppDoclist = 0; |
| 173977 | 174779 | *pnDoclist = 0; |
| | @@ -174003,11 +174805,11 @@ |
| 174003 | 174805 | int *pnDoclist /* OUT: size of doclist in bytes */ |
| 174004 | 174806 | ){ |
| 174005 | 174807 | Fts5HashEntry *p; |
| 174006 | 174808 | if( (p = pHash->pScan) ){ |
| 174007 | 174809 | int nTerm = (int)strlen(p->zKey); |
| 174008 | | - fts5HashAddPoslistSize(p); |
| 174810 | + fts5HashAddPoslistSize(pHash, p); |
| 174009 | 174811 | *pzTerm = p->zKey; |
| 174010 | 174812 | *ppDoclist = (const u8*)&p->zKey[nTerm+1]; |
| 174011 | 174813 | *pnDoclist = p->nData - (FTS5_HASHENTRYSIZE + nTerm + 1); |
| 174012 | 174814 | }else{ |
| 174013 | 174815 | *pzTerm = 0; |
| | @@ -174450,10 +175252,13 @@ |
| 174450 | 175252 | int iLeafPgno; /* Current leaf page number */ |
| 174451 | 175253 | Fts5Data *pLeaf; /* Current leaf data */ |
| 174452 | 175254 | Fts5Data *pNextLeaf; /* Leaf page (iLeafPgno+1) */ |
| 174453 | 175255 | int iLeafOffset; /* Byte offset within current leaf */ |
| 174454 | 175256 | |
| 175257 | + /* Next method */ |
| 175258 | + void (*xNext)(Fts5Index*, Fts5SegIter*, int*); |
| 175259 | + |
| 174455 | 175260 | /* The page and offset from which the current term was read. The offset |
| 174456 | 175261 | ** is the offset of the first rowid in the current doclist. */ |
| 174457 | 175262 | int iTermLeafPgno; |
| 174458 | 175263 | int iTermLeafOffset; |
| 174459 | 175264 | |
| | @@ -174469,11 +175274,11 @@ |
| 174469 | 175274 | |
| 174470 | 175275 | /* Variables populated based on current entry. */ |
| 174471 | 175276 | Fts5Buffer term; /* Current term */ |
| 174472 | 175277 | i64 iRowid; /* Current rowid */ |
| 174473 | 175278 | int nPos; /* Number of bytes in current position list */ |
| 174474 | | - int bDel; /* True if the delete flag is set */ |
| 175279 | + u8 bDel; /* True if the delete flag is set */ |
| 174475 | 175280 | }; |
| 174476 | 175281 | |
| 174477 | 175282 | /* |
| 174478 | 175283 | ** Argument is a pointer to an Fts5Data structure that contains a |
| 174479 | 175284 | ** leaf page. |
| | @@ -174482,11 +175287,10 @@ |
| 174482 | 175287 | (x)->szLeaf==(x)->nn || (x)->szLeaf==fts5GetU16(&(x)->p[2]) \ |
| 174483 | 175288 | ) |
| 174484 | 175289 | |
| 174485 | 175290 | #define FTS5_SEGITER_ONETERM 0x01 |
| 174486 | 175291 | #define FTS5_SEGITER_REVERSE 0x02 |
| 174487 | | - |
| 174488 | 175292 | |
| 174489 | 175293 | /* |
| 174490 | 175294 | ** Argument is a pointer to an Fts5Data structure that contains a leaf |
| 174491 | 175295 | ** page. This macro evaluates to true if the leaf contains no terms, or |
| 174492 | 175296 | ** false if it contains at least one term. |
| | @@ -175509,17 +176313,33 @@ |
| 175509 | 176313 | ** position list content (if any). |
| 175510 | 176314 | */ |
| 175511 | 176315 | static void fts5SegIterLoadNPos(Fts5Index *p, Fts5SegIter *pIter){ |
| 175512 | 176316 | if( p->rc==SQLITE_OK ){ |
| 175513 | 176317 | int iOff = pIter->iLeafOffset; /* Offset to read at */ |
| 175514 | | - int nSz; |
| 175515 | 176318 | ASSERT_SZLEAF_OK(pIter->pLeaf); |
| 175516 | | - fts5FastGetVarint32(pIter->pLeaf->p, iOff, nSz); |
| 175517 | | - pIter->bDel = (nSz & 0x0001); |
| 175518 | | - pIter->nPos = nSz>>1; |
| 176319 | + if( p->pConfig->eDetail==FTS5_DETAIL_NONE ){ |
| 176320 | + int iEod = MIN(pIter->iEndofDoclist, pIter->pLeaf->szLeaf); |
| 176321 | + pIter->bDel = 0; |
| 176322 | + pIter->nPos = 1; |
| 176323 | + if( iOff<iEod && pIter->pLeaf->p[iOff]==0 ){ |
| 176324 | + pIter->bDel = 1; |
| 176325 | + iOff++; |
| 176326 | + if( iOff<iEod && pIter->pLeaf->p[iOff]==0 ){ |
| 176327 | + pIter->nPos = 1; |
| 176328 | + iOff++; |
| 176329 | + }else{ |
| 176330 | + pIter->nPos = 0; |
| 176331 | + } |
| 176332 | + } |
| 176333 | + }else{ |
| 176334 | + int nSz; |
| 176335 | + fts5FastGetVarint32(pIter->pLeaf->p, iOff, nSz); |
| 176336 | + pIter->bDel = (nSz & 0x0001); |
| 176337 | + pIter->nPos = nSz>>1; |
| 176338 | + assert_nc( pIter->nPos>=0 ); |
| 176339 | + } |
| 175519 | 176340 | pIter->iLeafOffset = iOff; |
| 175520 | | - assert_nc( pIter->nPos>=0 ); |
| 175521 | 176341 | } |
| 175522 | 176342 | } |
| 175523 | 176343 | |
| 175524 | 176344 | static void fts5SegIterLoadRowid(Fts5Index *p, Fts5SegIter *pIter){ |
| 175525 | 176345 | u8 *a = pIter->pLeaf->p; /* Buffer to read data from */ |
| | @@ -175575,10 +176395,24 @@ |
| 175575 | 176395 | pIter->iEndofDoclist += nExtra; |
| 175576 | 176396 | } |
| 175577 | 176397 | |
| 175578 | 176398 | fts5SegIterLoadRowid(p, pIter); |
| 175579 | 176399 | } |
| 176400 | + |
| 176401 | +static void fts5SegIterNext(Fts5Index*, Fts5SegIter*, int*); |
| 176402 | +static void fts5SegIterNext_Reverse(Fts5Index*, Fts5SegIter*, int*); |
| 176403 | +static void fts5SegIterNext_None(Fts5Index*, Fts5SegIter*, int*); |
| 176404 | + |
| 176405 | +static void fts5SegIterSetNext(Fts5Index *p, Fts5SegIter *pIter){ |
| 176406 | + if( pIter->flags & FTS5_SEGITER_REVERSE ){ |
| 176407 | + pIter->xNext = fts5SegIterNext_Reverse; |
| 176408 | + }else if( p->pConfig->eDetail==FTS5_DETAIL_NONE ){ |
| 176409 | + pIter->xNext = fts5SegIterNext_None; |
| 176410 | + }else{ |
| 176411 | + pIter->xNext = fts5SegIterNext; |
| 176412 | + } |
| 176413 | +} |
| 175580 | 176414 | |
| 175581 | 176415 | /* |
| 175582 | 176416 | ** Initialize the iterator object pIter to iterate through the entries in |
| 175583 | 176417 | ** segment pSeg. The iterator is left pointing to the first entry when |
| 175584 | 176418 | ** this function returns. |
| | @@ -175601,10 +176435,11 @@ |
| 175601 | 176435 | return; |
| 175602 | 176436 | } |
| 175603 | 176437 | |
| 175604 | 176438 | if( p->rc==SQLITE_OK ){ |
| 175605 | 176439 | memset(pIter, 0, sizeof(*pIter)); |
| 176440 | + fts5SegIterSetNext(p, pIter); |
| 175606 | 176441 | pIter->pSeg = pSeg; |
| 175607 | 176442 | pIter->iLeafPgno = pSeg->pgnoFirst-1; |
| 175608 | 176443 | fts5SegIterNextPage(p, pIter); |
| 175609 | 176444 | } |
| 175610 | 176445 | |
| | @@ -175632,10 +176467,11 @@ |
| 175632 | 176467 | ** aRowidOffset[] and iRowidOffset variables. At this point the iterator |
| 175633 | 176468 | ** is in its regular state - Fts5SegIter.iLeafOffset points to the first |
| 175634 | 176469 | ** byte of the position list content associated with said rowid. |
| 175635 | 176470 | */ |
| 175636 | 176471 | static void fts5SegIterReverseInitPage(Fts5Index *p, Fts5SegIter *pIter){ |
| 176472 | + int eDetail = p->pConfig->eDetail; |
| 175637 | 176473 | int n = pIter->pLeaf->szLeaf; |
| 175638 | 176474 | int i = pIter->iLeafOffset; |
| 175639 | 176475 | u8 *a = pIter->pLeaf->p; |
| 175640 | 176476 | int iRowidOffset = 0; |
| 175641 | 176477 | |
| | @@ -175644,19 +176480,28 @@ |
| 175644 | 176480 | } |
| 175645 | 176481 | |
| 175646 | 176482 | ASSERT_SZLEAF_OK(pIter->pLeaf); |
| 175647 | 176483 | while( 1 ){ |
| 175648 | 176484 | i64 iDelta = 0; |
| 175649 | | - int nPos; |
| 175650 | | - int bDummy; |
| 175651 | 176485 | |
| 175652 | | - i += fts5GetPoslistSize(&a[i], &nPos, &bDummy); |
| 175653 | | - i += nPos; |
| 176486 | + if( eDetail==FTS5_DETAIL_NONE ){ |
| 176487 | + /* todo */ |
| 176488 | + if( i<n && a[i]==0 ){ |
| 176489 | + i++; |
| 176490 | + if( i<n && a[i]==0 ) i++; |
| 176491 | + } |
| 176492 | + }else{ |
| 176493 | + int nPos; |
| 176494 | + int bDummy; |
| 176495 | + i += fts5GetPoslistSize(&a[i], &nPos, &bDummy); |
| 176496 | + i += nPos; |
| 176497 | + } |
| 175654 | 176498 | if( i>=n ) break; |
| 175655 | 176499 | i += fts5GetVarint(&a[i], (u64*)&iDelta); |
| 175656 | 176500 | pIter->iRowid += iDelta; |
| 175657 | 176501 | |
| 176502 | + /* If necessary, grow the pIter->aRowidOffset[] array. */ |
| 175658 | 176503 | if( iRowidOffset>=pIter->nRowidOffset ){ |
| 175659 | 176504 | int nNew = pIter->nRowidOffset + 8; |
| 175660 | 176505 | int *aNew = (int*)sqlite3_realloc(pIter->aRowidOffset, nNew*sizeof(int)); |
| 175661 | 176506 | if( aNew==0 ){ |
| 175662 | 176507 | p->rc = SQLITE_NOMEM; |
| | @@ -175730,10 +176575,112 @@ |
| 175730 | 176575 | */ |
| 175731 | 176576 | static int fts5MultiIterIsEmpty(Fts5Index *p, Fts5IndexIter *pIter){ |
| 175732 | 176577 | Fts5SegIter *pSeg = &pIter->aSeg[pIter->aFirst[1].iFirst]; |
| 175733 | 176578 | return (p->rc==SQLITE_OK && pSeg->pLeaf && pSeg->nPos==0); |
| 175734 | 176579 | } |
| 176580 | + |
| 176581 | +/* |
| 176582 | +** Advance iterator pIter to the next entry. |
| 176583 | +** |
| 176584 | +** This version of fts5SegIterNext() is only used by reverse iterators. |
| 176585 | +*/ |
| 176586 | +static void fts5SegIterNext_Reverse( |
| 176587 | + Fts5Index *p, /* FTS5 backend object */ |
| 176588 | + Fts5SegIter *pIter, /* Iterator to advance */ |
| 176589 | + int *pbNewTerm /* OUT: Set for new term */ |
| 176590 | +){ |
| 176591 | + assert( pIter->flags & FTS5_SEGITER_REVERSE ); |
| 176592 | + assert( pIter->pNextLeaf==0 ); |
| 176593 | + if( pIter->iRowidOffset>0 ){ |
| 176594 | + u8 *a = pIter->pLeaf->p; |
| 176595 | + int iOff; |
| 176596 | + i64 iDelta; |
| 176597 | + |
| 176598 | + pIter->iRowidOffset--; |
| 176599 | + pIter->iLeafOffset = pIter->aRowidOffset[pIter->iRowidOffset]; |
| 176600 | + fts5SegIterLoadNPos(p, pIter); |
| 176601 | + iOff = pIter->iLeafOffset; |
| 176602 | + if( p->pConfig->eDetail!=FTS5_DETAIL_NONE ){ |
| 176603 | + iOff += pIter->nPos; |
| 176604 | + } |
| 176605 | + fts5GetVarint(&a[iOff], (u64*)&iDelta); |
| 176606 | + pIter->iRowid -= iDelta; |
| 176607 | + }else{ |
| 176608 | + fts5SegIterReverseNewPage(p, pIter); |
| 176609 | + } |
| 176610 | +} |
| 176611 | + |
| 176612 | +/* |
| 176613 | +** Advance iterator pIter to the next entry. |
| 176614 | +** |
| 176615 | +** This version of fts5SegIterNext() is only used if detail=none and the |
| 176616 | +** iterator is not a reverse direction iterator. |
| 176617 | +*/ |
| 176618 | +static void fts5SegIterNext_None( |
| 176619 | + Fts5Index *p, /* FTS5 backend object */ |
| 176620 | + Fts5SegIter *pIter, /* Iterator to advance */ |
| 176621 | + int *pbNewTerm /* OUT: Set for new term */ |
| 176622 | +){ |
| 176623 | + int iOff; |
| 176624 | + |
| 176625 | + assert( p->rc==SQLITE_OK ); |
| 176626 | + assert( (pIter->flags & FTS5_SEGITER_REVERSE)==0 ); |
| 176627 | + assert( p->pConfig->eDetail==FTS5_DETAIL_NONE ); |
| 176628 | + |
| 176629 | + ASSERT_SZLEAF_OK(pIter->pLeaf); |
| 176630 | + iOff = pIter->iLeafOffset; |
| 176631 | + |
| 176632 | + /* Next entry is on the next page */ |
| 176633 | + if( pIter->pSeg && iOff>=pIter->pLeaf->szLeaf ){ |
| 176634 | + fts5SegIterNextPage(p, pIter); |
| 176635 | + if( p->rc || pIter->pLeaf==0 ) return; |
| 176636 | + pIter->iRowid = 0; |
| 176637 | + iOff = 4; |
| 176638 | + } |
| 176639 | + |
| 176640 | + if( iOff<pIter->iEndofDoclist ){ |
| 176641 | + /* Next entry is on the current page */ |
| 176642 | + i64 iDelta; |
| 176643 | + iOff += sqlite3Fts5GetVarint(&pIter->pLeaf->p[iOff], (u64*)&iDelta); |
| 176644 | + pIter->iLeafOffset = iOff; |
| 176645 | + pIter->iRowid += iDelta; |
| 176646 | + }else if( (pIter->flags & FTS5_SEGITER_ONETERM)==0 ){ |
| 176647 | + if( pIter->pSeg ){ |
| 176648 | + int nKeep = 0; |
| 176649 | + if( iOff!=fts5LeafFirstTermOff(pIter->pLeaf) ){ |
| 176650 | + iOff += fts5GetVarint32(&pIter->pLeaf->p[iOff], nKeep); |
| 176651 | + } |
| 176652 | + pIter->iLeafOffset = iOff; |
| 176653 | + fts5SegIterLoadTerm(p, pIter, nKeep); |
| 176654 | + }else{ |
| 176655 | + const u8 *pList = 0; |
| 176656 | + const char *zTerm = 0; |
| 176657 | + int nList; |
| 176658 | + sqlite3Fts5HashScanNext(p->pHash); |
| 176659 | + sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &pList, &nList); |
| 176660 | + if( pList==0 ) goto next_none_eof; |
| 176661 | + pIter->pLeaf->p = (u8*)pList; |
| 176662 | + pIter->pLeaf->nn = nList; |
| 176663 | + pIter->pLeaf->szLeaf = nList; |
| 176664 | + pIter->iEndofDoclist = nList; |
| 176665 | + sqlite3Fts5BufferSet(&p->rc,&pIter->term, (int)strlen(zTerm), (u8*)zTerm); |
| 176666 | + pIter->iLeafOffset = fts5GetVarint(pList, (u64*)&pIter->iRowid); |
| 176667 | + } |
| 176668 | + |
| 176669 | + if( pbNewTerm ) *pbNewTerm = 1; |
| 176670 | + }else{ |
| 176671 | + goto next_none_eof; |
| 176672 | + } |
| 176673 | + |
| 176674 | + fts5SegIterLoadNPos(p, pIter); |
| 176675 | + |
| 176676 | + return; |
| 176677 | + next_none_eof: |
| 176678 | + fts5DataRelease(pIter->pLeaf); |
| 176679 | + pIter->pLeaf = 0; |
| 176680 | +} |
| 176681 | + |
| 175735 | 176682 | |
| 175736 | 176683 | /* |
| 175737 | 176684 | ** Advance iterator pIter to the next entry. |
| 175738 | 176685 | ** |
| 175739 | 176686 | ** If an error occurs, Fts5Index.rc is set to an appropriate error code. It |
| | @@ -175743,144 +176690,135 @@ |
| 175743 | 176690 | static void fts5SegIterNext( |
| 175744 | 176691 | Fts5Index *p, /* FTS5 backend object */ |
| 175745 | 176692 | Fts5SegIter *pIter, /* Iterator to advance */ |
| 175746 | 176693 | int *pbNewTerm /* OUT: Set for new term */ |
| 175747 | 176694 | ){ |
| 175748 | | - assert( pbNewTerm==0 || *pbNewTerm==0 ); |
| 175749 | | - if( p->rc==SQLITE_OK ){ |
| 175750 | | - if( pIter->flags & FTS5_SEGITER_REVERSE ){ |
| 175751 | | - assert( pIter->pNextLeaf==0 ); |
| 175752 | | - if( pIter->iRowidOffset>0 ){ |
| 175753 | | - u8 *a = pIter->pLeaf->p; |
| 175754 | | - int iOff; |
| 175755 | | - int nPos; |
| 175756 | | - int bDummy; |
| 175757 | | - i64 iDelta; |
| 175758 | | - |
| 175759 | | - pIter->iRowidOffset--; |
| 175760 | | - pIter->iLeafOffset = iOff = pIter->aRowidOffset[pIter->iRowidOffset]; |
| 175761 | | - iOff += fts5GetPoslistSize(&a[iOff], &nPos, &bDummy); |
| 175762 | | - iOff += nPos; |
| 175763 | | - fts5GetVarint(&a[iOff], (u64*)&iDelta); |
| 175764 | | - pIter->iRowid -= iDelta; |
| 175765 | | - fts5SegIterLoadNPos(p, pIter); |
| 175766 | | - }else{ |
| 175767 | | - fts5SegIterReverseNewPage(p, pIter); |
| 175768 | | - } |
| 175769 | | - }else{ |
| 175770 | | - Fts5Data *pLeaf = pIter->pLeaf; |
| 175771 | | - int iOff; |
| 175772 | | - int bNewTerm = 0; |
| 175773 | | - int nKeep = 0; |
| 175774 | | - |
| 175775 | | - /* Search for the end of the position list within the current page. */ |
| 175776 | | - u8 *a = pLeaf->p; |
| 175777 | | - int n = pLeaf->szLeaf; |
| 175778 | | - |
| 175779 | | - ASSERT_SZLEAF_OK(pLeaf); |
| 175780 | | - iOff = pIter->iLeafOffset + pIter->nPos; |
| 175781 | | - |
| 175782 | | - if( iOff<n ){ |
| 175783 | | - /* The next entry is on the current page. */ |
| 175784 | | - assert_nc( iOff<=pIter->iEndofDoclist ); |
| 175785 | | - if( iOff>=pIter->iEndofDoclist ){ |
| 175786 | | - bNewTerm = 1; |
| 175787 | | - if( iOff!=fts5LeafFirstTermOff(pLeaf) ){ |
| 175788 | | - iOff += fts5GetVarint32(&a[iOff], nKeep); |
| 175789 | | - } |
| 175790 | | - }else{ |
| 175791 | | - u64 iDelta; |
| 175792 | | - iOff += sqlite3Fts5GetVarint(&a[iOff], &iDelta); |
| 175793 | | - pIter->iRowid += iDelta; |
| 175794 | | - assert_nc( iDelta>0 ); |
| 175795 | | - } |
| 175796 | | - pIter->iLeafOffset = iOff; |
| 175797 | | - |
| 175798 | | - }else if( pIter->pSeg==0 ){ |
| 175799 | | - const u8 *pList = 0; |
| 175800 | | - const char *zTerm = 0; |
| 175801 | | - int nList = 0; |
| 175802 | | - assert( (pIter->flags & FTS5_SEGITER_ONETERM) || pbNewTerm ); |
| 175803 | | - if( 0==(pIter->flags & FTS5_SEGITER_ONETERM) ){ |
| 175804 | | - sqlite3Fts5HashScanNext(p->pHash); |
| 175805 | | - sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &pList, &nList); |
| 175806 | | - } |
| 175807 | | - if( pList==0 ){ |
| 175808 | | - fts5DataRelease(pIter->pLeaf); |
| 175809 | | - pIter->pLeaf = 0; |
| 175810 | | - }else{ |
| 175811 | | - pIter->pLeaf->p = (u8*)pList; |
| 175812 | | - pIter->pLeaf->nn = nList; |
| 175813 | | - pIter->pLeaf->szLeaf = nList; |
| 175814 | | - pIter->iEndofDoclist = nList+1; |
| 175815 | | - sqlite3Fts5BufferSet(&p->rc, &pIter->term, (int)strlen(zTerm), |
| 175816 | | - (u8*)zTerm); |
| 175817 | | - pIter->iLeafOffset = fts5GetVarint(pList, (u64*)&pIter->iRowid); |
| 175818 | | - *pbNewTerm = 1; |
| 175819 | | - } |
| 175820 | | - }else{ |
| 175821 | | - iOff = 0; |
| 175822 | | - /* Next entry is not on the current page */ |
| 175823 | | - while( iOff==0 ){ |
| 175824 | | - fts5SegIterNextPage(p, pIter); |
| 175825 | | - pLeaf = pIter->pLeaf; |
| 175826 | | - if( pLeaf==0 ) break; |
| 175827 | | - ASSERT_SZLEAF_OK(pLeaf); |
| 175828 | | - if( (iOff = fts5LeafFirstRowidOff(pLeaf)) && iOff<pLeaf->szLeaf ){ |
| 175829 | | - iOff += sqlite3Fts5GetVarint(&pLeaf->p[iOff], (u64*)&pIter->iRowid); |
| 175830 | | - pIter->iLeafOffset = iOff; |
| 175831 | | - |
| 175832 | | - if( pLeaf->nn>pLeaf->szLeaf ){ |
| 175833 | | - pIter->iPgidxOff = pLeaf->szLeaf + fts5GetVarint32( |
| 175834 | | - &pLeaf->p[pLeaf->szLeaf], pIter->iEndofDoclist |
| 175835 | | - ); |
| 175836 | | - } |
| 175837 | | - |
| 175838 | | - } |
| 175839 | | - else if( pLeaf->nn>pLeaf->szLeaf ){ |
| 175840 | | - pIter->iPgidxOff = pLeaf->szLeaf + fts5GetVarint32( |
| 175841 | | - &pLeaf->p[pLeaf->szLeaf], iOff |
| 175842 | | - ); |
| 175843 | | - pIter->iLeafOffset = iOff; |
| 175844 | | - pIter->iEndofDoclist = iOff; |
| 175845 | | - bNewTerm = 1; |
| 175846 | | - } |
| 175847 | | - if( iOff>=pLeaf->szLeaf ){ |
| 175848 | | - p->rc = FTS5_CORRUPT; |
| 175849 | | - return; |
| 175850 | | - } |
| 175851 | | - } |
| 175852 | | - } |
| 175853 | | - |
| 175854 | | - /* Check if the iterator is now at EOF. If so, return early. */ |
| 175855 | | - if( pIter->pLeaf ){ |
| 175856 | | - if( bNewTerm ){ |
| 175857 | | - if( pIter->flags & FTS5_SEGITER_ONETERM ){ |
| 175858 | | - fts5DataRelease(pIter->pLeaf); |
| 175859 | | - pIter->pLeaf = 0; |
| 175860 | | - }else{ |
| 175861 | | - fts5SegIterLoadTerm(p, pIter, nKeep); |
| 175862 | | - fts5SegIterLoadNPos(p, pIter); |
| 175863 | | - if( pbNewTerm ) *pbNewTerm = 1; |
| 175864 | | - } |
| 175865 | | - }else{ |
| 175866 | | - /* The following could be done by calling fts5SegIterLoadNPos(). But |
| 175867 | | - ** this block is particularly performance critical, so equivalent |
| 175868 | | - ** code is inlined. */ |
| 175869 | | - int nSz; |
| 175870 | | - assert( p->rc==SQLITE_OK ); |
| 175871 | | - fts5FastGetVarint32(pIter->pLeaf->p, pIter->iLeafOffset, nSz); |
| 175872 | | - pIter->bDel = (nSz & 0x0001); |
| 175873 | | - pIter->nPos = nSz>>1; |
| 175874 | | - assert_nc( pIter->nPos>=0 ); |
| 175875 | | - } |
| 175876 | | - } |
| 176695 | + Fts5Data *pLeaf = pIter->pLeaf; |
| 176696 | + int iOff; |
| 176697 | + int bNewTerm = 0; |
| 176698 | + int nKeep = 0; |
| 176699 | + u8 *a; |
| 176700 | + int n; |
| 176701 | + |
| 176702 | + assert( pbNewTerm==0 || *pbNewTerm==0 ); |
| 176703 | + assert( p->pConfig->eDetail!=FTS5_DETAIL_NONE ); |
| 176704 | + |
| 176705 | + /* Search for the end of the position list within the current page. */ |
| 176706 | + a = pLeaf->p; |
| 176707 | + n = pLeaf->szLeaf; |
| 176708 | + |
| 176709 | + ASSERT_SZLEAF_OK(pLeaf); |
| 176710 | + iOff = pIter->iLeafOffset + pIter->nPos; |
| 176711 | + |
| 176712 | + if( iOff<n ){ |
| 176713 | + /* The next entry is on the current page. */ |
| 176714 | + assert_nc( iOff<=pIter->iEndofDoclist ); |
| 176715 | + if( iOff>=pIter->iEndofDoclist ){ |
| 176716 | + bNewTerm = 1; |
| 176717 | + if( iOff!=fts5LeafFirstTermOff(pLeaf) ){ |
| 176718 | + iOff += fts5GetVarint32(&a[iOff], nKeep); |
| 176719 | + } |
| 176720 | + }else{ |
| 176721 | + u64 iDelta; |
| 176722 | + iOff += sqlite3Fts5GetVarint(&a[iOff], &iDelta); |
| 176723 | + pIter->iRowid += iDelta; |
| 176724 | + assert_nc( iDelta>0 ); |
| 176725 | + } |
| 176726 | + pIter->iLeafOffset = iOff; |
| 176727 | + |
| 176728 | + }else if( pIter->pSeg==0 ){ |
| 176729 | + const u8 *pList = 0; |
| 176730 | + const char *zTerm = 0; |
| 176731 | + int nList = 0; |
| 176732 | + assert( (pIter->flags & FTS5_SEGITER_ONETERM) || pbNewTerm ); |
| 176733 | + if( 0==(pIter->flags & FTS5_SEGITER_ONETERM) ){ |
| 176734 | + sqlite3Fts5HashScanNext(p->pHash); |
| 176735 | + sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &pList, &nList); |
| 176736 | + } |
| 176737 | + if( pList==0 ){ |
| 176738 | + fts5DataRelease(pIter->pLeaf); |
| 176739 | + pIter->pLeaf = 0; |
| 176740 | + }else{ |
| 176741 | + pIter->pLeaf->p = (u8*)pList; |
| 176742 | + pIter->pLeaf->nn = nList; |
| 176743 | + pIter->pLeaf->szLeaf = nList; |
| 176744 | + pIter->iEndofDoclist = nList+1; |
| 176745 | + sqlite3Fts5BufferSet(&p->rc, &pIter->term, (int)strlen(zTerm), |
| 176746 | + (u8*)zTerm); |
| 176747 | + pIter->iLeafOffset = fts5GetVarint(pList, (u64*)&pIter->iRowid); |
| 176748 | + *pbNewTerm = 1; |
| 176749 | + } |
| 176750 | + }else{ |
| 176751 | + iOff = 0; |
| 176752 | + /* Next entry is not on the current page */ |
| 176753 | + while( iOff==0 ){ |
| 176754 | + fts5SegIterNextPage(p, pIter); |
| 176755 | + pLeaf = pIter->pLeaf; |
| 176756 | + if( pLeaf==0 ) break; |
| 176757 | + ASSERT_SZLEAF_OK(pLeaf); |
| 176758 | + if( (iOff = fts5LeafFirstRowidOff(pLeaf)) && iOff<pLeaf->szLeaf ){ |
| 176759 | + iOff += sqlite3Fts5GetVarint(&pLeaf->p[iOff], (u64*)&pIter->iRowid); |
| 176760 | + pIter->iLeafOffset = iOff; |
| 176761 | + |
| 176762 | + if( pLeaf->nn>pLeaf->szLeaf ){ |
| 176763 | + pIter->iPgidxOff = pLeaf->szLeaf + fts5GetVarint32( |
| 176764 | + &pLeaf->p[pLeaf->szLeaf], pIter->iEndofDoclist |
| 176765 | + ); |
| 176766 | + } |
| 176767 | + |
| 176768 | + } |
| 176769 | + else if( pLeaf->nn>pLeaf->szLeaf ){ |
| 176770 | + pIter->iPgidxOff = pLeaf->szLeaf + fts5GetVarint32( |
| 176771 | + &pLeaf->p[pLeaf->szLeaf], iOff |
| 176772 | + ); |
| 176773 | + pIter->iLeafOffset = iOff; |
| 176774 | + pIter->iEndofDoclist = iOff; |
| 176775 | + bNewTerm = 1; |
| 176776 | + } |
| 176777 | + assert_nc( iOff<pLeaf->szLeaf ); |
| 176778 | + if( iOff>pLeaf->szLeaf ){ |
| 176779 | + p->rc = FTS5_CORRUPT; |
| 176780 | + return; |
| 176781 | + } |
| 176782 | + } |
| 176783 | + } |
| 176784 | + |
| 176785 | + /* Check if the iterator is now at EOF. If so, return early. */ |
| 176786 | + if( pIter->pLeaf ){ |
| 176787 | + if( bNewTerm ){ |
| 176788 | + if( pIter->flags & FTS5_SEGITER_ONETERM ){ |
| 176789 | + fts5DataRelease(pIter->pLeaf); |
| 176790 | + pIter->pLeaf = 0; |
| 176791 | + }else{ |
| 176792 | + fts5SegIterLoadTerm(p, pIter, nKeep); |
| 176793 | + fts5SegIterLoadNPos(p, pIter); |
| 176794 | + if( pbNewTerm ) *pbNewTerm = 1; |
| 176795 | + } |
| 176796 | + }else{ |
| 176797 | + /* The following could be done by calling fts5SegIterLoadNPos(). But |
| 176798 | + ** this block is particularly performance critical, so equivalent |
| 176799 | + ** code is inlined. |
| 176800 | + ** |
| 176801 | + ** Later: Switched back to fts5SegIterLoadNPos() because it supports |
| 176802 | + ** detail=none mode. Not ideal. |
| 176803 | + */ |
| 176804 | + int nSz; |
| 176805 | + assert( p->rc==SQLITE_OK ); |
| 176806 | + fts5FastGetVarint32(pIter->pLeaf->p, pIter->iLeafOffset, nSz); |
| 176807 | + pIter->bDel = (nSz & 0x0001); |
| 176808 | + pIter->nPos = nSz>>1; |
| 176809 | + assert_nc( pIter->nPos>=0 ); |
| 175877 | 176810 | } |
| 175878 | 176811 | } |
| 175879 | 176812 | } |
| 175880 | 176813 | |
| 175881 | 176814 | #define SWAPVAL(T, a, b) { T tmp; tmp=a; a=b; b=tmp; } |
| 176815 | + |
| 176816 | +#define fts5IndexSkipVarint(a, iOff) { \ |
| 176817 | + int iEnd = iOff+9; \ |
| 176818 | + while( (a[iOff++] & 0x80) && iOff<iEnd ); \ |
| 176819 | +} |
| 175882 | 176820 | |
| 175883 | 176821 | /* |
| 175884 | 176822 | ** Iterator pIter currently points to the first rowid in a doclist. This |
| 175885 | 176823 | ** function sets the iterator up so that iterates in reverse order through |
| 175886 | 176824 | ** the doclist. |
| | @@ -175898,11 +176836,21 @@ |
| 175898 | 176836 | Fts5Data *pLeaf = pIter->pLeaf; /* Current leaf data */ |
| 175899 | 176837 | |
| 175900 | 176838 | /* Currently, Fts5SegIter.iLeafOffset points to the first byte of |
| 175901 | 176839 | ** position-list content for the current rowid. Back it up so that it |
| 175902 | 176840 | ** points to the start of the position-list size field. */ |
| 175903 | | - pIter->iLeafOffset -= sqlite3Fts5GetVarintLen(pIter->nPos*2+pIter->bDel); |
| 176841 | + int iPoslist; |
| 176842 | + if( pIter->iTermLeafPgno==pIter->iLeafPgno ){ |
| 176843 | + iPoslist = pIter->iTermLeafOffset; |
| 176844 | + }else{ |
| 176845 | + iPoslist = 4; |
| 176846 | + } |
| 176847 | + fts5IndexSkipVarint(pLeaf->p, iPoslist); |
| 176848 | + assert( p->pConfig->eDetail==FTS5_DETAIL_NONE || iPoslist==( |
| 176849 | + pIter->iLeafOffset - sqlite3Fts5GetVarintLen(pIter->nPos*2+pIter->bDel) |
| 176850 | + )); |
| 176851 | + pIter->iLeafOffset = iPoslist; |
| 175904 | 176852 | |
| 175905 | 176853 | /* If this condition is true then the largest rowid for the current |
| 175906 | 176854 | ** term may not be stored on the current page. So search forward to |
| 175907 | 176855 | ** see where said rowid really is. */ |
| 175908 | 176856 | if( pIter->iEndofDoclist>=pLeaf->szLeaf ){ |
| | @@ -175982,15 +176930,10 @@ |
| 175982 | 176930 | } |
| 175983 | 176931 | |
| 175984 | 176932 | pIter->pDlidx = fts5DlidxIterInit(p, bRev, iSeg, pIter->iTermLeafPgno); |
| 175985 | 176933 | } |
| 175986 | 176934 | |
| 175987 | | -#define fts5IndexSkipVarint(a, iOff) { \ |
| 175988 | | - int iEnd = iOff+9; \ |
| 175989 | | - while( (a[iOff++] & 0x80) && iOff<iEnd ); \ |
| 175990 | | -} |
| 175991 | | - |
| 175992 | 176935 | /* |
| 175993 | 176936 | ** The iterator object passed as the second argument currently contains |
| 175994 | 176937 | ** no valid values except for the Fts5SegIter.pLeaf member variable. This |
| 175995 | 176938 | ** function searches the leaf page for a term matching (pTerm/nTerm). |
| 175996 | 176939 | ** |
| | @@ -176189,10 +177132,12 @@ |
| 176189 | 177132 | fts5SegIterReverse(p, pIter); |
| 176190 | 177133 | } |
| 176191 | 177134 | } |
| 176192 | 177135 | } |
| 176193 | 177136 | |
| 177137 | + fts5SegIterSetNext(p, pIter); |
| 177138 | + |
| 176194 | 177139 | /* Either: |
| 176195 | 177140 | ** |
| 176196 | 177141 | ** 1) an error has occurred, or |
| 176197 | 177142 | ** 2) the iterator points to EOF, or |
| 176198 | 177143 | ** 3) the iterator points to an entry with term (pTerm/nTerm), or |
| | @@ -176246,19 +177191,21 @@ |
| 176246 | 177191 | if( pLeaf==0 ) return; |
| 176247 | 177192 | pLeaf->p = (u8*)pList; |
| 176248 | 177193 | pLeaf->nn = pLeaf->szLeaf = nList; |
| 176249 | 177194 | pIter->pLeaf = pLeaf; |
| 176250 | 177195 | pIter->iLeafOffset = fts5GetVarint(pLeaf->p, (u64*)&pIter->iRowid); |
| 176251 | | - pIter->iEndofDoclist = pLeaf->nn+1; |
| 177196 | + pIter->iEndofDoclist = pLeaf->nn; |
| 176252 | 177197 | |
| 176253 | 177198 | if( flags & FTS5INDEX_QUERY_DESC ){ |
| 176254 | 177199 | pIter->flags |= FTS5_SEGITER_REVERSE; |
| 176255 | 177200 | fts5SegIterReverseInitPage(p, pIter); |
| 176256 | 177201 | }else{ |
| 176257 | 177202 | fts5SegIterLoadNPos(p, pIter); |
| 176258 | 177203 | } |
| 176259 | 177204 | } |
| 177205 | + |
| 177206 | + fts5SegIterSetNext(p, pIter); |
| 176260 | 177207 | } |
| 176261 | 177208 | |
| 176262 | 177209 | /* |
| 176263 | 177210 | ** Zero the iterator passed as the only argument. |
| 176264 | 177211 | */ |
| | @@ -176498,11 +177445,11 @@ |
| 176498 | 177445 | bMove = 0; |
| 176499 | 177446 | } |
| 176500 | 177447 | } |
| 176501 | 177448 | |
| 176502 | 177449 | do{ |
| 176503 | | - if( bMove ) fts5SegIterNext(p, pIter, 0); |
| 177450 | + if( bMove && p->rc==SQLITE_OK ) pIter->xNext(p, pIter, 0); |
| 176504 | 177451 | if( pIter->pLeaf==0 ) break; |
| 176505 | 177452 | if( bRev==0 && pIter->iRowid>=iMatch ) break; |
| 176506 | 177453 | if( bRev!=0 && pIter->iRowid<=iMatch ) break; |
| 176507 | 177454 | bMove = 1; |
| 176508 | 177455 | }while( p->rc==SQLITE_OK ); |
| | @@ -176532,11 +177479,13 @@ |
| 176532 | 177479 | ){ |
| 176533 | 177480 | int i; |
| 176534 | 177481 | for(i=(pIter->nSeg+iChanged)/2; i>=iMinset && p->rc==SQLITE_OK; i=i/2){ |
| 176535 | 177482 | int iEq; |
| 176536 | 177483 | if( (iEq = fts5MultiIterDoCompare(pIter, i)) ){ |
| 176537 | | - fts5SegIterNext(p, &pIter->aSeg[iEq], 0); |
| 177484 | + Fts5SegIter *pSeg = &pIter->aSeg[iEq]; |
| 177485 | + assert( p->rc==SQLITE_OK ); |
| 177486 | + pSeg->xNext(p, pSeg, 0); |
| 176538 | 177487 | i = pIter->nSeg + iEq; |
| 176539 | 177488 | } |
| 176540 | 177489 | } |
| 176541 | 177490 | } |
| 176542 | 177491 | |
| | @@ -176619,11 +177568,11 @@ |
| 176619 | 177568 | Fts5SegIter *pSeg = &pIter->aSeg[iFirst]; |
| 176620 | 177569 | assert( p->rc==SQLITE_OK ); |
| 176621 | 177570 | if( bUseFrom && pSeg->pDlidx ){ |
| 176622 | 177571 | fts5SegIterNextFrom(p, pSeg, iFrom); |
| 176623 | 177572 | }else{ |
| 176624 | | - fts5SegIterNext(p, pSeg, &bNewTerm); |
| 177573 | + pSeg->xNext(p, pSeg, &bNewTerm); |
| 176625 | 177574 | } |
| 176626 | 177575 | |
| 176627 | 177576 | if( pSeg->pLeaf==0 || bNewTerm |
| 176628 | 177577 | || fts5MultiIterAdvanceRowid(p, pIter, iFirst) |
| 176629 | 177578 | ){ |
| | @@ -176647,11 +177596,12 @@ |
| 176647 | 177596 | do { |
| 176648 | 177597 | int iFirst = pIter->aFirst[1].iFirst; |
| 176649 | 177598 | Fts5SegIter *pSeg = &pIter->aSeg[iFirst]; |
| 176650 | 177599 | int bNewTerm = 0; |
| 176651 | 177600 | |
| 176652 | | - fts5SegIterNext(p, pSeg, &bNewTerm); |
| 177601 | + assert( p->rc==SQLITE_OK ); |
| 177602 | + pSeg->xNext(p, pSeg, &bNewTerm); |
| 176653 | 177603 | if( pSeg->pLeaf==0 || bNewTerm |
| 176654 | 177604 | || fts5MultiIterAdvanceRowid(p, pIter, iFirst) |
| 176655 | 177605 | ){ |
| 176656 | 177606 | fts5MultiIterAdvanced(p, pIter, iFirst, 1); |
| 176657 | 177607 | fts5MultiIterSetEof(pIter); |
| | @@ -176767,11 +177717,12 @@ |
| 176767 | 177717 | ** object and set the output variable to NULL. */ |
| 176768 | 177718 | if( p->rc==SQLITE_OK ){ |
| 176769 | 177719 | for(iIter=pNew->nSeg-1; iIter>0; iIter--){ |
| 176770 | 177720 | int iEq; |
| 176771 | 177721 | if( (iEq = fts5MultiIterDoCompare(pNew, iIter)) ){ |
| 176772 | | - fts5SegIterNext(p, &pNew->aSeg[iEq], 0); |
| 177722 | + Fts5SegIter *pSeg = &pNew->aSeg[iEq]; |
| 177723 | + if( p->rc==SQLITE_OK ) pSeg->xNext(p, pSeg, 0); |
| 176773 | 177724 | fts5MultiIterAdvanced(p, pNew, iEq, iIter); |
| 176774 | 177725 | } |
| 176775 | 177726 | } |
| 176776 | 177727 | fts5MultiIterSetEof(pNew); |
| 176777 | 177728 | fts5AssertMultiIterSetup(p, pNew); |
| | @@ -176817,10 +177768,11 @@ |
| 176817 | 177768 | } |
| 176818 | 177769 | pData = 0; |
| 176819 | 177770 | }else{ |
| 176820 | 177771 | pNew->bEof = 1; |
| 176821 | 177772 | } |
| 177773 | + fts5SegIterSetNext(p, pIter); |
| 176822 | 177774 | |
| 176823 | 177775 | *ppOut = pNew; |
| 176824 | 177776 | } |
| 176825 | 177777 | |
| 176826 | 177778 | fts5DataRelease(pData); |
| | @@ -176885,10 +177837,13 @@ |
| 176885 | 177837 | Fts5Data *pData = 0; |
| 176886 | 177838 | u8 *pChunk = &pSeg->pLeaf->p[pSeg->iLeafOffset]; |
| 176887 | 177839 | int nChunk = MIN(nRem, pSeg->pLeaf->szLeaf - pSeg->iLeafOffset); |
| 176888 | 177840 | int pgno = pSeg->iLeafPgno; |
| 176889 | 177841 | int pgnoSave = 0; |
| 177842 | + |
| 177843 | + /* This function does notmwork with detail=none databases. */ |
| 177844 | + assert( p->pConfig->eDetail!=FTS5_DETAIL_NONE ); |
| 176890 | 177845 | |
| 176891 | 177846 | if( (pSeg->flags & FTS5_SEGITER_REVERSE)==0 ){ |
| 176892 | 177847 | pgnoSave = pgno+1; |
| 176893 | 177848 | } |
| 176894 | 177849 | |
| | @@ -177309,12 +178264,11 @@ |
| 177309 | 178264 | ** Append a rowid and position-list size field to the writers output. |
| 177310 | 178265 | */ |
| 177311 | 178266 | static void fts5WriteAppendRowid( |
| 177312 | 178267 | Fts5Index *p, |
| 177313 | 178268 | Fts5SegWriter *pWriter, |
| 177314 | | - i64 iRowid, |
| 177315 | | - int nPos |
| 178269 | + i64 iRowid |
| 177316 | 178270 | ){ |
| 177317 | 178271 | if( p->rc==SQLITE_OK ){ |
| 177318 | 178272 | Fts5PageWriter *pPage = &pWriter->writer; |
| 177319 | 178273 | |
| 177320 | 178274 | if( (pPage->buf.n + pPage->pgidx.n)>=p->pConfig->pgsz ){ |
| | @@ -177337,12 +178291,10 @@ |
| 177337 | 178291 | fts5BufferAppendVarint(&p->rc, &pPage->buf, iRowid - pWriter->iPrevRowid); |
| 177338 | 178292 | } |
| 177339 | 178293 | pWriter->iPrevRowid = iRowid; |
| 177340 | 178294 | pWriter->bFirstRowidInDoclist = 0; |
| 177341 | 178295 | pWriter->bFirstRowidInPage = 0; |
| 177342 | | - |
| 177343 | | - fts5BufferAppendVarint(&p->rc, &pPage->buf, nPos); |
| 177344 | 178296 | } |
| 177345 | 178297 | } |
| 177346 | 178298 | |
| 177347 | 178299 | static void fts5WriteAppendPoslistData( |
| 177348 | 178300 | Fts5Index *p, |
| | @@ -177534,10 +178486,11 @@ |
| 177534 | 178486 | int nInput; /* Number of input segments */ |
| 177535 | 178487 | Fts5SegWriter writer; /* Writer object */ |
| 177536 | 178488 | Fts5StructureSegment *pSeg; /* Output segment */ |
| 177537 | 178489 | Fts5Buffer term; |
| 177538 | 178490 | int bOldest; /* True if the output segment is the oldest */ |
| 178491 | + int eDetail = p->pConfig->eDetail; |
| 177539 | 178492 | |
| 177540 | 178493 | assert( iLvl<pStruct->nLevel ); |
| 177541 | 178494 | assert( pLvl->nMerge<=pLvl->nSeg ); |
| 177542 | 178495 | |
| 177543 | 178496 | memset(&writer, 0, sizeof(Fts5SegWriter)); |
| | @@ -177603,15 +178556,25 @@ |
| 177603 | 178556 | fts5BufferSet(&p->rc, &term, nTerm, pTerm); |
| 177604 | 178557 | } |
| 177605 | 178558 | |
| 177606 | 178559 | /* Append the rowid to the output */ |
| 177607 | 178560 | /* WRITEPOSLISTSIZE */ |
| 177608 | | - nPos = pSegIter->nPos*2 + pSegIter->bDel; |
| 177609 | | - fts5WriteAppendRowid(p, &writer, fts5MultiIterRowid(pIter), nPos); |
| 178561 | + fts5WriteAppendRowid(p, &writer, fts5MultiIterRowid(pIter)); |
| 177610 | 178562 | |
| 177611 | | - /* Append the position-list data to the output */ |
| 177612 | | - fts5ChunkIterate(p, pSegIter, (void*)&writer, fts5MergeChunkCallback); |
| 178563 | + if( eDetail==FTS5_DETAIL_NONE ){ |
| 178564 | + if( pSegIter->bDel ){ |
| 178565 | + fts5BufferAppendVarint(&p->rc, &writer.writer.buf, 0); |
| 178566 | + if( pSegIter->nPos>0 ){ |
| 178567 | + fts5BufferAppendVarint(&p->rc, &writer.writer.buf, 0); |
| 178568 | + } |
| 178569 | + } |
| 178570 | + }else{ |
| 178571 | + /* Append the position-list data to the output */ |
| 178572 | + nPos = pSegIter->nPos*2 + pSegIter->bDel; |
| 178573 | + fts5BufferAppendVarint(&p->rc, &writer.writer.buf, nPos); |
| 178574 | + fts5ChunkIterate(p, pSegIter, (void*)&writer, fts5MergeChunkCallback); |
| 178575 | + } |
| 177613 | 178576 | } |
| 177614 | 178577 | |
| 177615 | 178578 | /* Flush the last leaf page to disk. Set the output segment b-tree height |
| 177616 | 178579 | ** and last leaf page number at the same time. */ |
| 177617 | 178580 | fts5WriteFinish(p, &writer, &pSeg->pgnoLast); |
| | @@ -177795,11 +178758,11 @@ |
| 177795 | 178758 | pStruct = fts5StructureRead(p); |
| 177796 | 178759 | iSegid = fts5AllocateSegid(p, pStruct); |
| 177797 | 178760 | |
| 177798 | 178761 | if( iSegid ){ |
| 177799 | 178762 | const int pgsz = p->pConfig->pgsz; |
| 177800 | | - |
| 178763 | + int eDetail = p->pConfig->eDetail; |
| 177801 | 178764 | Fts5StructureSegment *pSeg; /* New segment within pStruct */ |
| 177802 | 178765 | Fts5Buffer *pBuf; /* Buffer in which to assemble leaf page */ |
| 177803 | 178766 | Fts5Buffer *pPgidx; /* Buffer in which to assemble pgidx */ |
| 177804 | 178767 | |
| 177805 | 178768 | Fts5SegWriter writer; |
| | @@ -177838,16 +178801,11 @@ |
| 177838 | 178801 | |
| 177839 | 178802 | /* The entire doclist will not fit on this leaf. The following |
| 177840 | 178803 | ** loop iterates through the poslists that make up the current |
| 177841 | 178804 | ** doclist. */ |
| 177842 | 178805 | while( p->rc==SQLITE_OK && iOff<nDoclist ){ |
| 177843 | | - int nPos; |
| 177844 | | - int nCopy; |
| 177845 | | - int bDummy; |
| 177846 | 178806 | iOff += fts5GetVarint(&pDoclist[iOff], (u64*)&iDelta); |
| 177847 | | - nCopy = fts5GetPoslistSize(&pDoclist[iOff], &nPos, &bDummy); |
| 177848 | | - nCopy += nPos; |
| 177849 | 178807 | iRowid += iDelta; |
| 177850 | 178808 | |
| 177851 | 178809 | if( writer.bFirstRowidInPage ){ |
| 177852 | 178810 | fts5PutU16(&pBuf->p[0], (u16)pBuf->n); /* first rowid on page */ |
| 177853 | 178811 | pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iRowid); |
| | @@ -177856,38 +178814,56 @@ |
| 177856 | 178814 | }else{ |
| 177857 | 178815 | pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iDelta); |
| 177858 | 178816 | } |
| 177859 | 178817 | assert( pBuf->n<=pBuf->nSpace ); |
| 177860 | 178818 | |
| 177861 | | - if( (pBuf->n + pPgidx->n + nCopy) <= pgsz ){ |
| 177862 | | - /* The entire poslist will fit on the current leaf. So copy |
| 177863 | | - ** it in one go. */ |
| 177864 | | - fts5BufferSafeAppendBlob(pBuf, &pDoclist[iOff], nCopy); |
| 177865 | | - }else{ |
| 177866 | | - /* The entire poslist will not fit on this leaf. So it needs |
| 177867 | | - ** to be broken into sections. The only qualification being |
| 177868 | | - ** that each varint must be stored contiguously. */ |
| 177869 | | - const u8 *pPoslist = &pDoclist[iOff]; |
| 177870 | | - int iPos = 0; |
| 177871 | | - while( p->rc==SQLITE_OK ){ |
| 177872 | | - int nSpace = pgsz - pBuf->n - pPgidx->n; |
| 177873 | | - int n = 0; |
| 177874 | | - if( (nCopy - iPos)<=nSpace ){ |
| 177875 | | - n = nCopy - iPos; |
| 177876 | | - }else{ |
| 177877 | | - n = fts5PoslistPrefix(&pPoslist[iPos], nSpace); |
| 177878 | | - } |
| 177879 | | - assert( n>0 ); |
| 177880 | | - fts5BufferSafeAppendBlob(pBuf, &pPoslist[iPos], n); |
| 177881 | | - iPos += n; |
| 177882 | | - if( (pBuf->n + pPgidx->n)>=pgsz ){ |
| 177883 | | - fts5WriteFlushLeaf(p, &writer); |
| 177884 | | - } |
| 177885 | | - if( iPos>=nCopy ) break; |
| 177886 | | - } |
| 177887 | | - } |
| 177888 | | - iOff += nCopy; |
| 178819 | + if( eDetail==FTS5_DETAIL_NONE ){ |
| 178820 | + if( iOff<nDoclist && pDoclist[iOff]==0 ){ |
| 178821 | + pBuf->p[pBuf->n++] = 0; |
| 178822 | + iOff++; |
| 178823 | + if( iOff<nDoclist && pDoclist[iOff]==0 ){ |
| 178824 | + pBuf->p[pBuf->n++] = 0; |
| 178825 | + iOff++; |
| 178826 | + } |
| 178827 | + } |
| 178828 | + if( (pBuf->n + pPgidx->n)>=pgsz ){ |
| 178829 | + fts5WriteFlushLeaf(p, &writer); |
| 178830 | + } |
| 178831 | + }else{ |
| 178832 | + int bDummy; |
| 178833 | + int nPos; |
| 178834 | + int nCopy = fts5GetPoslistSize(&pDoclist[iOff], &nPos, &bDummy); |
| 178835 | + nCopy += nPos; |
| 178836 | + if( (pBuf->n + pPgidx->n + nCopy) <= pgsz ){ |
| 178837 | + /* The entire poslist will fit on the current leaf. So copy |
| 178838 | + ** it in one go. */ |
| 178839 | + fts5BufferSafeAppendBlob(pBuf, &pDoclist[iOff], nCopy); |
| 178840 | + }else{ |
| 178841 | + /* The entire poslist will not fit on this leaf. So it needs |
| 178842 | + ** to be broken into sections. The only qualification being |
| 178843 | + ** that each varint must be stored contiguously. */ |
| 178844 | + const u8 *pPoslist = &pDoclist[iOff]; |
| 178845 | + int iPos = 0; |
| 178846 | + while( p->rc==SQLITE_OK ){ |
| 178847 | + int nSpace = pgsz - pBuf->n - pPgidx->n; |
| 178848 | + int n = 0; |
| 178849 | + if( (nCopy - iPos)<=nSpace ){ |
| 178850 | + n = nCopy - iPos; |
| 178851 | + }else{ |
| 178852 | + n = fts5PoslistPrefix(&pPoslist[iPos], nSpace); |
| 178853 | + } |
| 178854 | + assert( n>0 ); |
| 178855 | + fts5BufferSafeAppendBlob(pBuf, &pPoslist[iPos], n); |
| 178856 | + iPos += n; |
| 178857 | + if( (pBuf->n + pPgidx->n)>=pgsz ){ |
| 178858 | + fts5WriteFlushLeaf(p, &writer); |
| 178859 | + } |
| 178860 | + if( iPos>=nCopy ) break; |
| 178861 | + } |
| 178862 | + } |
| 178863 | + iOff += nCopy; |
| 178864 | + } |
| 177889 | 178865 | } |
| 177890 | 178866 | } |
| 177891 | 178867 | |
| 177892 | 178868 | /* TODO2: Doclist terminator written here. */ |
| 177893 | 178869 | /* pBuf->p[pBuf->n++] = '\0'; */ |
| | @@ -178018,10 +178994,18 @@ |
| 178018 | 178994 | Fts5Buffer *pBuf; /* Append to this buffer */ |
| 178019 | 178995 | Fts5Colset *pColset; /* Restrict matches to this column */ |
| 178020 | 178996 | int eState; /* See above */ |
| 178021 | 178997 | }; |
| 178022 | 178998 | |
| 178999 | +typedef struct PoslistOffsetsCtx PoslistOffsetsCtx; |
| 179000 | +struct PoslistOffsetsCtx { |
| 179001 | + Fts5Buffer *pBuf; /* Append to this buffer */ |
| 179002 | + Fts5Colset *pColset; /* Restrict matches to this column */ |
| 179003 | + int iRead; |
| 179004 | + int iWrite; |
| 179005 | +}; |
| 179006 | + |
| 178023 | 179007 | /* |
| 178024 | 179008 | ** TODO: Make this more efficient! |
| 178025 | 179009 | */ |
| 178026 | 179010 | static int fts5IndexColsetTest(Fts5Colset *pColset, int iCol){ |
| 178027 | 179011 | int i; |
| | @@ -178028,10 +179012,32 @@ |
| 178028 | 179012 | for(i=0; i<pColset->nCol; i++){ |
| 178029 | 179013 | if( pColset->aiCol[i]==iCol ) return 1; |
| 178030 | 179014 | } |
| 178031 | 179015 | return 0; |
| 178032 | 179016 | } |
| 179017 | + |
| 179018 | +static void fts5PoslistOffsetsCallback( |
| 179019 | + Fts5Index *p, |
| 179020 | + void *pContext, |
| 179021 | + const u8 *pChunk, int nChunk |
| 179022 | +){ |
| 179023 | + PoslistOffsetsCtx *pCtx = (PoslistOffsetsCtx*)pContext; |
| 179024 | + assert_nc( nChunk>=0 ); |
| 179025 | + if( nChunk>0 ){ |
| 179026 | + int i = 0; |
| 179027 | + while( i<nChunk ){ |
| 179028 | + int iVal; |
| 179029 | + i += fts5GetVarint32(&pChunk[i], iVal); |
| 179030 | + iVal += pCtx->iRead - 2; |
| 179031 | + pCtx->iRead = iVal; |
| 179032 | + if( fts5IndexColsetTest(pCtx->pColset, iVal) ){ |
| 179033 | + fts5BufferSafeAppendVarint(pCtx->pBuf, iVal + 2 - pCtx->iWrite); |
| 179034 | + pCtx->iWrite = iVal; |
| 179035 | + } |
| 179036 | + } |
| 179037 | + } |
| 179038 | +} |
| 178033 | 179039 | |
| 178034 | 179040 | static void fts5PoslistFilterCallback( |
| 178035 | 179041 | Fts5Index *p, |
| 178036 | 179042 | void *pContext, |
| 178037 | 179043 | const u8 *pChunk, int nChunk |
| | @@ -178096,16 +179102,24 @@ |
| 178096 | 179102 | ){ |
| 178097 | 179103 | if( 0==fts5BufferGrow(&p->rc, pBuf, pSeg->nPos) ){ |
| 178098 | 179104 | if( pColset==0 ){ |
| 178099 | 179105 | fts5ChunkIterate(p, pSeg, (void*)pBuf, fts5PoslistCallback); |
| 178100 | 179106 | }else{ |
| 178101 | | - PoslistCallbackCtx sCtx; |
| 178102 | | - sCtx.pBuf = pBuf; |
| 178103 | | - sCtx.pColset = pColset; |
| 178104 | | - sCtx.eState = fts5IndexColsetTest(pColset, 0); |
| 178105 | | - assert( sCtx.eState==0 || sCtx.eState==1 ); |
| 178106 | | - fts5ChunkIterate(p, pSeg, (void*)&sCtx, fts5PoslistFilterCallback); |
| 179107 | + if( p->pConfig->eDetail==FTS5_DETAIL_FULL ){ |
| 179108 | + PoslistCallbackCtx sCtx; |
| 179109 | + sCtx.pBuf = pBuf; |
| 179110 | + sCtx.pColset = pColset; |
| 179111 | + sCtx.eState = fts5IndexColsetTest(pColset, 0); |
| 179112 | + assert( sCtx.eState==0 || sCtx.eState==1 ); |
| 179113 | + fts5ChunkIterate(p, pSeg, (void*)&sCtx, fts5PoslistFilterCallback); |
| 179114 | + }else{ |
| 179115 | + PoslistOffsetsCtx sCtx; |
| 179116 | + memset(&sCtx, 0, sizeof(sCtx)); |
| 179117 | + sCtx.pBuf = pBuf; |
| 179118 | + sCtx.pColset = pColset; |
| 179119 | + fts5ChunkIterate(p, pSeg, (void*)&sCtx, fts5PoslistOffsetsCallback); |
| 179120 | + } |
| 178107 | 179121 | } |
| 178108 | 179122 | } |
| 178109 | 179123 | } |
| 178110 | 179124 | |
| 178111 | 179125 | /* |
| | @@ -178144,10 +179158,20 @@ |
| 178144 | 179158 | prev = *p++; |
| 178145 | 179159 | } |
| 178146 | 179160 | return p - (*pa); |
| 178147 | 179161 | } |
| 178148 | 179162 | |
| 179163 | +static int fts5AppendRowid( |
| 179164 | + Fts5Index *p, |
| 179165 | + i64 iDelta, |
| 179166 | + Fts5IndexIter *pMulti, |
| 179167 | + Fts5Colset *pColset, |
| 179168 | + Fts5Buffer *pBuf |
| 179169 | +){ |
| 179170 | + fts5BufferAppendVarint(&p->rc, pBuf, iDelta); |
| 179171 | + return 0; |
| 179172 | +} |
| 178149 | 179173 | |
| 178150 | 179174 | /* |
| 178151 | 179175 | ** Iterator pMulti currently points to a valid entry (not EOF). This |
| 178152 | 179176 | ** function appends the following to buffer pBuf: |
| 178153 | 179177 | ** |
| | @@ -178171,12 +179195,12 @@ |
| 178171 | 179195 | if( p->rc==SQLITE_OK ){ |
| 178172 | 179196 | Fts5SegIter *pSeg = &pMulti->aSeg[ pMulti->aFirst[1].iFirst ]; |
| 178173 | 179197 | assert( fts5MultiIterEof(p, pMulti)==0 ); |
| 178174 | 179198 | assert( pSeg->nPos>0 ); |
| 178175 | 179199 | if( 0==fts5BufferGrow(&p->rc, pBuf, pSeg->nPos+9+9) ){ |
| 178176 | | - |
| 178177 | | - if( pSeg->iLeafOffset+pSeg->nPos<=pSeg->pLeaf->szLeaf |
| 179200 | + if( p->pConfig->eDetail==FTS5_DETAIL_FULL |
| 179201 | + && pSeg->iLeafOffset+pSeg->nPos<=pSeg->pLeaf->szLeaf |
| 178178 | 179202 | && (pColset==0 || pColset->nCol==1) |
| 178179 | 179203 | ){ |
| 178180 | 179204 | const u8 *pPos = &pSeg->pLeaf->p[pSeg->iLeafOffset]; |
| 178181 | 179205 | int nPos; |
| 178182 | 179206 | if( pColset ){ |
| | @@ -178217,16 +179241,16 @@ |
| 178217 | 179241 | sqlite3Fts5PutVarint(&pBuf->p[iSv2], nActual*2); |
| 178218 | 179242 | } |
| 178219 | 179243 | } |
| 178220 | 179244 | } |
| 178221 | 179245 | } |
| 178222 | | - |
| 178223 | 179246 | } |
| 178224 | 179247 | } |
| 178225 | 179248 | |
| 178226 | 179249 | return 0; |
| 178227 | 179250 | } |
| 179251 | + |
| 178228 | 179252 | |
| 178229 | 179253 | static void fts5DoclistIterNext(Fts5DoclistIter *pIter){ |
| 178230 | 179254 | u8 *p = pIter->aPoslist + pIter->nSize + pIter->nPoslist; |
| 178231 | 179255 | |
| 178232 | 179256 | assert( pIter->aPoslist ); |
| | @@ -178283,10 +179307,73 @@ |
| 178283 | 179307 | #define fts5MergeAppendDocid(pBuf, iLastRowid, iRowid) { \ |
| 178284 | 179308 | assert( (pBuf)->n!=0 || (iLastRowid)==0 ); \ |
| 178285 | 179309 | fts5BufferSafeAppendVarint((pBuf), (iRowid) - (iLastRowid)); \ |
| 178286 | 179310 | (iLastRowid) = (iRowid); \ |
| 178287 | 179311 | } |
| 179312 | + |
| 179313 | +/* |
| 179314 | +** Swap the contents of buffer *p1 with that of *p2. |
| 179315 | +*/ |
| 179316 | +static void fts5BufferSwap(Fts5Buffer *p1, Fts5Buffer *p2){ |
| 179317 | + Fts5Buffer tmp = *p1; |
| 179318 | + *p1 = *p2; |
| 179319 | + *p2 = tmp; |
| 179320 | +} |
| 179321 | + |
| 179322 | +static void fts5NextRowid(Fts5Buffer *pBuf, int *piOff, i64 *piRowid){ |
| 179323 | + int i = *piOff; |
| 179324 | + if( i>=pBuf->n ){ |
| 179325 | + *piOff = -1; |
| 179326 | + }else{ |
| 179327 | + u64 iVal; |
| 179328 | + *piOff = i + sqlite3Fts5GetVarint(&pBuf->p[i], &iVal); |
| 179329 | + *piRowid += iVal; |
| 179330 | + } |
| 179331 | +} |
| 179332 | + |
| 179333 | +/* |
| 179334 | +** This is the equivalent of fts5MergePrefixLists() for detail=none mode. |
| 179335 | +** In this case the buffers consist of a delta-encoded list of rowids only. |
| 179336 | +*/ |
| 179337 | +static void fts5MergeRowidLists( |
| 179338 | + Fts5Index *p, /* FTS5 backend object */ |
| 179339 | + Fts5Buffer *p1, /* First list to merge */ |
| 179340 | + Fts5Buffer *p2 /* Second list to merge */ |
| 179341 | +){ |
| 179342 | + int i1 = 0; |
| 179343 | + int i2 = 0; |
| 179344 | + i64 iRowid1 = 0; |
| 179345 | + i64 iRowid2 = 0; |
| 179346 | + i64 iOut = 0; |
| 179347 | + |
| 179348 | + Fts5Buffer out; |
| 179349 | + memset(&out, 0, sizeof(out)); |
| 179350 | + sqlite3Fts5BufferSize(&p->rc, &out, p1->n + p2->n); |
| 179351 | + if( p->rc ) return; |
| 179352 | + |
| 179353 | + fts5NextRowid(p1, &i1, &iRowid1); |
| 179354 | + fts5NextRowid(p2, &i2, &iRowid2); |
| 179355 | + while( i1>=0 || i2>=0 ){ |
| 179356 | + if( i1>=0 && (i2<0 || iRowid1<iRowid2) ){ |
| 179357 | + assert( iOut==0 || iRowid1>iOut ); |
| 179358 | + fts5BufferSafeAppendVarint(&out, iRowid1 - iOut); |
| 179359 | + iOut = iRowid1; |
| 179360 | + fts5NextRowid(p1, &i1, &iRowid1); |
| 179361 | + }else{ |
| 179362 | + assert( iOut==0 || iRowid2>iOut ); |
| 179363 | + fts5BufferSafeAppendVarint(&out, iRowid2 - iOut); |
| 179364 | + iOut = iRowid2; |
| 179365 | + if( i1>=0 && iRowid1==iRowid2 ){ |
| 179366 | + fts5NextRowid(p1, &i1, &iRowid1); |
| 179367 | + } |
| 179368 | + fts5NextRowid(p2, &i2, &iRowid2); |
| 179369 | + } |
| 179370 | + } |
| 179371 | + |
| 179372 | + fts5BufferSwap(&out, p1); |
| 179373 | + fts5BufferFree(&out); |
| 179374 | +} |
| 178288 | 179375 | |
| 178289 | 179376 | /* |
| 178290 | 179377 | ** Buffers p1 and p2 contain doclists. This function merges the content |
| 178291 | 179378 | ** of the two doclists together and sets buffer p1 to the result before |
| 178292 | 179379 | ** returning. |
| | @@ -178352,11 +179439,13 @@ |
| 178352 | 179439 | sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2); |
| 178353 | 179440 | if( iPos1==iPos2 ){ |
| 178354 | 179441 | sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1,&iPos1); |
| 178355 | 179442 | } |
| 178356 | 179443 | } |
| 178357 | | - p->rc = sqlite3Fts5PoslistWriterAppend(&tmp, &writer, iNew); |
| 179444 | + if( iNew!=writer.iPrev || tmp.n==0 ){ |
| 179445 | + p->rc = sqlite3Fts5PoslistWriterAppend(&tmp, &writer, iNew); |
| 179446 | + } |
| 178358 | 179447 | } |
| 178359 | 179448 | |
| 178360 | 179449 | /* WRITEPOSLISTSIZE */ |
| 178361 | 179450 | fts5BufferSafeAppendVarint(&out, tmp.n * 2); |
| 178362 | 179451 | fts5BufferSafeAppendBlob(&out, tmp.p, tmp.n); |
| | @@ -178369,16 +179458,10 @@ |
| 178369 | 179458 | fts5BufferFree(&tmp); |
| 178370 | 179459 | fts5BufferFree(&out); |
| 178371 | 179460 | } |
| 178372 | 179461 | } |
| 178373 | 179462 | |
| 178374 | | -static void fts5BufferSwap(Fts5Buffer *p1, Fts5Buffer *p2){ |
| 178375 | | - Fts5Buffer tmp = *p1; |
| 178376 | | - *p1 = *p2; |
| 178377 | | - *p2 = tmp; |
| 178378 | | -} |
| 178379 | | - |
| 178380 | 179463 | static void fts5SetupPrefixIter( |
| 178381 | 179464 | Fts5Index *p, /* Index to read from */ |
| 178382 | 179465 | int bDesc, /* True for "ORDER BY rowid DESC" */ |
| 178383 | 179466 | const u8 *pToken, /* Buffer containing prefix to match */ |
| 178384 | 179467 | int nToken, /* Size of buffer pToken in bytes */ |
| | @@ -178386,10 +179469,20 @@ |
| 178386 | 179469 | Fts5IndexIter **ppIter /* OUT: New iterator */ |
| 178387 | 179470 | ){ |
| 178388 | 179471 | Fts5Structure *pStruct; |
| 178389 | 179472 | Fts5Buffer *aBuf; |
| 178390 | 179473 | const int nBuf = 32; |
| 179474 | + |
| 179475 | + void (*xMerge)(Fts5Index*, Fts5Buffer*, Fts5Buffer*); |
| 179476 | + int (*xAppend)(Fts5Index*, i64, Fts5IndexIter*, Fts5Colset*, Fts5Buffer*); |
| 179477 | + if( p->pConfig->eDetail==FTS5_DETAIL_NONE ){ |
| 179478 | + xMerge = fts5MergeRowidLists; |
| 179479 | + xAppend = fts5AppendRowid; |
| 179480 | + }else{ |
| 179481 | + xMerge = fts5MergePrefixLists; |
| 179482 | + xAppend = fts5AppendPoslist; |
| 179483 | + } |
| 178391 | 179484 | |
| 178392 | 179485 | aBuf = (Fts5Buffer*)fts5IdxMalloc(p, sizeof(Fts5Buffer)*nBuf); |
| 178393 | 179486 | pStruct = fts5StructureRead(p); |
| 178394 | 179487 | |
| 178395 | 179488 | if( aBuf && pStruct ){ |
| | @@ -178419,25 +179512,25 @@ |
| 178419 | 179512 | assert( i<nBuf ); |
| 178420 | 179513 | if( aBuf[i].n==0 ){ |
| 178421 | 179514 | fts5BufferSwap(&doclist, &aBuf[i]); |
| 178422 | 179515 | fts5BufferZero(&doclist); |
| 178423 | 179516 | }else{ |
| 178424 | | - fts5MergePrefixLists(p, &doclist, &aBuf[i]); |
| 179517 | + xMerge(p, &doclist, &aBuf[i]); |
| 178425 | 179518 | fts5BufferZero(&aBuf[i]); |
| 178426 | 179519 | } |
| 178427 | 179520 | } |
| 178428 | 179521 | iLastRowid = 0; |
| 178429 | 179522 | } |
| 178430 | 179523 | |
| 178431 | | - if( !fts5AppendPoslist(p, iRowid-iLastRowid, p1, pColset, &doclist) ){ |
| 179524 | + if( !xAppend(p, iRowid-iLastRowid, p1, pColset, &doclist) ){ |
| 178432 | 179525 | iLastRowid = iRowid; |
| 178433 | 179526 | } |
| 178434 | 179527 | } |
| 178435 | 179528 | |
| 178436 | 179529 | for(i=0; i<nBuf; i++){ |
| 178437 | 179530 | if( p->rc==SQLITE_OK ){ |
| 178438 | | - fts5MergePrefixLists(p, &doclist, &aBuf[i]); |
| 179531 | + xMerge(p, &doclist, &aBuf[i]); |
| 178439 | 179532 | } |
| 178440 | 179533 | fts5BufferFree(&aBuf[i]); |
| 178441 | 179534 | } |
| 178442 | 179535 | fts5MultiIterFree(p, p1); |
| 178443 | 179536 | |
| | @@ -178463,11 +179556,11 @@ |
| 178463 | 179556 | static int sqlite3Fts5IndexBeginWrite(Fts5Index *p, int bDelete, i64 iRowid){ |
| 178464 | 179557 | assert( p->rc==SQLITE_OK ); |
| 178465 | 179558 | |
| 178466 | 179559 | /* Allocate the hash table if it has not already been allocated */ |
| 178467 | 179560 | if( p->pHash==0 ){ |
| 178468 | | - p->rc = sqlite3Fts5HashNew(&p->pHash, &p->nPendingData); |
| 179561 | + p->rc = sqlite3Fts5HashNew(p->pConfig, &p->pHash, &p->nPendingData); |
| 178469 | 179562 | } |
| 178470 | 179563 | |
| 178471 | 179564 | /* Flush the hash table to disk if required */ |
| 178472 | 179565 | if( iRowid<p->iWriteRowid |
| 178473 | 179566 | || (iRowid==p->iWriteRowid && p->bDelete==0) |
| | @@ -178584,11 +179677,15 @@ |
| 178584 | 179677 | /* |
| 178585 | 179678 | ** Argument p points to a buffer containing utf-8 text that is n bytes in |
| 178586 | 179679 | ** size. Return the number of bytes in the nChar character prefix of the |
| 178587 | 179680 | ** buffer, or 0 if there are less than nChar characters in total. |
| 178588 | 179681 | */ |
| 178589 | | -static int fts5IndexCharlenToBytelen(const char *p, int nByte, int nChar){ |
| 179682 | +static int sqlite3Fts5IndexCharlenToBytelen( |
| 179683 | + const char *p, |
| 179684 | + int nByte, |
| 179685 | + int nChar |
| 179686 | +){ |
| 178590 | 179687 | int n = 0; |
| 178591 | 179688 | int i; |
| 178592 | 179689 | for(i=0; i<nChar; i++){ |
| 178593 | 179690 | if( n>=nByte ) return 0; /* Input contains fewer than nChar chars */ |
| 178594 | 179691 | if( (unsigned char)p[n++]>=0xc0 ){ |
| | @@ -178641,11 +179738,12 @@ |
| 178641 | 179738 | rc = sqlite3Fts5HashWrite( |
| 178642 | 179739 | p->pHash, p->iWriteRowid, iCol, iPos, FTS5_MAIN_PREFIX, pToken, nToken |
| 178643 | 179740 | ); |
| 178644 | 179741 | |
| 178645 | 179742 | for(i=0; i<pConfig->nPrefix && rc==SQLITE_OK; i++){ |
| 178646 | | - int nByte = fts5IndexCharlenToBytelen(pToken, nToken, pConfig->aPrefix[i]); |
| 179743 | + const int nChar = pConfig->aPrefix[i]; |
| 179744 | + int nByte = sqlite3Fts5IndexCharlenToBytelen(pToken, nToken, nChar); |
| 178647 | 179745 | if( nByte ){ |
| 178648 | 179746 | rc = sqlite3Fts5HashWrite(p->pHash, |
| 178649 | 179747 | p->iWriteRowid, iCol, iPos, (char)(FTS5_MAIN_PREFIX+i+1), pToken, |
| 178650 | 179748 | nByte |
| 178651 | 179749 | ); |
| | @@ -178819,13 +179917,20 @@ |
| 178819 | 179917 | const u8 **pp, /* OUT: Pointer to position-list data */ |
| 178820 | 179918 | int *pn, /* OUT: Size of position-list in bytes */ |
| 178821 | 179919 | i64 *piRowid /* OUT: Current rowid */ |
| 178822 | 179920 | ){ |
| 178823 | 179921 | Fts5SegIter *pSeg = &pIter->aSeg[ pIter->aFirst[1].iFirst ]; |
| 179922 | + int eDetail = pIter->pIndex->pConfig->eDetail; |
| 179923 | + |
| 178824 | 179924 | assert( pIter->pIndex->rc==SQLITE_OK ); |
| 178825 | 179925 | *piRowid = pSeg->iRowid; |
| 178826 | | - if( pSeg->iLeafOffset+pSeg->nPos<=pSeg->pLeaf->szLeaf ){ |
| 179926 | + if( eDetail==FTS5_DETAIL_NONE ){ |
| 179927 | + *pn = pSeg->nPos; |
| 179928 | + }else |
| 179929 | + if( eDetail==FTS5_DETAIL_FULL |
| 179930 | + && pSeg->iLeafOffset+pSeg->nPos<=pSeg->pLeaf->szLeaf |
| 179931 | + ){ |
| 178827 | 179932 | u8 *pPos = &pSeg->pLeaf->p[pSeg->iLeafOffset]; |
| 178828 | 179933 | if( pColset==0 || pIter->bFiltered ){ |
| 178829 | 179934 | *pn = pSeg->nPos; |
| 178830 | 179935 | *pp = pPos; |
| 178831 | 179936 | }else if( pColset->nCol==1 ){ |
| | @@ -178838,15 +179943,28 @@ |
| 178838 | 179943 | *pn = pIter->poslist.n; |
| 178839 | 179944 | } |
| 178840 | 179945 | }else{ |
| 178841 | 179946 | fts5BufferZero(&pIter->poslist); |
| 178842 | 179947 | fts5SegiterPoslist(pIter->pIndex, pSeg, pColset, &pIter->poslist); |
| 178843 | | - *pp = pIter->poslist.p; |
| 179948 | + if( eDetail==FTS5_DETAIL_FULL ){ |
| 179949 | + *pp = pIter->poslist.p; |
| 179950 | + } |
| 178844 | 179951 | *pn = pIter->poslist.n; |
| 178845 | 179952 | } |
| 178846 | 179953 | return fts5IndexReturn(pIter->pIndex); |
| 178847 | 179954 | } |
| 179955 | + |
| 179956 | +static int sqlite3Fts5IterCollist( |
| 179957 | + Fts5IndexIter *pIter, |
| 179958 | + const u8 **pp, /* OUT: Pointer to position-list data */ |
| 179959 | + int *pn /* OUT: Size of position-list in bytes */ |
| 179960 | +){ |
| 179961 | + assert( pIter->pIndex->pConfig->eDetail==FTS5_DETAIL_COLUMNS ); |
| 179962 | + *pp = pIter->poslist.p; |
| 179963 | + *pn = pIter->poslist.n; |
| 179964 | + return SQLITE_OK; |
| 179965 | +} |
| 178848 | 179966 | |
| 178849 | 179967 | /* |
| 178850 | 179968 | ** This function is similar to sqlite3Fts5IterPoslist(), except that it |
| 178851 | 179969 | ** copies the position list into the buffer supplied as the second |
| 178852 | 179970 | ** argument. |
| | @@ -178957,11 +180075,11 @@ |
| 178957 | 180075 | */ |
| 178958 | 180076 | |
| 178959 | 180077 | /* |
| 178960 | 180078 | ** Return a simple checksum value based on the arguments. |
| 178961 | 180079 | */ |
| 178962 | | -static u64 fts5IndexEntryCksum( |
| 180080 | +static u64 sqlite3Fts5IndexEntryCksum( |
| 178963 | 180081 | i64 iRowid, |
| 178964 | 180082 | int iCol, |
| 178965 | 180083 | int iPos, |
| 178966 | 180084 | int iIdx, |
| 178967 | 180085 | const char *pTerm, |
| | @@ -179027,34 +180145,41 @@ |
| 179027 | 180145 | const char *z, /* Index key to query for */ |
| 179028 | 180146 | int n, /* Size of index key in bytes */ |
| 179029 | 180147 | int flags, /* Flags for Fts5IndexQuery */ |
| 179030 | 180148 | u64 *pCksum /* IN/OUT: Checksum value */ |
| 179031 | 180149 | ){ |
| 180150 | + int eDetail = p->pConfig->eDetail; |
| 179032 | 180151 | u64 cksum = *pCksum; |
| 179033 | 180152 | Fts5IndexIter *pIdxIter = 0; |
| 180153 | + Fts5Buffer buf = {0, 0, 0}; |
| 179034 | 180154 | int rc = sqlite3Fts5IndexQuery(p, z, n, flags, 0, &pIdxIter); |
| 179035 | 180155 | |
| 179036 | 180156 | while( rc==SQLITE_OK && 0==sqlite3Fts5IterEof(pIdxIter) ){ |
| 179037 | | - i64 dummy; |
| 179038 | | - const u8 *pPos; |
| 179039 | | - int nPos; |
| 179040 | 180157 | i64 rowid = sqlite3Fts5IterRowid(pIdxIter); |
| 179041 | | - rc = sqlite3Fts5IterPoslist(pIdxIter, 0, &pPos, &nPos, &dummy); |
| 180158 | + |
| 180159 | + if( eDetail==FTS5_DETAIL_NONE ){ |
| 180160 | + cksum ^= sqlite3Fts5IndexEntryCksum(rowid, 0, 0, iIdx, z, n); |
| 180161 | + }else{ |
| 180162 | + rc = sqlite3Fts5IterPoslistBuffer(pIdxIter, &buf); |
| 180163 | + if( rc==SQLITE_OK ){ |
| 180164 | + Fts5PoslistReader sReader; |
| 180165 | + for(sqlite3Fts5PoslistReaderInit(buf.p, buf.n, &sReader); |
| 180166 | + sReader.bEof==0; |
| 180167 | + sqlite3Fts5PoslistReaderNext(&sReader) |
| 180168 | + ){ |
| 180169 | + int iCol = FTS5_POS2COLUMN(sReader.iPos); |
| 180170 | + int iOff = FTS5_POS2OFFSET(sReader.iPos); |
| 180171 | + cksum ^= sqlite3Fts5IndexEntryCksum(rowid, iCol, iOff, iIdx, z, n); |
| 180172 | + } |
| 180173 | + } |
| 180174 | + } |
| 179042 | 180175 | if( rc==SQLITE_OK ){ |
| 179043 | | - Fts5PoslistReader sReader; |
| 179044 | | - for(sqlite3Fts5PoslistReaderInit(pPos, nPos, &sReader); |
| 179045 | | - sReader.bEof==0; |
| 179046 | | - sqlite3Fts5PoslistReaderNext(&sReader) |
| 179047 | | - ){ |
| 179048 | | - int iCol = FTS5_POS2COLUMN(sReader.iPos); |
| 179049 | | - int iOff = FTS5_POS2OFFSET(sReader.iPos); |
| 179050 | | - cksum ^= fts5IndexEntryCksum(rowid, iCol, iOff, iIdx, z, n); |
| 179051 | | - } |
| 179052 | 180176 | rc = sqlite3Fts5IterNext(pIdxIter); |
| 179053 | 180177 | } |
| 179054 | 180178 | } |
| 179055 | 180179 | sqlite3Fts5IterClose(pIdxIter); |
| 180180 | + fts5BufferFree(&buf); |
| 179056 | 180181 | |
| 179057 | 180182 | *pCksum = cksum; |
| 179058 | 180183 | return rc; |
| 179059 | 180184 | } |
| 179060 | 180185 | |
| | @@ -179344,18 +180469,19 @@ |
| 179344 | 180469 | |
| 179345 | 180470 | |
| 179346 | 180471 | /* |
| 179347 | 180472 | ** Run internal checks to ensure that the FTS index (a) is internally |
| 179348 | 180473 | ** consistent and (b) contains entries for which the XOR of the checksums |
| 179349 | | -** as calculated by fts5IndexEntryCksum() is cksum. |
| 180474 | +** as calculated by sqlite3Fts5IndexEntryCksum() is cksum. |
| 179350 | 180475 | ** |
| 179351 | 180476 | ** Return SQLITE_CORRUPT if any of the internal checks fail, or if the |
| 179352 | 180477 | ** checksum does not match. Return SQLITE_OK if all checks pass without |
| 179353 | 180478 | ** error, or some other SQLite error code if another error (e.g. OOM) |
| 179354 | 180479 | ** occurs. |
| 179355 | 180480 | */ |
| 179356 | 180481 | static int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum){ |
| 180482 | + int eDetail = p->pConfig->eDetail; |
| 179357 | 180483 | u64 cksum2 = 0; /* Checksum based on contents of indexes */ |
| 179358 | 180484 | Fts5Buffer poslist = {0,0,0}; /* Buffer used to hold a poslist */ |
| 179359 | 180485 | Fts5IndexIter *pIter; /* Used to iterate through entire index */ |
| 179360 | 180486 | Fts5Structure *pStruct; /* Index structure */ |
| 179361 | 180487 | |
| | @@ -179403,16 +180529,22 @@ |
| 179403 | 180529 | char *z = (char*)fts5MultiIterTerm(pIter, &n); |
| 179404 | 180530 | |
| 179405 | 180531 | /* If this is a new term, query for it. Update cksum3 with the results. */ |
| 179406 | 180532 | fts5TestTerm(p, &term, z, n, cksum2, &cksum3); |
| 179407 | 180533 | |
| 179408 | | - poslist.n = 0; |
| 179409 | | - fts5SegiterPoslist(p, &pIter->aSeg[pIter->aFirst[1].iFirst] , 0, &poslist); |
| 179410 | | - while( 0==sqlite3Fts5PoslistNext64(poslist.p, poslist.n, &iOff, &iPos) ){ |
| 179411 | | - int iCol = FTS5_POS2COLUMN(iPos); |
| 179412 | | - int iTokOff = FTS5_POS2OFFSET(iPos); |
| 179413 | | - cksum2 ^= fts5IndexEntryCksum(iRowid, iCol, iTokOff, -1, z, n); |
| 180534 | + if( eDetail==FTS5_DETAIL_NONE ){ |
| 180535 | + if( 0==fts5MultiIterIsEmpty(p, pIter) ){ |
| 180536 | + cksum2 ^= sqlite3Fts5IndexEntryCksum(iRowid, 0, 0, -1, z, n); |
| 180537 | + } |
| 180538 | + }else{ |
| 180539 | + poslist.n = 0; |
| 180540 | + fts5SegiterPoslist(p, &pIter->aSeg[pIter->aFirst[1].iFirst], 0, &poslist); |
| 180541 | + while( 0==sqlite3Fts5PoslistNext64(poslist.p, poslist.n, &iOff, &iPos) ){ |
| 180542 | + int iCol = FTS5_POS2COLUMN(iPos); |
| 180543 | + int iTokOff = FTS5_POS2OFFSET(iPos); |
| 180544 | + cksum2 ^= sqlite3Fts5IndexEntryCksum(iRowid, iCol, iTokOff, -1, z, n); |
| 180545 | + } |
| 179414 | 180546 | } |
| 179415 | 180547 | } |
| 179416 | 180548 | fts5TestTerm(p, &term, 0, 0, cksum2, &cksum3); |
| 179417 | 180549 | |
| 179418 | 180550 | fts5MultiIterFree(p, pIter); |
| | @@ -179424,38 +180556,10 @@ |
| 179424 | 180556 | #endif |
| 179425 | 180557 | fts5BufferFree(&poslist); |
| 179426 | 180558 | return fts5IndexReturn(p); |
| 179427 | 180559 | } |
| 179428 | 180560 | |
| 179429 | | - |
| 179430 | | -/* |
| 179431 | | -** Calculate and return a checksum that is the XOR of the index entry |
| 179432 | | -** checksum of all entries that would be generated by the token specified |
| 179433 | | -** by the final 5 arguments. |
| 179434 | | -*/ |
| 179435 | | -static u64 sqlite3Fts5IndexCksum( |
| 179436 | | - Fts5Config *pConfig, /* Configuration object */ |
| 179437 | | - i64 iRowid, /* Document term appears in */ |
| 179438 | | - int iCol, /* Column term appears in */ |
| 179439 | | - int iPos, /* Position term appears in */ |
| 179440 | | - const char *pTerm, int nTerm /* Term at iPos */ |
| 179441 | | -){ |
| 179442 | | - u64 ret = 0; /* Return value */ |
| 179443 | | - int iIdx; /* For iterating through indexes */ |
| 179444 | | - |
| 179445 | | - ret = fts5IndexEntryCksum(iRowid, iCol, iPos, 0, pTerm, nTerm); |
| 179446 | | - |
| 179447 | | - for(iIdx=0; iIdx<pConfig->nPrefix; iIdx++){ |
| 179448 | | - int nByte = fts5IndexCharlenToBytelen(pTerm, nTerm, pConfig->aPrefix[iIdx]); |
| 179449 | | - if( nByte ){ |
| 179450 | | - ret ^= fts5IndexEntryCksum(iRowid, iCol, iPos, iIdx+1, pTerm, nByte); |
| 179451 | | - } |
| 179452 | | - } |
| 179453 | | - |
| 179454 | | - return ret; |
| 179455 | | -} |
| 179456 | | - |
| 179457 | 180561 | /************************************************************************* |
| 179458 | 180562 | ************************************************************************** |
| 179459 | 180563 | ** Below this point is the implementation of the fts5_decode() scalar |
| 179460 | 180564 | ** function only. |
| 179461 | 180565 | */ |
| | @@ -179618,10 +180722,51 @@ |
| 179618 | 180722 | } |
| 179619 | 180723 | } |
| 179620 | 180724 | |
| 179621 | 180725 | return iOff; |
| 179622 | 180726 | } |
| 180727 | + |
| 180728 | +/* |
| 180729 | +** This function is part of the fts5_decode() debugging function. It is |
| 180730 | +** only ever used with detail=none tables. |
| 180731 | +** |
| 180732 | +** Buffer (pData/nData) contains a doclist in the format used by detail=none |
| 180733 | +** tables. This function appends a human-readable version of that list to |
| 180734 | +** buffer pBuf. |
| 180735 | +** |
| 180736 | +** If *pRc is other than SQLITE_OK when this function is called, it is a |
| 180737 | +** no-op. If an OOM or other error occurs within this function, *pRc is |
| 180738 | +** set to an SQLite error code before returning. The final state of buffer |
| 180739 | +** pBuf is undefined in this case. |
| 180740 | +*/ |
| 180741 | +static void fts5DecodeRowidList( |
| 180742 | + int *pRc, /* IN/OUT: Error code */ |
| 180743 | + Fts5Buffer *pBuf, /* Buffer to append text to */ |
| 180744 | + const u8 *pData, int nData /* Data to decode list-of-rowids from */ |
| 180745 | +){ |
| 180746 | + int i = 0; |
| 180747 | + i64 iRowid = 0; |
| 180748 | + |
| 180749 | + while( i<nData ){ |
| 180750 | + const char *zApp = ""; |
| 180751 | + u64 iVal; |
| 180752 | + i += sqlite3Fts5GetVarint(&pData[i], &iVal); |
| 180753 | + iRowid += iVal; |
| 180754 | + |
| 180755 | + if( i<nData && pData[i]==0x00 ){ |
| 180756 | + i++; |
| 180757 | + if( i<nData && pData[i]==0x00 ){ |
| 180758 | + i++; |
| 180759 | + zApp = "+"; |
| 180760 | + }else{ |
| 180761 | + zApp = "*"; |
| 180762 | + } |
| 180763 | + } |
| 180764 | + |
| 180765 | + sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " %lld%s", iRowid, zApp); |
| 180766 | + } |
| 180767 | +} |
| 179623 | 180768 | |
| 179624 | 180769 | /* |
| 179625 | 180770 | ** The implementation of user-defined scalar function fts5_decode(). |
| 179626 | 180771 | */ |
| 179627 | 180772 | static void fts5DecodeFunction( |
| | @@ -179634,10 +180779,11 @@ |
| 179634 | 180779 | const u8 *aBlob; int n; /* Record to decode */ |
| 179635 | 180780 | u8 *a = 0; |
| 179636 | 180781 | Fts5Buffer s; /* Build up text to return here */ |
| 179637 | 180782 | int rc = SQLITE_OK; /* Return code */ |
| 179638 | 180783 | int nSpace = 0; |
| 180784 | + int eDetailNone = (sqlite3_user_data(pCtx)!=0); |
| 179639 | 180785 | |
| 179640 | 180786 | assert( nArg==2 ); |
| 179641 | 180787 | memset(&s, 0, sizeof(Fts5Buffer)); |
| 179642 | 180788 | iRowid = sqlite3_value_int64(apVal[0]); |
| 179643 | 180789 | |
| | @@ -179675,10 +180821,58 @@ |
| 179675 | 180821 | if( iRowid==FTS5_AVERAGES_ROWID ){ |
| 179676 | 180822 | fts5DecodeAverages(&rc, &s, a, n); |
| 179677 | 180823 | }else{ |
| 179678 | 180824 | fts5DecodeStructure(&rc, &s, a, n); |
| 179679 | 180825 | } |
| 180826 | + }else if( eDetailNone ){ |
| 180827 | + Fts5Buffer term; /* Current term read from page */ |
| 180828 | + int szLeaf; |
| 180829 | + int iPgidxOff = szLeaf = fts5GetU16(&a[2]); |
| 180830 | + int iTermOff; |
| 180831 | + int nKeep = 0; |
| 180832 | + int iOff; |
| 180833 | + |
| 180834 | + memset(&term, 0, sizeof(Fts5Buffer)); |
| 180835 | + |
| 180836 | + /* Decode any entries that occur before the first term. */ |
| 180837 | + if( szLeaf<n ){ |
| 180838 | + iPgidxOff += fts5GetVarint32(&a[iPgidxOff], iTermOff); |
| 180839 | + }else{ |
| 180840 | + iTermOff = szLeaf; |
| 180841 | + } |
| 180842 | + fts5DecodeRowidList(&rc, &s, &a[4], iTermOff-4); |
| 180843 | + |
| 180844 | + iOff = iTermOff; |
| 180845 | + while( iOff<szLeaf ){ |
| 180846 | + int nAppend; |
| 180847 | + |
| 180848 | + /* Read the term data for the next term*/ |
| 180849 | + iOff += fts5GetVarint32(&a[iOff], nAppend); |
| 180850 | + term.n = nKeep; |
| 180851 | + fts5BufferAppendBlob(&rc, &term, nAppend, &a[iOff]); |
| 180852 | + sqlite3Fts5BufferAppendPrintf( |
| 180853 | + &rc, &s, " term=%.*s", term.n, (const char*)term.p |
| 180854 | + ); |
| 180855 | + iOff += nAppend; |
| 180856 | + |
| 180857 | + /* Figure out where the doclist for this term ends */ |
| 180858 | + if( iPgidxOff<n ){ |
| 180859 | + int nIncr; |
| 180860 | + iPgidxOff += fts5GetVarint32(&a[iPgidxOff], nIncr); |
| 180861 | + iTermOff += nIncr; |
| 180862 | + }else{ |
| 180863 | + iTermOff = szLeaf; |
| 180864 | + } |
| 180865 | + |
| 180866 | + fts5DecodeRowidList(&rc, &s, &a[iOff], iTermOff-iOff); |
| 180867 | + iOff = iTermOff; |
| 180868 | + if( iOff<szLeaf ){ |
| 180869 | + iOff += fts5GetVarint32(&a[iOff], nKeep); |
| 180870 | + } |
| 180871 | + } |
| 180872 | + |
| 180873 | + fts5BufferFree(&term); |
| 179680 | 180874 | }else{ |
| 179681 | 180875 | Fts5Buffer term; /* Current term read from page */ |
| 179682 | 180876 | int szLeaf; /* Offset of pgidx in a[] */ |
| 179683 | 180877 | int iPgidxOff; |
| 179684 | 180878 | int iPgidxPrev = 0; /* Previous value read from pgidx */ |
| | @@ -179802,18 +180996,25 @@ |
| 179802 | 180996 | */ |
| 179803 | 180997 | static int sqlite3Fts5IndexInit(sqlite3 *db){ |
| 179804 | 180998 | int rc = sqlite3_create_function( |
| 179805 | 180999 | db, "fts5_decode", 2, SQLITE_UTF8, 0, fts5DecodeFunction, 0, 0 |
| 179806 | 181000 | ); |
| 181001 | + |
| 181002 | + if( rc==SQLITE_OK ){ |
| 181003 | + rc = sqlite3_create_function( |
| 181004 | + db, "fts5_decode_none", 2, |
| 181005 | + SQLITE_UTF8, (void*)db, fts5DecodeFunction, 0, 0 |
| 181006 | + ); |
| 181007 | + } |
| 181008 | + |
| 179807 | 181009 | if( rc==SQLITE_OK ){ |
| 179808 | 181010 | rc = sqlite3_create_function( |
| 179809 | 181011 | db, "fts5_rowid", -1, SQLITE_UTF8, 0, fts5RowidFunction, 0, 0 |
| 179810 | 181012 | ); |
| 179811 | 181013 | } |
| 179812 | 181014 | return rc; |
| 179813 | 181015 | } |
| 179814 | | - |
| 179815 | 181016 | |
| 179816 | 181017 | /* |
| 179817 | 181018 | ** 2014 Jun 09 |
| 179818 | 181019 | ** |
| 179819 | 181020 | ** The author disclaims copyright to this source code. In place of |
| | @@ -180039,10 +181240,11 @@ |
| 180039 | 181240 | #define FTS5CSR_REQUIRE_DOCSIZE 0x02 |
| 180040 | 181241 | #define FTS5CSR_REQUIRE_INST 0x04 |
| 180041 | 181242 | #define FTS5CSR_EOF 0x08 |
| 180042 | 181243 | #define FTS5CSR_FREE_ZRANK 0x10 |
| 180043 | 181244 | #define FTS5CSR_REQUIRE_RESEEK 0x20 |
| 181245 | +#define FTS5CSR_REQUIRE_POSLIST 0x40 |
| 180044 | 181246 | |
| 180045 | 181247 | #define BitFlagAllTest(x,y) (((x) & (y))==(y)) |
| 180046 | 181248 | #define BitFlagTest(x,y) (((x) & (y))!=0) |
| 180047 | 181249 | |
| 180048 | 181250 | |
| | @@ -180452,10 +181654,11 @@ |
| 180452 | 181654 | static void fts5CsrNewrow(Fts5Cursor *pCsr){ |
| 180453 | 181655 | CsrFlagSet(pCsr, |
| 180454 | 181656 | FTS5CSR_REQUIRE_CONTENT |
| 180455 | 181657 | | FTS5CSR_REQUIRE_DOCSIZE |
| 180456 | 181658 | | FTS5CSR_REQUIRE_INST |
| 181659 | + | FTS5CSR_REQUIRE_POSLIST |
| 180457 | 181660 | ); |
| 180458 | 181661 | } |
| 180459 | 181662 | |
| 180460 | 181663 | static void fts5FreeCursorComponents(Fts5Cursor *pCsr){ |
| 180461 | 181664 | Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); |
| | @@ -180534,19 +181737,22 @@ |
| 180534 | 181737 | |
| 180535 | 181738 | pSorter->iRowid = sqlite3_column_int64(pSorter->pStmt, 0); |
| 180536 | 181739 | nBlob = sqlite3_column_bytes(pSorter->pStmt, 1); |
| 180537 | 181740 | aBlob = a = sqlite3_column_blob(pSorter->pStmt, 1); |
| 180538 | 181741 | |
| 180539 | | - for(i=0; i<(pSorter->nIdx-1); i++){ |
| 180540 | | - int iVal; |
| 180541 | | - a += fts5GetVarint32(a, iVal); |
| 180542 | | - iOff += iVal; |
| 180543 | | - pSorter->aIdx[i] = iOff; |
| 180544 | | - } |
| 180545 | | - pSorter->aIdx[i] = &aBlob[nBlob] - a; |
| 180546 | | - |
| 180547 | | - pSorter->aPoslist = a; |
| 181742 | + /* nBlob==0 in detail=none mode. */ |
| 181743 | + if( nBlob>0 ){ |
| 181744 | + for(i=0; i<(pSorter->nIdx-1); i++){ |
| 181745 | + int iVal; |
| 181746 | + a += fts5GetVarint32(a, iVal); |
| 181747 | + iOff += iVal; |
| 181748 | + pSorter->aIdx[i] = iOff; |
| 181749 | + } |
| 181750 | + pSorter->aIdx[i] = &aBlob[nBlob] - a; |
| 181751 | + pSorter->aPoslist = a; |
| 181752 | + } |
| 181753 | + |
| 180548 | 181754 | fts5CsrNewrow(pCsr); |
| 180549 | 181755 | } |
| 180550 | 181756 | |
| 180551 | 181757 | return rc; |
| 180552 | 181758 | } |
| | @@ -180652,45 +181858,44 @@ |
| 180652 | 181858 | |
| 180653 | 181859 | return rc; |
| 180654 | 181860 | } |
| 180655 | 181861 | |
| 180656 | 181862 | |
| 180657 | | -static sqlite3_stmt *fts5PrepareStatement( |
| 180658 | | - int *pRc, |
| 181863 | +static int fts5PrepareStatement( |
| 181864 | + sqlite3_stmt **ppStmt, |
| 180659 | 181865 | Fts5Config *pConfig, |
| 180660 | 181866 | const char *zFmt, |
| 180661 | 181867 | ... |
| 180662 | 181868 | ){ |
| 180663 | 181869 | sqlite3_stmt *pRet = 0; |
| 181870 | + int rc; |
| 181871 | + char *zSql; |
| 180664 | 181872 | va_list ap; |
| 181873 | + |
| 180665 | 181874 | va_start(ap, zFmt); |
| 180666 | | - |
| 180667 | | - if( *pRc==SQLITE_OK ){ |
| 180668 | | - int rc; |
| 180669 | | - char *zSql = sqlite3_vmprintf(zFmt, ap); |
| 180670 | | - if( zSql==0 ){ |
| 180671 | | - rc = SQLITE_NOMEM; |
| 180672 | | - }else{ |
| 180673 | | - rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &pRet, 0); |
| 180674 | | - if( rc!=SQLITE_OK ){ |
| 180675 | | - *pConfig->pzErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(pConfig->db)); |
| 180676 | | - } |
| 180677 | | - sqlite3_free(zSql); |
| 180678 | | - } |
| 180679 | | - *pRc = rc; |
| 181875 | + zSql = sqlite3_vmprintf(zFmt, ap); |
| 181876 | + if( zSql==0 ){ |
| 181877 | + rc = SQLITE_NOMEM; |
| 181878 | + }else{ |
| 181879 | + rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &pRet, 0); |
| 181880 | + if( rc!=SQLITE_OK ){ |
| 181881 | + *pConfig->pzErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(pConfig->db)); |
| 181882 | + } |
| 181883 | + sqlite3_free(zSql); |
| 180680 | 181884 | } |
| 180681 | 181885 | |
| 180682 | 181886 | va_end(ap); |
| 180683 | | - return pRet; |
| 181887 | + *ppStmt = pRet; |
| 181888 | + return rc; |
| 180684 | 181889 | } |
| 180685 | 181890 | |
| 180686 | 181891 | static int fts5CursorFirstSorted(Fts5Table *pTab, Fts5Cursor *pCsr, int bDesc){ |
| 180687 | 181892 | Fts5Config *pConfig = pTab->pConfig; |
| 180688 | 181893 | Fts5Sorter *pSorter; |
| 180689 | 181894 | int nPhrase; |
| 180690 | 181895 | int nByte; |
| 180691 | | - int rc = SQLITE_OK; |
| 181896 | + int rc; |
| 180692 | 181897 | const char *zRank = pCsr->zRank; |
| 180693 | 181898 | const char *zRankArgs = pCsr->zRankArgs; |
| 180694 | 181899 | |
| 180695 | 181900 | nPhrase = sqlite3Fts5ExprPhraseCount(pCsr->pExpr); |
| 180696 | 181901 | nByte = sizeof(Fts5Sorter) + sizeof(int) * (nPhrase-1); |
| | @@ -180704,11 +181909,11 @@ |
| 180704 | 181909 | ** is not possible as SQLite reference counts the virtual table objects. |
| 180705 | 181910 | ** And since the statement required here reads from this very virtual |
| 180706 | 181911 | ** table, saving it creates a circular reference. |
| 180707 | 181912 | ** |
| 180708 | 181913 | ** If SQLite a built-in statement cache, this wouldn't be a problem. */ |
| 180709 | | - pSorter->pStmt = fts5PrepareStatement(&rc, pConfig, |
| 181914 | + rc = fts5PrepareStatement(&pSorter->pStmt, pConfig, |
| 180710 | 181915 | "SELECT rowid, rank FROM %Q.%Q ORDER BY %s(%s%s%s) %s", |
| 180711 | 181916 | pConfig->zDb, pConfig->zName, zRank, pConfig->zName, |
| 180712 | 181917 | (zRankArgs ? ", " : ""), |
| 180713 | 181918 | (zRankArgs ? zRankArgs : ""), |
| 180714 | 181919 | bDesc ? "DESC" : "ASC" |
| | @@ -180980,10 +182185,11 @@ |
| 180980 | 182185 | assert( pCsr->iLastRowid==LARGEST_INT64 ); |
| 180981 | 182186 | assert( pCsr->iFirstRowid==SMALLEST_INT64 ); |
| 180982 | 182187 | pCsr->ePlan = FTS5_PLAN_SOURCE; |
| 180983 | 182188 | pCsr->pExpr = pTab->pSortCsr->pExpr; |
| 180984 | 182189 | rc = fts5CursorFirst(pTab, pCsr, bDesc); |
| 182190 | + sqlite3Fts5ExprClearEof(pCsr->pExpr); |
| 180985 | 182191 | }else if( pMatch ){ |
| 180986 | 182192 | const char *zExpr = (const char*)sqlite3_value_text(apVal[0]); |
| 180987 | 182193 | if( zExpr==0 ) zExpr = ""; |
| 180988 | 182194 | |
| 180989 | 182195 | rc = fts5CursorParseRank(pConfig, pCsr, pRank); |
| | @@ -181212,11 +182418,11 @@ |
| 181212 | 182418 | ){ |
| 181213 | 182419 | int rc = SQLITE_OK; |
| 181214 | 182420 | int eType1 = sqlite3_value_type(apVal[1]); |
| 181215 | 182421 | if( eType1==SQLITE_INTEGER ){ |
| 181216 | 182422 | sqlite3_int64 iDel = sqlite3_value_int64(apVal[1]); |
| 181217 | | - rc = sqlite3Fts5StorageSpecialDelete(pTab->pStorage, iDel, &apVal[2]); |
| 182423 | + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, &apVal[2]); |
| 181218 | 182424 | } |
| 181219 | 182425 | return rc; |
| 181220 | 182426 | } |
| 181221 | 182427 | |
| 181222 | 182428 | static void fts5StorageInsert( |
| | @@ -181319,21 +182525,21 @@ |
| 181319 | 182525 | } |
| 181320 | 182526 | |
| 181321 | 182527 | /* Case 1: DELETE */ |
| 181322 | 182528 | else if( nArg==1 ){ |
| 181323 | 182529 | i64 iDel = sqlite3_value_int64(apVal[0]); /* Rowid to delete */ |
| 181324 | | - rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel); |
| 182530 | + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0); |
| 181325 | 182531 | } |
| 181326 | 182532 | |
| 181327 | 182533 | /* Case 2: INSERT */ |
| 181328 | 182534 | else if( eType0!=SQLITE_INTEGER ){ |
| 181329 | 182535 | /* If this is a REPLACE, first remove the current entry (if any) */ |
| 181330 | 182536 | if( eConflict==SQLITE_REPLACE |
| 181331 | 182537 | && sqlite3_value_type(apVal[1])==SQLITE_INTEGER |
| 181332 | 182538 | ){ |
| 181333 | 182539 | i64 iNew = sqlite3_value_int64(apVal[1]); /* Rowid to delete */ |
| 181334 | | - rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew); |
| 182540 | + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0); |
| 181335 | 182541 | } |
| 181336 | 182542 | fts5StorageInsert(&rc, pTab, apVal, pRowid); |
| 181337 | 182543 | } |
| 181338 | 182544 | |
| 181339 | 182545 | /* Case 2: UPDATE */ |
| | @@ -181340,26 +182546,26 @@ |
| 181340 | 182546 | else{ |
| 181341 | 182547 | i64 iOld = sqlite3_value_int64(apVal[0]); /* Old rowid */ |
| 181342 | 182548 | i64 iNew = sqlite3_value_int64(apVal[1]); /* New rowid */ |
| 181343 | 182549 | if( iOld!=iNew ){ |
| 181344 | 182550 | if( eConflict==SQLITE_REPLACE ){ |
| 181345 | | - rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld); |
| 182551 | + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0); |
| 181346 | 182552 | if( rc==SQLITE_OK ){ |
| 181347 | | - rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew); |
| 182553 | + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0); |
| 181348 | 182554 | } |
| 181349 | 182555 | fts5StorageInsert(&rc, pTab, apVal, pRowid); |
| 181350 | 182556 | }else{ |
| 181351 | 182557 | rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, pRowid); |
| 181352 | 182558 | if( rc==SQLITE_OK ){ |
| 181353 | | - rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld); |
| 182559 | + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0); |
| 181354 | 182560 | } |
| 181355 | 182561 | if( rc==SQLITE_OK ){ |
| 181356 | 182562 | rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal, *pRowid); |
| 181357 | 182563 | } |
| 181358 | 182564 | } |
| 181359 | 182565 | }else{ |
| 181360 | | - rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld); |
| 182566 | + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0); |
| 181361 | 182567 | fts5StorageInsert(&rc, pTab, apVal, pRowid); |
| 181362 | 182568 | } |
| 181363 | 182569 | } |
| 181364 | 182570 | } |
| 181365 | 182571 | |
| | @@ -181409,10 +182615,12 @@ |
| 181409 | 182615 | fts5CheckTransactionState(pTab, FTS5_ROLLBACK, 0); |
| 181410 | 182616 | rc = sqlite3Fts5StorageRollback(pTab->pStorage); |
| 181411 | 182617 | return rc; |
| 181412 | 182618 | } |
| 181413 | 182619 | |
| 182620 | +static int fts5CsrPoslist(Fts5Cursor*, int, const u8**, int*); |
| 182621 | + |
| 181414 | 182622 | static void *fts5ApiUserData(Fts5Context *pCtx){ |
| 181415 | 182623 | Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; |
| 181416 | 182624 | return pCsr->pAux->pUserData; |
| 181417 | 182625 | } |
| 181418 | 182626 | |
| | @@ -181458,21 +182666,76 @@ |
| 181458 | 182666 | static int fts5ApiPhraseSize(Fts5Context *pCtx, int iPhrase){ |
| 181459 | 182667 | Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; |
| 181460 | 182668 | return sqlite3Fts5ExprPhraseSize(pCsr->pExpr, iPhrase); |
| 181461 | 182669 | } |
| 181462 | 182670 | |
| 181463 | | -static int fts5CsrPoslist(Fts5Cursor *pCsr, int iPhrase, const u8 **pa){ |
| 181464 | | - int n; |
| 181465 | | - if( pCsr->pSorter ){ |
| 182671 | +static int fts5ApiColumnText( |
| 182672 | + Fts5Context *pCtx, |
| 182673 | + int iCol, |
| 182674 | + const char **pz, |
| 182675 | + int *pn |
| 182676 | +){ |
| 182677 | + int rc = SQLITE_OK; |
| 182678 | + Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; |
| 182679 | + if( fts5IsContentless((Fts5Table*)(pCsr->base.pVtab)) ){ |
| 182680 | + *pz = 0; |
| 182681 | + *pn = 0; |
| 182682 | + }else{ |
| 182683 | + rc = fts5SeekCursor(pCsr, 0); |
| 182684 | + if( rc==SQLITE_OK ){ |
| 182685 | + *pz = (const char*)sqlite3_column_text(pCsr->pStmt, iCol+1); |
| 182686 | + *pn = sqlite3_column_bytes(pCsr->pStmt, iCol+1); |
| 182687 | + } |
| 182688 | + } |
| 182689 | + return rc; |
| 182690 | +} |
| 182691 | + |
| 182692 | +static int fts5CsrPoslist( |
| 182693 | + Fts5Cursor *pCsr, |
| 182694 | + int iPhrase, |
| 182695 | + const u8 **pa, |
| 182696 | + int *pn |
| 182697 | +){ |
| 182698 | + Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig; |
| 182699 | + int rc = SQLITE_OK; |
| 182700 | + int bLive = (pCsr->pSorter==0); |
| 182701 | + |
| 182702 | + if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_POSLIST) ){ |
| 182703 | + |
| 182704 | + if( pConfig->eDetail!=FTS5_DETAIL_FULL ){ |
| 182705 | + Fts5PoslistPopulator *aPopulator; |
| 182706 | + int i; |
| 182707 | + aPopulator = sqlite3Fts5ExprClearPoslists(pCsr->pExpr, bLive); |
| 182708 | + if( aPopulator==0 ) rc = SQLITE_NOMEM; |
| 182709 | + for(i=0; i<pConfig->nCol && rc==SQLITE_OK; i++){ |
| 182710 | + int n; const char *z; |
| 182711 | + rc = fts5ApiColumnText((Fts5Context*)pCsr, i, &z, &n); |
| 182712 | + if( rc==SQLITE_OK ){ |
| 182713 | + rc = sqlite3Fts5ExprPopulatePoslists( |
| 182714 | + pConfig, pCsr->pExpr, aPopulator, i, z, n |
| 182715 | + ); |
| 182716 | + } |
| 182717 | + } |
| 182718 | + sqlite3_free(aPopulator); |
| 182719 | + |
| 182720 | + if( pCsr->pSorter ){ |
| 182721 | + sqlite3Fts5ExprCheckPoslists(pCsr->pExpr, pCsr->pSorter->iRowid); |
| 182722 | + } |
| 182723 | + } |
| 182724 | + CsrFlagClear(pCsr, FTS5CSR_REQUIRE_POSLIST); |
| 182725 | + } |
| 182726 | + |
| 182727 | + if( pCsr->pSorter && pConfig->eDetail==FTS5_DETAIL_FULL ){ |
| 181466 | 182728 | Fts5Sorter *pSorter = pCsr->pSorter; |
| 181467 | 182729 | int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]); |
| 181468 | | - n = pSorter->aIdx[iPhrase] - i1; |
| 182730 | + *pn = pSorter->aIdx[iPhrase] - i1; |
| 181469 | 182731 | *pa = &pSorter->aPoslist[i1]; |
| 181470 | 182732 | }else{ |
| 181471 | | - n = sqlite3Fts5ExprPoslist(pCsr->pExpr, iPhrase, pa); |
| 182733 | + *pn = sqlite3Fts5ExprPoslist(pCsr->pExpr, iPhrase, pa); |
| 181472 | 182734 | } |
| 181473 | | - return n; |
| 182735 | + |
| 182736 | + return rc; |
| 181474 | 182737 | } |
| 181475 | 182738 | |
| 181476 | 182739 | /* |
| 181477 | 182740 | ** Ensure that the Fts5Cursor.nInstCount and aInst[] variables are populated |
| 181478 | 182741 | ** correctly for the current view. Return SQLITE_OK if successful, or an |
| | @@ -181493,47 +182756,52 @@ |
| 181493 | 182756 | if( aIter ){ |
| 181494 | 182757 | int nInst = 0; /* Number instances seen so far */ |
| 181495 | 182758 | int i; |
| 181496 | 182759 | |
| 181497 | 182760 | /* Initialize all iterators */ |
| 181498 | | - for(i=0; i<nIter; i++){ |
| 182761 | + for(i=0; i<nIter && rc==SQLITE_OK; i++){ |
| 181499 | 182762 | const u8 *a; |
| 181500 | | - int n = fts5CsrPoslist(pCsr, i, &a); |
| 181501 | | - sqlite3Fts5PoslistReaderInit(a, n, &aIter[i]); |
| 181502 | | - } |
| 181503 | | - |
| 181504 | | - while( 1 ){ |
| 181505 | | - int *aInst; |
| 181506 | | - int iBest = -1; |
| 181507 | | - for(i=0; i<nIter; i++){ |
| 181508 | | - if( (aIter[i].bEof==0) |
| 181509 | | - && (iBest<0 || aIter[i].iPos<aIter[iBest].iPos) |
| 181510 | | - ){ |
| 181511 | | - iBest = i; |
| 181512 | | - } |
| 181513 | | - } |
| 181514 | | - if( iBest<0 ) break; |
| 181515 | | - |
| 181516 | | - nInst++; |
| 181517 | | - if( nInst>=pCsr->nInstAlloc ){ |
| 181518 | | - pCsr->nInstAlloc = pCsr->nInstAlloc ? pCsr->nInstAlloc*2 : 32; |
| 181519 | | - aInst = (int*)sqlite3_realloc( |
| 181520 | | - pCsr->aInst, pCsr->nInstAlloc*sizeof(int)*3 |
| 181521 | | - ); |
| 181522 | | - if( aInst ){ |
| 181523 | | - pCsr->aInst = aInst; |
| 181524 | | - }else{ |
| 181525 | | - rc = SQLITE_NOMEM; |
| 181526 | | - break; |
| 181527 | | - } |
| 181528 | | - } |
| 181529 | | - |
| 181530 | | - aInst = &pCsr->aInst[3 * (nInst-1)]; |
| 181531 | | - aInst[0] = iBest; |
| 181532 | | - aInst[1] = FTS5_POS2COLUMN(aIter[iBest].iPos); |
| 181533 | | - aInst[2] = FTS5_POS2OFFSET(aIter[iBest].iPos); |
| 181534 | | - sqlite3Fts5PoslistReaderNext(&aIter[iBest]); |
| 182763 | + int n; |
| 182764 | + rc = fts5CsrPoslist(pCsr, i, &a, &n); |
| 182765 | + if( rc==SQLITE_OK ){ |
| 182766 | + sqlite3Fts5PoslistReaderInit(a, n, &aIter[i]); |
| 182767 | + } |
| 182768 | + } |
| 182769 | + |
| 182770 | + if( rc==SQLITE_OK ){ |
| 182771 | + while( 1 ){ |
| 182772 | + int *aInst; |
| 182773 | + int iBest = -1; |
| 182774 | + for(i=0; i<nIter; i++){ |
| 182775 | + if( (aIter[i].bEof==0) |
| 182776 | + && (iBest<0 || aIter[i].iPos<aIter[iBest].iPos) |
| 182777 | + ){ |
| 182778 | + iBest = i; |
| 182779 | + } |
| 182780 | + } |
| 182781 | + if( iBest<0 ) break; |
| 182782 | + |
| 182783 | + nInst++; |
| 182784 | + if( nInst>=pCsr->nInstAlloc ){ |
| 182785 | + pCsr->nInstAlloc = pCsr->nInstAlloc ? pCsr->nInstAlloc*2 : 32; |
| 182786 | + aInst = (int*)sqlite3_realloc( |
| 182787 | + pCsr->aInst, pCsr->nInstAlloc*sizeof(int)*3 |
| 182788 | + ); |
| 182789 | + if( aInst ){ |
| 182790 | + pCsr->aInst = aInst; |
| 182791 | + }else{ |
| 182792 | + rc = SQLITE_NOMEM; |
| 182793 | + break; |
| 182794 | + } |
| 182795 | + } |
| 182796 | + |
| 182797 | + aInst = &pCsr->aInst[3 * (nInst-1)]; |
| 182798 | + aInst[0] = iBest; |
| 182799 | + aInst[1] = FTS5_POS2COLUMN(aIter[iBest].iPos); |
| 182800 | + aInst[2] = FTS5_POS2OFFSET(aIter[iBest].iPos); |
| 182801 | + sqlite3Fts5PoslistReaderNext(&aIter[iBest]); |
| 182802 | + } |
| 181535 | 182803 | } |
| 181536 | 182804 | |
| 181537 | 182805 | pCsr->nInstCount = nInst; |
| 181538 | 182806 | CsrFlagClear(pCsr, FTS5CSR_REQUIRE_INST); |
| 181539 | 182807 | } |
| | @@ -181562,10 +182830,16 @@ |
| 181562 | 182830 | if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_INST)==0 |
| 181563 | 182831 | || SQLITE_OK==(rc = fts5CacheInstArray(pCsr)) |
| 181564 | 182832 | ){ |
| 181565 | 182833 | if( iIdx<0 || iIdx>=pCsr->nInstCount ){ |
| 181566 | 182834 | rc = SQLITE_RANGE; |
| 182835 | +#if 0 |
| 182836 | + }else if( fts5IsOffsetless((Fts5Table*)pCsr->base.pVtab) ){ |
| 182837 | + *piPhrase = pCsr->aInst[iIdx*3]; |
| 182838 | + *piCol = pCsr->aInst[iIdx*3 + 2]; |
| 182839 | + *piOff = -1; |
| 182840 | +#endif |
| 181567 | 182841 | }else{ |
| 181568 | 182842 | *piPhrase = pCsr->aInst[iIdx*3]; |
| 181569 | 182843 | *piCol = pCsr->aInst[iIdx*3 + 1]; |
| 181570 | 182844 | *piOff = pCsr->aInst[iIdx*3 + 2]; |
| 181571 | 182845 | } |
| | @@ -181575,31 +182849,10 @@ |
| 181575 | 182849 | |
| 181576 | 182850 | static sqlite3_int64 fts5ApiRowid(Fts5Context *pCtx){ |
| 181577 | 182851 | return fts5CursorRowid((Fts5Cursor*)pCtx); |
| 181578 | 182852 | } |
| 181579 | 182853 | |
| 181580 | | -static int fts5ApiColumnText( |
| 181581 | | - Fts5Context *pCtx, |
| 181582 | | - int iCol, |
| 181583 | | - const char **pz, |
| 181584 | | - int *pn |
| 181585 | | -){ |
| 181586 | | - int rc = SQLITE_OK; |
| 181587 | | - Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; |
| 181588 | | - if( fts5IsContentless((Fts5Table*)(pCsr->base.pVtab)) ){ |
| 181589 | | - *pz = 0; |
| 181590 | | - *pn = 0; |
| 181591 | | - }else{ |
| 181592 | | - rc = fts5SeekCursor(pCsr, 0); |
| 181593 | | - if( rc==SQLITE_OK ){ |
| 181594 | | - *pz = (const char*)sqlite3_column_text(pCsr->pStmt, iCol+1); |
| 181595 | | - *pn = sqlite3_column_bytes(pCsr->pStmt, iCol+1); |
| 181596 | | - } |
| 181597 | | - } |
| 181598 | | - return rc; |
| 181599 | | -} |
| 181600 | | - |
| 181601 | 182854 | static int fts5ColumnSizeCb( |
| 181602 | 182855 | void *pContext, /* Pointer to int */ |
| 181603 | 182856 | int tflags, |
| 181604 | 182857 | const char *pToken, /* Buffer containing token */ |
| 181605 | 182858 | int nToken, /* Size of token in bytes */ |
| | @@ -181740,23 +182993,101 @@ |
| 181740 | 182993 | } |
| 181741 | 182994 | *piOff += (iVal-2); |
| 181742 | 182995 | } |
| 181743 | 182996 | } |
| 181744 | 182997 | |
| 181745 | | -static void fts5ApiPhraseFirst( |
| 182998 | +static int fts5ApiPhraseFirst( |
| 181746 | 182999 | Fts5Context *pCtx, |
| 181747 | 183000 | int iPhrase, |
| 181748 | 183001 | Fts5PhraseIter *pIter, |
| 181749 | 183002 | int *piCol, int *piOff |
| 181750 | 183003 | ){ |
| 181751 | 183004 | Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; |
| 181752 | | - int n = fts5CsrPoslist(pCsr, iPhrase, &pIter->a); |
| 181753 | | - pIter->b = &pIter->a[n]; |
| 181754 | | - *piCol = 0; |
| 181755 | | - *piOff = 0; |
| 181756 | | - fts5ApiPhraseNext(pCtx, pIter, piCol, piOff); |
| 183005 | + int n; |
| 183006 | + int rc = fts5CsrPoslist(pCsr, iPhrase, &pIter->a, &n); |
| 183007 | + if( rc==SQLITE_OK ){ |
| 183008 | + pIter->b = &pIter->a[n]; |
| 183009 | + *piCol = 0; |
| 183010 | + *piOff = 0; |
| 183011 | + fts5ApiPhraseNext(pCtx, pIter, piCol, piOff); |
| 183012 | + } |
| 183013 | + return rc; |
| 181757 | 183014 | } |
| 183015 | + |
| 183016 | +static void fts5ApiPhraseNextColumn( |
| 183017 | + Fts5Context *pCtx, |
| 183018 | + Fts5PhraseIter *pIter, |
| 183019 | + int *piCol |
| 183020 | +){ |
| 183021 | + Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; |
| 183022 | + Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig; |
| 183023 | + |
| 183024 | + if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){ |
| 183025 | + if( pIter->a>=pIter->b ){ |
| 183026 | + *piCol = -1; |
| 183027 | + }else{ |
| 183028 | + int iIncr; |
| 183029 | + pIter->a += fts5GetVarint32(&pIter->a[0], iIncr); |
| 183030 | + *piCol += (iIncr-2); |
| 183031 | + } |
| 183032 | + }else{ |
| 183033 | + while( 1 ){ |
| 183034 | + int dummy; |
| 183035 | + if( pIter->a>=pIter->b ){ |
| 183036 | + *piCol = -1; |
| 183037 | + return; |
| 183038 | + } |
| 183039 | + if( pIter->a[0]==0x01 ) break; |
| 183040 | + pIter->a += fts5GetVarint32(pIter->a, dummy); |
| 183041 | + } |
| 183042 | + pIter->a += 1 + fts5GetVarint32(&pIter->a[1], *piCol); |
| 183043 | + } |
| 183044 | +} |
| 183045 | + |
| 183046 | +static int fts5ApiPhraseFirstColumn( |
| 183047 | + Fts5Context *pCtx, |
| 183048 | + int iPhrase, |
| 183049 | + Fts5PhraseIter *pIter, |
| 183050 | + int *piCol |
| 183051 | +){ |
| 183052 | + int rc = SQLITE_OK; |
| 183053 | + Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; |
| 183054 | + Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig; |
| 183055 | + |
| 183056 | + if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){ |
| 183057 | + Fts5Sorter *pSorter = pCsr->pSorter; |
| 183058 | + int n; |
| 183059 | + if( pSorter ){ |
| 183060 | + int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]); |
| 183061 | + n = pSorter->aIdx[iPhrase] - i1; |
| 183062 | + pIter->a = &pSorter->aPoslist[i1]; |
| 183063 | + }else{ |
| 183064 | + rc = sqlite3Fts5ExprPhraseCollist(pCsr->pExpr, iPhrase, &pIter->a, &n); |
| 183065 | + } |
| 183066 | + if( rc==SQLITE_OK ){ |
| 183067 | + pIter->b = &pIter->a[n]; |
| 183068 | + *piCol = 0; |
| 183069 | + fts5ApiPhraseNextColumn(pCtx, pIter, piCol); |
| 183070 | + } |
| 183071 | + }else{ |
| 183072 | + int n; |
| 183073 | + rc = fts5CsrPoslist(pCsr, iPhrase, &pIter->a, &n); |
| 183074 | + if( rc==SQLITE_OK ){ |
| 183075 | + pIter->b = &pIter->a[n]; |
| 183076 | + if( n<=0 ){ |
| 183077 | + *piCol = -1; |
| 183078 | + }else if( pIter->a[0]==0x01 ){ |
| 183079 | + pIter->a += 1 + fts5GetVarint32(&pIter->a[1], *piCol); |
| 183080 | + }else{ |
| 183081 | + *piCol = 0; |
| 183082 | + } |
| 183083 | + } |
| 183084 | + } |
| 183085 | + |
| 183086 | + return rc; |
| 183087 | +} |
| 183088 | + |
| 181758 | 183089 | |
| 181759 | 183090 | static int fts5ApiQueryPhrase(Fts5Context*, int, void*, |
| 181760 | 183091 | int(*)(const Fts5ExtensionApi*, Fts5Context*, void*) |
| 181761 | 183092 | ); |
| 181762 | 183093 | |
| | @@ -181777,12 +183108,13 @@ |
| 181777 | 183108 | fts5ApiQueryPhrase, |
| 181778 | 183109 | fts5ApiSetAuxdata, |
| 181779 | 183110 | fts5ApiGetAuxdata, |
| 181780 | 183111 | fts5ApiPhraseFirst, |
| 181781 | 183112 | fts5ApiPhraseNext, |
| 183113 | + fts5ApiPhraseFirstColumn, |
| 183114 | + fts5ApiPhraseNextColumn, |
| 181782 | 183115 | }; |
| 181783 | | - |
| 181784 | 183116 | |
| 181785 | 183117 | /* |
| 181786 | 183118 | ** Implementation of API function xQueryPhrase(). |
| 181787 | 183119 | */ |
| 181788 | 183120 | static int fts5ApiQueryPhrase( |
| | @@ -181911,24 +183243,50 @@ |
| 181911 | 183243 | int rc = SQLITE_OK; |
| 181912 | 183244 | int nPhrase = sqlite3Fts5ExprPhraseCount(pCsr->pExpr); |
| 181913 | 183245 | Fts5Buffer val; |
| 181914 | 183246 | |
| 181915 | 183247 | memset(&val, 0, sizeof(Fts5Buffer)); |
| 181916 | | - |
| 181917 | | - /* Append the varints */ |
| 181918 | | - for(i=0; i<(nPhrase-1); i++){ |
| 181919 | | - const u8 *dummy; |
| 181920 | | - int nByte = sqlite3Fts5ExprPoslist(pCsr->pExpr, i, &dummy); |
| 181921 | | - sqlite3Fts5BufferAppendVarint(&rc, &val, nByte); |
| 181922 | | - } |
| 181923 | | - |
| 181924 | | - /* Append the position lists */ |
| 181925 | | - for(i=0; i<nPhrase; i++){ |
| 181926 | | - const u8 *pPoslist; |
| 181927 | | - int nPoslist; |
| 181928 | | - nPoslist = sqlite3Fts5ExprPoslist(pCsr->pExpr, i, &pPoslist); |
| 181929 | | - sqlite3Fts5BufferAppendBlob(&rc, &val, nPoslist, pPoslist); |
| 183248 | + switch( ((Fts5Table*)(pCsr->base.pVtab))->pConfig->eDetail ){ |
| 183249 | + case FTS5_DETAIL_FULL: |
| 183250 | + |
| 183251 | + /* Append the varints */ |
| 183252 | + for(i=0; i<(nPhrase-1); i++){ |
| 183253 | + const u8 *dummy; |
| 183254 | + int nByte = sqlite3Fts5ExprPoslist(pCsr->pExpr, i, &dummy); |
| 183255 | + sqlite3Fts5BufferAppendVarint(&rc, &val, nByte); |
| 183256 | + } |
| 183257 | + |
| 183258 | + /* Append the position lists */ |
| 183259 | + for(i=0; i<nPhrase; i++){ |
| 183260 | + const u8 *pPoslist; |
| 183261 | + int nPoslist; |
| 183262 | + nPoslist = sqlite3Fts5ExprPoslist(pCsr->pExpr, i, &pPoslist); |
| 183263 | + sqlite3Fts5BufferAppendBlob(&rc, &val, nPoslist, pPoslist); |
| 183264 | + } |
| 183265 | + break; |
| 183266 | + |
| 183267 | + case FTS5_DETAIL_COLUMNS: |
| 183268 | + |
| 183269 | + /* Append the varints */ |
| 183270 | + for(i=0; rc==SQLITE_OK && i<(nPhrase-1); i++){ |
| 183271 | + const u8 *dummy; |
| 183272 | + int nByte; |
| 183273 | + rc = sqlite3Fts5ExprPhraseCollist(pCsr->pExpr, i, &dummy, &nByte); |
| 183274 | + sqlite3Fts5BufferAppendVarint(&rc, &val, nByte); |
| 183275 | + } |
| 183276 | + |
| 183277 | + /* Append the position lists */ |
| 183278 | + for(i=0; rc==SQLITE_OK && i<nPhrase; i++){ |
| 183279 | + const u8 *pPoslist; |
| 183280 | + int nPoslist; |
| 183281 | + rc = sqlite3Fts5ExprPhraseCollist(pCsr->pExpr, i, &pPoslist, &nPoslist); |
| 183282 | + sqlite3Fts5BufferAppendBlob(&rc, &val, nPoslist, pPoslist); |
| 183283 | + } |
| 183284 | + break; |
| 183285 | + |
| 183286 | + default: |
| 183287 | + break; |
| 181930 | 183288 | } |
| 181931 | 183289 | |
| 181932 | 183290 | sqlite3_result_blob(pCtx, val.p, val.n, sqlite3_free); |
| 181933 | 183291 | return rc; |
| 181934 | 183292 | } |
| | @@ -182247,11 +183605,11 @@ |
| 182247 | 183605 | sqlite3_context *pCtx, /* Function call context */ |
| 182248 | 183606 | int nArg, /* Number of args */ |
| 182249 | 183607 | sqlite3_value **apVal /* Function arguments */ |
| 182250 | 183608 | ){ |
| 182251 | 183609 | assert( nArg==0 ); |
| 182252 | | - sqlite3_result_text(pCtx, "fts5: 2016-01-06 11:01:07 fd0a50f0797d154fefff724624f00548b5320566", -1, SQLITE_TRANSIENT); |
| 183610 | + sqlite3_result_text(pCtx, "fts5: 2016-01-20 14:22:41 204432ee72fda8e82d244c4aa18de7ec4811b8e1", -1, SQLITE_TRANSIENT); |
| 182253 | 183611 | } |
| 182254 | 183612 | |
| 182255 | 183613 | static int fts5Init(sqlite3 *db){ |
| 182256 | 183614 | static const sqlite3_module fts5Mod = { |
| 182257 | 183615 | /* iVersion */ 2, |
| | @@ -182732,43 +184090,56 @@ |
| 182732 | 184090 | /* |
| 182733 | 184091 | ** If a row with rowid iDel is present in the %_content table, add the |
| 182734 | 184092 | ** delete-markers to the FTS index necessary to delete it. Do not actually |
| 182735 | 184093 | ** remove the %_content row at this time though. |
| 182736 | 184094 | */ |
| 182737 | | -static int fts5StorageDeleteFromIndex(Fts5Storage *p, i64 iDel){ |
| 184095 | +static int fts5StorageDeleteFromIndex( |
| 184096 | + Fts5Storage *p, |
| 184097 | + i64 iDel, |
| 184098 | + sqlite3_value **apVal |
| 184099 | +){ |
| 182738 | 184100 | Fts5Config *pConfig = p->pConfig; |
| 182739 | | - sqlite3_stmt *pSeek; /* SELECT to read row iDel from %_data */ |
| 184101 | + sqlite3_stmt *pSeek = 0; /* SELECT to read row iDel from %_data */ |
| 182740 | 184102 | int rc; /* Return code */ |
| 184103 | + int rc2; /* sqlite3_reset() return code */ |
| 184104 | + int iCol; |
| 184105 | + Fts5InsertCtx ctx; |
| 182741 | 184106 | |
| 182742 | | - rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP, &pSeek, 0); |
| 182743 | | - if( rc==SQLITE_OK ){ |
| 182744 | | - int rc2; |
| 184107 | + if( apVal==0 ){ |
| 184108 | + rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP, &pSeek, 0); |
| 184109 | + if( rc!=SQLITE_OK ) return rc; |
| 182745 | 184110 | sqlite3_bind_int64(pSeek, 1, iDel); |
| 182746 | | - if( sqlite3_step(pSeek)==SQLITE_ROW ){ |
| 182747 | | - int iCol; |
| 182748 | | - Fts5InsertCtx ctx; |
| 182749 | | - ctx.pStorage = p; |
| 182750 | | - ctx.iCol = -1; |
| 182751 | | - rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 1, iDel); |
| 182752 | | - for(iCol=1; rc==SQLITE_OK && iCol<=pConfig->nCol; iCol++){ |
| 182753 | | - if( pConfig->abUnindexed[iCol-1] ) continue; |
| 182754 | | - ctx.szCol = 0; |
| 182755 | | - rc = sqlite3Fts5Tokenize(pConfig, |
| 182756 | | - FTS5_TOKENIZE_DOCUMENT, |
| 182757 | | - (const char*)sqlite3_column_text(pSeek, iCol), |
| 182758 | | - sqlite3_column_bytes(pSeek, iCol), |
| 182759 | | - (void*)&ctx, |
| 182760 | | - fts5StorageInsertCallback |
| 182761 | | - ); |
| 182762 | | - p->aTotalSize[iCol-1] -= (i64)ctx.szCol; |
| 182763 | | - } |
| 182764 | | - p->nTotalRow--; |
| 182765 | | - } |
| 182766 | | - rc2 = sqlite3_reset(pSeek); |
| 182767 | | - if( rc==SQLITE_OK ) rc = rc2; |
| 182768 | | - } |
| 182769 | | - |
| 184111 | + if( sqlite3_step(pSeek)!=SQLITE_ROW ){ |
| 184112 | + return sqlite3_reset(pSeek); |
| 184113 | + } |
| 184114 | + } |
| 184115 | + |
| 184116 | + ctx.pStorage = p; |
| 184117 | + ctx.iCol = -1; |
| 184118 | + rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 1, iDel); |
| 184119 | + for(iCol=1; rc==SQLITE_OK && iCol<=pConfig->nCol; iCol++){ |
| 184120 | + if( pConfig->abUnindexed[iCol-1]==0 ){ |
| 184121 | + const char *zText; |
| 184122 | + int nText; |
| 184123 | + if( pSeek ){ |
| 184124 | + zText = (const char*)sqlite3_column_text(pSeek, iCol); |
| 184125 | + nText = sqlite3_column_bytes(pSeek, iCol); |
| 184126 | + }else{ |
| 184127 | + zText = (const char*)sqlite3_value_text(apVal[iCol-1]); |
| 184128 | + nText = sqlite3_value_bytes(apVal[iCol-1]); |
| 184129 | + } |
| 184130 | + ctx.szCol = 0; |
| 184131 | + rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT, |
| 184132 | + zText, nText, (void*)&ctx, fts5StorageInsertCallback |
| 184133 | + ); |
| 184134 | + p->aTotalSize[iCol-1] -= (i64)ctx.szCol; |
| 184135 | + } |
| 184136 | + } |
| 184137 | + p->nTotalRow--; |
| 184138 | + |
| 184139 | + rc2 = sqlite3_reset(pSeek); |
| 184140 | + if( rc==SQLITE_OK ) rc = rc2; |
| 182770 | 184141 | return rc; |
| 182771 | 184142 | } |
| 182772 | 184143 | |
| 182773 | 184144 | |
| 182774 | 184145 | /* |
| | @@ -182844,20 +184215,21 @@ |
| 182844 | 184215 | } |
| 182845 | 184216 | |
| 182846 | 184217 | /* |
| 182847 | 184218 | ** Remove a row from the FTS table. |
| 182848 | 184219 | */ |
| 182849 | | -static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel){ |
| 184220 | +static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel, sqlite3_value **apVal){ |
| 182850 | 184221 | Fts5Config *pConfig = p->pConfig; |
| 182851 | 184222 | int rc; |
| 182852 | 184223 | sqlite3_stmt *pDel = 0; |
| 182853 | 184224 | |
| 184225 | + assert( pConfig->eContent!=FTS5_CONTENT_NORMAL || apVal==0 ); |
| 182854 | 184226 | rc = fts5StorageLoadTotals(p, 1); |
| 182855 | 184227 | |
| 182856 | 184228 | /* Delete the index records */ |
| 182857 | 184229 | if( rc==SQLITE_OK ){ |
| 182858 | | - rc = fts5StorageDeleteFromIndex(p, iDel); |
| 184230 | + rc = fts5StorageDeleteFromIndex(p, iDel, apVal); |
| 182859 | 184231 | } |
| 182860 | 184232 | |
| 182861 | 184233 | /* Delete the %_docsize record */ |
| 182862 | 184234 | if( rc==SQLITE_OK && pConfig->bColumnsize ){ |
| 182863 | 184235 | rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_DOCSIZE, &pDel, 0); |
| | @@ -182871,65 +184243,10 @@ |
| 182871 | 184243 | /* Delete the %_content record */ |
| 182872 | 184244 | if( pConfig->eContent==FTS5_CONTENT_NORMAL ){ |
| 182873 | 184245 | if( rc==SQLITE_OK ){ |
| 182874 | 184246 | rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_CONTENT, &pDel, 0); |
| 182875 | 184247 | } |
| 182876 | | - if( rc==SQLITE_OK ){ |
| 182877 | | - sqlite3_bind_int64(pDel, 1, iDel); |
| 182878 | | - sqlite3_step(pDel); |
| 182879 | | - rc = sqlite3_reset(pDel); |
| 182880 | | - } |
| 182881 | | - } |
| 182882 | | - |
| 182883 | | - /* Write the averages record */ |
| 182884 | | - if( rc==SQLITE_OK ){ |
| 182885 | | - rc = fts5StorageSaveTotals(p); |
| 182886 | | - } |
| 182887 | | - |
| 182888 | | - return rc; |
| 182889 | | -} |
| 182890 | | - |
| 182891 | | -static int sqlite3Fts5StorageSpecialDelete( |
| 182892 | | - Fts5Storage *p, |
| 182893 | | - i64 iDel, |
| 182894 | | - sqlite3_value **apVal |
| 182895 | | -){ |
| 182896 | | - Fts5Config *pConfig = p->pConfig; |
| 182897 | | - int rc; |
| 182898 | | - sqlite3_stmt *pDel = 0; |
| 182899 | | - |
| 182900 | | - assert( pConfig->eContent!=FTS5_CONTENT_NORMAL ); |
| 182901 | | - rc = fts5StorageLoadTotals(p, 1); |
| 182902 | | - |
| 182903 | | - /* Delete the index records */ |
| 182904 | | - if( rc==SQLITE_OK ){ |
| 182905 | | - int iCol; |
| 182906 | | - Fts5InsertCtx ctx; |
| 182907 | | - ctx.pStorage = p; |
| 182908 | | - ctx.iCol = -1; |
| 182909 | | - |
| 182910 | | - rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 1, iDel); |
| 182911 | | - for(iCol=0; rc==SQLITE_OK && iCol<pConfig->nCol; iCol++){ |
| 182912 | | - if( pConfig->abUnindexed[iCol] ) continue; |
| 182913 | | - ctx.szCol = 0; |
| 182914 | | - rc = sqlite3Fts5Tokenize(pConfig, |
| 182915 | | - FTS5_TOKENIZE_DOCUMENT, |
| 182916 | | - (const char*)sqlite3_value_text(apVal[iCol]), |
| 182917 | | - sqlite3_value_bytes(apVal[iCol]), |
| 182918 | | - (void*)&ctx, |
| 182919 | | - fts5StorageInsertCallback |
| 182920 | | - ); |
| 182921 | | - p->aTotalSize[iCol] -= (i64)ctx.szCol; |
| 182922 | | - } |
| 182923 | | - p->nTotalRow--; |
| 182924 | | - } |
| 182925 | | - |
| 182926 | | - /* Delete the %_docsize record */ |
| 182927 | | - if( pConfig->bColumnsize ){ |
| 182928 | | - if( rc==SQLITE_OK ){ |
| 182929 | | - rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_DOCSIZE, &pDel, 0); |
| 182930 | | - } |
| 182931 | 184248 | if( rc==SQLITE_OK ){ |
| 182932 | 184249 | sqlite3_bind_int64(pDel, 1, iDel); |
| 182933 | 184250 | sqlite3_step(pDel); |
| 182934 | 184251 | rc = sqlite3_reset(pDel); |
| 182935 | 184252 | } |
| | @@ -183179,32 +184496,77 @@ |
| 183179 | 184496 | struct Fts5IntegrityCtx { |
| 183180 | 184497 | i64 iRowid; |
| 183181 | 184498 | int iCol; |
| 183182 | 184499 | int szCol; |
| 183183 | 184500 | u64 cksum; |
| 184501 | + Fts5Termset *pTermset; |
| 183184 | 184502 | Fts5Config *pConfig; |
| 183185 | 184503 | }; |
| 184504 | + |
| 183186 | 184505 | |
| 183187 | 184506 | /* |
| 183188 | 184507 | ** Tokenization callback used by integrity check. |
| 183189 | 184508 | */ |
| 183190 | 184509 | static int fts5StorageIntegrityCallback( |
| 183191 | | - void *pContext, /* Pointer to Fts5InsertCtx object */ |
| 184510 | + void *pContext, /* Pointer to Fts5IntegrityCtx object */ |
| 183192 | 184511 | int tflags, |
| 183193 | 184512 | const char *pToken, /* Buffer containing token */ |
| 183194 | 184513 | int nToken, /* Size of token in bytes */ |
| 183195 | 184514 | int iStart, /* Start offset of token */ |
| 183196 | 184515 | int iEnd /* End offset of token */ |
| 183197 | 184516 | ){ |
| 183198 | 184517 | Fts5IntegrityCtx *pCtx = (Fts5IntegrityCtx*)pContext; |
| 184518 | + Fts5Termset *pTermset = pCtx->pTermset; |
| 184519 | + int bPresent; |
| 184520 | + int ii; |
| 184521 | + int rc = SQLITE_OK; |
| 184522 | + int iPos; |
| 184523 | + int iCol; |
| 184524 | + |
| 183199 | 184525 | if( (tflags & FTS5_TOKEN_COLOCATED)==0 || pCtx->szCol==0 ){ |
| 183200 | 184526 | pCtx->szCol++; |
| 183201 | 184527 | } |
| 183202 | | - pCtx->cksum ^= sqlite3Fts5IndexCksum( |
| 183203 | | - pCtx->pConfig, pCtx->iRowid, pCtx->iCol, pCtx->szCol-1, pToken, nToken |
| 183204 | | - ); |
| 183205 | | - return SQLITE_OK; |
| 184528 | + |
| 184529 | + switch( pCtx->pConfig->eDetail ){ |
| 184530 | + case FTS5_DETAIL_FULL: |
| 184531 | + iPos = pCtx->szCol-1; |
| 184532 | + iCol = pCtx->iCol; |
| 184533 | + break; |
| 184534 | + |
| 184535 | + case FTS5_DETAIL_COLUMNS: |
| 184536 | + iPos = pCtx->iCol; |
| 184537 | + iCol = 0; |
| 184538 | + break; |
| 184539 | + |
| 184540 | + default: |
| 184541 | + assert( pCtx->pConfig->eDetail==FTS5_DETAIL_NONE ); |
| 184542 | + iPos = 0; |
| 184543 | + iCol = 0; |
| 184544 | + break; |
| 184545 | + } |
| 184546 | + |
| 184547 | + rc = sqlite3Fts5TermsetAdd(pTermset, 0, pToken, nToken, &bPresent); |
| 184548 | + if( rc==SQLITE_OK && bPresent==0 ){ |
| 184549 | + pCtx->cksum ^= sqlite3Fts5IndexEntryCksum( |
| 184550 | + pCtx->iRowid, iCol, iPos, 0, pToken, nToken |
| 184551 | + ); |
| 184552 | + } |
| 184553 | + |
| 184554 | + for(ii=0; rc==SQLITE_OK && ii<pCtx->pConfig->nPrefix; ii++){ |
| 184555 | + const int nChar = pCtx->pConfig->aPrefix[ii]; |
| 184556 | + int nByte = sqlite3Fts5IndexCharlenToBytelen(pToken, nToken, nChar); |
| 184557 | + if( nByte ){ |
| 184558 | + rc = sqlite3Fts5TermsetAdd(pTermset, ii+1, pToken, nByte, &bPresent); |
| 184559 | + if( bPresent==0 ){ |
| 184560 | + pCtx->cksum ^= sqlite3Fts5IndexEntryCksum( |
| 184561 | + pCtx->iRowid, iCol, iPos, ii+1, pToken, nByte |
| 184562 | + ); |
| 184563 | + } |
| 184564 | + } |
| 184565 | + } |
| 184566 | + |
| 184567 | + return rc; |
| 183206 | 184568 | } |
| 183207 | 184569 | |
| 183208 | 184570 | /* |
| 183209 | 184571 | ** Check that the contents of the FTS index match that of the %_content |
| 183210 | 184572 | ** table. Return SQLITE_OK if they do, or SQLITE_CORRUPT if not. Return |
| | @@ -183235,27 +184597,42 @@ |
| 183235 | 184597 | int i; |
| 183236 | 184598 | ctx.iRowid = sqlite3_column_int64(pScan, 0); |
| 183237 | 184599 | ctx.szCol = 0; |
| 183238 | 184600 | if( pConfig->bColumnsize ){ |
| 183239 | 184601 | rc = sqlite3Fts5StorageDocsize(p, ctx.iRowid, aColSize); |
| 184602 | + } |
| 184603 | + if( rc==SQLITE_OK && pConfig->eDetail==FTS5_DETAIL_NONE ){ |
| 184604 | + rc = sqlite3Fts5TermsetNew(&ctx.pTermset); |
| 183240 | 184605 | } |
| 183241 | 184606 | for(i=0; rc==SQLITE_OK && i<pConfig->nCol; i++){ |
| 183242 | 184607 | if( pConfig->abUnindexed[i] ) continue; |
| 183243 | 184608 | ctx.iCol = i; |
| 183244 | 184609 | ctx.szCol = 0; |
| 183245 | | - rc = sqlite3Fts5Tokenize(pConfig, |
| 183246 | | - FTS5_TOKENIZE_DOCUMENT, |
| 183247 | | - (const char*)sqlite3_column_text(pScan, i+1), |
| 183248 | | - sqlite3_column_bytes(pScan, i+1), |
| 183249 | | - (void*)&ctx, |
| 183250 | | - fts5StorageIntegrityCallback |
| 183251 | | - ); |
| 183252 | | - if( pConfig->bColumnsize && ctx.szCol!=aColSize[i] ){ |
| 184610 | + if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){ |
| 184611 | + rc = sqlite3Fts5TermsetNew(&ctx.pTermset); |
| 184612 | + } |
| 184613 | + if( rc==SQLITE_OK ){ |
| 184614 | + rc = sqlite3Fts5Tokenize(pConfig, |
| 184615 | + FTS5_TOKENIZE_DOCUMENT, |
| 184616 | + (const char*)sqlite3_column_text(pScan, i+1), |
| 184617 | + sqlite3_column_bytes(pScan, i+1), |
| 184618 | + (void*)&ctx, |
| 184619 | + fts5StorageIntegrityCallback |
| 184620 | + ); |
| 184621 | + } |
| 184622 | + if( rc==SQLITE_OK && pConfig->bColumnsize && ctx.szCol!=aColSize[i] ){ |
| 183253 | 184623 | rc = FTS5_CORRUPT; |
| 183254 | 184624 | } |
| 183255 | 184625 | aTotalSize[i] += ctx.szCol; |
| 184626 | + if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){ |
| 184627 | + sqlite3Fts5TermsetFree(ctx.pTermset); |
| 184628 | + ctx.pTermset = 0; |
| 184629 | + } |
| 183256 | 184630 | } |
| 184631 | + sqlite3Fts5TermsetFree(ctx.pTermset); |
| 184632 | + ctx.pTermset = 0; |
| 184633 | + |
| 183257 | 184634 | if( rc!=SQLITE_OK ) break; |
| 183258 | 184635 | } |
| 183259 | 184636 | rc2 = sqlite3_reset(pScan); |
| 183260 | 184637 | if( rc==SQLITE_OK ) rc = rc2; |
| 183261 | 184638 | } |
| | @@ -185777,11 +187154,11 @@ |
| 185777 | 187154 | |
| 185778 | 187155 | pCsr->rowid++; |
| 185779 | 187156 | |
| 185780 | 187157 | if( pTab->eType==FTS5_VOCAB_COL ){ |
| 185781 | 187158 | for(pCsr->iCol++; pCsr->iCol<nCol; pCsr->iCol++){ |
| 185782 | | - if( pCsr->aCnt[pCsr->iCol] ) break; |
| 187159 | + if( pCsr->aDoc[pCsr->iCol] ) break; |
| 185783 | 187160 | } |
| 185784 | 187161 | } |
| 185785 | 187162 | |
| 185786 | 187163 | if( pTab->eType==FTS5_VOCAB_ROW || pCsr->iCol>=nCol ){ |
| 185787 | 187164 | if( sqlite3Fts5IterEof(pCsr->pIter) ){ |
| | @@ -185810,28 +187187,64 @@ |
| 185810 | 187187 | i64 dummy; |
| 185811 | 187188 | const u8 *pPos; int nPos; /* Position list */ |
| 185812 | 187189 | i64 iPos = 0; /* 64-bit position read from poslist */ |
| 185813 | 187190 | int iOff = 0; /* Current offset within position list */ |
| 185814 | 187191 | |
| 185815 | | - rc = sqlite3Fts5IterPoslist(pCsr->pIter, 0, &pPos, &nPos, &dummy); |
| 185816 | | - if( rc==SQLITE_OK ){ |
| 185817 | | - if( pTab->eType==FTS5_VOCAB_ROW ){ |
| 185818 | | - while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){ |
| 185819 | | - pCsr->aCnt[0]++; |
| 185820 | | - } |
| 185821 | | - pCsr->aDoc[0]++; |
| 185822 | | - }else{ |
| 185823 | | - int iCol = -1; |
| 185824 | | - while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){ |
| 185825 | | - int ii = FTS5_POS2COLUMN(iPos); |
| 185826 | | - pCsr->aCnt[ii]++; |
| 185827 | | - if( iCol!=ii ){ |
| 185828 | | - pCsr->aDoc[ii]++; |
| 185829 | | - iCol = ii; |
| 185830 | | - } |
| 185831 | | - } |
| 185832 | | - } |
| 187192 | + switch( pCsr->pConfig->eDetail ){ |
| 187193 | + case FTS5_DETAIL_FULL: |
| 187194 | + rc = sqlite3Fts5IterPoslist(pCsr->pIter, 0, &pPos, &nPos, &dummy); |
| 187195 | + if( rc==SQLITE_OK ){ |
| 187196 | + if( pTab->eType==FTS5_VOCAB_ROW ){ |
| 187197 | + while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){ |
| 187198 | + pCsr->aCnt[0]++; |
| 187199 | + } |
| 187200 | + pCsr->aDoc[0]++; |
| 187201 | + }else{ |
| 187202 | + int iCol = -1; |
| 187203 | + while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){ |
| 187204 | + int ii = FTS5_POS2COLUMN(iPos); |
| 187205 | + pCsr->aCnt[ii]++; |
| 187206 | + if( iCol!=ii ){ |
| 187207 | + if( ii>=nCol ){ |
| 187208 | + rc = FTS5_CORRUPT; |
| 187209 | + break; |
| 187210 | + } |
| 187211 | + pCsr->aDoc[ii]++; |
| 187212 | + iCol = ii; |
| 187213 | + } |
| 187214 | + } |
| 187215 | + } |
| 187216 | + } |
| 187217 | + break; |
| 187218 | + |
| 187219 | + case FTS5_DETAIL_COLUMNS: |
| 187220 | + if( pTab->eType==FTS5_VOCAB_ROW ){ |
| 187221 | + pCsr->aDoc[0]++; |
| 187222 | + }else{ |
| 187223 | + Fts5Buffer buf = {0, 0, 0}; |
| 187224 | + rc = sqlite3Fts5IterPoslistBuffer(pCsr->pIter, &buf); |
| 187225 | + if( rc==SQLITE_OK ){ |
| 187226 | + while( 0==sqlite3Fts5PoslistNext64(buf.p, buf.n, &iOff,&iPos) ){ |
| 187227 | + assert_nc( iPos>=0 && iPos<nCol ); |
| 187228 | + if( iPos>=nCol ){ |
| 187229 | + rc = FTS5_CORRUPT; |
| 187230 | + break; |
| 187231 | + } |
| 187232 | + pCsr->aDoc[iPos]++; |
| 187233 | + } |
| 187234 | + } |
| 187235 | + sqlite3Fts5BufferFree(&buf); |
| 187236 | + } |
| 187237 | + break; |
| 187238 | + |
| 187239 | + default: |
| 187240 | + assert( pCsr->pConfig->eDetail==FTS5_DETAIL_NONE ); |
| 187241 | + pCsr->aDoc[0]++; |
| 187242 | + break; |
| 187243 | + } |
| 187244 | + |
| 187245 | + if( rc==SQLITE_OK ){ |
| 185833 | 187246 | rc = sqlite3Fts5IterNextScan(pCsr->pIter); |
| 185834 | 187247 | } |
| 185835 | 187248 | |
| 185836 | 187249 | if( rc==SQLITE_OK ){ |
| 185837 | 187250 | zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm); |
| | @@ -185842,12 +187255,12 @@ |
| 185842 | 187255 | } |
| 185843 | 187256 | } |
| 185844 | 187257 | } |
| 185845 | 187258 | } |
| 185846 | 187259 | |
| 185847 | | - if( pCsr->bEof==0 && pTab->eType==FTS5_VOCAB_COL ){ |
| 185848 | | - while( pCsr->aCnt[pCsr->iCol]==0 ) pCsr->iCol++; |
| 187260 | + if( rc==SQLITE_OK && pCsr->bEof==0 && pTab->eType==FTS5_VOCAB_COL ){ |
| 187261 | + while( pCsr->aDoc[pCsr->iCol]==0 ) pCsr->iCol++; |
| 185849 | 187262 | assert( pCsr->iCol<pCsr->pConfig->nCol ); |
| 185850 | 187263 | } |
| 185851 | 187264 | return rc; |
| 185852 | 187265 | } |
| 185853 | 187266 | |
| | @@ -185923,34 +187336,40 @@ |
| 185923 | 187336 | sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */ |
| 185924 | 187337 | sqlite3_context *pCtx, /* Context for sqlite3_result_xxx() calls */ |
| 185925 | 187338 | int iCol /* Index of column to read value from */ |
| 185926 | 187339 | ){ |
| 185927 | 187340 | Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor; |
| 187341 | + int eDetail = pCsr->pConfig->eDetail; |
| 187342 | + int eType = ((Fts5VocabTable*)(pCursor->pVtab))->eType; |
| 187343 | + i64 iVal = 0; |
| 185928 | 187344 | |
| 185929 | 187345 | if( iCol==0 ){ |
| 185930 | 187346 | sqlite3_result_text( |
| 185931 | 187347 | pCtx, (const char*)pCsr->term.p, pCsr->term.n, SQLITE_TRANSIENT |
| 185932 | 187348 | ); |
| 185933 | | - } |
| 185934 | | - else if( ((Fts5VocabTable*)(pCursor->pVtab))->eType==FTS5_VOCAB_COL ){ |
| 187349 | + }else if( eType==FTS5_VOCAB_COL ){ |
| 185935 | 187350 | assert( iCol==1 || iCol==2 || iCol==3 ); |
| 185936 | 187351 | if( iCol==1 ){ |
| 185937 | | - const char *z = pCsr->pConfig->azCol[pCsr->iCol]; |
| 185938 | | - sqlite3_result_text(pCtx, z, -1, SQLITE_STATIC); |
| 187352 | + if( eDetail!=FTS5_DETAIL_NONE ){ |
| 187353 | + const char *z = pCsr->pConfig->azCol[pCsr->iCol]; |
| 187354 | + sqlite3_result_text(pCtx, z, -1, SQLITE_STATIC); |
| 187355 | + } |
| 185939 | 187356 | }else if( iCol==2 ){ |
| 185940 | | - sqlite3_result_int64(pCtx, pCsr->aDoc[pCsr->iCol]); |
| 187357 | + iVal = pCsr->aDoc[pCsr->iCol]; |
| 185941 | 187358 | }else{ |
| 185942 | | - sqlite3_result_int64(pCtx, pCsr->aCnt[pCsr->iCol]); |
| 187359 | + iVal = pCsr->aCnt[pCsr->iCol]; |
| 185943 | 187360 | } |
| 185944 | 187361 | }else{ |
| 185945 | 187362 | assert( iCol==1 || iCol==2 ); |
| 185946 | 187363 | if( iCol==1 ){ |
| 185947 | | - sqlite3_result_int64(pCtx, pCsr->aDoc[0]); |
| 187364 | + iVal = pCsr->aDoc[0]; |
| 185948 | 187365 | }else{ |
| 185949 | | - sqlite3_result_int64(pCtx, pCsr->aCnt[0]); |
| 187366 | + iVal = pCsr->aCnt[0]; |
| 185950 | 187367 | } |
| 185951 | 187368 | } |
| 187369 | + |
| 187370 | + if( iVal>0 ) sqlite3_result_int64(pCtx, iVal); |
| 185952 | 187371 | return SQLITE_OK; |
| 185953 | 187372 | } |
| 185954 | 187373 | |
| 185955 | 187374 | /* |
| 185956 | 187375 | ** This is the xRowid method. The SQLite core calls this routine to |
| 185957 | 187376 | |