diff --git a/ext/ota/sqlite3ota.c b/ext/ota/sqlite3ota.c index fcf0c8b9fd..aca28e2e3b 100644 --- a/ext/ota/sqlite3ota.c +++ b/ext/ota/sqlite3ota.c @@ -401,11 +401,46 @@ static int otaObjIterGetCols(sqlite3ota *p, OtaObjIter *pIter){ return p->rc; } +/* +** This function constructs and returns a pointer to a nul-terminated +** string containing some SQL clause or list based on one or more of the +** column names currently stored in the pIter->azTblCol[] array. +** +** If an OOM error is encountered, NULL is returned and an error code +** left in the OTA handle passed as the first argument. Otherwise, a pointer +** to the allocated string buffer is returned. It is the responsibility +** of the caller to eventually free this buffer using sqlite3_free(). +** +** The number of column names to include in the returned string is passed +** as the third argument. +** +** If arguments aiCol and azCollate are both NULL, then the returned string +** contains the first nCol column names as a comma-separated list. For +** example: +** +** "a", "b", "c" +** +** If argument aiCol is not NULL, it must point to an array containing nCol +** entries - the index of each column name to include in the comma-separated +** list. For example, if aiCol[] contains {2, 0, 1), then the returned +** string is changed to: +** +** "c", "a", "b" +** +** If azCollate is not NULL, it must also point to an array containing nCol +** entries - collation sequence names to associated with each element of +** the comma separated list. For example, ef azCollate[] contains +** {"BINARY", "NOCASE", "REVERSE"}, then the retuned string is: +** +** "c" COLLATE "BINARY", "a" COLLATE "NOCASE", "b" COLLATE "REVERSE" +** +*/ static char *otaObjIterGetCollist( - sqlite3ota *p, - OtaObjIter *pIter, - int nCol, - int *aiCol + sqlite3ota *p, /* OTA object */ + OtaObjIter *pIter, /* Object iterator for column names */ + int nCol, /* Number of column names */ + int *aiCol, /* Array of nCol column indexes */ + const char **azCollate /* Array of nCol collation sequence names */ ){ char *zList = 0; if( p->rc==SQLITE_OK ){ @@ -414,6 +449,9 @@ static char *otaObjIterGetCollist( for(i=0; i<nCol; i++){ int iCol = aiCol ? aiCol[i] : i; zList = sqlite3_mprintf("%z%s%s", zList, zSep, pIter->azTblCol[iCol]); + if( zList && azCollate ){ + zList = sqlite3_mprintf("%z COLLATE %Q", zList, azCollate[i]); + } zSep = ", "; if( zList==0 ){ p->rc = SQLITE_NOMEM; @@ -548,21 +586,22 @@ static int otaObjIterPrepareAll( if( zIdx ){ int *aiCol; /* Column map */ + const char **azColl; /* Collation sequences */ /* Create the index writers */ if( p->rc==SQLITE_OK ){ p->rc = sqlite3_index_writer( - p->db, 0, zIdx, &pIter->pInsert, &aiCol, &pIter->nCol + p->db, 0, zIdx, &pIter->pInsert, &azColl, &aiCol, &pIter->nCol ); } if( p->rc==SQLITE_OK ){ p->rc = sqlite3_index_writer( - p->db, 1, zIdx, &pIter->pDelete, &aiCol, &pIter->nCol + p->db, 1, zIdx, &pIter->pDelete, &azColl, &aiCol, &pIter->nCol ); } /* Create the SELECT statement to read keys in sorted order */ - zCollist = otaObjIterGetCollist(p, pIter, pIter->nCol, aiCol); + zCollist = otaObjIterGetCollist(p, pIter, pIter->nCol, aiCol, azColl); if( p->rc==SQLITE_OK ){ p->rc = prepareFreeAndCollectError(p->db, &pIter->pSelect, pz, sqlite3_mprintf( @@ -582,7 +621,7 @@ static int otaObjIterPrepareAll( char *zWhere = otaObjIterGetWhere(p, pIter); char *zOldlist = otaObjIterGetOldlist(p, pIter, "old"); char *zNewlist = otaObjIterGetOldlist(p, pIter, "new"); - zCollist = otaObjIterGetCollist(p, pIter, pIter->nTblCol, 0); + zCollist = otaObjIterGetCollist(p, pIter, pIter->nTblCol, 0, 0); pIter->nCol = pIter->nTblCol; /* Create the SELECT statement to read keys from data_xxx */ diff --git a/manifest b/manifest index 344ec70e00..9496fcd9a5 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Have\sthe\ssqlite3_index_writer()\sVMs\scheck\sthat\sthe\sfinal\svalues\sof\srecords\sinserted\sinto\sindexes\son\srowid\stables\sare\sintegers. -D 2014-09-15T12:18:29.913 +C Ensure\sthe\scorrect\scollation\ssequences\sare\sused\swhen\ssorting\sdata\sin\ssqlite3ota.c. +D 2014-09-15T14:54:07.328 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -125,7 +125,7 @@ F ext/ota/ota.c d37097e92a005d3915883adefbb93019ea6f8841 F ext/ota/ota1.test fe0bb8acf0caef6c19937b84c6547b788342610d F ext/ota/ota2.test 13f76922446c62ed96192e938b8e625ebf0142fa F ext/ota/ota3.test 7179a90eb64cf8135a6885568653f158fb130872 -F ext/ota/sqlite3ota.c 3697f6db2d51d5f7c0f0306fe94514785361e521 +F ext/ota/sqlite3ota.c c29b3eb617f37d0e51744508b8f609014244727d F ext/ota/sqlite3ota.h 39ce4dffbfcf4ade9e4526369fe2243709345c8e F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761 F ext/rtree/rtree.c 57bec53e1a677ab74217fe1f20a58c3a47261d6b @@ -231,7 +231,7 @@ F src/resolve.c 0ea356d32a5e884add23d1b9b4e8736681dd5697 F src/rowset.c a9c9aae3234b44a6d7c6f5a3cadf90dce1e627be F src/select.c 89e569b263535662f54b537eb9118b2c554ae7aa F src/shell.c 713cef4d73c05fc8e12f4960072329d767a05d50 -F src/sqlite.h.in 706b420dc3390532435a3bd196360a940805f02f +F src/sqlite.h.in 578c42cb3899ee6ad93a0cccff4eb47e1e9a2c80 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc F src/sqliteInt.h 7c090825333d91ca392c2479a9e835e7b6a5eb12 @@ -296,7 +296,7 @@ F src/vdbe.h c63fad052c9e7388d551e556e119c0bcf6bebdf8 F src/vdbeInt.h cdc8e421f85beb1ac9b4669ec5beadab6faa15e0 F src/vdbeapi.c 09677a53dd8c71bcd670b0bd073bb9aefa02b441 F src/vdbeaux.c cef5d34a64ae3a65b56d96d3fd663246ec8e1c36 -F src/vdbeblob.c 7ddae314db27c39f654fd2af577c9afc33d089d9 +F src/vdbeblob.c a8e2c3baa3e7081347c4677185a631bfc43de043 F src/vdbemem.c 921d5468a68ac06f369810992e84ca22cc730a62 F src/vdbesort.c 7c45bfcd823f30d172bbbc1b9f51ef4402fbfe8d F src/vdbetrace.c 6f52bc0c51e144b7efdcfb2a8f771167a8816767 @@ -1199,7 +1199,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P b9b38cb8e21826ddfb4c87a1f166ad33c3c7b6eb -R 6282c8b629d24290f7b2f44befcb6a71 +P cca376bff3510dc5e99fc5824862c3471ceced16 +R 286b5daf6c561394d2eea11438cdac48 U dan -Z 32d433205c33319cd81cbc2b152b81af +Z e26ad3cda7162cfc9e1d6f5aeb5cd971 diff --git a/manifest.uuid b/manifest.uuid index 8423c49a14..4e033cd4fd 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -cca376bff3510dc5e99fc5824862c3471ceced16 \ No newline at end of file +473a72d7009a22ea514a98ee8869e7e7bca14cf5 \ No newline at end of file diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 7011b67fd4..b543f1345d 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -7415,6 +7415,7 @@ int sqlite3_index_writer( int bDelete, /* Zero for insert, non-zero for delete */ const char *zIndex, /* Index to write to */ sqlite3_stmt**, /* OUT: New statement handle */ + const char ***pazColl, /* OUT: Collation sequences for each column */ int **paiCol, int *pnCol /* OUT: See above */ ); diff --git a/src/vdbeblob.c b/src/vdbeblob.c index 09c519cb59..4ecd56522f 100644 --- a/src/vdbeblob.c +++ b/src/vdbeblob.c @@ -463,12 +463,77 @@ int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){ return rc; } +static int indexWriterOutputVars( + sqlite3 *db, + Index *pIdx, + const char ***pazColl, /* OUT: Array of collation sequences */ + int **paiCol, /* OUT: Array of column indexes */ + int *pnCol /* OUT: Total columns in index keys */ +){ + Table *pTbl = pIdx->pTable; /* Table index is attached to */ + Index *pPk = 0; + int nByte = 0; /* Total bytes of space to allocate */ + int i; /* Iterator variable */ + + int *aiCol; + const char **azColl; + char *pCsr; + + if( !HasRowid(pTbl) ){ + pPk = sqlite3PrimaryKeyIndex(pTbl); + } + + for(i=0; i<pIdx->nColumn; i++){ + const char *zColl = 0; + if( i<pIdx->nKeyCol ){ + zColl = pIdx->azColl[i]; + }else if( pPk ){ + zColl = pPk->azColl[i-pIdx->nKeyCol]; + } + if( zColl==0 ) zColl = "BINARY"; + nByte += sqlite3Strlen30(zColl) + 1; + } + nByte += (pIdx->nColumn) * (sizeof(const char*) + sizeof(int)); + + /* Populate the output variables */ + *pazColl = azColl = (const char**)sqlite3DbMallocZero(db, nByte); + if( azColl==0 ) return SQLITE_NOMEM; + *paiCol = aiCol = (int*)&azColl[pIdx->nColumn]; + *pnCol = pIdx->nColumn; + pCsr = (char*)&aiCol[pIdx->nColumn]; + + for(i=0; i<pIdx->nColumn; i++){ + const char *zColl = 0; + int nColl; + int iCol = pTbl->iPKey; + if( i<pIdx->nKeyCol ){ + zColl = pIdx->azColl[i]; + iCol = pIdx->aiColumn[i]; + }else if( pPk ){ + zColl = pPk->azColl[i-pIdx->nKeyCol]; + iCol = pPk->aiColumn[i-pIdx->nKeyCol]; + } + if( zColl==0 ) zColl = "BINARY"; + + aiCol[i] = iCol; + azColl[i] = pCsr; + nColl = 1 + sqlite3Strlen30(zColl); + memcpy(pCsr, zColl, nColl); + pCsr += nColl; + } + + return SQLITE_OK; +} + + int sqlite3_index_writer( sqlite3 *db, int bDelete, const char *zIndex, sqlite3_stmt **ppStmt, - int **paiCol, int *pnCol + const char ***pazColl, /* OUT: Array of collation sequences */ + int **paiCol, /* OUT: Array of column indexes */ + int *pnCol /* OUT: Total columns in index keys */ ){ int rc = SQLITE_OK; Parse *pParse = 0; @@ -477,7 +542,6 @@ int sqlite3_index_writer( int i; /* Used to iterate through index columns */ Vdbe *v = 0; int regRec; /* Register to assemble record in */ - int *aiCol = 0; const char *zAffinity = 0; /* Affinity string for the current index */ sqlite3_mutex_enter(db->mutex); @@ -502,37 +566,15 @@ int sqlite3_index_writer( pTab = pIdx->pTable; zAffinity = sqlite3IndexAffinityStr(v, pIdx); - /* Populate the two output variables, *pnCol and *pnAiCol. */ - *pnCol = pIdx->nColumn; - *paiCol = aiCol = sqlite3DbMallocZero(db, sizeof(int) * pIdx->nColumn); - if( aiCol==0 ){ - rc = SQLITE_NOMEM; - goto index_writer_out; - } - for(i=0; i<pIdx->nKeyCol; i++){ - aiCol[i] = pIdx->aiColumn[i]; - } - if( !HasRowid(pTab) ){ - Index *pPk = sqlite3PrimaryKeyIndex(pIdx->pTable); - assert( pIdx->nColumn==pIdx->nKeyCol+pPk->nKeyCol ); - if( pPk==pIdx ){ - rc = SQLITE_ERROR; - goto index_writer_out; - } - for(i=0; i<pPk->nKeyCol; i++){ - aiCol[pIdx->nKeyCol+i] = pPk->aiColumn[i]; - } - }else{ - assert( pIdx->nColumn==pIdx->nKeyCol+1 ); - aiCol[i] = pTab->iPKey; - } + rc = indexWriterOutputVars(db, pIdx, pazColl, paiCol, pnCol); + if( rc!=SQLITE_OK ) goto index_writer_out; /* Add an OP_Noop to the VDBE program. Then store a pointer to the ** output array *paiCol as its P4 value. This is so that the array ** is automatically deleted when the user finalizes the statement. The ** OP_Noop serves no other purpose. */ sqlite3VdbeAddOp0(v, OP_Noop); - sqlite3VdbeChangeP4(v, -1, (const char*)aiCol, P4_INTARRAY); + sqlite3VdbeChangeP4(v, -1, (const char*)(*pazColl), P4_INTARRAY); sqlite3BeginWriteOperation(pParse, 0, 0);