| | @@ -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 | | -** 33a3f327855b427ae6ba0057218d043a1417. |
| 21 | +** baa83b460c677c210c7fa3f20314d7e05f30. |
| 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 |
| | @@ -254,14 +254,17 @@ |
| 254 | 254 | #endif |
| 255 | 255 | |
| 256 | 256 | /* |
| 257 | 257 | ** Macro to disable warnings about missing "break" at the end of a "case". |
| 258 | 258 | */ |
| 259 | | -#if GCC_VERSION>=7000000 |
| 260 | | -# define deliberate_fall_through __attribute__((fallthrough)); |
| 261 | | -#else |
| 262 | | -# define deliberate_fall_through |
| 259 | +#if defined(__has_attribute) |
| 260 | +# if __has_attribute(fallthrough) |
| 261 | +# define deliberate_fall_through __attribute__((fallthrough)); |
| 262 | +# endif |
| 263 | +#endif |
| 264 | +#if !defined(deliberate_fall_through) |
| 265 | +# define deliberate_fall_through |
| 263 | 266 | #endif |
| 264 | 267 | |
| 265 | 268 | /* |
| 266 | 269 | ** For MinGW, check to see if we can include the header file containing its |
| 267 | 270 | ** version information, among other things. Normally, this internal MinGW |
| | @@ -459,11 +462,11 @@ |
| 459 | 462 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 460 | 463 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 461 | 464 | */ |
| 462 | 465 | #define SQLITE_VERSION "3.47.0" |
| 463 | 466 | #define SQLITE_VERSION_NUMBER 3047000 |
| 464 | | -#define SQLITE_SOURCE_ID "2024-06-11 18:22:48 33a3f327855b427ae6ba0057218d043a1417bc9d780728f47f23acdd836e1686" |
| 467 | +#define SQLITE_SOURCE_ID "2024-07-03 20:19:33 baa83b460c677c210c7fa3f20314d7e05f305aed8a69026bc5fa106a3de4ea38" |
| 465 | 468 | |
| 466 | 469 | /* |
| 467 | 470 | ** CAPI3REF: Run-Time Library Version Numbers |
| 468 | 471 | ** KEYWORDS: sqlite3_version sqlite3_sourceid |
| 469 | 472 | ** |
| | @@ -1083,12 +1086,12 @@ |
| 1083 | 1086 | ** xUnlock() downgrades the database file lock to either SHARED or NONE. |
| 1084 | 1087 | ** If the lock is already at or below the requested lock state, then the call |
| 1085 | 1088 | ** to xUnlock() is a no-op. |
| 1086 | 1089 | ** The xCheckReservedLock() method checks whether any database connection, |
| 1087 | 1090 | ** either in this process or in some other process, is holding a RESERVED, |
| 1088 | | -** PENDING, or EXCLUSIVE lock on the file. It returns true |
| 1089 | | -** if such a lock exists and false otherwise. |
| 1091 | +** PENDING, or EXCLUSIVE lock on the file. It returns, via its output |
| 1092 | +** pointer parameter, true if such a lock exists and false otherwise. |
| 1090 | 1093 | ** |
| 1091 | 1094 | ** The xFileControl() method is a generic interface that allows custom |
| 1092 | 1095 | ** VFS implementations to directly control an open file using the |
| 1093 | 1096 | ** [sqlite3_file_control()] interface. The second "op" argument is an |
| 1094 | 1097 | ** integer opcode. The third argument is a generic pointer intended to |
| | @@ -13345,10 +13348,14 @@ |
| 13345 | 13348 | ** "detail=none" or "detail=column" option. If the FTS5 table is created |
| 13346 | 13349 | ** with either "detail=none" or "detail=column" and "content=" option |
| 13347 | 13350 | ** (i.e. if it is a contentless table), then this API always iterates |
| 13348 | 13351 | ** through an empty set (all calls to xPhraseFirst() set iCol to -1). |
| 13349 | 13352 | ** |
| 13353 | +** In all cases, matches are visited in (column ASC, offset ASC) order. |
| 13354 | +** i.e. all those in column 0, sorted by offset, followed by those in |
| 13355 | +** column 1, etc. |
| 13356 | +** |
| 13350 | 13357 | ** xPhraseNext() |
| 13351 | 13358 | ** See xPhraseFirst above. |
| 13352 | 13359 | ** |
| 13353 | 13360 | ** xPhraseFirstColumn() |
| 13354 | 13361 | ** This function and xPhraseNextColumn() are similar to the xPhraseFirst() |
| | @@ -15167,11 +15174,10 @@ |
| 15167 | 15174 | ** 0x00008000 After all FROM-clause analysis |
| 15168 | 15175 | ** 0x00010000 Beginning of DELETE/INSERT/UPDATE processing |
| 15169 | 15176 | ** 0x00020000 Transform DISTINCT into GROUP BY |
| 15170 | 15177 | ** 0x00040000 SELECT tree dump after all code has been generated |
| 15171 | 15178 | ** 0x00080000 NOT NULL strength reduction |
| 15172 | | -** 0x00100000 EXISTS-to-JOIN optimization |
| 15173 | 15179 | */ |
| 15174 | 15180 | |
| 15175 | 15181 | /* |
| 15176 | 15182 | ** Macros for "wheretrace" |
| 15177 | 15183 | */ |
| | @@ -17894,11 +17900,10 @@ |
| 17894 | 17900 | /* TH3 expects this value ^^^^^^^^^^ See flatten04.test */ |
| 17895 | 17901 | #define SQLITE_IndexedExpr 0x01000000 /* Pull exprs from index when able */ |
| 17896 | 17902 | #define SQLITE_Coroutines 0x02000000 /* Co-routines for subqueries */ |
| 17897 | 17903 | #define SQLITE_NullUnusedCols 0x04000000 /* NULL unused columns in subqueries */ |
| 17898 | 17904 | #define SQLITE_OnePass 0x08000000 /* Single-pass DELETE and UPDATE */ |
| 17899 | | -#define SQLITE_ExistsToJoin 0x10000000 /* The EXISTS-to-JOIN optimization */ |
| 17900 | 17905 | #define SQLITE_AllOpts 0xffffffff /* All optimizations */ |
| 17901 | 17906 | |
| 17902 | 17907 | /* |
| 17903 | 17908 | ** Macros for testing whether or not optimizations are enabled or disabled. |
| 17904 | 17909 | */ |
| | @@ -19590,11 +19595,15 @@ |
| 19590 | 19595 | ** of the query. This destination implies "LIMIT 1". |
| 19591 | 19596 | ** |
| 19592 | 19597 | ** SRT_Set The result must be a single column. Store each |
| 19593 | 19598 | ** row of result as the key in table pDest->iSDParm. |
| 19594 | 19599 | ** Apply the affinity pDest->affSdst before storing |
| 19595 | | -** results. Used to implement "IN (SELECT ...)". |
| 19600 | +** results. if pDest->iSDParm2 is positive, then it is |
| 19601 | +** a regsiter holding a Bloom filter for the IN operator |
| 19602 | +** that should be populated in addition to the |
| 19603 | +** pDest->iSDParm table. This SRT is used to |
| 19604 | +** implement "IN (SELECT ...)". |
| 19596 | 19605 | ** |
| 19597 | 19606 | ** SRT_EphemTab Create an temporary table pDest->iSDParm and store |
| 19598 | 19607 | ** the result there. The cursor is left open after |
| 19599 | 19608 | ** returning. This is like SRT_Table except that |
| 19600 | 19609 | ** this destination uses OP_OpenEphemeral to create |
| | @@ -19798,11 +19807,10 @@ |
| 19798 | 19807 | u8 okConstFactor; /* OK to factor out constants */ |
| 19799 | 19808 | u8 disableLookaside; /* Number of times lookaside has been disabled */ |
| 19800 | 19809 | u8 prepFlags; /* SQLITE_PREPARE_* flags */ |
| 19801 | 19810 | u8 withinRJSubrtn; /* Nesting level for RIGHT JOIN body subroutines */ |
| 19802 | 19811 | u8 bHasWith; /* True if statement contains WITH */ |
| 19803 | | - u8 bHasExists; /* Has a correlated "EXISTS (SELECT ....)" expression */ |
| 19804 | 19812 | #if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST) |
| 19805 | 19813 | u8 earlyCleanup; /* OOM inside sqlite3ParserAddCleanup() */ |
| 19806 | 19814 | #endif |
| 19807 | 19815 | #ifdef SQLITE_DEBUG |
| 19808 | 19816 | u8 ifNotExists; /* Might be true if IF NOT EXISTS. Assert()s only */ |
| | @@ -20094,11 +20102,11 @@ |
| 20094 | 20102 | int iRetReg; /* Register array for holding a row of RETURNING */ |
| 20095 | 20103 | char zName[40]; /* Name of trigger: "sqlite_returning_%p" */ |
| 20096 | 20104 | }; |
| 20097 | 20105 | |
| 20098 | 20106 | /* |
| 20099 | | -** An objected used to accumulate the text of a string where we |
| 20107 | +** An object used to accumulate the text of a string where we |
| 20100 | 20108 | ** do not necessarily know how big the string will be in the end. |
| 20101 | 20109 | */ |
| 20102 | 20110 | struct sqlite3_str { |
| 20103 | 20111 | sqlite3 *db; /* Optional database for lookaside. Can be NULL */ |
| 20104 | 20112 | char *zText; /* The string collected so far */ |
| | @@ -20108,11 +20116,11 @@ |
| 20108 | 20116 | u8 accError; /* SQLITE_NOMEM or SQLITE_TOOBIG */ |
| 20109 | 20117 | u8 printfFlags; /* SQLITE_PRINTF flags below */ |
| 20110 | 20118 | }; |
| 20111 | 20119 | #define SQLITE_PRINTF_INTERNAL 0x01 /* Internal-use-only converters allowed */ |
| 20112 | 20120 | #define SQLITE_PRINTF_SQLFUNC 0x02 /* SQL function arguments to VXPrintf */ |
| 20113 | | -#define SQLITE_PRINTF_MALLOCED 0x04 /* True if xText is allocated space */ |
| 20121 | +#define SQLITE_PRINTF_MALLOCED 0x04 /* True if zText is allocated space */ |
| 20114 | 20122 | |
| 20115 | 20123 | #define isMalloced(X) (((X)->printfFlags & SQLITE_PRINTF_MALLOCED)!=0) |
| 20116 | 20124 | |
| 20117 | 20125 | /* |
| 20118 | 20126 | ** The following object is the header for an "RCStr" or "reference-counted |
| | @@ -33485,13 +33493,14 @@ |
| 33485 | 33493 | }else{ |
| 33486 | 33494 | int i; |
| 33487 | 33495 | sqlite3TreeViewLine(pView, "%s", zLabel); |
| 33488 | 33496 | for(i=0; i<pList->nExpr; i++){ |
| 33489 | 33497 | int j = pList->a[i].u.x.iOrderByCol; |
| 33498 | + u8 sortFlags = pList->a[i].fg.sortFlags; |
| 33490 | 33499 | char *zName = pList->a[i].zEName; |
| 33491 | 33500 | int moreToFollow = i<pList->nExpr - 1; |
| 33492 | | - if( j || zName ){ |
| 33501 | + if( j || zName || sortFlags ){ |
| 33493 | 33502 | sqlite3TreeViewPush(&pView, moreToFollow); |
| 33494 | 33503 | moreToFollow = 0; |
| 33495 | 33504 | sqlite3TreeViewLine(pView, 0); |
| 33496 | 33505 | if( zName ){ |
| 33497 | 33506 | switch( pList->a[i].fg.eEName ){ |
| | @@ -33508,17 +33517,22 @@ |
| 33508 | 33517 | fprintf(stdout, "SPAN(\"%s\") ", zName); |
| 33509 | 33518 | break; |
| 33510 | 33519 | } |
| 33511 | 33520 | } |
| 33512 | 33521 | if( j ){ |
| 33513 | | - fprintf(stdout, "iOrderByCol=%d", j); |
| 33522 | + fprintf(stdout, "iOrderByCol=%d ", j); |
| 33523 | + } |
| 33524 | + if( sortFlags & KEYINFO_ORDER_DESC ){ |
| 33525 | + fprintf(stdout, "DESC "); |
| 33526 | + }else if( sortFlags & KEYINFO_ORDER_BIGNULL ){ |
| 33527 | + fprintf(stdout, "NULLS-LAST"); |
| 33514 | 33528 | } |
| 33515 | 33529 | fprintf(stdout, "\n"); |
| 33516 | 33530 | fflush(stdout); |
| 33517 | 33531 | } |
| 33518 | 33532 | sqlite3TreeViewExpr(pView, pList->a[i].pExpr, moreToFollow); |
| 33519 | | - if( j || zName ){ |
| 33533 | + if( j || zName || sortFlags ){ |
| 33520 | 33534 | sqlite3TreeViewPop(&pView); |
| 33521 | 33535 | } |
| 33522 | 33536 | } |
| 33523 | 33537 | } |
| 33524 | 33538 | } |
| | @@ -40643,30 +40657,26 @@ |
| 40643 | 40657 | */ |
| 40644 | 40658 | #define DOTLOCK_SUFFIX ".lock" |
| 40645 | 40659 | |
| 40646 | 40660 | /* |
| 40647 | 40661 | ** This routine checks if there is a RESERVED lock held on the specified |
| 40648 | | -** file by this or any other process. If such a lock is held, set *pResOut |
| 40649 | | -** to a non-zero value otherwise *pResOut is set to zero. The return value |
| 40650 | | -** is set to SQLITE_OK unless an I/O error occurs during lock checking. |
| 40651 | | -** |
| 40652 | | -** In dotfile locking, either a lock exists or it does not. So in this |
| 40653 | | -** variation of CheckReservedLock(), *pResOut is set to true if any lock |
| 40654 | | -** is held on the file and false if the file is unlocked. |
| 40662 | +** file by this or any other process. If the caller holds a SHARED |
| 40663 | +** or greater lock when it is called, then it is assumed that no other |
| 40664 | +** client may hold RESERVED. Or, if the caller holds no lock, then it |
| 40665 | +** is assumed another client holds RESERVED if the lock-file exists. |
| 40655 | 40666 | */ |
| 40656 | 40667 | static int dotlockCheckReservedLock(sqlite3_file *id, int *pResOut) { |
| 40657 | | - int rc = SQLITE_OK; |
| 40658 | | - int reserved = 0; |
| 40659 | 40668 | unixFile *pFile = (unixFile*)id; |
| 40660 | | - |
| 40661 | 40669 | SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; ); |
| 40662 | 40670 | |
| 40663 | | - assert( pFile ); |
| 40664 | | - reserved = osAccess((const char*)pFile->lockingContext, 0)==0; |
| 40665 | | - OSTRACE(("TEST WR-LOCK %d %d %d (dotlock)\n", pFile->h, rc, reserved)); |
| 40666 | | - *pResOut = reserved; |
| 40667 | | - return rc; |
| 40671 | + if( pFile->eFileLock>=SHARED_LOCK ){ |
| 40672 | + *pResOut = 0; |
| 40673 | + }else{ |
| 40674 | + *pResOut = osAccess((const char*)pFile->lockingContext, 0)==0; |
| 40675 | + } |
| 40676 | + OSTRACE(("TEST WR-LOCK %d %d %d (dotlock)\n", pFile->h, 0, *pResOut)); |
| 40677 | + return SQLITE_OK; |
| 40668 | 40678 | } |
| 40669 | 40679 | |
| 40670 | 40680 | /* |
| 40671 | 40681 | ** Lock the file with the lock specified by parameter eFileLock - one |
| 40672 | 40682 | ** of the following: |
| | @@ -98433,10 +98443,11 @@ |
| 98433 | 98443 | if( r.nField>0 ){ |
| 98434 | 98444 | /* Key values in an array of registers */ |
| 98435 | 98445 | r.pKeyInfo = pC->pKeyInfo; |
| 98436 | 98446 | r.default_rc = 0; |
| 98437 | 98447 | #ifdef SQLITE_DEBUG |
| 98448 | + (void)sqlite3FaultSim(50); /* For use by --counter in TH3 */ |
| 98438 | 98449 | for(ii=0; ii<r.nField; ii++){ |
| 98439 | 98450 | assert( memIsValid(&r.aMem[ii]) ); |
| 98440 | 98451 | assert( (r.aMem[ii].flags & MEM_Zero)==0 || r.aMem[ii].n==0 ); |
| 98441 | 98452 | if( ii ) REGISTER_TRACE(pOp->p3+ii, &r.aMem[ii]); |
| 98442 | 98453 | } |
| | @@ -108130,11 +108141,10 @@ |
| 108130 | 108141 | } |
| 108131 | 108142 | assert( pNC->nRef>=nRef ); |
| 108132 | 108143 | if( nRef!=pNC->nRef ){ |
| 108133 | 108144 | ExprSetProperty(pExpr, EP_VarSelect); |
| 108134 | 108145 | pExpr->x.pSelect->selFlags |= SF_Correlated; |
| 108135 | | - if( pExpr->op==TK_EXISTS ) pParse->bHasExists = 1; |
| 108136 | 108146 | } |
| 108137 | 108147 | pNC->ncFlags |= NC_Subquery; |
| 108138 | 108148 | } |
| 108139 | 108149 | break; |
| 108140 | 108150 | } |
| | @@ -109133,11 +109143,13 @@ |
| 109133 | 109143 | || (pExpr->op==TK_REGISTER && pExpr->op2==TK_IF_NULL_ROW) ); |
| 109134 | 109144 | pExpr = pExpr->pLeft; |
| 109135 | 109145 | op = pExpr->op; |
| 109136 | 109146 | continue; |
| 109137 | 109147 | } |
| 109138 | | - if( op!=TK_REGISTER || (op = pExpr->op2)==TK_REGISTER ) break; |
| 109148 | + if( op!=TK_REGISTER ) break; |
| 109149 | + op = pExpr->op2; |
| 109150 | + if( NEVER( op==TK_REGISTER ) ) break; |
| 109139 | 109151 | } |
| 109140 | 109152 | return pExpr->affExpr; |
| 109141 | 109153 | } |
| 109142 | 109154 | |
| 109143 | 109155 | /* |
| | @@ -112582,19 +112594,34 @@ |
| 112582 | 112594 | if( ALWAYS(pEList->nExpr==nVal) ){ |
| 112583 | 112595 | Select *pCopy; |
| 112584 | 112596 | SelectDest dest; |
| 112585 | 112597 | int i; |
| 112586 | 112598 | int rc; |
| 112599 | + int addrBloom = 0; |
| 112587 | 112600 | sqlite3SelectDestInit(&dest, SRT_Set, iTab); |
| 112588 | 112601 | dest.zAffSdst = exprINAffinity(pParse, pExpr); |
| 112589 | 112602 | pSelect->iLimit = 0; |
| 112603 | + if( addrOnce && OptimizationEnabled(pParse->db, SQLITE_BloomFilter) ){ |
| 112604 | + int regBloom = ++pParse->nMem; |
| 112605 | + addrBloom = sqlite3VdbeAddOp2(v, OP_Blob, 10000, regBloom); |
| 112606 | + VdbeComment((v, "Bloom filter")); |
| 112607 | + dest.iSDParm2 = regBloom; |
| 112608 | + } |
| 112590 | 112609 | testcase( pSelect->selFlags & SF_Distinct ); |
| 112591 | 112610 | testcase( pKeyInfo==0 ); /* Caused by OOM in sqlite3KeyInfoAlloc() */ |
| 112592 | 112611 | pCopy = sqlite3SelectDup(pParse->db, pSelect, 0); |
| 112593 | 112612 | rc = pParse->db->mallocFailed ? 1 :sqlite3Select(pParse, pCopy, &dest); |
| 112594 | 112613 | sqlite3SelectDelete(pParse->db, pCopy); |
| 112595 | 112614 | sqlite3DbFree(pParse->db, dest.zAffSdst); |
| 112615 | + if( addrBloom ){ |
| 112616 | + sqlite3VdbeGetOp(v, addrOnce)->p3 = dest.iSDParm2; |
| 112617 | + if( dest.iSDParm2==0 ){ |
| 112618 | + sqlite3VdbeChangeToNoop(v, addrBloom); |
| 112619 | + }else{ |
| 112620 | + sqlite3VdbeGetOp(v, addrOnce)->p3 = dest.iSDParm2; |
| 112621 | + } |
| 112622 | + } |
| 112596 | 112623 | if( rc ){ |
| 112597 | 112624 | sqlite3KeyInfoUnref(pKeyInfo); |
| 112598 | 112625 | return; |
| 112599 | 112626 | } |
| 112600 | 112627 | assert( pKeyInfo!=0 ); /* OOM will cause exit after sqlite3Select() */ |
| | @@ -113033,10 +113060,19 @@ |
| 113033 | 113060 | addrTruthOp = sqlite3VdbeAddOp0(v, OP_Goto); /* Return True */ |
| 113034 | 113061 | }else{ |
| 113035 | 113062 | sqlite3VdbeAddOp4(v, OP_Affinity, rLhs, nVector, 0, zAff, nVector); |
| 113036 | 113063 | if( destIfFalse==destIfNull ){ |
| 113037 | 113064 | /* Combine Step 3 and Step 5 into a single opcode */ |
| 113065 | + if( ExprHasProperty(pExpr, EP_Subrtn) ){ |
| 113066 | + const VdbeOp *pOp = sqlite3VdbeGetOp(v, pExpr->y.sub.iAddr); |
| 113067 | + assert( pOp->opcode==OP_Once || pParse->nErr ); |
| 113068 | + if( pOp->opcode==OP_Once && pOp->p3>0 ){ |
| 113069 | + assert( OptimizationEnabled(pParse->db, SQLITE_BloomFilter) ); |
| 113070 | + sqlite3VdbeAddOp4Int(v, OP_Filter, pOp->p3, destIfFalse, |
| 113071 | + rLhs, nVector); VdbeCoverage(v); |
| 113072 | + } |
| 113073 | + } |
| 113038 | 113074 | sqlite3VdbeAddOp4Int(v, OP_NotFound, iTab, destIfFalse, |
| 113039 | 113075 | rLhs, nVector); VdbeCoverage(v); |
| 113040 | 113076 | goto sqlite3ExprCodeIN_finished; |
| 113041 | 113077 | } |
| 113042 | 113078 | /* Ordinary Step 3, for the case where FALSE and NULL are distinct */ |
| | @@ -113318,14 +113354,18 @@ |
| 113318 | 113354 | ** the correct value for the expression. |
| 113319 | 113355 | */ |
| 113320 | 113356 | SQLITE_PRIVATE void sqlite3ExprToRegister(Expr *pExpr, int iReg){ |
| 113321 | 113357 | Expr *p = sqlite3ExprSkipCollateAndLikely(pExpr); |
| 113322 | 113358 | if( NEVER(p==0) ) return; |
| 113323 | | - p->op2 = p->op; |
| 113324 | | - p->op = TK_REGISTER; |
| 113325 | | - p->iTable = iReg; |
| 113326 | | - ExprClearProperty(p, EP_Skip); |
| 113359 | + if( p->op==TK_REGISTER ){ |
| 113360 | + assert( p->iTable==iReg ); |
| 113361 | + }else{ |
| 113362 | + p->op2 = p->op; |
| 113363 | + p->op = TK_REGISTER; |
| 113364 | + p->iTable = iReg; |
| 113365 | + ExprClearProperty(p, EP_Skip); |
| 113366 | + } |
| 113327 | 113367 | } |
| 113328 | 113368 | |
| 113329 | 113369 | /* |
| 113330 | 113370 | ** Evaluate an expression (either a vector or a scalar expression) and store |
| 113331 | 113371 | ** the result in contiguous temporary registers. Return the index of |
| | @@ -126476,21 +126516,18 @@ |
| 126476 | 126516 | ** Append the contents of SrcList p2 to SrcList p1 and return the resulting |
| 126477 | 126517 | ** SrcList. Or, if an error occurs, return NULL. In all cases, p1 and p2 |
| 126478 | 126518 | ** are deleted by this function. |
| 126479 | 126519 | */ |
| 126480 | 126520 | SQLITE_PRIVATE SrcList *sqlite3SrcListAppendList(Parse *pParse, SrcList *p1, SrcList *p2){ |
| 126481 | | - assert( p1 ); |
| 126521 | + assert( p1 && p1->nSrc==1 ); |
| 126482 | 126522 | if( p2 ){ |
| 126483 | | - int nOld = p1->nSrc; |
| 126484 | | - SrcList *pNew = sqlite3SrcListEnlarge(pParse, p1, p2->nSrc, nOld); |
| 126523 | + SrcList *pNew = sqlite3SrcListEnlarge(pParse, p1, p2->nSrc, 1); |
| 126485 | 126524 | if( pNew==0 ){ |
| 126486 | 126525 | sqlite3SrcListDelete(pParse->db, p2); |
| 126487 | 126526 | }else{ |
| 126488 | 126527 | p1 = pNew; |
| 126489 | | - memcpy(&p1->a[nOld], p2->a, p2->nSrc*sizeof(SrcItem)); |
| 126490 | | - assert( nOld==1 || (p2->nSrc==1 && (p2->a[0].fg.jointype&JT_LTORJ)==0) ); |
| 126491 | | - assert( p1->nSrc>=2 ); |
| 126528 | + memcpy(&p1->a[1], p2->a, p2->nSrc*sizeof(SrcItem)); |
| 126492 | 126529 | sqlite3DbFree(pParse->db, p2); |
| 126493 | 126530 | p1->a[0].fg.jointype |= (JT_LTORJ & p1->a[1].fg.jointype); |
| 126494 | 126531 | } |
| 126495 | 126532 | } |
| 126496 | 126533 | return p1; |
| | @@ -144332,16 +144369,22 @@ |
| 144332 | 144369 | ** ORDER BY in this case since the order of entries in the set |
| 144333 | 144370 | ** does not matter. But there might be a LIMIT clause, in which |
| 144334 | 144371 | ** case the order does matter */ |
| 144335 | 144372 | pushOntoSorter( |
| 144336 | 144373 | pParse, pSort, p, regResult, regOrig, nResultCol, nPrefixReg); |
| 144374 | + pDest->iSDParm2 = 0; /* Signal that any Bloom filter is unpopulated */ |
| 144337 | 144375 | }else{ |
| 144338 | 144376 | int r1 = sqlite3GetTempReg(pParse); |
| 144339 | 144377 | assert( sqlite3Strlen30(pDest->zAffSdst)==nResultCol ); |
| 144340 | 144378 | sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult, nResultCol, |
| 144341 | 144379 | r1, pDest->zAffSdst, nResultCol); |
| 144342 | 144380 | sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regResult, nResultCol); |
| 144381 | + if( pDest->iSDParm2 ){ |
| 144382 | + sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pDest->iSDParm2, 0, |
| 144383 | + regResult, nResultCol); |
| 144384 | + ExplainQueryPlan((pParse, 0, "CREATE BLOOM FILTER")); |
| 144385 | + } |
| 144343 | 144386 | sqlite3ReleaseTempReg(pParse, r1); |
| 144344 | 144387 | } |
| 144345 | 144388 | break; |
| 144346 | 144389 | } |
| 144347 | 144390 | |
| | @@ -146271,10 +146314,15 @@ |
| 146271 | 146314 | r1 = sqlite3GetTempReg(pParse); |
| 146272 | 146315 | sqlite3VdbeAddOp4(v, OP_MakeRecord, pIn->iSdst, pIn->nSdst, |
| 146273 | 146316 | r1, pDest->zAffSdst, pIn->nSdst); |
| 146274 | 146317 | sqlite3VdbeAddOp4Int(v, OP_IdxInsert, pDest->iSDParm, r1, |
| 146275 | 146318 | pIn->iSdst, pIn->nSdst); |
| 146319 | + if( pDest->iSDParm2>0 ){ |
| 146320 | + sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pDest->iSDParm2, 0, |
| 146321 | + pIn->iSdst, pIn->nSdst); |
| 146322 | + ExplainQueryPlan((pParse, 0, "CREATE BLOOM FILTER")); |
| 146323 | + } |
| 146276 | 146324 | sqlite3ReleaseTempReg(pParse, r1); |
| 146277 | 146325 | break; |
| 146278 | 146326 | } |
| 146279 | 146327 | |
| 146280 | 146328 | /* If this is a scalar select that is part of an expression, then |
| | @@ -150238,162 +150286,10 @@ |
| 150238 | 150286 | if( pItem->pSelect!=0 ) return 0; /* (1c-i) */ |
| 150239 | 150287 | } |
| 150240 | 150288 | return 1; |
| 150241 | 150289 | } |
| 150242 | 150290 | |
| 150243 | | -/* |
| 150244 | | -** sqlite3WalkExpr() callback used by exprReferencesTable(). |
| 150245 | | -*/ |
| 150246 | | -static int exprReferencesTableExprCb(Walker *pWalker, Expr *pExpr){ |
| 150247 | | - if( pExpr->op==TK_COLUMN && pExpr->iTable==pWalker->u.iCur ){ |
| 150248 | | - pWalker->eCode = 1; |
| 150249 | | - } |
| 150250 | | - return WRC_Continue; |
| 150251 | | -} |
| 150252 | | - |
| 150253 | | -/* |
| 150254 | | -** Return true if the expression passed as the first argument refers |
| 150255 | | -** to cursor number iCur. Otherwise return false. |
| 150256 | | -*/ |
| 150257 | | -static int exprReferencesTable(Expr *pExpr, int iCur){ |
| 150258 | | - Walker w; |
| 150259 | | - memset(&w, 0, sizeof(w)); |
| 150260 | | - w.u.iCur = iCur; |
| 150261 | | - w.xExprCallback = exprReferencesTableExprCb; |
| 150262 | | - w.xSelectCallback = sqlite3SelectWalkNoop; |
| 150263 | | - sqlite3WalkExpr(&w, pExpr); |
| 150264 | | - return w.eCode; |
| 150265 | | -} |
| 150266 | | - |
| 150267 | | -/* |
| 150268 | | -** Index pIdx is a UNIQUE index on the table accessed by cursor number |
| 150269 | | -** iCsr. This function returns a mask of the index columns that are |
| 150270 | | -** constrained to match a single, non-NULL value by the WHERE clause |
| 150271 | | -** passed as the 4th argument. For example, if the index is: |
| 150272 | | -** |
| 150273 | | -** CREATE UNIQUE INDEX idx ON tbl(a, b, c); |
| 150274 | | -** |
| 150275 | | -** and pWhere: |
| 150276 | | -** |
| 150277 | | -** WHERE a=? AND c=? |
| 150278 | | -** |
| 150279 | | -** then this function returns 5. |
| 150280 | | -*/ |
| 150281 | | -static u64 findConstIdxTerms( |
| 150282 | | - Parse *pParse, |
| 150283 | | - int iCsr, |
| 150284 | | - Index *pIdx, |
| 150285 | | - Expr *pWhere |
| 150286 | | -){ |
| 150287 | | - u64 m = 0; |
| 150288 | | - if( pWhere->op==TK_AND ){ |
| 150289 | | - m = findConstIdxTerms(pParse, iCsr, pIdx, pWhere->pLeft); |
| 150290 | | - m |= findConstIdxTerms(pParse, iCsr, pIdx, pWhere->pRight); |
| 150291 | | - }else if( pWhere->op==TK_EQ ){ |
| 150292 | | - Expr *pLeft = sqlite3ExprSkipCollateAndLikely(pWhere->pLeft); |
| 150293 | | - Expr *pRight = sqlite3ExprSkipCollateAndLikely(pWhere->pRight); |
| 150294 | | - if( pRight->op==TK_COLUMN && pRight->iTable==iCsr ){ |
| 150295 | | - SWAP(Expr*, pLeft, pRight); |
| 150296 | | - } |
| 150297 | | - if( pLeft->op==TK_COLUMN |
| 150298 | | - && pLeft->iTable==iCsr |
| 150299 | | - && exprReferencesTable(pRight, iCsr)==0 |
| 150300 | | - ){ |
| 150301 | | - if( pIdx ){ |
| 150302 | | - int ii; |
| 150303 | | - for(ii=0; ii<pIdx->nKeyCol; ii++){ |
| 150304 | | - assert( pIdx->azColl[ii] ); |
| 150305 | | - if( pLeft->iColumn==pIdx->aiColumn[ii] ){ |
| 150306 | | - CollSeq *pColl = sqlite3ExprCompareCollSeq(pParse, pWhere); |
| 150307 | | - if( pColl && sqlite3StrICmp(pColl->zName, pIdx->azColl[ii])==0 ){ |
| 150308 | | - m |= ((u64)1 << ii); |
| 150309 | | - break; |
| 150310 | | - } |
| 150311 | | - } |
| 150312 | | - } |
| 150313 | | - }else{ |
| 150314 | | - if( pLeft->iColumn<0 ) m = 1; |
| 150315 | | - } |
| 150316 | | - } |
| 150317 | | - } |
| 150318 | | - return m; |
| 150319 | | -} |
| 150320 | | - |
| 150321 | | -/* |
| 150322 | | -** Argument pWhere is the WHERE clause belonging to SELECT statement p. This |
| 150323 | | -** function attempts to transform expressions of the form: |
| 150324 | | -** |
| 150325 | | -** EXISTS (SELECT ...) |
| 150326 | | -** |
| 150327 | | -** into joins. For example, given |
| 150328 | | -** |
| 150329 | | -** CREATE TABLE sailors(sid INTEGER PRIMARY KEY, name TEXT); |
| 150330 | | -** CREATE TABLE reserves(sid INT, day DATE, PRIMARY KEY(sid, day)); |
| 150331 | | -** |
| 150332 | | -** SELECT name FROM sailors AS S WHERE EXISTS ( |
| 150333 | | -** SELECT * FROM reserves AS R WHERE S.sid = R.sid AND R.day = '2022-10-25' |
| 150334 | | -** ); |
| 150335 | | -** |
| 150336 | | -** the SELECT statement may be transformed as follows: |
| 150337 | | -** |
| 150338 | | -** SELECT name FROM sailors AS S, reserves AS R |
| 150339 | | -** WHERE S.sid = R.sid AND R.day = '2022-10-25'; |
| 150340 | | -*/ |
| 150341 | | -static void existsToJoin(Parse *pParse, Select *p, Expr *pWhere){ |
| 150342 | | - if( pWhere && p->pSrc->nSrc>0 && pParse->db->mallocFailed==0 ){ |
| 150343 | | - if( pWhere->op==TK_AND ){ |
| 150344 | | - Expr *pRight = pWhere->pRight; |
| 150345 | | - existsToJoin(pParse, p, pWhere->pLeft); |
| 150346 | | - existsToJoin(pParse, p, pRight); |
| 150347 | | - } |
| 150348 | | - else if( pWhere->op==TK_EXISTS ){ |
| 150349 | | - Select *pSub = pWhere->x.pSelect; |
| 150350 | | - if( pSub->pSrc->nSrc==1 |
| 150351 | | - && (pSub->selFlags & (SF_Aggregate|SF_Correlated))==SF_Correlated |
| 150352 | | - && pSub->pWhere |
| 150353 | | - ){ |
| 150354 | | - int bTransform = 0; /* True if EXISTS can be made into join */ |
| 150355 | | - Table *pTab = pSub->pSrc->a[0].pTab; |
| 150356 | | - int iCsr = pSub->pSrc->a[0].iCursor; |
| 150357 | | - Index *pIdx; |
| 150358 | | - if( HasRowid(pTab) && findConstIdxTerms(pParse, iCsr, 0,pSub->pWhere) ){ |
| 150359 | | - bTransform = 1; |
| 150360 | | - } |
| 150361 | | - for(pIdx=pTab->pIndex; pIdx && bTransform==0; pIdx=pIdx->pNext){ |
| 150362 | | - if( pIdx->onError && pIdx->nKeyCol<=63 ){ |
| 150363 | | - u64 c = findConstIdxTerms(pParse, iCsr, pIdx, pSub->pWhere); |
| 150364 | | - if( c==((u64)1 << pIdx->nKeyCol)-1 ){ |
| 150365 | | - bTransform = 1; |
| 150366 | | - } |
| 150367 | | - } |
| 150368 | | - } |
| 150369 | | - if( bTransform ){ |
| 150370 | | - memset(pWhere, 0, sizeof(*pWhere)); |
| 150371 | | - pWhere->op = TK_INTEGER; |
| 150372 | | - pWhere->u.iValue = 1; |
| 150373 | | - ExprSetProperty(pWhere, EP_IntValue); |
| 150374 | | - |
| 150375 | | - assert( p->pWhere!=0 ); |
| 150376 | | - p->pSrc = sqlite3SrcListAppendList(pParse, p->pSrc, pSub->pSrc); |
| 150377 | | - p->pWhere = sqlite3PExpr(pParse, TK_AND, p->pWhere, pSub->pWhere); |
| 150378 | | - |
| 150379 | | - pSub->pWhere = 0; |
| 150380 | | - pSub->pSrc = 0; |
| 150381 | | - sqlite3ParserAddCleanup(pParse, sqlite3SelectDeleteGeneric, pSub); |
| 150382 | | -#if TREETRACE_ENABLED |
| 150383 | | - if( sqlite3TreeTrace & 0x100000 ){ |
| 150384 | | - TREETRACE(0x100000,pParse,p, |
| 150385 | | - ("After EXISTS-to-JOIN optimization:\n")); |
| 150386 | | - sqlite3TreeViewSelect(0, p, 0); |
| 150387 | | - } |
| 150388 | | -#endif |
| 150389 | | - } |
| 150390 | | - } |
| 150391 | | - } |
| 150392 | | - } |
| 150393 | | -} |
| 150394 | | - |
| 150395 | 150291 | /* |
| 150396 | 150292 | ** Generate code for the SELECT statement given in the p argument. |
| 150397 | 150293 | ** |
| 150398 | 150294 | ** The results are returned according to the SelectDest structure. |
| 150399 | 150295 | ** See comments in sqliteInt.h for further information. |
| | @@ -150642,17 +150538,20 @@ |
| 150642 | 150538 | ** (5) The ORDER BY isn't going to accomplish anything because |
| 150643 | 150539 | ** one of: |
| 150644 | 150540 | ** (a) The outer query has a different ORDER BY clause |
| 150645 | 150541 | ** (b) The subquery is part of a join |
| 150646 | 150542 | ** See forum post 062d576715d277c8 |
| 150543 | + ** (6) The subquery is not a recursive CTE. ORDER BY has a different |
| 150544 | + ** meaning for recursive CTEs and this optimization does not |
| 150545 | + ** apply. |
| 150647 | 150546 | ** |
| 150648 | 150547 | ** Also retain the ORDER BY if the OmitOrderBy optimization is disabled. |
| 150649 | 150548 | */ |
| 150650 | 150549 | if( pSub->pOrderBy!=0 |
| 150651 | 150550 | && (p->pOrderBy!=0 || pTabList->nSrc>1) /* Condition (5) */ |
| 150652 | 150551 | && pSub->pLimit==0 /* Condition (1) */ |
| 150653 | | - && (pSub->selFlags & SF_OrderByReqd)==0 /* Condition (2) */ |
| 150552 | + && (pSub->selFlags & (SF_OrderByReqd|SF_Recursive))==0 /* (2) and (6) */ |
| 150654 | 150553 | && (p->selFlags & SF_OrderByReqd)==0 /* Condition (3) and (4) */ |
| 150655 | 150554 | && OptimizationEnabled(db, SQLITE_OmitOrderBy) |
| 150656 | 150555 | ){ |
| 150657 | 150556 | TREETRACE(0x800,pParse,p, |
| 150658 | 150557 | ("omit superfluous ORDER BY on %r FROM-clause subquery\n",i+1)); |
| | @@ -150716,17 +150615,10 @@ |
| 150716 | 150615 | if( p->pNext==0 ) ExplainQueryPlanPop(pParse); |
| 150717 | 150616 | return rc; |
| 150718 | 150617 | } |
| 150719 | 150618 | #endif |
| 150720 | 150619 | |
| 150721 | | - /* If there may be an "EXISTS (SELECT ...)" in the WHERE clause, attempt |
| 150722 | | - ** to change it into a join. */ |
| 150723 | | - if( pParse->bHasExists && OptimizationEnabled(db,SQLITE_ExistsToJoin) ){ |
| 150724 | | - existsToJoin(pParse, p, p->pWhere); |
| 150725 | | - pTabList = p->pSrc; |
| 150726 | | - } |
| 150727 | | - |
| 150728 | 150620 | /* Do the WHERE-clause constant propagation optimization if this is |
| 150729 | 150621 | ** a join. No need to speed time on this operation for non-join queries |
| 150730 | 150622 | ** as the equivalent optimization will be handled by query planner in |
| 150731 | 150623 | ** sqlite3WhereBegin(). |
| 150732 | 150624 | */ |
| | @@ -151447,11 +151339,14 @@ |
| 151447 | 151339 | } |
| 151448 | 151340 | |
| 151449 | 151341 | if( iOrderByCol ){ |
| 151450 | 151342 | Expr *pX = p->pEList->a[iOrderByCol-1].pExpr; |
| 151451 | 151343 | Expr *pBase = sqlite3ExprSkipCollateAndLikely(pX); |
| 151452 | | - if( ALWAYS(pBase!=0) && pBase->op!=TK_AGG_COLUMN ){ |
| 151344 | + if( ALWAYS(pBase!=0) |
| 151345 | + && pBase->op!=TK_AGG_COLUMN |
| 151346 | + && pBase->op!=TK_REGISTER |
| 151347 | + ){ |
| 151453 | 151348 | sqlite3ExprToRegister(pX, iAMem+j); |
| 151454 | 151349 | } |
| 151455 | 151350 | } |
| 151456 | 151351 | } |
| 151457 | 151352 | sqlite3VdbeAddOp4(v, OP_Compare, iAMem, iBMem, pGroupBy->nExpr, |
| | @@ -167412,11 +167307,11 @@ |
| 167412 | 167307 | nColumn = pIndex->nColumn; |
| 167413 | 167308 | assert( nColumn==nKeyCol+1 || !HasRowid(pIndex->pTable) ); |
| 167414 | 167309 | assert( pIndex->aiColumn[nColumn-1]==XN_ROWID |
| 167415 | 167310 | || !HasRowid(pIndex->pTable)); |
| 167416 | 167311 | /* All relevant terms of the index must also be non-NULL in order |
| 167417 | | - ** for isOrderDistinct to be true. So the isOrderDistint value |
| 167312 | + ** for isOrderDistinct to be true. So the isOrderDistinct value |
| 167418 | 167313 | ** computed here might be a false positive. Corrections will be |
| 167419 | 167314 | ** made at tag-20210426-1 below */ |
| 167420 | 167315 | isOrderDistinct = IsUniqueIndex(pIndex) |
| 167421 | 167316 | && (pLoop->wsFlags & WHERE_SKIPSCAN)==0; |
| 167422 | 167317 | } |
| | @@ -232187,10 +232082,14 @@ |
| 232187 | 232082 | ** "detail=none" or "detail=column" option. If the FTS5 table is created |
| 232188 | 232083 | ** with either "detail=none" or "detail=column" and "content=" option |
| 232189 | 232084 | ** (i.e. if it is a contentless table), then this API always iterates |
| 232190 | 232085 | ** through an empty set (all calls to xPhraseFirst() set iCol to -1). |
| 232191 | 232086 | ** |
| 232087 | +** In all cases, matches are visited in (column ASC, offset ASC) order. |
| 232088 | +** i.e. all those in column 0, sorted by offset, followed by those in |
| 232089 | +** column 1, etc. |
| 232090 | +** |
| 232192 | 232091 | ** xPhraseNext() |
| 232193 | 232092 | ** See xPhraseFirst above. |
| 232194 | 232093 | ** |
| 232195 | 232094 | ** xPhraseFirstColumn() |
| 232196 | 232095 | ** This function and xPhraseNextColumn() are similar to the xPhraseFirst() |
| | @@ -239066,10 +238965,11 @@ |
| 239066 | 238965 | ** no token characters at all. (e.g ... MATCH '""'). */ |
| 239067 | 238966 | sCtx.pPhrase = sqlite3Fts5MallocZero(&pParse->rc, sizeof(Fts5ExprPhrase)); |
| 239068 | 238967 | }else if( sCtx.pPhrase->nTerm ){ |
| 239069 | 238968 | sCtx.pPhrase->aTerm[sCtx.pPhrase->nTerm-1].bPrefix = (u8)bPrefix; |
| 239070 | 238969 | } |
| 238970 | + assert( pParse->apPhrase!=0 ); |
| 239071 | 238971 | pParse->apPhrase[pParse->nPhrase-1] = sCtx.pPhrase; |
| 239072 | 238972 | } |
| 239073 | 238973 | |
| 239074 | 238974 | return sCtx.pPhrase; |
| 239075 | 238975 | } |
| | @@ -239085,11 +238985,11 @@ |
| 239085 | 238985 | ){ |
| 239086 | 238986 | int rc = SQLITE_OK; /* Return code */ |
| 239087 | 238987 | Fts5ExprPhrase *pOrig = 0; /* The phrase extracted from pExpr */ |
| 239088 | 238988 | Fts5Expr *pNew = 0; /* Expression to return via *ppNew */ |
| 239089 | 238989 | TokenCtx sCtx = {0,0,0}; /* Context object for fts5ParseTokenize */ |
| 239090 | | - if( iPhrase<0 || iPhrase>=pExpr->nPhrase ){ |
| 238990 | + if( !pExpr || iPhrase<0 || iPhrase>=pExpr->nPhrase ){ |
| 239091 | 238991 | rc = SQLITE_RANGE; |
| 239092 | 238992 | }else{ |
| 239093 | 238993 | pOrig = pExpr->apExprPhrase[iPhrase]; |
| 239094 | 238994 | pNew = (Fts5Expr*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Expr)); |
| 239095 | 238995 | } |
| | @@ -239660,10 +239560,12 @@ |
| 239660 | 239560 | || pPrev->eType==FTS5_TERM |
| 239661 | 239561 | || pPrev->eType==FTS5_EOF |
| 239662 | 239562 | ); |
| 239663 | 239563 | |
| 239664 | 239564 | if( pRight->eType==FTS5_EOF ){ |
| 239565 | + assert( pParse->apPhrase!=0 ); |
| 239566 | + assert( pParse->nPhrase>0 ); |
| 239665 | 239567 | assert( pParse->apPhrase[pParse->nPhrase-1]==pRight->pNear->apPhrase[0] ); |
| 239666 | 239568 | sqlite3Fts5ParseNodeFree(pRight); |
| 239667 | 239569 | pRet = pLeft; |
| 239668 | 239570 | pParse->nPhrase--; |
| 239669 | 239571 | } |
| | @@ -251077,10 +250979,11 @@ |
| 251077 | 250979 | "%s", sqlite3_errmsg(pConfig->db) |
| 251078 | 250980 | ); |
| 251079 | 250981 | } |
| 251080 | 250982 | }else{ |
| 251081 | 250983 | rc = SQLITE_OK; |
| 250984 | + CsrFlagSet(pCsr, FTS5CSR_REQUIRE_DOCSIZE); |
| 251082 | 250985 | } |
| 251083 | 250986 | break; |
| 251084 | 250987 | } |
| 251085 | 250988 | } |
| 251086 | 250989 | } |
| | @@ -251550,13 +251453,17 @@ |
| 251550 | 251453 | */ |
| 251551 | 251454 | static i64 fts5CursorRowid(Fts5Cursor *pCsr){ |
| 251552 | 251455 | assert( pCsr->ePlan==FTS5_PLAN_MATCH |
| 251553 | 251456 | || pCsr->ePlan==FTS5_PLAN_SORTED_MATCH |
| 251554 | 251457 | || pCsr->ePlan==FTS5_PLAN_SOURCE |
| 251458 | + || pCsr->ePlan==FTS5_PLAN_SCAN |
| 251459 | + || pCsr->ePlan==FTS5_PLAN_ROWID |
| 251555 | 251460 | ); |
| 251556 | 251461 | if( pCsr->pSorter ){ |
| 251557 | 251462 | return pCsr->pSorter->iRowid; |
| 251463 | + }else if( pCsr->ePlan>=FTS5_PLAN_SCAN ){ |
| 251464 | + return sqlite3_column_int64(pCsr->pStmt, 0); |
| 251558 | 251465 | }else{ |
| 251559 | 251466 | return sqlite3Fts5ExprRowid(pCsr->pExpr); |
| 251560 | 251467 | } |
| 251561 | 251468 | } |
| 251562 | 251469 | |
| | @@ -251569,24 +251476,14 @@ |
| 251569 | 251476 | static int fts5RowidMethod(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){ |
| 251570 | 251477 | Fts5Cursor *pCsr = (Fts5Cursor*)pCursor; |
| 251571 | 251478 | int ePlan = pCsr->ePlan; |
| 251572 | 251479 | |
| 251573 | 251480 | assert( CsrFlagTest(pCsr, FTS5CSR_EOF)==0 ); |
| 251574 | | - switch( ePlan ){ |
| 251575 | | - case FTS5_PLAN_SPECIAL: |
| 251576 | | - *pRowid = 0; |
| 251577 | | - break; |
| 251578 | | - |
| 251579 | | - case FTS5_PLAN_SOURCE: |
| 251580 | | - case FTS5_PLAN_MATCH: |
| 251581 | | - case FTS5_PLAN_SORTED_MATCH: |
| 251582 | | - *pRowid = fts5CursorRowid(pCsr); |
| 251583 | | - break; |
| 251584 | | - |
| 251585 | | - default: |
| 251586 | | - *pRowid = sqlite3_column_int64(pCsr->pStmt, 0); |
| 251587 | | - break; |
| 251481 | + if( ePlan==FTS5_PLAN_SPECIAL ){ |
| 251482 | + *pRowid = 0; |
| 251483 | + }else{ |
| 251484 | + *pRowid = fts5CursorRowid(pCsr); |
| 251588 | 251485 | } |
| 251589 | 251486 | |
| 251590 | 251487 | return SQLITE_OK; |
| 251591 | 251488 | } |
| 251592 | 251489 | |
| | @@ -253071,11 +252968,11 @@ |
| 253071 | 252968 | int nArg, /* Number of args */ |
| 253072 | 252969 | sqlite3_value **apUnused /* Function arguments */ |
| 253073 | 252970 | ){ |
| 253074 | 252971 | assert( nArg==0 ); |
| 253075 | 252972 | UNUSED_PARAM2(nArg, apUnused); |
| 253076 | | - sqlite3_result_text(pCtx, "fts5: 2024-06-11 17:37:36 5f25a9518a675efbd0525cc2f5595ee7bc7122be7cfecdf6b20c909185dea370", -1, SQLITE_TRANSIENT); |
| 252973 | + sqlite3_result_text(pCtx, "fts5: 2024-07-03 20:19:33 baa83b460c677c210c7fa3f20314d7e05f305aed8a69026bc5fa106a3de4ea38", -1, SQLITE_TRANSIENT); |
| 253077 | 252974 | } |
| 253078 | 252975 | |
| 253079 | 252976 | /* |
| 253080 | 252977 | ** Return true if zName is the extension on one of the shadow tables used |
| 253081 | 252978 | ** by this module. |
| 253082 | 252979 | |