| | @@ -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 | | -** c476d956d0bd3065cf894de6f9d393b999ff with changes in files: |
| 21 | +** b67889e4f17c3280f839ee7045256cc47d6c with changes in files: |
| 22 | 22 | ** |
| 23 | 23 | ** |
| 24 | 24 | */ |
| 25 | 25 | #ifndef SQLITE_AMALGAMATION |
| 26 | 26 | #define SQLITE_CORE 1 |
| | @@ -467,14 +467,14 @@ |
| 467 | 467 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 468 | 468 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 469 | 469 | */ |
| 470 | 470 | #define SQLITE_VERSION "3.52.0" |
| 471 | 471 | #define SQLITE_VERSION_NUMBER 3052000 |
| 472 | | -#define SQLITE_SOURCE_ID "2026-02-04 20:51:27 c476d956d0bd3065cf894de6f9d393b999ff7d2268a35f01a6d88804789ab58f" |
| 472 | +#define SQLITE_SOURCE_ID "2026-02-10 19:33:11 b67889e4f17c3280f839ee7045256cc47d6ce3ed60d880925e3d30f9ebbcf3ff" |
| 473 | 473 | #define SQLITE_SCM_BRANCH "trunk" |
| 474 | 474 | #define SQLITE_SCM_TAGS "" |
| 475 | | -#define SQLITE_SCM_DATETIME "2026-02-04T20:51:27.822Z" |
| 475 | +#define SQLITE_SCM_DATETIME "2026-02-10T19:33:11.305Z" |
| 476 | 476 | |
| 477 | 477 | /* |
| 478 | 478 | ** CAPI3REF: Run-Time Library Version Numbers |
| 479 | 479 | ** KEYWORDS: sqlite3_version sqlite3_sourceid |
| 480 | 480 | ** |
| | @@ -20359,11 +20359,11 @@ |
| 20359 | 20359 | #define SF_Distinct 0x0000001 /* Output should be DISTINCT */ |
| 20360 | 20360 | #define SF_All 0x0000002 /* Includes the ALL keyword */ |
| 20361 | 20361 | #define SF_Resolved 0x0000004 /* Identifiers have been resolved */ |
| 20362 | 20362 | #define SF_Aggregate 0x0000008 /* Contains agg functions or a GROUP BY */ |
| 20363 | 20363 | #define SF_HasAgg 0x0000010 /* Contains aggregate functions */ |
| 20364 | | -/* 0x0000020 // available for reuse */ |
| 20364 | +#define SF_ClonedRhsIn 0x0000020 /* Cloned RHS of an IN operator */ |
| 20365 | 20365 | #define SF_Expanded 0x0000040 /* sqlite3SelectExpand() called on this */ |
| 20366 | 20366 | #define SF_HasTypeInfo 0x0000080 /* FROM subqueries have Table metadata */ |
| 20367 | 20367 | #define SF_Compound 0x0000100 /* Part of a compound query */ |
| 20368 | 20368 | #define SF_Values 0x0000200 /* Synthesized from VALUES clause */ |
| 20369 | 20369 | #define SF_MultiValue 0x0000400 /* Single VALUES term with multiple rows */ |
| | @@ -22174,11 +22174,11 @@ |
| 22174 | 22174 | SQLITE_PRIVATE void sqlite3AlterAddConstraint(Parse*,SrcList*,Token*,Token*,const char*,int); |
| 22175 | 22175 | SQLITE_PRIVATE void sqlite3AlterSetNotNull(Parse*, SrcList*, Token*, Token*); |
| 22176 | 22176 | SQLITE_PRIVATE i64 sqlite3GetToken(const unsigned char *, int *); |
| 22177 | 22177 | SQLITE_PRIVATE void sqlite3NestedParse(Parse*, const char*, ...); |
| 22178 | 22178 | SQLITE_PRIVATE void sqlite3ExpirePreparedStatements(sqlite3*, int); |
| 22179 | | -SQLITE_PRIVATE void sqlite3CodeRhsOfIN(Parse*, Expr*, int); |
| 22179 | +SQLITE_PRIVATE void sqlite3CodeRhsOfIN(Parse*, Expr*, int, int); |
| 22180 | 22180 | SQLITE_PRIVATE int sqlite3CodeSubselect(Parse*, Expr*); |
| 22181 | 22181 | SQLITE_PRIVATE void sqlite3SelectPrep(Parse*, Select*, NameContext*); |
| 22182 | 22182 | SQLITE_PRIVATE int sqlite3ExpandSubquery(Parse*, SrcItem*); |
| 22183 | 22183 | SQLITE_PRIVATE void sqlite3SelectWrongNumTermsError(Parse *pParse, Select *p); |
| 22184 | 22184 | SQLITE_PRIVATE int sqlite3MatchEName( |
| | @@ -34928,11 +34928,17 @@ |
| 34928 | 34928 | ** sqlite3ShowWhereTerm() in where.c |
| 34929 | 34929 | */ |
| 34930 | 34930 | SQLITE_PRIVATE void sqlite3ShowExpr(const Expr *p){ sqlite3TreeViewExpr(0,p,0); } |
| 34931 | 34931 | SQLITE_PRIVATE void sqlite3ShowExprList(const ExprList *p){ sqlite3TreeViewExprList(0,p,0,0);} |
| 34932 | 34932 | SQLITE_PRIVATE void sqlite3ShowIdList(const IdList *p){ sqlite3TreeViewIdList(0,p,0,0); } |
| 34933 | | -SQLITE_PRIVATE void sqlite3ShowSrcList(const SrcList *p){ sqlite3TreeViewSrcList(0,p); } |
| 34933 | +SQLITE_PRIVATE void sqlite3ShowSrcList(const SrcList *p){ |
| 34934 | + TreeView *pView = 0; |
| 34935 | + sqlite3TreeViewPush(&pView, 0); |
| 34936 | + sqlite3TreeViewLine(pView, "SRCLIST"); |
| 34937 | + sqlite3TreeViewSrcList(pView,p); |
| 34938 | + sqlite3TreeViewPop(&pView); |
| 34939 | +} |
| 34934 | 34940 | SQLITE_PRIVATE void sqlite3ShowSelect(const Select *p){ sqlite3TreeViewSelect(0,p,0); } |
| 34935 | 34941 | SQLITE_PRIVATE void sqlite3ShowWith(const With *p){ sqlite3TreeViewWith(0,p,0); } |
| 34936 | 34942 | SQLITE_PRIVATE void sqlite3ShowUpsert(const Upsert *p){ sqlite3TreeViewUpsert(0,p,0); } |
| 34937 | 34943 | #ifndef SQLITE_OMIT_TRIGGER |
| 34938 | 34944 | SQLITE_PRIVATE void sqlite3ShowTriggerStep(const TriggerStep *p){ |
| | @@ -114883,18 +114889,25 @@ |
| 114883 | 114889 | /* Could not find an existing table or index to use as the RHS b-tree. |
| 114884 | 114890 | ** We will have to generate an ephemeral table to do the job. |
| 114885 | 114891 | */ |
| 114886 | 114892 | u32 savedNQueryLoop = pParse->nQueryLoop; |
| 114887 | 114893 | int rMayHaveNull = 0; |
| 114894 | + int bloomOk = (inFlags & IN_INDEX_MEMBERSHIP)!=0; |
| 114888 | 114895 | eType = IN_INDEX_EPH; |
| 114889 | 114896 | if( inFlags & IN_INDEX_LOOP ){ |
| 114890 | 114897 | pParse->nQueryLoop = 0; |
| 114891 | 114898 | }else if( prRhsHasNull ){ |
| 114892 | 114899 | *prRhsHasNull = rMayHaveNull = ++pParse->nMem; |
| 114893 | 114900 | } |
| 114894 | 114901 | assert( pX->op==TK_IN ); |
| 114895 | | - sqlite3CodeRhsOfIN(pParse, pX, iTab); |
| 114902 | + if( !bloomOk |
| 114903 | + && ExprUseXSelect(pX) |
| 114904 | + && (pX->x.pSelect->selFlags & SF_ClonedRhsIn)!=0 |
| 114905 | + ){ |
| 114906 | + bloomOk = 1; |
| 114907 | + } |
| 114908 | + sqlite3CodeRhsOfIN(pParse, pX, iTab, bloomOk); |
| 114896 | 114909 | if( rMayHaveNull ){ |
| 114897 | 114910 | sqlite3SetHasNullFlag(v, iTab, rMayHaveNull); |
| 114898 | 114911 | } |
| 114899 | 114912 | pParse->nQueryLoop = savedNQueryLoop; |
| 114900 | 114913 | } |
| | @@ -115048,11 +115061,12 @@ |
| 115048 | 115061 | ** is used. |
| 115049 | 115062 | */ |
| 115050 | 115063 | SQLITE_PRIVATE void sqlite3CodeRhsOfIN( |
| 115051 | 115064 | Parse *pParse, /* Parsing context */ |
| 115052 | 115065 | Expr *pExpr, /* The IN operator */ |
| 115053 | | - int iTab /* Use this cursor number */ |
| 115066 | + int iTab, /* Use this cursor number */ |
| 115067 | + int allowBloom /* True to allow the use of a Bloom filter */ |
| 115054 | 115068 | ){ |
| 115055 | 115069 | int addrOnce = 0; /* Address of the OP_Once instruction at top */ |
| 115056 | 115070 | int addr; /* Address of OP_OpenEphemeral instruction */ |
| 115057 | 115071 | Expr *pLeft; /* the LHS of the IN operator */ |
| 115058 | 115072 | KeyInfo *pKeyInfo = 0; /* Key information */ |
| | @@ -115170,11 +115184,14 @@ |
| 115170 | 115184 | int rc; |
| 115171 | 115185 | int addrBloom = 0; |
| 115172 | 115186 | sqlite3SelectDestInit(&dest, SRT_Set, iTab); |
| 115173 | 115187 | dest.zAffSdst = exprINAffinity(pParse, pExpr); |
| 115174 | 115188 | pSelect->iLimit = 0; |
| 115175 | | - if( addrOnce && OptimizationEnabled(pParse->db, SQLITE_BloomFilter) ){ |
| 115189 | + if( addrOnce |
| 115190 | + && allowBloom |
| 115191 | + && OptimizationEnabled(pParse->db, SQLITE_BloomFilter) |
| 115192 | + ){ |
| 115176 | 115193 | int regBloom = ++pParse->nMem; |
| 115177 | 115194 | addrBloom = sqlite3VdbeAddOp2(v, OP_Blob, 10000, regBloom); |
| 115178 | 115195 | VdbeComment((v, "Bloom filter")); |
| 115179 | 115196 | dest.iSDParm2 = regBloom; |
| 115180 | 115197 | } |
| | @@ -124934,11 +124951,11 @@ |
| 124934 | 124951 | if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; |
| 124935 | 124952 | #endif |
| 124936 | 124953 | sqlite3_mutex_enter(db->mutex); |
| 124937 | 124954 | db->xAuth = (sqlite3_xauth)xAuth; |
| 124938 | 124955 | db->pAuthArg = pArg; |
| 124939 | | - if( db->xAuth ) sqlite3ExpirePreparedStatements(db, 1); |
| 124956 | + sqlite3ExpirePreparedStatements(db, 1); |
| 124940 | 124957 | sqlite3_mutex_leave(db->mutex); |
| 124941 | 124958 | return SQLITE_OK; |
| 124942 | 124959 | } |
| 124943 | 124960 | |
| 124944 | 124961 | /* |
| | @@ -148217,10 +148234,14 @@ |
| 148217 | 148234 | p->pWhere = sqlite3ExprAnd(pParse, p->pWhere, pRight->u3.pOn); |
| 148218 | 148235 | pRight->u3.pOn = 0; |
| 148219 | 148236 | pRight->fg.isOn = 1; |
| 148220 | 148237 | p->selFlags |= SF_OnToWhere; |
| 148221 | 148238 | } |
| 148239 | + |
| 148240 | + if( IsVirtual(pRightTab) && joinType==EP_OuterON && pRight->u1.pFuncArg ){ |
| 148241 | + p->selFlags |= SF_OnToWhere; |
| 148242 | + } |
| 148222 | 148243 | } |
| 148223 | 148244 | return 0; |
| 148224 | 148245 | } |
| 148225 | 148246 | |
| 148226 | 148247 | /* |
| | @@ -152828,10 +152849,20 @@ |
| 152828 | 152849 | x.isOuterJoin = 0; |
| 152829 | 152850 | x.nSelDepth = 0; |
| 152830 | 152851 | x.pEList = pSubq->pEList; |
| 152831 | 152852 | x.pCList = findLeftmostExprlist(pSubq); |
| 152832 | 152853 | pNew = substExpr(&x, pNew); |
| 152854 | + assert( pNew!=0 || pParse->nErr!=0 ); |
| 152855 | + if( pParse->nErr==0 && pNew->op==TK_IN && ExprUseXSelect(pNew) ){ |
| 152856 | + assert( pNew->x.pSelect!=0 ); |
| 152857 | + pNew->x.pSelect->selFlags |= SF_ClonedRhsIn; |
| 152858 | + assert( pWhere!=0 ); |
| 152859 | + assert( pWhere->op==TK_IN ); |
| 152860 | + assert( ExprUseXSelect(pWhere) ); |
| 152861 | + assert( pWhere->x.pSelect!=0 ); |
| 152862 | + pWhere->x.pSelect->selFlags |= SF_ClonedRhsIn; |
| 152863 | + } |
| 152833 | 152864 | #ifndef SQLITE_OMIT_WINDOWFUNC |
| 152834 | 152865 | if( pSubq->pWin && 0==pushDownWindowCheck(pParse, pSubq, pNew) ){ |
| 152835 | 152866 | /* Restriction 6c has prevented push-down in this case */ |
| 152836 | 152867 | sqlite3ExprDelete(pParse->db, pNew); |
| 152837 | 152868 | nChng--; |
| | @@ -154946,10 +154977,11 @@ |
| 154946 | 154977 | */ |
| 154947 | 154978 | typedef struct CheckOnCtx CheckOnCtx; |
| 154948 | 154979 | struct CheckOnCtx { |
| 154949 | 154980 | SrcList *pSrc; /* SrcList for this context */ |
| 154950 | 154981 | int iJoin; /* Cursor numbers must be =< than this */ |
| 154982 | + int bFuncArg; /* True for table-function arg */ |
| 154951 | 154983 | CheckOnCtx *pParent; /* Parent context */ |
| 154952 | 154984 | }; |
| 154953 | 154985 | |
| 154954 | 154986 | /* |
| 154955 | 154987 | ** True if the SrcList passed as the only argument contains at least |
| | @@ -154997,11 +155029,13 @@ |
| 154997 | 155029 | SrcList *pSrc = pCtx->pSrc; |
| 154998 | 155030 | int iTab = pExpr->iTable; |
| 154999 | 155031 | if( iTab>=pSrc->a[0].iCursor && iTab<=pSrc->a[pSrc->nSrc-1].iCursor ){ |
| 155000 | 155032 | if( pCtx->iJoin && iTab>pCtx->iJoin ){ |
| 155001 | 155033 | sqlite3ErrorMsg(pWalker->pParse, |
| 155002 | | - "ON clause references tables to its right"); |
| 155034 | + "%s references tables to its right", |
| 155035 | + (pCtx->bFuncArg ? "table-function argument" : "ON clause") |
| 155036 | + ); |
| 155003 | 155037 | return WRC_Abort; |
| 155004 | 155038 | } |
| 155005 | 155039 | break; |
| 155006 | 155040 | } |
| 155007 | 155041 | pCtx = pCtx->pParent; |
| | @@ -155035,21 +155069,36 @@ |
| 155035 | 155069 | ** columns to the right. |
| 155036 | 155070 | */ |
| 155037 | 155071 | static void selectCheckOnClauses(Parse *pParse, Select *pSelect){ |
| 155038 | 155072 | Walker w; |
| 155039 | 155073 | CheckOnCtx sCtx; |
| 155074 | + int ii; |
| 155040 | 155075 | assert( pSelect->selFlags & SF_OnToWhere ); |
| 155041 | 155076 | assert( pSelect->pSrc!=0 && pSelect->pSrc->nSrc>=2 ); |
| 155042 | 155077 | memset(&w, 0, sizeof(w)); |
| 155043 | 155078 | w.pParse = pParse; |
| 155044 | 155079 | w.xExprCallback = selectCheckOnClausesExpr; |
| 155045 | 155080 | w.xSelectCallback = selectCheckOnClausesSelect; |
| 155046 | 155081 | w.u.pCheckOnCtx = &sCtx; |
| 155047 | 155082 | memset(&sCtx, 0, sizeof(sCtx)); |
| 155048 | 155083 | sCtx.pSrc = pSelect->pSrc; |
| 155049 | | - sqlite3WalkExprNN(&w, pSelect->pWhere); |
| 155084 | + sqlite3WalkExpr(&w, pSelect->pWhere); |
| 155050 | 155085 | pSelect->selFlags &= ~SF_OnToWhere; |
| 155086 | + |
| 155087 | + /* Check for any table-function args that are attached to virtual tables |
| 155088 | + ** on the RHS of an outer join. They are subject to the same constraints |
| 155089 | + ** as ON clauses. */ |
| 155090 | + sCtx.bFuncArg = 1; |
| 155091 | + for(ii=0; ii<pSelect->pSrc->nSrc; ii++){ |
| 155092 | + SrcItem *pItem = &pSelect->pSrc->a[ii]; |
| 155093 | + if( pItem->fg.isTabFunc |
| 155094 | + && (pItem->fg.jointype & JT_OUTER) |
| 155095 | + ){ |
| 155096 | + sCtx.iJoin = pItem->iCursor; |
| 155097 | + sqlite3WalkExprList(&w, pItem->u1.pFuncArg); |
| 155098 | + } |
| 155099 | + } |
| 155051 | 155100 | } |
| 155052 | 155101 | |
| 155053 | 155102 | /* |
| 155054 | 155103 | ** If p2 exists and p1 and p2 have the same number of terms, then change |
| 155055 | 155104 | ** every term of p1 to have the same sort order as p2 and return true. |
| | @@ -164043,11 +164092,11 @@ |
| 164043 | 164092 | if( NEVER(pTerm==0) ) continue; |
| 164044 | 164093 | if( pTerm->eOperator & WO_IN ){ |
| 164045 | 164094 | if( SMASKBIT32(j) & pLoop->u.vtab.mHandleIn ){ |
| 164046 | 164095 | int iTab = pParse->nTab++; |
| 164047 | 164096 | int iCache = ++pParse->nMem; |
| 164048 | | - sqlite3CodeRhsOfIN(pParse, pTerm->pExpr, iTab); |
| 164097 | + sqlite3CodeRhsOfIN(pParse, pTerm->pExpr, iTab, 0); |
| 164049 | 164098 | sqlite3VdbeAddOp3(v, OP_VInitIn, iTab, iTarget, iCache); |
| 164050 | 164099 | }else{ |
| 164051 | 164100 | codeEqualityTerm(pParse, pTerm, pLevel, j, bRev, iTarget); |
| 164052 | 164101 | addrNotFound = pLevel->addrNxt; |
| 164053 | 164102 | } |
| | @@ -172943,16 +172992,25 @@ |
| 172943 | 172992 | ** |
| 172944 | 172993 | ** 18 for star queries |
| 172945 | 172994 | ** 12 otherwise |
| 172946 | 172995 | ** |
| 172947 | 172996 | ** For the purposes of this heuristic, a star-query is defined as a query |
| 172948 | | -** with a large central table that is joined using an INNER JOIN, |
| 172949 | | -** not CROSS or OUTER JOINs, against four or more smaller tables. |
| 172950 | | -** The central table is called the "fact" table. The smaller tables |
| 172951 | | -** that get joined are "dimension tables". Also, any table that is |
| 172952 | | -** self-joined cannot be a dimension table; we assume that dimension |
| 172953 | | -** tables may only be joined against fact tables. |
| 172997 | +** with a central "fact" table that is joined against multiple |
| 172998 | +** "dimension" tables, subject to the following constraints: |
| 172999 | +** |
| 173000 | +** (aa) Only a five-way or larger join is considered for this |
| 173001 | +** optimization. If there are fewer than four terms in the FROM |
| 173002 | +** clause, this heuristic does not apply. |
| 173003 | +** |
| 173004 | +** (bb) The join between the fact table and the dimension tables must |
| 173005 | +** be an INNER join. CROSS and OUTER JOINs do not qualify. |
| 173006 | +** |
| 173007 | +** (cc) A table must have 3 or more dimension tables in order to be |
| 173008 | +** considered a fact table. (Was 4 prior to 2026-02-10.) |
| 173009 | +** |
| 173010 | +** (dd) A table that is a self-join cannot be a dimension table. |
| 173011 | +** Dimension tables are joined against fact tables. |
| 172954 | 173012 | ** |
| 172955 | 173013 | ** SIDE EFFECT: (and really the whole point of this subroutine) |
| 172956 | 173014 | ** |
| 172957 | 173015 | ** If pWInfo describes a star-query, then the cost for SCANs of dimension |
| 172958 | 173016 | ** WhereLoops is increased to be slightly larger than the cost of a SCAN |
| | @@ -173001,11 +173059,11 @@ |
| 173001 | 173059 | assert( pWLoop->maskSelf==MASKBIT(pWLoop->iTab) ); |
| 173002 | 173060 | assert( pWLoop->pNextLoop==0 || pWLoop->iTab<=pWLoop->pNextLoop->iTab ); |
| 173003 | 173061 | } |
| 173004 | 173062 | #endif /* SQLITE_DEBUG */ |
| 173005 | 173063 | |
| 173006 | | - if( nLoop>=5 |
| 173064 | + if( nLoop>=4 /* Constraint (aa) */ |
| 173007 | 173065 | && !pWInfo->bStarDone |
| 173008 | 173066 | && OptimizationEnabled(pWInfo->pParse->db, SQLITE_StarQuery) |
| 173009 | 173067 | ){ |
| 173010 | 173068 | SrcItem *aFromTabs; /* All terms of the FROM clause */ |
| 173011 | 173069 | int iFromIdx; /* Term of FROM clause is the candidate fact-table */ |
| | @@ -173013,11 +173071,11 @@ |
| 173013 | 173071 | Bitmask mSelfJoin = 0; /* Tables that cannot be dimension tables */ |
| 173014 | 173072 | WhereLoop *pStart; /* Where to start searching for dimension-tables */ |
| 173015 | 173073 | |
| 173016 | 173074 | pWInfo->bStarDone = 1; /* Only do this computation once */ |
| 173017 | 173075 | |
| 173018 | | - /* Look for fact tables with four or more dimensions where the |
| 173076 | + /* Look for fact tables with three or more dimensions where the |
| 173019 | 173077 | ** dimension tables are not separately from the fact tables by an outer |
| 173020 | 173078 | ** or cross join. Adjust cost weights if found. |
| 173021 | 173079 | */ |
| 173022 | 173080 | assert( !pWInfo->bStarUsed ); |
| 173023 | 173081 | aFromTabs = pWInfo->pTabList->a; |
| | @@ -173030,22 +173088,21 @@ |
| 173030 | 173088 | |
| 173031 | 173089 | pFactTab = aFromTabs + iFromIdx; |
| 173032 | 173090 | if( (pFactTab->fg.jointype & (JT_OUTER|JT_CROSS))!=0 ){ |
| 173033 | 173091 | /* If the candidate fact-table is the right table of an outer join |
| 173034 | 173092 | ** restrict the search for dimension-tables to be tables to the right |
| 173035 | | - ** of the fact-table. */ |
| 173036 | | - if( iFromIdx+4 > nLoop ) break; /* Impossible to reach nDep>=4 */ |
| 173093 | + ** of the fact-table. Constraint (bb) */ |
| 173094 | + if( iFromIdx+3 > nLoop ){ |
| 173095 | + break; /* ^-- Impossible to reach nDep>=2 - Constraint (cc) */ |
| 173096 | + } |
| 173037 | 173097 | while( pStart && pStart->iTab<=iFromIdx ){ |
| 173038 | 173098 | pStart = pStart->pNextLoop; |
| 173039 | 173099 | } |
| 173040 | 173100 | } |
| 173041 | 173101 | for(pWLoop=pStart; pWLoop; pWLoop=pWLoop->pNextLoop){ |
| 173042 | 173102 | if( (aFromTabs[pWLoop->iTab].fg.jointype & (JT_OUTER|JT_CROSS))!=0 ){ |
| 173043 | | - /* Fact-tables and dimension-tables cannot be separated by an |
| 173044 | | - ** outer join (at least for the definition of fact- and dimension- |
| 173045 | | - ** used by this heuristic). */ |
| 173046 | | - break; |
| 173103 | + break; /* Constraint (bb) */ |
| 173047 | 173104 | } |
| 173048 | 173105 | if( (pWLoop->prereq & m)!=0 /* pWInfo depends on iFromIdx */ |
| 173049 | 173106 | && (pWLoop->maskSelf & mSeen)==0 /* pWInfo not already a dependency */ |
| 173050 | 173107 | && (pWLoop->maskSelf & mSelfJoin)==0 /* Not a self-join */ |
| 173051 | 173108 | ){ |
| | @@ -173055,11 +173112,13 @@ |
| 173055 | 173112 | nDep++; |
| 173056 | 173113 | mSeen |= pWLoop->maskSelf; |
| 173057 | 173114 | } |
| 173058 | 173115 | } |
| 173059 | 173116 | } |
| 173060 | | - if( nDep<=3 ) continue; |
| 173117 | + if( nDep<=2 ){ |
| 173118 | + continue; /* Constraint (cc) */ |
| 173119 | + } |
| 173061 | 173120 | |
| 173062 | 173121 | /* If we reach this point, it means that pFactTab is a fact table |
| 173063 | 173122 | ** with four or more dimensions connected by inner joins. Proceed |
| 173064 | 173123 | ** to make cost adjustments. */ |
| 173065 | 173124 | |
| | @@ -173068,10 +173127,27 @@ |
| 173068 | 173127 | if( !pWInfo->bStarUsed ){ |
| 173069 | 173128 | for(pWLoop=pWInfo->pLoops; pWLoop; pWLoop=pWLoop->pNextLoop){ |
| 173070 | 173129 | pWLoop->rStarDelta = 0; |
| 173071 | 173130 | } |
| 173072 | 173131 | } |
| 173132 | +#endif |
| 173133 | +#ifdef WHERETRACE_ENABLED /* 0x80000 */ |
| 173134 | + if( sqlite3WhereTrace & 0x80000 ){ |
| 173135 | + Bitmask mShow = mSeen; |
| 173136 | + sqlite3DebugPrintf("Fact table %s(%d), dimensions:", |
| 173137 | + pFactTab->zAlias ? pFactTab->zAlias : pFactTab->pSTab->zName, |
| 173138 | + iFromIdx); |
| 173139 | + for(pWLoop=pStart; pWLoop; pWLoop=pWLoop->pNextLoop){ |
| 173140 | + if( mShow & pWLoop->maskSelf ){ |
| 173141 | + SrcItem *pDim = aFromTabs + pWLoop->iTab; |
| 173142 | + mShow &= ~pWLoop->maskSelf; |
| 173143 | + sqlite3DebugPrintf(" %s(%d)", |
| 173144 | + pDim->zAlias ? pDim->zAlias: pDim->pSTab->zName, pWLoop->iTab); |
| 173145 | + } |
| 173146 | + } |
| 173147 | + sqlite3DebugPrintf("\n"); |
| 173148 | + } |
| 173073 | 173149 | #endif |
| 173074 | 173150 | pWInfo->bStarUsed = 1; |
| 173075 | 173151 | |
| 173076 | 173152 | /* Compute the maximum cost of any WhereLoop for the |
| 173077 | 173153 | ** fact table plus one epsilon */ |
| | @@ -173091,14 +173167,12 @@ |
| 173091 | 173167 | if( pWLoop->rRun<mxRun ){ |
| 173092 | 173168 | #ifdef WHERETRACE_ENABLED /* 0x80000 */ |
| 173093 | 173169 | if( sqlite3WhereTrace & 0x80000 ){ |
| 173094 | 173170 | SrcItem *pDim = aFromTabs + pWLoop->iTab; |
| 173095 | 173171 | sqlite3DebugPrintf( |
| 173096 | | - "Increase SCAN cost of dimension %s(%d) of fact %s(%d) to %d\n", |
| 173097 | | - pDim->zAlias ? pDim->zAlias: pDim->pSTab->zName, pWLoop->iTab, |
| 173098 | | - pFactTab->zAlias ? pFactTab->zAlias : pFactTab->pSTab->zName, |
| 173099 | | - iFromIdx, mxRun |
| 173172 | + "Increase SCAN cost of %s to %d\n", |
| 173173 | + pDim->zAlias ? pDim->zAlias: pDim->pSTab->zName, mxRun |
| 173100 | 173174 | ); |
| 173101 | 173175 | } |
| 173102 | 173176 | pWLoop->rStarDelta = mxRun - pWLoop->rRun; |
| 173103 | 173177 | #endif /* WHERETRACE_ENABLED */ |
| 173104 | 173178 | pWLoop->rRun = mxRun; |
| | @@ -261473,11 +261547,11 @@ |
| 261473 | 261547 | int nArg, /* Number of args */ |
| 261474 | 261548 | sqlite3_value **apUnused /* Function arguments */ |
| 261475 | 261549 | ){ |
| 261476 | 261550 | assert( nArg==0 ); |
| 261477 | 261551 | UNUSED_PARAM2(nArg, apUnused); |
| 261478 | | - sqlite3_result_text(pCtx, "fts5: 2026-02-04 18:10:49 e6902937ecdbeb449986469859b46631272fb0a9e7e1c31adea14cff072b6d67", -1, SQLITE_TRANSIENT); |
| 261552 | + sqlite3_result_text(pCtx, "fts5: 2026-02-11 19:42:46 38d8c0d8a0b0e9990ba7bdcce979f2824ffee22a083cb788a75917628b1eb559", -1, SQLITE_TRANSIENT); |
| 261479 | 261553 | } |
| 261480 | 261554 | |
| 261481 | 261555 | /* |
| 261482 | 261556 | ** Implementation of fts5_locale(LOCALE, TEXT) function. |
| 261483 | 261557 | ** |
| 261484 | 261558 | |