]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
The number of declared columns in an index is limited to SQLITE_LIMIT_COLUMN.
authordrh <>
Fri, 21 Feb 2025 20:35:37 +0000 (20:35 +0000)
committerdrh <>
Fri, 21 Feb 2025 20:35:37 +0000 (20:35 +0000)
But the actual number of columns in the implementation might need to be
twice as much to account for the primary key at the end.  Ensure that the
code is able to deal with this.  This is a correction to
check-in [d7729dbbf231d57c].

FossilOrigin-Name: 5822feec43be9352fd87bf9968c39c0218e01ab5fe3ba50431ae21cba79e6c89

manifest
manifest.uuid
src/build.c
src/sqliteInt.h
src/sqliteLimit.h
src/where.c
test/without_rowid1.test

index 0a89891bbe55554954e596b1e661f99caa258186..eb3b50595e245c81470805fc77b084e472546c83 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Makefile-internal\svar\srenaming\sin\sprep\sfor\spending\sportability-related\schanges\sin\sthe\shandling\sof\sDLLs.\sNo\sfunctional/build\sinterface\schanges.
-D 2025-02-21T20:22:56.972
+C The\snumber\sof\sdeclared\scolumns\sin\san\sindex\sis\slimited\sto\sSQLITE_LIMIT_COLUMN.\nBut\sthe\sactual\snumber\sof\scolumns\sin\sthe\simplementation\smight\sneed\sto\sbe\ntwice\sas\smuch\sto\saccount\sfor\sthe\sprimary\skey\sat\sthe\send.\s\sEnsure\sthat\sthe\ncode\sis\sable\sto\sdeal\swith\sthis.\s\sThis\sis\sa\scorrection\sto\ncheck-in\s[d7729dbbf231d57c].
+D 2025-02-21T20:35:37.743
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md e108e1e69ae8e8a59e93c455654b8ac9356a11720d3345df2a4743e9590fb20d
@@ -725,7 +725,7 @@ F src/btmutex.c 79a43670447eacc651519a429f6ece9fd638563cf95b469d6891185ddae2b522
 F src/btree.c 9316859aa5f14bde4a3719ffb1570219e51c5de433221e38b87ea19db868aedf
 F src/btree.h 18e5e7b2124c23426a283523e5f31a4bff029131b795bb82391f9d2f3136fc50
 F src/btreeInt.h 98aadb6dcb77b012cab2574d6a728fad56b337fc946839b9898c4b4c969e30b6
-F src/build.c c2bcfc7e5072a743a051699f06329ee206299729adf4323fed9be8aa2d64af73
+F src/build.c 20793695ef64d2d0c147501e37f344f828f09f16d346a987b516316186030996
 F src/callback.c acae8c8dddda41ee85cfdf19b926eefe830f371069f8aadca3aa39adf5b1c859
 F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
 F src/date.c 842c08ac143a56a627b05ac51d68624f2b7b03e3b4cba596205e735eed64ee57
@@ -786,8 +786,8 @@ F src/shell.c.in bf997e43faaa1ef0ff78d4d7b9be6a9430cf1edda9a47a14e7fef646fcb459a
 F src/sqlite.h.in 8d4486fb28a90de818ac1e8c6206ea458e7de6bd8e0dfa3d554494f155be8c01
 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
 F src/sqlite3ext.h 3f046c04ea3595d6bfda99b781926b17e672fd6d27da2ba6d8d8fc39981dcb54
-F src/sqliteInt.h a5c850981cff99331b2ed48d519fb54a47f5f91c680e2cab64d91e259685de69
-F src/sqliteLimit.h b963c1e8c48791cc5cf733bb33e4741d0fbb7d0650cc2344cce5e4c17be4e8fd
+F src/sqliteInt.h e74f0ea0bc4d3c16afd5004557b264137d6f1d61d2a1ff2a49877b0589945462
+F src/sqliteLimit.h 6d817c28a8f19af95e6f4921933b7fbbca48a962bce0eb0ec81e8bb3ef38e68b
 F src/status.c 0e72e4f6be6ccfde2488eb63210297e75f569f3ce9920f6c3d77590ec6ce5ffd
 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
 F src/tclsqlite.c 5c1e367e26711044730c93d4b81312170918a8d1fe811f45be740ab48f7de8c1
@@ -865,7 +865,7 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
 F src/wal.c cefdffc112c767c79596d9c0d15cb4de27071132e9b8a0fce323b140cd4af683
 F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452
 F src/walker.c d5006d6b005e4ea7302ad390957a8d41ed83faa177e412f89bc5600a7462a014
-F src/where.c 09dc313e7223ca1217c39c7026b00f16ff449a8323511a762fcba7863a00f4cd
+F src/where.c 12cca5dfbe96e2589f951c43c0720fc58e52611787c37d85a0d9c10376202e8b
 F src/whereInt.h d20cddddb1d61b18d5cb1fcfa9b77fbeebbc4afe44d996e603452a23b3009ee1
 F src/wherecode.c 5baa06f0daae7d38aca1d4814030b82ad4f127fe6bad18f0644776a474f6088b
 F src/whereexpr.c 2415c8eee5ff89a8b709d7d83d71c1ff986cd720d0520057e1d8a5371339012a
@@ -2095,7 +2095,7 @@ F test/with4.test 257be66c0c67fee1defbbac0f685c3465e2cad037f21ce65f23f86084f1982
 F test/with5.test 6248213c41fab36290b5b73aa3f937309dfba337004d9d8434c3fabc8c7d4be8
 F test/with6.test 281e4861b5e517f6c3c2f08517a520c1e2ee7c11966545d3901f258a4fe8ef76
 F test/withM.test 693b61765f2b387b5e3e24a4536e2e82de15ff64
-F test/without_rowid1.test 7120af676485e68930d3e513d083f3644622893477901f55eec954387125d550
+F test/without_rowid1.test 545a98bde0dc641cce8d361cd589677a70561f36f9033ae48de8ae37418d6ce2
 F test/without_rowid2.test af260339f79d13cb220288b67cd287fbcf81ad99
 F test/without_rowid3.test 39ab0dd773eaa62e59b17093f875327630f54c4145458f6d2b053d68d4b2f67b
 F test/without_rowid4.test 4e08bcbaee0399f35d58b5581881e7a6243d458a
@@ -2210,8 +2210,8 @@ F tool/version-info.c 3b36468a90faf1bbd59c65fd0eb66522d9f941eedd364fabccd7227350
 F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
 F tool/warnings.sh 49a486c5069de041aedcbde4de178293e0463ae9918ecad7539eedf0ec77a139
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P d7729dbbf231d57cbcaaa5004d0a9c4957f112dd6520052995b232aa521c0ca3
-R 9fa57efe9e24b037978a77954d886617
-U stephan
-Z 3e199b62ebb0fe5383698c3c45ceb587
+P ebf41fc90aa9fb1bb96239145c0cdd06eced391499975c71734610996d088641
+R ea801290870a4070bffe00dffce34b68
+U drh
+Z e1106d68193ec85ec463ffb759ee622e
 # Remove this line to create a well-formed Fossil manifest.
index e261d3c10bf2192c43a7a1943c93b889d8d7a6f9..83f71c4a07ff3e25f054d02ce39a3e01b555860f 100644 (file)
@@ -1 +1 @@
-ebf41fc90aa9fb1bb96239145c0cdd06eced391499975c71734610996d088641
+5822feec43be9352fd87bf9968c39c0218e01ab5fe3ba50431ae21cba79e6c89
index 18bf27b8338e401087c896e196fca9b964b5fe02..907494b193850faa950d78bb0be7c4882f7ea8d5 100644 (file)
@@ -1067,7 +1067,7 @@ Index *sqlite3PrimaryKeyIndex(Table *pTab){
 ** find the (first) offset of that column in index pIdx.  Or return -1
 ** if column iCol is not used in index pIdx.
 */
-i16 sqlite3TableColumnToIndex(Index *pIdx, int iCol){
+int sqlite3TableColumnToIndex(Index *pIdx, int iCol){
   int i;
   i16 iCol16;
   assert( iCol>=(-1) && iCol<=SQLITE_MAX_COLUMN );
@@ -2175,16 +2175,15 @@ static char *createTableStmt(sqlite3 *db, Table *p){
 */
 static int resizeIndexObject(Parse *pParse, Index *pIdx, int N){
   char *zExtra;
-  int nByte;
+  u64 nByte;
   sqlite3 *db;
   if( pIdx->nColumn>=N ) return SQLITE_OK;
   db = pParse->db;
-  if( N>db->aLimit[SQLITE_LIMIT_COLUMN] ){
-    sqlite3ErrorMsg(pParse, "too many columns on %s", pIdx->zName);
-    return SQLITE_ERROR;
-  }
+  assert( N>0 );
+  assert( N <= SQLITE_MAX_COLUMN*2 /* tag-20250221-1 */ );
+  testcase( N==2*pParse->db->aLimit[SQLITE_LIMIT_COLUMN] );
   assert( pIdx->isResized==0 );
-  nByte = (sizeof(char*) + sizeof(LogEst) + sizeof(i16) + 1)*N;
+  nByte = (sizeof(char*) + sizeof(LogEst) + sizeof(i16) + 1)*(u64)N;
   zExtra = sqlite3DbMallocZero(db, nByte);
   if( zExtra==0 ) return SQLITE_NOMEM_BKPT;
   memcpy(zExtra, pIdx->azColl, sizeof(char*)*pIdx->nColumn);
@@ -2198,7 +2197,7 @@ static int resizeIndexObject(Parse *pParse, Index *pIdx, int N){
   zExtra += sizeof(i16)*N;
   memcpy(zExtra, pIdx->aSortOrder, pIdx->nColumn);
   pIdx->aSortOrder = (u8*)zExtra;
-  pIdx->nColumn = N;
+  pIdx->nColumn = (u16)N;  /* See tag-20250221-1 above for proof of safety */
   pIdx->isResized = 1;
   return SQLITE_OK;
 }
@@ -3860,13 +3859,14 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
 */
 Index *sqlite3AllocateIndexObject(
   sqlite3 *db,         /* Database connection */
-  i16 nCol,            /* Total number of columns in the index */
+  int nCol,            /* Total number of columns in the index */
   int nExtra,          /* Number of bytes of extra space to alloc */
   char **ppExtra       /* Pointer to the "extra" space */
 ){
   Index *p;            /* Allocated index object */
   i64 nByte;           /* Bytes of space for Index object + arrays */
 
+  assert( nCol <= 2*db->aLimit[SQLITE_LIMIT_COLUMN] );
   nByte = ROUND8(sizeof(Index)) +              /* Index structure  */
           ROUND8(sizeof(char*)*nCol) +         /* Index.azColl     */
           ROUND8(sizeof(LogEst)*(nCol+1) +     /* Index.aiRowLogEst   */
@@ -3879,8 +3879,9 @@ Index *sqlite3AllocateIndexObject(
     p->aiRowLogEst = (LogEst*)pExtra; pExtra += sizeof(LogEst)*(nCol+1);
     p->aiColumn = (i16*)pExtra;       pExtra += sizeof(i16)*nCol;
     p->aSortOrder = (u8*)pExtra;
-    p->nColumn = nCol;
-    p->nKeyCol = nCol - 1;
+    assert( nCol>0 );
+    p->nColumn = (u16)nCol;
+    p->nKeyCol = (u16)(nCol - 1);
     *ppExtra = ((char*)p) + nByte;
   }
   return p;
index d4b99830913c2fe26f0f45680747e98d1836ee78..de3ce7aa29b7517955507c01ac7ecceb4087c296 100644 (file)
@@ -2759,7 +2759,7 @@ struct Index {
   Pgno tnum;               /* DB Page containing root of this index */
   LogEst szIdxRow;         /* Estimated average row size in bytes */
   u16 nKeyCol;             /* Number of columns forming the key */
-  u16 nColumn;             /* Number of columns stored in the index */
+  u16 nColumn;             /* Nr columns in btree. Can be 2*Table.nCol */
   u8 onError;              /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
   unsigned idxType:2;      /* 0:Normal 1:UNIQUE, 2:PRIMARY KEY, 3:IPK */
   unsigned bUnordered:1;   /* Use this index for == or IN queries only */
@@ -4908,7 +4908,7 @@ void sqlite3SubqueryColumnTypes(Parse*,Table*,Select*,char);
 Table *sqlite3ResultSetOfSelect(Parse*,Select*,char);
 void sqlite3OpenSchemaTable(Parse *, int);
 Index *sqlite3PrimaryKeyIndex(Table*);
-i16 sqlite3TableColumnToIndex(Index*, int);
+int sqlite3TableColumnToIndex(Index*, int);
 #ifdef SQLITE_OMIT_GENERATED_COLUMNS
 # define sqlite3TableColumnToStorage(T,X) (X)  /* No-op pass-through */
 # define sqlite3StorageColumnToTable(T,X) (X)  /* No-op pass-through */
@@ -5006,7 +5006,7 @@ void sqlite3SrcListAssignCursors(Parse*, SrcList*);
 void sqlite3IdListDelete(sqlite3*, IdList*);
 void sqlite3ClearOnOrUsing(sqlite3*, OnOrUsing*);
 void sqlite3SrcListDelete(sqlite3*, SrcList*);
-Index *sqlite3AllocateIndexObject(sqlite3*,i16,int,char**);
+Index *sqlite3AllocateIndexObject(sqlite3*,int,int,char**);
 void sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*,
                           Expr*, int, int, u8);
 void sqlite3DropIndex(Parse*, SrcList*, int);
index 0d15b31822ab744308433b1a6656553671455da1..ec774889b5deb15d5fd34454e4738cceccc32373 100644 (file)
 ** not have more than a dozen or so columns in any table.  And if
 ** that is the case, there is no point in having more than a few
 ** dozen values in any of the other situations described above.
+**
+** An index can only have SQLITE_MAX_COLUMN columns from the user
+** point of view, but the underlying b-tree that implements the index
+** might have up to twice as many columns in a WITHOUT ROWID table,
+** since must also store the primary key at the end.  Hence the
+** column count for Index is u16 instead of i16.
 */
 #if !defined(SQLITE_MAX_COLUMN)
 # define SQLITE_MAX_COLUMN 2000
index 5cb52b8adb0a933f1a7a35b809e01ea7fbb2cbd6..12752500678eae823da9348ecd447722b804deb0 100644 (file)
@@ -1104,6 +1104,8 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
   }
 
   /* Construct the Index object to describe this index */
+  assert( nKeyCol <= pTable->nCol + MAX(0, pTable->nCol - BMS + 1) );
+  /* ^-- This guarantees that the number of index columns will fit in the u16 */
   pIdx = sqlite3AllocateIndexObject(pParse->db, nKeyCol+HasRowid(pTable),
                                     0, &zNotUsed);
   if( pIdx==0 ) goto end_auto_index_create;
index 0095fab0c054ff5cfd98facc6a571d029748d9b7..5d0bc81105ebb6b86823d075e452e04ee310a14d 100644 (file)
@@ -493,18 +493,27 @@ ifcapable altertable {
 #
 reset_db
 sqlite3_limit db SQLITE_LIMIT_COLUMN 8
-do_catchsql_test 16.1 {
+do_execsql_test 16.1 {
   CREATE TABLE t1(
     c1,c2,c3,c4,c5,c6,c7,c8,
     PRIMARY KEY(c1,c2,c1 COLLATE NOCASE)
   ) WITHOUT ROWID;
-} {1 {too many columns on sqlite_autoindex_t1_1}}
-do_catchsql_test 16.2 {
-  CREATE TABLE t1(
+} {}
+do_execsql_test 16.2 {
+  CREATE TABLE t2(
+    c1,c2,c3,c4,c5,c6,c7,c8,
+    PRIMARY KEY(c1 COLLATE nocase,c1 COLLATE rtrim,
+                c2 COLLATE nocase,c2 COLLATE rtrim,
+                c3 COLLATE nocase,c3 COLLATE rtrim,
+                c4 COLLATE nocase,c4 COLLATE rtrim)
+  ) WITHOUT ROWID;
+} {}
+do_execsql_test 16.3 {
+  CREATE TABLE t3(
     c1,c2,c3,c4,c5,c6,c7,c8,
     PRIMARY KEY(c1,c2),
     UNIQUE(c3,c4,c5,c6,c7,c8,c3 COLLATE nocase)
   ) WITHOUT ROWID;
-} {1 {too many columns on sqlite_autoindex_t1_2}}
+} {}
 
 finish_test