diff --git a/manifest b/manifest index 135e363efd..a0c8b388f4 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C sqlite3MemCompare\snow\stakes\sa\sCollSeq*\sargument.\s(CVS\s1419) -D 2004-05-20T13:54:54 +C Add\sinternal\ssupport\sfor\scollating\ssequences.\s\sThis\sbreaks\s244\stests.\s(CVS\s1420) +D 2004-05-20T22:16:29 F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd @@ -24,51 +24,51 @@ F sqlite.def fc4f5734786fe4743cfe2aa98eb2da4b089edb5f F sqlite.pc.in 30552343140c53304c2a658c080fbe810cd09ca2 F src/attach.c c315c58cb16fd6e913b3bfa6412aedecb4567fa5 F src/auth.c 5c2f0bea4729c98c2be3b69d6b466fc51448fe79 -F src/btree.c 7abf1261c204e23aeeef12ec1bf75f5eca57d469 +F src/btree.c 68f8e0f6271afd31551abf0b48de9667c5f7368b F src/btree.h b65140b5ae891f30d2a39e64b9f0343225553545 F src/btree_rb.c 9d7973e266ee6f9c61ce592f68742ce9cd5b10e5 -F src/build.c 7310eb68de59281c6dbfe49b728200e3d89b91dd +F src/build.c ec02b35d542d647ab22f31387733759ee0538826 F src/copy.c 4d2038602fd0549d80c59bda27d96f13ea9b5e29 F src/date.c 0eb0a89960bb45c7f7e768748605a7a97b0c8064 F src/delete.c 2e1dda38345416a1ea1c0a6468589a7472334dac F src/encode.c a876af473d1d636faa3dca51c7571f2e007eea37 -F src/expr.c 22ee818d11c6dec2a4d1e8117b42c59928995e49 +F src/expr.c cba2b8c089ef03de307f028ac51eb53f583700d6 F src/func.c cfbb7096efb58e2857e3b312a8958a12774b625a F src/hash.c 440c2f8cb373ee1b4e13a0988489c7cd95d55b6f F src/hash.h 762d95f1e567664d1eafc1687de755626be962fb -F src/insert.c 04865f0a8a5cbc81eab7ca7406498d5356ef0763 -F src/main.c 1bbb26e37c167443ee4c6c27b9150744be01ba81 +F src/insert.c e510d62d23b4de4d901e7ccbbe7833b7fb3b9570 +F src/main.c bb0e84eda9beb447bff109b061a82e6c9b3dc811 F src/md5.c 8e39fdae6d8776b87558e91dcc94740c9b635a9c F src/os.c ddcda92f7fd71b4513c57c1ec797917f206d504e F src/os.h 6e446a17cbeb6c2ce470683a0bb8d9c63abe8607 F src/pager.c 6ff6b906427d4824099140776cb8768f922f3dc5 F src/pager.h 78a00ac280899bcba1a89dc51585dcae6b7b3253 -F src/parse.y 4ed66f12583796dd4d5fff6860dc7e16f1d15cae -F src/pragma.c 2332e7fa9d7cd4b21f30583a696bee36628404ca +F src/parse.y 7c8eb3a305292fb4a0a9cee8c80ff68fdc1a1011 +F src/pragma.c aeeba7dc5bc32a6f0980e6516cb2a48a50973fab F src/printf.c ef750e8e2398ca7e8b58be991075f08c6a7f0e53 F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3 -F src/select.c 2510f0f16bf28108d89ba6e5680a9f090adc31b7 +F src/select.c 97c78398a825553f58139abaa0dd122c6834baca F src/shell.c 0c4662e13bfbfd3d13b066c5859cc97ad2f95d21 F src/sqlite.h.in 8c000826a517ac7302dc2e1c483e71cd06eaf0de -F src/sqliteInt.h 50ec7fb9635403ee71698d9fe0867564b915c52a +F src/sqliteInt.h cdde94b620596f39d7b7a4835a8e9ff8d42ed1ec F src/table.c af14284fa36c8d41f6829e3f2819dce07d3e2de2 F src/tclsqlite.c fbf0fac73624ae246551a6c671f1de0235b5faa1 -F src/test1.c cc6061579f0d9f1e952ad746394c34afd66a64f2 +F src/test1.c 5ba6352c8d63eae9eb98e6ae5bfe24a448b3bcb7 F src/test2.c 6195a1ca2c8d0d2d93644e86da3289b403486872 F src/test3.c 5e4a6d596f982f6f47a5f9f75ede9b4a3b739968 F src/test4.c b3fab9aea7a8940a8a7386ce1c7e2157b09bd296 F src/test5.c c92dca7028b19b9c8319d55e0a5037fc183640a6 F src/tokenize.c e7536dd31205d5afb76c1bdc832dea009c7a3847 F src/trigger.c 11afe9abfba13a2ba142944c797c952e162d117f -F src/update.c 1f6687f8d1085f896a24c0fa13d802223ed55539 +F src/update.c 1a5e9182596f3ea8c7a141e308a3d2a7e5689fee F src/utf.c c27c4f1120f7aaef00cd6942b3d9e3f4ca4fe0e4 F src/util.c 5cbeb452da09cfc7248de9948c15b14d840723f7 F src/vacuum.c c134702e023db8778e6be59ac0ea7b02315b5476 -F src/vdbe.c 4aedca4e37bd4762c1ad7f90e0ababf4ad52aa29 -F src/vdbe.h e75fe13aff16cc6e840371f473762615239264e4 -F src/vdbeInt.h 69a7dd040f0656e211d4e20b3cafdcee8461107e -F src/vdbeaux.c b770802151f30589bd063f434174d230aa043406 -F src/where.c 626b2cbc4290d8be6c04ad7c8395f46d4e21d0d8 +F src/vdbe.c 09ba3911b8cab84604fa2019cfc252f175b74938 +F src/vdbe.h 5bf4ad99fcb5eee0fb72239775e85ef0d70911cf +F src/vdbeInt.h cea492c1fcd85fb78f031e274d1844885d5222e2 +F src/vdbeaux.c 4446afcd568d4002cf2020691d38cdf2c799bc9b +F src/where.c efe5d25fe18cd7381722457898cd863e84097a0c F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242 F test/attach.test cb9b884344e6cfa5e165965d5b1adea679a24c83 F test/attach2.test 7c388dee63a4c1997695c3d41957f32ce784ac56 @@ -80,7 +80,7 @@ F test/btree.test 08e4093c78d2bc1d54e27266f8d17fed14751125 F test/btree2.test aa4a6d05b1ea90b1acaf83ba89039dd302a88635 F test/btree4.test 3797b4305694c7af6828675b0f4b1424b8ca30e4 F test/btree5.test 8e5ff32c02e685d36516c6499add9375fe1377f2 -F test/btree6.test b7524d7165faff496a767dfa2c78a1ae4d8ba09a +F test/btree6.test a5ede6bfbbb2ec8b27e62813612c0f28e8f3e027 F test/capi2.test ec96e0e235d87b53cbaef3d8e3e0f8ccf32c71ca F test/capi3.test acc3919c0f37e85ac3561fc33d6abf7183e1aee1 F test/conflict.test 0911bb2f079046914a6e9c3341b36658c4e2103e @@ -137,7 +137,7 @@ F test/table.test 50e4534552d0385a0e59b3a6d7dde059ced02f83 F test/tableapi.test e0c4cce61e58343caa84dab33fa6823cb35fe1e1 F test/tclsqlite.test a684fc191b81e6cded8a81263663d5a130fbb013 F test/temptable.test a770ba6308d7f7332fce985086b8e06bed6430c2 -F test/tester.tcl 4b7e254be6b3f817d992f42391a73465d7330f16 +F test/tester.tcl 4f7d3ec86d86d9e6ce6939ad6dba4438d8375fba F test/thread1.test 53f050d5be6932d9430df7756edd379366508ff6 F test/threadtest1.c f7f896e62ed46feae1dc411114a48c15a0f82ee2 F test/threadtest2.c d94ca4114fd1504f7e0ae724bcd83d4b40931d86 @@ -195,7 +195,7 @@ F www/sqlite.tcl 3c83b08cf9f18aa2d69453ff441a36c40e431604 F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1 F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4 -P 8411718f0ac17e9c2376fdf8b5fa0cc5fc88be9b -R 0120dca1e321b23f5d0817fb2f4d18f3 +P 5c1e47a25244eacc69b688f5f4e62cec9f09665a +R ce21bc93f28abe94d7cac8a777c1f594 U drh -Z 85c2c075127be3f9e1f00b69921810df +Z 85f85a1caf6d7ec42aba1c203751fff5 diff --git a/manifest.uuid b/manifest.uuid index e70de3aee0..26a76249a4 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5c1e47a25244eacc69b688f5f4e62cec9f09665a \ No newline at end of file +a6cb09d7af537726acc87b9133f68c81e839e047 \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 8ee854e354..481bf2e645 100644 --- a/src/btree.c +++ b/src/btree.c @@ -9,7 +9,7 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* -** $Id: btree.c,v 1.144 2004/05/20 02:01:27 drh Exp $ +** $Id: btree.c,v 1.145 2004/05/20 22:16:29 drh Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** For a detailed discussion of BTrees, refer to @@ -1406,10 +1406,13 @@ create_cursor_exception: return rc; } +/* +** Change the value of the comparison function used by a cursor. +*/ void sqlite3BtreeSetCompare( - BtCursor *pCur, - int(* xCmp)(void*,int,const void*,int,const void*), - void *pArg + BtCursor *pCur, /* The cursor to whose comparison function is changed */ + int(*xCmp)(void*,int,const void*,int,const void*), /* New comparison func */ + void *pArg /* First argument to xCmp() */ ){ pCur->xCompare = xCmp ? xCmp : dfltCompare; pCur->pArg = pArg; diff --git a/src/build.c b/src/build.c index cd9bac81b2..84cd83026c 100644 --- a/src/build.c +++ b/src/build.c @@ -23,7 +23,7 @@ ** ROLLBACK ** PRAGMA ** -** $Id: build.c,v 1.189 2004/05/20 12:41:20 drh Exp $ +** $Id: build.c,v 1.190 2004/05/20 22:16:29 drh Exp $ */ #include "sqliteInt.h" #include @@ -591,6 +591,7 @@ void sqlite3AddColumn(Parse *pParse, Token *pName){ ** will be called next to set pCol->affinity correctly. */ pCol->affinity = SQLITE_AFF_NUMERIC; + pCol->pColl = pParse->db->pDfltColl; p->nCol++; } @@ -703,7 +704,9 @@ void sqlite3AddPrimaryKey(Parse *pParse, IdList *pList, int onError){ }else{ for(i=0; inId; i++){ for(iCol=0; iColnCol; iCol++){ - if( sqlite3StrICmp(pList->a[i].zName, pTab->aCol[iCol].zName)==0 ) break; + if( sqlite3StrICmp(pList->a[i].zName, pTab->aCol[iCol].zName)==0 ){ + break; + } } if( iColnCol ) pTab->aCol[iCol].isPrimKey = 1; } @@ -726,44 +729,73 @@ primary_key_exit: } /* -** Return the appropriate collating type given a type name. -** -** The collation type is text (SQLITE_SO_TEXT) if the type -** name contains the character stream "text" or "blob" or -** "clob". Any other type name is collated as numeric -** (SQLITE_SO_NUM). +** Return a pointer to CollSeq given the name of a collating sequence. +** If the collating sequence did not previously exist, create it but +** assign it an NULL comparison function. */ -int sqlite3CollateType(const char *zType, int nType){ - int i; - for(i=0; idb; + + pColl = sqlite3HashFind(&db->aCollSeq, zType, nType); + if( pColl==0 ){ + sqlite3ChangeCollatingFunction(db, zType, nType, 0, 0); + pColl = sqlite3HashFind(&db->aCollSeq, zType, nType); } - return SQLITE_SO_NUM; + return pColl; } /* -** This routine is called by the parser while in the middle of -** parsing a CREATE TABLE statement. A "COLLATE" clause has -** been seen on a column. This routine sets the Column.sortOrder on -** the column currently under construction. +** Set the collation function of the most recently parsed table column +** to the CollSeq given. */ -void sqlite3AddCollateType(Parse *pParse, int collType){ +void sqlite3AddCollateType(Parse *pParse, const char *zType, int nType){ Table *p; - int i; - if( (p = pParse->pNewTable)==0 ) return; - i = p->nCol-1; + CollSeq *pColl; + sqlite *db = pParse->db; - /* FIX ME */ - /* if( i>=0 ) p->aCol[i].sortOrder = collType; */ + if( (p = pParse->pNewTable)==0 ) return; + pColl = sqlite3HashFind(&db->aCollSeq, zType, nType); + if( pColl==0 ){ + pColl = sqlite3ChangeCollatingFunction(db, zType, nType, 0, 0); + } + if( pColl ){ + p->aCol[p->nCol-1].pColl = pColl; + } +} + +/* +** Create or modify a collating sequence entry in the sqlite.aCollSeq +** table. +** +** Once an entry is added to the sqlite.aCollSeq table, it can never +** be removed, though is comparison function or user data can be changed. +** +** Return a pointer to the collating function that was created or modified. +*/ +CollSeq *sqlite3ChangeCollatingFunction( + sqlite *db, /* Database into which to insert the collation */ + const char *zName, /* Name of the collation */ + int nName, /* Number of characters in zName */ + void *pUser, /* First argument to xCmp */ + int (*xCmp)(void*,int,const void*,int,const void*) /* Comparison function */ +){ + CollSeq *pColl; + + pColl = sqlite3HashFind(&db->aCollSeq, zName, nName); + if( pColl==0 ){ + pColl = sqliteMallocRaw( sizeof(*pColl) + nName + 1 ); + if( pColl==0 ){ + return 0; + } + pColl->zName = (char*)&pColl[1]; + pColl->reverseOrder = 0; + memcpy(pColl->zName, zName, nName+1); + sqlite3HashInsert(&db->aCollSeq, pColl->zName, nName, pColl); + } + pColl->pUser = pUser; + pColl->xCmp = xCmp; + return pColl; } /* @@ -1606,9 +1638,9 @@ void sqlite3CreateIndex( ** Allocate the index structure. */ pIndex = sqliteMalloc( sizeof(Index) + strlen(zName) + 1 + - sizeof(int)*pList->nId ); + (sizeof(int) + sizeof(CollSeq*))*pList->nId ); if( pIndex==0 ) goto exit_create_index; - pIndex->aiColumn = (int*)&pIndex[1]; + pIndex->aiColumn = (int*)&pIndex->keyInfo.aColl[pList->nId]; pIndex->zName = (char*)&pIndex->aiColumn[pList->nId]; strcpy(pIndex->zName, zName); pIndex->pTable = pTab; @@ -1632,7 +1664,9 @@ void sqlite3CreateIndex( goto exit_create_index; } pIndex->aiColumn[i] = j; + pIndex->keyInfo.aColl[i] = pTab->aCol[j].pColl; } + pIndex->keyInfo.nField = pList->nId; /* Link the new Index structure to its table and to the other ** in-memory database structures. @@ -1713,8 +1747,9 @@ void sqlite3CreateIndex( sqlite3VdbeCode(v, OP_Dup, 0, 0, OP_Integer, isTemp, 0, - OP_OpenWrite, 1, 0, 0); + sqlite3VdbeOp3(v, OP_OpenWrite, 1, 0, + (char*)&pIndex->keyInfo, P3_KEYINFO); } addr = sqlite3VdbeAddOp(v, OP_String, 0, 0); if( pStart && pEnd ){ @@ -1725,7 +1760,8 @@ void sqlite3CreateIndex( sqlite3VdbeAddOp(v, OP_PutIntKey, 0, 0); if( pTable ){ sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0); - sqlite3VdbeOp3(v, OP_OpenRead, 2, pTab->tnum, pTab->zName, 0); + sqlite3VdbeAddOp(v, OP_OpenRead, 2, pTab->tnum); + /* VdbeComment((v, "%s", pTab->zName)); */ sqlite3VdbeAddOp(v, OP_SetNumColumns, 2, pTab->nCol); lbl2 = sqlite3VdbeMakeLabel(v); sqlite3VdbeAddOp(v, OP_Rewind, 2, lbl2); diff --git a/src/expr.c b/src/expr.c index 1987169e0b..f1776e065b 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.124 2004/05/20 13:54:54 drh Exp $ +** $Id: expr.c,v 1.125 2004/05/20 22:16:29 drh Exp $ */ #include "sqliteInt.h" #include @@ -588,10 +588,6 @@ 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; - - /* FIX ME: Expr::dataType will be removed... */ - pExpr->dataType = - (pCol->affinity==SQLITE_AFF_TEXT?SQLITE_SO_TEXT:SQLITE_SO_NUM); break; } } @@ -624,9 +620,6 @@ static int lookupName( cnt++; pExpr->iColumn = j==pTab->iPKey ? -1 : j; pExpr->affinity = pTab->aCol[j].affinity; - /* FIX ME: Expr::dataType will be removed... */ - pExpr->dataType = - (pCol->affinity==SQLITE_AFF_TEXT?SQLITE_SO_TEXT:SQLITE_SO_NUM); break; } } @@ -639,7 +632,6 @@ static int lookupName( if( cnt==0 && cntTab==1 && sqlite3IsRowid(zCol) ){ cnt = 1; pExpr->iColumn = -1; - pExpr->dataType = SQLITE_SO_NUM; pExpr->affinity = SQLITE_AFF_INTEGER; } @@ -805,6 +797,8 @@ int sqlite3ExprResolveIds( case TK_IN: { char affinity; Vdbe *v = sqlite3GetVdbe(pParse); + KeyInfo keyInfo; + if( v==0 ) return 1; if( sqlite3ExprResolveIds(pParse, pSrcList, pEList, pExpr->pLeft) ){ return 1; @@ -825,7 +819,11 @@ int sqlite3ExprResolveIds( ** is used. */ pExpr->iTable = pParse->nTab++; - sqlite3VdbeAddOp(v, OP_OpenTemp, pExpr->iTable, 1); + memset(&keyInfo, 0, sizeof(keyInfo)); + keyInfo.nField = 1; + keyInfo.aColl[0] = pParse->db->pDfltColl; + sqlite3VdbeOp3(v, OP_OpenTemp, pExpr->iTable, 0, \ + (char*)&keyInfo, P3_KEYINFO); if( pExpr->pSelect ){ /* Case 1: expr IN (SELECT ...) @@ -1002,28 +1000,8 @@ int sqlite3ExprCheck(Parse *pParse, Expr *pExpr, int allowAgg, int *pIsAgg){ nErr = sqlite3ExprCheck(pParse, pExpr->pList->a[i].pExpr, allowAgg && !is_agg, pIsAgg); } - if( pDef==0 ){ - /* Already reported an error */ - }else if( pDef->dataType>=0 ){ - if( pDef->dataTypedataType = - sqlite3ExprType(pExpr->pList->a[pDef->dataType].pExpr); - }else{ - pExpr->dataType = SQLITE_SO_NUM; - } - }else if( pDef->dataType==SQLITE_ARGS ){ - pDef->dataType = SQLITE_SO_TEXT; - for(i=0; ipList->a[i].pExpr)==SQLITE_SO_NUM ){ - pExpr->dataType = SQLITE_SO_NUM; - break; - } - } - }else if( pDef->dataType==SQLITE_NUMERIC ){ - pExpr->dataType = SQLITE_SO_NUM; - }else{ - pExpr->dataType = SQLITE_SO_TEXT; - } + /** TODO: Compute pExpr->affinity based on the expected return + ** type of the function */ } default: { if( pExpr->pLeft ){ @@ -1047,95 +1025,37 @@ int sqlite3ExprCheck(Parse *pParse, Expr *pExpr, int allowAgg, int *pIsAgg){ } /* -** Return either SQLITE_SO_NUM or SQLITE_SO_TEXT to indicate whether the -** given expression should sort as numeric values or as text. +** Return one of the SQLITE_AFF_* affinity types that indicates the likely +** data type of the result of the given expression. +** +** Not every expression has a fixed type. If the type cannot be determined +** at compile-time, then try to return the type affinity if the expression +** is a column. Otherwise just return SQLITE_AFF_NONE. ** ** The sqlite3ExprResolveIds() and sqlite3ExprCheck() routines must have ** both been called on the expression before it is passed to this routine. */ int sqlite3ExprType(Expr *p){ - if( p==0 ) return SQLITE_SO_NUM; + if( p==0 ) return SQLITE_AFF_NONE; while( p ) switch( p->op ){ - case TK_PLUS: - case TK_MINUS: - case TK_STAR: - case TK_SLASH: - case TK_AND: - case TK_OR: - case TK_ISNULL: - case TK_NOTNULL: - case TK_NOT: - case TK_UMINUS: - case TK_UPLUS: - case TK_BITAND: - case TK_BITOR: - case TK_BITNOT: - case TK_LSHIFT: - case TK_RSHIFT: - case TK_REM: - case TK_INTEGER: - case TK_FLOAT: - case TK_IN: - case TK_BETWEEN: - case TK_GLOB: - case TK_LIKE: - return SQLITE_SO_NUM; - - case TK_STRING: - case TK_NULL: case TK_CONCAT: - case TK_VARIABLE: - return SQLITE_SO_TEXT; - - case TK_LT: - case TK_LE: - case TK_GT: - case TK_GE: - case TK_NE: - case TK_EQ: - if( sqlite3ExprType(p->pLeft)==SQLITE_SO_NUM ){ - return SQLITE_SO_NUM; - } - p = p->pRight; - break; + return SQLITE_AFF_TEXT; case TK_AS: p = p->pLeft; break; - case TK_COLUMN: - case TK_FUNCTION: - case TK_AGG_FUNCTION: - return p->dataType; + case TK_NULL: + return SQLITE_AFF_NONE; - case TK_SELECT: - assert( p->pSelect ); - assert( p->pSelect->pEList ); - assert( p->pSelect->pEList->nExpr>0 ); - p = p->pSelect->pEList->a[0].pExpr; - break; - - case TK_CASE: { - if( p->pRight && sqlite3ExprType(p->pRight)==SQLITE_SO_NUM ){ - return SQLITE_SO_NUM; - } - if( p->pList ){ - int i; - ExprList *pList = p->pList; - for(i=1; inExpr; i+=2){ - if( sqlite3ExprType(pList->a[i].pExpr)==SQLITE_SO_NUM ){ - return SQLITE_SO_NUM; - } - } - } - return SQLITE_SO_TEXT; - } + case TK_SELECT: /*** FIX ME ****/ + case TK_COLUMN: /*** FIX ME ****/ + case TK_CASE: /*** FIX ME ****/ default: - assert( p->op==TK_ABORT ); /* Can't Happen */ - break; + return SQLITE_AFF_NUMERIC; } - return SQLITE_SO_NUM; + return SQLITE_AFF_NONE; } /* @@ -1444,9 +1364,8 @@ int sqlite3ExprCodeExprList( for(pItem=pList->a, i=0; ipExpr); if( includeTypes ){ - sqlite3VdbeOp3(v, OP_String, 0, 0, - sqlite3ExprType(pItem->pExpr)==SQLITE_SO_NUM ? "numeric" : "text", - P3_STATIC); + /** DEPRECATED. This will go away with the new function interface **/ + sqlite3VdbeOp3(v, OP_String, 0, 0, "numeric", P3_STATIC); } } return includeTypes ? n*2 : n; diff --git a/src/insert.c b/src/insert.c index d105ad1952..c122643d4d 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.104 2004/05/20 02:42:16 drh Exp $ +** $Id: insert.c,v 1.105 2004/05/20 22:16:29 drh Exp $ */ #include "sqliteInt.h" @@ -1002,11 +1002,12 @@ int sqlite3OpenTableAndIndices(Parse *pParse, Table *pTab, int base){ Vdbe *v = sqlite3GetVdbe(pParse); assert( v!=0 ); sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0); - sqlite3VdbeOp3(v, OP_OpenWrite, base, pTab->tnum, pTab->zName, P3_STATIC); + sqlite3VdbeAddOp(v, OP_OpenWrite, base, pTab->tnum); sqlite3VdbeAddOp(v, OP_SetNumColumns, base, pTab->nCol); for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ sqlite3VdbeAddOp(v, OP_Integer, pIdx->iDb, 0); - sqlite3VdbeOp3(v, OP_OpenWrite, i+base, pIdx->tnum, pIdx->zName, P3_STATIC); + sqlite3VdbeOp3(v, OP_OpenWrite, i+base, pIdx->tnum, + (char*)&pIdx->keyInfo, P3_KEYINFO); } return i; } diff --git a/src/main.c b/src/main.c index d0e7297ce4..84c4d96edc 100644 --- a/src/main.c +++ b/src/main.c @@ -14,7 +14,7 @@ ** other files are for internal use by SQLite and should not be ** accessed by users of the library. ** -** $Id: main.c,v 1.177 2004/05/20 11:00:52 danielk1977 Exp $ +** $Id: main.c,v 1.178 2004/05/20 22:16:29 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -375,6 +375,24 @@ const char sqlite3_encoding[] = "UTF-8"; const char sqlite3_encoding[] = "iso8859"; #endif +/* +** This is the default collating function named "BINARY" which is always +** available. +*/ +static int binaryCollatingFunc( + void *NotUsed, + int nKey1, const void *pKey1, + int nKey2, const void *pKey2 +){ + int rc, n; + n = nKey1aDb = db->aDbStatic; /* db->flags |= SQLITE_ShortColNames; */ sqlite3HashInit(&db->aFunc, SQLITE_HASH_STRING, 1); + sqlite3HashInit(&db->aCollSeq, SQLITE_HASH_STRING, 0); for(i=0; inDb; i++){ sqlite3HashInit(&db->aDb[i].tblHash, SQLITE_HASH_STRING, 0); sqlite3HashInit(&db->aDb[i].idxHash, SQLITE_HASH_STRING, 0); sqlite3HashInit(&db->aDb[i].trigHash, SQLITE_HASH_STRING, 0); sqlite3HashInit(&db->aDb[i].aFKey, SQLITE_HASH_STRING, 1); } + db->pDfltColl = + sqlite3ChangeCollatingFunction(db, "BINARY", 6, 0, binaryCollatingFunc); /* Open the backend database driver */ if( zFilename[0]==':' && strcmp(zFilename,":memory:")==0 ){ diff --git a/src/parse.y b/src/parse.y index c4dad6906c..4bfa6a81b0 100644 --- a/src/parse.y +++ b/src/parse.y @@ -14,7 +14,7 @@ ** the parser. Lemon will also generate a header file containing ** numeric codes for all of the tokens. ** -** @(#) $Id: parse.y,v 1.115 2004/05/20 12:41:20 drh Exp $ +** @(#) $Id: parse.y,v 1.116 2004/05/20 22:16:29 drh Exp $ */ %token_prefix TK_ %token_type {Token} @@ -193,9 +193,7 @@ ccons ::= CHECK LP expr RP onconf. ccons ::= REFERENCES nm(T) idxlist_opt(TA) refargs(R). {sqlite3CreateForeignKey(pParse,0,&T,TA,R);} ccons ::= defer_subclause(D). {sqlite3DeferForeignKey(pParse,D);} -ccons ::= COLLATE id(C). { - sqlite3AddCollateType(pParse, sqlite3CollateType(C.z, C.n)); -} +ccons ::= COLLATE id(C). {sqlite3AddCollateType(pParse, C.z, C.n);} // The next group of rules parses the arguments to a REFERENCES clause // that determine if the referential integrity checking is deferred or @@ -437,23 +435,23 @@ using_opt(U) ::= . {U = 0;} orderby_opt(A) ::= . {A = 0;} orderby_opt(A) ::= ORDER BY sortlist(X). {A = X;} sortlist(A) ::= sortlist(X) COMMA sortitem(Y) collate(C) sortorder(Z). { - A = sqlite3ExprListAppend(X,Y,0); - if( A ) A->a[A->nExpr-1].sortOrder = C+Z; + A = sqlite3ExprListAppend(X,Y,&C); + if( A ) A->a[A->nExpr-1].sortOrder = Z; } sortlist(A) ::= sortitem(Y) collate(C) sortorder(Z). { - A = sqlite3ExprListAppend(0,Y,0); - if( A ) A->a[0].sortOrder = C+Z; + A = sqlite3ExprListAppend(0,Y,&C); + if( A ) A->a[0].sortOrder = Z; } sortitem(A) ::= expr(X). {A = X;} %type sortorder {int} -%type collate {int} +%type collate {Token} sortorder(A) ::= ASC. {A = SQLITE_SO_ASC;} sortorder(A) ::= DESC. {A = SQLITE_SO_DESC;} sortorder(A) ::= . {A = SQLITE_SO_ASC;} -collate(C) ::= . {C = SQLITE_SO_UNK;} -collate(C) ::= COLLATE id(X). {C = sqlite3CollateType(X.z, X.n);} +collate(C) ::= . {C.z = 0; C.n = 0;} +collate(C) ::= COLLATE id(X). {C = X;} %type groupby_opt {ExprList*} %destructor groupby_opt {sqlite3ExprListDelete($$);} diff --git a/src/pragma.c b/src/pragma.c index c167ec0044..47b0a17278 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.26 2004/05/18 22:17:46 drh Exp $ +** $Id: pragma.c,v 1.27 2004/05/20 22:16:29 drh Exp $ */ #include "sqliteInt.h" #include @@ -638,12 +638,13 @@ void sqlite3Pragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){ if( pTab->pIndex==0 ) continue; sqlite3VdbeAddOp(v, OP_Integer, i, 0); - sqlite3VdbeOp3(v, OP_OpenRead, 1, pTab->tnum, pTab->zName, 0); + sqlite3VdbeAddOp(v, OP_OpenRead, 1, pTab->tnum); sqlite3VdbeAddOp(v, OP_SetNumColumns, 1, pTab->nCol); for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ if( pIdx->tnum==0 ) continue; sqlite3VdbeAddOp(v, OP_Integer, pIdx->iDb, 0); - sqlite3VdbeOp3(v, OP_OpenRead, j+2, pIdx->tnum, pIdx->zName, 0); + sqlite3VdbeOp3(v, OP_OpenRead, j+2, pIdx->tnum, + (char*)&pIdx->keyInfo, P3_KEYINFO); } sqlite3VdbeAddOp(v, OP_Integer, 0, 0); sqlite3VdbeAddOp(v, OP_MemStore, 1, 1); diff --git a/src/select.c b/src/select.c index 633dca59aa..7565804c7d 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.170 2004/05/20 03:02:47 drh Exp $ +** $Id: select.c,v 1.171 2004/05/20 22:16:29 drh Exp $ */ #include "sqliteInt.h" @@ -324,19 +324,11 @@ static void pushOntoSorter(Parse *pParse, Vdbe *v, ExprList *pOrderBy){ if( zSortOrder==0 ) return; for(i=0; inExpr; i++){ int order = pOrderBy->a[i].sortOrder; - int type; int c; - if( (order & SQLITE_SO_TYPEMASK)==SQLITE_SO_TEXT ){ - type = SQLITE_SO_TEXT; - }else if( (order & SQLITE_SO_TYPEMASK)==SQLITE_SO_NUM ){ - type = SQLITE_SO_NUM; + if( order==SQLITE_SO_ASC ){ + c = 'A'; }else{ - type = sqlite3ExprType(pOrderBy->a[i].pExpr); - } - if( (order & SQLITE_SO_DIRMASK)==SQLITE_SO_ASC ){ - c = type==SQLITE_SO_TEXT ? 'A' : '+'; - }else{ - c = type==SQLITE_SO_TEXT ? 'D' : '-'; + c = 'D'; } zSortOrder[i] = c; sqlite3ExprCode(pParse, pOrderBy->a[i].pExpr); @@ -346,28 +338,6 @@ static void pushOntoSorter(Parse *pParse, Vdbe *v, ExprList *pOrderBy){ sqlite3VdbeAddOp(v, OP_SortPut, 0, 0); } -/* -** This routine adds a P3 argument to the last VDBE opcode that was -** inserted. The P3 argument added is a string suitable for the -** OP_MakeKey or OP_MakeIdxKey opcodes. The string consists of -** characters 't' or 'n' depending on whether or not the various -** fields of the key to be generated should be treated as numeric -** or as text. See the OP_MakeKey and OP_MakeIdxKey opcode -** documentation for additional information about the P3 string. -** See also the sqlite3AddIdxKeyType() routine. -*/ -void sqlite3AddKeyType(Vdbe *v, ExprList *pEList){ - int nColumn = pEList->nExpr; - char *zType = sqliteMalloc( nColumn+1 ); - int i; - if( zType==0 ) return; - for(i=0; ia[i].pExpr)==SQLITE_SO_NUM ? 'n' : 't'; - } - zType[i] = 0; - sqlite3VdbeChangeP3(v, -1, zType, P3_DYNAMIC); -} - /* ** This routine generates the code for the inside of the inner loop ** of a SELECT. @@ -432,8 +402,8 @@ static int selectInnerLoop( #if NULL_ALWAYS_DISTINCT sqlite3VdbeAddOp(v, OP_IsNull, -pEList->nExpr, sqlite3VdbeCurrentAddr(v)+7); #endif + /* Deliberately leave the affinity string off of the following OP_MakeKey */ sqlite3VdbeAddOp(v, OP_MakeKey, pEList->nExpr, 1); - sqlite3AddKeyType(v, pEList); sqlite3VdbeAddOp(v, OP_Distinct, distinct, sqlite3VdbeCurrentAddr(v)+3); sqlite3VdbeAddOp(v, OP_Pop, pEList->nExpr+1, 0); sqlite3VdbeAddOp(v, OP_Goto, 0, iContinue); @@ -682,11 +652,9 @@ static void generateColumnTypes( zType = pTab->aCol[iCol].zType; } }else{ - if( sqlite3ExprType(p)==SQLITE_SO_TEXT ){ - zType = "TEXT"; - }else{ - zType = "NUMERIC"; - } + zType = "ANY"; + /** TODO: Perhaps something related to the affinity of the + ** exprsssion? */ } sqlite3VdbeOp3(v, OP_ColumnName, i + pEList->nExpr, 0, zType, 0); } @@ -1079,13 +1047,6 @@ void sqlite3SelectUnbind(Select *p){ ** ** Any entry that does not match is flagged as an error. The number ** of errors is returned. -** -** This routine does NOT correctly initialize the Expr.dataType field -** of the ORDER BY expressions. The multiSelectSortOrder() routine -** must be called to do that after the individual select statements -** have all been analyzed. This routine is unable to compute Expr.dataType -** because it must be called before the individual select statements -** have been analyzed. */ static int matchOrderbyToColumn( Parse *pParse, /* A place to leave error messages */ @@ -1170,55 +1131,7 @@ Vdbe *sqlite3GetVdbe(Parse *pParse){ return v; } -/* -** This routine sets the Expr.dataType field on all elements of -** the pOrderBy expression list. The pOrderBy list will have been -** set up by matchOrderbyToColumn(). Hence each expression has -** a TK_COLUMN as its root node. The Expr.iColumn refers to a -** column in the result set. The datatype is set to SQLITE_SO_TEXT -** if the corresponding column in p and every SELECT to the left of -** p has a datatype of SQLITE_SO_TEXT. If the cooressponding column -** in p or any of the left SELECTs is SQLITE_SO_NUM, then the datatype -** of the order-by expression is set to SQLITE_SO_NUM. -** -** Examples: -** -** CREATE TABLE one(a INTEGER, b TEXT); -** CREATE TABLE two(c VARCHAR(5), d FLOAT); -** -** SELECT b, b FROM one UNION SELECT d, c FROM two ORDER BY 1, 2; -** -** The primary sort key will use SQLITE_SO_NUM because the "d" in -** the second SELECT is numeric. The 1st column of the first SELECT -** is text but that does not matter because a numeric always overrides -** a text. -** -** The secondary key will use the SQLITE_SO_TEXT sort order because -** both the (second) "b" in the first SELECT and the "c" in the second -** SELECT have a datatype of text. -*/ -static void multiSelectSortOrder(Select *p, ExprList *pOrderBy){ - int i; - ExprList *pEList; - if( pOrderBy==0 ) return; - if( p==0 ){ - for(i=0; inExpr; i++){ - pOrderBy->a[i].pExpr->dataType = SQLITE_SO_TEXT; - } - return; - } - multiSelectSortOrder(p->pPrior, pOrderBy); - pEList = p->pEList; - for(i=0; inExpr; i++){ - Expr *pE = pOrderBy->a[i].pExpr; - if( pE->dataType==SQLITE_SO_NUM ) continue; - assert( pE->iColumn>=0 ); - if( pEList->nExpr>pE->iColumn ){ - pE->dataType = sqlite3ExprType(pEList->a[pE->iColumn].pExpr); - } - } -} - +#if 0 /***** This routine needs deleting *****/ static void multiSelectAffinity(Select *p, char *zAff){ int i; @@ -1231,6 +1144,7 @@ static void multiSelectAffinity(Select *p, char *zAff){ } } } +#endif /* ** Compute the iLimit and iOffset fields of the SELECT based on the @@ -1278,6 +1192,35 @@ static void computeLimitRegisters(Parse *pParse, Select *p){ } } +/* +** Generate VDBE instructions that will open a transient table that +** will be used for an index or to store keyed results for a compound +** select. In other words, open a transient table that needs a +** KeyInfo structure. The number of columns in the KeyInfo is determined +** by the result set of the SELECT statement in the second argument. +** +** Make the new table a KeyAsData table if keyAsData is true. +*/ +static void openTempIndex(Parse *pParse, Select *p, int iTab, int keyAsData){ + KeyInfo *pKeyInfo; + int nColumn = p->pEList->nExpr; + sqlite *db = pParse->db; + int i; + Vdbe *v = pParse->pVdbe; + + pKeyInfo = sqliteMalloc( sizeof(*pKeyInfo)+nColumn*sizeof(CollSeq*) ); + if( pKeyInfo==0 ) return; + pKeyInfo->nField = nColumn; + for(i=0; iaColl[i] = db->pDfltColl; + } + sqlite3VdbeOp3(v, OP_OpenTemp, iTab, 0, (char*)pKeyInfo, P3_KEYINFO); + sqliteFree(pKeyInfo); + if( keyAsData ){ + sqlite3VdbeAddOp(v, OP_KeyAsData, iTab, 1); + } +} + /* ** This routine is called to process a query that is really the union ** or intersection of two or more separate queries. @@ -1320,6 +1263,7 @@ static int multiSelect( Vdbe *v; /* Generate code to this VDBE */ char *affStr = 0; +#if 0 /* NOT USED */ if( !aff ){ int len; rc = fillInColumnList(pParse, p); @@ -1335,6 +1279,7 @@ static int multiSelect( memset(affStr, (int)SQLITE_AFF_NUMERIC, len-1); aff = affStr; } +#endif /* Make sure there is no ORDER BY or LIMIT clause on prior SELECTs. Only ** the last SELECT in the series may have an ORDER BY or LIMIT. @@ -1424,8 +1369,7 @@ static int multiSelect( goto multi_select_end; } if( p->op!=TK_ALL ){ - sqlite3VdbeAddOp(v, OP_OpenTemp, unionTab, 1); - sqlite3VdbeAddOp(v, OP_KeyAsData, unionTab, 1); + openTempIndex(pParse, p, unionTab, 1); }else{ sqlite3VdbeAddOp(v, OP_OpenTemp, unionTab, 0); } @@ -1481,7 +1425,6 @@ static int multiSelect( sqlite3VdbeAddOp(v, OP_Rewind, unionTab, iBreak); computeLimitRegisters(pParse, p); iStart = sqlite3VdbeCurrentAddr(v); - multiSelectSortOrder(p, p->pOrderBy); rc = selectInnerLoop(pParse, p, p->pEList, unionTab, p->pEList->nExpr, p->pOrderBy, -1, eDest, iParm, iCont, iBreak, 0); @@ -1514,8 +1457,7 @@ static int multiSelect( rc = 1; goto multi_select_end; } - sqlite3VdbeAddOp(v, OP_OpenTemp, tab1, 1); - sqlite3VdbeAddOp(v, OP_KeyAsData, tab1, 1); + openTempIndex(pParse, p, tab1, 1); assert( p->pEList ); /* Code the SELECTs to our left into temporary table "tab1". @@ -1527,8 +1469,7 @@ static int multiSelect( /* Code the current SELECT into temporary table "tab2" */ - sqlite3VdbeAddOp(v, OP_OpenTemp, tab2, 1); - sqlite3VdbeAddOp(v, OP_KeyAsData, tab2, 1); + openTempIndex(pParse, p, tab2, 1); p->pPrior = 0; nLimit = p->nLimit; p->nLimit = -1; @@ -1556,7 +1497,6 @@ static int multiSelect( computeLimitRegisters(pParse, p); iStart = sqlite3VdbeAddOp(v, OP_FullKey, tab1, 0); sqlite3VdbeAddOp(v, OP_NotFound, tab2, iCont); - multiSelectSortOrder(p, p->pOrderBy); rc = selectInnerLoop(pParse, p, p->pEList, tab1, p->pEList->nExpr, p->pOrderBy, -1, eDest, iParm, iCont, iBreak, 0); @@ -1584,6 +1524,7 @@ static int multiSelect( } multi_select_end: +#if 0 /*** NOT USED ****/ if( affStr ){ if( rc!=SQLITE_OK ){ sqliteFree(affStr); @@ -1592,6 +1533,7 @@ multi_select_end: sqlite3VdbeOp3(v, OP_Noop, 0, 0, affStr, P3_DYNAMIC); } } +#endif return rc; } @@ -1621,7 +1563,6 @@ static void substExpr(Expr *pExpr, int iTable, ExprList *pEList){ pNew = pEList->a[pExpr->iColumn].pExpr; assert( pNew!=0 ); pExpr->op = pNew->op; - pExpr->dataType = pNew->dataType; assert( pExpr->pLeft==0 ); pExpr->pLeft = sqlite3ExprDup(pNew->pLeft); assert( pExpr->pRight==0 ); @@ -2011,7 +1952,7 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){ computeLimitRegisters(pParse, p); if( pSrc->a[0].pSelect==0 ){ sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0); - sqlite3VdbeOp3(v, OP_OpenRead, base, pTab->tnum, pTab->zName, 0); + sqlite3VdbeAddOp(v, OP_OpenRead, base, pTab->tnum); sqlite3VdbeAddOp(v, OP_SetNumColumns, base, pTab->nCol); } cont = sqlite3VdbeMakeLabel(v); @@ -2019,7 +1960,8 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){ sqlite3VdbeAddOp(v, seekOp, base, 0); }else{ sqlite3VdbeAddOp(v, OP_Integer, pIdx->iDb, 0); - sqlite3VdbeOp3(v, OP_OpenRead, base+1, pIdx->tnum, pIdx->zName, P3_STATIC); + sqlite3VdbeOp3(v, OP_OpenRead, base+1, pIdx->tnum, + (char*)&pIdx->keyInfo, P3_KEYINFO); sqlite3VdbeAddOp(v, seekOp, base+1, 0); sqlite3VdbeAddOp(v, OP_IdxRecno, base+1, 0); sqlite3VdbeAddOp(v, OP_Close, base+1, 0); @@ -2274,6 +2216,7 @@ int sqlite3Select( generateColumnNames(pParse, pTabList, pEList); } +#if 1 /* I do not think we need the following code any more.... */ /* If the destination is SRT_Union, then set the number of columns in ** the records that will be inserted into the temporary table. The caller ** couldn't do this, in case the select statement is of the form @@ -2288,6 +2231,7 @@ int sqlite3Select( if( eDest==SRT_Union ){ sqlite3VdbeAddOp(v, OP_SetNumColumns, iParm, pEList->nExpr); } +#endif /* Generate code for all sub-queries in the FROM clause */ @@ -2416,7 +2360,7 @@ int sqlite3Select( */ if( isDistinct ){ distinct = pParse->nTab++; - sqlite3VdbeAddOp(v, OP_OpenTemp, distinct, 1); + openTempIndex(pParse, p, distinct, 0); }else{ distinct = -1; } @@ -2447,8 +2391,9 @@ int sqlite3Select( for(i=0; inExpr; i++){ sqlite3ExprCode(pParse, pGroupBy->a[i].pExpr); } + /* No affinity string is attached to the following OP_MakeKey + ** because we do not need to do any coercion of datatypes. */ sqlite3VdbeAddOp(v, OP_MakeKey, pGroupBy->nExpr, 0); - sqlite3AddKeyType(v, pGroupBy); lbl1 = sqlite3VdbeMakeLabel(v); sqlite3VdbeAddOp(v, OP_AggFocus, 0, lbl1); for(i=0, pAgg=pParse->aAgg; inAgg; i++, pAgg++){ diff --git a/src/sqliteInt.h b/src/sqliteInt.h index da97159646..3c3d9aa705 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.240 2004/05/20 11:00:52 danielk1977 Exp $ +** @(#) $Id: sqliteInt.h,v 1.241 2004/05/20 22:16:30 drh Exp $ */ #include "config.h" #include "sqlite.h" @@ -260,6 +260,8 @@ typedef struct Db Db; typedef struct AuthContext AuthContext; typedef struct KeyClass KeyClass; typedef struct CollSeq CollSeq; +typedef struct KeyInfo KeyInfo; + /* ** Each database file to be accessed by the system is an instance @@ -376,7 +378,7 @@ struct sqlite { int (*xCommitCallback)(void*);/* Invoked at every commit. */ Hash aFunc; /* All functions that can be in SQL exprs */ Hash aCollSeq; /* All collating sequences */ - CollSeq *pDfltColl; /* The default collating sequence (memcmp) */ + CollSeq *pDfltColl; /* The default collating sequence (BINARY) */ i64 lastRowid; /* ROWID of most recent insert (see above) */ i64 priorNewRowid; /* Last randomly generated ROWID */ int magic; /* Magic number for detect library misuse */ @@ -491,18 +493,10 @@ struct CollSeq { }; /* -** The allowed sort orders. -** -** The TEXT and NUM values use bits that do not overlap with DESC and ASC. -** That way the two can be combined into a single number. +** A sort order can be either ASC or DESC. */ -#define SQLITE_SO_UNK 0 /* Use the default collating type. (SCT_NUM) */ -#define SQLITE_SO_TEXT 2 /* Sort using memcmp() */ -#define SQLITE_SO_NUM 4 /* Sort using sqlite3Compare() */ -#define SQLITE_SO_TYPEMASK 6 /* Mask to extract the collating sequence */ #define SQLITE_SO_ASC 0 /* Sort in ascending order */ -#define SQLITE_SO_DESC 1 /* Sort in descending order */ -#define SQLITE_SO_DIRMASK 1 /* Mask to extract the sort direction */ +#define SQLITE_SO_DESC 1 /* Sort in ascending order */ /* ** Column affinity types. @@ -641,6 +635,21 @@ struct FKey { #define OE_Default 99 /* Do whatever the default action is */ + +/* +** An instance of the following structure is passed as the first +** argument to sqlite3VdbeKeyCompare and is used to control the +** comparison of the two index keys. +** +** If the KeyInfo.incrKey value is true and the comparison would +** otherwise be equal, then return a result as if the second key larger. +*/ +struct KeyInfo { + u8 incrKey; /* Increase 2nd key by epsilon before comparison */ + int nField; /* Number of entries in aColl[] */ + CollSeq *aColl[1]; /* Collating sequence for each term of the key */ +}; + /* ** Each SQL index is represented in memory by an ** instance of the following structure. @@ -678,6 +687,7 @@ struct Index { 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 */ + KeyInfo keyInfo; /* Info on how to order keys. MUST BE LAST */ }; /* @@ -732,7 +742,6 @@ struct Token { */ struct Expr { u8 op; /* Operation performed by this node */ - u8 dataType; /* Either SQLITE_SO_TEXT or SQLITE_SO_NUM */ char affinity; /* The affinity of the column or 0 if not a column */ u8 iDb; /* Database referenced by this expression */ u8 flags; /* Various flags. See below */ @@ -1200,8 +1209,9 @@ void sqlite3AddNotNull(Parse*, int); void sqlite3AddPrimaryKey(Parse*, IdList*, int); void sqlite3AddColumnType(Parse*,Token*,Token*); void sqlite3AddDefaultValue(Parse*,Token*,int); -int sqlite3CollateType(const char*, int); -void sqlite3AddCollateType(Parse*, int); +void sqlite3AddCollateType(Parse*, const char*, int); +CollSeq *sqlite3ChangeCollatingFunction(sqlite*,const char*,int, + void*, int(*)(void*,int,const void*,int,const void*)); void sqlite3EndTable(Parse*,Token*,Select*); void sqlite3CreateView(Parse*,Token*,Token*,Select*,int); int sqlite3ViewGetColumnNames(Parse*,Table*); @@ -1343,4 +1353,3 @@ int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity); char sqlite3ExprAffinity(Expr *pExpr); int sqlite3atoi64(const char*, i64*); void sqlite3Error(sqlite *, int, const char*,...); - diff --git a/src/test1.c b/src/test1.c index bff18c97f7..3636d81d2d 100644 --- a/src/test1.c +++ b/src/test1.c @@ -13,7 +13,7 @@ ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** -** $Id: test1.c,v 1.42 2004/05/20 11:00:52 danielk1977 Exp $ +** $Id: test1.c,v 1.43 2004/05/20 22:16:30 drh Exp $ */ #include "sqliteInt.h" #include "tcl.h" @@ -1407,6 +1407,49 @@ static int test_prepare16( return TCL_OK; } + +/* +** This is a collating function named "REVERSE" which sorts text +** in reverse order. +*/ +static int reverseCollatingFunc( + void *NotUsed, + int nKey1, const void *pKey1, + int nKey2, const void *pKey2 +){ + int rc, n; + n = nKey1pIndex; pIdx; pIdx=pIdx->pNext, i++){ if( openAll || aIdxUsed[i] ){ sqlite3VdbeAddOp(v, OP_Integer, pIdx->iDb, 0); - sqlite3VdbeAddOp(v, OP_OpenWrite, iCur+i+1, pIdx->tnum); + sqlite3VdbeOp3(v, OP_OpenWrite, iCur+i+1, pIdx->tnum, + (char*)&pIdx->keyInfo, P3_KEYINFO); assert( pParse->nTab>iCur+i+1 ); } } diff --git a/src/vdbe.c b/src/vdbe.c index ee12fc4cce..daa1528f84 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -43,7 +43,7 @@ ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** -** $Id: vdbe.c,v 1.308 2004/05/20 13:54:54 drh Exp $ +** $Id: vdbe.c,v 1.309 2004/05/20 22:16:30 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -2187,7 +2187,7 @@ case OP_MakeRecord: { ** 't' TEXT ** 'o' NONE ** -** If P3 is NULL then all index fields have the affinity NUMERIC. +** If P3 is NULL then datatype coercion occurs. */ case OP_MakeKey: case OP_MakeIdxKey: { @@ -2202,8 +2202,8 @@ case OP_MakeIdxKey: { int offset = 0; char *zAffinity = pOp->p3; - assert( zAffinity ); nField = pOp->p1; + assert( zAffinity==0 || strlen(zAffinity)>=nField ); pData0 = &pTos[1-nField]; assert( pData0>=p->aStack ); @@ -2223,7 +2223,9 @@ case OP_MakeIdxKey: { */ for(pRec=pData0; pRec<=pTos; pRec++){ u64 serial_type; - applyAffinity(pRec, zAffinity[pRec-pData0]); + if( zAffinity ){ + applyAffinity(pRec, zAffinity[pRec-pData0]); + } if( pRec->flags&MEM_Null ){ containsNull = 1; } @@ -2513,10 +2515,9 @@ case OP_VerifyCookie: { ** to get a read lock but fails, the script terminates with an ** SQLITE_BUSY error code. ** -** The P3 value is the name of the table or index being opened. -** The P3 value is not actually used by this opcode and may be -** omitted. But the code generator usually inserts the index or -** table name into P3 to make the code easier to read. +** The P3 value is a pointer to a KeyInfo structure that defines the +** content and collating sequence of indices. P3 is NULL for cursors +** that are not pointing to indices. ** ** See also OpenWrite. */ @@ -2525,10 +2526,9 @@ case OP_VerifyCookie: { ** Open a read/write cursor named P1 on the table or index whose root ** page is P2. If P2==0 then take the root page number from the stack. ** -** The P3 value is the name of the table or index being opened. -** The P3 value is not actually used by this opcode and may be -** omitted. But the code generator usually inserts the index or -** table name into P3 to make the code easier to read. +** The P3 value is a pointer to a KeyInfo structure that defines the +** content and collating sequence of indices. P3 is NULL for cursors +** that are not pointing to indices. ** ** This instruction works just like OpenRead except that it opens the cursor ** in read/write mode. For a given table, there can be one or more read-only @@ -2576,8 +2576,15 @@ case OP_OpenWrite: { ** sqlite3VdbeKeyCompare(). If the table being opened is of type ** INTKEY, the btree layer won't call the comparison function anyway. */ - rc = sqlite3BtreeCursor(pX, p2, wrFlag, sqlite3VdbeKeyCompare, pCur, - &pCur->pCursor); + rc = sqlite3BtreeCursor(pX, p2, wrFlag, + sqlite3VdbeKeyCompare, pOp->p3, + &pCur->pCursor); + pCur->pKeyInfo = (KeyInfo*)pOp->p3; + if( pCur->pKeyInfo ){ + pCur->pIncrKey = &pCur->pKeyInfo->incrKey; + }else{ + pCur->pIncrKey = &pCur->bogusIncrKey; + } switch( rc ){ case SQLITE_BUSY: { if( db->xBusyCallback==0 ){ @@ -2611,16 +2618,16 @@ case OP_OpenWrite: { break; } -/* Opcode: OpenTemp P1 P2 * +/* Opcode: OpenTemp P1 * P3 ** ** Open a new cursor to a transient table. ** The transient cursor is always opened read/write even if ** the main database is read-only. The transient table is deleted ** automatically when the cursor is closed. ** -** The cursor points to a BTree table if P2==0 and to a BTree index -** if P2==1. A BTree table must have an integer key and can have arbitrary -** data. A BTree index has no data but can have an arbitrary key. +** The cursor points to a BTree table if P3==0 and to a BTree index +** if P3 is not 0. If P3 is not NULL, it points to a KeyInfo structure +** that defines the format of keys in the index. ** ** This opcode is used for tables that exist for the duration of a single ** SQL statement only. Tables created using CREATE TEMPORARY TABLE @@ -2649,17 +2656,21 @@ case OP_OpenTemp: { ** opening it. If a transient table is required, just use the ** automatically created table with root-page 1 (an INTKEY table). */ - if( pOp->p2 ){ + if( pOp->p3 ){ int pgno; + assert( pOp->p3type==P3_KEYINFO ); rc = sqlite3BtreeCreateTable(pCx->pBt, &pgno, BTREE_ZERODATA); if( rc==SQLITE_OK ){ assert( pgno==MASTER_ROOT+1 ); rc = sqlite3BtreeCursor(pCx->pBt, pgno, 1, sqlite3VdbeKeyCompare, - pCx, &pCx->pCursor); + pOp->p3, &pCx->pCursor); + pCx->pKeyInfo = (KeyInfo*)pOp->p3; + pCx->pIncrKey = &pCx->pKeyInfo->incrKey; } }else{ rc = sqlite3BtreeCursor(pCx->pBt, MASTER_ROOT, 1, 0, 0, &pCx->pCursor); pCx->intKey = 1; + pCx->pIncrKey = &pCx->bogusIncrKey; } } break; @@ -2685,6 +2696,7 @@ case OP_OpenPseudo: { memset(pCx, 0, sizeof(*pCx)); pCx->nullRow = 1; pCx->pseudoTable = 1; + pCx->pIncrKey = &pCx->bogusIncrKey; break; } @@ -2755,7 +2767,7 @@ case OP_MoveGt: { int res, oc; oc = pOp->opcode; pC->nullRow = 0; - pC->incrKey = oc==OP_MoveGt || oc==OP_MoveLe; + *pC->pIncrKey = oc==OP_MoveGt || oc==OP_MoveLe; if( pC->intKey ){ i64 iKey; assert( !pOp->p3 ); @@ -2772,17 +2784,13 @@ case OP_MoveGt: { pC->lastRecno = pTos->i; pC->recnoIsValid = res==0; }else{ - if( pOp->p3 ){ - pC->incrKey = 1; - } Stringify(pTos); sqlite3BtreeMoveto(pC->pCursor, pTos->z, pTos->n, &res); - pC->incrKey = 0; pC->recnoIsValid = 0; } pC->deferredMoveto = 0; pC->cacheValid = 0; - pC->incrKey = 0; + *pC->pIncrKey = 0; sqlite3_search_count++; if( oc==OP_MoveGe || oc==OP_MoveGt ){ if( res<0 ){ @@ -3282,7 +3290,7 @@ case OP_KeyAsData: { assert( i>=0 && inCursor ); pC = p->apCsr[i]; pC->keyAsData = pOp->p2; - sqlite3BtreeSetCompare(pC->pCursor, sqlite3VdbeRowCompare, pC); + sqlite3BtreeSetCompare(pC->pCursor, sqlite3VdbeRowCompare, pC->pKeyInfo); break; } @@ -3811,10 +3819,10 @@ case OP_IdxGE: { Stringify(pTos); assert( pC->deferredMoveto==0 ); - pC->incrKey = pOp->p3!=0; + *pC->pIncrKey = pOp->p3!=0; assert( pOp->p3==0 || pOp->opcode!=OP_IdxGT ); rc = sqlite3VdbeIdxKeyCompare(pC, pTos->n, pTos->z, &res); - pC->incrKey = 0; + *pC->pIncrKey = 0; if( rc!=SQLITE_OK ){ break; } diff --git a/src/vdbe.h b/src/vdbe.h index b997ce98fb..c368ccda46 100644 --- a/src/vdbe.h +++ b/src/vdbe.h @@ -15,7 +15,7 @@ ** or VDBE. The VDBE implements an abstract machine that runs a ** simple program to access and modify the underlying database. ** -** $Id: vdbe.h,v 1.78 2004/05/20 13:54:54 drh Exp $ +** $Id: vdbe.h,v 1.79 2004/05/20 22:16:30 drh Exp $ */ #ifndef _SQLITE_VDBE_H_ #define _SQLITE_VDBE_H_ @@ -39,6 +39,9 @@ struct VdbeOp { int p2; /* Second parameter (often the jump destination) */ char *p3; /* Third parameter */ int p3type; /* P3_STATIC, P3_DYNAMIC or P3_POINTER */ +#ifndef NDEBUG + char *zComment; /* Comments explaining what this opcode does */ +#endif #ifdef VDBE_PROFILE int cnt; /* Number of times this instruction was executed */ long long cycles; /* Total time spend executing this instruction */ @@ -66,6 +69,7 @@ typedef struct VdbeOpList VdbeOpList; #define P3_STATIC (-2) /* Pointer to a static string */ #define P3_POINTER (-3) /* P3 is a pointer to some structure or object */ #define P3_COLLSEQ (-4) /* P3 is a pointer to a CollSeq structure */ +#define P3_KEYINFO (-5) /* P3 is a pointer to a KeyInfo structure */ /* ** The following macro converts a relative address in the p2 field @@ -81,22 +85,6 @@ typedef struct VdbeOpList VdbeOpList; */ #include "opcodes.h" -/* -** An instance of the following structure is passed as the first -** argument to sqlite3VdbeKeyCompare and is used to control the -** comparison of the two keys. -** -** If the KeyInfo.incrKey value is true and the comparison would -** otherwise be equal, then return a result as if the second key larger. -*/ -typedef struct KeyInfo KeyInfo; -struct KeyInfo { - u8 incrKey; /* Increase value of 2nd key by epsilon */ - u8 reverseOrder; /* If true, reverse the comparison order */ - int nField; /* Number of entries in aColl[] */ - struct CollSeq *aColl[1]; /* Collating sequence for each term of the key */ -}; - /* ** Prototypes for the VDBE interface. See comments on the implementation ** for a description of what each of these routines does. @@ -126,4 +114,11 @@ void sqlite3VdbeCompressSpace(Vdbe*,int); int sqlite3VdbeReset(Vdbe*,char **); int sqliteVdbeSetVariables(Vdbe*,int,const char**); +#ifndef NDEBUG + void sqlite3VdbeComment(Vdbe*, const char*, ...); +# define VdbeComment(X) sqlite3VdbeComment X +#else +# define VdbeComment(X) +#endif + #endif diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 3751126aac..38de819816 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -72,12 +72,14 @@ struct Cursor { Bool deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */ Bool intKey; /* True if the table requires integer keys */ Bool zeroData; /* True if table contains keys only - no data */ - Bool incrKey; /* Searches on the table simulate OP_IncrKey */ + u8 bogusIncrKey; /* Something for pIncrKey to point to if pKeyInfo==0 */ i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */ Btree *pBt; /* Separate file holding temporary table */ int nData; /* Number of bytes in pData */ char *pData; /* Data for a NEW or OLD pseudo-table */ i64 iKey; /* Key for the NEW or OLD pseudo-table row */ + u8 *pIncrKey; /* Pointer to pKeyInfo->incrKey */ + KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */ /* Cached information about the header for the data record that the ** cursor is currently pointing to */ diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 45c104bb3c..d92c067cc4 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -100,6 +100,7 @@ int sqlite3VdbeAddOp(Vdbe *p, int op, int p1, int p2){ pOp->p3 = 0; pOp->p3type = P3_NOTUSED; #ifndef NDEBUG + pOp->zComment = 0; if( sqlite3_vdbe_addop_trace ) sqlite3VdbePrintOp(0, i, &p->aOp[i]); #endif return i; @@ -226,6 +227,7 @@ int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp){ pOut->p3 = pIn->p3; pOut->p3type = pIn->p3 ? P3_STATIC : P3_NOTUSED; #ifndef NDEBUG + pOut->zComment = 0; if( sqlite3_vdbe_addop_trace ){ sqlite3VdbePrintOp(0, i+addr, &p->aOp[i+addr]); } @@ -274,7 +276,10 @@ void sqlite3VdbeChangeP2(Vdbe *p, int addr, int val){ ** ** If n==P3_STATIC it means that zP3 is a pointer to a constant static ** string and we can just copy the pointer. n==P3_POINTER means zP3 is -** a pointer to some object other than a string. +** a pointer to some object other than a string. n==P3_COLLSEQ and +** n==P3_KEYINFO mean that zP3 is a pointer to a CollSeq or KeyInfo +** structure. A copy is made of KeyInfo structures into memory obtained +** from sqliteMalloc. ** ** If addr<0 then change P3 on the most recently inserted instruction. */ @@ -294,6 +299,19 @@ void sqlite3VdbeChangeP3(Vdbe *p, int addr, const char *zP3, int n){ if( zP3==0 ){ pOp->p3 = 0; pOp->p3type = P3_NOTUSED; + }else if( n==P3_KEYINFO ){ + KeyInfo *pKeyInfo; + int nField, nByte; + nField = ((KeyInfo*)zP3)->nField; + nByte = sizeof(*pKeyInfo) + (nField-1)*sizeof(pKeyInfo->aColl[0]); + pKeyInfo = sqliteMalloc( nByte ); + pOp->p3 = (char*)pKeyInfo; + if( pKeyInfo ){ + memcpy(pKeyInfo, zP3, nByte); + pOp->p3type = P3_KEYINFO; + }else{ + pOp->p3type = P3_NOTUSED; + } }else if( n<0 ){ pOp->p3 = (char*)zP3; pOp->p3type = n; @@ -322,11 +340,11 @@ void sqlite3VdbeDequoteP3(Vdbe *p, int addr){ } pOp = &p->aOp[addr]; if( pOp->p3==0 || pOp->p3[0]==0 ) return; - if( pOp->p3type==P3_POINTER ) return; - if( pOp->p3type!=P3_DYNAMIC ){ + if( pOp->p3type==P3_STATIC ){ pOp->p3 = sqliteStrDup(pOp->p3); pOp->p3type = P3_DYNAMIC; } + assert( pOp->p3type==P3_DYNAMIC ); sqlite3Dequote(pOp->p3); } @@ -342,13 +360,11 @@ void sqlite3VdbeCompressSpace(Vdbe *p, int addr){ assert( p->magic==VDBE_MAGIC_INIT ); if( p->aOp==0 || addr<0 || addr>=p->nOp ) return; pOp = &p->aOp[addr]; - if( pOp->p3type==P3_POINTER ){ - return; - } - if( pOp->p3type!=P3_DYNAMIC ){ + if( pOp->p3type==P3_STATIC ){ pOp->p3 = sqliteStrDup(pOp->p3); pOp->p3type = P3_DYNAMIC; } + assert( pOp->p3type==P3_DYNAMIC ); z = (unsigned char*)pOp->p3; if( z==0 ) return; i = j = 0; @@ -365,6 +381,23 @@ void sqlite3VdbeCompressSpace(Vdbe *p, int addr){ z[j] = 0; } +#ifndef NDEBUG +/* +** Add comment text to the most recently inserted opcode +*/ +void sqlite3VdbeAddComment(Vdbe *p, const char *zFormat, ...){ + va_list ap; + VdbeOp *pOp; + char *zText; + va_start(ap, zFormat); + zText = sqlite3_vmprintf(zFormat, ap); + va_end(ap); + pOp = &p->aOp[p->nOp-1]; + sqliteFree(pOp->zComment); + pOp->zComment = zText; +} +#endif + /* ** Search the current program starting at instruction addr for the given ** opcode and P2 value. Return the address plus 1 if found and 0 if not @@ -504,22 +537,85 @@ int sqlite3_aggregate_count(sqlite_func *p){ return p->cnt; } +/* +** Compute a string that describes the P3 parameter for an opcode. +** Use zTemp for any required temporary buffer space. +*/ +static char *displayP3(Op *pOp, char *zTemp, int nTemp){ + char *zP3; + assert( nTemp>=20 ); + switch( pOp->p3type ){ + case P3_POINTER: { + sprintf(zTemp, "ptr(%#x)", (int)pOp->p3); + zP3 = zTemp; + break; + } + case P3_KEYINFO: { + int i, j; + KeyInfo *pKeyInfo = (KeyInfo*)pOp->p3; + sprintf(zTemp, "keyinfo(%d", pKeyInfo->nField); + i = strlen(zTemp); + for(j=0; jnField; j++){ + CollSeq *pColl = pKeyInfo->aColl[j]; + if( pColl ){ + int n = strlen(pColl->zName); + if( i+n>nTemp-6 ){ + strcpy(&zTemp[i],",..."); + break; + } + zTemp[i++] = ','; + if( pColl->reverseOrder ){ + zTemp[i++] = '-'; + } + strcpy(&zTemp[i], pColl->zName); + i += n; + }else if( i+4p3; + sprintf(zTemp, "collseq(%s%.20s)", + pColl->reverseOrder ? "-" : "", pColl->zName); + zP3 = zTemp; + break; + } + default: { + zP3 = pOp->p3; + if( zP3==0 ){ + zP3 = ""; + } + } + } + return zP3; +} + + #if !defined(NDEBUG) || defined(VDBE_PROFILE) /* ** Print a single opcode. This routine is used for debugging only. */ void sqlite3VdbePrintOp(FILE *pOut, int pc, Op *pOp){ char *zP3; - char zPtr[40]; - if( pOp->p3type==P3_POINTER ){ - sprintf(zPtr, "ptr(%#x)", (int)pOp->p3); - zP3 = zPtr; - }else{ - zP3 = pOp->p3; - } + char zPtr[50]; + static const char *zFormat1 = "%4d %-13s %4d %4d %s\n"; + static const char *zFormat2 = "%4d %-13s %4d %4d %-20s -- %s\n"; if( pOut==0 ) pOut = stdout; - fprintf(pOut,"%4d %-12s %4d %4d %s\n", - pc, sqlite3OpcodeNames[pOp->opcode], pOp->p1, pOp->p2, zP3 ? zP3 : ""); + zP3 = displayP3(pOp, zPtr, sizeof(zPtr)); +#ifdef NDEBUG + fprintf(pOut, zFormat1, + pc, sqlite3OpcodeNames[pOp->opcode], pOp->p1, pOp->p2, zP3); +#else + fprintf(pOut, pOp->zComment ? zFormat2 : zFormat1, + pc, sqlite3OpcodeNames[pOp->opcode], pOp->p1, pOp->p2, zP3,pOp->zComment); +#endif fflush(pOut); } #endif @@ -562,16 +658,13 @@ int sqlite3VdbeList( rc = SQLITE_ERROR; sqlite3SetString(&p->zErrMsg, sqlite3_error_string(p->rc), (char*)0); }else{ + Op *pOp = &p->aOp[i]; sprintf(p->zArgv[0],"%d",i); - sprintf(p->zArgv[2],"%d", p->aOp[i].p1); - sprintf(p->zArgv[3],"%d", p->aOp[i].p2); - if( p->aOp[i].p3type==P3_POINTER ){ - sprintf(p->aStack[4].zShort, "ptr(%#x)", (int)p->aOp[i].p3); - p->zArgv[4] = p->aStack[4].zShort; - }else{ - p->zArgv[4] = p->aOp[i].p3; - } - p->zArgv[1] = sqlite3OpcodeNames[p->aOp[i].opcode]; + sprintf(p->zArgv[2],"%d", pOp->p1); + sprintf(p->zArgv[3],"%d", pOp->p2); + p->zArgv[4] = + displayP3(pOp, p->aStack[4].zShort, sizeof(p->aStack[4].zShort)); + p->zArgv[1] = sqlite3OpcodeNames[pOp->opcode]; p->pc = i+1; p->azResColumn = p->zArgv; p->nResColumn = 5; @@ -1165,9 +1258,13 @@ void sqlite3VdbeDelete(Vdbe *p){ p->nOp = 0; } for(i=0; inOp; i++){ - if( p->aOp[i].p3type==P3_DYNAMIC ){ - sqliteFree(p->aOp[i].p3); + Op *pOp = &p->aOp[i]; + if( pOp->p3type==P3_DYNAMIC || pOp->p3type==P3_KEYINFO ){ + sqliteFree(pOp->p3); } +#ifndef NDEBUG + sqliteFree(pOp->zComment); +#endif } for(i=0; inVar; i++){ if( p->apVar[i].flags&MEM_Dyn ){ @@ -1196,7 +1293,7 @@ int sqlite3VdbeCursorMoveto(Cursor *p){ }else{ sqlite3BtreeMoveto(p->pCursor,(char*)&p->movetoTarget,sizeof(i64),&res); } - p->incrKey = 0; + *p->pIncrKey = 0; p->lastRecno = keyToInt(p->movetoTarget); p->recnoIsValid = res==0; if( res<0 ){ @@ -1421,8 +1518,8 @@ int sqlite3VdbeSerialGet(const unsigned char *buf, u64 serial_type, Mem *pMem){ ** Compare the values contained by the two memory cells, returning ** negative, zero or positive if pMem1 is less than, equal to, or greater ** than pMem2. Sorting order is NULL's first, followed by numbers (integers -** and reals) sorted numerically, followed by text ordered by memcmp() and -** finally blob's ordered by memcmp(). +** and reals) sorted numerically, followed by text ordered by the collating +** sequence pColl and finally blob's ordered by memcmp(). ** ** Two NULL values are considered equal by this function. */ @@ -1531,12 +1628,14 @@ int sqlite3VdbeKeyCompare( int nKey1, const void *pKey1, int nKey2, const void *pKey2 ){ - Cursor *pC = (Cursor *)userData; + KeyInfo *pKeyInfo = (KeyInfo*)userData; int offset1 = 0; int offset2 = 0; + int i = 0; const unsigned char *aKey1 = (const unsigned char *)pKey1; const unsigned char *aKey2 = (const unsigned char *)pKey2; + assert( pKeyInfo!=0 ); while( offset1incrKey ); sqlite3GetVarint(&aKey1[offset1], &serial_type1); sqlite3GetVarint(&aKey2[offset2], &serial_type2); return ( (i64)serial_type1 - (i64)serial_type2 ); } + assert( inField ); + /* Assert that there is enough space left in each key for the blob of ** data to go with the serial type just read. This assert may fail if ** the file is corrupted. Then read the value from each key into mem1 @@ -1569,7 +1669,7 @@ int sqlite3VdbeKeyCompare( offset1 += sqlite3VdbeSerialGet(&aKey1[offset1], serial_type1, &mem1); offset2 += sqlite3VdbeSerialGet(&aKey2[offset2], serial_type2, &mem2); - rc = sqlite3MemCompare(&mem1, &mem2, 0); + rc = sqlite3MemCompare(&mem1, &mem2, pKeyInfo->aColl[i]); if( mem1.flags&MEM_Dyn ){ sqliteFree(mem1.z); } @@ -1579,13 +1679,14 @@ int sqlite3VdbeKeyCompare( if( rc!=0 ){ return rc; } + i++; } /* One of the keys ran out of fields, but all the fields up to that point ** were equal. If the incrKey flag is true, then the second key is ** treated as larger. */ - if( pC && pC->incrKey ){ + if( pKeyInfo->incrKey ){ assert( offset2==nKey2 ); return -1; } @@ -1615,7 +1716,7 @@ int sqlite3VdbeRowCompare( int nKey1, const void *pKey1, int nKey2, const void *pKey2 ){ - Cursor *pC = (Cursor *)userData; + KeyInfo *pKeyInfo = (KeyInfo*)userData; int offset1 = 0; int offset2 = 0; int toffset1 = 0; @@ -1624,16 +1725,16 @@ int sqlite3VdbeRowCompare( const unsigned char *aKey1 = (const unsigned char *)pKey1; const unsigned char *aKey2 = (const unsigned char *)pKey2; - assert( pC ); - assert( pC->nField>0 ); + assert( pKeyInfo ); + assert( pKeyInfo->nField>0 ); - for( i=0; inField; i++ ){ + for( i=0; inField; i++ ){ u64 dummy; offset1 += sqlite3GetVarint(&aKey1[offset1], &dummy); offset2 += sqlite3GetVarint(&aKey1[offset1], &dummy); } - for( i=0; inField; i++ ){ + for( i=0; inField; i++ ){ Mem mem1; Mem mem2; u64 serial_type1; @@ -1654,7 +1755,7 @@ int sqlite3VdbeRowCompare( offset1 += sqlite3VdbeSerialGet(&aKey1[offset1], serial_type1, &mem1); offset2 += sqlite3VdbeSerialGet(&aKey2[offset2], serial_type2, &mem2); - rc = sqlite3MemCompare(&mem1, &mem2, 0); + rc = sqlite3MemCompare(&mem1, &mem2, pKeyInfo->aColl[i]); if( mem1.flags&MEM_Dyn ){ sqliteFree(mem1.z); } @@ -1712,10 +1813,12 @@ int sqlite3VdbeIdxRowid(BtCursor *pCur, i64 *rowid){ } /* -** Compare the key of index entry that cursor pC is point to against +** Compare the key of the index entry that cursor pC is point to against ** the key string in pKey (of length nKey). Write into *pRes a number ** that is negative, zero, or positive if pC is less than, equal to, ** or greater than pKey. Return SQLITE_OK on success. +** +** pKey might contain fewer terms than the cursor. */ int sqlite3VdbeIdxKeyCompare( Cursor *pC, /* The cursor to compare against */ @@ -1752,7 +1855,7 @@ int sqlite3VdbeIdxKeyCompare( len = nCellKey-2; while( pCellKey[len] && --len ); - *res = sqlite3VdbeKeyCompare(pC, len, pCellKey, nKey, pKey); + *res = sqlite3VdbeKeyCompare(pC->pKeyInfo, len, pCellKey, nKey, pKey); if( freeCellKey ){ sqliteFree(pCellKey); diff --git a/src/where.c b/src/where.c index af4fa53a90..29143aff6d 100644 --- a/src/where.c +++ b/src/where.c @@ -12,7 +12,7 @@ ** This module contains C code that generates VDBE code used to process ** the WHERE clause of SQL statements. ** -** $Id: where.c,v 1.99 2004/05/19 20:41:04 drh Exp $ +** $Id: where.c,v 1.100 2004/05/20 22:16:30 drh Exp $ */ #include "sqliteInt.h" @@ -222,15 +222,15 @@ static Index *findSortingIndex( assert( pOrderBy!=0 ); assert( pOrderBy->nExpr>0 ); - sortOrder = pOrderBy->a[0].sortOrder & SQLITE_SO_DIRMASK; + sortOrder = pOrderBy->a[0].sortOrder; for(i=0; inExpr; i++){ Expr *p; - if( (pOrderBy->a[i].sortOrder & SQLITE_SO_DIRMASK)!=sortOrder ){ + if( pOrderBy->a[i].sortOrder!=sortOrder ){ /* Indices can only be used if all ORDER BY terms are either ** DESC or ASC. Indices cannot be used on a mixture. */ return 0; } - if( (pOrderBy->a[i].sortOrder & SQLITE_SO_TYPEMASK)!=SQLITE_SO_UNK ){ + if( pOrderBy->a[i].zName!=0 ){ /* Do not sort by index if there is a COLLATE clause */ return 0; } @@ -678,13 +678,13 @@ WhereInfo *sqlite3WhereBegin( pTab = pTabList->a[i].pTab; if( pTab->isTransient || pTab->pSelect ) continue; sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0); - sqlite3VdbeOp3(v, OP_OpenRead, pTabList->a[i].iCursor, pTab->tnum, - pTab->zName, P3_STATIC); + sqlite3VdbeAddOp(v, OP_OpenRead, pTabList->a[i].iCursor, pTab->tnum); sqlite3VdbeAddOp(v, OP_SetNumColumns, pTabList->a[i].iCursor, pTab->nCol); sqlite3CodeVerifySchema(pParse, pTab->iDb); if( (pIx = pWInfo->a[i].pIdx)!=0 ){ sqlite3VdbeAddOp(v, OP_Integer, pIx->iDb, 0); - sqlite3VdbeOp3(v, OP_OpenRead, pWInfo->a[i].iCur, pIx->tnum,pIx->zName,0); + sqlite3VdbeOp3(v, OP_OpenRead, pWInfo->a[i].iCur, pIx->tnum, + (char*)&pIx->keyInfo, P3_KEYINFO); } } diff --git a/test/btree6.test b/test/btree6.test index 2591c91477..2d311577b6 100644 --- a/test/btree6.test +++ b/test/btree6.test @@ -13,7 +13,7 @@ # the B+tree tables. B+trees store all data on the leaves rather # that storing data with keys on interior nodes. # -# $Id: btree6.test,v 1.3 2004/05/13 11:34:17 danielk1977 Exp $ +# $Id: btree6.test,v 1.4 2004/05/20 22:16:31 drh Exp $ set testdir [file dirname $argv0] @@ -102,7 +102,7 @@ expr srand(1) # Do the tests. # set cnt 0 -for {set i 1} {$i<=100} {incr i} { +for {set i 1} {$i<=40} {incr i} { do_test btree6-1.$i.1 { random_inserts $cur 200 incr cnt 200 diff --git a/test/tester.tcl b/test/tester.tcl index 33014ccb66..cc09d9593b 100644 --- a/test/tester.tcl +++ b/test/tester.tcl @@ -11,7 +11,7 @@ # This file implements some common TCL routines used for regression # testing the SQLite library # -# $Id: tester.tcl,v 1.32 2004/05/12 11:24:03 danielk1977 Exp $ +# $Id: tester.tcl,v 1.33 2004/05/20 22:16:31 drh Exp $ # Make sure tclsqlite was compiled correctly. Abort now with an # error message if not. @@ -74,11 +74,12 @@ set nTest 0 set nProb 0 set skip_test 0 set failList {} +set maxErr 1000 # Invoke the do_test procedure to run a single test # proc do_test {name cmd expected} { - global argv nErr nTest skip_test + global argv nErr nTest skip_test maxErr if {$skip_test} { set skip_test 0 return @@ -102,12 +103,12 @@ proc do_test {name cmd expected} { puts "\nError: $result" incr nErr lappend ::failList $name - if {$nErr>100} {puts "*** Giving up..."; finalize_testing} + if {$nErr>$maxErr} {puts "*** Giving up..."; finalize_testing} } elseif {[string compare $result $expected]} { puts "\nExpected: \[$expected\]\n Got: \[$result\]" incr nErr lappend ::failList $name - if {$nErr>=100} {puts "*** Giving up..."; finalize_testing} + if {$nErr>=$maxErr} {puts "*** Giving up..."; finalize_testing} } else { puts " Ok" }