diff options
author | drh <> | 2025-02-21 20:35:37 +0000 |
---|---|---|
committer | drh <> | 2025-02-21 20:35:37 +0000 |
commit | cc803b209f2ffa9dcaad43c37eb8ccafaed199bd (patch) | |
tree | d58455eecf8e403f2ecf00a75fb28a22f8d23a2d /src | |
parent | d9959bf48b13bffda4c073de17eb13752b9cb5c9 (diff) | |
download | sqlite-cc803b209f2ffa9dcaad43c37eb8ccafaed199bd.tar.gz sqlite-cc803b209f2ffa9dcaad43c37eb8ccafaed199bd.zip |
The number of declared columns in an index is limited to SQLITE_LIMIT_COLUMN.
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
Diffstat (limited to 'src')
-rw-r--r-- | src/build.c | 23 | ||||
-rw-r--r-- | src/sqliteInt.h | 6 | ||||
-rw-r--r-- | src/sqliteLimit.h | 6 | ||||
-rw-r--r-- | src/where.c | 2 |
4 files changed, 23 insertions, 14 deletions
diff --git a/src/build.c b/src/build.c index 18bf27b83..907494b19 100644 --- a/src/build.c +++ b/src/build.c @@ -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; diff --git a/src/sqliteInt.h b/src/sqliteInt.h index d4b998309..de3ce7aa2 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -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); diff --git a/src/sqliteLimit.h b/src/sqliteLimit.h index 0d15b3182..ec774889b 100644 --- a/src/sqliteLimit.h +++ b/src/sqliteLimit.h @@ -41,6 +41,12 @@ ** 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 diff --git a/src/where.c b/src/where.c index 5cb52b8ad..127525006 100644 --- a/src/where.c +++ b/src/where.c @@ -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; |