-C Fix\sa\sfailing\sassert()\scaused\sby\schanges\son\sthis\sbranch.
-D 2023-09-23T18:52:22.726
+C Avoid\san\serror\swhen\sparsing\sa\sschema\sthat\scontains\sindexes\swith\sWHERE\sclauses\scontaining\sunknown\scollation\ssequences.
+D 2023-09-23T19:25:03.559
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
F src/btree.c d2e73513d382e6e4829b823fb41b5f2eddd9c5984b1492a7a6333cd91be15601
F src/btree.h 03e3356f5208bcab8eed4e094240fdac4a7f9f5ddf5e91045ce589f67d47c240
F src/btreeInt.h 91a9e0c41a0e71fa91a742ec285c63dd8dcb38b73d14fae0ed7209174ff0fdc1
-F src/build.c a52c1e9a1747a5650aa9eb16c417bb9be07d2e66473431e73bbbd1b24047ed61
+F src/build.c a08d098ad1bfd5d46a5f3a6e29a822897e9a021ddba7c021c7c1ae5d4366d1a0
F src/callback.c db3a45e376deff6a16c0058163fe0ae2b73a2945f3f408ca32cf74960b28d490
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
F src/ctime.c db847fac81837ff5e5028a5f7505147ac645ae676104adc5bc08e356f243de40
F src/sqlite.h.in 931a58d119d5cf87110648f39fa0bb9f1738b0068cb68250d893304a471bd6c0
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 2f30b2671f4c03cd27a43f039e11251391066c97d11385f5f963bb40b03038ac
-F src/sqliteInt.h 876f5ffc0eaa876a55b2b220fff6cc3e8250fa207b864ab10b07949f1fba9b57
+F src/sqliteInt.h 1fc2a2ee3016dd3ce433db8432bef50b8266d017527d38ccb8abed87c8305d76
F src/sqliteLimit.h 33b1c9baba578d34efe7dfdb43193b366111cdf41476b1e82699e14c11ee1fb6
F src/status.c 160c445d7d28c984a0eae38c144f6419311ed3eace59b44ac6dafc20db4af749
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
F src/wal.c 01e051a1e713d9eabdb25df38602837cec8f4c2cae448ce2cf6accc87af903e9
F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452
F src/walker.c 7c7ea0115345851c3da4e04e2e239a29983b61fb5b038b94eede6aba462640e2
-F src/where.c e2ce695f5963620d4c403fb97e51216ca364247090e806bec938c82af9573eee
+F src/where.c c68648edade39a91687f2c63aacb07cb0f6a823814289af35b0aa1d43c62fed2
F src/whereInt.h 4b38c5889514e3aead3f27d0ee9a26e47c3f150efc59e2a8b4e3bc8835e4d7a1
F src/wherecode.c 5d77db30a2a3dd532492ae882de114edba2fae672622056b1c7fd61f5917a8f1
F src/whereexpr.c dc5096eca5ed503999be3bdee8a90c51361289a678d396a220912e9cb73b3c00
F test/index7.test b238344318e0b4e42126717f6554f0e7dfd0b39cecad4b736039b43e1e3b6eb3
F test/index8.test caa097735c91dbc23d8a402f5e63a2a03c83840ba3928733ed7f9a03f8a912a3
F test/index9.test 2ac891806a4136ef3e91280477e23114e67575207dc331e6797fa0ed9379f997
-F test/indexA.test 0f2a0f67f49a437714f374b304f924c692319c1cb56b46d2de67b735a3d62eb2
+F test/indexA.test 3ae5e98564c3a36d68942b218e53126a6996a48b95a5eb38b9aa7adf19784949
F test/indexedby.test f21eca4f7a6ffe14c8500a7ad6cd53166666c99e5ccd311842a28bc94a195fe0
F test/indexexpr1.test 62558b1cfd7ccbe7bc015849cc6d1a13ef124e80cbd5b3a98dc66c3c9cce0cf4
F test/indexexpr2.test 1c382e81ef996d8ae8b834a74f2a9013dddf59214c32201d7c8a656d739f999a
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 7c4210253b660b385d14de3ae7ab30f038036308e1164ec17b40e2805b9b2235
-R 79f7b7ac29c4d246921dcdd8df4ce062
+P d0e21f20bd8643d21c4b88fb75b83939d68e9b7118f7289a164656f11d2ee555
+R 2173ec5daddfa5c65583f3ffe032fd88
U dan
-Z 1c7c371de6fd21faea295aab95777c4c
+Z 5d069b0b0f770f8e55162243a5db6bc9
# Remove this line to create a well-formed Fossil manifest.
return rc;
}
+/*
+** This is an sqlite3ParserAddCleanup() callback that is invoked to
+** free the Parse->pIdxEpr list when the Parse object is destroyed.
+*/
+static void whereIndexedExprCleanup(sqlite3 *db, void *pObject){
+ IndexedExpr **pp = (IndexedExpr**)pObject;
+ while( *pp!=0 ){
+ IndexedExpr *p = *pp;
+ *pp = p->pIENext;
+ sqlite3ExprDelete(db, p->pExpr);
+ sqlite3DbFreeNN(db, p);
+ }
+}
+
+/*
+** This function is called for a partial index - one with a WHERE clause - in
+** two scenarios. In both cases, it determines whether or not the WHERE
+** clause on the index implies that a column of the table may be safely
+** replaced by a constant expression. For example, in the following
+** SELECT:
+**
+** CREATE INDEX i1 ON t1(b, c) WHERE a=<expr>;
+** SELECT a, b, c FROM t1 WHERE a=<expr> AND b=?;
+**
+** The "a" in the select-list may be replaced by <expr>, iff:
+**
+** (a) <expr> is a constant expression, and
+** (b) The (a=<expr>) comparison uses the BINARY collation sequence, and
+** (c) Column "a" has an affinity other than NONE or BLOB.
+**
+** If argument pItem is NULL, then pMask must not be NULL. In this case this
+** function is being called as part of determining whether or not pIdx
+** is a covering index. This function clears any bits in (*pMask)
+** corresponding to columns that may be replaced by constants as described
+** above.
+**
+** Otherwise, if pItem is not NULL, then this function is being called
+** as part of coding a loop that uses index pIdx. In this case, add entries
+** to the Parse.pIdxPartExpr list for each column that can be replaced
+** by a constant.
+*/
+static void wherePartIdxExpr(
+ Parse *pParse, /* Parse context */
+ Index *pIdx, /* Partial index being processed */
+ Expr *pPart, /* WHERE clause being processed */
+ Bitmask *pMask, /* Mask to clear bits in */
+ int iIdxCur, /* Cursor number for index */
+ SrcItem *pItem /* The FROM clause entry for the table */
+){
+ assert( pItem==0 || (pItem->fg.jointype & JT_RIGHT)==0 );
+ assert( (pItem==0 || pMask==0) && (pMask!=0 || pItem!=0) );
+
+ if( pPart->op==TK_AND ){
+ wherePartIdxExpr(pParse, pIdx, pPart->pRight, pMask, iIdxCur, pItem);
+ pPart = pPart->pLeft;
+ }
+
+ if( (pPart->op==TK_EQ || pPart->op==TK_IS) ){
+ Expr *pLeft = pPart->pLeft;
+ Expr *pRight = pPart->pRight;
+ u8 aff;
+
+ if( pRight->op==TK_COLUMN ){
+ SWAP(Expr*, pLeft, pRight);
+ }
+
+ if( pLeft->op!=TK_COLUMN ) return;
+ if( !sqlite3ExprIsConstant(pRight) ) return;
+ if( !sqlite3IsBinary(sqlite3ExprCompareCollSeq(pParse, pPart)) ) return;
+ if( pLeft->iColumn<0 ) return;
+ aff = pIdx->pTable->aCol[pLeft->iColumn].affinity;
+ if( aff>=SQLITE_AFF_TEXT ){
+ if( pItem ){
+ sqlite3 *db = pParse->db;
+ IndexedExpr *p = (IndexedExpr*)sqlite3DbMallocZero(db, sizeof(*p));
+ if( p ){
+ int bNullRow = (pItem->fg.jointype&(JT_LEFT|JT_LTORJ))!=0;
+ p->pExpr = sqlite3ExprDup(db, pRight, 0);
+ p->iDataCur = pItem->iCursor;
+ p->iIdxCur = iIdxCur;
+ p->iIdxCol = pLeft->iColumn;
+ p->bMaybeNullRow = bNullRow;
+ p->pIENext = pParse->pIdxPartExpr;
+ p->aff = aff;
+ pParse->pIdxPartExpr = p;
+ if( p->pIENext==0 ){
+ void *pArg = (void*)&pParse->pIdxPartExpr;
+ sqlite3ParserAddCleanup(pParse, whereIndexedExprCleanup, pArg);
+ }
+ }
+ }else if( pLeft->iColumn<(BMS-1) ){
+ *pMask &= ~((Bitmask)1 << pLeft->iColumn);
+ }
+ }
+ }
+}
+
+
/*
** Add all WhereLoop objects for a single table of the join where the table
** is identified by pBuilder->pNew->iTab. That table is guaranteed to be
pNew->wsFlags = WHERE_IDX_ONLY | WHERE_INDEXED;
}else{
m = pSrc->colUsed & pProbe->colNotIdxed;
+ if( pProbe->pPartIdxWhere ){
+ wherePartIdxExpr(pWInfo->pParse, pProbe, pProbe->pPartIdxWhere, &m, 0, 0);
+ }
pNew->wsFlags = WHERE_INDEXED;
if( m==TOPBIT || (pProbe->bHasExpr && !pProbe->bHasVCol && m!=0) ){
u32 isCov = whereIsCoveringIndex(pWInfo, pProbe, pSrc->iCursor);
}
}
-/*
-** This is an sqlite3ParserAddCleanup() callback that is invoked to
-** free the Parse->pIdxEpr list when the Parse object is destroyed.
-*/
-static void whereIndexedExprCleanup(sqlite3 *db, void *pObject){
- IndexedExpr **pp = (IndexedExpr**)pObject;
- while( *pp!=0 ){
- IndexedExpr *p = *pp;
- *pp = p->pIENext;
- sqlite3ExprDelete(db, p->pExpr);
- sqlite3DbFreeNN(db, p);
- }
-}
-
/*
** The index pIdx is used by a query and contains one or more expressions.
** In other words pIdx is an index on an expression. iIdxCur is the cursor
}
}
-/*
-** This function is called for a partial index - one with a WHERE clause - in
-** two scenarios. In both cases, it determines whether or not the WHERE
-** clause on the index implies that a column of the table may be safely
-** replaced by a constant expression. For example, in the following
-** SELECT:
-**
-** CREATE INDEX i1 ON t1(b, c) WHERE a=<expr>;
-** SELECT a, b, c FROM t1 WHERE a=<expr> AND b=?;
-**
-** The "a" in the select-list may be replaced by <expr>, iff:
-**
-** (a) <expr> is a constant expression, and
-** (b) The (a=<expr>) comparison uses the BINARY collation sequence, and
-** (c) Column "a" has an affinity other than NONE or BLOB.
-**
-** If argument pTabItem is NULL, then this function is being called as part
-** of parsing the CREATE INDEX statement. In that case the Index.colNotIdxed
-** mask is updated to mark any columns that will be replaced by constant
-** values as indexed.
-**
-** Otherwise, if pTabItem is not NULL, then this function is being called
-** as part of coding a loop that uses index pIdx. In this case, add entries
-** to the Parse.pIdxPartExpr list for each column that can be replaced
-** by a constant.
-*/
-void sqlite3WherePartIdxExpr(
- Parse *pParse, /* Parse context */
- Index *pIdx, /* Partial index being processed */
- Expr *pPart, /* WHERE clause being processed */
- int iIdxCur, /* Cursor number for index */
- SrcItem *pTabItem /* The FROM clause entry for the table */
-){
- assert( pTabItem==0 || (pTabItem->fg.jointype & JT_RIGHT)==0 );
- if( pPart->op==TK_AND ){
- sqlite3WherePartIdxExpr(pParse, pIdx, pPart->pRight, iIdxCur, pTabItem);
- pPart = pPart->pLeft;
- }
-
- if( (pPart->op==TK_EQ || pPart->op==TK_IS) ){
- Expr *pLeft = pPart->pLeft;
- Expr *pRight = pPart->pRight;
- u8 aff;
-
- if( pRight->op==TK_COLUMN ){
- SWAP(Expr*, pLeft, pRight);
- }
-
- if( pLeft->op!=TK_COLUMN ) return;
- if( !sqlite3ExprIsConstant(pRight) ) return;
- if( !sqlite3IsBinary(sqlite3ExprCompareCollSeq(pParse, pPart)) ) return;
- if( pLeft->iColumn<0 ) return;
- aff = pIdx->pTable->aCol[pLeft->iColumn].affinity;
- if( aff>=SQLITE_AFF_TEXT ){
- if( pTabItem ){
- sqlite3 *db = pParse->db;
- IndexedExpr *p = (IndexedExpr*)sqlite3DbMallocZero(db, sizeof(*p));
- if( p ){
- int bNullRow = (pTabItem->fg.jointype&(JT_LEFT|JT_LTORJ))!=0;
- p->pExpr = sqlite3ExprDup(db, pRight, 0);
- p->iDataCur = pTabItem->iCursor;
- p->iIdxCur = iIdxCur;
- p->iIdxCol = pLeft->iColumn;
- p->bMaybeNullRow = bNullRow;
- p->pIENext = pParse->pIdxPartExpr;
- p->aff = aff;
- pParse->pIdxPartExpr = p;
- if( p->pIENext==0 ){
- void *pArg = (void*)&pParse->pIdxPartExpr;
- sqlite3ParserAddCleanup(pParse, whereIndexedExprCleanup, pArg);
- }
- }
- }else if( pLeft->iColumn<(BMS-1) ){
- pIdx->colNotIdxed &= ~((Bitmask)1 << pLeft->iColumn);
- }
- }
- }
-}
-
/*
** Set the reverse-scan order mask to one for all tables in the query
** with the exception of MATERIALIZED common table expressions that have
whereAddIndexedExpr(pParse, pIx, iIndexCur, pTabItem);
}
if( pIx->pPartIdxWhere && (pTabItem->fg.jointype & JT_RIGHT)==0 ){
- sqlite3WherePartIdxExpr(
- pParse, pIx, pIx->pPartIdxWhere, iIndexCur, pTabItem
+ wherePartIdxExpr(
+ pParse, pIx, pIx->pPartIdxWhere, 0, iIndexCur, pTabItem
);
}
}