Add internal support for collating sequences. This breaks 244 tests. (CVS 1420)

FossilOrigin-Name: a6cb09d7af537726acc87b9133f68c81e839e047
This commit is contained in:
drh 2004-05-20 22:16:29 +00:00
parent 53db145800
commit d3d39e939d
20 changed files with 530 additions and 445 deletions

View File

@ -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

View File

@ -1 +1 @@
5c1e47a25244eacc69b688f5f4e62cec9f09665a
a6cb09d7af537726acc87b9133f68c81e839e047

View File

@ -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;

View File

@ -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 <ctype.h>
@ -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; 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;
}
@ -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; 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;
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);

View File

@ -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 <ctype.h>
@ -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->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 ){
@ -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; 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;
}
/*
@ -1444,9 +1364,8 @@ int sqlite3ExprCodeExprList(
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;

View File

@ -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;
}

View File

@ -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 = 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.
@ -399,12 +417,15 @@ sqlite *sqlite3_open(const char *zFilename, int mode, char **pzErrMsg){
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 ){

View File

@ -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($$);}

View File

@ -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 <ctype.h>
@ -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);

View File

@ -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; 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);
@ -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; 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.
@ -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; 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;
@ -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; 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.
@ -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; 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++){

View File

@ -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*,...);

View File

@ -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 = 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.
*/
@ -1419,31 +1462,31 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
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;
@ -1461,6 +1504,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "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;
@ -1482,5 +1526,3 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
(char*)&sqlite_static_bind_value, TCL_LINK_STRING);
return TCL_OK;
}

View File

@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser
** to handle UPDATE statements.
**
** $Id: update.c,v 1.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"
@ -331,7 +331,8 @@ void sqlite3Update(
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 );
}
}

View File

@ -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 && i<p->nCursor );
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;
}

View File

@ -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

View File

@ -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 */

View File

@ -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; 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
@ -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; 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 ){
@ -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( offset1<nKey1 && offset2<nKey2 ){
Mem mem1;
Mem mem2;
@ -1555,12 +1654,13 @@ int sqlite3VdbeKeyCompare(
*/
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
@ -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; 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;
@ -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);

View File

@ -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; 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;
}
@ -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);
}
}

View File

@ -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

View File

@ -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"
}