From: drh <> Date: Thu, 5 Aug 2021 15:27:19 +0000 (+0000) Subject: Store the collating sequence name for each column of a table as an X-Git-Tag: version-3.37.0~295 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=65b400931ddbaaa2059094a014ecf46c0840857c;p=thirdparty%2Fsqlite.git Store the collating sequence name for each column of a table as an extension to the column name, for an additional savings in the heap space needed to hold the schema. FossilOrigin-Name: 832ac4c1ee384be0de72a4bdd55ed87e0f8294e7df5eefcf6b4942db3d85a69e --- diff --git a/manifest b/manifest index 019a53ba43..0f3d8820af 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sNEVER()\smacros\son\srecently\sintroduced\sunreachable\sbranches. -D 2021-08-04T14:50:23.224 +C Store\sthe\scollating\ssequence\sname\sfor\seach\scolumn\sof\sa\stable\sas\san\nextension\sto\sthe\scolumn\sname,\sfor\san\sadditional\ssavings\sin\sthe\sheap\sspace\nneeded\sto\shold\sthe\sschema. +D 2021-08-05T15:27:19.168 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -478,7 +478,7 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786 F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a -F src/alter.c f2a1c9eeed22a40ac88285fb393aff1a21d153d80bde1955202191430beb9e09 +F src/alter.c 38975b971a4c36dbcc8004c74b492213a851ab368d29238c531a22636508a5d4 F src/analyze.c abbaaf7dca79d1c31c713500324fc0b55bf3eeac5b7b07001452a3d0f210de4f F src/attach.c a514e81758ba7b3a3a0501faf70af6cfc509de8810235db726cfc9f25165e929 F src/auth.c f4fa91b6a90bbc8e0d0f738aa284551739c9543a367071f55574681e0f24f8cf @@ -488,7 +488,7 @@ F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 F src/btree.c e204a9c8fb4fe5dbb910a863ba487f4af9b5c501254ec4ccbfcdd6b1f65b7fb4 F src/btree.h 74d64b8f28cfa4a894d14d4ed64fa432cd697b98b61708d4351482ae15913e22 F src/btreeInt.h 7bc15a24a02662409ebcd6aeaa1065522d14b7fda71573a2b0568b458f514ae0 -F src/build.c 9d607ffcaeb6120daf8fdc229b064f9de1be3cfc7188d0d4fff010ca2f05c835 +F src/build.c ac4c6990ff076676bf172442c7098d2ae8370adf8c3ac6280aef23d05336ec9c F src/callback.c d0b853dd413255d2e337b34545e54d888ea02f20da5ad0e63585b389624c4a6c F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/ctime.c 8159d5f706551861c18ec6c8f6bdf105e15ea00367f05d9ab65d31a1077facc1 @@ -496,19 +496,19 @@ F src/date.c e0632f335952b32401482d099321bbf12716b29d6e72836b53ae49683ebae4bf F src/dbpage.c 8a01e865bf8bc6d7b1844b4314443a6436c07c3efe1d488ed89e81719047833a F src/dbstat.c 3aa79fc3aed7ce906e4ea6c10e85d657299e304f6049861fe300053ac57de36c F src/delete.c 3ce6af6b64c8b476de51ccc32da0cb3142d42e65754e1d8118addf65b8bcba15 -F src/expr.c 0d541b9f9ecddf9d6d310f31922006f03509d7264ef53ac39c391b82a62383f9 +F src/expr.c e98375fc63552cc8cdd36a41bdca3039cb603d9fe67abd9c9f40adae8405fbc5 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 -F src/fkey.c 9e2b4127463c18e6351ff3665475045f048dd2e2f72a3761721e4ff6c6a45abf +F src/fkey.c 1905af1821b88321e1bb9d6a69e704495b6844a9b6c29398d40117cc251e893c F src/func.c c224240cbc97fa5e9c4fe9acb128716cb835ca045532bca6951b7c45b020c56c F src/global.c 5eba017ebbd887e2365e6e6e815e1619e41406b8946d17594e94116174787df5 F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19 F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38 F src/hwtime.h cb1d7e3e1ed94b7aa6fde95ae2c2daccc3df826be26fc9ed7fd90d1750ae6144 F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 -F src/insert.c c6419bc4b447f3d4cdb7b1167690baaea3b796a80cea48e7cf26da65487d430d +F src/insert.c 4ebff642574d3866316439b3dfce165f80e130e8969853c656d71b2afc5dd73c F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 0aa9e7f08e168e3874cb54984408e3976dafdf5616d511952c425b5ac088ea3e -F src/main.c 2c17a667133d2d1666319cfef975a48aa640a3de0c57d68b362372a12ad5557b +F src/main.c 5c8c47584612a60bd05c309aadbbfa4728824df0a94148d2a4e7e97d34676a22 F src/malloc.c cbc93cdd429c4594912017d92ab656e2579aca64dbd1c6888551275bed46f25b F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de @@ -544,12 +544,12 @@ F src/printf.c 78fabb49b9ac9a12dd1c89d744abdc9b67fd3205e62967e158f78b965a29ec4b F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c F src/resolve.c 42b94d37a54200707a95566eff4f7e8a380e32d080016b699f23bd79a73a5028 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 -F src/select.c 52041124629704feb24b1bc7dabf8ec03a0857c69d23f2dd0c33c9ed3d074adb +F src/select.c 63077c0243ded1432d97c90c1a4c3419b3a574b36634c674599a68bfe4c3bdc2 F src/shell.c.in 24b99dae8818d1a234732d73f4d5b49f12b510bc62735a41c04e314fafae09e3 F src/sqlite.h.in 43fcf0fe2af04081f420a906fc020bde1243851ba44b0aa567a27f94bf8c3145 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h e97f4e9b509408fea4c4e9bef5a41608dfac343b4d3c7a990dedde1e19af9510 -F src/sqliteInt.h 6f02ceb8d6b8784faf7218bd58b59580837c9e95e54a5b34d48ae93504ba67ce +F src/sqliteInt.h 3dbca904012fc663b4e8c51ad644eb99ba17bb03589de0b1358496fa73dc8039 F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657 F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 @@ -633,7 +633,7 @@ F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a F src/walker.c 7342becedf3f8a26f9817f08436bdf8b56ad69af83705f6b9320a0ad3092c2ac F src/where.c 99b6e13664a7bd9a553c554978d0e253066995dade621f44cffa8928c8b493b5 F src/whereInt.h 9248161dd004f625ce5d3841ca9b99fed3fc8d61522cf76340fc5217dbe1375b -F src/wherecode.c ef36790a797fa679f58dbd51930e3ee7ef7cb6c906ae412032e4d319a36a2eef +F src/wherecode.c 9b33f463a279feeee69622b747b0050f0b836eb8b5ac48599ba3a6bfbea798a7 F src/whereexpr.c 3a9144a9d52e110efdc012a73b1574e7b2b4df4bf98949387cb620295eba0975 F src/window.c 420167512050a0dfc0f0115b9f0c7d299da9759c9bb2ae83a61fb8d730a5707f F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 @@ -1920,7 +1920,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 164662ef01ad45ca570c44631a1117cccce6e34b00dbba7f422c089e8ffaa932 -R 4753b5d71292c9ebc3a2ba2d009a17d6 +P 806939eb5947f9187dc9c4814b26e9f94ec0186596c7be97981dbea7c2169c26 +R c05bd2cc9216ebbd1f44d1211c54be18 U drh -Z 98a283af33e1b680aea1e6779f6dcf99 +Z 761dcef26d3489b5940c28f76fcc5ec9 diff --git a/manifest.uuid b/manifest.uuid index de16e75317..cd11bd283e 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -806939eb5947f9187dc9c4814b26e9f94ec0186596c7be97981dbea7c2169c26 \ No newline at end of file +832ac4c1ee384be0de72a4bdd55ed87e0f8294e7df5eefcf6b4942db3d85a69e \ No newline at end of file diff --git a/src/alter.c b/src/alter.c index 5780d2df0c..c059a62ecd 100644 --- a/src/alter.c +++ b/src/alter.c @@ -532,7 +532,6 @@ void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){ Column *pCol = &pNew->aCol[i]; pCol->zCnName = sqlite3DbStrDup(db, pCol->zCnName); pCol->hName = sqlite3StrIHash(pCol->zCnName); - pCol->zCnColl = 0; } assert( !IsVirtual(pNew) ); pNew->u.tab.pDfltList = sqlite3ExprListDup(db, pTab->u.tab.pDfltList, 0); diff --git a/src/build.c b/src/build.c index 942dc85f8b..6343da4f58 100644 --- a/src/build.c +++ b/src/build.c @@ -710,6 +710,45 @@ Expr *sqlite3ColumnExpr(Table *pTab, Column *pCol){ return pTab->u.tab.pDfltList->a[pCol->iDflt-1].pExpr; } +/* +** Set the collating sequence name for a column. +*/ +void sqlite3ColumnSetColl( + sqlite3 *db, + Column *pCol, + const char *zColl +){ + int nColl; + int n; + char *zNew; + assert( zColl!=0 ); + n = sqlite3Strlen30(pCol->zCnName) + 1; + if( pCol->colFlags & COLFLAG_HASTYPE ){ + n += sqlite3Strlen30(pCol->zCnName+n) + 1; + } + nColl = sqlite3Strlen30(zColl) + 1; + zNew = sqlite3DbRealloc(db, pCol->zCnName, nColl+n); + if( zNew ){ + pCol->zCnName = zNew; + memcpy(pCol->zCnName + n, zColl, nColl); + pCol->colFlags |= COLFLAG_HASCOLL; + } +} + +/* +** Return the collating squence name for a column +*/ +const char *sqlite3ColumnColl(Column *pCol){ + const char *z; + if( (pCol->colFlags & COLFLAG_HASCOLL)==0 ) return 0; + z = pCol->zCnName; + while( *z ){ z++; } + if( pCol->colFlags & COLFLAG_HASTYPE ){ + do{ z++; }while( *z ); + } + return z+1; +} + /* ** Delete memory allocated for the column names of a table or view (the ** Table.aCol[] array). @@ -722,7 +761,6 @@ void sqlite3DeleteColumnNames(sqlite3 *db, Table *pTable){ for(i=0; inCol; i++, pCol++){ assert( pCol->zCnName==0 || pCol->hName==sqlite3StrIHash(pCol->zCnName) ); sqlite3DbFree(db, pCol->zCnName); - sqlite3DbFree(db, pCol->zCnColl); } sqlite3DbFree(db, pTable->aCol); if( !IsVirtual(pTable) ){ @@ -1891,8 +1929,7 @@ void sqlite3AddCollateType(Parse *pParse, Token *pToken){ if( sqlite3LocateCollSeq(pParse, zColl) ){ Index *pIdx; - sqlite3DbFree(db, p->aCol[i].zCnColl); - p->aCol[i].zCnColl = zColl; + sqlite3ColumnSetColl(db, &p->aCol[i], zColl); /* If the column is declared as " PRIMARY KEY COLLATE ", ** then an index may have been created on this column before the @@ -1901,12 +1938,11 @@ void sqlite3AddCollateType(Parse *pParse, Token *pToken){ for(pIdx=p->pIndex; pIdx; pIdx=pIdx->pNext){ assert( pIdx->nKeyCol==1 ); if( pIdx->aiColumn[0]==i ){ - pIdx->azColl[0] = p->aCol[i].zCnColl; + pIdx->azColl[0] = sqlite3ColumnColl(&p->aCol[i]); } } - }else{ - sqlite3DbFree(db, zColl); } + sqlite3DbFree(db, zColl); } /* Change the most recently parsed column to be a GENERATED ALWAYS AS @@ -4066,7 +4102,7 @@ void sqlite3CreateIndex( zExtra += nColl; nExtra -= nColl; }else if( j>=0 ){ - zColl = pTab->aCol[j].zCnColl; + zColl = sqlite3ColumnColl(&pTab->aCol[j]); } if( !zColl ) zColl = sqlite3StrBINARY; if( !db->init.busy && !sqlite3LocateCollSeq(pParse, zColl) ){ diff --git a/src/expr.c b/src/expr.c index 0f900c0c6c..34f14e3687 100644 --- a/src/expr.c +++ b/src/expr.c @@ -173,7 +173,7 @@ CollSeq *sqlite3ExprCollSeq(Parse *pParse, const Expr *pExpr){ ** a TK_COLUMN but was previously evaluated and cached in a register */ int j = p->iColumn; if( j>=0 ){ - const char *zColl = p->y.pTab->aCol[j].zCnColl; + const char *zColl = sqlite3ColumnColl(&p->y.pTab->aCol[j]); pColl = sqlite3FindCollSeq(db, ENC(db), zColl, 0); } break; diff --git a/src/fkey.c b/src/fkey.c index 5105b5cc79..5888e558fb 100644 --- a/src/fkey.c +++ b/src/fkey.c @@ -259,7 +259,7 @@ int sqlite3FkLocateIndex( /* If the index uses a collation sequence that is different from ** the default collation sequence for the column, this index is ** unusable. Bail out early in this case. */ - zDfltColl = pParent->aCol[iCol].zCnColl; + zDfltColl = sqlite3ColumnColl(&pParent->aCol[iCol]); if( !zDfltColl ) zDfltColl = sqlite3StrBINARY; if( sqlite3StrICmp(pIdx->azColl[i], zDfltColl) ) break; @@ -487,7 +487,7 @@ static Expr *exprTableRegister( pCol = &pTab->aCol[iCol]; pExpr->iTable = regBase + sqlite3TableColumnToStorage(pTab,iCol) + 1; pExpr->affExpr = pCol->affinity; - zColl = pCol->zCnColl; + zColl = sqlite3ColumnColl(pCol); if( zColl==0 ) zColl = db->pDfltColl->zName; pExpr = sqlite3ExprAddCollateString(pParse, pExpr, zColl); }else{ diff --git a/src/insert.c b/src/insert.c index 06952586b0..0692198b1e 100644 --- a/src/insert.c +++ b/src/insert.c @@ -2843,7 +2843,8 @@ static int xferOptimization( if( pDestCol->affinity!=pSrcCol->affinity ){ return 0; /* Affinity must be the same on all columns */ } - if( sqlite3_stricmp(pDestCol->zCnColl, pSrcCol->zCnColl)!=0 ){ + if( sqlite3_stricmp(sqlite3ColumnColl(pDestCol), + sqlite3ColumnColl(pSrcCol))!=0 ){ return 0; /* Collating sequence must be the same on all columns */ } if( pDestCol->notNull && !pSrcCol->notNull ){ diff --git a/src/main.c b/src/main.c index 3c1191c368..a37301a640 100644 --- a/src/main.c +++ b/src/main.c @@ -3769,7 +3769,7 @@ int sqlite3_table_column_metadata( */ if( pCol ){ zDataType = sqlite3ColumnType(pCol,0); - zCollSeq = pCol->zCnColl; + zCollSeq = sqlite3ColumnColl(pCol); notnull = pCol->notNull!=0; primarykey = (pCol->colFlags & COLFLAG_PRIMKEY)!=0; autoinc = pTab->iPKey==iCol && (pTab->tabFlags & TF_Autoincrement)!=0; diff --git a/src/select.c b/src/select.c index 064ea758d8..375050bdcd 100644 --- a/src/select.c +++ b/src/select.c @@ -2193,8 +2193,9 @@ void sqlite3SelectAddColumnTypeAndCollation( } if( pCol->affinity<=SQLITE_AFF_NONE ) pCol->affinity = aff; pColl = sqlite3ExprCollSeq(pParse, p); - if( pColl && pCol->zCnColl==0 ){ - pCol->zCnColl = sqlite3DbStrDup(db, pColl->zName); + if( pColl && (pCol->colFlags & COLFLAG_HASCOLL)==0 ){ + assert( pTab->pIndex==0 ); + sqlite3ColumnSetColl(db, pCol, pColl->zName); } } pTab->szTabRow = 1; /* Any non-zero value works */ diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 083ba5a335..9f4d211752 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -2028,10 +2028,17 @@ struct Module { ** or equal to the table column index. It is ** equal if and only if there are no VIRTUAL ** columns to the left. +** +** Notes on zCnName: +** The zCnName field stores the name of the column, the datatype of the +** column, and the collating sequence for the column, in that order, all in +** a single allocation. Each string is 0x00 terminated. The datatype +** is only included if the COLFLAG_HASTYPE bit of colFlags is set and the +** collating sequence name is only included if the COLFLAG_HASCOLL bit is +** set. */ struct Column { char *zCnName; /* Name of this column */ - char *zCnColl; /* Collating sequence. If NULL, use the default */ u8 notNull : 4; /* An OE_ code for handling a NOT NULL constraint */ u8 eType : 4; /* One of the standard types */ char affinity; /* One of the SQLITE_AFF_... values */ @@ -2072,6 +2079,7 @@ struct Column { #define COLFLAG_STORED 0x0040 /* GENERATED ALWAYS AS ... STORED */ #define COLFLAG_NOTAVAIL 0x0080 /* STORED column not yet calculated */ #define COLFLAG_BUSY 0x0100 /* Blocks recursion on GENERATED columns */ +#define COLFLAG_HASCOLL 0x0200 /* Has collating sequence name in zCnName */ #define COLFLAG_GENERATED 0x0060 /* Combo: _STORED, _VIRTUAL */ #define COLFLAG_NOINSERT 0x0062 /* Combo: _HIDDEN, _STORED, _VIRTUAL */ @@ -4398,6 +4406,8 @@ void sqlite3CollapseDatabaseArray(sqlite3*); void sqlite3CommitInternalChanges(sqlite3*); void sqlite3ColumnSetExpr(Parse*,Table*,Column*,Expr*); Expr *sqlite3ColumnExpr(Table*,Column*); +void sqlite3ColumnSetColl(sqlite3*,Column*,const char*zColl); +const char *sqlite3ColumnColl(Column*); void sqlite3DeleteColumnNames(sqlite3*,Table*); void sqlite3GenerateColumnNames(Parse *pParse, Select *pSelect); int sqlite3ColumnsFromExprList(Parse*,ExprList*,i16*,Column**); diff --git a/src/wherecode.c b/src/wherecode.c index f3589bb0ac..28b417c9ae 100644 --- a/src/wherecode.c +++ b/src/wherecode.c @@ -1241,8 +1241,9 @@ static void whereIndexExprTrans( #ifndef SQLITE_OMIT_GENERATED_COLUMNS }else if( iRef>=0 && (pTab->aCol[iRef].colFlags & COLFLAG_VIRTUAL)!=0 - && (pTab->aCol[iRef].zCnColl==0 - || sqlite3StrICmp(pTab->aCol[iRef].zCnColl, sqlite3StrBINARY)==0) + && ((pTab->aCol[iRef].colFlags & COLFLAG_HASCOLL)==0 + || sqlite3StrICmp(sqlite3ColumnColl(&pTab->aCol[iRef]), + sqlite3StrBINARY)==0) ){ /* Check to see if there are direct references to generated columns ** that are contained in the index. Pulling the generated column