| | @@ -16,11 +16,11 @@ |
| 16 | 16 | ** if you want a wrapper to interface SQLite with your choice of programming |
| 17 | 17 | ** language. The code for the "sqlite3" command-line shell is also in a |
| 18 | 18 | ** separate file. This file contains only code for the core SQLite library. |
| 19 | 19 | ** |
| 20 | 20 | ** The content in this amalgamation comes from Fossil check-in |
| 21 | | -** 27d4a89a5ff96b7b7fc5dc9650e1269f7c7e. |
| 21 | +** c216921b115169ebfd239267b4ab5ad0fc96. |
| 22 | 22 | */ |
| 23 | 23 | #define SQLITE_CORE 1 |
| 24 | 24 | #define SQLITE_AMALGAMATION 1 |
| 25 | 25 | #ifndef SQLITE_PRIVATE |
| 26 | 26 | # define SQLITE_PRIVATE static |
| | @@ -459,11 +459,11 @@ |
| 459 | 459 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 460 | 460 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 461 | 461 | */ |
| 462 | 462 | #define SQLITE_VERSION "3.45.0" |
| 463 | 463 | #define SQLITE_VERSION_NUMBER 3045000 |
| 464 | | -#define SQLITE_SOURCE_ID "2023-12-14 16:34:47 27d4a89a5ff96b7b7fc5dc9650e1269f7c7edf91de9b9aafce40be9ecc8b95e9" |
| 464 | +#define SQLITE_SOURCE_ID "2023-12-31 12:38:43 c216921b115169ebfd239267b4ab5ad0fc960ffadce09044b68812f49110d607" |
| 465 | 465 | |
| 466 | 466 | /* |
| 467 | 467 | ** CAPI3REF: Run-Time Library Version Numbers |
| 468 | 468 | ** KEYWORDS: sqlite3_version sqlite3_sourceid |
| 469 | 469 | ** |
| | @@ -8350,13 +8350,15 @@ |
| 8350 | 8350 | ** can enter.)^ If the same thread tries to enter any mutex other |
| 8351 | 8351 | ** than an SQLITE_MUTEX_RECURSIVE more than once, the behavior is undefined. |
| 8352 | 8352 | ** |
| 8353 | 8353 | ** ^(Some systems (for example, Windows 95) do not support the operation |
| 8354 | 8354 | ** implemented by sqlite3_mutex_try(). On those systems, sqlite3_mutex_try() |
| 8355 | | -** will always return SQLITE_BUSY. The SQLite core only ever uses |
| 8356 | | -** sqlite3_mutex_try() as an optimization so this is acceptable |
| 8357 | | -** behavior.)^ |
| 8355 | +** will always return SQLITE_BUSY. In most cases the SQLite core only uses |
| 8356 | +** sqlite3_mutex_try() as an optimization, so this is acceptable |
| 8357 | +** behavior. The exceptions are unix builds that set the |
| 8358 | +** SQLITE_ENABLE_SETLK_TIMEOUT build option. In that case a working |
| 8359 | +** sqlite3_mutex_try() is required.)^ |
| 8358 | 8360 | ** |
| 8359 | 8361 | ** ^The sqlite3_mutex_leave() routine exits a mutex that was |
| 8360 | 8362 | ** previously entered by the same thread. The behavior |
| 8361 | 8363 | ** is undefined if the mutex is not currently entered by the |
| 8362 | 8364 | ** calling thread or is not currently allocated. |
| | @@ -13125,23 +13127,28 @@ |
| 13125 | 13127 | ** |
| 13126 | 13128 | ** This function may be quite inefficient if used with an FTS5 table |
| 13127 | 13129 | ** created with the "columnsize=0" option. |
| 13128 | 13130 | ** |
| 13129 | 13131 | ** xColumnText: |
| 13130 | | -** This function attempts to retrieve the text of column iCol of the |
| 13131 | | -** current document. If successful, (*pz) is set to point to a buffer |
| 13132 | +** If parameter iCol is less than zero, or greater than or equal to the |
| 13133 | +** number of columns in the table, SQLITE_RANGE is returned. |
| 13134 | +** |
| 13135 | +** Otherwise, this function attempts to retrieve the text of column iCol of |
| 13136 | +** the current document. If successful, (*pz) is set to point to a buffer |
| 13132 | 13137 | ** containing the text in utf-8 encoding, (*pn) is set to the size in bytes |
| 13133 | 13138 | ** (not characters) of the buffer and SQLITE_OK is returned. Otherwise, |
| 13134 | 13139 | ** if an error occurs, an SQLite error code is returned and the final values |
| 13135 | 13140 | ** of (*pz) and (*pn) are undefined. |
| 13136 | 13141 | ** |
| 13137 | 13142 | ** xPhraseCount: |
| 13138 | 13143 | ** Returns the number of phrases in the current query expression. |
| 13139 | 13144 | ** |
| 13140 | 13145 | ** xPhraseSize: |
| 13141 | | -** Returns the number of tokens in phrase iPhrase of the query. Phrases |
| 13142 | | -** are numbered starting from zero. |
| 13146 | +** If parameter iCol is less than zero, or greater than or equal to the |
| 13147 | +** number of phrases in the current query, as returned by xPhraseCount, |
| 13148 | +** 0 is returned. Otherwise, this function returns the number of tokens in |
| 13149 | +** phrase iPhrase of the query. Phrases are numbered starting from zero. |
| 13143 | 13150 | ** |
| 13144 | 13151 | ** xInstCount: |
| 13145 | 13152 | ** Set *pnInst to the total number of occurrences of all phrases within |
| 13146 | 13153 | ** the query within the current row. Return SQLITE_OK if successful, or |
| 13147 | 13154 | ** an error code (i.e. SQLITE_NOMEM) if an error occurs. |
| | @@ -13153,16 +13160,17 @@ |
| 13153 | 13160 | ** |
| 13154 | 13161 | ** xInst: |
| 13155 | 13162 | ** Query for the details of phrase match iIdx within the current row. |
| 13156 | 13163 | ** Phrase matches are numbered starting from zero, so the iIdx argument |
| 13157 | 13164 | ** should be greater than or equal to zero and smaller than the value |
| 13158 | | -** output by xInstCount(). |
| 13165 | +** output by xInstCount(). If iIdx is less than zero or greater than |
| 13166 | +** or equal to the value returned by xInstCount(), SQLITE_RANGE is returned. |
| 13159 | 13167 | ** |
| 13160 | | -** Usually, output parameter *piPhrase is set to the phrase number, *piCol |
| 13168 | +** Otherwise, output parameter *piPhrase is set to the phrase number, *piCol |
| 13161 | 13169 | ** to the column in which it occurs and *piOff the token offset of the |
| 13162 | | -** first token of the phrase. Returns SQLITE_OK if successful, or an error |
| 13163 | | -** code (i.e. SQLITE_NOMEM) if an error occurs. |
| 13170 | +** first token of the phrase. SQLITE_OK is returned if successful, or an |
| 13171 | +** error code (i.e. SQLITE_NOMEM) if an error occurs. |
| 13164 | 13172 | ** |
| 13165 | 13173 | ** This API can be quite slow if used with an FTS5 table created with the |
| 13166 | 13174 | ** "detail=none" or "detail=column" option. |
| 13167 | 13175 | ** |
| 13168 | 13176 | ** xRowid: |
| | @@ -13183,10 +13191,14 @@ |
| 13183 | 13191 | ** row visited, the callback function passed as the fourth argument |
| 13184 | 13192 | ** is invoked. The context and API objects passed to the callback |
| 13185 | 13193 | ** function may be used to access the properties of each matched row. |
| 13186 | 13194 | ** Invoking Api.xUserData() returns a copy of the pointer passed as |
| 13187 | 13195 | ** the third argument to pUserData. |
| 13196 | +** |
| 13197 | +** If parameter iPhrase is less than zero, or greater than or equal to |
| 13198 | +** the number of phrases in the query, as returned by xPhraseCount(), |
| 13199 | +** this function returns SQLITE_RANGE. |
| 13188 | 13200 | ** |
| 13189 | 13201 | ** If the callback function returns any value other than SQLITE_OK, the |
| 13190 | 13202 | ** query is abandoned and the xQueryPhrase function returns immediately. |
| 13191 | 13203 | ** If the returned value is SQLITE_DONE, xQueryPhrase returns SQLITE_OK. |
| 13192 | 13204 | ** Otherwise, the error code is propagated upwards. |
| | @@ -13304,22 +13316,30 @@ |
| 13304 | 13316 | ** xQueryToken(pFts5, iPhrase, iToken, ppToken, pnToken) |
| 13305 | 13317 | ** This is used to access token iToken of phrase iPhrase of the current |
| 13306 | 13318 | ** query. Before returning, output parameter *ppToken is set to point |
| 13307 | 13319 | ** to a buffer containing the requested token, and *pnToken to the |
| 13308 | 13320 | ** size of this buffer in bytes. |
| 13321 | +** |
| 13322 | +** If iPhrase or iToken are less than zero, or if iPhrase is greater than |
| 13323 | +** or equal to the number of phrases in the query as reported by |
| 13324 | +** xPhraseCount(), or if iToken is equal to or greater than the number of |
| 13325 | +** tokens in the phrase, SQLITE_RANGE is returned and *ppToken and *pnToken |
| 13326 | + are both zeroed. |
| 13309 | 13327 | ** |
| 13310 | 13328 | ** The output text is not a copy of the query text that specified the |
| 13311 | 13329 | ** token. It is the output of the tokenizer module. For tokendata=1 |
| 13312 | 13330 | ** tables, this includes any embedded 0x00 and trailing data. |
| 13313 | 13331 | ** |
| 13314 | 13332 | ** xInstToken(pFts5, iIdx, iToken, ppToken, pnToken) |
| 13315 | 13333 | ** This is used to access token iToken of phrase hit iIdx within the |
| 13316 | | -** current row. Output variable (*ppToken) is set to point to a buffer |
| 13317 | | -** containing the matching document token, and (*pnToken) to the size |
| 13318 | | -** of that buffer in bytes. This API is not available if the specified |
| 13319 | | -** token matches a prefix query term. In that case both output variables |
| 13320 | | -** are always set to 0. |
| 13334 | +** current row. If iIdx is less than zero or greater than or equal to the |
| 13335 | +** value returned by xInstCount(), SQLITE_RANGE is returned. Otherwise, |
| 13336 | +** output variable (*ppToken) is set to point to a buffer containing the |
| 13337 | +** matching document token, and (*pnToken) to the size of that buffer in |
| 13338 | +** bytes. This API is not available if the specified token matches a |
| 13339 | +** prefix query term. In that case both output variables are always set |
| 13340 | +** to 0. |
| 13321 | 13341 | ** |
| 13322 | 13342 | ** The output text is not a copy of the document text that was tokenized. |
| 13323 | 13343 | ** It is the output of the tokenizer module. For tokendata=1 tables, this |
| 13324 | 13344 | ** includes any embedded 0x00 and trailing data. |
| 13325 | 13345 | ** |
| | @@ -13991,10 +14011,23 @@ |
| 13991 | 14011 | #if defined(_MSC_VER) && !defined(SQLITE_OMIT_SEH) |
| 13992 | 14012 | # define SQLITE_USE_SEH 1 |
| 13993 | 14013 | #else |
| 13994 | 14014 | # undef SQLITE_USE_SEH |
| 13995 | 14015 | #endif |
| 14016 | + |
| 14017 | +/* |
| 14018 | +** Enable SQLITE_DIRECT_OVERFLOW_READ, unless the build explicitly |
| 14019 | +** disables it using -DSQLITE_DIRECT_OVERFLOW_READ=0 |
| 14020 | +*/ |
| 14021 | +#if defined(SQLITE_DIRECT_OVERFLOW_READ) && SQLITE_DIRECT_OVERFLOW_READ+1==1 |
| 14022 | + /* Disable if -DSQLITE_DIRECT_OVERFLOW_READ=0 */ |
| 14023 | +# undef SQLITE_DIRECT_OVERFLOW_READ |
| 14024 | +#else |
| 14025 | + /* In all other cases, enable */ |
| 14026 | +# define SQLITE_DIRECT_OVERFLOW_READ 1 |
| 14027 | +#endif |
| 14028 | + |
| 13996 | 14029 | |
| 13997 | 14030 | /* |
| 13998 | 14031 | ** The SQLITE_THREADSAFE macro must be defined as 0, 1, or 2. |
| 13999 | 14032 | ** 0 means mutexes are permanently disable and the library is never |
| 14000 | 14033 | ** threadsafe. 1 means the library is serialized which is the highest |
| | @@ -15874,11 +15907,11 @@ |
| 15874 | 15907 | SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager*); |
| 15875 | 15908 | SQLITE_PRIVATE sqlite3_file *sqlite3PagerJrnlFile(Pager*); |
| 15876 | 15909 | SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager*); |
| 15877 | 15910 | SQLITE_PRIVATE void *sqlite3PagerTempSpace(Pager*); |
| 15878 | 15911 | SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager*); |
| 15879 | | -SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *, int, int, int *); |
| 15912 | +SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *, int, int, u64*); |
| 15880 | 15913 | SQLITE_PRIVATE void sqlite3PagerClearCache(Pager*); |
| 15881 | 15914 | SQLITE_PRIVATE int sqlite3SectorSize(sqlite3_file *); |
| 15882 | 15915 | |
| 15883 | 15916 | /* Functions used to truncate the database file. */ |
| 15884 | 15917 | SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager*,Pgno); |
| | @@ -18630,10 +18663,11 @@ |
| 18630 | 18663 | unsigned isResized:1; /* True if resizeIndexObject() has been called */ |
| 18631 | 18664 | unsigned isCovering:1; /* True if this is a covering index */ |
| 18632 | 18665 | unsigned noSkipScan:1; /* Do not try to use skip-scan if true */ |
| 18633 | 18666 | unsigned hasStat1:1; /* aiRowLogEst values come from sqlite_stat1 */ |
| 18634 | 18667 | unsigned bNoQuery:1; /* Do not use this index to optimize queries */ |
| 18668 | + unsigned bSlow:1; /* This index is not good for equality lookups */ |
| 18635 | 18669 | unsigned bAscKeyBug:1; /* True if the bba7b69f9849b5bf bug applies */ |
| 18636 | 18670 | unsigned bHasVCol:1; /* Index references one or more VIRTUAL columns */ |
| 18637 | 18671 | unsigned bHasExpr:1; /* Index contains an expression, either a literal |
| 18638 | 18672 | ** expression, or a reference to a VIRTUAL column */ |
| 18639 | 18673 | #ifdef SQLITE_ENABLE_STAT4 |
| | @@ -24028,11 +24062,11 @@ |
| 24028 | 24062 | /* no break */ deliberate_fall_through |
| 24029 | 24063 | case SQLITE_DBSTATUS_CACHE_HIT: |
| 24030 | 24064 | case SQLITE_DBSTATUS_CACHE_MISS: |
| 24031 | 24065 | case SQLITE_DBSTATUS_CACHE_WRITE:{ |
| 24032 | 24066 | int i; |
| 24033 | | - int nRet = 0; |
| 24067 | + u64 nRet = 0; |
| 24034 | 24068 | assert( SQLITE_DBSTATUS_CACHE_MISS==SQLITE_DBSTATUS_CACHE_HIT+1 ); |
| 24035 | 24069 | assert( SQLITE_DBSTATUS_CACHE_WRITE==SQLITE_DBSTATUS_CACHE_HIT+2 ); |
| 24036 | 24070 | |
| 24037 | 24071 | for(i=0; i<db->nDb; i++){ |
| 24038 | 24072 | if( db->aDb[i].pBt ){ |
| | @@ -24041,11 +24075,11 @@ |
| 24041 | 24075 | } |
| 24042 | 24076 | } |
| 24043 | 24077 | *pHighwater = 0; /* IMP: R-42420-56072 */ |
| 24044 | 24078 | /* IMP: R-54100-20147 */ |
| 24045 | 24079 | /* IMP: R-29431-39229 */ |
| 24046 | | - *pCurrent = nRet; |
| 24080 | + *pCurrent = (int)nRet & 0x7fffffff; |
| 24047 | 24081 | break; |
| 24048 | 24082 | } |
| 24049 | 24083 | |
| 24050 | 24084 | /* Set *pCurrent to non-zero if there are unresolved deferred foreign |
| 24051 | 24085 | ** key constraints. Set *pCurrent to zero if all foreign key constraints |
| | @@ -34677,11 +34711,11 @@ |
| 34677 | 34711 | ** Load the sqlite3.iSysErrno field if that is an appropriate thing |
| 34678 | 34712 | ** to do based on the SQLite error code in rc. |
| 34679 | 34713 | */ |
| 34680 | 34714 | SQLITE_PRIVATE void sqlite3SystemError(sqlite3 *db, int rc){ |
| 34681 | 34715 | if( rc==SQLITE_IOERR_NOMEM ) return; |
| 34682 | | -#ifdef SQLITE_USE_SEH |
| 34716 | +#if defined(SQLITE_USE_SEH) && !defined(SQLITE_OMIT_WAL) |
| 34683 | 34717 | if( rc==SQLITE_IOERR_IN_PAGE ){ |
| 34684 | 34718 | int ii; |
| 34685 | 34719 | int iErr; |
| 34686 | 34720 | sqlite3BtreeEnterAll(db); |
| 34687 | 34721 | for(ii=0; ii<db->nDb; ii++){ |
| | @@ -42365,13 +42399,19 @@ |
| 42365 | 42399 | struct flock f; /* The posix advisory locking structure */ |
| 42366 | 42400 | int rc = SQLITE_OK; /* Result code form fcntl() */ |
| 42367 | 42401 | |
| 42368 | 42402 | pShmNode = pFile->pInode->pShmNode; |
| 42369 | 42403 | |
| 42370 | | - /* Assert that the correct mutex or mutexes are held. */ |
| 42371 | | - if( pShmNode->nRef==0 ){ |
| 42372 | | - assert( ofst==UNIX_SHM_DMS && n==1 && unixMutexHeld() ); |
| 42404 | + /* Assert that the parameters are within expected range and that the |
| 42405 | + ** correct mutex or mutexes are held. */ |
| 42406 | + assert( pShmNode->nRef>=0 ); |
| 42407 | + assert( (ofst==UNIX_SHM_DMS && n==1) |
| 42408 | + || (ofst>=UNIX_SHM_BASE && ofst+n<=(UNIX_SHM_BASE+SQLITE_SHM_NLOCK)) |
| 42409 | + ); |
| 42410 | + if( ofst==UNIX_SHM_DMS ){ |
| 42411 | + assert( pShmNode->nRef>0 || unixMutexHeld() ); |
| 42412 | + assert( pShmNode->nRef==0 || sqlite3_mutex_held(pShmNode->pShmMutex) ); |
| 42373 | 42413 | }else{ |
| 42374 | 42414 | #ifdef SQLITE_ENABLE_SETLK_TIMEOUT |
| 42375 | 42415 | int ii; |
| 42376 | 42416 | for(ii=ofst-UNIX_SHM_BASE; ii<ofst-UNIX_SHM_BASE+n; ii++){ |
| 42377 | 42417 | assert( sqlite3_mutex_held(pShmNode->aMutex[ii]) ); |
| | @@ -57333,11 +57373,11 @@ |
| 57333 | 57373 | i64 journalSizeLimit; /* Size limit for persistent journal files */ |
| 57334 | 57374 | char *zFilename; /* Name of the database file */ |
| 57335 | 57375 | char *zJournal; /* Name of the journal file */ |
| 57336 | 57376 | int (*xBusyHandler)(void*); /* Function to call when busy */ |
| 57337 | 57377 | void *pBusyHandlerArg; /* Context argument for xBusyHandler */ |
| 57338 | | - int aStat[4]; /* Total cache hits, misses, writes, spills */ |
| 57378 | + u32 aStat[4]; /* Total cache hits, misses, writes, spills */ |
| 57339 | 57379 | #ifdef SQLITE_TEST |
| 57340 | 57380 | int nRead; /* Database pages read */ |
| 57341 | 57381 | #endif |
| 57342 | 57382 | void (*xReiniter)(DbPage*); /* Call this routine when reloading pages */ |
| 57343 | 57383 | int (*xGet)(Pager*,Pgno,DbPage**,int); /* Routine to fetch a patch */ |
| | @@ -63477,15 +63517,15 @@ |
| 63477 | 63517 | a[1] = sqlite3PcachePagecount(pPager->pPCache); |
| 63478 | 63518 | a[2] = sqlite3PcacheGetCachesize(pPager->pPCache); |
| 63479 | 63519 | a[3] = pPager->eState==PAGER_OPEN ? -1 : (int) pPager->dbSize; |
| 63480 | 63520 | a[4] = pPager->eState; |
| 63481 | 63521 | a[5] = pPager->errCode; |
| 63482 | | - a[6] = pPager->aStat[PAGER_STAT_HIT]; |
| 63483 | | - a[7] = pPager->aStat[PAGER_STAT_MISS]; |
| 63522 | + a[6] = (int)pPager->aStat[PAGER_STAT_HIT] & 0x7fffffff; |
| 63523 | + a[7] = (int)pPager->aStat[PAGER_STAT_MISS] & 0x7fffffff; |
| 63484 | 63524 | a[8] = 0; /* Used to be pPager->nOvfl */ |
| 63485 | 63525 | a[9] = pPager->nRead; |
| 63486 | | - a[10] = pPager->aStat[PAGER_STAT_WRITE]; |
| 63526 | + a[10] = (int)pPager->aStat[PAGER_STAT_WRITE] & 0x7fffffff; |
| 63487 | 63527 | return a; |
| 63488 | 63528 | } |
| 63489 | 63529 | #endif |
| 63490 | 63530 | |
| 63491 | 63531 | /* |
| | @@ -63497,11 +63537,11 @@ |
| 63497 | 63537 | ** Before returning, *pnVal is incremented by the |
| 63498 | 63538 | ** current cache hit or miss count, according to the value of eStat. If the |
| 63499 | 63539 | ** reset parameter is non-zero, the cache hit or miss count is zeroed before |
| 63500 | 63540 | ** returning. |
| 63501 | 63541 | */ |
| 63502 | | -SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *pPager, int eStat, int reset, int *pnVal){ |
| 63542 | +SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *pPager, int eStat, int reset, u64 *pnVal){ |
| 63503 | 63543 | |
| 63504 | 63544 | assert( eStat==SQLITE_DBSTATUS_CACHE_HIT |
| 63505 | 63545 | || eStat==SQLITE_DBSTATUS_CACHE_MISS |
| 63506 | 63546 | || eStat==SQLITE_DBSTATUS_CACHE_WRITE |
| 63507 | 63547 | || eStat==SQLITE_DBSTATUS_CACHE_WRITE+1 |
| | @@ -64437,11 +64477,11 @@ |
| 64437 | 64477 | assert( pPager->eState>=PAGER_READER ); |
| 64438 | 64478 | return sqlite3WalFramesize(pPager->pWal); |
| 64439 | 64479 | } |
| 64440 | 64480 | #endif |
| 64441 | 64481 | |
| 64442 | | -#ifdef SQLITE_USE_SEH |
| 64482 | +#if defined(SQLITE_USE_SEH) && !defined(SQLITE_OMIT_WAL) |
| 64443 | 64483 | SQLITE_PRIVATE int sqlite3PagerWalSystemErrno(Pager *pPager){ |
| 64444 | 64484 | return sqlite3WalSystemErrno(pPager->pWal); |
| 64445 | 64485 | } |
| 64446 | 64486 | #endif |
| 64447 | 64487 | |
| | @@ -106789,10 +106829,11 @@ |
| 106789 | 106829 | sqlite3ErrorMsg(pParse, "%s: %s", zErr, zCol); |
| 106790 | 106830 | } |
| 106791 | 106831 | sqlite3RecordErrorOffsetOfExpr(pParse->db, pExpr); |
| 106792 | 106832 | pParse->checkSchema = 1; |
| 106793 | 106833 | pTopNC->nNcErr++; |
| 106834 | + eNewExprOp = TK_NULL; |
| 106794 | 106835 | } |
| 106795 | 106836 | assert( pFJMatch==0 ); |
| 106796 | 106837 | |
| 106797 | 106838 | /* Remove all substructure from pExpr */ |
| 106798 | 106839 | if( !ExprHasProperty(pExpr,(EP_TokenOnly|EP_Leaf)) ){ |
| | @@ -110976,13 +111017,14 @@ |
| 110976 | 111017 | case TK_BLOB: |
| 110977 | 111018 | return 0; |
| 110978 | 111019 | case TK_COLUMN: |
| 110979 | 111020 | assert( ExprUseYTab(p) ); |
| 110980 | 111021 | return ExprHasProperty(p, EP_CanBeNull) || |
| 110981 | | - p->y.pTab==0 || /* Reference to column of index on expression */ |
| 111022 | + NEVER(p->y.pTab==0) || /* Reference to column of index on expr */ |
| 110982 | 111023 | (p->iColumn>=0 |
| 110983 | 111024 | && p->y.pTab->aCol!=0 /* Possible due to prior error */ |
| 111025 | + && ALWAYS(p->iColumn<p->y.pTab->nCol) |
| 110984 | 111026 | && p->y.pTab->aCol[p->iColumn].notNull==0); |
| 110985 | 111027 | default: |
| 110986 | 111028 | return 1; |
| 110987 | 111029 | } |
| 110988 | 111030 | } |
| | @@ -113560,12 +113602,14 @@ |
| 113560 | 113602 | assert( pParse->pVdbe!=0 || pParse->db->mallocFailed ); |
| 113561 | 113603 | if( pParse->pVdbe==0 ) return; |
| 113562 | 113604 | inReg = sqlite3ExprCodeTarget(pParse, pExpr, target); |
| 113563 | 113605 | if( inReg!=target ){ |
| 113564 | 113606 | u8 op; |
| 113565 | | - if( ALWAYS(pExpr) |
| 113566 | | - && (ExprHasProperty(pExpr,EP_Subquery) || pExpr->op==TK_REGISTER) |
| 113607 | + Expr *pX = sqlite3ExprSkipCollateAndLikely(pExpr); |
| 113608 | + testcase( pX!=pExpr ); |
| 113609 | + if( ALWAYS(pX) |
| 113610 | + && (ExprHasProperty(pX,EP_Subquery) || pX->op==TK_REGISTER) |
| 113567 | 113611 | ){ |
| 113568 | 113612 | op = OP_Copy; |
| 113569 | 113613 | }else{ |
| 113570 | 113614 | op = OP_SCopy; |
| 113571 | 113615 | } |
| | @@ -117827,10 +117871,11 @@ |
| 117827 | 117871 | typedef struct StatAccum StatAccum; |
| 117828 | 117872 | typedef struct StatSample StatSample; |
| 117829 | 117873 | struct StatSample { |
| 117830 | 117874 | tRowcnt *anEq; /* sqlite_stat4.nEq */ |
| 117831 | 117875 | tRowcnt *anDLt; /* sqlite_stat4.nDLt */ |
| 117876 | + tRowcnt *amxEq; /* Maximum length run of equal values */ |
| 117832 | 117877 | #ifdef SQLITE_ENABLE_STAT4 |
| 117833 | 117878 | tRowcnt *anLt; /* sqlite_stat4.nLt */ |
| 117834 | 117879 | union { |
| 117835 | 117880 | i64 iRowid; /* Rowid in main table of the key */ |
| 117836 | 117881 | u8 *aRowid; /* Key for WITHOUT ROWID tables */ |
| | @@ -117986,10 +118031,11 @@ |
| 117986 | 118031 | assert( nKeyCol>0 ); |
| 117987 | 118032 | |
| 117988 | 118033 | /* Allocate the space required for the StatAccum object */ |
| 117989 | 118034 | n = sizeof(*p) |
| 117990 | 118035 | + sizeof(tRowcnt)*nColUp /* StatAccum.anEq */ |
| 118036 | + + sizeof(tRowcnt)*nColUp /* StatAccum.amxEq */ |
| 117991 | 118037 | + sizeof(tRowcnt)*nColUp; /* StatAccum.anDLt */ |
| 117992 | 118038 | #ifdef SQLITE_ENABLE_STAT4 |
| 117993 | 118039 | if( mxSample ){ |
| 117994 | 118040 | n += sizeof(tRowcnt)*nColUp /* StatAccum.anLt */ |
| 117995 | 118041 | + sizeof(StatSample)*(nCol+mxSample) /* StatAccum.aBest[], a[] */ |
| | @@ -118008,11 +118054,12 @@ |
| 118008 | 118054 | p->nLimit = sqlite3_value_int64(argv[3]); |
| 118009 | 118055 | p->nCol = nCol; |
| 118010 | 118056 | p->nKeyCol = nKeyCol; |
| 118011 | 118057 | p->nSkipAhead = 0; |
| 118012 | 118058 | p->current.anDLt = (tRowcnt*)&p[1]; |
| 118013 | | - p->current.anEq = &p->current.anDLt[nColUp]; |
| 118059 | + p->current.amxEq = &p->current.anDLt[nColUp]; |
| 118060 | + p->current.anEq = &p->current.amxEq[nColUp]; |
| 118014 | 118061 | |
| 118015 | 118062 | #ifdef SQLITE_ENABLE_STAT4 |
| 118016 | 118063 | p->mxSample = p->nLimit==0 ? mxSample : 0; |
| 118017 | 118064 | if( mxSample ){ |
| 118018 | 118065 | u8 *pSpace; /* Allocated space not yet assigned */ |
| | @@ -118277,11 +118324,14 @@ |
| 118277 | 118324 | assert( p->nCol>0 ); |
| 118278 | 118325 | assert( iChng<p->nCol ); |
| 118279 | 118326 | |
| 118280 | 118327 | if( p->nRow==0 ){ |
| 118281 | 118328 | /* This is the first call to this function. Do initialization. */ |
| 118282 | | - for(i=0; i<p->nCol; i++) p->current.anEq[i] = 1; |
| 118329 | + for(i=0; i<p->nCol; i++){ |
| 118330 | + p->current.anEq[i] = 1; |
| 118331 | + p->current.amxEq[i] = 1; |
| 118332 | + } |
| 118283 | 118333 | }else{ |
| 118284 | 118334 | /* Second and subsequent calls get processed here */ |
| 118285 | 118335 | #ifdef SQLITE_ENABLE_STAT4 |
| 118286 | 118336 | if( p->mxSample ) samplePushPrevious(p, iChng); |
| 118287 | 118337 | #endif |
| | @@ -118294,10 +118344,13 @@ |
| 118294 | 118344 | for(i=iChng; i<p->nCol; i++){ |
| 118295 | 118345 | p->current.anDLt[i]++; |
| 118296 | 118346 | #ifdef SQLITE_ENABLE_STAT4 |
| 118297 | 118347 | if( p->mxSample ) p->current.anLt[i] += p->current.anEq[i]; |
| 118298 | 118348 | #endif |
| 118349 | + if( p->current.amxEq[i]<p->current.anEq[i] ){ |
| 118350 | + p->current.amxEq[i] = p->current.anEq[i]; |
| 118351 | + } |
| 118299 | 118352 | p->current.anEq[i] = 1; |
| 118300 | 118353 | } |
| 118301 | 118354 | } |
| 118302 | 118355 | |
| 118303 | 118356 | p->nRow++; |
| | @@ -118402,37 +118455,65 @@ |
| 118402 | 118455 | ** for each indexed column. This additional integer is an estimate of |
| 118403 | 118456 | ** the number of rows matched by a equality query on the index using |
| 118404 | 118457 | ** a key with the corresponding number of fields. In other words, |
| 118405 | 118458 | ** if the index is on columns (a,b) and the sqlite_stat1 value is |
| 118406 | 118459 | ** "100 10 2", then SQLite estimates that: |
| 118407 | | - ** |
| 118408 | | - ** * the index contains 100 rows, |
| 118409 | | - ** * "WHERE a=?" matches 10 rows, and |
| 118410 | | - ** * "WHERE a=? AND b=?" matches 2 rows. |
| 118460 | + ** | | | |
| 118461 | + ** | | `-- "WHERE a=? AND b=?" matches approximately 2 rows |
| 118462 | + ** | `---- "WHERE a=?" matches approximately 10 rows |
| 118463 | + ** `-------- There are approximately 100 rows in the index total |
| 118411 | 118464 | ** |
| 118412 | 118465 | ** If D is the count of distinct values and K is the total number of |
| 118413 | 118466 | ** rows, then each estimate is usually computed as: |
| 118414 | 118467 | ** |
| 118415 | 118468 | ** I = (K+D-1)/D |
| 118416 | 118469 | ** |
| 118417 | | - ** In other words, I is K/D rounded up to the next whole integer. |
| 118418 | | - ** However, if I is between 1.0 and 1.1 (in other words if I is |
| 118419 | | - ** close to 1.0 but just a little larger) then do not round up but |
| 118420 | | - ** instead keep the I value at 1.0. |
| 118470 | + ** Adjustments to the I value are made in some cases. See comments |
| 118471 | + ** in-line below. |
| 118421 | 118472 | */ |
| 118422 | 118473 | sqlite3_str sStat; /* Text of the constructed "stat" line */ |
| 118423 | 118474 | int i; /* Loop counter */ |
| 118475 | + int iUneven = 1; /* max/avg */ |
| 118476 | + u64 nRow; /* Number of rows in the index */ |
| 118424 | 118477 | |
| 118425 | 118478 | sqlite3StrAccumInit(&sStat, 0, 0, 0, (p->nKeyCol+1)*100); |
| 118426 | | - sqlite3_str_appendf(&sStat, "%llu", |
| 118427 | | - p->nSkipAhead ? (u64)p->nEst : (u64)p->nRow); |
| 118479 | + nRow = p->nSkipAhead ? p->nEst : p->nRow; |
| 118480 | + sqlite3_str_appendf(&sStat, "%llu", nRow); |
| 118428 | 118481 | for(i=0; i<p->nKeyCol; i++){ |
| 118429 | 118482 | u64 nDistinct = p->current.anDLt[i] + 1; |
| 118430 | 118483 | u64 iVal = (p->nRow + nDistinct - 1) / nDistinct; |
| 118431 | | - if( iVal==2 && p->nRow*10 <= nDistinct*11 ) iVal = 1; |
| 118484 | + u64 mx = p->current.amxEq[i]; |
| 118485 | + if( nDistinct==1 && p->nLimit>0 ){ |
| 118486 | + /* If we never saw more than a single value in a PRAGMA analysis_limit |
| 118487 | + ** search, then set the estimated number of matching rows to the |
| 118488 | + ** estimated number of rows in the index. */ |
| 118489 | + iVal = p->nEst; |
| 118490 | + }else if( iVal<mx/10 ){ |
| 118491 | + /* Report uneven= if the maximum run of identical values ever |
| 118492 | + ** reaches or exceeds 10 times the average run */ |
| 118493 | + int iRatio = mx/iVal; |
| 118494 | + if( iUneven<iRatio ) iUneven = iRatio; |
| 118495 | + }else if( iVal==2 && p->nRow*10 <= nDistinct*11 ){ |
| 118496 | + /* If the value is less than or equal to 1.1, round it down to 1.0 */ |
| 118497 | + iVal = 1; |
| 118498 | + } |
| 118432 | 118499 | sqlite3_str_appendf(&sStat, " %llu", iVal); |
| 118433 | 118500 | assert( p->current.anEq[i] ); |
| 118501 | + |
| 118502 | + /* Add the "slow" argument if the peak number of rows obtained |
| 118503 | + ** from a full equality match is so large that a full table scan |
| 118504 | + ** seems likely to be faster. |
| 118505 | + */ |
| 118506 | + if( i==p->nKeyCol-1 |
| 118507 | + && nRow > 1000 |
| 118508 | + && nRow <= iVal*iUneven + sqlite3LogEst(nRow*2/3) |
| 118509 | + ){ |
| 118510 | + sqlite3_str_appendf(&sStat, " slow"); |
| 118511 | + } |
| 118512 | + } |
| 118513 | + if( iUneven>1 ){ |
| 118514 | + sqlite3_str_appendf(&sStat, " uneven=%d", iUneven); |
| 118434 | 118515 | } |
| 118435 | 118516 | sqlite3ResultStrAccum(context, &sStat); |
| 118436 | 118517 | } |
| 118437 | 118518 | #ifdef SQLITE_ENABLE_STAT4 |
| 118438 | 118519 | else if( eCall==STAT_GET_ROWID ){ |
| | @@ -119075,11 +119156,11 @@ |
| 119075 | 119156 | #ifdef SQLITE_ENABLE_STAT4 |
| 119076 | 119157 | if( z==0 ) z = ""; |
| 119077 | 119158 | #else |
| 119078 | 119159 | assert( z!=0 ); |
| 119079 | 119160 | #endif |
| 119080 | | - for(i=0; *z && i<nOut; i++){ |
| 119161 | + for(i=0; i<nOut; i++){ |
| 119081 | 119162 | v = 0; |
| 119082 | 119163 | while( (c=z[0])>='0' && c<='9' ){ |
| 119083 | 119164 | v = v*10 + c - '0'; |
| 119084 | 119165 | z++; |
| 119085 | 119166 | } |
| | @@ -119099,19 +119180,38 @@ |
| 119099 | 119180 | #else |
| 119100 | 119181 | if( pIndex ){ |
| 119101 | 119182 | #endif |
| 119102 | 119183 | pIndex->bUnordered = 0; |
| 119103 | 119184 | pIndex->noSkipScan = 0; |
| 119185 | + pIndex->bSlow = 0; |
| 119104 | 119186 | while( z[0] ){ |
| 119105 | 119187 | if( sqlite3_strglob("unordered*", z)==0 ){ |
| 119106 | 119188 | pIndex->bUnordered = 1; |
| 119107 | 119189 | }else if( sqlite3_strglob("sz=[0-9]*", z)==0 ){ |
| 119108 | 119190 | int sz = sqlite3Atoi(z+3); |
| 119109 | 119191 | if( sz<2 ) sz = 2; |
| 119110 | 119192 | pIndex->szIdxRow = sqlite3LogEst(sz); |
| 119111 | 119193 | }else if( sqlite3_strglob("noskipscan*", z)==0 ){ |
| 119112 | 119194 | pIndex->noSkipScan = 1; |
| 119195 | + }else if( sqlite3_strglob("slow*", z)==0 ){ |
| 119196 | + pIndex->bSlow = 1; |
| 119197 | + }else if( sqlite3_strglob("uneven=[0-9]*", z)==0 ){ |
| 119198 | + /* An argument of "uneven=NNN" means that the maximum length |
| 119199 | + ** run of the same value is NNN times longer than the average. |
| 119200 | + ** Go through the iaRowLogEst[] values for the index and increase |
| 119201 | + ** them so that so that they are each no less than 1/8th the |
| 119202 | + ** maximum value. */ |
| 119203 | + LogEst scale = sqlite3LogEst(sqlite3Atoi(z+7)) - 30; |
| 119204 | + if( scale>0 ){ |
| 119205 | + LogEst mx = aLog[0]; |
| 119206 | + int jj; |
| 119207 | + for(jj=1; jj<pIndex->nKeyCol; jj++){ |
| 119208 | + LogEst x = aLog[jj] + scale; |
| 119209 | + if( x>mx ) x = mx; |
| 119210 | + aLog[jj] = x; |
| 119211 | + } |
| 119212 | + } |
| 119113 | 119213 | } |
| 119114 | 119214 | #ifdef SQLITE_ENABLE_COSTMULT |
| 119115 | 119215 | else if( sqlite3_strglob("costmult=[0-9]*",z)==0 ){ |
| 119116 | 119216 | pIndex->pTable->costMult = sqlite3LogEst(sqlite3Atoi(z+9)); |
| 119117 | 119217 | } |
| | @@ -148743,11 +148843,11 @@ |
| 148743 | 148843 | pSub->pPrior = 0; |
| 148744 | 148844 | pSub->pNext = 0; |
| 148745 | 148845 | pSub->selFlags |= SF_Aggregate; |
| 148746 | 148846 | pSub->selFlags &= ~SF_Compound; |
| 148747 | 148847 | pSub->nSelectRow = 0; |
| 148748 | | - sqlite3ExprListDelete(db, pSub->pEList); |
| 148848 | + sqlite3ParserAddCleanup(pParse, sqlite3ExprListDeleteGeneric, pSub->pEList); |
| 148749 | 148849 | pTerm = pPrior ? sqlite3ExprDup(db, pCount, 0) : pCount; |
| 148750 | 148850 | pSub->pEList = sqlite3ExprListAppend(pParse, 0, pTerm); |
| 148751 | 148851 | pTerm = sqlite3PExpr(pParse, TK_SELECT, 0, 0); |
| 148752 | 148852 | sqlite3PExprAddSelect(pParse, pTerm, pSub); |
| 148753 | 148853 | if( pExpr==0 ){ |
| | @@ -154295,11 +154395,10 @@ |
| 154295 | 154395 | assert( sqlite3BtreeHoldsAllMutexes(db) ); |
| 154296 | 154396 | assert( sqlite3_mutex_held(db->mutex) ); |
| 154297 | 154397 | |
| 154298 | 154398 | if( p ){ |
| 154299 | 154399 | db->pDisconnect = 0; |
| 154300 | | - sqlite3ExpirePreparedStatements(db, 0); |
| 154301 | 154400 | do { |
| 154302 | 154401 | VTable *pNext = p->pNext; |
| 154303 | 154402 | sqlite3VtabUnlock(p); |
| 154304 | 154403 | p = pNext; |
| 154305 | 154404 | }while( p ); |
| | @@ -155861,11 +155960,11 @@ |
| 155861 | 155960 | */ |
| 155862 | 155961 | SQLITE_PRIVATE Bitmask sqlite3WhereGetMask(WhereMaskSet*,int); |
| 155863 | 155962 | #ifdef WHERETRACE_ENABLED |
| 155864 | 155963 | SQLITE_PRIVATE void sqlite3WhereClausePrint(WhereClause *pWC); |
| 155865 | 155964 | SQLITE_PRIVATE void sqlite3WhereTermPrint(WhereTerm *pTerm, int iTerm); |
| 155866 | | -SQLITE_PRIVATE void sqlite3WhereLoopPrint(WhereLoop *p, WhereClause *pWC); |
| 155965 | +SQLITE_PRIVATE void sqlite3WhereLoopPrint(const WhereLoop *p, const WhereClause *pWC); |
| 155867 | 155966 | #endif |
| 155868 | 155967 | SQLITE_PRIVATE WhereTerm *sqlite3WhereFindTerm( |
| 155869 | 155968 | WhereClause *pWC, /* The WHERE clause to be searched */ |
| 155870 | 155969 | int iCur, /* Cursor number of LHS */ |
| 155871 | 155970 | int iColumn, /* Column number of LHS */ |
| | @@ -162890,21 +162989,38 @@ |
| 162890 | 162989 | #endif |
| 162891 | 162990 | |
| 162892 | 162991 | #ifdef WHERETRACE_ENABLED |
| 162893 | 162992 | /* |
| 162894 | 162993 | ** Print a WhereLoop object for debugging purposes |
| 162994 | +** |
| 162995 | +** Format example: |
| 162996 | +** |
| 162997 | +** .--- Position in WHERE clause rSetup, rRun, nOut ---. |
| 162998 | +** | | |
| 162999 | +** | .--- selfMask nTerm ------. | |
| 163000 | +** | | | | |
| 163001 | +** | | .-- prereq Idx wsFlags----. | | |
| 163002 | +** | | | Name | | | |
| 163003 | +** | | | __|__ nEq ---. ___|__ | __|__ |
| 163004 | +** | / \ / \ / \ | / \ / \ / \ |
| 163005 | +** 1.002.001 t2.t2xy 2 f 010241 N 2 cost 0,56,31 |
| 162895 | 163006 | */ |
| 162896 | | -SQLITE_PRIVATE void sqlite3WhereLoopPrint(WhereLoop *p, WhereClause *pWC){ |
| 162897 | | - WhereInfo *pWInfo = pWC->pWInfo; |
| 162898 | | - int nb = 1+(pWInfo->pTabList->nSrc+3)/4; |
| 162899 | | - SrcItem *pItem = pWInfo->pTabList->a + p->iTab; |
| 162900 | | - Table *pTab = pItem->pTab; |
| 162901 | | - Bitmask mAll = (((Bitmask)1)<<(nb*4)) - 1; |
| 162902 | | - sqlite3DebugPrintf("%c%2d.%0*llx.%0*llx", p->cId, |
| 162903 | | - p->iTab, nb, p->maskSelf, nb, p->prereq & mAll); |
| 162904 | | - sqlite3DebugPrintf(" %12s", |
| 162905 | | - pItem->zAlias ? pItem->zAlias : pTab->zName); |
| 163007 | +SQLITE_PRIVATE void sqlite3WhereLoopPrint(const WhereLoop *p, const WhereClause *pWC){ |
| 163008 | + if( pWC ){ |
| 163009 | + WhereInfo *pWInfo = pWC->pWInfo; |
| 163010 | + int nb = 1+(pWInfo->pTabList->nSrc+3)/4; |
| 163011 | + SrcItem *pItem = pWInfo->pTabList->a + p->iTab; |
| 163012 | + Table *pTab = pItem->pTab; |
| 163013 | + Bitmask mAll = (((Bitmask)1)<<(nb*4)) - 1; |
| 163014 | + sqlite3DebugPrintf("%c%2d.%0*llx.%0*llx", p->cId, |
| 163015 | + p->iTab, nb, p->maskSelf, nb, p->prereq & mAll); |
| 163016 | + sqlite3DebugPrintf(" %12s", |
| 163017 | + pItem->zAlias ? pItem->zAlias : pTab->zName); |
| 163018 | + }else{ |
| 163019 | + sqlite3DebugPrintf("%c%2d.%03llx.%03llx %c%d", |
| 163020 | + p->cId, p->iTab, p->maskSelf, p->prereq & 0xfff, p->cId, p->iTab); |
| 163021 | + } |
| 162906 | 163022 | if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){ |
| 162907 | 163023 | const char *zName; |
| 162908 | 163024 | if( p->u.btree.pIndex && (zName = p->u.btree.pIndex->zName)!=0 ){ |
| 162909 | 163025 | if( strncmp(zName, "sqlite_autoindex_", 17)==0 ){ |
| 162910 | 163026 | int i = sqlite3Strlen30(zName) - 1; |
| | @@ -162936,10 +163052,19 @@ |
| 162936 | 163052 | int i; |
| 162937 | 163053 | for(i=0; i<p->nLTerm; i++){ |
| 162938 | 163054 | sqlite3WhereTermPrint(p->aLTerm[i], i); |
| 162939 | 163055 | } |
| 162940 | 163056 | } |
| 163057 | +} |
| 163058 | +SQLITE_PRIVATE void sqlite3ShowWhereLoop(const WhereLoop *p){ |
| 163059 | + if( p ) sqlite3WhereLoopPrint(p, 0); |
| 163060 | +} |
| 163061 | +SQLITE_PRIVATE void sqlite3ShowWhereLoopList(const WhereLoop *p){ |
| 163062 | + while( p ){ |
| 163063 | + sqlite3ShowWhereLoop(p); |
| 163064 | + p = p->pNextLoop; |
| 163065 | + } |
| 162941 | 163066 | } |
| 162942 | 163067 | #endif |
| 162943 | 163068 | |
| 162944 | 163069 | /* |
| 162945 | 163070 | ** Convert bulk memory into a valid WhereLoop that can be passed |
| | @@ -163049,50 +163174,64 @@ |
| 163049 | 163174 | } |
| 163050 | 163175 | sqlite3DbNNFreeNN(db, pWInfo); |
| 163051 | 163176 | } |
| 163052 | 163177 | |
| 163053 | 163178 | /* |
| 163054 | | -** Return TRUE if all of the following are true: |
| 163055 | | -** |
| 163056 | | -** (1) X has the same or lower cost, or returns the same or fewer rows, |
| 163057 | | -** than Y. |
| 163058 | | -** (2) X uses fewer WHERE clause terms than Y |
| 163059 | | -** (3) Every WHERE clause term used by X is also used by Y |
| 163060 | | -** (4) X skips at least as many columns as Y |
| 163061 | | -** (5) If X is a covering index, than Y is too |
| 163062 | | -** |
| 163063 | | -** Conditions (2) and (3) mean that X is a "proper subset" of Y. |
| 163064 | | -** If X is a proper subset of Y then Y is a better choice and ought |
| 163065 | | -** to have a lower cost. This routine returns TRUE when that cost |
| 163066 | | -** relationship is inverted and needs to be adjusted. Constraint (4) |
| 163067 | | -** was added because if X uses skip-scan less than Y it still might |
| 163068 | | -** deserve a lower cost even if it is a proper subset of Y. Constraint (5) |
| 163069 | | -** was added because a covering index probably deserves to have a lower cost |
| 163070 | | -** than a non-covering index even if it is a proper subset. |
| 163179 | +** Return TRUE if X is a proper subset of Y but is of equal or less cost. |
| 163180 | +** In other words, return true if all constraints of X are also part of Y |
| 163181 | +** and Y has additional constraints that might speed the search that X lacks |
| 163182 | +** but the cost of running X is not more than the cost of running Y. |
| 163183 | +** |
| 163184 | +** In other words, return true if the cost relationwship between X and Y |
| 163185 | +** is inverted and needs to be adjusted. |
| 163186 | +** |
| 163187 | +** Case 1: |
| 163188 | +** |
| 163189 | +** (1a) X and Y use the same index. |
| 163190 | +** (1b) X has fewer == terms than Y |
| 163191 | +** (1c) Neither X nor Y use skip-scan |
| 163192 | +** (1d) X does not have a a greater cost than Y |
| 163193 | +** |
| 163194 | +** Case 2: |
| 163195 | +** |
| 163196 | +** (2a) X has the same or lower cost, or returns the same or fewer rows, |
| 163197 | +** than Y. |
| 163198 | +** (2b) X uses fewer WHERE clause terms than Y |
| 163199 | +** (2c) Every WHERE clause term used by X is also used by Y |
| 163200 | +** (2d) X skips at least as many columns as Y |
| 163201 | +** (2e) If X is a covering index, than Y is too |
| 163071 | 163202 | */ |
| 163072 | 163203 | static int whereLoopCheaperProperSubset( |
| 163073 | 163204 | const WhereLoop *pX, /* First WhereLoop to compare */ |
| 163074 | 163205 | const WhereLoop *pY /* Compare against this WhereLoop */ |
| 163075 | 163206 | ){ |
| 163076 | 163207 | int i, j; |
| 163208 | + if( pX->rRun>pY->rRun && pX->nOut>pY->nOut ) return 0; /* (1d) and (2a) */ |
| 163209 | + assert( (pX->wsFlags & WHERE_VIRTUALTABLE)==0 ); |
| 163210 | + assert( (pY->wsFlags & WHERE_VIRTUALTABLE)==0 ); |
| 163211 | + if( pX->u.btree.nEq < pY->u.btree.nEq /* (1b) */ |
| 163212 | + && pX->u.btree.pIndex==pY->u.btree.pIndex /* (1a) */ |
| 163213 | + && pX->nSkip==0 && pY->nSkip==0 /* (1c) */ |
| 163214 | + ){ |
| 163215 | + return 1; /* Case 1 is true */ |
| 163216 | + } |
| 163077 | 163217 | if( pX->nLTerm-pX->nSkip >= pY->nLTerm-pY->nSkip ){ |
| 163078 | | - return 0; /* X is not a subset of Y */ |
| 163218 | + return 0; /* (2b) */ |
| 163079 | 163219 | } |
| 163080 | | - if( pX->rRun>pY->rRun && pX->nOut>pY->nOut ) return 0; |
| 163081 | | - if( pY->nSkip > pX->nSkip ) return 0; |
| 163220 | + if( pY->nSkip > pX->nSkip ) return 0; /* (2d) */ |
| 163082 | 163221 | for(i=pX->nLTerm-1; i>=0; i--){ |
| 163083 | 163222 | if( pX->aLTerm[i]==0 ) continue; |
| 163084 | 163223 | for(j=pY->nLTerm-1; j>=0; j--){ |
| 163085 | 163224 | if( pY->aLTerm[j]==pX->aLTerm[i] ) break; |
| 163086 | 163225 | } |
| 163087 | | - if( j<0 ) return 0; /* X not a subset of Y since term X[i] not used by Y */ |
| 163226 | + if( j<0 ) return 0; /* (2c) */ |
| 163088 | 163227 | } |
| 163089 | 163228 | if( (pX->wsFlags&WHERE_IDX_ONLY)!=0 |
| 163090 | 163229 | && (pY->wsFlags&WHERE_IDX_ONLY)==0 ){ |
| 163091 | | - return 0; /* Constraint (5) */ |
| 163230 | + return 0; /* (2e) */ |
| 163092 | 163231 | } |
| 163093 | | - return 1; /* All conditions meet */ |
| 163232 | + return 1; /* Case 2 is true */ |
| 163094 | 163233 | } |
| 163095 | 163234 | |
| 163096 | 163235 | /* |
| 163097 | 163236 | ** Try to adjust the cost and number of output rows of WhereLoop pTemplate |
| 163098 | 163237 | ** upwards or downwards so that: |
| | @@ -163578,11 +163717,14 @@ |
| 163578 | 163717 | opMask = WO_LT|WO_LE; |
| 163579 | 163718 | }else{ |
| 163580 | 163719 | assert( pNew->u.btree.nBtm==0 ); |
| 163581 | 163720 | opMask = WO_EQ|WO_IN|WO_GT|WO_GE|WO_LT|WO_LE|WO_ISNULL|WO_IS; |
| 163582 | 163721 | } |
| 163583 | | - if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE); |
| 163722 | + if( pProbe->bUnordered || pProbe->bSlow ){ |
| 163723 | + if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE); |
| 163724 | + if( pProbe->bSlow ) opMask &= ~(WO_EQ|WO_IN|WO_IS); |
| 163725 | + } |
| 163584 | 163726 | |
| 163585 | 163727 | assert( pNew->u.btree.nEq<pProbe->nColumn ); |
| 163586 | 163728 | assert( pNew->u.btree.nEq<pProbe->nKeyCol |
| 163587 | 163729 | || pProbe->idxType!=SQLITE_IDXTYPE_PRIMARYKEY ); |
| 163588 | 163730 | |
| | @@ -166683,11 +166825,14 @@ |
| 166683 | 166825 | ** struct, the contents of WhereInfo.a[], the WhereClause structure |
| 166684 | 166826 | ** and the WhereMaskSet structure. Since WhereClause contains an 8-byte |
| 166685 | 166827 | ** field (type Bitmask) it must be aligned on an 8-byte boundary on |
| 166686 | 166828 | ** some architectures. Hence the ROUND8() below. |
| 166687 | 166829 | */ |
| 166688 | | - nByteWInfo = ROUND8P(sizeof(WhereInfo)+(nTabList-1)*sizeof(WhereLevel)); |
| 166830 | + nByteWInfo = ROUND8P(sizeof(WhereInfo)); |
| 166831 | + if( nTabList>1 ){ |
| 166832 | + nByteWInfo = ROUND8P(nByteWInfo + (nTabList-1)*sizeof(WhereLevel)); |
| 166833 | + } |
| 166689 | 166834 | pWInfo = sqlite3DbMallocRawNN(db, nByteWInfo + sizeof(WhereLoop)); |
| 166690 | 166835 | if( db->mallocFailed ){ |
| 166691 | 166836 | sqlite3DbFree(db, pWInfo); |
| 166692 | 166837 | pWInfo = 0; |
| 166693 | 166838 | goto whereBeginError; |
| | @@ -167245,10 +167390,15 @@ |
| 167245 | 167390 | whereBeginError: |
| 167246 | 167391 | if( pWInfo ){ |
| 167247 | 167392 | pParse->nQueryLoop = pWInfo->savedNQueryLoop; |
| 167248 | 167393 | whereInfoFree(db, pWInfo); |
| 167249 | 167394 | } |
| 167395 | +#ifdef WHERETRACE_ENABLED |
| 167396 | + /* Prevent harmless compiler warnings about debugging routines |
| 167397 | + ** being declared but never used */ |
| 167398 | + sqlite3ShowWhereLoopList(0); |
| 167399 | +#endif /* WHERETRACE_ENABLED */ |
| 167250 | 167400 | return 0; |
| 167251 | 167401 | } |
| 167252 | 167402 | |
| 167253 | 167403 | /* |
| 167254 | 167404 | ** Part of sqlite3WhereEnd() will rewrite opcodes to reference the |
| | @@ -203027,13 +203177,13 @@ |
| 203027 | 203177 | ** The original design stored all JSON as pure text, canonical RFC-8259. |
| 203028 | 203178 | ** Support for JSON-5 extensions was added with version 3.42.0 (2023-05-16). |
| 203029 | 203179 | ** All generated JSON text still conforms strictly to RFC-8259, but text |
| 203030 | 203180 | ** with JSON-5 extensions is accepted as input. |
| 203031 | 203181 | ** |
| 203032 | | -** Beginning with version 3.45.0 (pending), these routines also accept |
| 203033 | | -** BLOB values that have JSON encoded using a binary representation we |
| 203034 | | -** call JSONB. The name JSONB comes from PostgreSQL, however the on-disk |
| 203182 | +** Beginning with version 3.45.0 (circa 2024-01-01), these routines also |
| 203183 | +** accept BLOB values that have JSON encoded using a binary representation |
| 203184 | +** called "JSONB". The name JSONB comes from PostgreSQL, however the on-disk |
| 203035 | 203185 | ** format SQLite JSONB is completely different and incompatible with |
| 203036 | 203186 | ** PostgreSQL JSONB. |
| 203037 | 203187 | ** |
| 203038 | 203188 | ** Decoding and interpreting JSONB is still O(N) where N is the size of |
| 203039 | 203189 | ** the input, the same as text JSON. However, the constant of proportionality |
| | @@ -203120,10 +203270,13 @@ |
| 203120 | 203270 | ** code is between 0 and 12 and that the total size of the element |
| 203121 | 203271 | ** (header plus payload) is the same as the size of the BLOB. If those |
| 203122 | 203272 | ** checks are true, the BLOB is assumed to be JSONB and processing continues. |
| 203123 | 203273 | ** Errors are only raised if some other miscoding is discovered during |
| 203124 | 203274 | ** processing. |
| 203275 | +** |
| 203276 | +** Additional information can be found in the doc/jsonb.md file of the |
| 203277 | +** canonical SQLite source tree. |
| 203125 | 203278 | */ |
| 203126 | 203279 | #ifndef SQLITE_OMIT_JSON |
| 203127 | 203280 | /* #include "sqliteInt.h" */ |
| 203128 | 203281 | |
| 203129 | 203282 | /* JSONB element types |
| | @@ -203218,18 +203371,26 @@ |
| 203218 | 203371 | ** Magic number used for the JSON parse cache in sqlite3_get_auxdata() |
| 203219 | 203372 | */ |
| 203220 | 203373 | #define JSON_CACHE_ID (-429938) /* Cache entry */ |
| 203221 | 203374 | #define JSON_CACHE_SIZE 4 /* Max number of cache entries */ |
| 203222 | 203375 | |
| 203376 | +/* |
| 203377 | +** jsonUnescapeOneChar() returns this invalid code point if it encounters |
| 203378 | +** a syntax error. |
| 203379 | +*/ |
| 203380 | +#define JSON_INVALID_CHAR 0x99999 |
| 203381 | + |
| 203223 | 203382 | /* A cache mapping JSON text into JSONB blobs. |
| 203224 | 203383 | ** |
| 203225 | 203384 | ** Each cache entry is a JsonParse object with the following restrictions: |
| 203226 | 203385 | ** |
| 203227 | 203386 | ** * The bReadOnly flag must be set |
| 203228 | 203387 | ** |
| 203229 | 203388 | ** * The aBlob[] array must be owned by the JsonParse object. In other |
| 203230 | 203389 | ** words, nBlobAlloc must be non-zero. |
| 203390 | +** |
| 203391 | +** * eEdit and delta must be zero. |
| 203231 | 203392 | ** |
| 203232 | 203393 | ** * zJson must be an RCStr. In other words bJsonIsRCStr must be true. |
| 203233 | 203394 | */ |
| 203234 | 203395 | struct JsonCache { |
| 203235 | 203396 | sqlite3 *db; /* Database connection */ |
| | @@ -203286,27 +203447,27 @@ |
| 203286 | 203447 | ** |
| 203287 | 203448 | ** 3. Zero or more changes are made to aBlob[] (via json_remove() or |
| 203288 | 203449 | ** json_replace() or json_patch() or similar). |
| 203289 | 203450 | ** |
| 203290 | 203451 | ** 4. New JSON text is generated from the aBlob[] for output. This step |
| 203291 | | -** is skipped the function is one of the jsonb_* functions that returns |
| 203292 | | -** JSONB instead of text JSON. |
| 203452 | +** is skipped if the function is one of the jsonb_* functions that |
| 203453 | +** returns JSONB instead of text JSON. |
| 203293 | 203454 | */ |
| 203294 | 203455 | struct JsonParse { |
| 203295 | 203456 | u8 *aBlob; /* JSONB representation of JSON value */ |
| 203296 | 203457 | u32 nBlob; /* Bytes of aBlob[] actually used */ |
| 203297 | 203458 | u32 nBlobAlloc; /* Bytes allocated to aBlob[]. 0 if aBlob is external */ |
| 203298 | 203459 | char *zJson; /* Json text used for parsing */ |
| 203299 | 203460 | int nJson; /* Length of the zJson string in bytes */ |
| 203461 | + u32 nJPRef; /* Number of references to this object */ |
| 203462 | + u32 iErr; /* Error location in zJson[] */ |
| 203300 | 203463 | u16 iDepth; /* Nesting depth */ |
| 203301 | 203464 | u8 nErr; /* Number of errors seen */ |
| 203302 | 203465 | u8 oom; /* Set to true if out of memory */ |
| 203303 | 203466 | u8 bJsonIsRCStr; /* True if zJson is an RCStr */ |
| 203304 | 203467 | u8 hasNonstd; /* True if input uses non-standard features like JSON5 */ |
| 203305 | 203468 | u8 bReadOnly; /* Do not modify. */ |
| 203306 | | - u32 nJPRef; /* Number of references to this object */ |
| 203307 | | - u32 iErr; /* Error location in zJson[] */ |
| 203308 | 203469 | /* Search and edit information. See jsonLookupStep() */ |
| 203309 | 203470 | u8 eEdit; /* Edit operation to apply */ |
| 203310 | 203471 | int delta; /* Size change due to the edit */ |
| 203311 | 203472 | u32 nIns; /* Number of bytes to insert */ |
| 203312 | 203473 | u32 iLabel; /* Location of label if search landed on an object value */ |
| | @@ -203341,11 +203502,11 @@ |
| 203341 | 203502 | /************************************************************************** |
| 203342 | 203503 | ** Forward references |
| 203343 | 203504 | **************************************************************************/ |
| 203344 | 203505 | static void jsonReturnStringAsBlob(JsonString*); |
| 203345 | 203506 | static int jsonFuncArgMightBeBinary(sqlite3_value *pJson); |
| 203346 | | -static u32 jsonXlateBlobToText(const JsonParse*,u32,JsonString*); |
| 203507 | +static u32 jsonTranslateBlobToText(const JsonParse*,u32,JsonString*); |
| 203347 | 203508 | static void jsonReturnParse(sqlite3_context*,JsonParse*); |
| 203348 | 203509 | static JsonParse *jsonParseFuncArg(sqlite3_context*,sqlite3_value*,u32); |
| 203349 | 203510 | static void jsonParseFree(JsonParse*); |
| 203350 | 203511 | static u32 jsonbPayloadSize(const JsonParse*, u32, u32*); |
| 203351 | 203512 | static u32 jsonUnescapeOneChar(const char*, u32, u32*); |
| | @@ -203381,10 +203542,11 @@ |
| 203381 | 203542 | ){ |
| 203382 | 203543 | JsonCache *p; |
| 203383 | 203544 | |
| 203384 | 203545 | assert( pParse->zJson!=0 ); |
| 203385 | 203546 | assert( pParse->bJsonIsRCStr ); |
| 203547 | + assert( pParse->delta==0 ); |
| 203386 | 203548 | p = sqlite3_get_auxdata(ctx, JSON_CACHE_ID); |
| 203387 | 203549 | if( p==0 ){ |
| 203388 | 203550 | sqlite3 *db = sqlite3_context_db_handle(ctx); |
| 203389 | 203551 | p = sqlite3DbMallocZero(db, sizeof(*p)); |
| 203390 | 203552 | if( p==0 ) return SQLITE_NOMEM; |
| | @@ -203453,10 +203615,11 @@ |
| 203453 | 203615 | JsonParse *tmp = p->a[i]; |
| 203454 | 203616 | memmove(&p->a[i], &p->a[i+1], (p->nUsed-i-1)*sizeof(tmp)); |
| 203455 | 203617 | p->a[p->nUsed-1] = tmp; |
| 203456 | 203618 | i = p->nUsed - 1; |
| 203457 | 203619 | } |
| 203620 | + assert( p->a[i]->delta==0 ); |
| 203458 | 203621 | return p->a[i]; |
| 203459 | 203622 | }else{ |
| 203460 | 203623 | return 0; |
| 203461 | 203624 | } |
| 203462 | 203625 | } |
| | @@ -203621,12 +203784,37 @@ |
| 203621 | 203784 | if( z==0 ) return; |
| 203622 | 203785 | if( (N+p->nUsed+2 >= p->nAlloc) && jsonStringGrow(p,N+2)!=0 ) return; |
| 203623 | 203786 | p->zBuf[p->nUsed++] = '"'; |
| 203624 | 203787 | while( 1 /*exit-by-break*/ ){ |
| 203625 | 203788 | k = 0; |
| 203626 | | - while( k+1<N && jsonIsOk[z[k]] && jsonIsOk[z[k+1]] ){ k += 2; } /* <--, */ |
| 203627 | | - while( k<N && jsonIsOk[z[k]] ){ k++; } /* <-- loop unwound for speed */ |
| 203789 | + /* The following while() is the 4-way unwound equivalent of |
| 203790 | + ** |
| 203791 | + ** while( k<N && jsonIsOk[z[k]] ){ k++; } |
| 203792 | + */ |
| 203793 | + while( 1 /* Exit by break */ ){ |
| 203794 | + if( k+3>=N ){ |
| 203795 | + while( k<N && jsonIsOk[z[k]] ){ k++; } |
| 203796 | + break; |
| 203797 | + } |
| 203798 | + if( !jsonIsOk[z[k]] ){ |
| 203799 | + break; |
| 203800 | + } |
| 203801 | + if( !jsonIsOk[z[k+1]] ){ |
| 203802 | + k += 1; |
| 203803 | + break; |
| 203804 | + } |
| 203805 | + if( !jsonIsOk[z[k+2]] ){ |
| 203806 | + k += 2; |
| 203807 | + break; |
| 203808 | + } |
| 203809 | + if( !jsonIsOk[z[k+3]] ){ |
| 203810 | + k += 3; |
| 203811 | + break; |
| 203812 | + }else{ |
| 203813 | + k += 4; |
| 203814 | + } |
| 203815 | + } |
| 203628 | 203816 | if( k>=N ){ |
| 203629 | 203817 | if( k>0 ){ |
| 203630 | 203818 | memcpy(&p->zBuf[p->nUsed], z, k); |
| 203631 | 203819 | p->nUsed += k; |
| 203632 | 203820 | } |
| | @@ -203714,11 +203902,11 @@ |
| 203714 | 203902 | if( jsonFuncArgMightBeBinary(pValue) ){ |
| 203715 | 203903 | JsonParse px; |
| 203716 | 203904 | memset(&px, 0, sizeof(px)); |
| 203717 | 203905 | px.aBlob = (u8*)sqlite3_value_blob(pValue); |
| 203718 | 203906 | px.nBlob = sqlite3_value_bytes(pValue); |
| 203719 | | - jsonXlateBlobToText(&px, 0, p); |
| 203907 | + jsonTranslateBlobToText(&px, 0, p); |
| 203720 | 203908 | }else if( p->eErr==0 ){ |
| 203721 | 203909 | sqlite3_result_error(p->pCtx, "JSON cannot hold BLOB values", -1); |
| 203722 | 203910 | p->eErr = JSTRING_ERR; |
| 203723 | 203911 | jsonStringReset(p); |
| 203724 | 203912 | } |
| | @@ -204231,18 +204419,14 @@ |
| 204231 | 204419 | ** then set *pOp to JSONB_TEXTJ and return true. If not, do not make |
| 204232 | 204420 | ** any changes to *pOp and return false. |
| 204233 | 204421 | */ |
| 204234 | 204422 | static int jsonIs4HexB(const char *z, int *pOp){ |
| 204235 | 204423 | if( z[0]!='u' ) return 0; |
| 204236 | | - if( !sqlite3Isxdigit(z[1]) ) return 0; |
| 204237 | | - if( !sqlite3Isxdigit(z[2]) ) return 0; |
| 204238 | | - if( !sqlite3Isxdigit(z[3]) ) return 0; |
| 204239 | | - if( !sqlite3Isxdigit(z[4]) ) return 0; |
| 204424 | + if( !jsonIs4Hex(&z[1]) ) return 0; |
| 204240 | 204425 | *pOp = JSONB_TEXTJ; |
| 204241 | 204426 | return 1; |
| 204242 | 204427 | } |
| 204243 | | - |
| 204244 | 204428 | |
| 204245 | 204429 | /* |
| 204246 | 204430 | ** Check a single element of the JSONB in pParse for validity. |
| 204247 | 204431 | ** |
| 204248 | 204432 | ** The element to be checked starts at offset i and must end at on the |
| | @@ -204384,11 +204568,11 @@ |
| 204384 | 204568 | }else if( x!=JSONB_TEXT5 ){ |
| 204385 | 204569 | return j+1; |
| 204386 | 204570 | }else{ |
| 204387 | 204571 | u32 c = 0; |
| 204388 | 204572 | u32 szC = jsonUnescapeOneChar((const char*)&z[j], k-j, &c); |
| 204389 | | - if( c==0xfffd ) return j+1; |
| 204573 | + if( c==JSON_INVALID_CHAR ) return j+1; |
| 204390 | 204574 | j += szC - 1; |
| 204391 | 204575 | } |
| 204392 | 204576 | } |
| 204393 | 204577 | j++; |
| 204394 | 204578 | } |
| | @@ -204456,11 +204640,11 @@ |
| 204456 | 204640 | ** -2 '}' seen \ |
| 204457 | 204641 | ** -3 ']' seen \___ For these returns, pParse->iErr is set to |
| 204458 | 204642 | ** -4 ',' seen / the index in zJson[] of the seen character |
| 204459 | 204643 | ** -5 ':' seen / |
| 204460 | 204644 | */ |
| 204461 | | -static int jsonXlateTextToBlob(JsonParse *pParse, u32 i){ |
| 204645 | +static int jsonTranslateTextToBlob(JsonParse *pParse, u32 i){ |
| 204462 | 204646 | char c; |
| 204463 | 204647 | u32 j; |
| 204464 | 204648 | u32 iThis, iStart; |
| 204465 | 204649 | int x; |
| 204466 | 204650 | u8 t; |
| | @@ -204476,11 +204660,11 @@ |
| 204476 | 204660 | return -1; |
| 204477 | 204661 | } |
| 204478 | 204662 | iStart = pParse->nBlob; |
| 204479 | 204663 | for(j=i+1;;j++){ |
| 204480 | 204664 | u32 iBlob = pParse->nBlob; |
| 204481 | | - x = jsonXlateTextToBlob(pParse, j); |
| 204665 | + x = jsonTranslateTextToBlob(pParse, j); |
| 204482 | 204666 | if( x<=0 ){ |
| 204483 | 204667 | int op; |
| 204484 | 204668 | if( x==(-2) ){ |
| 204485 | 204669 | j = pParse->iErr; |
| 204486 | 204670 | if( pParse->nBlob!=(u32)iStart ) pParse->hasNonstd = 1; |
| | @@ -204522,19 +204706,19 @@ |
| 204522 | 204706 | if( z[j]==':' ){ |
| 204523 | 204707 | j++; |
| 204524 | 204708 | goto parse_object_value; |
| 204525 | 204709 | } |
| 204526 | 204710 | } |
| 204527 | | - x = jsonXlateTextToBlob(pParse, j); |
| 204711 | + x = jsonTranslateTextToBlob(pParse, j); |
| 204528 | 204712 | if( x!=(-5) ){ |
| 204529 | 204713 | if( x!=(-1) ) pParse->iErr = j; |
| 204530 | 204714 | return -1; |
| 204531 | 204715 | } |
| 204532 | 204716 | j = pParse->iErr+1; |
| 204533 | 204717 | } |
| 204534 | 204718 | parse_object_value: |
| 204535 | | - x = jsonXlateTextToBlob(pParse, j); |
| 204719 | + x = jsonTranslateTextToBlob(pParse, j); |
| 204536 | 204720 | if( x<=0 ){ |
| 204537 | 204721 | if( x!=(-1) ) pParse->iErr = j; |
| 204538 | 204722 | return -1; |
| 204539 | 204723 | } |
| 204540 | 204724 | j = x; |
| | @@ -204549,11 +204733,11 @@ |
| 204549 | 204733 | continue; |
| 204550 | 204734 | }else if( z[j]=='}' ){ |
| 204551 | 204735 | break; |
| 204552 | 204736 | } |
| 204553 | 204737 | } |
| 204554 | | - x = jsonXlateTextToBlob(pParse, j); |
| 204738 | + x = jsonTranslateTextToBlob(pParse, j); |
| 204555 | 204739 | if( x==(-4) ){ |
| 204556 | 204740 | j = pParse->iErr; |
| 204557 | 204741 | continue; |
| 204558 | 204742 | } |
| 204559 | 204743 | if( x==(-2) ){ |
| | @@ -204577,11 +204761,11 @@ |
| 204577 | 204761 | if( ++pParse->iDepth > JSON_MAX_DEPTH ){ |
| 204578 | 204762 | pParse->iErr = i; |
| 204579 | 204763 | return -1; |
| 204580 | 204764 | } |
| 204581 | 204765 | for(j=i+1;;j++){ |
| 204582 | | - x = jsonXlateTextToBlob(pParse, j); |
| 204766 | + x = jsonTranslateTextToBlob(pParse, j); |
| 204583 | 204767 | if( x<=0 ){ |
| 204584 | 204768 | if( x==(-3) ){ |
| 204585 | 204769 | j = pParse->iErr; |
| 204586 | 204770 | if( pParse->nBlob!=iStart ) pParse->hasNonstd = 1; |
| 204587 | 204771 | break; |
| | @@ -204601,11 +204785,11 @@ |
| 204601 | 204785 | continue; |
| 204602 | 204786 | }else if( z[j]==']' ){ |
| 204603 | 204787 | break; |
| 204604 | 204788 | } |
| 204605 | 204789 | } |
| 204606 | | - x = jsonXlateTextToBlob(pParse, j); |
| 204790 | + x = jsonTranslateTextToBlob(pParse, j); |
| 204607 | 204791 | if( x==(-4) ){ |
| 204608 | 204792 | j = pParse->iErr; |
| 204609 | 204793 | continue; |
| 204610 | 204794 | } |
| 204611 | 204795 | if( x==(-3) ){ |
| | @@ -204924,11 +205108,11 @@ |
| 204924 | 205108 | JsonParse *pParse, /* Initialize and fill this JsonParse object */ |
| 204925 | 205109 | sqlite3_context *pCtx /* Report errors here */ |
| 204926 | 205110 | ){ |
| 204927 | 205111 | int i; |
| 204928 | 205112 | const char *zJson = pParse->zJson; |
| 204929 | | - i = jsonXlateTextToBlob(pParse, 0); |
| 205113 | + i = jsonTranslateTextToBlob(pParse, 0); |
| 204930 | 205114 | if( pParse->oom ) i = -1; |
| 204931 | 205115 | if( i>0 ){ |
| 204932 | 205116 | #ifdef SQLITE_DEBUG |
| 204933 | 205117 | assert( pParse->iDepth==0 ); |
| 204934 | 205118 | if( sqlite3Config.bJsonSelfcheck ){ |
| | @@ -204969,11 +205153,11 @@ |
| 204969 | 205153 | JsonParse px; |
| 204970 | 205154 | memset(&px, 0, sizeof(px)); |
| 204971 | 205155 | jsonStringTerminate(pStr); |
| 204972 | 205156 | px.zJson = pStr->zBuf; |
| 204973 | 205157 | px.nJson = pStr->nUsed; |
| 204974 | | - (void)jsonXlateTextToBlob(&px, 0); |
| 205158 | + (void)jsonTranslateTextToBlob(&px, 0); |
| 204975 | 205159 | if( px.oom ){ |
| 204976 | 205160 | sqlite3_free(px.aBlob); |
| 204977 | 205161 | sqlite3_result_error_nomem(pStr->pCtx); |
| 204978 | 205162 | }else{ |
| 204979 | 205163 | assert( px.nBlobAlloc>0 ); |
| | @@ -205057,11 +205241,11 @@ |
| 205057 | 205241 | ** are detected. So a malformed JSONB input might either result |
| 205058 | 205242 | ** in an error, or in incorrect JSON. |
| 205059 | 205243 | ** |
| 205060 | 205244 | ** The pOut->eErr JSTRING_OOM flag is set on a OOM. |
| 205061 | 205245 | */ |
| 205062 | | -static u32 jsonXlateBlobToText( |
| 205246 | +static u32 jsonTranslateBlobToText( |
| 205063 | 205247 | const JsonParse *pParse, /* the complete parse of the JSON */ |
| 205064 | 205248 | u32 i, /* Start rendering at this index */ |
| 205065 | 205249 | JsonString *pOut /* Write JSON here */ |
| 205066 | 205250 | ){ |
| 205067 | 205251 | u32 sz, n, j, iEnd; |
| | @@ -205228,11 +205412,11 @@ |
| 205228 | 205412 | case JSONB_ARRAY: { |
| 205229 | 205413 | jsonAppendChar(pOut, '['); |
| 205230 | 205414 | j = i+n; |
| 205231 | 205415 | iEnd = j+sz; |
| 205232 | 205416 | while( j<iEnd ){ |
| 205233 | | - j = jsonXlateBlobToText(pParse, j, pOut); |
| 205417 | + j = jsonTranslateBlobToText(pParse, j, pOut); |
| 205234 | 205418 | jsonAppendChar(pOut, ','); |
| 205235 | 205419 | } |
| 205236 | 205420 | if( sz>0 ) pOut->nUsed--; |
| 205237 | 205421 | jsonAppendChar(pOut, ']'); |
| 205238 | 205422 | break; |
| | @@ -205241,11 +205425,11 @@ |
| 205241 | 205425 | int x = 0; |
| 205242 | 205426 | jsonAppendChar(pOut, '{'); |
| 205243 | 205427 | j = i+n; |
| 205244 | 205428 | iEnd = j+sz; |
| 205245 | 205429 | while( j<iEnd ){ |
| 205246 | | - j = jsonXlateBlobToText(pParse, j, pOut); |
| 205430 | + j = jsonTranslateBlobToText(pParse, j, pOut); |
| 205247 | 205431 | jsonAppendChar(pOut, (x++ & 1) ? ',' : ':'); |
| 205248 | 205432 | } |
| 205249 | 205433 | if( x & 1 ) pOut->eErr |= JSTRING_MALFORMED; |
| 205250 | 205434 | if( sz>0 ) pOut->nUsed--; |
| 205251 | 205435 | jsonAppendChar(pOut, '}'); |
| | @@ -205394,23 +205578,27 @@ |
| 205394 | 205578 | |
| 205395 | 205579 | /* |
| 205396 | 205580 | ** Input z[0..n] defines JSON escape sequence including the leading '\\'. |
| 205397 | 205581 | ** Decode that escape sequence into a single character. Write that |
| 205398 | 205582 | ** character into *piOut. Return the number of bytes in the escape sequence. |
| 205583 | +** |
| 205584 | +** If there is a syntax error of some kind (for example too few characters |
| 205585 | +** after the '\\' to complete the encoding) then *piOut is set to |
| 205586 | +** JSON_INVALID_CHAR. |
| 205399 | 205587 | */ |
| 205400 | 205588 | static u32 jsonUnescapeOneChar(const char *z, u32 n, u32 *piOut){ |
| 205401 | 205589 | assert( n>0 ); |
| 205402 | 205590 | assert( z[0]=='\\' ); |
| 205403 | 205591 | if( n<2 ){ |
| 205404 | | - *piOut = 0xFFFD; |
| 205592 | + *piOut = JSON_INVALID_CHAR; |
| 205405 | 205593 | return n; |
| 205406 | 205594 | } |
| 205407 | 205595 | switch( (u8)z[1] ){ |
| 205408 | 205596 | case 'u': { |
| 205409 | 205597 | u32 v, vlo; |
| 205410 | 205598 | if( n<6 ){ |
| 205411 | | - *piOut = 0xFFFD; |
| 205599 | + *piOut = JSON_INVALID_CHAR; |
| 205412 | 205600 | return n; |
| 205413 | 205601 | } |
| 205414 | 205602 | v = jsonHexToInt4(&z[2]); |
| 205415 | 205603 | if( (v & 0xfc00)==0xd800 |
| 205416 | 205604 | && n>=12 |
| | @@ -205436,11 +205624,11 @@ |
| 205436 | 205624 | case '"': |
| 205437 | 205625 | case '/': |
| 205438 | 205626 | case '\\':{ *piOut = z[1]; return 2; } |
| 205439 | 205627 | case 'x': { |
| 205440 | 205628 | if( n<4 ){ |
| 205441 | | - *piOut = 0xFFFD; |
| 205629 | + *piOut = JSON_INVALID_CHAR; |
| 205442 | 205630 | return n; |
| 205443 | 205631 | } |
| 205444 | 205632 | *piOut = (jsonHexToInt(z[2])<<4) | jsonHexToInt(z[3]); |
| 205445 | 205633 | return 4; |
| 205446 | 205634 | } |
| | @@ -205447,11 +205635,11 @@ |
| 205447 | 205635 | case 0xe2: |
| 205448 | 205636 | case '\r': |
| 205449 | 205637 | case '\n': { |
| 205450 | 205638 | u32 nSkip = jsonBytesToBypass(z, n); |
| 205451 | 205639 | if( nSkip==0 ){ |
| 205452 | | - *piOut = 0xFFFD; |
| 205640 | + *piOut = JSON_INVALID_CHAR; |
| 205453 | 205641 | return n; |
| 205454 | 205642 | }else if( nSkip==n ){ |
| 205455 | 205643 | *piOut = 0; |
| 205456 | 205644 | return n; |
| 205457 | 205645 | }else if( z[nSkip]=='\\' ){ |
| | @@ -205460,11 +205648,11 @@ |
| 205460 | 205648 | int sz = sqlite3Utf8ReadLimited((u8*)&z[nSkip], n-nSkip, piOut); |
| 205461 | 205649 | return nSkip + sz; |
| 205462 | 205650 | } |
| 205463 | 205651 | } |
| 205464 | 205652 | default: { |
| 205465 | | - *piOut = 0xFFFD; |
| 205653 | + *piOut = JSON_INVALID_CHAR; |
| 205466 | 205654 | return 2; |
| 205467 | 205655 | } |
| 205468 | 205656 | } |
| 205469 | 205657 | } |
| 205470 | 205658 | |
| | @@ -205823,11 +206011,11 @@ |
| 205823 | 206011 | if( NEVER(aBlob==0) ) return; |
| 205824 | 206012 | memset(&x, 0, sizeof(x)); |
| 205825 | 206013 | x.aBlob = (u8*)aBlob; |
| 205826 | 206014 | x.nBlob = nBlob; |
| 205827 | 206015 | jsonStringInit(&s, ctx); |
| 205828 | | - jsonXlateBlobToText(&x, 0, &s); |
| 206016 | + jsonTranslateBlobToText(&x, 0, &s); |
| 205829 | 206017 | jsonReturnString(&s, 0, 0); |
| 205830 | 206018 | } |
| 205831 | 206019 | |
| 205832 | 206020 | |
| 205833 | 206021 | /* |
| | @@ -205934,21 +206122,21 @@ |
| 205934 | 206122 | if( c=='\\' ){ |
| 205935 | 206123 | u32 v; |
| 205936 | 206124 | u32 szEscape = jsonUnescapeOneChar(&z[iIn], sz-iIn, &v); |
| 205937 | 206125 | if( v<=0x7f ){ |
| 205938 | 206126 | zOut[iOut++] = (char)v; |
| 205939 | | - }else if( v==0xfffd ){ |
| 205940 | | - /* Silently ignore illegal unicode */ |
| 205941 | 206127 | }else if( v<=0x7ff ){ |
| 205942 | 206128 | assert( szEscape>=2 ); |
| 205943 | 206129 | zOut[iOut++] = (char)(0xc0 | (v>>6)); |
| 205944 | 206130 | zOut[iOut++] = 0x80 | (v&0x3f); |
| 205945 | 206131 | }else if( v<0x10000 ){ |
| 205946 | 206132 | assert( szEscape>=3 ); |
| 205947 | 206133 | zOut[iOut++] = 0xe0 | (v>>12); |
| 205948 | 206134 | zOut[iOut++] = 0x80 | ((v>>6)&0x3f); |
| 205949 | 206135 | zOut[iOut++] = 0x80 | (v&0x3f); |
| 206136 | + }else if( v==JSON_INVALID_CHAR ){ |
| 206137 | + /* Silently ignore illegal unicode */ |
| 205950 | 206138 | }else{ |
| 205951 | 206139 | assert( szEscape>=4 ); |
| 205952 | 206140 | zOut[iOut++] = 0xf0 | (v>>18); |
| 205953 | 206141 | zOut[iOut++] = 0x80 | ((v>>12)&0x3f); |
| 205954 | 206142 | zOut[iOut++] = 0x80 | ((v>>6)&0x3f); |
| | @@ -206046,17 +206234,33 @@ |
| 206046 | 206234 | }else{ |
| 206047 | 206235 | jsonBlobAppendNode(pParse, JSONB_TEXTRAW, nJson, zJson); |
| 206048 | 206236 | } |
| 206049 | 206237 | break; |
| 206050 | 206238 | } |
| 206051 | | - case SQLITE_FLOAT: |
| 206239 | + case SQLITE_FLOAT: { |
| 206240 | + double r = sqlite3_value_double(pArg); |
| 206241 | + if( NEVER(sqlite3IsNaN(r)) ){ |
| 206242 | + jsonBlobAppendNode(pParse, JSONB_NULL, 0, 0); |
| 206243 | + }else{ |
| 206244 | + int n = sqlite3_value_bytes(pArg); |
| 206245 | + const char *z = (const char*)sqlite3_value_text(pArg); |
| 206246 | + if( z==0 ) return 1; |
| 206247 | + if( z[0]=='I' ){ |
| 206248 | + jsonBlobAppendNode(pParse, JSONB_FLOAT, 5, "9e999"); |
| 206249 | + }else if( z[0]=='-' && z[1]=='I' ){ |
| 206250 | + jsonBlobAppendNode(pParse, JSONB_FLOAT, 6, "-9e999"); |
| 206251 | + }else{ |
| 206252 | + jsonBlobAppendNode(pParse, JSONB_FLOAT, n, z); |
| 206253 | + } |
| 206254 | + } |
| 206255 | + break; |
| 206256 | + } |
| 206052 | 206257 | case SQLITE_INTEGER: { |
| 206053 | 206258 | int n = sqlite3_value_bytes(pArg); |
| 206054 | 206259 | const char *z = (const char*)sqlite3_value_text(pArg); |
| 206055 | | - int e = eType==SQLITE_INTEGER ? JSONB_INT : JSONB_FLOAT; |
| 206056 | 206260 | if( z==0 ) return 1; |
| 206057 | | - jsonBlobAppendNode(pParse, e, n, z); |
| 206261 | + jsonBlobAppendNode(pParse, JSONB_INT, n, z); |
| 206058 | 206262 | break; |
| 206059 | 206263 | } |
| 206060 | 206264 | } |
| 206061 | 206265 | if( pParse->oom ){ |
| 206062 | 206266 | sqlite3_result_error_nomem(ctx); |
| | @@ -206153,15 +206357,10 @@ |
| 206153 | 206357 | }else{ |
| 206154 | 206358 | jsonBadPathError(ctx, zPath); |
| 206155 | 206359 | } |
| 206156 | 206360 | return; |
| 206157 | 206361 | } |
| 206158 | | - |
| 206159 | | -/* |
| 206160 | | -** Make a copy of a JsonParse object. The copy will be editable. |
| 206161 | | -*/ |
| 206162 | | - |
| 206163 | 206362 | |
| 206164 | 206363 | /* |
| 206165 | 206364 | ** Generate a JsonParse object, containing valid JSONB in aBlob and nBlob, |
| 206166 | 206365 | ** from the SQL function argument pArg. Return a pointer to the new |
| 206167 | 206366 | ** JsonParse object. |
| | @@ -206313,11 +206512,12 @@ |
| 206313 | 206512 | sqlite3_result_blob(ctx, p->aBlob, p->nBlob, SQLITE_TRANSIENT); |
| 206314 | 206513 | } |
| 206315 | 206514 | }else{ |
| 206316 | 206515 | JsonString s; |
| 206317 | 206516 | jsonStringInit(&s, ctx); |
| 206318 | | - jsonXlateBlobToText(p, 0, &s); |
| 206517 | + p->delta = 0; |
| 206518 | + jsonTranslateBlobToText(p, 0, &s); |
| 206319 | 206519 | jsonReturnString(&s, p, ctx); |
| 206320 | 206520 | sqlite3_result_subtype(ctx, JSON_SUBTYPE); |
| 206321 | 206521 | } |
| 206322 | 206522 | } |
| 206323 | 206523 | |
| | @@ -206333,29 +206533,32 @@ |
| 206333 | 206533 | */ |
| 206334 | 206534 | static void jsonDebugPrintBlob( |
| 206335 | 206535 | JsonParse *pParse, /* JSON content */ |
| 206336 | 206536 | u32 iStart, /* Start rendering here */ |
| 206337 | 206537 | u32 iEnd, /* Do not render this byte or any byte after this one */ |
| 206338 | | - int nIndent /* Indent by this many spaces */ |
| 206538 | + int nIndent, /* Indent by this many spaces */ |
| 206539 | + sqlite3_str *pOut /* Generate output into this sqlite3_str object */ |
| 206339 | 206540 | ){ |
| 206340 | 206541 | while( iStart<iEnd ){ |
| 206341 | 206542 | u32 i, n, nn, sz = 0; |
| 206342 | 206543 | int showContent = 1; |
| 206343 | 206544 | u8 x = pParse->aBlob[iStart] & 0x0f; |
| 206344 | 206545 | u32 savedNBlob = pParse->nBlob; |
| 206345 | | - printf("%5d:%*s", iStart, nIndent, ""); |
| 206546 | + sqlite3_str_appendf(pOut, "%5d:%*s", iStart, nIndent, ""); |
| 206346 | 206547 | if( pParse->nBlobAlloc>pParse->nBlob ){ |
| 206347 | 206548 | pParse->nBlob = pParse->nBlobAlloc; |
| 206348 | 206549 | } |
| 206349 | 206550 | nn = n = jsonbPayloadSize(pParse, iStart, &sz); |
| 206350 | 206551 | if( nn==0 ) nn = 1; |
| 206351 | 206552 | if( sz>0 && x<JSONB_ARRAY ){ |
| 206352 | 206553 | nn += sz; |
| 206353 | 206554 | } |
| 206354 | | - for(i=0; i<nn; i++) printf(" %02x", pParse->aBlob[iStart+i]); |
| 206555 | + for(i=0; i<nn; i++){ |
| 206556 | + sqlite3_str_appendf(pOut, " %02x", pParse->aBlob[iStart+i]); |
| 206557 | + } |
| 206355 | 206558 | if( n==0 ){ |
| 206356 | | - printf(" ERROR invalid node size\n"); |
| 206559 | + sqlite3_str_appendf(pOut, " ERROR invalid node size\n"); |
| 206357 | 206560 | iStart = n==0 ? iStart+1 : iEnd; |
| 206358 | 206561 | continue; |
| 206359 | 206562 | } |
| 206360 | 206563 | pParse->nBlob = savedNBlob; |
| 206361 | 206564 | if( iStart+n+sz>iEnd ){ |
| | @@ -206366,59 +206569,61 @@ |
| 206366 | 206569 | }else{ |
| 206367 | 206570 | iEnd = pParse->nBlob; |
| 206368 | 206571 | } |
| 206369 | 206572 | } |
| 206370 | 206573 | } |
| 206371 | | - printf(" <-- "); |
| 206574 | + sqlite3_str_appendall(pOut," <-- "); |
| 206372 | 206575 | switch( x ){ |
| 206373 | | - case JSONB_NULL: printf("null"); break; |
| 206374 | | - case JSONB_TRUE: printf("true"); break; |
| 206375 | | - case JSONB_FALSE: printf("false"); break; |
| 206376 | | - case JSONB_INT: printf("int"); break; |
| 206377 | | - case JSONB_INT5: printf("int5"); break; |
| 206378 | | - case JSONB_FLOAT: printf("float"); break; |
| 206379 | | - case JSONB_FLOAT5: printf("float5"); break; |
| 206380 | | - case JSONB_TEXT: printf("text"); break; |
| 206381 | | - case JSONB_TEXTJ: printf("textj"); break; |
| 206382 | | - case JSONB_TEXT5: printf("text5"); break; |
| 206383 | | - case JSONB_TEXTRAW: printf("textraw"); break; |
| 206576 | + case JSONB_NULL: sqlite3_str_appendall(pOut,"null"); break; |
| 206577 | + case JSONB_TRUE: sqlite3_str_appendall(pOut,"true"); break; |
| 206578 | + case JSONB_FALSE: sqlite3_str_appendall(pOut,"false"); break; |
| 206579 | + case JSONB_INT: sqlite3_str_appendall(pOut,"int"); break; |
| 206580 | + case JSONB_INT5: sqlite3_str_appendall(pOut,"int5"); break; |
| 206581 | + case JSONB_FLOAT: sqlite3_str_appendall(pOut,"float"); break; |
| 206582 | + case JSONB_FLOAT5: sqlite3_str_appendall(pOut,"float5"); break; |
| 206583 | + case JSONB_TEXT: sqlite3_str_appendall(pOut,"text"); break; |
| 206584 | + case JSONB_TEXTJ: sqlite3_str_appendall(pOut,"textj"); break; |
| 206585 | + case JSONB_TEXT5: sqlite3_str_appendall(pOut,"text5"); break; |
| 206586 | + case JSONB_TEXTRAW: sqlite3_str_appendall(pOut,"textraw"); break; |
| 206384 | 206587 | case JSONB_ARRAY: { |
| 206385 | | - printf("array, %u bytes\n", sz); |
| 206386 | | - jsonDebugPrintBlob(pParse, iStart+n, iStart+n+sz, nIndent+2); |
| 206588 | + sqlite3_str_appendf(pOut,"array, %u bytes\n", sz); |
| 206589 | + jsonDebugPrintBlob(pParse, iStart+n, iStart+n+sz, nIndent+2, pOut); |
| 206387 | 206590 | showContent = 0; |
| 206388 | 206591 | break; |
| 206389 | 206592 | } |
| 206390 | 206593 | case JSONB_OBJECT: { |
| 206391 | | - printf("object, %u bytes\n", sz); |
| 206392 | | - jsonDebugPrintBlob(pParse, iStart+n, iStart+n+sz, nIndent+2); |
| 206594 | + sqlite3_str_appendf(pOut, "object, %u bytes\n", sz); |
| 206595 | + jsonDebugPrintBlob(pParse, iStart+n, iStart+n+sz, nIndent+2, pOut); |
| 206393 | 206596 | showContent = 0; |
| 206394 | 206597 | break; |
| 206395 | 206598 | } |
| 206396 | 206599 | default: { |
| 206397 | | - printf("ERROR: unknown node type\n"); |
| 206600 | + sqlite3_str_appendall(pOut, "ERROR: unknown node type\n"); |
| 206398 | 206601 | showContent = 0; |
| 206399 | 206602 | break; |
| 206400 | 206603 | } |
| 206401 | 206604 | } |
| 206402 | 206605 | if( showContent ){ |
| 206403 | 206606 | if( sz==0 && x<=JSONB_FALSE ){ |
| 206404 | | - printf("\n"); |
| 206607 | + sqlite3_str_append(pOut, "\n", 1); |
| 206405 | 206608 | }else{ |
| 206406 | 206609 | u32 i; |
| 206407 | | - printf(": \""); |
| 206610 | + sqlite3_str_appendall(pOut, ": \""); |
| 206408 | 206611 | for(i=iStart+n; i<iStart+n+sz; i++){ |
| 206409 | 206612 | u8 c = pParse->aBlob[i]; |
| 206410 | 206613 | if( c<0x20 || c>=0x7f ) c = '.'; |
| 206411 | | - putchar(c); |
| 206614 | + sqlite3_str_append(pOut, (char*)&c, 1); |
| 206412 | 206615 | } |
| 206413 | | - printf("\"\n"); |
| 206616 | + sqlite3_str_append(pOut, "\"\n", 2); |
| 206414 | 206617 | } |
| 206415 | 206618 | } |
| 206416 | 206619 | iStart += n + sz; |
| 206417 | 206620 | } |
| 206418 | 206621 | } |
| 206419 | 206622 | static void jsonShowParse(JsonParse *pParse){ |
| 206623 | + sqlite3_str out; |
| 206624 | + char zBuf[1000]; |
| 206420 | 206625 | if( pParse==0 ){ |
| 206421 | 206626 | printf("NULL pointer\n"); |
| 206422 | 206627 | return; |
| 206423 | 206628 | }else{ |
| 206424 | 206629 | printf("nBlobAlloc = %u\n", pParse->nBlobAlloc); |
| | @@ -206425,31 +206630,42 @@ |
| 206425 | 206630 | printf("nBlob = %u\n", pParse->nBlob); |
| 206426 | 206631 | printf("delta = %d\n", pParse->delta); |
| 206427 | 206632 | if( pParse->nBlob==0 ) return; |
| 206428 | 206633 | printf("content (bytes 0..%u):\n", pParse->nBlob-1); |
| 206429 | 206634 | } |
| 206430 | | - jsonDebugPrintBlob(pParse, 0, pParse->nBlob, 0); |
| 206635 | + sqlite3StrAccumInit(&out, 0, zBuf, sizeof(zBuf), 1000000); |
| 206636 | + jsonDebugPrintBlob(pParse, 0, pParse->nBlob, 0, &out); |
| 206637 | + printf("%s", sqlite3_str_value(&out)); |
| 206638 | + sqlite3_str_reset(&out); |
| 206431 | 206639 | } |
| 206432 | 206640 | #endif /* SQLITE_DEBUG */ |
| 206433 | 206641 | |
| 206434 | 206642 | #ifdef SQLITE_DEBUG |
| 206435 | 206643 | /* |
| 206436 | 206644 | ** SQL function: json_parse(JSON) |
| 206437 | 206645 | ** |
| 206438 | | -** Parse JSON using jsonParseFuncArg(). Then print a dump of that |
| 206439 | | -** parse on standard output. |
| 206646 | +** Parse JSON using jsonParseFuncArg(). Return text that is a |
| 206647 | +** human-readable dump of the binary JSONB for the input parameter. |
| 206440 | 206648 | */ |
| 206441 | 206649 | static void jsonParseFunc( |
| 206442 | 206650 | sqlite3_context *ctx, |
| 206443 | 206651 | int argc, |
| 206444 | 206652 | sqlite3_value **argv |
| 206445 | 206653 | ){ |
| 206446 | 206654 | JsonParse *p; /* The parse */ |
| 206655 | + sqlite3_str out; |
| 206447 | 206656 | |
| 206448 | | - assert( argc==1 ); |
| 206657 | + assert( argc>=1 ); |
| 206658 | + sqlite3StrAccumInit(&out, 0, 0, 0, 1000000); |
| 206449 | 206659 | p = jsonParseFuncArg(ctx, argv[0], 0); |
| 206450 | | - jsonShowParse(p); |
| 206660 | + if( p==0 ) return; |
| 206661 | + if( argc==1 ){ |
| 206662 | + jsonDebugPrintBlob(p, 0, p->nBlob, 0, &out); |
| 206663 | + sqlite3_result_text64(ctx, out.zText, out.nChar, sqlite3_free, SQLITE_UTF8); |
| 206664 | + }else{ |
| 206665 | + jsonShowParse(p); |
| 206666 | + } |
| 206451 | 206667 | jsonParseFree(p); |
| 206452 | 206668 | } |
| 206453 | 206669 | #endif /* SQLITE_DEBUG */ |
| 206454 | 206670 | |
| 206455 | 206671 | /**************************************************************************** |
| | @@ -206641,11 +206857,11 @@ |
| 206641 | 206857 | } |
| 206642 | 206858 | if( j<p->nBlob ){ |
| 206643 | 206859 | if( argc==2 ){ |
| 206644 | 206860 | if( flags & JSON_JSON ){ |
| 206645 | 206861 | jsonStringInit(&jx, ctx); |
| 206646 | | - jsonXlateBlobToText(p, j, &jx); |
| 206862 | + jsonTranslateBlobToText(p, j, &jx); |
| 206647 | 206863 | jsonReturnString(&jx, 0, 0); |
| 206648 | 206864 | jsonStringReset(&jx); |
| 206649 | 206865 | assert( (flags & JSON_BLOB)==0 ); |
| 206650 | 206866 | sqlite3_result_subtype(ctx, JSON_SUBTYPE); |
| 206651 | 206867 | }else{ |
| | @@ -206656,11 +206872,11 @@ |
| 206656 | 206872 | sqlite3_result_subtype(ctx, JSON_SUBTYPE); |
| 206657 | 206873 | } |
| 206658 | 206874 | } |
| 206659 | 206875 | }else{ |
| 206660 | 206876 | jsonAppendSeparator(&jx); |
| 206661 | | - jsonXlateBlobToText(p, j, &jx); |
| 206877 | + jsonTranslateBlobToText(p, j, &jx); |
| 206662 | 206878 | } |
| 206663 | 206879 | }else if( j==JSON_LOOKUP_NOTFOUND ){ |
| 206664 | 206880 | if( argc==2 ){ |
| 206665 | 206881 | goto json_extract_error; /* Return NULL if not found */ |
| 206666 | 206882 | }else{ |
| | @@ -229267,23 +229483,28 @@ |
| 229267 | 229483 | ** |
| 229268 | 229484 | ** This function may be quite inefficient if used with an FTS5 table |
| 229269 | 229485 | ** created with the "columnsize=0" option. |
| 229270 | 229486 | ** |
| 229271 | 229487 | ** xColumnText: |
| 229272 | | -** This function attempts to retrieve the text of column iCol of the |
| 229273 | | -** current document. If successful, (*pz) is set to point to a buffer |
| 229488 | +** If parameter iCol is less than zero, or greater than or equal to the |
| 229489 | +** number of columns in the table, SQLITE_RANGE is returned. |
| 229490 | +** |
| 229491 | +** Otherwise, this function attempts to retrieve the text of column iCol of |
| 229492 | +** the current document. If successful, (*pz) is set to point to a buffer |
| 229274 | 229493 | ** containing the text in utf-8 encoding, (*pn) is set to the size in bytes |
| 229275 | 229494 | ** (not characters) of the buffer and SQLITE_OK is returned. Otherwise, |
| 229276 | 229495 | ** if an error occurs, an SQLite error code is returned and the final values |
| 229277 | 229496 | ** of (*pz) and (*pn) are undefined. |
| 229278 | 229497 | ** |
| 229279 | 229498 | ** xPhraseCount: |
| 229280 | 229499 | ** Returns the number of phrases in the current query expression. |
| 229281 | 229500 | ** |
| 229282 | 229501 | ** xPhraseSize: |
| 229283 | | -** Returns the number of tokens in phrase iPhrase of the query. Phrases |
| 229284 | | -** are numbered starting from zero. |
| 229502 | +** If parameter iCol is less than zero, or greater than or equal to the |
| 229503 | +** number of phrases in the current query, as returned by xPhraseCount, |
| 229504 | +** 0 is returned. Otherwise, this function returns the number of tokens in |
| 229505 | +** phrase iPhrase of the query. Phrases are numbered starting from zero. |
| 229285 | 229506 | ** |
| 229286 | 229507 | ** xInstCount: |
| 229287 | 229508 | ** Set *pnInst to the total number of occurrences of all phrases within |
| 229288 | 229509 | ** the query within the current row. Return SQLITE_OK if successful, or |
| 229289 | 229510 | ** an error code (i.e. SQLITE_NOMEM) if an error occurs. |
| | @@ -229295,16 +229516,17 @@ |
| 229295 | 229516 | ** |
| 229296 | 229517 | ** xInst: |
| 229297 | 229518 | ** Query for the details of phrase match iIdx within the current row. |
| 229298 | 229519 | ** Phrase matches are numbered starting from zero, so the iIdx argument |
| 229299 | 229520 | ** should be greater than or equal to zero and smaller than the value |
| 229300 | | -** output by xInstCount(). |
| 229521 | +** output by xInstCount(). If iIdx is less than zero or greater than |
| 229522 | +** or equal to the value returned by xInstCount(), SQLITE_RANGE is returned. |
| 229301 | 229523 | ** |
| 229302 | | -** Usually, output parameter *piPhrase is set to the phrase number, *piCol |
| 229524 | +** Otherwise, output parameter *piPhrase is set to the phrase number, *piCol |
| 229303 | 229525 | ** to the column in which it occurs and *piOff the token offset of the |
| 229304 | | -** first token of the phrase. Returns SQLITE_OK if successful, or an error |
| 229305 | | -** code (i.e. SQLITE_NOMEM) if an error occurs. |
| 229526 | +** first token of the phrase. SQLITE_OK is returned if successful, or an |
| 229527 | +** error code (i.e. SQLITE_NOMEM) if an error occurs. |
| 229306 | 229528 | ** |
| 229307 | 229529 | ** This API can be quite slow if used with an FTS5 table created with the |
| 229308 | 229530 | ** "detail=none" or "detail=column" option. |
| 229309 | 229531 | ** |
| 229310 | 229532 | ** xRowid: |
| | @@ -229325,10 +229547,14 @@ |
| 229325 | 229547 | ** row visited, the callback function passed as the fourth argument |
| 229326 | 229548 | ** is invoked. The context and API objects passed to the callback |
| 229327 | 229549 | ** function may be used to access the properties of each matched row. |
| 229328 | 229550 | ** Invoking Api.xUserData() returns a copy of the pointer passed as |
| 229329 | 229551 | ** the third argument to pUserData. |
| 229552 | +** |
| 229553 | +** If parameter iPhrase is less than zero, or greater than or equal to |
| 229554 | +** the number of phrases in the query, as returned by xPhraseCount(), |
| 229555 | +** this function returns SQLITE_RANGE. |
| 229330 | 229556 | ** |
| 229331 | 229557 | ** If the callback function returns any value other than SQLITE_OK, the |
| 229332 | 229558 | ** query is abandoned and the xQueryPhrase function returns immediately. |
| 229333 | 229559 | ** If the returned value is SQLITE_DONE, xQueryPhrase returns SQLITE_OK. |
| 229334 | 229560 | ** Otherwise, the error code is propagated upwards. |
| | @@ -229446,22 +229672,30 @@ |
| 229446 | 229672 | ** xQueryToken(pFts5, iPhrase, iToken, ppToken, pnToken) |
| 229447 | 229673 | ** This is used to access token iToken of phrase iPhrase of the current |
| 229448 | 229674 | ** query. Before returning, output parameter *ppToken is set to point |
| 229449 | 229675 | ** to a buffer containing the requested token, and *pnToken to the |
| 229450 | 229676 | ** size of this buffer in bytes. |
| 229677 | +** |
| 229678 | +** If iPhrase or iToken are less than zero, or if iPhrase is greater than |
| 229679 | +** or equal to the number of phrases in the query as reported by |
| 229680 | +** xPhraseCount(), or if iToken is equal to or greater than the number of |
| 229681 | +** tokens in the phrase, SQLITE_RANGE is returned and *ppToken and *pnToken |
| 229682 | + are both zeroed. |
| 229451 | 229683 | ** |
| 229452 | 229684 | ** The output text is not a copy of the query text that specified the |
| 229453 | 229685 | ** token. It is the output of the tokenizer module. For tokendata=1 |
| 229454 | 229686 | ** tables, this includes any embedded 0x00 and trailing data. |
| 229455 | 229687 | ** |
| 229456 | 229688 | ** xInstToken(pFts5, iIdx, iToken, ppToken, pnToken) |
| 229457 | 229689 | ** This is used to access token iToken of phrase hit iIdx within the |
| 229458 | | -** current row. Output variable (*ppToken) is set to point to a buffer |
| 229459 | | -** containing the matching document token, and (*pnToken) to the size |
| 229460 | | -** of that buffer in bytes. This API is not available if the specified |
| 229461 | | -** token matches a prefix query term. In that case both output variables |
| 229462 | | -** are always set to 0. |
| 229690 | +** current row. If iIdx is less than zero or greater than or equal to the |
| 229691 | +** value returned by xInstCount(), SQLITE_RANGE is returned. Otherwise, |
| 229692 | +** output variable (*ppToken) is set to point to a buffer containing the |
| 229693 | +** matching document token, and (*pnToken) to the size of that buffer in |
| 229694 | +** bytes. This API is not available if the specified token matches a |
| 229695 | +** prefix query term. In that case both output variables are always set |
| 229696 | +** to 0. |
| 229463 | 229697 | ** |
| 229464 | 229698 | ** The output text is not a copy of the document text that was tokenized. |
| 229465 | 229699 | ** It is the output of the tokenizer module. For tokendata=1 tables, this |
| 229466 | 229700 | ** includes any embedded 0x00 and trailing data. |
| 229467 | 229701 | ** |
| | @@ -232433,12 +232667,14 @@ |
| 232433 | 232667 | memset(&ctx, 0, sizeof(HighlightContext)); |
| 232434 | 232668 | ctx.zOpen = (const char*)sqlite3_value_text(apVal[1]); |
| 232435 | 232669 | ctx.zClose = (const char*)sqlite3_value_text(apVal[2]); |
| 232436 | 232670 | ctx.iRangeEnd = -1; |
| 232437 | 232671 | rc = pApi->xColumnText(pFts, iCol, &ctx.zIn, &ctx.nIn); |
| 232438 | | - |
| 232439 | | - if( ctx.zIn ){ |
| 232672 | + if( rc==SQLITE_RANGE ){ |
| 232673 | + sqlite3_result_text(pCtx, "", -1, SQLITE_STATIC); |
| 232674 | + rc = SQLITE_OK; |
| 232675 | + }else if( ctx.zIn ){ |
| 232440 | 232676 | if( rc==SQLITE_OK ){ |
| 232441 | 232677 | rc = fts5CInstIterInit(pApi, pFts, iCol, &ctx.iter); |
| 232442 | 232678 | } |
| 232443 | 232679 | |
| 232444 | 232680 | if( rc==SQLITE_OK ){ |
| | @@ -236273,15 +236509,19 @@ |
| 236273 | 236509 | Fts5Expr *pExpr, |
| 236274 | 236510 | int iPhrase, |
| 236275 | 236511 | Fts5Expr **ppNew |
| 236276 | 236512 | ){ |
| 236277 | 236513 | int rc = SQLITE_OK; /* Return code */ |
| 236278 | | - Fts5ExprPhrase *pOrig; /* The phrase extracted from pExpr */ |
| 236514 | + Fts5ExprPhrase *pOrig = 0; /* The phrase extracted from pExpr */ |
| 236279 | 236515 | Fts5Expr *pNew = 0; /* Expression to return via *ppNew */ |
| 236280 | 236516 | TokenCtx sCtx = {0,0,0}; /* Context object for fts5ParseTokenize */ |
| 236281 | | - pOrig = pExpr->apExprPhrase[iPhrase]; |
| 236282 | | - pNew = (Fts5Expr*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Expr)); |
| 236517 | + if( iPhrase<0 || iPhrase>=pExpr->nPhrase ){ |
| 236518 | + rc = SQLITE_RANGE; |
| 236519 | + }else{ |
| 236520 | + pOrig = pExpr->apExprPhrase[iPhrase]; |
| 236521 | + pNew = (Fts5Expr*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Expr)); |
| 236522 | + } |
| 236283 | 236523 | if( rc==SQLITE_OK ){ |
| 236284 | 236524 | pNew->apExprPhrase = (Fts5ExprPhrase**)sqlite3Fts5MallocZero(&rc, |
| 236285 | 236525 | sizeof(Fts5ExprPhrase*)); |
| 236286 | 236526 | } |
| 236287 | 236527 | if( rc==SQLITE_OK ){ |
| | @@ -236290,11 +236530,11 @@ |
| 236290 | 236530 | } |
| 236291 | 236531 | if( rc==SQLITE_OK ){ |
| 236292 | 236532 | pNew->pRoot->pNear = (Fts5ExprNearset*)sqlite3Fts5MallocZero(&rc, |
| 236293 | 236533 | sizeof(Fts5ExprNearset) + sizeof(Fts5ExprPhrase*)); |
| 236294 | 236534 | } |
| 236295 | | - if( rc==SQLITE_OK ){ |
| 236535 | + if( rc==SQLITE_OK && ALWAYS(pOrig!=0) ){ |
| 236296 | 236536 | Fts5Colset *pColsetOrig = pOrig->pNode->pNear->pColset; |
| 236297 | 236537 | if( pColsetOrig ){ |
| 236298 | 236538 | sqlite3_int64 nByte; |
| 236299 | 236539 | Fts5Colset *pColset; |
| 236300 | 236540 | nByte = sizeof(Fts5Colset) + (pColsetOrig->nCol-1) * sizeof(int); |
| | @@ -236304,29 +236544,31 @@ |
| 236304 | 236544 | } |
| 236305 | 236545 | pNew->pRoot->pNear->pColset = pColset; |
| 236306 | 236546 | } |
| 236307 | 236547 | } |
| 236308 | 236548 | |
| 236309 | | - if( pOrig->nTerm ){ |
| 236310 | | - int i; /* Used to iterate through phrase terms */ |
| 236311 | | - sCtx.pConfig = pExpr->pConfig; |
| 236312 | | - for(i=0; rc==SQLITE_OK && i<pOrig->nTerm; i++){ |
| 236313 | | - int tflags = 0; |
| 236314 | | - Fts5ExprTerm *p; |
| 236315 | | - for(p=&pOrig->aTerm[i]; p && rc==SQLITE_OK; p=p->pSynonym){ |
| 236316 | | - rc = fts5ParseTokenize((void*)&sCtx, tflags, p->pTerm,p->nFullTerm,0,0); |
| 236317 | | - tflags = FTS5_TOKEN_COLOCATED; |
| 236318 | | - } |
| 236319 | | - if( rc==SQLITE_OK ){ |
| 236320 | | - sCtx.pPhrase->aTerm[i].bPrefix = pOrig->aTerm[i].bPrefix; |
| 236321 | | - sCtx.pPhrase->aTerm[i].bFirst = pOrig->aTerm[i].bFirst; |
| 236322 | | - } |
| 236323 | | - } |
| 236324 | | - }else{ |
| 236325 | | - /* This happens when parsing a token or quoted phrase that contains |
| 236326 | | - ** no token characters at all. (e.g ... MATCH '""'). */ |
| 236327 | | - sCtx.pPhrase = sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprPhrase)); |
| 236549 | + if( rc==SQLITE_OK ){ |
| 236550 | + if( pOrig->nTerm ){ |
| 236551 | + int i; /* Used to iterate through phrase terms */ |
| 236552 | + sCtx.pConfig = pExpr->pConfig; |
| 236553 | + for(i=0; rc==SQLITE_OK && i<pOrig->nTerm; i++){ |
| 236554 | + int tflags = 0; |
| 236555 | + Fts5ExprTerm *p; |
| 236556 | + for(p=&pOrig->aTerm[i]; p && rc==SQLITE_OK; p=p->pSynonym){ |
| 236557 | + rc = fts5ParseTokenize((void*)&sCtx,tflags,p->pTerm,p->nFullTerm,0,0); |
| 236558 | + tflags = FTS5_TOKEN_COLOCATED; |
| 236559 | + } |
| 236560 | + if( rc==SQLITE_OK ){ |
| 236561 | + sCtx.pPhrase->aTerm[i].bPrefix = pOrig->aTerm[i].bPrefix; |
| 236562 | + sCtx.pPhrase->aTerm[i].bFirst = pOrig->aTerm[i].bFirst; |
| 236563 | + } |
| 236564 | + } |
| 236565 | + }else{ |
| 236566 | + /* This happens when parsing a token or quoted phrase that contains |
| 236567 | + ** no token characters at all. (e.g ... MATCH '""'). */ |
| 236568 | + sCtx.pPhrase = sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprPhrase)); |
| 236569 | + } |
| 236328 | 236570 | } |
| 236329 | 236571 | |
| 236330 | 236572 | if( rc==SQLITE_OK && ALWAYS(sCtx.pPhrase) ){ |
| 236331 | 236573 | /* All the allocations succeeded. Put the expression object together. */ |
| 236332 | 236574 | pNew->pIndex = pExpr->pIndex; |
| | @@ -239776,13 +240018,13 @@ |
| 239776 | 240018 | for(iOff=pLvl->iOff; iOff<pData->nn; iOff++){ |
| 239777 | 240019 | if( pData->p[iOff] ) break; |
| 239778 | 240020 | } |
| 239779 | 240021 | |
| 239780 | 240022 | if( iOff<pData->nn ){ |
| 239781 | | - i64 iVal; |
| 240023 | + u64 iVal; |
| 239782 | 240024 | pLvl->iLeafPgno += (iOff - pLvl->iOff) + 1; |
| 239783 | | - iOff += fts5GetVarint(&pData->p[iOff], (u64*)&iVal); |
| 240025 | + iOff += fts5GetVarint(&pData->p[iOff], &iVal); |
| 239784 | 240026 | pLvl->iRowid += iVal; |
| 239785 | 240027 | pLvl->iOff = iOff; |
| 239786 | 240028 | }else{ |
| 239787 | 240029 | pLvl->bEof = 1; |
| 239788 | 240030 | } |
| | @@ -246173,20 +246415,20 @@ |
| 246173 | 246415 | fts5DataRelease(pLeaf); |
| 246174 | 246416 | } |
| 246175 | 246417 | } |
| 246176 | 246418 | |
| 246177 | 246419 | static void fts5IntegrityCheckPgidx(Fts5Index *p, Fts5Data *pLeaf){ |
| 246178 | | - int iTermOff = 0; |
| 246420 | + i64 iTermOff = 0; |
| 246179 | 246421 | int ii; |
| 246180 | 246422 | |
| 246181 | 246423 | Fts5Buffer buf1 = {0,0,0}; |
| 246182 | 246424 | Fts5Buffer buf2 = {0,0,0}; |
| 246183 | 246425 | |
| 246184 | 246426 | ii = pLeaf->szLeaf; |
| 246185 | 246427 | while( ii<pLeaf->nn && p->rc==SQLITE_OK ){ |
| 246186 | 246428 | int res; |
| 246187 | | - int iOff; |
| 246429 | + i64 iOff; |
| 246188 | 246430 | int nIncr; |
| 246189 | 246431 | |
| 246190 | 246432 | ii += fts5GetVarint32(&pLeaf->p[ii], nIncr); |
| 246191 | 246433 | iTermOff += nIncr; |
| 246192 | 246434 | iOff = iTermOff; |
| | @@ -249207,11 +249449,14 @@ |
| 249207 | 249449 | const char **pz, |
| 249208 | 249450 | int *pn |
| 249209 | 249451 | ){ |
| 249210 | 249452 | int rc = SQLITE_OK; |
| 249211 | 249453 | Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; |
| 249212 | | - if( fts5IsContentless((Fts5FullTable*)(pCsr->base.pVtab)) |
| 249454 | + Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); |
| 249455 | + if( iCol<0 || iCol>=pTab->pConfig->nCol ){ |
| 249456 | + rc = SQLITE_RANGE; |
| 249457 | + }else if( fts5IsContentless((Fts5FullTable*)(pCsr->base.pVtab)) |
| 249213 | 249458 | || pCsr->ePlan==FTS5_PLAN_SPECIAL |
| 249214 | 249459 | ){ |
| 249215 | 249460 | *pz = 0; |
| 249216 | 249461 | *pn = 0; |
| 249217 | 249462 | }else{ |
| | @@ -249232,12 +249477,13 @@ |
| 249232 | 249477 | ){ |
| 249233 | 249478 | Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig; |
| 249234 | 249479 | int rc = SQLITE_OK; |
| 249235 | 249480 | int bLive = (pCsr->pSorter==0); |
| 249236 | 249481 | |
| 249237 | | - if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_POSLIST) ){ |
| 249238 | | - |
| 249482 | + if( iPhrase<0 || iPhrase>=sqlite3Fts5ExprPhraseCount(pCsr->pExpr) ){ |
| 249483 | + rc = SQLITE_RANGE; |
| 249484 | + }else if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_POSLIST) ){ |
| 249239 | 249485 | if( pConfig->eDetail!=FTS5_DETAIL_FULL ){ |
| 249240 | 249486 | Fts5PoslistPopulator *aPopulator; |
| 249241 | 249487 | int i; |
| 249242 | 249488 | aPopulator = sqlite3Fts5ExprClearPoslists(pCsr->pExpr, bLive); |
| 249243 | 249489 | if( aPopulator==0 ) rc = SQLITE_NOMEM; |
| | @@ -249257,18 +249503,24 @@ |
| 249257 | 249503 | } |
| 249258 | 249504 | } |
| 249259 | 249505 | CsrFlagClear(pCsr, FTS5CSR_REQUIRE_POSLIST); |
| 249260 | 249506 | } |
| 249261 | 249507 | |
| 249262 | | - if( pCsr->pSorter && pConfig->eDetail==FTS5_DETAIL_FULL ){ |
| 249263 | | - Fts5Sorter *pSorter = pCsr->pSorter; |
| 249264 | | - int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]); |
| 249265 | | - *pn = pSorter->aIdx[iPhrase] - i1; |
| 249266 | | - *pa = &pSorter->aPoslist[i1]; |
| 249508 | + if( rc==SQLITE_OK ){ |
| 249509 | + if( pCsr->pSorter && pConfig->eDetail==FTS5_DETAIL_FULL ){ |
| 249510 | + Fts5Sorter *pSorter = pCsr->pSorter; |
| 249511 | + int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]); |
| 249512 | + *pn = pSorter->aIdx[iPhrase] - i1; |
| 249513 | + *pa = &pSorter->aPoslist[i1]; |
| 249514 | + }else{ |
| 249515 | + *pn = sqlite3Fts5ExprPoslist(pCsr->pExpr, iPhrase, pa); |
| 249516 | + } |
| 249267 | 249517 | }else{ |
| 249268 | | - *pn = sqlite3Fts5ExprPoslist(pCsr->pExpr, iPhrase, pa); |
| 249518 | + *pa = 0; |
| 249519 | + *pn = 0; |
| 249269 | 249520 | } |
| 249521 | + |
| 249270 | 249522 | |
| 249271 | 249523 | return rc; |
| 249272 | 249524 | } |
| 249273 | 249525 | |
| 249274 | 249526 | /* |
| | @@ -250223,11 +250475,11 @@ |
| 250223 | 250475 | int nArg, /* Number of args */ |
| 250224 | 250476 | sqlite3_value **apUnused /* Function arguments */ |
| 250225 | 250477 | ){ |
| 250226 | 250478 | assert( nArg==0 ); |
| 250227 | 250479 | UNUSED_PARAM2(nArg, apUnused); |
| 250228 | | - sqlite3_result_text(pCtx, "fts5: 2023-12-14 16:34:47 27d4a89a5ff96b7b7fc5dc9650e1269f7c7edf91de9b9aafce40be9ecc8b95e9", -1, SQLITE_TRANSIENT); |
| 250480 | + sqlite3_result_text(pCtx, "fts5: 2023-12-29 19:03:01 4b70b94616ef37bac969051eee3ea6913a28f30520cdd4fc3a19e848f2cf12b7", -1, SQLITE_TRANSIENT); |
| 250229 | 250481 | } |
| 250230 | 250482 | |
| 250231 | 250483 | /* |
| 250232 | 250484 | ** Return true if zName is the extension on one of the shadow tables used |
| 250233 | 250485 | ** by this module. |
| 250234 | 250486 | |