-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
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
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
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
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
-5c1e47a25244eacc69b688f5f4e62cec9f09665a
\ No newline at end of file
+a6cb09d7af537726acc87b9133f68c81e839e047
\ No newline at end of file
** 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
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;
** 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 <ctype.h>
** will be called next to set pCol->affinity correctly.
*/
pCol->affinity = SQLITE_AFF_NUMERIC;
+ pCol->pColl = pParse->db->pDfltColl;
p->nCol++;
}
}else{
for(i=0; i<pList->nId; i++){
for(iCol=0; iCol<pTab->nCol; 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( iCol<pTab->nCol ) pTab->aCol[iCol].isPrimKey = 1;
}
}
/*
-** 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; i<nType-3; i++){
- int c = *(zType++) | 0x60;
- if( (c=='b' || c=='c') && sqlite3StrNICmp(zType, "lob", 3)==0 ){
- return SQLITE_SO_TEXT;
- }
- if( c=='c' && sqlite3StrNICmp(zType, "har", 3)==0 ){
- return SQLITE_SO_TEXT;
- }
- if( c=='t' && sqlite3StrNICmp(zType, "ext", 3)==0 ){
- return SQLITE_SO_TEXT;
- }
+CollSeq *sqlite3CollateType(Parse *pParse, const char *zType, int nType){
+ CollSeq *pColl;
+ sqlite *db = pParse->db;
+
+ 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;
+ CollSeq *pColl;
+ sqlite *db = pParse->db;
+
if( (p = pParse->pNewTable)==0 ) return;
- i = p->nCol-1;
+ 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;
+ }
+}
- /* FIX ME */
- /* if( i>=0 ) p->aCol[i].sortOrder = collType; */
+/*
+** 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;
}
/*
** 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;
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.
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 ){
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);
** 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 <ctype.h>
/* 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;
}
}
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;
}
}
if( cnt==0 && cntTab==1 && sqlite3IsRowid(zCol) ){
cnt = 1;
pExpr->iColumn = -1;
- pExpr->dataType = SQLITE_SO_NUM;
pExpr->affinity = SQLITE_AFF_INTEGER;
}
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;
** 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 ...)
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->dataType<n ){
- pExpr->dataType =
- 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; i<n; i++){
- if( sqlite3ExprType(pExpr->pList->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 ){
}
/*
-** 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_SELECT:
- assert( p->pSelect );
- assert( p->pSelect->pEList );
- assert( p->pSelect->pEList->nExpr>0 );
- p = p->pSelect->pEList->a[0].pExpr;
- break;
+ case TK_NULL:
+ return SQLITE_AFF_NONE;
- 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; i<pList->nExpr; 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;
}
/*
for(pItem=pList->a, i=0; i<n; i++, pItem++){
sqlite3ExprCode(pParse, pItem->pExpr);
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;
** 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"
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;
}
** 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"
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 = nKey1<nKey2 ? nKey1 : nKey2;
+ rc = memcmp(pKey1, pKey2, n);
+ if( rc==0 ){
+ rc = nKey1 - nKey2;
+ }
+ return rc;
+}
+
/*
** Open a new SQLite database. Construct an "sqlite" structure to define
** the state of this database and return a pointer to that structure.
db->aDb = db->aDbStatic;
/* db->flags |= SQLITE_ShortColNames; */
sqlite3HashInit(&db->aFunc, SQLITE_HASH_STRING, 1);
+ sqlite3HashInit(&db->aCollSeq, SQLITE_HASH_STRING, 0);
for(i=0; i<db->nDb; 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 ){
** 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}
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
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($$);}
*************************************************************************
** 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 <ctype.h>
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);
** 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"
if( zSortOrder==0 ) return;
for(i=0; i<pOrderBy->nExpr; 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);
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; i<nColumn; i++){
- zType[i] = sqlite3ExprType(pEList->a[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.
#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);
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);
}
**
** 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 */
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; i<pOrderBy->nExpr; i++){
- pOrderBy->a[i].pExpr->dataType = SQLITE_SO_TEXT;
- }
- return;
- }
- multiSelectSortOrder(p->pPrior, pOrderBy);
- pEList = p->pEList;
- for(i=0; i<pOrderBy->nExpr; 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;
}
}
}
+#endif
/*
** Compute the iLimit and iOffset fields of the SELECT based on the
}
}
+/*
+** 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; i<nColumn; i++){
+ pKeyInfo->aColl[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.
Vdbe *v; /* Generate code to this VDBE */
char *affStr = 0;
+#if 0 /* NOT USED */
if( !aff ){
int len;
rc = fillInColumnList(pParse, p);
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.
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);
}
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);
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".
/* 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;
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);
}
multi_select_end:
+#if 0 /*** NOT USED ****/
if( affStr ){
if( rc!=SQLITE_OK ){
sqliteFree(affStr);
sqlite3VdbeOp3(v, OP_Noop, 0, 0, affStr, P3_DYNAMIC);
}
}
+#endif
return rc;
}
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 );
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);
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);
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
if( eDest==SRT_Union ){
sqlite3VdbeAddOp(v, OP_SetNumColumns, iParm, pEList->nExpr);
}
+#endif
/* Generate code for all sub-queries in the FROM clause
*/
*/
if( isDistinct ){
distinct = pParse->nTab++;
- sqlite3VdbeAddOp(v, OP_OpenTemp, distinct, 1);
+ openTempIndex(pParse, p, distinct, 0);
}else{
distinct = -1;
}
for(i=0; i<pGroupBy->nExpr; 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; i<pParse->nAgg; i++, pAgg++){
*************************************************************************
** 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"
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
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 */
};
/*
-** 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.
#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.
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 */
};
/*
*/
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 */
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*);
char sqlite3ExprAffinity(Expr *pExpr);
int sqlite3atoi64(const char*, i64*);
void sqlite3Error(sqlite *, int, const char*,...);
-
** 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"
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 = nKey1<nKey2 ? nKey1 : nKey2;
+ rc = memcmp(pKey1, pKey2, n);
+ if( rc==0 ){
+ rc = nKey1 - nKey2;
+ }
+ return -rc;
+}
+
+/*
+** Usage: add_reverse_collating_func DB
+**
+** This routine adds a collation named "REVERSE" to database given.
+** REVERSE is used for testing only.
+*/
+static int reverse_collfunc(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+ sqlite3 *db;
+
+ if( objc!=2 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "DB");
+ return TCL_ERROR;
+ }
+ if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
+ sqlite3ChangeCollatingFunction(db, "REVERSE", 7, 0, reverseCollatingFunc);
+ return TCL_OK;
+}
+
+
/*
** Register commands with the TCL interpreter.
*/
char *zName;
Tcl_CmdProc *xProc;
} aCmd[] = {
- { "sqlite3_mprintf_int", (Tcl_CmdProc*)sqlite3_mprintf_int },
- { "sqlite3_mprintf_str", (Tcl_CmdProc*)sqlite3_mprintf_str },
- { "sqlite3_mprintf_double", (Tcl_CmdProc*)sqlite3_mprintf_double },
- { "sqlite3_mprintf_scaled", (Tcl_CmdProc*)sqlite3_mprintf_scaled },
- { "sqlite3_mprintf_z_test", (Tcl_CmdProc*)test_mprintf_z },
- { "sqlite3_open", (Tcl_CmdProc*)sqlite_test_open },
- { "sqlite3_last_insert_rowid", (Tcl_CmdProc*)test_last_rowid },
- { "sqlite3_exec_printf", (Tcl_CmdProc*)test_exec_printf },
- { "sqlite3_get_table_printf", (Tcl_CmdProc*)test_get_table_printf },
- { "sqlite3_close", (Tcl_CmdProc*)sqlite_test_close },
- { "sqlite3_create_function", (Tcl_CmdProc*)test_create_function },
- { "sqlite3_create_aggregate", (Tcl_CmdProc*)test_create_aggregate },
- { "sqlite_register_test_function", (Tcl_CmdProc*)test_register_func },
- { "sqlite_abort", (Tcl_CmdProc*)sqlite_abort },
- { "sqlite_datatypes", (Tcl_CmdProc*)sqlite_datatypes },
+ { "sqlite3_mprintf_int", (Tcl_CmdProc*)sqlite3_mprintf_int },
+ { "sqlite3_mprintf_str", (Tcl_CmdProc*)sqlite3_mprintf_str },
+ { "sqlite3_mprintf_double", (Tcl_CmdProc*)sqlite3_mprintf_double },
+ { "sqlite3_mprintf_scaled", (Tcl_CmdProc*)sqlite3_mprintf_scaled },
+ { "sqlite3_mprintf_z_test", (Tcl_CmdProc*)test_mprintf_z },
+ { "sqlite3_open", (Tcl_CmdProc*)sqlite_test_open },
+ { "sqlite3_last_insert_rowid", (Tcl_CmdProc*)test_last_rowid },
+ { "sqlite3_exec_printf", (Tcl_CmdProc*)test_exec_printf },
+ { "sqlite3_get_table_printf", (Tcl_CmdProc*)test_get_table_printf },
+ { "sqlite3_close", (Tcl_CmdProc*)sqlite_test_close },
+ { "sqlite3_create_function", (Tcl_CmdProc*)test_create_function },
+ { "sqlite3_create_aggregate", (Tcl_CmdProc*)test_create_aggregate },
+ { "sqlite_register_test_function", (Tcl_CmdProc*)test_register_func },
+ { "sqlite_abort", (Tcl_CmdProc*)sqlite_abort },
+ { "sqlite_datatypes", (Tcl_CmdProc*)sqlite_datatypes },
#ifdef MEMORY_DEBUG
- { "sqlite_malloc_fail", (Tcl_CmdProc*)sqlite_malloc_fail },
- { "sqlite_malloc_stat", (Tcl_CmdProc*)sqlite_malloc_stat },
+ { "sqlite_malloc_fail", (Tcl_CmdProc*)sqlite_malloc_fail },
+ { "sqlite_malloc_stat", (Tcl_CmdProc*)sqlite_malloc_stat },
#endif
- { "sqlite_compile", (Tcl_CmdProc*)test_compile },
- { "sqlite_step", (Tcl_CmdProc*)test_step },
- { "sqlite_finalize", (Tcl_CmdProc*)test_finalize },
- { "sqlite_bind", (Tcl_CmdProc*)test_bind },
- { "sqlite_reset", (Tcl_CmdProc*)test_reset },
- { "breakpoint", (Tcl_CmdProc*)test_breakpoint },
+ { "sqlite_compile", (Tcl_CmdProc*)test_compile },
+ { "sqlite_step", (Tcl_CmdProc*)test_step },
+ { "sqlite_finalize", (Tcl_CmdProc*)test_finalize },
+ { "sqlite_bind", (Tcl_CmdProc*)test_bind },
+ { "sqlite_reset", (Tcl_CmdProc*)test_reset },
+ { "breakpoint", (Tcl_CmdProc*)test_breakpoint },
};
static struct {
char *zName;
{ "sqlite3_errmsg16", (Tcl_ObjCmdProc*)test_errmsg16 },
{ "sqlite3_prepare", (Tcl_ObjCmdProc*)test_prepare },
{ "sqlite3_prepare16", (Tcl_ObjCmdProc*)test_prepare16 },
+ { "add_reverse_collating_func", (Tcl_ObjCmdProc*)reverse_collfunc },
};
int i;
(char*)&sqlite_static_bind_value, TCL_LINK_STRING);
return TCL_OK;
}
-
-
** This file contains C code routines that are called by the parser
** to handle UPDATE statements.
**
-** $Id: update.c,v 1.77 2004/05/19 14:56:57 drh Exp $
+** $Id: update.c,v 1.78 2004/05/20 22:16:30 drh Exp $
*/
#include "sqliteInt.h"
for(i=0, pIdx=pTab->pIndex; 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 );
}
}
** 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"
** '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: {
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 );
*/
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;
}
** 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.
*/
** 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
** 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 ){
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
** 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;
memset(pCx, 0, sizeof(*pCx));
pCx->nullRow = 1;
pCx->pseudoTable = 1;
+ pCx->pIncrKey = &pCx->bogusIncrKey;
break;
}
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 );
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 ){
assert( i>=0 && i<p->nCursor );
pC = p->apCsr[i];
pC->keyAsData = pOp->p2;
- sqlite3BtreeSetCompare(pC->pCursor, sqlite3VdbeRowCompare, pC);
+ sqlite3BtreeSetCompare(pC->pCursor, sqlite3VdbeRowCompare, pC->pKeyInfo);
break;
}
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;
}
** 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_
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 */
#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
*/
#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.
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
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 */
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;
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]);
}
**
** 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.
*/
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;
}
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);
}
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;
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
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; j<pKeyInfo->nField; 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+4<nTemp-6 ){
+ strcpy(&zTemp[i],",nil");
+ i += 4;
+ }
+ }
+ zTemp[i++] = ')';
+ zTemp[i] = 0;
+ assert( i<nTemp );
+ zP3 = zTemp;
+ break;
+ }
+ case P3_COLLSEQ: {
+ CollSeq *pColl = (CollSeq*)pOp->p3;
+ 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
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;
p->nOp = 0;
}
for(i=0; i<p->nOp; 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; i<p->nVar; i++){
if( p->apVar[i].flags&MEM_Dyn ){
}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 ){
** 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.
*/
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( offset1<nKey1 && offset2<nKey2 ){
Mem mem1;
Mem mem2;
*/
if( !serial_type1 || !serial_type2 ){
assert( !serial_type1 && !serial_type2 );
- assert( !pC || !pC->incrKey );
sqlite3GetVarint(&aKey1[offset1], &serial_type1);
sqlite3GetVarint(&aKey2[offset2], &serial_type2);
return ( (i64)serial_type1 - (i64)serial_type2 );
}
+ assert( i<pKeyInfo->nField );
+
/* 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
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);
}
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;
}
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;
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; i<pC->nField; i++ ){
+ for( i=0; i<pKeyInfo->nField; i++ ){
u64 dummy;
offset1 += sqlite3GetVarint(&aKey1[offset1], &dummy);
offset2 += sqlite3GetVarint(&aKey1[offset1], &dummy);
}
- for( i=0; i<pC->nField; i++ ){
+ for( i=0; i<pKeyInfo->nField; i++ ){
Mem mem1;
Mem mem2;
u64 serial_type1;
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);
}
}
/*
-** 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 */
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);
** 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"
assert( pOrderBy!=0 );
assert( pOrderBy->nExpr>0 );
- sortOrder = pOrderBy->a[0].sortOrder & SQLITE_SO_DIRMASK;
+ sortOrder = pOrderBy->a[0].sortOrder;
for(i=0; i<pOrderBy->nExpr; 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;
}
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);
}
}
# 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]
# 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
# 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.
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
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"
}