2.5 KiB
UNDF: UNDF-2026-000000300
sqlite-0003 — sqlite3CreateForeignKey: O(F×C) column resolution with sqlite3StrICmp inside nested loop
Status
PATCHED
Severity
MEDIUM (>50× speedup at F=100 FK cols, C=1000 table cols)
Location
src/build.c, function sqlite3CreateForeignKey(), lines ~3680-3688
Description
When resolving FK source column names to column indices during CREATE TABLE
parsing, SQLite uses a nested loop:
for(i=0; i<nCol; i++){ /* F = number of FK columns */
int j;
for(j=0; j<p->nCol; j++){ /* C = total columns in table */
if( sqlite3StrICmp(p->aCol[j].zCnName, pFromCol->a[i].zEName)==0 ){
pFKey->aCol[i].iFrom = j;
break;
}
}
if( j>=p->nCol ){
/* error: unknown column */
}
}
Total cost: O(F × C) with sqlite3StrICmp (case-insensitive string compare)
for each comparison.
sqlite3ColumnIndex(Table *, const char *) already exists and uses the
pre-built pTab->aHx[] hash table for amortized-O(1) case-insensitive
column lookup. The table p already has aHx fully populated at FK parsing
time (columns are parsed before REFERENCES clauses in SQL syntax).
Patch
--- a/src/build.c
+++ b/src/build.c
@@ -3680,14 +3680,17 @@ void sqlite3CreateForeignKey(...){
if( pFromCol==0 ){
pFKey->aCol[0].iFrom = p->nCol-1;
}else{
for(i=0; i<nCol; i++){
- int j;
- for(j=0; j<p->nCol; j++){
- if( sqlite3StrICmp(p->aCol[j].zCnName, pFromCol->a[i].zEName)==0 ){
- pFKey->aCol[i].iFrom = j;
- break;
- }
- }
- if( j>=p->nCol ){
+ /* CWE-407 fix (sqlite-0003): use hash-based sqlite3ColumnIndex instead
+ ** of O(p->nCol) sqlite3StrICmp inner loop. */
+ int j = sqlite3ColumnIndex(p, pFromCol->a[i].zEName);
+ if( j<0 ){
sqlite3ErrorMsg(pParse,
"unknown column \"%s\" in foreign key definition",
pFromCol->a[i].zEName);
goto fk_end;
+ }else{
+ pFKey->aCol[i].iFrom = j;
}
if( IN_RENAME_OBJECT ){
Speedup
At F=100, C=1000: O(F×C)=100,000 sqlite3StrICmp calls → O(F)=100 hash
lookups → 1000× speedup.
Typical case (F=5, C=100): O(500) → O(5) → 100× speedup.
The CREATE TABLE stage is compilation, not runtime execution. Still matters
for schema-intensive workloads (migrations, ORM startup, test suites creating
many tables with wide FK column sets).
Test
defects/sqlite/unit/SqliteTest.java — sqlite-0003 section.