From b3bf556ef649d070a71ec9d6573c9c583e1cf156 Mon Sep 17 00:00:00 2001 From: danielk1977 Date: Tue, 10 Jan 2006 17:58:23 +0000 Subject: [PATCH] Store collation sequence names instead of pointers in sharable schema data structures. (CVS 2904) FossilOrigin-Name: 0f0213be4d064b3d24e31ff93ec16f6862003d26 --- manifest | 38 +++++----- manifest.uuid | 2 +- src/analyze.c | 6 +- src/build.c | 184 ++++++++++++++++++++++++++++++------------------ src/callback.c | 10 ++- src/delete.c | 9 +-- src/expr.c | 8 ++- src/insert.c | 13 +--- src/pragma.c | 3 +- src/prepare.c | 4 +- src/select.c | 19 +++-- src/sqliteInt.h | 13 ++-- src/update.c | 6 +- src/vdbemem.c | 6 +- src/where.c | 18 ++--- 15 files changed, 196 insertions(+), 143 deletions(-) diff --git a/manifest b/manifest index 681fed375a..e4a6a1e151 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Updates\sto\sthe\sC-API\sdocumentation.\s\sChange\sthe\sparameter\stype\sof\nsqlite3_soft_heap_limit\sto\sinteger.\s(CVS\s2903) -D 2006-01-10T15:18:28 +C Store\scollation\ssequence\snames\sinstead\sof\spointers\sin\ssharable\sschema\sdata\sstructures.\s(CVS\s2904) +D 2006-01-10T17:58:23 F Makefile.in ab3ffd8d469cef4477257169b82810030a6bb967 F Makefile.linux-gcc aee18d8a05546dcf1888bd4547e442008a49a092 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 @@ -31,22 +31,22 @@ F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc F sqlite3.def c413e514217736884254739a105c8c942fdf0c2f F sqlite3.pc.in 985b9bf34192a549d7d370e0f0b6b34a4f61369a F src/alter.c d0dd079b9ef0d551ff4a4ce09ee270c07b307bbb -F src/analyze.c ed87abad3f6f60e1bd5308ed6ff6e0fa396db52b +F src/analyze.c 7d2b7ab9a9c2fd6e55700f69064dfdd3e36d7a8a F src/attach.c 8438a2808f89c01cfd472e676a27d771ac4405aa F src/auth.c cdec356a5cd8b217c346f816c5912221537fe87f F src/btree.c 874eaba6dec1660c7c917d5afc790f69de82cf2e F src/btree.h 5663c4f43e8521546ccebc8fc95acb013b8f3184 -F src/build.c 97997d435acfb9406f776f14931c16559bd534e5 -F src/callback.c 1c2b78a210fda18cdd4d0b604ed41bf0e1f5125c +F src/build.c 59c4a6fc0e89590c7eec3154acb4cf6644674d7d +F src/callback.c 51fe813309f7cf69d3d19a2e7be2103130186efd F src/complete.c df1681cef40dec33a286006981845f87b194e7a4 F src/date.c a927bdbb51296ac398d2f667086a7072c099e5ab -F src/delete.c 66199ba71a0f753033073b080baebb349157c960 +F src/delete.c b242a0d9462d2b7054e38c5250bdbe94d6772a8e F src/experimental.c 50c1e3b34f752f4ac10c36f287db095c2b61766d -F src/expr.c 426717b11cf55cb538ccd3db8a3b22a0f956ce8d +F src/expr.c b90fa835a2216edd6808b4bb5da6bbf3b8ee29b9 F src/func.c e013c3b6c607c6a1654f5260eab59f5609a5ce4a F src/hash.c 8747cf51d12de46512880dfcf1b68b4e24072863 F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84 -F src/insert.c 16610475976dc9b25d231338e283dd4b4362a430 +F src/insert.c 337785137430a012ff0f1c181d4a4d55d2a942d3 F src/legacy.c f651ccd3700f99fa05766ac53506bf9a0694761b F src/main.c 3fe4b606db7d269d7a57c7b51ab3d9ff488e4b98 F src/md5.c c5fdfa5c2593eaee2e32a5ce6c6927c986eaf217 @@ -62,15 +62,15 @@ F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b F src/pager.c f84488fa616f1279761aaf06b0acc42af345d3a5 F src/pager.h e0acb095b3ad0bca48f2ab00c87346665643f64f F src/parse.y 83df51fea35f68f7e07384d75dce83d1ed30434c -F src/pragma.c 05abacaa5a1817a44876d9dbb4790aa7c784427b -F src/prepare.c 41d9a8563e2b988932922c9f96a7bb1271932564 +F src/pragma.c 711992e440ce78569322dd625d2cfe1cd696ccfb +F src/prepare.c 3283bb65b4b217a092c9cbf65014774e6c3a142d F src/printf.c f47a2f4b5387cd2ebb12e9117a1a5d6bd9a2b812 F src/random.c d40f8d356cecbd351ccfab6eaedd7ec1b54f5261 -F src/select.c acfeda959fe07eac04950d945ac7ec0518ef4b7d +F src/select.c 579cfdd250c5598de7c867134f7d35a2099b1dcc F src/server.c 42a2bd02eec5018098a96e08f7a923f4965a2b1d F src/shell.c 66b073375efbdee19045e7e0cd38b85f9aff71da F src/sqlite.h.in 821b93f918d126c54d9a91fc928434945655edc3 -F src/sqliteInt.h f3fe5c8b7d3a7491d6f47f0605b7ed70f146c59f +F src/sqliteInt.h d7584dc5b8e15f1732a195ece9e93049ccde35fa F src/table.c 486dcfce532685b53b5a2b5da8bba0ded6fb2316 F src/tclsqlite.c d650bea0248fc0a310ddc2cb94273a3a5021fddf F src/test1.c 5f634ce9aa452dbcc362993c9612047df800216c @@ -83,7 +83,7 @@ F src/test7.c bfe36c62cae189509660acfeeb891ffb9da8ef0c F src/test_async.c 9733deb7fefa18a3596e5234c1ef05b4685c6ad7 F src/tokenize.c 196486012c871cdcad6cc84a820cc988603f1b9d F src/trigger.c 883b5f3b97137fbe417e3337c3fa20ac8e9c1ae5 -F src/update.c e09da54cb8e042f89f4177f4ef879b594d8ab946 +F src/update.c cd8ad5bb1a29f2056347481308fca4a59f2f4764 F src/utf.c b7bffac4260177ae7f83c01d025fe0f5ed70ce71 F src/util.c 5d5792d4a4dda20d70fdfb973ed8a5ed71fea98c F src/vacuum.c f5a068096b22fad438bf1f1cf69ccb7f9e8cc7fb @@ -93,8 +93,8 @@ F src/vdbeInt.h 5451cf71f229e366ac543607c0a17f36e5737ea9 F src/vdbeapi.c 6d20e92de62b90ae27aeea3a7b18653734b0b1cb F src/vdbeaux.c e4b8f492e41e3b8ecee8f66045e897dae92d1356 F src/vdbefifo.c 9efb94c8c3f4c979ebd0028219483f88e57584f5 -F src/vdbemem.c d712dfd80d58011db688fa8234c1821262a57cae -F src/where.c 18a7a16a5b050b2df6f8b03945313ec0f46dc30c +F src/vdbemem.c 2ada7cae76da9c840cd0d3c01d2b3987d97141c6 +F src/where.c 4fecfccf8f35ec7b325d666f0cd2fb016a53da43 F tclinstaller.tcl 046e3624671962dc50f0481d7c25b38ef803eb42 F test/all.test 90cf64bb655e3d474b0dda04e63ece03e36b0ce2 F test/alter.test b94b640063e725d062b2997bd2810ac39195c718 @@ -340,7 +340,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl a99cf5f6d8bd4d5537584a2b342f0fb9fa601d8b F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513 -P 4f2ec95283f1ae0a28b2f9ce0afc5a7203de87fb -R 6f27b31eddededb37a4ce53e31f18e64 -U drh -Z abf90018e50b865b136d9f985b2b2657 +P bdd35e9fbb651fe7a1ed5042923c9529c3c5ab7c +R 86f043f12b95a158f3793bd5117e0f9d +U danielk1977 +Z 598f1f083965de59648a9c0d25b3df80 diff --git a/manifest.uuid b/manifest.uuid index 367af7c8c5..6dee7c9d14 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -bdd35e9fbb651fe7a1ed5042923c9529c3c5ab7c \ No newline at end of file +0f0213be4d064b3d24e31ff93ec16f6862003d26 \ No newline at end of file diff --git a/src/analyze.c b/src/analyze.c index ba07b7bd2d..3d27134e4a 100644 --- a/src/analyze.c +++ b/src/analyze.c @@ -11,7 +11,7 @@ ************************************************************************* ** This file contains code associated with the ANALYZE command. ** -** @(#) $Id: analyze.c,v 1.15 2006/01/09 06:29:48 danielk1977 Exp $ +** @(#) $Id: analyze.c,v 1.16 2006/01/10 17:58:23 danielk1977 Exp $ */ #ifndef SQLITE_OMIT_ANALYZE #include "sqliteInt.h" @@ -114,13 +114,15 @@ static void analyzeOneTable( iIdxCur = pParse->nTab; for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ + KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx); + /* Open a cursor to the index to be analyzed */ assert( iDb==sqlite3SchemaToIndex(pParse->db, pIdx->pSchema) ); sqlite3VdbeAddOp(v, OP_Integer, iDb, 0); VdbeComment((v, "# %s", pIdx->zName)); sqlite3VdbeOp3(v, OP_OpenRead, iIdxCur, pIdx->tnum, - (char*)&pIdx->keyInfo, P3_KEYINFO); + (char *)pKey, P3_KEYINFO_HANDOFF); nCol = pIdx->nColumn; if( iMem+nCol*2>=pParse->nMem ){ pParse->nMem = iMem+nCol*2+1; diff --git a/src/build.c b/src/build.c index 3fd4308f12..e7c1742e29 100644 --- a/src/build.c +++ b/src/build.c @@ -22,7 +22,7 @@ ** COMMIT ** ROLLBACK ** -** $Id: build.c,v 1.374 2006/01/10 07:14:23 danielk1977 Exp $ +** $Id: build.c,v 1.375 2006/01/10 17:58:23 danielk1977 Exp $ */ #include "sqliteInt.h" #include @@ -468,6 +468,7 @@ static void sqliteResetColumnNames(Table *pTable){ sqliteFree(pCol->zName); sqlite3ExprDelete(pCol->pDflt); sqliteFree(pCol->zType); + sqliteFree(pCol->zColl); } sqliteFree(pTable->aCol); } @@ -938,7 +939,6 @@ void sqlite3AddColumn(Parse *pParse, Token *pName){ ** be called next to set pCol->affinity correctly. */ pCol->affinity = SQLITE_AFF_NONE; - pCol->pColl = pParse->db->pDfltColl; p->nCol++; } @@ -1167,41 +1167,26 @@ void sqlite3AddCheckConstraint( */ void sqlite3AddCollateType(Parse *pParse, const char *zType, int nType){ Table *p; - Index *pIdx; - CollSeq *pColl; int i; if( (p = pParse->pNewTable)==0 ) return; i = p->nCol-1; - pColl = sqlite3LocateCollSeq(pParse, zType, nType); - p->aCol[i].pColl = pColl; - - /* If the column is declared as " PRIMARY KEY COLLATE ", - ** then an index may have been created on this column before the - ** collation type was added. Correct this if it is the case. - */ - for(pIdx = p->pIndex; pIdx; pIdx=pIdx->pNext){ - assert( pIdx->nColumn==1 ); - if( pIdx->aiColumn[0]==i ) pIdx->keyInfo.aColl[0] = pColl; - } -} - -/* -** Call sqlite3CheckCollSeq() for all collating sequences in an index, -** in order to verify that all the necessary collating sequences are -** loaded. -*/ -int sqlite3CheckIndexCollSeq(Parse *pParse, Index *pIdx){ - if( pIdx ){ - int i; - for(i=0; inColumn; i++){ - if( sqlite3CheckCollSeq(pParse, pIdx->keyInfo.aColl[i]) ){ - return SQLITE_ERROR; + if( sqlite3LocateCollSeq(pParse, zType, nType) ){ + Index *pIdx; + p->aCol[i].zColl = sqlite3StrNDup(zType, nType); + + /* If the column is declared as " PRIMARY KEY COLLATE ", + ** then an index may have been created on this column before the + ** collation type was added. Correct this if it is the case. + */ + for(pIdx=p->pIndex; pIdx; pIdx=pIdx->pNext){ + assert( pIdx->nColumn==1 ); + if( pIdx->aiColumn[0]==i ){ + pIdx->azColl[0] = p->aCol[i].zColl; } } } - return SQLITE_OK; } /* @@ -1222,8 +1207,9 @@ CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName, int nName){ sqlite3 *db = pParse->db; u8 enc = ENC(db); u8 initbusy = db->init.busy; + CollSeq *pColl; - CollSeq *pColl = sqlite3FindCollSeq(db, enc, zName, nName, initbusy); + pColl = sqlite3FindCollSeq(db, enc, zName, nName, initbusy); if( !initbusy && (!pColl || !pColl->xCmp) ){ pColl = sqlite3GetCollSeq(db, pColl, zName, nName); if( !pColl ){ @@ -2131,6 +2117,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ int addr1; /* Address of top of loop */ int tnum; /* Root page of index */ Vdbe *v; /* Generate code into this virtual machine */ + KeyInfo *pKey; /* KeyInfo for index */ int iDb = sqlite3SchemaToIndex(pParse->db, pIndex->pSchema); #ifndef SQLITE_OMIT_AUTHORIZATION @@ -2140,14 +2127,6 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ } #endif - /* Ensure all the required collation sequences are available. This - ** routine will invoke the collation-needed callback if necessary (and - ** if one has been registered). - */ - if( sqlite3CheckIndexCollSeq(pParse, pIndex) ){ - return; - } - /* Require a write-lock on the table to perform this operation */ sqlite3TableLock(pParse, iDb, pTab->tnum, 1, pTab->zName); @@ -2161,8 +2140,8 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ sqlite3VdbeAddOp(v, OP_Clear, tnum, iDb); } sqlite3VdbeAddOp(v, OP_Integer, iDb, 0); - sqlite3VdbeOp3(v, OP_OpenWrite, iIdx, tnum, - (char*)&pIndex->keyInfo, P3_KEYINFO); + pKey = sqlite3IndexKeyinfo(pParse, pIndex); + sqlite3VdbeOp3(v, OP_OpenWrite, iIdx, tnum, (char *)pKey, P3_KEYINFO_HANDOFF); sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead); addr1 = sqlite3VdbeAddOp(v, OP_Rewind, iTab, 0); sqlite3GenerateIndexKey(v, pIndex, iTab); @@ -2221,6 +2200,9 @@ void sqlite3CreateIndex( int iDb; /* Index of the database that is being written */ Token *pName = 0; /* Unqualified name of the index to create */ struct ExprList_item *pListItem; /* For looping over pList */ + int nCol; + int nExtra = 0; + char *zExtra; if( pParse->nErr || sqlite3ThreadData()->mallocFailed ){ goto exit_create_index; @@ -2352,17 +2334,37 @@ void sqlite3CreateIndex( pList->a[0].sortOrder = sortOrder; } + /* Figure out how many bytes of space are required to store explicitly + ** specified collation sequence names. + */ + for(i=0; inExpr; i++){ + Expr *pExpr = pList->a[i].pExpr; + if( pExpr ){ + nExtra += (1 + strlen(pExpr->pColl->zName)); + } + } + /* ** Allocate the index structure. */ nName = strlen(zName); - pIndex = sqliteMalloc( sizeof(Index) + nName + 2 + sizeof(int) + - (sizeof(int)*2 + sizeof(CollSeq*) + 1)*pList->nExpr ); + nCol = pList->nExpr; + pIndex = sqliteMalloc( + sizeof(Index) + /* Index structure */ + sizeof(int)*nCol + /* Index.aiColumn */ + sizeof(int)*(nCol+1) + /* Index.aiRowEst */ + sizeof(char *)*nCol + /* Index.azColl */ + sizeof(u8)*nCol + /* Index.aSortOrder */ + nName + 1 + /* Index.zName */ + nExtra /* Collation sequence names */ + ); if( sqlite3ThreadData()->mallocFailed ) goto exit_create_index; - pIndex->aiColumn = (int*)&pIndex->keyInfo.aColl[pList->nExpr]; - pIndex->aiRowEst = (unsigned*)&pIndex->aiColumn[pList->nExpr]; - pIndex->zName = (char*)&pIndex->aiRowEst[pList->nExpr+1]; - pIndex->keyInfo.aSortOrder = &pIndex->zName[nName+1]; + pIndex->aiColumn = (int *)(&pIndex[1]); + pIndex->aiRowEst = (int *)(&pIndex->aiColumn[nCol]); + pIndex->azColl = (char **)(&pIndex->aiRowEst[nCol+1]); + pIndex->aSortOrder = (u8 *)(&pIndex->azColl[nCol]); + pIndex->zName = (char *)(&pIndex->aSortOrder[nCol]); + zExtra = (char *)(&pIndex->zName[nName+1]); strcpy(pIndex->zName, zName); pIndex->pTable = pTab; pIndex->nColumn = pList->nExpr; @@ -2386,6 +2388,8 @@ void sqlite3CreateIndex( const char *zColName = pListItem->zName; Column *pTabCol; int requestedSortOrder; + char *zColl; /* Collation sequence */ + for(j=0, pTabCol=pTab->aCol; jnCol; j++, pTabCol++){ if( sqlite3StrICmp(zColName, pTabCol->zName)==0 ) break; } @@ -2397,20 +2401,22 @@ void sqlite3CreateIndex( pIndex->aiColumn[i] = j; if( pListItem->pExpr ){ assert( pListItem->pExpr->pColl ); - pIndex->keyInfo.aColl[i] = pListItem->pExpr->pColl; + zColl = zExtra; + strcpy(zExtra, pListItem->pExpr->pColl->zName); + zExtra += (strlen(zColl) + 1); }else{ - pIndex->keyInfo.aColl[i] = pTab->aCol[j].pColl; + zColl = pTab->aCol[j].zColl; + if( !zColl ){ + zColl = db->pDfltColl->zName; + } } - assert( pIndex->keyInfo.aColl[i] ); - if( !db->init.busy && - sqlite3CheckCollSeq(pParse, pIndex->keyInfo.aColl[i]) - ){ + if( !db->init.busy && !sqlite3LocateCollSeq(pParse, zColl, -1) ){ goto exit_create_index; } + pIndex->azColl[i] = zColl; requestedSortOrder = pListItem->sortOrder & sortOrderMask; - pIndex->keyInfo.aSortOrder[i] = requestedSortOrder; + pIndex->aSortOrder[i] = requestedSortOrder; } - pIndex->keyInfo.nField = pList->nExpr; sqlite3DefaultRowEst(pIndex); if( pTab==pParse->pNewTable ){ @@ -2436,9 +2442,11 @@ void sqlite3CreateIndex( if( pIdx->nColumn!=pIndex->nColumn ) continue; for(k=0; knColumn; k++){ + const char *z1 = pIdx->azColl[k]; + const char *z2 = pIndex->azColl[k]; if( pIdx->aiColumn[k]!=pIndex->aiColumn[k] ) break; - if( pIdx->keyInfo.aColl[k]!=pIndex->keyInfo.aColl[k] ) break; - if( pIdx->keyInfo.aSortOrder[k]!=pIndex->keyInfo.aSortOrder[k] ) break; + if( pIdx->aSortOrder[k]!=pIndex->aSortOrder[k] ) break; + if( z1!=z2 && sqlite3StrICmp(z1, z2) ) break; } if( k==pIdx->nColumn ){ if( pIdx->onError!=pIndex->onError ){ @@ -3054,12 +3062,13 @@ void sqlite3BeginWriteOperation(Parse *pParse, int setStatement, int iDb){ ** true if it does and false if it does not. */ #ifndef SQLITE_OMIT_REINDEX -static int collationMatch(CollSeq *pColl, Index *pIndex){ - int n = pIndex->keyInfo.nField; - CollSeq **pp = pIndex->keyInfo.aColl; - while( n-- ){ - if( *pp==pColl ) return 1; - pp++; +static int collationMatch(const char *zColl, Index *pIndex){ + int i; + for(i=0; inColumn; i++){ + const char *z = pIndex->azColl[i]; + if( z==zColl || (z && zColl && 0==sqlite3StrICmp(z, zColl)) ){ + return 1; + } } return 0; } @@ -3070,11 +3079,11 @@ static int collationMatch(CollSeq *pColl, Index *pIndex){ ** If pColl==0 then recompute all indices of pTab. */ #ifndef SQLITE_OMIT_REINDEX -static void reindexTable(Parse *pParse, Table *pTab, CollSeq *pColl){ +static void reindexTable(Parse *pParse, Table *pTab, char const *zColl){ Index *pIndex; /* An index associated with pTab */ for(pIndex=pTab->pIndex; pIndex; pIndex=pIndex->pNext){ - if( pColl==0 || collationMatch(pColl,pIndex) ){ + if( zColl==0 || collationMatch(zColl, pIndex) ){ int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); sqlite3BeginWriteOperation(pParse, 0, iDb); sqlite3RefillIndex(pParse, pIndex, -1); @@ -3089,7 +3098,7 @@ static void reindexTable(Parse *pParse, Table *pTab, CollSeq *pColl){ ** all indices everywhere. */ #ifndef SQLITE_OMIT_REINDEX -static void reindexDatabases(Parse *pParse, CollSeq *pColl){ +static void reindexDatabases(Parse *pParse, char const *zColl){ Db *pDb; /* A single database */ int iDb; /* The database index number */ sqlite3 *db = pParse->db; /* The database connection */ @@ -3100,7 +3109,7 @@ static void reindexDatabases(Parse *pParse, CollSeq *pColl){ if( pDb==0 ) continue; for(k=sqliteHashFirst(&pDb->pSchema->tblHash); k; k=sqliteHashNext(k)){ pTab = (Table*)sqliteHashData(k); - reindexTable(pParse, pTab, pColl); + reindexTable(pParse, pTab, zColl); } } } @@ -3140,9 +3149,14 @@ void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){ reindexDatabases(pParse, 0); return; }else if( pName2==0 || pName2->z==0 ){ + assert( pName1->z ); pColl = sqlite3FindCollSeq(db, ENC(db), (char*)pName1->z, pName1->n, 0); if( pColl ){ - reindexDatabases(pParse, pColl); + char *z = sqlite3StrNDup(pName1->z, pName1->n); + if( z ){ + reindexDatabases(pParse, z); + sqliteFree(z); + } return; } } @@ -3166,3 +3180,39 @@ void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){ sqlite3ErrorMsg(pParse, "unable to identify the object to be reindexed"); } #endif + +/* +** Return a dynamicly allocated KeyInfo structure that can be used +** with OP_OpenRead or OP_OpenWrite to access database index pIdx. +** +** If successful, a pointer to the new structure is returned. In this case +** the caller is responsible for calling sqliteFree() on the returned +** pointer. If an error occurs (out of memory or missing collation +** sequence), NULL is returned and the state of pParse updated to reflect +** the error. +*/ +KeyInfo *sqlite3IndexKeyinfo(Parse *pParse, Index *pIdx){ + int i; + int nCol = pIdx->nColumn; + int nBytes = sizeof(KeyInfo) + (nCol-1)*sizeof(CollSeq*) + nCol; + KeyInfo *pKey = (KeyInfo *)sqliteMalloc(nBytes); + + if( pKey ){ + pKey->aSortOrder = (u8 *)&(pKey->aColl[nCol]); + assert( &pKey->aSortOrder[nCol]==&(((u8 *)pKey)[nBytes]) ); + for(i=0; iazColl[i]; + assert( zColl ); + pKey->aColl[i] = sqlite3LocateCollSeq(pParse, zColl, -1); + pKey->aSortOrder[i] = pIdx->aSortOrder[i]; + } + pKey->nField = nCol; + } + + if( pParse->nErr ){ + sqliteFree(pKey); + pKey = 0; + } + return pKey; +} + diff --git a/src/callback.c b/src/callback.c index bd8e28eeb6..a1bf577895 100644 --- a/src/callback.c +++ b/src/callback.c @@ -13,7 +13,7 @@ ** This file contains functions used to access the internal hash tables ** of user defined functions and collation sequences. ** -** $Id: callback.c,v 1.9 2006/01/09 16:12:05 danielk1977 Exp $ +** $Id: callback.c,v 1.10 2006/01/10 17:58:23 danielk1977 Exp $ */ #include "sqliteInt.h" @@ -130,6 +130,7 @@ int sqlite3CheckCollSeq(Parse *pParse, CollSeq *pColl){ pParse->nErr++; return SQLITE_ERROR; } + assert( p==pColl ); } return SQLITE_OK; } @@ -199,7 +200,12 @@ CollSeq *sqlite3FindCollSeq( int nName, int create ){ - CollSeq *pColl = findCollSeqEntry(db, zName, nName, create); + CollSeq *pColl; + if( zName ){ + pColl = findCollSeqEntry(db, zName, nName, create); + }else{ + pColl = db->pDfltColl; + } assert( SQLITE_UTF8==1 && SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 ); assert( enc>=SQLITE_UTF8 && enc<=SQLITE_UTF16BE ); if( pColl ) pColl += enc-1; diff --git a/src/delete.c b/src/delete.c index fd5065d544..c1bc529986 100644 --- a/src/delete.c +++ b/src/delete.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** in order to generate code for DELETE FROM statements. ** -** $Id: delete.c,v 1.116 2006/01/09 06:29:48 danielk1977 Exp $ +** $Id: delete.c,v 1.117 2006/01/10 17:58:23 danielk1977 Exp $ */ #include "sqliteInt.h" @@ -236,13 +236,6 @@ void sqlite3DeleteFrom( ** the table and pick which records to delete. */ else{ - /* Ensure all required collation sequences are available. */ - for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ - if( sqlite3CheckIndexCollSeq(pParse, pIdx) ){ - goto delete_from_cleanup; - } - } - /* Begin the database scan */ pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0); diff --git a/src/expr.c b/src/expr.c index d3c31f1588..fa7be8c35d 100644 --- a/src/expr.c +++ b/src/expr.c @@ -12,7 +12,7 @@ ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. ** -** $Id: expr.c,v 1.246 2006/01/09 16:12:05 danielk1977 Exp $ +** $Id: expr.c,v 1.247 2006/01/10 17:58:23 danielk1977 Exp $ */ #include "sqliteInt.h" #include @@ -867,6 +867,7 @@ static int lookupName( } for(j=0, pCol=pTab->aCol; jnCol; j++, pCol++){ if( sqlite3StrICmp(pCol->zName, zCol)==0 ){ + const char *zColl = pTab->aCol[j].zColl; IdList *pUsing; cnt++; pExpr->iTable = pItem->iCursor; @@ -875,7 +876,7 @@ static int lookupName( /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */ pExpr->iColumn = j==pTab->iPKey ? -1 : j; pExpr->affinity = pTab->aCol[j].affinity; - pExpr->pColl = pTab->aCol[j].pColl; + pExpr->pColl = sqlite3FindCollSeq(db, ENC(db), zColl,-1, 0); if( pItem->jointype & JT_NATURAL ){ /* If this match occurred in the left table of a natural join, ** then skip the right table to avoid a duplicate match */ @@ -926,10 +927,11 @@ static int lookupName( cntTab++; for(j=0; j < pTab->nCol; j++, pCol++) { if( sqlite3StrICmp(pCol->zName, zCol)==0 ){ + const char *zColl = pTab->aCol[j].zColl; cnt++; pExpr->iColumn = j==pTab->iPKey ? -1 : j; pExpr->affinity = pTab->aCol[j].affinity; - pExpr->pColl = pTab->aCol[j].pColl; + pExpr->pColl = sqlite3FindCollSeq(db, ENC(db), zColl,-1, 0); pExpr->pTab = pTab; break; } diff --git a/src/insert.c b/src/insert.c index b1191eb7d0..3d4c460b65 100644 --- a/src/insert.c +++ b/src/insert.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle INSERT statements in SQLite. ** -** $Id: insert.c,v 1.155 2006/01/09 06:29:48 danielk1977 Exp $ +** $Id: insert.c,v 1.156 2006/01/10 17:58:23 danielk1977 Exp $ */ #include "sqliteInt.h" @@ -275,13 +275,6 @@ void sqlite3Insert( goto insert_cleanup; } - /* Ensure all required collation sequences are available. */ - for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ - if( sqlite3CheckIndexCollSeq(pParse, pIdx) ){ - goto insert_cleanup; - } - } - /* Allocate a VDBE */ v = sqlite3GetVdbe(pParse); @@ -1108,11 +1101,11 @@ void sqlite3OpenTableAndIndices( assert( v!=0 ); sqlite3OpenTable(pParse, base, iDb, pTab, op); for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ + KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx); assert( pIdx->pSchema==pTab->pSchema ); sqlite3VdbeAddOp(v, OP_Integer, iDb, 0); VdbeComment((v, "# %s", pIdx->zName)); - sqlite3VdbeOp3(v, op, i+base, pIdx->tnum, - (char*)&pIdx->keyInfo, P3_KEYINFO); + sqlite3VdbeOp3(v, op, i+base, pIdx->tnum, (char*)pKey, P3_KEYINFO_HANDOFF); } if( pParse->nTab<=base+i ){ pParse->nTab = base+i; diff --git a/src/pragma.c b/src/pragma.c index ff694146d3..b9f510cd7a 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -11,7 +11,7 @@ ************************************************************************* ** This file contains code used to implement the PRAGMA command. ** -** $Id: pragma.c,v 1.111 2006/01/09 16:12:05 danielk1977 Exp $ +** $Id: pragma.c,v 1.112 2006/01/10 17:58:23 danielk1977 Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -670,7 +670,6 @@ void sqlite3Pragma( sqlite3VdbeAddOp(v, OP_Integer, pTab->tnum, 0); cnt++; for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ - if( sqlite3CheckIndexCollSeq(pParse, pIdx) ) goto pragma_out; sqlite3VdbeAddOp(v, OP_Integer, pIdx->tnum, 0); cnt++; } diff --git a/src/prepare.c b/src/prepare.c index 4efdf1fec5..c59d7fc82a 100644 --- a/src/prepare.c +++ b/src/prepare.c @@ -13,7 +13,7 @@ ** interface, and routines that contribute to loading the database schema ** from disk. ** -** $Id: prepare.c,v 1.17 2006/01/09 16:12:05 danielk1977 Exp $ +** $Id: prepare.c,v 1.18 2006/01/10 17:58:23 danielk1977 Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -262,7 +262,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ if( iDb==0 ){ /* If opening the main database, set ENC(db). */ ENC(db) = (u8)meta[4]; - db->pDfltColl = sqlite3FindCollSeq(db, ENC(db), "BINARY", 6, 0); + db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, "BINARY", 6, 0); }else{ /* If opening an attached database, the encoding much match ENC(db) */ if( meta[4]!=ENC(db) ){ diff --git a/src/select.c b/src/select.c index 0b401b392d..145f319b08 100644 --- a/src/select.c +++ b/src/select.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** -** $Id: select.c,v 1.291 2006/01/09 16:12:05 danielk1977 Exp $ +** $Id: select.c,v 1.292 2006/01/10 17:58:23 danielk1977 Exp $ */ #include "sqliteInt.h" @@ -978,6 +978,7 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){ char *zType; char *zName; char *zBasename; + CollSeq *pColl; int cnt; NameContext sNC; @@ -1030,9 +1031,9 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){ zType = sqliteStrDup(columnType(&sNC, p)); pCol->zType = zType; pCol->affinity = sqlite3ExprAffinity(p); - pCol->pColl = sqlite3ExprCollSeq(pParse, p); - if( !pCol->pColl ){ - pCol->pColl = pParse->db->pDfltColl; + pColl = sqlite3ExprCollSeq(pParse, p); + if( pColl ){ + pCol->zColl = sqlite3StrDup(pColl->zName); } } pTab->iPKey = -1; @@ -2278,7 +2279,10 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){ CollSeq *pColl = sqlite3ExprCollSeq(pParse, pExpr); for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ assert( pIdx->nColumn>=1 ); - if( pIdx->aiColumn[0]==iCol && pIdx->keyInfo.aColl[0]==pColl ) break; + if( pIdx->aiColumn[0]==iCol && + 0==sqlite3StrICmp(pIdx->azColl[0], pColl->zName) ){ + break; + } } if( pIdx==0 ) return 0; } @@ -2321,11 +2325,12 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){ ** "INSERT INTO x SELECT max() FROM x". */ int iIdx; + KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx); iIdx = pParse->nTab++; assert( pIdx->pSchema==pTab->pSchema ); sqlite3VdbeAddOp(v, OP_Integer, iDb, 0); - sqlite3VdbeOp3(v, OP_OpenRead, iIdx, pIdx->tnum, - (char*)&pIdx->keyInfo, P3_KEYINFO); + sqlite3VdbeOp3(v, OP_OpenRead, iIdx, pIdx->tnum, + (char*)pKey, P3_KEYINFO_HANDOFF); if( seekOp==OP_Rewind ){ sqlite3VdbeAddOp(v, OP_Null, 0, 0); sqlite3VdbeAddOp(v, OP_MakeRecord, 1, 0); diff --git a/src/sqliteInt.h b/src/sqliteInt.h index f3a9227f7d..5dc84f2dec 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.459 2006/01/10 15:18:28 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.460 2006/01/10 17:58:23 danielk1977 Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ @@ -584,7 +584,7 @@ struct Column { char *zName; /* Name of this column */ Expr *pDflt; /* Default value of this column */ char *zType; /* Data type for this column */ - CollSeq *pColl; /* Collating sequence. If NULL, use the default */ + char *zColl; /* Collating sequence. If NULL, use the default */ u8 notNull; /* True if there is a NOT NULL constraint */ u8 isPrimKey; /* True if this column is part of the PRIMARY KEY */ char affinity; /* One of the SQLITE_AFF_... values */ @@ -600,7 +600,7 @@ struct Column { ** processes text encoded in UTF-16 (CollSeq.xCmp16), using the machine ** native byte order. When a collation sequence is invoked, SQLite selects ** the version that will require the least expensive encoding -** transalations, if any. +** translations, if any. ** ** The CollSeq.pUser member variable is an extra parameter that passed in ** as the first argument to the UTF-8 comparison function, xCmp. @@ -845,11 +845,11 @@ struct Index { int tnum; /* Page containing root of this index in database file */ u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */ u8 autoIndex; /* True if is automatically created (ex: by UNIQUE) */ - // u8 iDb; /* Index in sqlite.aDb[] of where this index is stored */ char *zColAff; /* String defining the affinity of each column */ Index *pNext; /* The next index associated with the same table */ - Schema *pSchema; - KeyInfo keyInfo; /* Info on how to order keys. MUST BE LAST */ + Schema *pSchema; /* Schema containing this index */ + u8 *aSortOrder; /* Array of size Index.nColumn. True==DESC, False==ASC */ + char **azColl; /* Array of collation sequence names for index */ }; /* @@ -1736,6 +1736,7 @@ void sqlite3MinimumFileFormat(Parse*, int, int); void sqlite3SchemaFree(void *); Schema *sqlite3SchemaGet(Btree *); int sqlite3SchemaToIndex(sqlite3 *db, Schema *); +KeyInfo *sqlite3IndexKeyinfo(Parse *, Index *); #ifndef SQLITE_OMIT_SHARED_CACHE void sqlite3TableLock(Parse *, int, int, u8, const char *); diff --git a/src/update.c b/src/update.c index 3c8cb61a83..c44e24e1eb 100644 --- a/src/update.c +++ b/src/update.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle UPDATE statements. ** -** $Id: update.c,v 1.118 2006/01/09 16:12:05 danielk1977 Exp $ +** $Id: update.c,v 1.119 2006/01/10 17:58:23 danielk1977 Exp $ */ #include "sqliteInt.h" @@ -233,7 +233,6 @@ void sqlite3Update( } } if( inColumn ){ - if( sqlite3CheckIndexCollSeq(pParse, pIdx) ) goto update_cleanup; apIdx[nIdx++] = pIdx; aIdxUsed[j] = 1; }else{ @@ -378,9 +377,10 @@ void sqlite3Update( } for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ if( openAll || aIdxUsed[i] ){ + KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx); sqlite3VdbeAddOp(v, OP_Integer, iDb, 0); sqlite3VdbeOp3(v, OP_OpenWrite, iCur+i+1, pIdx->tnum, - (char*)&pIdx->keyInfo, P3_KEYINFO); + (char*)pKey, P3_KEYINFO_HANDOFF); assert( pParse->nTab>iCur+i+1 ); } } diff --git a/src/vdbemem.c b/src/vdbemem.c index e7b5b0d632..e3463352f8 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -579,9 +579,9 @@ int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){ assert( pMem1->enc==SQLITE_UTF8 || pMem1->enc==SQLITE_UTF16LE || pMem1->enc==SQLITE_UTF16BE ); - /* This assert may fail if the collation sequence is deleted after this - ** vdbe program is compiled. The documentation defines this as an - ** undefined condition. A crash is usual result. + /* The collation sequence must be defined at this point, even if + ** the user deletes the collation sequence after the vdbe program is + ** compiled (this was not always the case). */ assert( !pColl || pColl->xCmp ); diff --git a/src/where.c b/src/where.c index 104a7892e6..e427e62c12 100644 --- a/src/where.c +++ b/src/where.c @@ -16,7 +16,7 @@ ** so is applicable. Because this module is responsible for selecting ** indices, you might also think of this module as the "query optimizer". ** -** $Id: where.c,v 1.192 2006/01/09 06:29:49 danielk1977 Exp $ +** $Id: where.c,v 1.193 2006/01/10 17:58:23 danielk1977 Exp $ */ #include "sqliteInt.h" @@ -450,7 +450,7 @@ static WhereTerm *findTerm( } for(k=0; knColumn && pIdx->aiColumn[k]!=iColumn; k++){} assert( knColumn ); - if( pColl!=pIdx->keyInfo.aColl[k] ) continue; + if( sqlite3StrICmp(pColl->zName, pIdx->azColl[k]) ) continue; } return pTerm; } @@ -810,7 +810,8 @@ static int isSortingIndex( } pColl = sqlite3ExprCollSeq(pParse, pExpr); if( !pColl ) pColl = db->pDfltColl; - if( pExpr->iColumn!=pIdx->aiColumn[i] || pColl!=pIdx->keyInfo.aColl[i] ){ + if( pExpr->iColumn!=pIdx->aiColumn[i] || + sqlite3StrICmp(pColl->zName, pIdx->azColl[i]) ){ /* Term j of the ORDER BY clause does not match column i of the index */ if( ikeyInfo.aSortOrder!=0 ); + assert( pIdx->aSortOrder!=0 ); assert( pTerm->sortOrder==0 || pTerm->sortOrder==1 ); - assert( pIdx->keyInfo.aSortOrder[i]==0 || pIdx->keyInfo.aSortOrder[i]==1 ); - termSortOrder = pIdx->keyInfo.aSortOrder[i] ^ pTerm->sortOrder; + assert( pIdx->aSortOrder[i]==0 || pIdx->aSortOrder[i]==1 ); + termSortOrder = pIdx->aSortOrder[i] ^ pTerm->sortOrder; if( i>nEqCol ){ if( termSortOrder!=sortOrder ){ /* Indices can only be used if all ORDER BY terms past the @@ -1586,11 +1587,12 @@ WhereInfo *sqlite3WhereBegin( } pLevel->iTabCur = pTabItem->iCursor; if( (pIx = pLevel->pIdx)!=0 ){ + KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIx); assert( pIx->pSchema==pTab->pSchema ); sqlite3VdbeAddOp(v, OP_Integer, iDb, 0); VdbeComment((v, "# %s", pIx->zName)); sqlite3VdbeOp3(v, OP_OpenRead, iIdxCur, pIx->tnum, - (char*)&pIx->keyInfo, P3_KEYINFO); + (char*)pKey, P3_KEYINFO_HANDOFF); } if( (pLevel->flags & WHERE_IDX_ONLY)!=0 ){ sqlite3VdbeAddOp(v, OP_SetNumColumns, iIdxCur, pIx->nColumn+1); @@ -1747,7 +1749,7 @@ WhereInfo *sqlite3WhereBegin( ** index the operators are reversed. */ nNotNull = nEq + topLimit; - if( pIdx->keyInfo.aSortOrder[nEq]==SQLITE_SO_ASC ){ + if( pIdx->aSortOrder[nEq]==SQLITE_SO_ASC ){ topOp = WO_LT|WO_LE; btmOp = WO_GT|WO_GE; }else{ -- 2.47.2