| | @@ -1,8 +1,8 @@ |
| 1 | 1 | /****************************************************************************** |
| 2 | 2 | ** This file is an amalgamation of many separate C source files from SQLite |
| 3 | | -** version 3.48.0. By combining all the individual C code files into this |
| 3 | +** version 3.49.0. By combining all the individual C code files into this |
| 4 | 4 | ** single large file, the entire code can be compiled as a single translation |
| 5 | 5 | ** unit. This allows many compilers to do optimizations that would not be |
| 6 | 6 | ** possible if the files were compiled separately. Performance improvements |
| 7 | 7 | ** of 5% or more are commonly seen when SQLite is compiled as a single |
| 8 | 8 | ** translation unit. |
| | @@ -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 | | -** d2fe6b05f38d9d7cd78c5d252e99ac59f1ae with changes in files: |
| 21 | +** d7c07581203a0a88456588e49e51b40a8341 with changes in files: |
| 22 | 22 | ** |
| 23 | 23 | ** |
| 24 | 24 | */ |
| 25 | 25 | #ifndef SQLITE_AMALGAMATION |
| 26 | 26 | #define SQLITE_CORE 1 |
| | @@ -463,13 +463,13 @@ |
| 463 | 463 | ** |
| 464 | 464 | ** See also: [sqlite3_libversion()], |
| 465 | 465 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 466 | 466 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 467 | 467 | */ |
| 468 | | -#define SQLITE_VERSION "3.48.0" |
| 469 | | -#define SQLITE_VERSION_NUMBER 3048000 |
| 470 | | -#define SQLITE_SOURCE_ID "2025-01-14 11:05:00 d2fe6b05f38d9d7cd78c5d252e99ac59f1aea071d669830c1ffe4e8966e84010" |
| 468 | +#define SQLITE_VERSION "3.49.0" |
| 469 | +#define SQLITE_VERSION_NUMBER 3049000 |
| 470 | +#define SQLITE_SOURCE_ID "2025-01-29 18:53:19 d7c07581203a0a88456588e49e51b40a8341b0e7121809f75be0ee882d91650f" |
| 471 | 471 | |
| 472 | 472 | /* |
| 473 | 473 | ** CAPI3REF: Run-Time Library Version Numbers |
| 474 | 474 | ** KEYWORDS: sqlite3_version sqlite3_sourceid |
| 475 | 475 | ** |
| | @@ -11065,12 +11065,13 @@ |
| 11065 | 11065 | SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb); |
| 11066 | 11066 | |
| 11067 | 11067 | /* |
| 11068 | 11068 | ** CAPI3REF: Serialize a database |
| 11069 | 11069 | ** |
| 11070 | | -** The sqlite3_serialize(D,S,P,F) interface returns a pointer to memory |
| 11071 | | -** that is a serialization of the S database on [database connection] D. |
| 11070 | +** The sqlite3_serialize(D,S,P,F) interface returns a pointer to |
| 11071 | +** memory that is a serialization of the S database on |
| 11072 | +** [database connection] D. If S is a NULL pointer, the main database is used. |
| 11072 | 11073 | ** If P is not a NULL pointer, then the size of the database in bytes |
| 11073 | 11074 | ** is written into *P. |
| 11074 | 11075 | ** |
| 11075 | 11076 | ** For an ordinary on-disk database file, the serialization is just a |
| 11076 | 11077 | ** copy of the disk file. For an in-memory database or a "TEMP" database, |
| | @@ -15127,10 +15128,12 @@ |
| 15127 | 15128 | ** Examples: |
| 15128 | 15129 | ** |
| 15129 | 15130 | ** 0.5 -> -10 0.1 -> -33 0.0625 -> -40 |
| 15130 | 15131 | */ |
| 15131 | 15132 | typedef INT16_TYPE LogEst; |
| 15133 | +#define LOGEST_MIN (-32768) |
| 15134 | +#define LOGEST_MAX (32767) |
| 15132 | 15135 | |
| 15133 | 15136 | /* |
| 15134 | 15137 | ** Set the SQLITE_PTRSIZE macro to the number of bytes in a pointer |
| 15135 | 15138 | */ |
| 15136 | 15139 | #ifndef SQLITE_PTRSIZE |
| | @@ -15397,11 +15400,11 @@ |
| 15397 | 15400 | ** 0x-------F High-level debug messages |
| 15398 | 15401 | ** 0x----FFF- More detail |
| 15399 | 15402 | ** 0xFFFF---- Low-level debug messages |
| 15400 | 15403 | ** |
| 15401 | 15404 | ** 0x00000001 Code generation |
| 15402 | | -** 0x00000002 Solver |
| 15405 | +** 0x00000002 Solver (Use 0x40000 for less detail) |
| 15403 | 15406 | ** 0x00000004 Solver costs |
| 15404 | 15407 | ** 0x00000008 WhereLoop inserts |
| 15405 | 15408 | ** |
| 15406 | 15409 | ** 0x00000010 Display sqlite3_index_info xBestIndex calls |
| 15407 | 15410 | ** 0x00000020 Range an equality scan metrics |
| | @@ -15416,10 +15419,12 @@ |
| 15416 | 15419 | ** 0x00004000 Show all WHERE terms at key points |
| 15417 | 15420 | ** 0x00008000 Show the full SELECT statement at key places |
| 15418 | 15421 | ** |
| 15419 | 15422 | ** 0x00010000 Show more detail when printing WHERE terms |
| 15420 | 15423 | ** 0x00020000 Show WHERE terms returned from whereScanNext() |
| 15424 | +** 0x00040000 Solver overview messages |
| 15425 | +** 0x00080000 Star-query heuristic |
| 15421 | 15426 | */ |
| 15422 | 15427 | |
| 15423 | 15428 | |
| 15424 | 15429 | /* |
| 15425 | 15430 | ** An instance of the following structure is used to store the busy-handler |
| | @@ -18097,10 +18102,11 @@ |
| 18097 | 18102 | #define SQLITE_IndexedExpr 0x01000000 /* Pull exprs from index when able */ |
| 18098 | 18103 | #define SQLITE_Coroutines 0x02000000 /* Co-routines for subqueries */ |
| 18099 | 18104 | #define SQLITE_NullUnusedCols 0x04000000 /* NULL unused columns in subqueries */ |
| 18100 | 18105 | #define SQLITE_OnePass 0x08000000 /* Single-pass DELETE and UPDATE */ |
| 18101 | 18106 | #define SQLITE_OrderBySubq 0x10000000 /* ORDER BY in subquery helps outer */ |
| 18107 | +#define SQLITE_StarQuery 0x20000000 /* Heurists for star queries */ |
| 18102 | 18108 | #define SQLITE_AllOpts 0xffffffff /* All optimizations */ |
| 18103 | 18109 | |
| 18104 | 18110 | /* |
| 18105 | 18111 | ** Macros for testing whether or not optimizations are enabled or disabled. |
| 18106 | 18112 | */ |
| | @@ -19426,17 +19432,12 @@ |
| 19426 | 19432 | ** |
| 19427 | 19433 | ** If "a" is the k-th column of table "t", then IdList.a[0].idx==k. |
| 19428 | 19434 | */ |
| 19429 | 19435 | struct IdList { |
| 19430 | 19436 | int nId; /* Number of identifiers on the list */ |
| 19431 | | - u8 eU4; /* Which element of a.u4 is valid */ |
| 19432 | 19437 | struct IdList_item { |
| 19433 | 19438 | char *zName; /* Name of the identifier */ |
| 19434 | | - union { |
| 19435 | | - int idx; /* Index in some Table.aCol[] of a column named zName */ |
| 19436 | | - Expr *pExpr; /* Expr to implement a USING variable -- NOT USED */ |
| 19437 | | - } u4; |
| 19438 | 19439 | } a[1]; |
| 19439 | 19440 | }; |
| 19440 | 19441 | |
| 19441 | 19442 | /* |
| 19442 | 19443 | ** Allowed values for IdList.eType, which determines which value of the a.u4 |
| | @@ -23579,10 +23580,11 @@ |
| 23579 | 23580 | char *zMalloc; /* Space to hold MEM_Str or MEM_Blob if szMalloc>0 */ |
| 23580 | 23581 | void (*xDel)(void*);/* Destructor for Mem.z - only valid if MEM_Dyn */ |
| 23581 | 23582 | #ifdef SQLITE_DEBUG |
| 23582 | 23583 | Mem *pScopyFrom; /* This Mem is a shallow copy of pScopyFrom */ |
| 23583 | 23584 | u16 mScopyFlags; /* flags value immediately after the shallow copy */ |
| 23585 | + u8 bScopy; /* The pScopyFrom of some other Mem *might* point here */ |
| 23584 | 23586 | #endif |
| 23585 | 23587 | }; |
| 23586 | 23588 | |
| 23587 | 23589 | /* |
| 23588 | 23590 | ** Size of struct Mem not including the Mem.zMalloc member or anything that |
| | @@ -24677,10 +24679,13 @@ |
| 24677 | 24679 | ms = ms*10.0 + *zDate - '0'; |
| 24678 | 24680 | rScale *= 10.0; |
| 24679 | 24681 | zDate++; |
| 24680 | 24682 | } |
| 24681 | 24683 | ms /= rScale; |
| 24684 | + /* Truncate to avoid problems with sub-milliseconds |
| 24685 | + ** rounding. https://sqlite.org/forum/forumpost/766a2c9231 */ |
| 24686 | + if( ms>0.999 ) ms = 0.999; |
| 24682 | 24687 | } |
| 24683 | 24688 | }else{ |
| 24684 | 24689 | s = 0; |
| 24685 | 24690 | } |
| 24686 | 24691 | p->validJD = 0; |
| | @@ -25884,11 +25889,11 @@ |
| 25884 | 25889 | sqlite3_str_appendf(&sRes, cf=='d' ? "%02d" : "%2d", x.D); |
| 25885 | 25890 | break; |
| 25886 | 25891 | } |
| 25887 | 25892 | case 'f': { /* Fractional seconds. (Non-standard) */ |
| 25888 | 25893 | double s = x.s; |
| 25889 | | - if( s>59.999 ) s = 59.999; |
| 25894 | + if( NEVER(s>59.999) ) s = 59.999; |
| 25890 | 25895 | sqlite3_str_appendf(&sRes, "%06.3f", s); |
| 25891 | 25896 | break; |
| 25892 | 25897 | } |
| 25893 | 25898 | case 'F': { |
| 25894 | 25899 | sqlite3_str_appendf(&sRes, "%04d-%02d-%02d", x.Y, x.M, x.D); |
| | @@ -33815,25 +33820,11 @@ |
| 33815 | 33820 | char *zName = pList->a[i].zName; |
| 33816 | 33821 | int moreToFollow = i<pList->nId - 1; |
| 33817 | 33822 | if( zName==0 ) zName = "(null)"; |
| 33818 | 33823 | sqlite3TreeViewPush(&pView, moreToFollow); |
| 33819 | 33824 | sqlite3TreeViewLine(pView, 0); |
| 33820 | | - if( pList->eU4==EU4_NONE ){ |
| 33821 | | - fprintf(stdout, "%s\n", zName); |
| 33822 | | - }else if( pList->eU4==EU4_IDX ){ |
| 33823 | | - fprintf(stdout, "%s (%d)\n", zName, pList->a[i].u4.idx); |
| 33824 | | - }else{ |
| 33825 | | - assert( pList->eU4==EU4_EXPR ); |
| 33826 | | - if( pList->a[i].u4.pExpr==0 ){ |
| 33827 | | - fprintf(stdout, "%s (pExpr=NULL)\n", zName); |
| 33828 | | - }else{ |
| 33829 | | - fprintf(stdout, "%s\n", zName); |
| 33830 | | - sqlite3TreeViewPush(&pView, i<pList->nId-1); |
| 33831 | | - sqlite3TreeViewExpr(pView, pList->a[i].u4.pExpr, 0); |
| 33832 | | - sqlite3TreeViewPop(&pView); |
| 33833 | | - } |
| 33834 | | - } |
| 33825 | + fprintf(stdout, "%s\n", zName); |
| 33835 | 33826 | sqlite3TreeViewPop(&pView); |
| 33836 | 33827 | } |
| 33837 | 33828 | } |
| 33838 | 33829 | } |
| 33839 | 33830 | SQLITE_PRIVATE void sqlite3TreeViewIdList( |
| | @@ -40170,11 +40161,11 @@ |
| 40170 | 40161 | assert( pInode!=0 ); |
| 40171 | 40162 | assert( sqlite3_mutex_held(pInode->pLockMutex) ); |
| 40172 | 40163 | if( (pFile->ctrlFlags & (UNIXFILE_EXCL|UNIXFILE_RDONLY))==UNIXFILE_EXCL ){ |
| 40173 | 40164 | if( pInode->bProcessLock==0 ){ |
| 40174 | 40165 | struct flock lock; |
| 40175 | | - assert( pInode->nLock==0 ); |
| 40166 | + /* assert( pInode->nLock==0 ); <-- Not true if unix-excl READONLY used */ |
| 40176 | 40167 | lock.l_whence = SEEK_SET; |
| 40177 | 40168 | lock.l_start = SHARED_FIRST; |
| 40178 | 40169 | lock.l_len = SHARED_SIZE; |
| 40179 | 40170 | lock.l_type = F_WRLCK; |
| 40180 | 40171 | rc = osSetPosixAdvisoryLock(pFile->h, &lock, pFile); |
| | @@ -58053,11 +58044,11 @@ |
| 58053 | 58044 | if( sqlite3PCacheIsDirty(pPager->pPCache) ) return 0; /* Failed (3) */ |
| 58054 | 58045 | #ifndef SQLITE_OMIT_WAL |
| 58055 | 58046 | if( pPager->pWal ){ |
| 58056 | 58047 | u32 iRead = 0; |
| 58057 | 58048 | (void)sqlite3WalFindFrame(pPager->pWal, pgno, &iRead); |
| 58058 | | - return iRead==0; /* Condition (4) */ |
| 58049 | + if( iRead ) return 0; /* Case (4) */ |
| 58059 | 58050 | } |
| 58060 | 58051 | #endif |
| 58061 | 58052 | assert( pPager->fd->pMethods->xDeviceCharacteristics!=0 ); |
| 58062 | 58053 | if( (pPager->fd->pMethods->xDeviceCharacteristics(pPager->fd) |
| 58063 | 58054 | & SQLITE_IOCAP_SUBPAGE_READ)==0 ){ |
| | @@ -84001,31 +83992,34 @@ |
| 84001 | 83992 | ** copies (created by OP_SCopy) are not misused. |
| 84002 | 83993 | */ |
| 84003 | 83994 | SQLITE_PRIVATE void sqlite3VdbeMemAboutToChange(Vdbe *pVdbe, Mem *pMem){ |
| 84004 | 83995 | int i; |
| 84005 | 83996 | Mem *pX; |
| 84006 | | - for(i=1, pX=pVdbe->aMem+1; i<pVdbe->nMem; i++, pX++){ |
| 84007 | | - if( pX->pScopyFrom==pMem ){ |
| 84008 | | - u16 mFlags; |
| 84009 | | - if( pVdbe->db->flags & SQLITE_VdbeTrace ){ |
| 84010 | | - sqlite3DebugPrintf("Invalidate R[%d] due to change in R[%d]\n", |
| 84011 | | - (int)(pX - pVdbe->aMem), (int)(pMem - pVdbe->aMem)); |
| 84012 | | - } |
| 84013 | | - /* If pX is marked as a shallow copy of pMem, then try to verify that |
| 84014 | | - ** no significant changes have been made to pX since the OP_SCopy. |
| 84015 | | - ** A significant change would indicated a missed call to this |
| 84016 | | - ** function for pX. Minor changes, such as adding or removing a |
| 84017 | | - ** dual type, are allowed, as long as the underlying value is the |
| 84018 | | - ** same. */ |
| 84019 | | - mFlags = pMem->flags & pX->flags & pX->mScopyFlags; |
| 84020 | | - assert( (mFlags&(MEM_Int|MEM_IntReal))==0 || pMem->u.i==pX->u.i ); |
| 84021 | | - |
| 84022 | | - /* pMem is the register that is changing. But also mark pX as |
| 84023 | | - ** undefined so that we can quickly detect the shallow-copy error */ |
| 84024 | | - pX->flags = MEM_Undefined; |
| 84025 | | - pX->pScopyFrom = 0; |
| 84026 | | - } |
| 83997 | + if( pMem->bScopy ){ |
| 83998 | + for(i=1, pX=pVdbe->aMem+1; i<pVdbe->nMem; i++, pX++){ |
| 83999 | + if( pX->pScopyFrom==pMem ){ |
| 84000 | + u16 mFlags; |
| 84001 | + if( pVdbe->db->flags & SQLITE_VdbeTrace ){ |
| 84002 | + sqlite3DebugPrintf("Invalidate R[%d] due to change in R[%d]\n", |
| 84003 | + (int)(pX - pVdbe->aMem), (int)(pMem - pVdbe->aMem)); |
| 84004 | + } |
| 84005 | + /* If pX is marked as a shallow copy of pMem, then try to verify that |
| 84006 | + ** no significant changes have been made to pX since the OP_SCopy. |
| 84007 | + ** A significant change would indicated a missed call to this |
| 84008 | + ** function for pX. Minor changes, such as adding or removing a |
| 84009 | + ** dual type, are allowed, as long as the underlying value is the |
| 84010 | + ** same. */ |
| 84011 | + mFlags = pMem->flags & pX->flags & pX->mScopyFlags; |
| 84012 | + assert( (mFlags&(MEM_Int|MEM_IntReal))==0 || pMem->u.i==pX->u.i ); |
| 84013 | + |
| 84014 | + /* pMem is the register that is changing. But also mark pX as |
| 84015 | + ** undefined so that we can quickly detect the shallow-copy error */ |
| 84016 | + pX->flags = MEM_Undefined; |
| 84017 | + pX->pScopyFrom = 0; |
| 84018 | + } |
| 84019 | + } |
| 84020 | + pMem->bScopy = 0; |
| 84027 | 84021 | } |
| 84028 | 84022 | pMem->pScopyFrom = 0; |
| 84029 | 84023 | } |
| 84030 | 84024 | #endif /* SQLITE_DEBUG */ |
| 84031 | 84025 | |
| | @@ -87163,10 +87157,11 @@ |
| 87163 | 87157 | p->flags = flags; |
| 87164 | 87158 | p->db = db; |
| 87165 | 87159 | p->szMalloc = 0; |
| 87166 | 87160 | #ifdef SQLITE_DEBUG |
| 87167 | 87161 | p->pScopyFrom = 0; |
| 87162 | + p->bScopy = 0; |
| 87168 | 87163 | #endif |
| 87169 | 87164 | p++; |
| 87170 | 87165 | }while( (--N)>0 ); |
| 87171 | 87166 | } |
| 87172 | 87167 | } |
| | @@ -91348,11 +91343,11 @@ |
| 91348 | 91343 | if( db->nVdbeActive==0 ){ |
| 91349 | 91344 | AtomicStore(&db->u1.isInterrupted, 0); |
| 91350 | 91345 | } |
| 91351 | 91346 | |
| 91352 | 91347 | assert( db->nVdbeWrite>0 || db->autoCommit==0 |
| 91353 | | - || (db->nDeferredCons==0 && db->nDeferredImmCons==0) |
| 91348 | + || ((db->nDeferredCons + db->nDeferredImmCons)==0) |
| 91354 | 91349 | ); |
| 91355 | 91350 | |
| 91356 | 91351 | #ifndef SQLITE_OMIT_TRACE |
| 91357 | 91352 | if( (db->mTrace & (SQLITE_TRACE_PROFILE|SQLITE_TRACE_XPROFILE))!=0 |
| 91358 | 91353 | && !db->init.busy && p->zSql ){ |
| | @@ -91859,10 +91854,11 @@ |
| 91859 | 91854 | /* .zMalloc = */ (char*)0, |
| 91860 | 91855 | /* .xDel = */ (void(*)(void*))0, |
| 91861 | 91856 | #ifdef SQLITE_DEBUG |
| 91862 | 91857 | /* .pScopyFrom = */ (Mem*)0, |
| 91863 | 91858 | /* .mScopyFlags= */ 0, |
| 91859 | + /* .bScopy = */ 0, |
| 91864 | 91860 | #endif |
| 91865 | 91861 | }; |
| 91866 | 91862 | return &nullMem; |
| 91867 | 91863 | } |
| 91868 | 91864 | |
| | @@ -92741,10 +92737,11 @@ |
| 92741 | 92737 | */ |
| 92742 | 92738 | SQLITE_API int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppValue){ |
| 92743 | 92739 | PreUpdate *p; |
| 92744 | 92740 | Mem *pMem; |
| 92745 | 92741 | int rc = SQLITE_OK; |
| 92742 | + int iStore = 0; |
| 92746 | 92743 | |
| 92747 | 92744 | #ifdef SQLITE_ENABLE_API_ARMOR |
| 92748 | 92745 | if( db==0 || ppValue==0 ){ |
| 92749 | 92746 | return SQLITE_MISUSE_BKPT; |
| 92750 | 92747 | } |
| | @@ -92755,13 +92752,15 @@ |
| 92755 | 92752 | if( !p || p->op==SQLITE_INSERT ){ |
| 92756 | 92753 | rc = SQLITE_MISUSE_BKPT; |
| 92757 | 92754 | goto preupdate_old_out; |
| 92758 | 92755 | } |
| 92759 | 92756 | if( p->pPk ){ |
| 92760 | | - iIdx = sqlite3TableColumnToIndex(p->pPk, iIdx); |
| 92757 | + iStore = sqlite3TableColumnToIndex(p->pPk, iIdx); |
| 92758 | + }else{ |
| 92759 | + iStore = sqlite3TableColumnToStorage(p->pTab, iIdx); |
| 92761 | 92760 | } |
| 92762 | | - if( iIdx>=p->pCsr->nField || iIdx<0 ){ |
| 92761 | + if( iStore>=p->pCsr->nField || iStore<0 ){ |
| 92763 | 92762 | rc = SQLITE_RANGE; |
| 92764 | 92763 | goto preupdate_old_out; |
| 92765 | 92764 | } |
| 92766 | 92765 | |
| 92767 | 92766 | if( iIdx==p->pTab->iPKey ){ |
| | @@ -92788,12 +92787,12 @@ |
| 92788 | 92787 | goto preupdate_old_out; |
| 92789 | 92788 | } |
| 92790 | 92789 | p->aRecord = aRec; |
| 92791 | 92790 | } |
| 92792 | 92791 | |
| 92793 | | - pMem = *ppValue = &p->pUnpacked->aMem[iIdx]; |
| 92794 | | - if( iIdx>=p->pUnpacked->nField ){ |
| 92792 | + pMem = *ppValue = &p->pUnpacked->aMem[iStore]; |
| 92793 | + if( iStore>=p->pUnpacked->nField ){ |
| 92795 | 92794 | /* This occurs when the table has been extended using ALTER TABLE |
| 92796 | 92795 | ** ADD COLUMN. The value to return is the default value of the column. */ |
| 92797 | 92796 | Column *pCol = &p->pTab->aCol[iIdx]; |
| 92798 | 92797 | if( pCol->iDflt>0 ){ |
| 92799 | 92798 | if( p->apDflt==0 ){ |
| | @@ -92893,10 +92892,11 @@ |
| 92893 | 92892 | */ |
| 92894 | 92893 | SQLITE_API int sqlite3_preupdate_new(sqlite3 *db, int iIdx, sqlite3_value **ppValue){ |
| 92895 | 92894 | PreUpdate *p; |
| 92896 | 92895 | int rc = SQLITE_OK; |
| 92897 | 92896 | Mem *pMem; |
| 92897 | + int iStore = 0; |
| 92898 | 92898 | |
| 92899 | 92899 | #ifdef SQLITE_ENABLE_API_ARMOR |
| 92900 | 92900 | if( db==0 || ppValue==0 ){ |
| 92901 | 92901 | return SQLITE_MISUSE_BKPT; |
| 92902 | 92902 | } |
| | @@ -92905,13 +92905,16 @@ |
| 92905 | 92905 | if( !p || p->op==SQLITE_DELETE ){ |
| 92906 | 92906 | rc = SQLITE_MISUSE_BKPT; |
| 92907 | 92907 | goto preupdate_new_out; |
| 92908 | 92908 | } |
| 92909 | 92909 | if( p->pPk && p->op!=SQLITE_UPDATE ){ |
| 92910 | | - iIdx = sqlite3TableColumnToIndex(p->pPk, iIdx); |
| 92910 | + iStore = sqlite3TableColumnToIndex(p->pPk, iIdx); |
| 92911 | + }else{ |
| 92912 | + iStore = sqlite3TableColumnToStorage(p->pTab, iIdx); |
| 92911 | 92913 | } |
| 92912 | | - if( iIdx>=p->pCsr->nField || iIdx<0 ){ |
| 92914 | + |
| 92915 | + if( iStore>=p->pCsr->nField || iStore<0 ){ |
| 92913 | 92916 | rc = SQLITE_RANGE; |
| 92914 | 92917 | goto preupdate_new_out; |
| 92915 | 92918 | } |
| 92916 | 92919 | |
| 92917 | 92920 | if( p->op==SQLITE_INSERT ){ |
| | @@ -92927,18 +92930,18 @@ |
| 92927 | 92930 | rc = SQLITE_NOMEM; |
| 92928 | 92931 | goto preupdate_new_out; |
| 92929 | 92932 | } |
| 92930 | 92933 | p->pNewUnpacked = pUnpack; |
| 92931 | 92934 | } |
| 92932 | | - pMem = &pUnpack->aMem[iIdx]; |
| 92935 | + pMem = &pUnpack->aMem[iStore]; |
| 92933 | 92936 | if( iIdx==p->pTab->iPKey ){ |
| 92934 | 92937 | sqlite3VdbeMemSetInt64(pMem, p->iKey2); |
| 92935 | | - }else if( iIdx>=pUnpack->nField ){ |
| 92938 | + }else if( iStore>=pUnpack->nField ){ |
| 92936 | 92939 | pMem = (sqlite3_value *)columnNullValue(); |
| 92937 | 92940 | } |
| 92938 | 92941 | }else{ |
| 92939 | | - /* For an UPDATE, memory cell (p->iNewReg+1+iIdx) contains the required |
| 92942 | + /* For an UPDATE, memory cell (p->iNewReg+1+iStore) contains the required |
| 92940 | 92943 | ** value. Make a copy of the cell contents and return a pointer to it. |
| 92941 | 92944 | ** It is not safe to return a pointer to the memory cell itself as the |
| 92942 | 92945 | ** caller may modify the value text encoding. |
| 92943 | 92946 | */ |
| 92944 | 92947 | assert( p->op==SQLITE_UPDATE ); |
| | @@ -92947,17 +92950,17 @@ |
| 92947 | 92950 | if( !p->aNew ){ |
| 92948 | 92951 | rc = SQLITE_NOMEM; |
| 92949 | 92952 | goto preupdate_new_out; |
| 92950 | 92953 | } |
| 92951 | 92954 | } |
| 92952 | | - assert( iIdx>=0 && iIdx<p->pCsr->nField ); |
| 92953 | | - pMem = &p->aNew[iIdx]; |
| 92955 | + assert( iStore>=0 && iStore<p->pCsr->nField ); |
| 92956 | + pMem = &p->aNew[iStore]; |
| 92954 | 92957 | if( pMem->flags==0 ){ |
| 92955 | 92958 | if( iIdx==p->pTab->iPKey ){ |
| 92956 | 92959 | sqlite3VdbeMemSetInt64(pMem, p->iKey2); |
| 92957 | 92960 | }else{ |
| 92958 | | - rc = sqlite3VdbeMemCopy(pMem, &p->v->aMem[p->iNewReg+1+iIdx]); |
| 92961 | + rc = sqlite3VdbeMemCopy(pMem, &p->v->aMem[p->iNewReg+1+iStore]); |
| 92959 | 92962 | if( rc!=SQLITE_OK ) goto preupdate_new_out; |
| 92960 | 92963 | } |
| 92961 | 92964 | } |
| 92962 | 92965 | } |
| 92963 | 92966 | *ppValue = pMem; |
| | @@ -94042,10 +94045,11 @@ |
| 94042 | 94045 | } |
| 94043 | 94046 | static void registerTrace(int iReg, Mem *p){ |
| 94044 | 94047 | printf("R[%d] = ", iReg); |
| 94045 | 94048 | memTracePrint(p); |
| 94046 | 94049 | if( p->pScopyFrom ){ |
| 94050 | + assert( p->pScopyFrom->bScopy ); |
| 94047 | 94051 | printf(" <== R[%d]", (int)(p->pScopyFrom - &p[-iReg])); |
| 94048 | 94052 | } |
| 94049 | 94053 | printf("\n"); |
| 94050 | 94054 | sqlite3VdbeCheckMemInvariants(p); |
| 94051 | 94055 | } |
| | @@ -95025,10 +95029,11 @@ |
| 95025 | 95029 | #ifdef SQLITE_DEBUG |
| 95026 | 95030 | pIn1->pScopyFrom = 0; |
| 95027 | 95031 | { int i; |
| 95028 | 95032 | for(i=1; i<p->nMem; i++){ |
| 95029 | 95033 | if( aMem[i].pScopyFrom==pIn1 ){ |
| 95034 | + assert( aMem[i].bScopy ); |
| 95030 | 95035 | aMem[i].pScopyFrom = pOut; |
| 95031 | 95036 | } |
| 95032 | 95037 | } |
| 95033 | 95038 | } |
| 95034 | 95039 | #endif |
| | @@ -95097,10 +95102,11 @@ |
| 95097 | 95102 | assert( pOut!=pIn1 ); |
| 95098 | 95103 | sqlite3VdbeMemShallowCopy(pOut, pIn1, MEM_Ephem); |
| 95099 | 95104 | #ifdef SQLITE_DEBUG |
| 95100 | 95105 | pOut->pScopyFrom = pIn1; |
| 95101 | 95106 | pOut->mScopyFlags = pIn1->flags; |
| 95107 | + pIn1->bScopy = 1; |
| 95102 | 95108 | #endif |
| 95103 | 95109 | break; |
| 95104 | 95110 | } |
| 95105 | 95111 | |
| 95106 | 95112 | /* Opcode: IntCopy P1 P2 * * * |
| | @@ -111360,20 +111366,17 @@ |
| 111360 | 111366 | SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3 *db, const IdList *p){ |
| 111361 | 111367 | IdList *pNew; |
| 111362 | 111368 | int i; |
| 111363 | 111369 | assert( db!=0 ); |
| 111364 | 111370 | if( p==0 ) return 0; |
| 111365 | | - assert( p->eU4!=EU4_EXPR ); |
| 111366 | 111371 | pNew = sqlite3DbMallocRawNN(db, sizeof(*pNew)+(p->nId-1)*sizeof(p->a[0]) ); |
| 111367 | 111372 | if( pNew==0 ) return 0; |
| 111368 | 111373 | pNew->nId = p->nId; |
| 111369 | | - pNew->eU4 = p->eU4; |
| 111370 | 111374 | for(i=0; i<p->nId; i++){ |
| 111371 | 111375 | struct IdList_item *pNewItem = &pNew->a[i]; |
| 111372 | 111376 | const struct IdList_item *pOldItem = &p->a[i]; |
| 111373 | 111377 | pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName); |
| 111374 | | - pNewItem->u4 = pOldItem->u4; |
| 111375 | 111378 | } |
| 111376 | 111379 | return pNew; |
| 111377 | 111380 | } |
| 111378 | 111381 | SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, const Select *pDup, int flags){ |
| 111379 | 111382 | Select *pRet = 0; |
| | @@ -126726,11 +126729,10 @@ |
| 126726 | 126729 | */ |
| 126727 | 126730 | SQLITE_PRIVATE void sqlite3IdListDelete(sqlite3 *db, IdList *pList){ |
| 126728 | 126731 | int i; |
| 126729 | 126732 | assert( db!=0 ); |
| 126730 | 126733 | if( pList==0 ) return; |
| 126731 | | - assert( pList->eU4!=EU4_EXPR ); /* EU4_EXPR mode is not currently used */ |
| 126732 | 126734 | for(i=0; i<pList->nId; i++){ |
| 126733 | 126735 | sqlite3DbFree(db, pList->a[i].zName); |
| 126734 | 126736 | } |
| 126735 | 126737 | sqlite3DbNNFreeNN(db, pList); |
| 126736 | 126738 | } |
| | @@ -128107,16 +128109,22 @@ |
| 128107 | 128109 | FuncDef *p, /* The function we are evaluating for match quality */ |
| 128108 | 128110 | int nArg, /* Desired number of arguments. (-1)==any */ |
| 128109 | 128111 | u8 enc /* Desired text encoding */ |
| 128110 | 128112 | ){ |
| 128111 | 128113 | int match; |
| 128112 | | - assert( p->nArg>=-1 ); |
| 128114 | + assert( p->nArg>=(-4) && p->nArg!=(-2) ); |
| 128115 | + assert( nArg>=(-2) ); |
| 128113 | 128116 | |
| 128114 | 128117 | /* Wrong number of arguments means "no match" */ |
| 128115 | 128118 | if( p->nArg!=nArg ){ |
| 128116 | | - if( nArg==(-2) ) return (p->xSFunc==0) ? 0 : FUNC_PERFECT_MATCH; |
| 128119 | + if( nArg==(-2) ) return p->xSFunc==0 ? 0 : FUNC_PERFECT_MATCH; |
| 128117 | 128120 | if( p->nArg>=0 ) return 0; |
| 128121 | + /* Special p->nArg values available to built-in functions only: |
| 128122 | + ** -3 1 or more arguments required |
| 128123 | + ** -4 2 or more arguments required |
| 128124 | + */ |
| 128125 | + if( p->nArg<(-2) && nArg<(-2-p->nArg) ) return 0; |
| 128118 | 128126 | } |
| 128119 | 128127 | |
| 128120 | 128128 | /* Give a better score to a function with a specific number of arguments |
| 128121 | 128129 | ** than to function that accepts any number of arguments. */ |
| 128122 | 128130 | if( p->nArg==nArg ){ |
| | @@ -132076,16 +132084,14 @@ |
| 132076 | 132084 | FUNCTION(ltrim, 2, 1, 0, trimFunc ), |
| 132077 | 132085 | FUNCTION(rtrim, 1, 2, 0, trimFunc ), |
| 132078 | 132086 | FUNCTION(rtrim, 2, 2, 0, trimFunc ), |
| 132079 | 132087 | FUNCTION(trim, 1, 3, 0, trimFunc ), |
| 132080 | 132088 | FUNCTION(trim, 2, 3, 0, trimFunc ), |
| 132081 | | - FUNCTION(min, -1, 0, 1, minmaxFunc ), |
| 132082 | | - FUNCTION(min, 0, 0, 1, 0 ), |
| 132089 | + FUNCTION(min, -3, 0, 1, minmaxFunc ), |
| 132083 | 132090 | WAGGREGATE(min, 1, 0, 1, minmaxStep, minMaxFinalize, minMaxValue, 0, |
| 132084 | 132091 | SQLITE_FUNC_MINMAX|SQLITE_FUNC_ANYORDER ), |
| 132085 | | - FUNCTION(max, -1, 1, 1, minmaxFunc ), |
| 132086 | | - FUNCTION(max, 0, 1, 1, 0 ), |
| 132092 | + FUNCTION(max, -3, 1, 1, minmaxFunc ), |
| 132087 | 132093 | WAGGREGATE(max, 1, 1, 1, minmaxStep, minMaxFinalize, minMaxValue, 0, |
| 132088 | 132094 | SQLITE_FUNC_MINMAX|SQLITE_FUNC_ANYORDER ), |
| 132089 | 132095 | FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF), |
| 132090 | 132096 | FUNCTION2(subtype, 1, 0, 0, subtypeFunc, |
| 132091 | 132097 | SQLITE_FUNC_TYPEOF|SQLITE_SUBTYPE), |
| | @@ -132108,15 +132114,12 @@ |
| 132108 | 132114 | FUNCTION(upper, 1, 0, 0, upperFunc ), |
| 132109 | 132115 | FUNCTION(lower, 1, 0, 0, lowerFunc ), |
| 132110 | 132116 | FUNCTION(hex, 1, 0, 0, hexFunc ), |
| 132111 | 132117 | FUNCTION(unhex, 1, 0, 0, unhexFunc ), |
| 132112 | 132118 | FUNCTION(unhex, 2, 0, 0, unhexFunc ), |
| 132113 | | - FUNCTION(concat, -1, 0, 0, concatFunc ), |
| 132114 | | - FUNCTION(concat, 0, 0, 0, 0 ), |
| 132115 | | - FUNCTION(concat_ws, -1, 0, 0, concatwsFunc ), |
| 132116 | | - FUNCTION(concat_ws, 0, 0, 0, 0 ), |
| 132117 | | - FUNCTION(concat_ws, 1, 0, 0, 0 ), |
| 132119 | + FUNCTION(concat, -3, 0, 0, concatFunc ), |
| 132120 | + FUNCTION(concat_ws, -4, 0, 0, concatwsFunc ), |
| 132118 | 132121 | INLINE_FUNC(ifnull, 2, INLINEFUNC_coalesce, 0 ), |
| 132119 | 132122 | VFUNCTION(random, 0, 0, 0, randomFunc ), |
| 132120 | 132123 | VFUNCTION(randomblob, 1, 0, 0, randomBlob ), |
| 132121 | 132124 | FUNCTION(nullif, 2, 0, 1, nullifFunc ), |
| 132122 | 132125 | DFUNCTION(sqlite_version, 0, 0, 0, versionFunc ), |
| | @@ -132156,12 +132159,10 @@ |
| 132156 | 132159 | LIKEFUNC(like, 3, &likeInfoNorm, SQLITE_FUNC_LIKE), |
| 132157 | 132160 | #endif |
| 132158 | 132161 | #ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION |
| 132159 | 132162 | FUNCTION(unknown, -1, 0, 0, unknownFunc ), |
| 132160 | 132163 | #endif |
| 132161 | | - FUNCTION(coalesce, 1, 0, 0, 0 ), |
| 132162 | | - FUNCTION(coalesce, 0, 0, 0, 0 ), |
| 132163 | 132164 | #ifdef SQLITE_ENABLE_MATH_FUNCTIONS |
| 132164 | 132165 | MFUNCTION(ceil, 1, xCeil, ceilingFunc ), |
| 132165 | 132166 | MFUNCTION(ceiling, 1, xCeil, ceilingFunc ), |
| 132166 | 132167 | MFUNCTION(floor, 1, xFloor, ceilingFunc ), |
| 132167 | 132168 | #if SQLITE_HAVE_C99_MATH_FUNCS |
| | @@ -132195,15 +132196,13 @@ |
| 132195 | 132196 | MFUNCTION(radians, 1, degToRad, math1Func ), |
| 132196 | 132197 | MFUNCTION(degrees, 1, radToDeg, math1Func ), |
| 132197 | 132198 | MFUNCTION(pi, 0, 0, piFunc ), |
| 132198 | 132199 | #endif /* SQLITE_ENABLE_MATH_FUNCTIONS */ |
| 132199 | 132200 | FUNCTION(sign, 1, 0, 0, signFunc ), |
| 132200 | | - INLINE_FUNC(coalesce, -1, INLINEFUNC_coalesce, 0 ), |
| 132201 | | - INLINE_FUNC(iif, 2, INLINEFUNC_iif, 0 ), |
| 132202 | | - INLINE_FUNC(iif, 3, INLINEFUNC_iif, 0 ), |
| 132203 | | - INLINE_FUNC(if, 2, INLINEFUNC_iif, 0 ), |
| 132204 | | - INLINE_FUNC(if, 3, INLINEFUNC_iif, 0 ), |
| 132201 | + INLINE_FUNC(coalesce, -4, INLINEFUNC_coalesce, 0 ), |
| 132202 | + INLINE_FUNC(iif, -4, INLINEFUNC_iif, 0 ), |
| 132203 | + INLINE_FUNC(if, -4, INLINEFUNC_iif, 0 ), |
| 132205 | 132204 | }; |
| 132206 | 132205 | #ifndef SQLITE_OMIT_ALTERTABLE |
| 132207 | 132206 | sqlite3AlterFunctions(); |
| 132208 | 132207 | #endif |
| 132209 | 132208 | sqlite3WindowFunctions(); |
| | @@ -134645,10 +134644,11 @@ |
| 134645 | 134644 | int regRowCount = 0; /* Memory cell used for the row counter */ |
| 134646 | 134645 | int regIns; /* Block of regs holding rowid+data being inserted */ |
| 134647 | 134646 | int regRowid; /* registers holding insert rowid */ |
| 134648 | 134647 | int regData; /* register holding first column to insert */ |
| 134649 | 134648 | int *aRegIdx = 0; /* One register allocated to each index */ |
| 134649 | + int *aTabColMap = 0; /* Mapping from pTab columns to pCol entries */ |
| 134650 | 134650 | |
| 134651 | 134651 | #ifndef SQLITE_OMIT_TRIGGER |
| 134652 | 134652 | int isView; /* True if attempting to insert into a view */ |
| 134653 | 134653 | Trigger *pTrigger; /* List of triggers on pTab, if required */ |
| 134654 | 134654 | int tmask; /* Mask of trigger times */ |
| | @@ -134789,19 +134789,19 @@ |
| 134789 | 134789 | ** columns into storage order. False negatives are harmless, |
| 134790 | 134790 | ** but false positives will cause database corruption. |
| 134791 | 134791 | */ |
| 134792 | 134792 | bIdListInOrder = (pTab->tabFlags & (TF_OOOHidden|TF_HasStored))==0; |
| 134793 | 134793 | if( pColumn ){ |
| 134794 | | - assert( pColumn->eU4!=EU4_EXPR ); |
| 134795 | | - pColumn->eU4 = EU4_IDX; |
| 134796 | | - for(i=0; i<pColumn->nId; i++){ |
| 134797 | | - pColumn->a[i].u4.idx = -1; |
| 134798 | | - } |
| 134799 | | - for(i=0; i<pColumn->nId; i++){ |
| 134800 | | - for(j=0; j<pTab->nCol; j++){ |
| 134801 | | - if( sqlite3StrICmp(pColumn->a[i].zName, pTab->aCol[j].zCnName)==0 ){ |
| 134802 | | - pColumn->a[i].u4.idx = j; |
| 134794 | + aTabColMap = sqlite3DbMallocZero(db, pTab->nCol*sizeof(int)); |
| 134795 | + if( aTabColMap==0 ) goto insert_cleanup; |
| 134796 | + for(i=0; i<pColumn->nId; i++){ |
| 134797 | + const char *zCName = pColumn->a[i].zName; |
| 134798 | + u8 hName = sqlite3StrIHash(zCName); |
| 134799 | + for(j=0; j<pTab->nCol; j++){ |
| 134800 | + if( pTab->aCol[j].hName!=hName ) continue; |
| 134801 | + if( sqlite3StrICmp(zCName, pTab->aCol[j].zCnName)==0 ){ |
| 134802 | + if( aTabColMap[j]==0 ) aTabColMap[j] = i+1; |
| 134803 | 134803 | if( i!=j ) bIdListInOrder = 0; |
| 134804 | 134804 | if( j==pTab->iPKey ){ |
| 134805 | 134805 | ipkColumn = i; assert( !withoutRowid ); |
| 134806 | 134806 | } |
| 134807 | 134807 | #ifndef SQLITE_OMIT_GENERATED_COLUMNS |
| | @@ -135119,21 +135119,21 @@ |
| 135119 | 135119 | iRegStore); |
| 135120 | 135120 | continue; |
| 135121 | 135121 | } |
| 135122 | 135122 | } |
| 135123 | 135123 | if( pColumn ){ |
| 135124 | | - assert( pColumn->eU4==EU4_IDX ); |
| 135125 | | - for(j=0; j<pColumn->nId && pColumn->a[j].u4.idx!=i; j++){} |
| 135126 | | - if( j>=pColumn->nId ){ |
| 135124 | + j = aTabColMap[i]; |
| 135125 | + assert( j>=0 && j<=pColumn->nId ); |
| 135126 | + if( j==0 ){ |
| 135127 | 135127 | /* A column not named in the insert column list gets its |
| 135128 | 135128 | ** default value */ |
| 135129 | 135129 | sqlite3ExprCodeFactorable(pParse, |
| 135130 | 135130 | sqlite3ColumnExpr(pTab, &pTab->aCol[i]), |
| 135131 | 135131 | iRegStore); |
| 135132 | 135132 | continue; |
| 135133 | 135133 | } |
| 135134 | | - k = j; |
| 135134 | + k = j - 1; |
| 135135 | 135135 | }else if( nColumn==0 ){ |
| 135136 | 135136 | /* This is INSERT INTO ... DEFAULT VALUES. Load the default value. */ |
| 135137 | 135137 | sqlite3ExprCodeFactorable(pParse, |
| 135138 | 135138 | sqlite3ColumnExpr(pTab, &pTab->aCol[i]), |
| 135139 | 135139 | iRegStore); |
| | @@ -135374,11 +135374,14 @@ |
| 135374 | 135374 | insert_cleanup: |
| 135375 | 135375 | sqlite3SrcListDelete(db, pTabList); |
| 135376 | 135376 | sqlite3ExprListDelete(db, pList); |
| 135377 | 135377 | sqlite3UpsertDelete(db, pUpsert); |
| 135378 | 135378 | sqlite3SelectDelete(db, pSelect); |
| 135379 | | - sqlite3IdListDelete(db, pColumn); |
| 135379 | + if( pColumn ){ |
| 135380 | + sqlite3IdListDelete(db, pColumn); |
| 135381 | + sqlite3DbFree(db, aTabColMap); |
| 135382 | + } |
| 135380 | 135383 | if( aRegIdx ) sqlite3DbNNFreeNN(db, aRegIdx); |
| 135381 | 135384 | } |
| 135382 | 135385 | |
| 135383 | 135386 | /* Make sure "isView" and other macros defined above are undefined. Otherwise |
| 135384 | 135387 | ** they may interfere with compilation of other functions in this file |
| | @@ -157961,12 +157964,14 @@ |
| 157961 | 157964 | u16 nLTerm; /* Number of entries in aLTerm[] */ |
| 157962 | 157965 | u16 nSkip; /* Number of NULL aLTerm[] entries */ |
| 157963 | 157966 | /**** whereLoopXfer() copies fields above ***********************/ |
| 157964 | 157967 | # define WHERE_LOOP_XFER_SZ offsetof(WhereLoop,nLSlot) |
| 157965 | 157968 | u16 nLSlot; /* Number of slots allocated for aLTerm[] */ |
| 157969 | +#ifdef WHERETRACE_ENABLED |
| 157966 | 157970 | LogEst rStarDelta; /* Cost delta due to star-schema heuristic. Not |
| 157967 | | - ** initialized unless pWInfo->nOutStarDelta>0 */ |
| 157971 | + ** initialized unless pWInfo->bStarUsed */ |
| 157972 | +#endif |
| 157968 | 157973 | WhereTerm **aLTerm; /* WhereTerms used */ |
| 157969 | 157974 | WhereLoop *pNextLoop; /* Next WhereLoop object in the WhereClause */ |
| 157970 | 157975 | WhereTerm *aLTermSpace[3]; /* Initial aLTerm[] space */ |
| 157971 | 157976 | }; |
| 157972 | 157977 | |
| | @@ -158011,11 +158016,11 @@ |
| 158011 | 158016 | struct WherePath { |
| 158012 | 158017 | Bitmask maskLoop; /* Bitmask of all WhereLoop objects in this path */ |
| 158013 | 158018 | Bitmask revLoop; /* aLoop[]s that should be reversed for ORDER BY */ |
| 158014 | 158019 | LogEst nRow; /* Estimated number of rows generated by this path */ |
| 158015 | 158020 | LogEst rCost; /* Total cost of this path */ |
| 158016 | | - LogEst rUnsorted; /* Total cost of this path ignoring sorting costs */ |
| 158021 | + LogEst rUnsort; /* Total cost of this path ignoring sorting costs */ |
| 158017 | 158022 | i8 isOrdered; /* No. of ORDER BY terms satisfied. -1 for unknown */ |
| 158018 | 158023 | WhereLoop **aLoop; /* Array of WhereLoop objects implementing this path */ |
| 158019 | 158024 | }; |
| 158020 | 158025 | |
| 158021 | 158026 | /* |
| | @@ -158284,13 +158289,17 @@ |
| 158284 | 158289 | u8 eOnePass; /* ONEPASS_OFF, or _SINGLE, or _MULTI */ |
| 158285 | 158290 | u8 eDistinct; /* One of the WHERE_DISTINCT_* values */ |
| 158286 | 158291 | unsigned bDeferredSeek :1; /* Uses OP_DeferredSeek */ |
| 158287 | 158292 | unsigned untestedTerms :1; /* Not all WHERE terms resolved by outer loop */ |
| 158288 | 158293 | unsigned bOrderedInnerLoop:1;/* True if only the inner-most loop is ordered */ |
| 158289 | | - unsigned sorted :1; /* True if really sorted (not just grouped) */ |
| 158290 | | - LogEst nOutStarDelta; /* Artifical nOut reduction for star-query */ |
| 158294 | + unsigned sorted :1; /* True if really sorted (not just grouped) */ |
| 158295 | + unsigned bStarDone :1; /* True if check for star-query is complete */ |
| 158296 | + unsigned bStarUsed :1; /* True if star-query heuristic is used */ |
| 158291 | 158297 | LogEst nRowOut; /* Estimated number of output rows */ |
| 158298 | +#ifdef WHERETRACE_ENABLED |
| 158299 | + LogEst rTotalCost; /* Total cost of the solution */ |
| 158300 | +#endif |
| 158292 | 158301 | int iTop; /* The very beginning of the WHERE loop */ |
| 158293 | 158302 | int iEndWhere; /* End of the WHERE clause itself */ |
| 158294 | 158303 | WhereLoop *pLoops; /* List of all WhereLoop objects */ |
| 158295 | 158304 | WhereMemBlock *pMemToFree;/* Memory to free when this object destroyed */ |
| 158296 | 158305 | Bitmask revMask; /* Mask of ORDER BY terms that need reversing */ |
| | @@ -164232,11 +164241,11 @@ |
| 164232 | 164241 | char *zText = 0; |
| 164233 | 164242 | int ii = 0; |
| 164234 | 164243 | sqlite3_str *pStr = sqlite3_str_new(pParse->db); |
| 164235 | 164244 | sqlite3_str_appendf(pStr,"CREATE AUTOMATIC INDEX ON %s(", pTab->zName); |
| 164236 | 164245 | assert( pIdx->nColumn>1 ); |
| 164237 | | - assert( pIdx->aiColumn[pIdx->nColumn-1]==XN_ROWID ); |
| 164246 | + assert( pIdx->aiColumn[pIdx->nColumn-1]==XN_ROWID || !HasRowid(pTab) ); |
| 164238 | 164247 | for(ii=0; ii<(pIdx->nColumn-1); ii++){ |
| 164239 | 164248 | const char *zName = 0; |
| 164240 | 164249 | int iCol = pIdx->aiColumn[ii]; |
| 164241 | 164250 | |
| 164242 | 164251 | zName = pTab->aCol[iCol].zCnName; |
| | @@ -164362,10 +164371,23 @@ |
| 164362 | 164371 | */ |
| 164363 | 164372 | if( IsView(pTable) ){ |
| 164364 | 164373 | extraCols = ALLBITS & ~idxCols; |
| 164365 | 164374 | }else{ |
| 164366 | 164375 | extraCols = pSrc->colUsed & (~idxCols | MASKBIT(BMS-1)); |
| 164376 | + } |
| 164377 | + if( !HasRowid(pTable) ){ |
| 164378 | + /* For WITHOUT ROWID tables, ensure that all PRIMARY KEY columns are |
| 164379 | + ** either in the idxCols mask or in the extraCols mask */ |
| 164380 | + for(i=0; i<pTable->nCol; i++){ |
| 164381 | + if( (pTable->aCol[i].colFlags & COLFLAG_PRIMKEY)==0 ) continue; |
| 164382 | + if( i>=BMS-1 ){ |
| 164383 | + extraCols |= MASKBIT(BMS-1); |
| 164384 | + break; |
| 164385 | + } |
| 164386 | + if( idxCols & MASKBIT(i) ) continue; |
| 164387 | + extraCols |= MASKBIT(i); |
| 164388 | + } |
| 164367 | 164389 | } |
| 164368 | 164390 | mxBitCol = MIN(BMS-1,pTable->nCol); |
| 164369 | 164391 | testcase( pTable->nCol==BMS-1 ); |
| 164370 | 164392 | testcase( pTable->nCol==BMS-2 ); |
| 164371 | 164393 | for(i=0; i<mxBitCol; i++){ |
| | @@ -164374,11 +164396,12 @@ |
| 164374 | 164396 | if( pSrc->colUsed & MASKBIT(BMS-1) ){ |
| 164375 | 164397 | nKeyCol += pTable->nCol - BMS + 1; |
| 164376 | 164398 | } |
| 164377 | 164399 | |
| 164378 | 164400 | /* Construct the Index object to describe this index */ |
| 164379 | | - pIdx = sqlite3AllocateIndexObject(pParse->db, nKeyCol+1, 0, &zNotUsed); |
| 164401 | + pIdx = sqlite3AllocateIndexObject(pParse->db, nKeyCol+HasRowid(pTable), |
| 164402 | + 0, &zNotUsed); |
| 164380 | 164403 | if( pIdx==0 ) goto end_auto_index_create; |
| 164381 | 164404 | pLoop->u.btree.pIndex = pIdx; |
| 164382 | 164405 | pIdx->zName = "auto-index"; |
| 164383 | 164406 | pIdx->pTable = pTable; |
| 164384 | 164407 | n = 0; |
| | @@ -164430,12 +164453,14 @@ |
| 164430 | 164453 | pIdx->azColl[n] = sqlite3StrBINARY; |
| 164431 | 164454 | n++; |
| 164432 | 164455 | } |
| 164433 | 164456 | } |
| 164434 | 164457 | assert( n==nKeyCol ); |
| 164435 | | - pIdx->aiColumn[n] = XN_ROWID; |
| 164436 | | - pIdx->azColl[n] = sqlite3StrBINARY; |
| 164458 | + if( HasRowid(pTable) ){ |
| 164459 | + pIdx->aiColumn[n] = XN_ROWID; |
| 164460 | + pIdx->azColl[n] = sqlite3StrBINARY; |
| 164461 | + } |
| 164437 | 164462 | |
| 164438 | 164463 | /* Create the automatic index */ |
| 164439 | 164464 | explainAutomaticIndex(pParse, pIdx, pPartial!=0, &addrExp); |
| 164440 | 164465 | assert( pLevel->iIdxCur>=0 ); |
| 164441 | 164466 | pLevel->iIdxCur = pParse->nTab++; |
| | @@ -165698,21 +165723,23 @@ |
| 165698 | 165723 | ** | | | __|__ nEq ---. ___|__ | __|__ |
| 165699 | 165724 | ** | / \ / \ / \ | / \ / \ / \ |
| 165700 | 165725 | ** 1.002.001 t2.t2xy 2 f 010241 N 2 cost 0,56,31 |
| 165701 | 165726 | */ |
| 165702 | 165727 | SQLITE_PRIVATE void sqlite3WhereLoopPrint(const WhereLoop *p, const WhereClause *pWC){ |
| 165728 | + WhereInfo *pWInfo; |
| 165703 | 165729 | if( pWC ){ |
| 165704 | | - WhereInfo *pWInfo = pWC->pWInfo; |
| 165730 | + pWInfo = pWC->pWInfo; |
| 165705 | 165731 | int nb = 1+(pWInfo->pTabList->nSrc+3)/4; |
| 165706 | 165732 | SrcItem *pItem = pWInfo->pTabList->a + p->iTab; |
| 165707 | 165733 | Table *pTab = pItem->pSTab; |
| 165708 | 165734 | Bitmask mAll = (((Bitmask)1)<<(nb*4)) - 1; |
| 165709 | 165735 | sqlite3DebugPrintf("%c%2d.%0*llx.%0*llx", p->cId, |
| 165710 | 165736 | p->iTab, nb, p->maskSelf, nb, p->prereq & mAll); |
| 165711 | 165737 | sqlite3DebugPrintf(" %12s", |
| 165712 | 165738 | pItem->zAlias ? pItem->zAlias : pTab->zName); |
| 165713 | 165739 | }else{ |
| 165740 | + pWInfo = 0; |
| 165714 | 165741 | sqlite3DebugPrintf("%c%2d.%03llx.%03llx %c%d", |
| 165715 | 165742 | p->cId, p->iTab, p->maskSelf, p->prereq & 0xfff, p->cId, p->iTab); |
| 165716 | 165743 | } |
| 165717 | 165744 | if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){ |
| 165718 | 165745 | const char *zName; |
| | @@ -165740,11 +165767,16 @@ |
| 165740 | 165767 | if( p->wsFlags & WHERE_SKIPSCAN ){ |
| 165741 | 165768 | sqlite3DebugPrintf(" f %06x %d-%d", p->wsFlags, p->nLTerm,p->nSkip); |
| 165742 | 165769 | }else{ |
| 165743 | 165770 | sqlite3DebugPrintf(" f %06x N %d", p->wsFlags, p->nLTerm); |
| 165744 | 165771 | } |
| 165745 | | - sqlite3DebugPrintf(" cost %d,%d,%d\n", p->rSetup, p->rRun, p->nOut); |
| 165772 | + if( pWInfo && pWInfo->bStarUsed && p->rStarDelta!=0 ){ |
| 165773 | + sqlite3DebugPrintf(" cost %d,%d,%d delta=%d\n", |
| 165774 | + p->rSetup, p->rRun, p->nOut, p->rStarDelta); |
| 165775 | + }else{ |
| 165776 | + sqlite3DebugPrintf(" cost %d,%d,%d\n", p->rSetup, p->rRun, p->nOut); |
| 165777 | + } |
| 165746 | 165778 | if( p->nLTerm && (sqlite3WhereTrace & 0x4000)!=0 ){ |
| 165747 | 165779 | int i; |
| 165748 | 165780 | for(i=0; i<p->nLTerm; i++){ |
| 165749 | 165781 | sqlite3WhereTermPrint(p->aLTerm[i], i); |
| 165750 | 165782 | } |
| | @@ -167206,11 +167238,10 @@ |
| 167206 | 167238 | if( !pBuilder->pOrSet /* Not part of an OR optimization */ |
| 167207 | 167239 | && (pWInfo->wctrlFlags & (WHERE_RIGHT_JOIN|WHERE_OR_SUBCLAUSE))==0 |
| 167208 | 167240 | && (pWInfo->pParse->db->flags & SQLITE_AutoIndex)!=0 |
| 167209 | 167241 | && !pSrc->fg.isIndexedBy /* Has no INDEXED BY clause */ |
| 167210 | 167242 | && !pSrc->fg.notIndexed /* Has no NOT INDEXED clause */ |
| 167211 | | - && HasRowid(pTab) /* Not WITHOUT ROWID table. (FIXME: Why not?) */ |
| 167212 | 167243 | && !pSrc->fg.isCorrelated /* Not a correlated subquery */ |
| 167213 | 167244 | && !pSrc->fg.isRecursive /* Not a recursive common table expression. */ |
| 167214 | 167245 | && (pSrc->fg.jointype & JT_RIGHT)==0 /* Not the right tab of a RIGHT JOIN */ |
| 167215 | 167246 | ){ |
| 167216 | 167247 | /* Generate auto-index WhereLoops */ |
| | @@ -168709,72 +168740,205 @@ |
| 168709 | 168740 | ** The value returned is a tuning parameter. Currently the value is: |
| 168710 | 168741 | ** |
| 168711 | 168742 | ** 18 for star queries |
| 168712 | 168743 | ** 12 otherwise |
| 168713 | 168744 | ** |
| 168714 | | -** For the purposes of SQLite, a star-query is defined as a query |
| 168715 | | -** with a large central table that is joined against four or more |
| 168716 | | -** smaller tables. The central table is called the "fact" table. |
| 168717 | | -** The smaller tables that get joined are "dimension tables". |
| 168745 | +** For the purposes of this heuristic, a star-query is defined as a query |
| 168746 | +** with a large central table that is joined using an INNER JOIN, |
| 168747 | +** not CROSS or OUTER JOINs, against four or more smaller tables. |
| 168748 | +** The central table is called the "fact" table. The smaller tables |
| 168749 | +** that get joined are "dimension tables". Also, any table that is |
| 168750 | +** self-joined cannot be a dimension table; we assume that dimension |
| 168751 | +** tables may only be joined against fact tables. |
| 168718 | 168752 | ** |
| 168719 | 168753 | ** SIDE EFFECT: (and really the whole point of this subroutine) |
| 168720 | 168754 | ** |
| 168721 | | -** If pWInfo describes a star-query, then the cost on WhereLoops for the |
| 168722 | | -** fact table is reduced. This heuristic helps keep fact tables in |
| 168723 | | -** outer loops. Without this heuristic, paths with fact tables in outer |
| 168724 | | -** loops tend to get pruned by the mxChoice limit on the number of paths, |
| 168725 | | -** resulting in poor query plans. The total amount of heuristic cost |
| 168726 | | -** adjustment is stored in pWInfo->nOutStarDelta and the cost adjustment |
| 168727 | | -** for each WhereLoop is stored in its rStarDelta field. |
| 168755 | +** If pWInfo describes a star-query, then the cost for SCANs of dimension |
| 168756 | +** WhereLoops is increased to be slightly larger than the cost of a SCAN |
| 168757 | +** in the fact table. Only SCAN costs are increased. SEARCH costs are |
| 168758 | +** unchanged. This heuristic helps keep fact tables in outer loops. Without |
| 168759 | +** this heuristic, paths with fact tables in outer loops tend to get pruned |
| 168760 | +** by the mxChoice limit on the number of paths, resulting in poor query |
| 168761 | +** plans. See the starschema1.test test module for examples of queries |
| 168762 | +** that need this heuristic to find good query plans. |
| 168763 | +** |
| 168764 | +** This heuristic can be completely disabled, so that no query is |
| 168765 | +** considered a star-query, using SQLITE_TESTCTRL_OPTIMIZATION to |
| 168766 | +** disable the SQLITE_StarQuery optimization. In the CLI, the command |
| 168767 | +** to do that is: ".testctrl opt -starquery". |
| 168768 | +** |
| 168769 | +** HISTORICAL NOTES: |
| 168770 | +** |
| 168771 | +** This optimization was first added on 2024-05-09 by check-in 38db9b5c83d. |
| 168772 | +** The original optimization reduced the cost and output size estimate for |
| 168773 | +** fact tables to help them move to outer loops. But months later (as people |
| 168774 | +** started upgrading) performance regression reports started caming in, |
| 168775 | +** including: |
| 168776 | +** |
| 168777 | +** forum post b18ef983e68d06d1 (2024-12-21) |
| 168778 | +** forum post 0025389d0860af82 (2025-01-14) |
| 168779 | +** forum post d87570a145599033 (2025-01-17) |
| 168780 | +** |
| 168781 | +** To address these, the criteria for a star-query was tightened to exclude |
| 168782 | +** cases where the fact and dimensions are separated by an outer join, and |
| 168783 | +** the affect of star-schema detection was changed to increase the rRun cost |
| 168784 | +** on just full table scans of dimension tables, rather than reducing costs |
| 168785 | +** in the all access methods of the fact table. |
| 168728 | 168786 | */ |
| 168729 | | -static int computeMxChoice(WhereInfo *pWInfo, LogEst nRowEst){ |
| 168787 | +static int computeMxChoice(WhereInfo *pWInfo){ |
| 168730 | 168788 | int nLoop = pWInfo->nLevel; /* Number of terms in the join */ |
| 168731 | | - if( nRowEst==0 && nLoop>=5 ){ |
| 168732 | | - /* Check to see if we are dealing with a star schema and if so, reduce |
| 168733 | | - ** the cost of fact tables relative to dimension tables, as a heuristic |
| 168734 | | - ** to help keep the fact tables in outer loops. |
| 168789 | + WhereLoop *pWLoop; /* For looping over WhereLoops */ |
| 168790 | + |
| 168791 | +#ifdef SQLITE_DEBUG |
| 168792 | + /* The star-query detection code below makes use of the following |
| 168793 | + ** properties of the WhereLoop list, so verify them before |
| 168794 | + ** continuing: |
| 168795 | + ** (1) .maskSelf is the bitmask corresponding to .iTab |
| 168796 | + ** (2) The WhereLoop list is in ascending .iTab order |
| 168797 | + */ |
| 168798 | + for(pWLoop=pWInfo->pLoops; pWLoop; pWLoop=pWLoop->pNextLoop){ |
| 168799 | + assert( pWLoop->maskSelf==MASKBIT(pWLoop->iTab) ); |
| 168800 | + assert( pWLoop->pNextLoop==0 || pWLoop->iTab<=pWLoop->pNextLoop->iTab ); |
| 168801 | + } |
| 168802 | +#endif /* SQLITE_DEBUG */ |
| 168803 | + |
| 168804 | + if( nLoop>=5 |
| 168805 | + && !pWInfo->bStarDone |
| 168806 | + && OptimizationEnabled(pWInfo->pParse->db, SQLITE_StarQuery) |
| 168807 | + ){ |
| 168808 | + SrcItem *aFromTabs; /* All terms of the FROM clause */ |
| 168809 | + int iFromIdx; /* Term of FROM clause is the candidate fact-table */ |
| 168810 | + Bitmask m; /* Bitmask for candidate fact-table */ |
| 168811 | + Bitmask mSelfJoin = 0; /* Tables that cannot be dimension tables */ |
| 168812 | + WhereLoop *pStart; /* Where to start searching for dimension-tables */ |
| 168813 | + |
| 168814 | + pWInfo->bStarDone = 1; /* Only do this computation once */ |
| 168815 | + |
| 168816 | + /* Look for fact tables with four or more dimensions where the |
| 168817 | + ** dimension tables are not separately from the fact tables by an outer |
| 168818 | + ** or cross join. Adjust cost weights if found. |
| 168735 | 168819 | */ |
| 168736 | | - int iLoop; /* Counter over join terms */ |
| 168737 | | - Bitmask m; /* Bitmask for current loop */ |
| 168738 | | - assert( pWInfo->nOutStarDelta==0 ); |
| 168739 | | - for(iLoop=0, m=1; iLoop<nLoop; iLoop++, m<<=1){ |
| 168740 | | - WhereLoop *pWLoop; /* For looping over WhereLoops */ |
| 168820 | + assert( !pWInfo->bStarUsed ); |
| 168821 | + aFromTabs = pWInfo->pTabList->a; |
| 168822 | + pStart = pWInfo->pLoops; |
| 168823 | + for(iFromIdx=0, m=1; iFromIdx<nLoop; iFromIdx++, m<<=1){ |
| 168741 | 168824 | int nDep = 0; /* Number of dimension tables */ |
| 168742 | | - LogEst rDelta; /* Heuristic cost adjustment */ |
| 168825 | + LogEst mxRun; /* Maximum SCAN cost of a fact table */ |
| 168743 | 168826 | Bitmask mSeen = 0; /* Mask of dimension tables */ |
| 168744 | | - for(pWLoop=pWInfo->pLoops; pWLoop; pWLoop=pWLoop->pNextLoop){ |
| 168745 | | - if( (pWLoop->prereq & m)!=0 && (pWLoop->maskSelf & mSeen)==0 ){ |
| 168746 | | - nDep++; |
| 168747 | | - mSeen |= pWLoop->maskSelf; |
| 168827 | + SrcItem *pFactTab; /* The candidate fact table */ |
| 168828 | + |
| 168829 | + pFactTab = aFromTabs + iFromIdx; |
| 168830 | + if( (pFactTab->fg.jointype & (JT_OUTER|JT_CROSS))!=0 ){ |
| 168831 | + /* If the candidate fact-table is the right table of an outer join |
| 168832 | + ** restrict the search for dimension-tables to be tables to the right |
| 168833 | + ** of the fact-table. */ |
| 168834 | + if( iFromIdx+4 > nLoop ) break; /* Impossible to reach nDep>=4 */ |
| 168835 | + while( pStart && pStart->iTab<=iFromIdx ){ |
| 168836 | + pStart = pStart->pNextLoop; |
| 168837 | + } |
| 168838 | + } |
| 168839 | + for(pWLoop=pStart; pWLoop; pWLoop=pWLoop->pNextLoop){ |
| 168840 | + if( (aFromTabs[pWLoop->iTab].fg.jointype & (JT_OUTER|JT_CROSS))!=0 ){ |
| 168841 | + /* Fact-tables and dimension-tables cannot be separated by an |
| 168842 | + ** outer join (at least for the definition of fact- and dimension- |
| 168843 | + ** used by this heuristic). */ |
| 168844 | + break; |
| 168845 | + } |
| 168846 | + if( (pWLoop->prereq & m)!=0 /* pWInfo depends on iFromIdx */ |
| 168847 | + && (pWLoop->maskSelf & mSeen)==0 /* pWInfo not already a dependency */ |
| 168848 | + && (pWLoop->maskSelf & mSelfJoin)==0 /* Not a self-join */ |
| 168849 | + ){ |
| 168850 | + if( aFromTabs[pWLoop->iTab].pSTab==pFactTab->pSTab ){ |
| 168851 | + mSelfJoin |= m; |
| 168852 | + }else{ |
| 168853 | + nDep++; |
| 168854 | + mSeen |= pWLoop->maskSelf; |
| 168855 | + } |
| 168748 | 168856 | } |
| 168749 | 168857 | } |
| 168750 | 168858 | if( nDep<=3 ) continue; |
| 168751 | | - rDelta = 15*(nDep-3); |
| 168752 | | -#ifdef WHERETRACE_ENABLED /* 0x4 */ |
| 168753 | | - if( sqlite3WhereTrace&0x4 ){ |
| 168754 | | - SrcItem *pItem = pWInfo->pTabList->a + iLoop; |
| 168755 | | - sqlite3DebugPrintf("Fact-table %s: %d dimensions, cost reduced %d\n", |
| 168756 | | - pItem->zAlias ? pItem->zAlias : pItem->pSTab->zName, |
| 168757 | | - nDep, rDelta); |
| 168758 | | - } |
| 168759 | | -#endif |
| 168760 | | - if( pWInfo->nOutStarDelta==0 ){ |
| 168859 | + |
| 168860 | + /* If we reach this point, it means that pFactTab is a fact table |
| 168861 | + ** with four or more dimensions connected by inner joins. Proceed |
| 168862 | + ** to make cost adjustments. */ |
| 168863 | + |
| 168864 | +#ifdef WHERETRACE_ENABLED |
| 168865 | + /* Make sure rStarDelta values are initialized */ |
| 168866 | + if( !pWInfo->bStarUsed ){ |
| 168761 | 168867 | for(pWLoop=pWInfo->pLoops; pWLoop; pWLoop=pWLoop->pNextLoop){ |
| 168762 | 168868 | pWLoop->rStarDelta = 0; |
| 168763 | 168869 | } |
| 168764 | 168870 | } |
| 168765 | | - pWInfo->nOutStarDelta += rDelta; |
| 168871 | +#endif |
| 168872 | + pWInfo->bStarUsed = 1; |
| 168873 | + |
| 168874 | + /* Compute the maximum cost of any WhereLoop for the |
| 168875 | + ** fact table plus one epsilon */ |
| 168876 | + mxRun = LOGEST_MIN; |
| 168877 | + for(pWLoop=pStart; pWLoop; pWLoop=pWLoop->pNextLoop){ |
| 168878 | + if( pWLoop->iTab<iFromIdx ) continue; |
| 168879 | + if( pWLoop->iTab>iFromIdx ) break; |
| 168880 | + if( pWLoop->rRun>mxRun ) mxRun = pWLoop->rRun; |
| 168881 | + } |
| 168882 | + if( ALWAYS(mxRun<LOGEST_MAX) ) mxRun++; |
| 168883 | + |
| 168884 | + /* Increase the cost of table scans for dimension tables to be |
| 168885 | + ** slightly more than the maximum cost of the fact table */ |
| 168886 | + for(pWLoop=pStart; pWLoop; pWLoop=pWLoop->pNextLoop){ |
| 168887 | + if( (pWLoop->maskSelf & mSeen)==0 ) continue; |
| 168888 | + if( pWLoop->nLTerm ) continue; |
| 168889 | + if( pWLoop->rRun<mxRun ){ |
| 168890 | +#ifdef WHERETRACE_ENABLED /* 0x80000 */ |
| 168891 | + if( sqlite3WhereTrace & 0x80000 ){ |
| 168892 | + SrcItem *pDim = aFromTabs + pWLoop->iTab; |
| 168893 | + sqlite3DebugPrintf( |
| 168894 | + "Increase SCAN cost of dimension %s(%d) of fact %s(%d) to %d\n", |
| 168895 | + pDim->zAlias ? pDim->zAlias: pDim->pSTab->zName, pWLoop->iTab, |
| 168896 | + pFactTab->zAlias ? pFactTab->zAlias : pFactTab->pSTab->zName, |
| 168897 | + iFromIdx, mxRun |
| 168898 | + ); |
| 168899 | + } |
| 168900 | + pWLoop->rStarDelta = mxRun - pWLoop->rRun; |
| 168901 | +#endif /* WHERETRACE_ENABLED */ |
| 168902 | + pWLoop->rRun = mxRun; |
| 168903 | + } |
| 168904 | + } |
| 168905 | + } |
| 168906 | +#ifdef WHERETRACE_ENABLED /* 0x80000 */ |
| 168907 | + if( (sqlite3WhereTrace & 0x80000)!=0 && pWInfo->bStarUsed ){ |
| 168908 | + sqlite3DebugPrintf("WhereLoops changed by star-query heuristic:\n"); |
| 168766 | 168909 | for(pWLoop=pWInfo->pLoops; pWLoop; pWLoop=pWLoop->pNextLoop){ |
| 168767 | | - if( pWLoop->maskSelf==m ){ |
| 168768 | | - pWLoop->rRun -= rDelta; |
| 168769 | | - pWLoop->nOut -= rDelta; |
| 168770 | | - pWLoop->rStarDelta = rDelta; |
| 168910 | + if( pWLoop->rStarDelta ){ |
| 168911 | + sqlite3WhereLoopPrint(pWLoop, &pWInfo->sWC); |
| 168771 | 168912 | } |
| 168772 | 168913 | } |
| 168773 | 168914 | } |
| 168915 | +#endif |
| 168774 | 168916 | } |
| 168775 | | - return pWInfo->nOutStarDelta>0 ? 18 : 12; |
| 168917 | + return pWInfo->bStarUsed ? 18 : 12; |
| 168918 | +} |
| 168919 | + |
| 168920 | +/* |
| 168921 | +** Two WhereLoop objects, pCandidate and pBaseline, are known to have the |
| 168922 | +** same cost. Look deep into each to see if pCandidate is even slightly |
| 168923 | +** better than pBaseline. Return false if it is, if pCandidate is is preferred. |
| 168924 | +** Return true if pBaseline is preferred or if we cannot tell the difference. |
| 168925 | +** |
| 168926 | +** Result Meaning |
| 168927 | +** -------- ---------------------------------------------------------- |
| 168928 | +** true We cannot tell the difference in pCandidate and pBaseline |
| 168929 | +** false pCandidate seems like a better choice than pBaseline |
| 168930 | +*/ |
| 168931 | +static SQLITE_NOINLINE int whereLoopIsNoBetter( |
| 168932 | + const WhereLoop *pCandidate, |
| 168933 | + const WhereLoop *pBaseline |
| 168934 | +){ |
| 168935 | + if( (pCandidate->wsFlags & WHERE_INDEXED)==0 ) return 1; |
| 168936 | + if( (pBaseline->wsFlags & WHERE_INDEXED)==0 ) return 1; |
| 168937 | + if( pCandidate->u.btree.pIndex->szIdxRow < |
| 168938 | + pBaseline->u.btree.pIndex->szIdxRow ) return 0; |
| 168939 | + return 1; |
| 168776 | 168940 | } |
| 168777 | 168941 | |
| 168778 | 168942 | /* |
| 168779 | 168943 | ** Given the list of WhereLoop objects at pWInfo->pLoops, this routine |
| 168780 | 168944 | ** attempts to find the lowest cost path that visits each WhereLoop |
| | @@ -168794,11 +168958,11 @@ |
| 168794 | 168958 | int iLoop; /* Loop counter over the terms of the join */ |
| 168795 | 168959 | int ii, jj; /* Loop counters */ |
| 168796 | 168960 | int mxI = 0; /* Index of next entry to replace */ |
| 168797 | 168961 | int nOrderBy; /* Number of ORDER BY clause terms */ |
| 168798 | 168962 | LogEst mxCost = 0; /* Maximum cost of a set of paths */ |
| 168799 | | - LogEst mxUnsorted = 0; /* Maximum unsorted cost of a set of path */ |
| 168963 | + LogEst mxUnsort = 0; /* Maximum unsorted cost of a set of path */ |
| 168800 | 168964 | int nTo, nFrom; /* Number of valid entries in aTo[] and aFrom[] */ |
| 168801 | 168965 | WherePath *aFrom; /* All nFrom paths at the previous level */ |
| 168802 | 168966 | WherePath *aTo; /* The nTo best paths at the current level */ |
| 168803 | 168967 | WherePath *pFrom; /* An element of aFrom[] that we are working on */ |
| 168804 | 168968 | WherePath *pTo; /* An element of aTo[] that we are working on */ |
| | @@ -168823,12 +168987,14 @@ |
| 168823 | 168987 | */ |
| 168824 | 168988 | if( nLoop<=1 ){ |
| 168825 | 168989 | mxChoice = 1; |
| 168826 | 168990 | }else if( nLoop==2 ){ |
| 168827 | 168991 | mxChoice = 5; |
| 168992 | + }else if( pParse->nErr ){ |
| 168993 | + mxChoice = 1; |
| 168828 | 168994 | }else{ |
| 168829 | | - mxChoice = computeMxChoice(pWInfo, nRowEst); |
| 168995 | + mxChoice = computeMxChoice(pWInfo); |
| 168830 | 168996 | } |
| 168831 | 168997 | assert( nLoop<=pWInfo->pTabList->nSrc ); |
| 168832 | 168998 | |
| 168833 | 168999 | /* If nRowEst is zero and there is an ORDER BY clause, ignore it. In this |
| 168834 | 169000 | ** case the purpose of this call is to estimate the number of rows returned |
| | @@ -168891,11 +169057,11 @@ |
| 168891 | 169057 | nTo = 0; |
| 168892 | 169058 | for(ii=0, pFrom=aFrom; ii<nFrom; ii++, pFrom++){ |
| 168893 | 169059 | for(pWLoop=pWInfo->pLoops; pWLoop; pWLoop=pWLoop->pNextLoop){ |
| 168894 | 169060 | LogEst nOut; /* Rows visited by (pFrom+pWLoop) */ |
| 168895 | 169061 | LogEst rCost; /* Cost of path (pFrom+pWLoop) */ |
| 168896 | | - LogEst rUnsorted; /* Unsorted cost of (pFrom+pWLoop) */ |
| 169062 | + LogEst rUnsort; /* Unsorted cost of (pFrom+pWLoop) */ |
| 168897 | 169063 | i8 isOrdered; /* isOrdered for (pFrom+pWLoop) */ |
| 168898 | 169064 | Bitmask maskNew; /* Mask of src visited by (..) */ |
| 168899 | 169065 | Bitmask revMask; /* Mask of rev-order loops for (..) */ |
| 168900 | 169066 | |
| 168901 | 169067 | if( (pWLoop->prereq & ~pFrom->maskLoop)!=0 ) continue; |
| | @@ -168909,15 +169075,15 @@ |
| 168909 | 169075 | continue; |
| 168910 | 169076 | } |
| 168911 | 169077 | |
| 168912 | 169078 | /* At this point, pWLoop is a candidate to be the next loop. |
| 168913 | 169079 | ** Compute its cost */ |
| 168914 | | - rUnsorted = pWLoop->rRun + pFrom->nRow; |
| 169080 | + rUnsort = pWLoop->rRun + pFrom->nRow; |
| 168915 | 169081 | if( pWLoop->rSetup ){ |
| 168916 | | - rUnsorted = sqlite3LogEstAdd(pWLoop->rSetup, rUnsorted); |
| 169082 | + rUnsort = sqlite3LogEstAdd(pWLoop->rSetup, rUnsort); |
| 168917 | 169083 | } |
| 168918 | | - rUnsorted = sqlite3LogEstAdd(rUnsorted, pFrom->rUnsorted); |
| 169084 | + rUnsort = sqlite3LogEstAdd(rUnsort, pFrom->rUnsort); |
| 168919 | 169085 | nOut = pFrom->nRow + pWLoop->nOut; |
| 168920 | 169086 | maskNew = pFrom->maskLoop | pWLoop->maskSelf; |
| 168921 | 169087 | isOrdered = pFrom->isOrdered; |
| 168922 | 169088 | if( isOrdered<0 ){ |
| 168923 | 169089 | revMask = 0; |
| | @@ -168935,19 +169101,19 @@ |
| 168935 | 169101 | } |
| 168936 | 169102 | /* TUNING: Add a small extra penalty (3) to sorting as an |
| 168937 | 169103 | ** extra encouragement to the query planner to select a plan |
| 168938 | 169104 | ** where the rows emerge in the correct order without any sorting |
| 168939 | 169105 | ** required. */ |
| 168940 | | - rCost = sqlite3LogEstAdd(rUnsorted, aSortCost[isOrdered]) + 3; |
| 169106 | + rCost = sqlite3LogEstAdd(rUnsort, aSortCost[isOrdered]) + 3; |
| 168941 | 169107 | |
| 168942 | 169108 | WHERETRACE(0x002, |
| 168943 | 169109 | ("---- sort cost=%-3d (%d/%d) increases cost %3d to %-3d\n", |
| 168944 | 169110 | aSortCost[isOrdered], (nOrderBy-isOrdered), nOrderBy, |
| 168945 | | - rUnsorted, rCost)); |
| 169111 | + rUnsort, rCost)); |
| 168946 | 169112 | }else{ |
| 168947 | | - rCost = rUnsorted; |
| 168948 | | - rUnsorted -= 2; /* TUNING: Slight bias in favor of no-sort plans */ |
| 169113 | + rCost = rUnsort; |
| 169114 | + rUnsort -= 2; /* TUNING: Slight bias in favor of no-sort plans */ |
| 168949 | 169115 | } |
| 168950 | 169116 | |
| 168951 | 169117 | /* Check to see if pWLoop should be added to the set of |
| 168952 | 169118 | ** mxChoice best-so-far paths. |
| 168953 | 169119 | ** |
| | @@ -168969,19 +169135,19 @@ |
| 168969 | 169135 | } |
| 168970 | 169136 | } |
| 168971 | 169137 | if( jj>=nTo ){ |
| 168972 | 169138 | /* None of the existing best-so-far paths match the candidate. */ |
| 168973 | 169139 | if( nTo>=mxChoice |
| 168974 | | - && (rCost>mxCost || (rCost==mxCost && rUnsorted>=mxUnsorted)) |
| 169140 | + && (rCost>mxCost || (rCost==mxCost && rUnsort>=mxUnsort)) |
| 168975 | 169141 | ){ |
| 168976 | 169142 | /* The current candidate is no better than any of the mxChoice |
| 168977 | 169143 | ** paths currently in the best-so-far buffer. So discard |
| 168978 | 169144 | ** this candidate as not viable. */ |
| 168979 | 169145 | #ifdef WHERETRACE_ENABLED /* 0x4 */ |
| 168980 | 169146 | if( sqlite3WhereTrace&0x4 ){ |
| 168981 | 169147 | sqlite3DebugPrintf("Skip %s cost=%-3d,%3d,%3d order=%c\n", |
| 168982 | | - wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted, |
| 169148 | + wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsort, |
| 168983 | 169149 | isOrdered>=0 ? isOrdered+'0' : '?'); |
| 168984 | 169150 | } |
| 168985 | 169151 | #endif |
| 168986 | 169152 | continue; |
| 168987 | 169153 | } |
| | @@ -168996,11 +169162,11 @@ |
| 168996 | 169162 | } |
| 168997 | 169163 | pTo = &aTo[jj]; |
| 168998 | 169164 | #ifdef WHERETRACE_ENABLED /* 0x4 */ |
| 168999 | 169165 | if( sqlite3WhereTrace&0x4 ){ |
| 169000 | 169166 | sqlite3DebugPrintf("New %s cost=%-3d,%3d,%3d order=%c\n", |
| 169001 | | - wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted, |
| 169167 | + wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsort, |
| 169002 | 169168 | isOrdered>=0 ? isOrdered+'0' : '?'); |
| 169003 | 169169 | } |
| 169004 | 169170 | #endif |
| 169005 | 169171 | }else{ |
| 169006 | 169172 | /* Control reaches here if best-so-far path pTo=aTo[jj] covers the |
| | @@ -169007,28 +169173,27 @@ |
| 169007 | 169173 | ** same set of loops and has the same isOrdered setting as the |
| 169008 | 169174 | ** candidate path. Check to see if the candidate should replace |
| 169009 | 169175 | ** pTo or if the candidate should be skipped. |
| 169010 | 169176 | ** |
| 169011 | 169177 | ** The conditional is an expanded vector comparison equivalent to: |
| 169012 | | - ** (pTo->rCost,pTo->nRow,pTo->rUnsorted) <= (rCost,nOut,rUnsorted) |
| 169178 | + ** (pTo->rCost,pTo->nRow,pTo->rUnsort) <= (rCost,nOut,rUnsort) |
| 169013 | 169179 | */ |
| 169014 | | - if( pTo->rCost<rCost |
| 169015 | | - || (pTo->rCost==rCost |
| 169016 | | - && (pTo->nRow<nOut |
| 169017 | | - || (pTo->nRow==nOut && pTo->rUnsorted<=rUnsorted) |
| 169018 | | - ) |
| 169019 | | - ) |
| 169180 | + if( (pTo->rCost<rCost) |
| 169181 | + || (pTo->rCost==rCost && pTo->nRow<nOut) |
| 169182 | + || (pTo->rCost==rCost && pTo->nRow==nOut && pTo->rUnsort<rUnsort) |
| 169183 | + || (pTo->rCost==rCost && pTo->nRow==nOut && pTo->rUnsort==rUnsort |
| 169184 | + && whereLoopIsNoBetter(pWLoop, pTo->aLoop[iLoop]) ) |
| 169020 | 169185 | ){ |
| 169021 | 169186 | #ifdef WHERETRACE_ENABLED /* 0x4 */ |
| 169022 | 169187 | if( sqlite3WhereTrace&0x4 ){ |
| 169023 | 169188 | sqlite3DebugPrintf( |
| 169024 | 169189 | "Skip %s cost=%-3d,%3d,%3d order=%c", |
| 169025 | | - wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted, |
| 169190 | + wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsort, |
| 169026 | 169191 | isOrdered>=0 ? isOrdered+'0' : '?'); |
| 169027 | 169192 | sqlite3DebugPrintf(" vs %s cost=%-3d,%3d,%3d order=%c\n", |
| 169028 | 169193 | wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow, |
| 169029 | | - pTo->rUnsorted, pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?'); |
| 169194 | + pTo->rUnsort, pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?'); |
| 169030 | 169195 | } |
| 169031 | 169196 | #endif |
| 169032 | 169197 | /* Discard the candidate path from further consideration */ |
| 169033 | 169198 | testcase( pTo->rCost==rCost ); |
| 169034 | 169199 | continue; |
| | @@ -169038,37 +169203,37 @@ |
| 169038 | 169203 | ** pTo path. Replace pTo with the candidate. */ |
| 169039 | 169204 | #ifdef WHERETRACE_ENABLED /* 0x4 */ |
| 169040 | 169205 | if( sqlite3WhereTrace&0x4 ){ |
| 169041 | 169206 | sqlite3DebugPrintf( |
| 169042 | 169207 | "Update %s cost=%-3d,%3d,%3d order=%c", |
| 169043 | | - wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted, |
| 169208 | + wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsort, |
| 169044 | 169209 | isOrdered>=0 ? isOrdered+'0' : '?'); |
| 169045 | 169210 | sqlite3DebugPrintf(" was %s cost=%-3d,%3d,%3d order=%c\n", |
| 169046 | 169211 | wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow, |
| 169047 | | - pTo->rUnsorted, pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?'); |
| 169212 | + pTo->rUnsort, pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?'); |
| 169048 | 169213 | } |
| 169049 | 169214 | #endif |
| 169050 | 169215 | } |
| 169051 | 169216 | /* pWLoop is a winner. Add it to the set of best so far */ |
| 169052 | 169217 | pTo->maskLoop = pFrom->maskLoop | pWLoop->maskSelf; |
| 169053 | 169218 | pTo->revLoop = revMask; |
| 169054 | 169219 | pTo->nRow = nOut; |
| 169055 | 169220 | pTo->rCost = rCost; |
| 169056 | | - pTo->rUnsorted = rUnsorted; |
| 169221 | + pTo->rUnsort = rUnsort; |
| 169057 | 169222 | pTo->isOrdered = isOrdered; |
| 169058 | 169223 | memcpy(pTo->aLoop, pFrom->aLoop, sizeof(WhereLoop*)*iLoop); |
| 169059 | 169224 | pTo->aLoop[iLoop] = pWLoop; |
| 169060 | 169225 | if( nTo>=mxChoice ){ |
| 169061 | 169226 | mxI = 0; |
| 169062 | 169227 | mxCost = aTo[0].rCost; |
| 169063 | | - mxUnsorted = aTo[0].nRow; |
| 169228 | + mxUnsort = aTo[0].nRow; |
| 169064 | 169229 | for(jj=1, pTo=&aTo[1]; jj<mxChoice; jj++, pTo++){ |
| 169065 | 169230 | if( pTo->rCost>mxCost |
| 169066 | | - || (pTo->rCost==mxCost && pTo->rUnsorted>mxUnsorted) |
| 169231 | + || (pTo->rCost==mxCost && pTo->rUnsort>mxUnsort) |
| 169067 | 169232 | ){ |
| 169068 | 169233 | mxCost = pTo->rCost; |
| 169069 | | - mxUnsorted = pTo->rUnsorted; |
| 169234 | + mxUnsort = pTo->rUnsort; |
| 169070 | 169235 | mxI = jj; |
| 169071 | 169236 | } |
| 169072 | 169237 | } |
| 169073 | 169238 | } |
| 169074 | 169239 | } |
| | @@ -169076,12 +169241,14 @@ |
| 169076 | 169241 | |
| 169077 | 169242 | #ifdef WHERETRACE_ENABLED /* >=2 */ |
| 169078 | 169243 | if( sqlite3WhereTrace & 0x02 ){ |
| 169079 | 169244 | LogEst rMin, rFloor = 0; |
| 169080 | 169245 | int nDone = 0; |
| 169246 | + int nProgress; |
| 169081 | 169247 | sqlite3DebugPrintf("---- after round %d ----\n", iLoop); |
| 169082 | | - while( nDone<nTo ){ |
| 169248 | + do{ |
| 169249 | + nProgress = 0; |
| 169083 | 169250 | rMin = 0x7fff; |
| 169084 | 169251 | for(ii=0, pTo=aTo; ii<nTo; ii++, pTo++){ |
| 169085 | 169252 | if( pTo->rCost>rFloor && pTo->rCost<rMin ) rMin = pTo->rCost; |
| 169086 | 169253 | } |
| 169087 | 169254 | for(ii=0, pTo=aTo; ii<nTo; ii++, pTo++){ |
| | @@ -169093,14 +169260,15 @@ |
| 169093 | 169260 | sqlite3DebugPrintf(" rev=0x%llx\n", pTo->revLoop); |
| 169094 | 169261 | }else{ |
| 169095 | 169262 | sqlite3DebugPrintf("\n"); |
| 169096 | 169263 | } |
| 169097 | 169264 | nDone++; |
| 169265 | + nProgress++; |
| 169098 | 169266 | } |
| 169099 | 169267 | } |
| 169100 | 169268 | rFloor = rMin; |
| 169101 | | - } |
| 169269 | + }while( nDone<nTo && nProgress>0 ); |
| 169102 | 169270 | } |
| 169103 | 169271 | #endif |
| 169104 | 169272 | |
| 169105 | 169273 | /* Swap the roles of aFrom and aTo for the next generation */ |
| 169106 | 169274 | pFrom = aTo; |
| | @@ -169190,11 +169358,14 @@ |
| 169190 | 169358 | pWInfo->revMask = revMask; |
| 169191 | 169359 | } |
| 169192 | 169360 | } |
| 169193 | 169361 | } |
| 169194 | 169362 | |
| 169195 | | - pWInfo->nRowOut = pFrom->nRow + pWInfo->nOutStarDelta; |
| 169363 | + pWInfo->nRowOut = pFrom->nRow; |
| 169364 | +#ifdef WHERETRACE_ENABLED |
| 169365 | + pWInfo->rTotalCost = pFrom->rCost; |
| 169366 | +#endif |
| 169196 | 169367 | |
| 169197 | 169368 | /* Free temporary memory and return success */ |
| 169198 | 169369 | sqlite3StackFreeNN(pParse->db, pSpace); |
| 169199 | 169370 | return SQLITE_OK; |
| 169200 | 169371 | } |
| | @@ -169588,11 +169759,10 @@ |
| 169588 | 169759 | pLoop->cId, (double)sqlite3LogEstToInt(nSearch), pTab->zName, |
| 169589 | 169760 | (double)sqlite3LogEstToInt(pTab->nRowLogEst))); |
| 169590 | 169761 | } |
| 169591 | 169762 | } |
| 169592 | 169763 | nSearch += pLoop->nOut; |
| 169593 | | - if( pWInfo->nOutStarDelta ) nSearch += pLoop->rStarDelta; |
| 169594 | 169764 | } |
| 169595 | 169765 | } |
| 169596 | 169766 | |
| 169597 | 169767 | /* |
| 169598 | 169768 | ** The index pIdx is used by a query and contains one or more expressions. |
| | @@ -170071,11 +170241,12 @@ |
| 170071 | 170241 | goto whereBeginError; |
| 170072 | 170242 | } |
| 170073 | 170243 | assert( db->mallocFailed==0 ); |
| 170074 | 170244 | #ifdef WHERETRACE_ENABLED |
| 170075 | 170245 | if( sqlite3WhereTrace ){ |
| 170076 | | - sqlite3DebugPrintf("---- Solution nRow=%d", pWInfo->nRowOut); |
| 170246 | + sqlite3DebugPrintf("---- Solution cost=%d, nRow=%d", |
| 170247 | + pWInfo->rTotalCost, pWInfo->nRowOut); |
| 170077 | 170248 | if( pWInfo->nOBSat>0 ){ |
| 170078 | 170249 | sqlite3DebugPrintf(" ORDERBY=%d,0x%llx", pWInfo->nOBSat, pWInfo->revMask); |
| 170079 | 170250 | } |
| 170080 | 170251 | switch( pWInfo->eDistinct ){ |
| 170081 | 170252 | case WHERE_DISTINCT_UNIQUE: { |
| | @@ -226574,15 +226745,17 @@ |
| 226574 | 226745 | ** SELECT 1, NULL, 'abc' |
| 226575 | 226746 | */ |
| 226576 | 226747 | struct SessionTable { |
| 226577 | 226748 | SessionTable *pNext; |
| 226578 | 226749 | char *zName; /* Local name of table */ |
| 226579 | | - int nCol; /* Number of columns in table zName */ |
| 226750 | + int nCol; /* Number of non-hidden columns */ |
| 226751 | + int nTotalCol; /* Number of columns including hidden */ |
| 226580 | 226752 | int bStat1; /* True if this is sqlite_stat1 */ |
| 226581 | 226753 | int bRowid; /* True if this table uses rowid for PK */ |
| 226582 | 226754 | const char **azCol; /* Column names */ |
| 226583 | 226755 | const char **azDflt; /* Default value expressions */ |
| 226756 | + int *aiIdx; /* Index to pass to xNew/xOld */ |
| 226584 | 226757 | u8 *abPK; /* Array of primary key flags */ |
| 226585 | 226758 | int nEntry; /* Total number of entries in hash table */ |
| 226586 | 226759 | int nChange; /* Size of apChange[] array */ |
| 226587 | 226760 | SessionChange **apChange; /* Hash table buckets */ |
| 226588 | 226761 | sqlite3_stmt *pDfltStmt; |
| | @@ -226981,26 +227154,26 @@ |
| 226981 | 227154 | int *pbNullPK /* OUT: True if there are NULL values in PK */ |
| 226982 | 227155 | ){ |
| 226983 | 227156 | unsigned int h = 0; /* Hash value to return */ |
| 226984 | 227157 | int i; /* Used to iterate through columns */ |
| 226985 | 227158 | |
| 227159 | + assert( pTab->nTotalCol==pSession->hook.xCount(pSession->hook.pCtx) ); |
| 226986 | 227160 | if( pTab->bRowid ){ |
| 226987 | | - assert( pTab->nCol-1==pSession->hook.xCount(pSession->hook.pCtx) ); |
| 226988 | 227161 | h = sessionHashAppendI64(h, iRowid); |
| 226989 | 227162 | }else{ |
| 226990 | 227163 | assert( *pbNullPK==0 ); |
| 226991 | | - assert( pTab->nCol==pSession->hook.xCount(pSession->hook.pCtx) ); |
| 226992 | 227164 | for(i=0; i<pTab->nCol; i++){ |
| 226993 | 227165 | if( pTab->abPK[i] ){ |
| 226994 | 227166 | int rc; |
| 226995 | 227167 | int eType; |
| 226996 | 227168 | sqlite3_value *pVal; |
| 227169 | + int iIdx = pTab->aiIdx[i]; |
| 226997 | 227170 | |
| 226998 | 227171 | if( bNew ){ |
| 226999 | | - rc = pSession->hook.xNew(pSession->hook.pCtx, i, &pVal); |
| 227172 | + rc = pSession->hook.xNew(pSession->hook.pCtx, iIdx, &pVal); |
| 227000 | 227173 | }else{ |
| 227001 | | - rc = pSession->hook.xOld(pSession->hook.pCtx, i, &pVal); |
| 227174 | + rc = pSession->hook.xOld(pSession->hook.pCtx, iIdx, &pVal); |
| 227002 | 227175 | } |
| 227003 | 227176 | if( rc!=SQLITE_OK ) return rc; |
| 227004 | 227177 | |
| 227005 | 227178 | eType = sqlite3_value_type(pVal); |
| 227006 | 227179 | h = sessionHashAppendType(h, eType); |
| | @@ -227333,22 +227506,23 @@ |
| 227333 | 227506 | a += sessionSerialLen(a); |
| 227334 | 227507 | }else{ |
| 227335 | 227508 | sqlite3_value *pVal; /* Value returned by preupdate_new/old */ |
| 227336 | 227509 | int rc; /* Error code from preupdate_new/old */ |
| 227337 | 227510 | int eType = *a++; /* Type of value from change record */ |
| 227511 | + int iIdx = pTab->aiIdx[iCol]; |
| 227338 | 227512 | |
| 227339 | 227513 | /* The following calls to preupdate_new() and preupdate_old() can not |
| 227340 | 227514 | ** fail. This is because they cache their return values, and by the |
| 227341 | 227515 | ** time control flows to here they have already been called once from |
| 227342 | 227516 | ** within sessionPreupdateHash(). The first two asserts below verify |
| 227343 | 227517 | ** this (that the method has already been called). */ |
| 227344 | 227518 | if( op==SQLITE_INSERT ){ |
| 227345 | 227519 | /* assert( db->pPreUpdate->pNewUnpacked || db->pPreUpdate->aNew ); */ |
| 227346 | | - rc = pSession->hook.xNew(pSession->hook.pCtx, iCol, &pVal); |
| 227520 | + rc = pSession->hook.xNew(pSession->hook.pCtx, iIdx, &pVal); |
| 227347 | 227521 | }else{ |
| 227348 | 227522 | /* assert( db->pPreUpdate->pUnpacked ); */ |
| 227349 | | - rc = pSession->hook.xOld(pSession->hook.pCtx, iCol, &pVal); |
| 227523 | + rc = pSession->hook.xOld(pSession->hook.pCtx, iIdx, &pVal); |
| 227350 | 227524 | } |
| 227351 | 227525 | assert( rc==SQLITE_OK ); |
| 227352 | 227526 | (void)rc; /* Suppress warning about unused variable */ |
| 227353 | 227527 | if( sqlite3_value_type(pVal)!=eType ) return 0; |
| 227354 | 227528 | |
| | @@ -227469,13 +227643,15 @@ |
| 227469 | 227643 | sqlite3_session *pSession, /* For memory accounting. May be NULL */ |
| 227470 | 227644 | sqlite3 *db, /* Database connection */ |
| 227471 | 227645 | const char *zDb, /* Name of attached database (e.g. "main") */ |
| 227472 | 227646 | const char *zThis, /* Table name */ |
| 227473 | 227647 | int *pnCol, /* OUT: number of columns */ |
| 227648 | + int *pnTotalCol, /* OUT: number of hidden columns */ |
| 227474 | 227649 | const char **pzTab, /* OUT: Copy of zThis */ |
| 227475 | 227650 | const char ***pazCol, /* OUT: Array of column names for table */ |
| 227476 | 227651 | const char ***pazDflt, /* OUT: Array of default value expressions */ |
| 227652 | + int **paiIdx, /* OUT: Array of xNew/xOld indexes */ |
| 227477 | 227653 | u8 **pabPK, /* OUT: Array of booleans - true for PK col */ |
| 227478 | 227654 | int *pbRowid /* OUT: True if only PK is a rowid */ |
| 227479 | 227655 | ){ |
| 227480 | 227656 | char *zPragma; |
| 227481 | 227657 | sqlite3_stmt *pStmt; |
| | @@ -227486,37 +227662,40 @@ |
| 227486 | 227662 | int i; |
| 227487 | 227663 | u8 *pAlloc = 0; |
| 227488 | 227664 | char **azCol = 0; |
| 227489 | 227665 | char **azDflt = 0; |
| 227490 | 227666 | u8 *abPK = 0; |
| 227667 | + int *aiIdx = 0; |
| 227491 | 227668 | int bRowid = 0; /* Set to true to use rowid as PK */ |
| 227492 | 227669 | |
| 227493 | 227670 | assert( pazCol && pabPK ); |
| 227494 | 227671 | |
| 227495 | 227672 | *pazCol = 0; |
| 227496 | 227673 | *pabPK = 0; |
| 227497 | 227674 | *pnCol = 0; |
| 227675 | + if( pnTotalCol ) *pnTotalCol = 0; |
| 227676 | + if( paiIdx ) *paiIdx = 0; |
| 227498 | 227677 | if( pzTab ) *pzTab = 0; |
| 227499 | 227678 | if( pazDflt ) *pazDflt = 0; |
| 227500 | 227679 | |
| 227501 | 227680 | nThis = sqlite3Strlen30(zThis); |
| 227502 | 227681 | if( nThis==12 && 0==sqlite3_stricmp("sqlite_stat1", zThis) ){ |
| 227503 | 227682 | rc = sqlite3_table_column_metadata(db, zDb, zThis, 0, 0, 0, 0, 0, 0); |
| 227504 | 227683 | if( rc==SQLITE_OK ){ |
| 227505 | 227684 | /* For sqlite_stat1, pretend that (tbl,idx) is the PRIMARY KEY. */ |
| 227506 | 227685 | zPragma = sqlite3_mprintf( |
| 227507 | | - "SELECT 0, 'tbl', '', 0, '', 1 UNION ALL " |
| 227508 | | - "SELECT 1, 'idx', '', 0, '', 2 UNION ALL " |
| 227509 | | - "SELECT 2, 'stat', '', 0, '', 0" |
| 227686 | + "SELECT 0, 'tbl', '', 0, '', 1, 0 UNION ALL " |
| 227687 | + "SELECT 1, 'idx', '', 0, '', 2, 0 UNION ALL " |
| 227688 | + "SELECT 2, 'stat', '', 0, '', 0, 0" |
| 227510 | 227689 | ); |
| 227511 | 227690 | }else if( rc==SQLITE_ERROR ){ |
| 227512 | 227691 | zPragma = sqlite3_mprintf(""); |
| 227513 | 227692 | }else{ |
| 227514 | 227693 | return rc; |
| 227515 | 227694 | } |
| 227516 | 227695 | }else{ |
| 227517 | | - zPragma = sqlite3_mprintf("PRAGMA '%q'.table_info('%q')", zDb, zThis); |
| 227696 | + zPragma = sqlite3_mprintf("PRAGMA '%q'.table_xinfo('%q')", zDb, zThis); |
| 227518 | 227697 | } |
| 227519 | 227698 | if( !zPragma ){ |
| 227520 | 227699 | return SQLITE_NOMEM; |
| 227521 | 227700 | } |
| 227522 | 227701 | |
| | @@ -227529,20 +227708,22 @@ |
| 227529 | 227708 | nByte = nThis + 1; |
| 227530 | 227709 | bRowid = (pbRowid!=0); |
| 227531 | 227710 | while( SQLITE_ROW==sqlite3_step(pStmt) ){ |
| 227532 | 227711 | nByte += sqlite3_column_bytes(pStmt, 1); /* name */ |
| 227533 | 227712 | nByte += sqlite3_column_bytes(pStmt, 4); /* dflt_value */ |
| 227534 | | - nDbCol++; |
| 227713 | + if( sqlite3_column_int(pStmt, 6)==0 ){ /* !hidden */ |
| 227714 | + nDbCol++; |
| 227715 | + } |
| 227535 | 227716 | if( sqlite3_column_int(pStmt, 5) ) bRowid = 0; /* pk */ |
| 227536 | 227717 | } |
| 227537 | 227718 | if( nDbCol==0 ) bRowid = 0; |
| 227538 | 227719 | nDbCol += bRowid; |
| 227539 | 227720 | nByte += strlen(SESSIONS_ROWID); |
| 227540 | 227721 | rc = sqlite3_reset(pStmt); |
| 227541 | 227722 | |
| 227542 | 227723 | if( rc==SQLITE_OK ){ |
| 227543 | | - nByte += nDbCol * (sizeof(const char *)*2 + sizeof(u8) + 1 + 1); |
| 227724 | + nByte += nDbCol * (sizeof(const char *)*2 +sizeof(int)+sizeof(u8) + 1 + 1); |
| 227544 | 227725 | pAlloc = sessionMalloc64(pSession, nByte); |
| 227545 | 227726 | if( pAlloc==0 ){ |
| 227546 | 227727 | rc = SQLITE_NOMEM; |
| 227547 | 227728 | }else{ |
| 227548 | 227729 | memset(pAlloc, 0, nByte); |
| | @@ -227549,12 +227730,12 @@ |
| 227549 | 227730 | } |
| 227550 | 227731 | } |
| 227551 | 227732 | if( rc==SQLITE_OK ){ |
| 227552 | 227733 | azCol = (char **)pAlloc; |
| 227553 | 227734 | azDflt = (char**)&azCol[nDbCol]; |
| 227554 | | - pAlloc = (u8 *)&azDflt[nDbCol]; |
| 227555 | | - abPK = (u8 *)pAlloc; |
| 227735 | + aiIdx = (int*)&azDflt[nDbCol]; |
| 227736 | + abPK = (u8 *)&aiIdx[nDbCol]; |
| 227556 | 227737 | pAlloc = &abPK[nDbCol]; |
| 227557 | 227738 | if( pzTab ){ |
| 227558 | 227739 | memcpy(pAlloc, zThis, nThis+1); |
| 227559 | 227740 | *pzTab = (char *)pAlloc; |
| 227560 | 227741 | pAlloc += nThis+1; |
| | @@ -227565,31 +227746,36 @@ |
| 227565 | 227746 | size_t nName = strlen(SESSIONS_ROWID); |
| 227566 | 227747 | memcpy(pAlloc, SESSIONS_ROWID, nName+1); |
| 227567 | 227748 | azCol[i] = (char*)pAlloc; |
| 227568 | 227749 | pAlloc += nName+1; |
| 227569 | 227750 | abPK[i] = 1; |
| 227751 | + aiIdx[i] = -1; |
| 227570 | 227752 | i++; |
| 227571 | 227753 | } |
| 227572 | 227754 | while( SQLITE_ROW==sqlite3_step(pStmt) ){ |
| 227573 | | - int nName = sqlite3_column_bytes(pStmt, 1); |
| 227574 | | - int nDflt = sqlite3_column_bytes(pStmt, 4); |
| 227575 | | - const unsigned char *zName = sqlite3_column_text(pStmt, 1); |
| 227576 | | - const unsigned char *zDflt = sqlite3_column_text(pStmt, 4); |
| 227577 | | - |
| 227578 | | - if( zName==0 ) break; |
| 227579 | | - memcpy(pAlloc, zName, nName+1); |
| 227580 | | - azCol[i] = (char *)pAlloc; |
| 227581 | | - pAlloc += nName+1; |
| 227582 | | - if( zDflt ){ |
| 227583 | | - memcpy(pAlloc, zDflt, nDflt+1); |
| 227584 | | - azDflt[i] = (char *)pAlloc; |
| 227585 | | - pAlloc += nDflt+1; |
| 227586 | | - }else{ |
| 227587 | | - azDflt[i] = 0; |
| 227588 | | - } |
| 227589 | | - abPK[i] = sqlite3_column_int(pStmt, 5); |
| 227590 | | - i++; |
| 227755 | + if( sqlite3_column_int(pStmt, 6)==0 ){ /* !hidden */ |
| 227756 | + int nName = sqlite3_column_bytes(pStmt, 1); |
| 227757 | + int nDflt = sqlite3_column_bytes(pStmt, 4); |
| 227758 | + const unsigned char *zName = sqlite3_column_text(pStmt, 1); |
| 227759 | + const unsigned char *zDflt = sqlite3_column_text(pStmt, 4); |
| 227760 | + |
| 227761 | + if( zName==0 ) break; |
| 227762 | + memcpy(pAlloc, zName, nName+1); |
| 227763 | + azCol[i] = (char *)pAlloc; |
| 227764 | + pAlloc += nName+1; |
| 227765 | + if( zDflt ){ |
| 227766 | + memcpy(pAlloc, zDflt, nDflt+1); |
| 227767 | + azDflt[i] = (char *)pAlloc; |
| 227768 | + pAlloc += nDflt+1; |
| 227769 | + }else{ |
| 227770 | + azDflt[i] = 0; |
| 227771 | + } |
| 227772 | + abPK[i] = sqlite3_column_int(pStmt, 5); |
| 227773 | + aiIdx[i] = sqlite3_column_int(pStmt, 0); |
| 227774 | + i++; |
| 227775 | + } |
| 227776 | + if( pnTotalCol ) (*pnTotalCol)++; |
| 227591 | 227777 | } |
| 227592 | 227778 | rc = sqlite3_reset(pStmt); |
| 227593 | 227779 | } |
| 227594 | 227780 | |
| 227595 | 227781 | /* If successful, populate the output variables. Otherwise, zero them and |
| | @@ -227598,10 +227784,11 @@ |
| 227598 | 227784 | if( rc==SQLITE_OK ){ |
| 227599 | 227785 | *pazCol = (const char**)azCol; |
| 227600 | 227786 | if( pazDflt ) *pazDflt = (const char**)azDflt; |
| 227601 | 227787 | *pabPK = abPK; |
| 227602 | 227788 | *pnCol = nDbCol; |
| 227789 | + if( paiIdx ) *paiIdx = aiIdx; |
| 227603 | 227790 | }else{ |
| 227604 | 227791 | sessionFree(pSession, azCol); |
| 227605 | 227792 | } |
| 227606 | 227793 | if( pbRowid ) *pbRowid = bRowid; |
| 227607 | 227794 | sqlite3_finalize(pStmt); |
| | @@ -227629,11 +227816,12 @@ |
| 227629 | 227816 | |
| 227630 | 227817 | if( pTab->nCol==0 ){ |
| 227631 | 227818 | u8 *abPK; |
| 227632 | 227819 | assert( pTab->azCol==0 || pTab->abPK==0 ); |
| 227633 | 227820 | rc = sessionTableInfo(pSession, db, zDb, |
| 227634 | | - pTab->zName, &pTab->nCol, 0, &pTab->azCol, &pTab->azDflt, &abPK, |
| 227821 | + pTab->zName, &pTab->nCol, &pTab->nTotalCol, 0, &pTab->azCol, |
| 227822 | + &pTab->azDflt, &pTab->aiIdx, &abPK, |
| 227635 | 227823 | ((pSession==0 || pSession->bImplicitPK) ? &pTab->bRowid : 0) |
| 227636 | 227824 | ); |
| 227637 | 227825 | if( rc==SQLITE_OK ){ |
| 227638 | 227826 | int i; |
| 227639 | 227827 | for(i=0; i<pTab->nCol; i++){ |
| | @@ -227664,19 +227852,21 @@ |
| 227664 | 227852 | /* |
| 227665 | 227853 | ** Re-initialize table object pTab. |
| 227666 | 227854 | */ |
| 227667 | 227855 | static int sessionReinitTable(sqlite3_session *pSession, SessionTable *pTab){ |
| 227668 | 227856 | int nCol = 0; |
| 227857 | + int nTotalCol = 0; |
| 227669 | 227858 | const char **azCol = 0; |
| 227670 | 227859 | const char **azDflt = 0; |
| 227860 | + int *aiIdx = 0; |
| 227671 | 227861 | u8 *abPK = 0; |
| 227672 | 227862 | int bRowid = 0; |
| 227673 | 227863 | |
| 227674 | 227864 | assert( pSession->rc==SQLITE_OK ); |
| 227675 | 227865 | |
| 227676 | 227866 | pSession->rc = sessionTableInfo(pSession, pSession->db, pSession->zDb, |
| 227677 | | - pTab->zName, &nCol, 0, &azCol, &azDflt, &abPK, |
| 227867 | + pTab->zName, &nCol, &nTotalCol, 0, &azCol, &azDflt, &aiIdx, &abPK, |
| 227678 | 227868 | (pSession->bImplicitPK ? &bRowid : 0) |
| 227679 | 227869 | ); |
| 227680 | 227870 | if( pSession->rc==SQLITE_OK ){ |
| 227681 | 227871 | if( pTab->nCol>nCol || pTab->bRowid!=bRowid ){ |
| 227682 | 227872 | pSession->rc = SQLITE_SCHEMA; |
| | @@ -227695,12 +227885,14 @@ |
| 227695 | 227885 | |
| 227696 | 227886 | if( pSession->rc==SQLITE_OK ){ |
| 227697 | 227887 | const char **a = pTab->azCol; |
| 227698 | 227888 | pTab->azCol = azCol; |
| 227699 | 227889 | pTab->nCol = nCol; |
| 227890 | + pTab->nTotalCol = nTotalCol; |
| 227700 | 227891 | pTab->azDflt = azDflt; |
| 227701 | 227892 | pTab->abPK = abPK; |
| 227893 | + pTab->aiIdx = aiIdx; |
| 227702 | 227894 | azCol = a; |
| 227703 | 227895 | } |
| 227704 | 227896 | if( pSession->bEnableSize ){ |
| 227705 | 227897 | pSession->nMaxChangesetSize += (nCol - nOldCol); |
| 227706 | 227898 | pSession->nMaxChangesetSize += sessionVarintLen(nCol); |
| | @@ -228014,11 +228206,11 @@ |
| 228014 | 228206 | if( pTab->bRowid ) nNew += 9; |
| 228015 | 228207 | if( op!=SQLITE_DELETE ){ |
| 228016 | 228208 | int ii; |
| 228017 | 228209 | for(ii=0; ii<pTab->nCol; ii++){ |
| 228018 | 228210 | sqlite3_value *p = 0; |
| 228019 | | - pSession->hook.xNew(pSession->hook.pCtx, ii, &p); |
| 228211 | + pSession->hook.xNew(pSession->hook.pCtx, pTab->aiIdx[ii], &p); |
| 228020 | 228212 | sessionSerializeValue(0, p, &nNew); |
| 228021 | 228213 | } |
| 228022 | 228214 | } |
| 228023 | 228215 | }else if( op==SQLITE_DELETE ){ |
| 228024 | 228216 | nNew += pC->nRecord; |
| | @@ -228034,12 +228226,13 @@ |
| 228034 | 228226 | } |
| 228035 | 228227 | for(ii=pTab->bRowid; ii<pTab->nCol; ii++){ |
| 228036 | 228228 | int bChanged = 1; |
| 228037 | 228229 | int nOld = 0; |
| 228038 | 228230 | int eType; |
| 228231 | + int iIdx = pTab->aiIdx[ii]; |
| 228039 | 228232 | sqlite3_value *p = 0; |
| 228040 | | - pSession->hook.xNew(pSession->hook.pCtx, ii-pTab->bRowid, &p); |
| 228233 | + pSession->hook.xNew(pSession->hook.pCtx, iIdx, &p); |
| 228041 | 228234 | if( p==0 ){ |
| 228042 | 228235 | return SQLITE_NOMEM; |
| 228043 | 228236 | } |
| 228044 | 228237 | |
| 228045 | 228238 | eType = *pCsr++; |
| | @@ -228132,15 +228325,15 @@ |
| 228132 | 228325 | if( sessionInitTable(pSession, pTab, pSession->db, pSession->zDb) ) return; |
| 228133 | 228326 | |
| 228134 | 228327 | /* Check the number of columns in this xPreUpdate call matches the |
| 228135 | 228328 | ** number of columns in the table. */ |
| 228136 | 228329 | nExpect = pSession->hook.xCount(pSession->hook.pCtx); |
| 228137 | | - if( (pTab->nCol-pTab->bRowid)<nExpect ){ |
| 228330 | + if( pTab->nTotalCol<nExpect ){ |
| 228138 | 228331 | if( sessionReinitTable(pSession, pTab) ) return; |
| 228139 | 228332 | if( sessionUpdateChanges(pSession, pTab) ) return; |
| 228140 | 228333 | } |
| 228141 | | - if( (pTab->nCol-pTab->bRowid)!=nExpect ){ |
| 228334 | + if( pTab->nTotalCol!=nExpect ){ |
| 228142 | 228335 | pSession->rc = SQLITE_SCHEMA; |
| 228143 | 228336 | return; |
| 228144 | 228337 | } |
| 228145 | 228338 | |
| 228146 | 228339 | /* Grow the hash table if required */ |
| | @@ -228193,18 +228386,19 @@ |
| 228193 | 228386 | assert( rc==SQLITE_OK ); |
| 228194 | 228387 | pTab->nEntry++; |
| 228195 | 228388 | |
| 228196 | 228389 | /* Figure out how large an allocation is required */ |
| 228197 | 228390 | nByte = sizeof(SessionChange); |
| 228198 | | - for(i=0; i<(pTab->nCol-pTab->bRowid); i++){ |
| 228391 | + for(i=pTab->bRowid; i<pTab->nCol; i++){ |
| 228392 | + int iIdx = pTab->aiIdx[i]; |
| 228199 | 228393 | sqlite3_value *p = 0; |
| 228200 | 228394 | if( op!=SQLITE_INSERT ){ |
| 228201 | 228395 | /* This may fail if the column has a non-NULL default and was added |
| 228202 | 228396 | ** using ALTER TABLE ADD COLUMN after this record was created. */ |
| 228203 | | - rc = pSession->hook.xOld(pSession->hook.pCtx, i, &p); |
| 228397 | + rc = pSession->hook.xOld(pSession->hook.pCtx, iIdx, &p); |
| 228204 | 228398 | }else if( pTab->abPK[i] ){ |
| 228205 | | - TESTONLY(int trc = ) pSession->hook.xNew(pSession->hook.pCtx, i, &p); |
| 228399 | + TESTONLY(int trc = ) pSession->hook.xNew(pSession->hook.pCtx,iIdx,&p); |
| 228206 | 228400 | assert( trc==SQLITE_OK ); |
| 228207 | 228401 | } |
| 228208 | 228402 | |
| 228209 | 228403 | if( rc==SQLITE_OK ){ |
| 228210 | 228404 | /* This may fail if SQLite value p contains a utf-16 string that must |
| | @@ -228235,16 +228429,17 @@ |
| 228235 | 228429 | if( pTab->bRowid ){ |
| 228236 | 228430 | pC->aRecord[0] = SQLITE_INTEGER; |
| 228237 | 228431 | sessionPutI64(&pC->aRecord[1], iRowid); |
| 228238 | 228432 | nByte = 9; |
| 228239 | 228433 | } |
| 228240 | | - for(i=0; i<(pTab->nCol-pTab->bRowid); i++){ |
| 228434 | + for(i=pTab->bRowid; i<pTab->nCol; i++){ |
| 228241 | 228435 | sqlite3_value *p = 0; |
| 228436 | + int iIdx = pTab->aiIdx[i]; |
| 228242 | 228437 | if( op!=SQLITE_INSERT ){ |
| 228243 | | - pSession->hook.xOld(pSession->hook.pCtx, i, &p); |
| 228438 | + pSession->hook.xOld(pSession->hook.pCtx, iIdx, &p); |
| 228244 | 228439 | }else if( pTab->abPK[i] ){ |
| 228245 | | - pSession->hook.xNew(pSession->hook.pCtx, i, &p); |
| 228440 | + pSession->hook.xNew(pSession->hook.pCtx, iIdx, &p); |
| 228246 | 228441 | } |
| 228247 | 228442 | sessionSerializeValue(&pC->aRecord[nByte], p, &nByte); |
| 228248 | 228443 | } |
| 228249 | 228444 | |
| 228250 | 228445 | /* Add the change to the hash-table */ |
| | @@ -228642,11 +228837,12 @@ |
| 228642 | 228837 | int bMismatch = 0; |
| 228643 | 228838 | int nCol; /* Columns in zFrom.zTbl */ |
| 228644 | 228839 | int bRowid = 0; |
| 228645 | 228840 | u8 *abPK; |
| 228646 | 228841 | const char **azCol = 0; |
| 228647 | | - rc = sessionTableInfo(0, db, zFrom, zTbl, &nCol, 0, &azCol, 0, &abPK, |
| 228842 | + rc = sessionTableInfo(0, db, zFrom, zTbl, |
| 228843 | + &nCol, 0, 0, &azCol, 0, 0, &abPK, |
| 228648 | 228844 | pSession->bImplicitPK ? &bRowid : 0 |
| 228649 | 228845 | ); |
| 228650 | 228846 | if( rc==SQLITE_OK ){ |
| 228651 | 228847 | if( pTo->nCol!=nCol ){ |
| 228652 | 228848 | bMismatch = 1; |
| | @@ -229219,14 +229415,14 @@ |
| 229219 | 229415 | sqlite3_stmt **ppStmt /* OUT: Prepared SELECT statement */ |
| 229220 | 229416 | ){ |
| 229221 | 229417 | int rc = SQLITE_OK; |
| 229222 | 229418 | char *zSql = 0; |
| 229223 | 229419 | const char *zSep = ""; |
| 229224 | | - const char *zCols = bRowid ? SESSIONS_ROWID ", *" : "*"; |
| 229225 | 229420 | int nSql = -1; |
| 229226 | 229421 | int i; |
| 229227 | 229422 | |
| 229423 | + SessionBuffer cols = {0, 0, 0}; |
| 229228 | 229424 | SessionBuffer nooptest = {0, 0, 0}; |
| 229229 | 229425 | SessionBuffer pkfield = {0, 0, 0}; |
| 229230 | 229426 | SessionBuffer pkvar = {0, 0, 0}; |
| 229231 | 229427 | |
| 229232 | 229428 | sessionAppendStr(&nooptest, ", 1", &rc); |
| | @@ -229235,13 +229431,20 @@ |
| 229235 | 229431 | sessionAppendStr(&nooptest, " AND (?6 OR ?3 IS stat)", &rc); |
| 229236 | 229432 | sessionAppendStr(&pkfield, "tbl, idx", &rc); |
| 229237 | 229433 | sessionAppendStr(&pkvar, |
| 229238 | 229434 | "?1, (CASE WHEN ?2=X'' THEN NULL ELSE ?2 END)", &rc |
| 229239 | 229435 | ); |
| 229240 | | - zCols = "tbl, ?2, stat"; |
| 229436 | + sessionAppendStr(&cols, "tbl, ?2, stat", &rc); |
| 229241 | 229437 | }else{ |
| 229438 | + #if 0 |
| 229439 | + if( bRowid ){ |
| 229440 | + sessionAppendStr(&cols, SESSIONS_ROWID, &rc); |
| 229441 | + } |
| 229442 | + #endif |
| 229242 | 229443 | for(i=0; i<nCol; i++){ |
| 229444 | + if( cols.nBuf ) sessionAppendStr(&cols, ", ", &rc); |
| 229445 | + sessionAppendIdent(&cols, azCol[i], &rc); |
| 229243 | 229446 | if( abPK[i] ){ |
| 229244 | 229447 | sessionAppendStr(&pkfield, zSep, &rc); |
| 229245 | 229448 | sessionAppendStr(&pkvar, zSep, &rc); |
| 229246 | 229449 | zSep = ", "; |
| 229247 | 229450 | sessionAppendIdent(&pkfield, azCol[i], &rc); |
| | @@ -229255,11 +229458,11 @@ |
| 229255 | 229458 | } |
| 229256 | 229459 | |
| 229257 | 229460 | if( rc==SQLITE_OK ){ |
| 229258 | 229461 | zSql = sqlite3_mprintf( |
| 229259 | 229462 | "SELECT %s%s FROM %Q.%Q WHERE (%s) IS (%s)", |
| 229260 | | - zCols, (bIgnoreNoop ? (char*)nooptest.aBuf : ""), |
| 229463 | + (char*)cols.aBuf, (bIgnoreNoop ? (char*)nooptest.aBuf : ""), |
| 229261 | 229464 | zDb, zTab, (char*)pkfield.aBuf, (char*)pkvar.aBuf |
| 229262 | 229465 | ); |
| 229263 | 229466 | if( zSql==0 ) rc = SQLITE_NOMEM; |
| 229264 | 229467 | } |
| 229265 | 229468 | |
| | @@ -229298,10 +229501,11 @@ |
| 229298 | 229501 | } |
| 229299 | 229502 | sqlite3_free(zSql); |
| 229300 | 229503 | sqlite3_free(nooptest.aBuf); |
| 229301 | 229504 | sqlite3_free(pkfield.aBuf); |
| 229302 | 229505 | sqlite3_free(pkvar.aBuf); |
| 229506 | + sqlite3_free(cols.aBuf); |
| 229303 | 229507 | return rc; |
| 229304 | 229508 | } |
| 229305 | 229509 | |
| 229306 | 229510 | /* |
| 229307 | 229511 | ** Bind the PRIMARY KEY values from the change passed in argument pChange |
| | @@ -231638,11 +231842,12 @@ |
| 231638 | 231842 | int nMinCol = 0; |
| 231639 | 231843 | int i; |
| 231640 | 231844 | |
| 231641 | 231845 | sqlite3changeset_pk(pIter, &abPK, 0); |
| 231642 | 231846 | rc = sessionTableInfo(0, db, "main", zNew, |
| 231643 | | - &sApply.nCol, &zTab, &sApply.azCol, 0, &sApply.abPK, &sApply.bRowid |
| 231847 | + &sApply.nCol, 0, &zTab, &sApply.azCol, 0, 0, |
| 231848 | + &sApply.abPK, &sApply.bRowid |
| 231644 | 231849 | ); |
| 231645 | 231850 | if( rc!=SQLITE_OK ) break; |
| 231646 | 231851 | for(i=0; i<sApply.nCol; i++){ |
| 231647 | 231852 | if( sApply.abPK[i] ) nMinCol = i+1; |
| 231648 | 231853 | } |
| | @@ -231718,10 +231923,15 @@ |
| 231718 | 231923 | if( res!=SQLITE_CHANGESET_OMIT ){ |
| 231719 | 231924 | rc = SQLITE_CONSTRAINT; |
| 231720 | 231925 | } |
| 231721 | 231926 | } |
| 231722 | 231927 | } |
| 231928 | + |
| 231929 | + { |
| 231930 | + int rc2 = sqlite3_exec(db, "PRAGMA defer_foreign_keys = 0", 0, 0, 0); |
| 231931 | + if( rc==SQLITE_OK ) rc = rc2; |
| 231932 | + } |
| 231723 | 231933 | |
| 231724 | 231934 | if( (flags & SQLITE_CHANGESETAPPLY_NOSAVEPOINT)==0 ){ |
| 231725 | 231935 | if( rc==SQLITE_OK ){ |
| 231726 | 231936 | rc = sqlite3_exec(db, "RELEASE changeset_apply", 0, 0, 0); |
| 231727 | 231937 | } |
| | @@ -243230,15 +243440,17 @@ |
| 243230 | 243440 | } |
| 243231 | 243441 | |
| 243232 | 243442 | /* |
| 243233 | 243443 | ** Close the read-only blob handle, if it is open. |
| 243234 | 243444 | */ |
| 243235 | | -static void sqlite3Fts5IndexCloseReader(Fts5Index *p){ |
| 243445 | +static void fts5IndexCloseReader(Fts5Index *p){ |
| 243236 | 243446 | if( p->pReader ){ |
| 243447 | + int rc; |
| 243237 | 243448 | sqlite3_blob *pReader = p->pReader; |
| 243238 | 243449 | p->pReader = 0; |
| 243239 | | - sqlite3_blob_close(pReader); |
| 243450 | + rc = sqlite3_blob_close(pReader); |
| 243451 | + if( p->rc==SQLITE_OK ) p->rc = rc; |
| 243240 | 243452 | } |
| 243241 | 243453 | } |
| 243242 | 243454 | |
| 243243 | 243455 | /* |
| 243244 | 243456 | ** Retrieve a record from the %_data table. |
| | @@ -243259,11 +243471,11 @@ |
| 243259 | 243471 | p->pReader = 0; |
| 243260 | 243472 | rc = sqlite3_blob_reopen(pBlob, iRowid); |
| 243261 | 243473 | assert( p->pReader==0 ); |
| 243262 | 243474 | p->pReader = pBlob; |
| 243263 | 243475 | if( rc!=SQLITE_OK ){ |
| 243264 | | - sqlite3Fts5IndexCloseReader(p); |
| 243476 | + fts5IndexCloseReader(p); |
| 243265 | 243477 | } |
| 243266 | 243478 | if( rc==SQLITE_ABORT ) rc = SQLITE_OK; |
| 243267 | 243479 | } |
| 243268 | 243480 | |
| 243269 | 243481 | /* If the blob handle is not open at this point, open it and seek |
| | @@ -247460,10 +247672,18 @@ |
| 247460 | 247672 | static int fts5IndexReturn(Fts5Index *p){ |
| 247461 | 247673 | int rc = p->rc; |
| 247462 | 247674 | p->rc = SQLITE_OK; |
| 247463 | 247675 | return rc; |
| 247464 | 247676 | } |
| 247677 | + |
| 247678 | +/* |
| 247679 | +** Close the read-only blob handle, if it is open. |
| 247680 | +*/ |
| 247681 | +static void sqlite3Fts5IndexCloseReader(Fts5Index *p){ |
| 247682 | + fts5IndexCloseReader(p); |
| 247683 | + fts5IndexReturn(p); |
| 247684 | +} |
| 247465 | 247685 | |
| 247466 | 247686 | typedef struct Fts5FlushCtx Fts5FlushCtx; |
| 247467 | 247687 | struct Fts5FlushCtx { |
| 247468 | 247688 | Fts5Index *pIdx; |
| 247469 | 247689 | Fts5SegWriter writer; |
| | @@ -249182,11 +249402,11 @@ |
| 249182 | 249402 | ** Commit data to disk. |
| 249183 | 249403 | */ |
| 249184 | 249404 | static int sqlite3Fts5IndexSync(Fts5Index *p){ |
| 249185 | 249405 | assert( p->rc==SQLITE_OK ); |
| 249186 | 249406 | fts5IndexFlush(p); |
| 249187 | | - sqlite3Fts5IndexCloseReader(p); |
| 249407 | + fts5IndexCloseReader(p); |
| 249188 | 249408 | return fts5IndexReturn(p); |
| 249189 | 249409 | } |
| 249190 | 249410 | |
| 249191 | 249411 | /* |
| 249192 | 249412 | ** Discard any data stored in the in-memory hash tables. Do not write it |
| | @@ -249193,15 +249413,14 @@ |
| 249193 | 249413 | ** to the database. Additionally, assume that the contents of the %_data |
| 249194 | 249414 | ** table may have changed on disk. So any in-memory caches of %_data |
| 249195 | 249415 | ** records must be invalidated. |
| 249196 | 249416 | */ |
| 249197 | 249417 | static int sqlite3Fts5IndexRollback(Fts5Index *p){ |
| 249198 | | - sqlite3Fts5IndexCloseReader(p); |
| 249418 | + fts5IndexCloseReader(p); |
| 249199 | 249419 | fts5IndexDiscardData(p); |
| 249200 | 249420 | fts5StructureInvalidate(p); |
| 249201 | | - /* assert( p->rc==SQLITE_OK ); */ |
| 249202 | | - return SQLITE_OK; |
| 249421 | + return fts5IndexReturn(p); |
| 249203 | 249422 | } |
| 249204 | 249423 | |
| 249205 | 249424 | /* |
| 249206 | 249425 | ** The %_data table is completely empty when this function is called. This |
| 249207 | 249426 | ** function populates it with the initial structure objects for each index, |
| | @@ -249397,10 +249616,20 @@ |
| 249397 | 249616 | */ |
| 249398 | 249617 | static void fts5SegIterSetEOF(Fts5SegIter *pSeg){ |
| 249399 | 249618 | fts5DataRelease(pSeg->pLeaf); |
| 249400 | 249619 | pSeg->pLeaf = 0; |
| 249401 | 249620 | } |
| 249621 | + |
| 249622 | +static void fts5IterClose(Fts5IndexIter *pIndexIter){ |
| 249623 | + if( pIndexIter ){ |
| 249624 | + Fts5Iter *pIter = (Fts5Iter*)pIndexIter; |
| 249625 | + Fts5Index *pIndex = pIter->pIndex; |
| 249626 | + fts5TokendataIterDelete(pIter->pTokenDataIter); |
| 249627 | + fts5MultiIterFree(pIter); |
| 249628 | + fts5IndexCloseReader(pIndex); |
| 249629 | + } |
| 249630 | +} |
| 249402 | 249631 | |
| 249403 | 249632 | /* |
| 249404 | 249633 | ** This function appends iterator pAppend to Fts5TokenDataIter pIn and |
| 249405 | 249634 | ** returns the result. |
| 249406 | 249635 | */ |
| | @@ -249425,11 +249654,11 @@ |
| 249425 | 249654 | pNew->nIterAlloc = nAlloc; |
| 249426 | 249655 | } |
| 249427 | 249656 | } |
| 249428 | 249657 | } |
| 249429 | 249658 | if( p->rc ){ |
| 249430 | | - sqlite3Fts5IterClose((Fts5IndexIter*)pAppend); |
| 249659 | + fts5IterClose((Fts5IndexIter*)pAppend); |
| 249431 | 249660 | }else{ |
| 249432 | 249661 | pRet->apIter[pRet->nIter++] = pAppend; |
| 249433 | 249662 | } |
| 249434 | 249663 | assert( pRet==0 || pRet->nIter<=pRet->nIterAlloc ); |
| 249435 | 249664 | |
| | @@ -249638,11 +249867,11 @@ |
| 249638 | 249867 | fts5BufferAppendBlob(&p->rc, &bSeek, 1, (const u8*)"\0"); |
| 249639 | 249868 | }else{ |
| 249640 | 249869 | fts5BufferSet(&p->rc, &bSeek, nToken, pToken); |
| 249641 | 249870 | } |
| 249642 | 249871 | if( p->rc ){ |
| 249643 | | - sqlite3Fts5IterClose((Fts5IndexIter*)pNew); |
| 249872 | + fts5IterClose((Fts5IndexIter*)pNew); |
| 249644 | 249873 | break; |
| 249645 | 249874 | } |
| 249646 | 249875 | |
| 249647 | 249876 | pNewIter = &pNew->aSeg[0]; |
| 249648 | 249877 | pPrevIter = (pPrev ? &pPrev->aSeg[0] : 0); |
| | @@ -249703,11 +249932,11 @@ |
| 249703 | 249932 | |
| 249704 | 249933 | /* If pSmall is still NULL at this point, then the new iterator does |
| 249705 | 249934 | ** not point to any terms that match the query. So delete it and break |
| 249706 | 249935 | ** out of the loop - all required iterators have been collected. */ |
| 249707 | 249936 | if( pSmall==0 ){ |
| 249708 | | - sqlite3Fts5IterClose((Fts5IndexIter*)pNew); |
| 249937 | + fts5IterClose((Fts5IndexIter*)pNew); |
| 249709 | 249938 | break; |
| 249710 | 249939 | } |
| 249711 | 249940 | |
| 249712 | 249941 | /* Append this iterator to the set and continue. */ |
| 249713 | 249942 | pSet = fts5AppendTokendataIter(p, pSet, pNew); |
| | @@ -249832,13 +250061,13 @@ |
| 249832 | 250061 | } |
| 249833 | 250062 | } |
| 249834 | 250063 | } |
| 249835 | 250064 | |
| 249836 | 250065 | if( p->rc ){ |
| 249837 | | - sqlite3Fts5IterClose((Fts5IndexIter*)pRet); |
| 250066 | + fts5IterClose((Fts5IndexIter*)pRet); |
| 249838 | 250067 | pRet = 0; |
| 249839 | | - sqlite3Fts5IndexCloseReader(p); |
| 250068 | + fts5IndexCloseReader(p); |
| 249840 | 250069 | } |
| 249841 | 250070 | |
| 249842 | 250071 | *ppIter = (Fts5IndexIter*)pRet; |
| 249843 | 250072 | sqlite3Fts5BufferFree(&buf); |
| 249844 | 250073 | } |
| | @@ -250084,15 +250313,13 @@ |
| 250084 | 250313 | /* |
| 250085 | 250314 | ** Close an iterator opened by an earlier call to sqlite3Fts5IndexQuery(). |
| 250086 | 250315 | */ |
| 250087 | 250316 | static void sqlite3Fts5IterClose(Fts5IndexIter *pIndexIter){ |
| 250088 | 250317 | if( pIndexIter ){ |
| 250089 | | - Fts5Iter *pIter = (Fts5Iter*)pIndexIter; |
| 250090 | | - Fts5Index *pIndex = pIter->pIndex; |
| 250091 | | - fts5TokendataIterDelete(pIter->pTokenDataIter); |
| 250092 | | - fts5MultiIterFree(pIter); |
| 250093 | | - sqlite3Fts5IndexCloseReader(pIndex); |
| 250318 | + Fts5Index *pIndex = ((Fts5Iter*)pIndexIter)->pIndex; |
| 250319 | + fts5IterClose(pIndexIter); |
| 250320 | + fts5IndexReturn(pIndex); |
| 250094 | 250321 | } |
| 250095 | 250322 | } |
| 250096 | 250323 | |
| 250097 | 250324 | /* |
| 250098 | 250325 | ** Read and decode the "averages" record from the database. |
| | @@ -250618,11 +250845,11 @@ |
| 250618 | 250845 | } |
| 250619 | 250846 | if( rc==SQLITE_OK ){ |
| 250620 | 250847 | rc = sqlite3Fts5IterNext(pIter); |
| 250621 | 250848 | } |
| 250622 | 250849 | } |
| 250623 | | - sqlite3Fts5IterClose(pIter); |
| 250850 | + fts5IterClose(pIter); |
| 250624 | 250851 | |
| 250625 | 250852 | *pCksum = cksum; |
| 250626 | 250853 | return rc; |
| 250627 | 250854 | } |
| 250628 | 250855 | |
| | @@ -255462,11 +255689,11 @@ |
| 255462 | 255689 | int nArg, /* Number of args */ |
| 255463 | 255690 | sqlite3_value **apUnused /* Function arguments */ |
| 255464 | 255691 | ){ |
| 255465 | 255692 | assert( nArg==0 ); |
| 255466 | 255693 | UNUSED_PARAM2(nArg, apUnused); |
| 255467 | | - sqlite3_result_text(pCtx, "fts5: 2025-01-14 11:05:00 d2fe6b05f38d9d7cd78c5d252e99ac59f1aea071d669830c1ffe4e8966e84010", -1, SQLITE_TRANSIENT); |
| 255694 | + sqlite3_result_text(pCtx, "fts5: 2025-01-29 18:53:19 d7c07581203a0a88456588e49e51b40a8341b0e7121809f75be0ee882d91650f", -1, SQLITE_TRANSIENT); |
| 255468 | 255695 | } |
| 255469 | 255696 | |
| 255470 | 255697 | /* |
| 255471 | 255698 | ** Implementation of fts5_locale(LOCALE, TEXT) function. |
| 255472 | 255699 | ** |
| 255473 | 255700 | |