From 38640e15af4c00270c20bdf980225e2a6f7423b5 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 5 Jul 2002 21:42:36 +0000 Subject: [PATCH] All the code is now in place for SQLite to distinguish between NUMERIC and TEXT datatypes. Still need to turn on the new code and test it. (CVS 659) FossilOrigin-Name: b4737a16c997a6c139d616211fb6bc4b0fae181c --- manifest | 30 +++++++++---------- manifest.uuid | 2 +- src/build.c | 44 +++++++++++++++++++++++++++- src/delete.c | 9 ++++-- src/insert.c | 5 ++-- src/parse.y | 6 ++-- src/select.c | 73 ++++++++++++++++++++++++++++++++++++--------- src/sqliteInt.h | 8 +++-- src/update.c | 4 +-- src/util.c | 78 +++++++++++++++++++++++++++++-------------------- src/vdbe.c | 6 ++-- test/table.test | 29 ++++++++++++++++-- 12 files changed, 213 insertions(+), 81 deletions(-) diff --git a/manifest b/manifest index 61265ffe64..e8849d23c3 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sfor\sticket\s#92:\sCorrect\sthe\ssqliteExprCompare()\sfunction\sso\sthat\sis\stakes\ninto\saccount\sthe\siTable\sand\siColumn\sfields\sof\sthe\sExpr\sstructure.\s\sOtherwise,\n"min(a)"\sand\s"min(b)"\swill\scompare\sequal\sto\seach\sother\sin\sviews.\s(CVS\s658) -D 2002-07-02T13:05:05 +C All\sthe\scode\sis\snow\sin\splace\sfor\sSQLite\sto\sdistinguish\sbetween\sNUMERIC\sand\nTEXT\sdatatypes.\s\sStill\sneed\sto\sturn\son\sthe\snew\scode\sand\stest\sit.\s(CVS\s659) +D 2002-07-05T21:42:36 F Makefile.in 6291a33b87d2a395aafd7646ee1ed562c6f2c28c F Makefile.template 4e11752e0b5c7a043ca50af4296ec562857ba495 F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0 @@ -20,28 +20,28 @@ F sqlite.1 83f4a9d37bdf2b7ef079a82d54eaf2e3509ee6ea F src/TODO af7f3cab0228e34149cf98e073aa83d45878e7e6 F src/btree.c 6aaa67d7eab70c2531dc13e5d9eb87e626c0b4d7 F src/btree.h 8abeabfe6e0b1a990b64fa457592a6482f6674f3 -F src/build.c 0834185cbe316dda5173de50886ed804b82e3ba6 -F src/delete.c 44c45460b1e03033756e35adc6d569ffbf30b725 +F src/build.c ea4a3bc15d6338294e68100f642edf48e4082403 +F src/delete.c 215492ffcea4262a993e55f3c4a67dc9fea4da9c F src/encode.c 346b12b46148506c32038524b95c4631ab46d760 F src/expr.c 4b25ee5e65f351d40dea8575b998605762556d76 F src/func.c 5eae8227a8b0d276a64d51a3880a6e86f238fedf F src/hash.c 6a6236b89c8c060c65dabd300a1c8ce7c10edb72 F src/hash.h cd0433998bc1a3759d244e1637fe5a3c13b53bf8 -F src/insert.c 4bb40ed9dbaba4516fc2abbcff3f08d5687b073c +F src/insert.c 4511e06abce1688664ce90cbf09fa13433b82c43 F src/main.c 6ac32ca71ab4728212c5b44aed25e26dc6cfe73c F src/md5.c 0ae1f3e2cac92d06fc6246d1b4b8f61a2fe66d3b F src/os.c 9cc40c5384baba4a85e160e67807645ca98ba3cc F src/os.h 4a361fccfbc4e7609b3e1557f604f94c1e96ad10 F src/pager.c 58ae9f569b3c664ea9205c6f6da432e3ae180f56 F src/pager.h 6fddfddd3b73aa8abc081b973886320e3c614f0e -F src/parse.y dcaf21965b6cba956d1ad014b87d849cee52af13 +F src/parse.y 35437ac29441ce2d34904d8e93f40b7d112147a9 F src/printf.c 236ed7a79386feed4456fa728fff8be793f1547c F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe -F src/select.c 63a10ea636c8ac8cdf2fbb804fbfcfd372150717 +F src/select.c 1c7c0b42c27b9d115c955023074a292197a17b3b F src/shell.c 0b06e4421ddf34f30263a2674abe768a2b5fd538 F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e F src/sqlite.h.in 75c5bbb066d0faf34424b7d1babf8b44d5b31af2 -F src/sqliteInt.h 314a4feb08cccdeb90b434e6dde86b93d2f36b8e +F src/sqliteInt.h 6a36f4fc32cbbf3e6bf15516137b113b3dc973aa F src/table.c eed2098c9b577aa17f8abe89313a9c4413f57d63 F src/tclsqlite.c e932591c0bb522b0a35ea7dc861c623ccb2e3aa8 F src/test1.c a2f2b6b1df07d4e8b380323896c3ed34442cea91 @@ -50,9 +50,9 @@ F src/test3.c 72ac6a9017a70e542954907a1dfd87ab6f7824e3 F src/threadtest.c 81f0598e0f031c1bd506af337fdc1b7e8dff263f F src/tokenize.c b5500e193a82b5b9888fbf947efd90d3b4858178 F src/trigger.c d88ab4d68d68955c217b38fb6717e090fbbf54a4 -F src/update.c 06303bf3895032c7eccb748927f650ed02b9f0cf -F src/util.c 876b259f9186e84b944b72e793dd3dad50e63e95 -F src/vdbe.c c83ece2aeb3a6ce7de9a1636c98c3feec9267499 +F src/update.c 494479cc4fe34165cb9ea97bccefb405e7b875d2 +F src/util.c 7a99e754c44dd220e881122e30581c08b6d6adef +F src/vdbe.c 0169270bb73e8dec4174b90dffc7070c4cabe039 F src/vdbe.h a9292f2b5fcecef924fa255fb74609e9cbc776c2 F src/where.c 6a43aa6c80eab12221eeca754cba852a9ecd1e13 F test/all.test e4d3821eeba751829b419cd47814bd20af4286d1 @@ -95,7 +95,7 @@ F test/select5.test c2a6c4a003316ee42cbbd689eebef8fdce0db2ac F test/select6.test efb8d0c07a440441db87db2c4ade6904e1407e85 F test/sort.test 3b996ce7ca385f9cd559944ac0f4027a23aa546b F test/subselect.test 64e71b1be804dc57c72b61d2bd7b506dbc962c40 -F test/table.test 42511f98a3e9bbee62913e3ae1774777faa23d35 +F test/table.test bc571115def9be8adab6df93aca0b0c05c007eea F test/tableapi.test 3c80421a889e1d106df16e5800fa787f0d2914a6 F test/tclsqlite.test 6f4b9760681c7dbca52a18d0ab46a1679cdc79b9 F test/temptable.test 9ed7ec0288f887e132de66d90c428ad109105f67 @@ -137,7 +137,7 @@ F www/speed.tcl da8afcc1d3ccc5696cfb388a68982bc3d9f7f00f F www/sqlite.tcl ae3dcfb077e53833b59d4fcc94d8a12c50a44098 F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331 F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218 -P 3cac283de4939538f09cd11e2cbdc84e9a9602f2 -R dcd0974614e55fffecaf44a18cd6cd53 +P 85793a4f03250166c21007cab3525709592d0866 +R f77acd757b229f1cdb42ab7cac78b933 U drh -Z d34a13be1a939e0f9ee685ea0fba9ad6 +Z 6c4c383ead0a1302c4ea68955c9a4a90 diff --git a/manifest.uuid b/manifest.uuid index 1f47792465..24b731aef6 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -85793a4f03250166c21007cab3525709592d0866 \ No newline at end of file +b4737a16c997a6c139d616211fb6bc4b0fae181c \ No newline at end of file diff --git a/src/build.c b/src/build.c index 47bdf12d90..9f1aa9cd20 100644 --- a/src/build.c +++ b/src/build.c @@ -25,7 +25,7 @@ ** ROLLBACK ** PRAGMA ** -** $Id: build.c,v 1.100 2002/06/28 12:18:47 drh Exp $ +** $Id: build.c,v 1.101 2002/07/05 21:42:36 drh Exp $ */ #include "sqliteInt.h" #include @@ -463,6 +463,14 @@ void sqliteAddColumnType(Parse *pParse, Token *pFirst, Token *pLast){ pCol->sortOrder = SQLITE_SO_NUM; for(i=0; z[i]; i++){ switch( z[i] ){ + case 'b': + case 'B': { + if( sqliteStrNICmp(&z[i],"blob",4)==0 ){ + pCol->sortOrder = SQLITE_SO_TEXT; + return; + } + break; + } case 'c': case 'C': { if( sqliteStrNICmp(&z[i],"char",4)==0 || @@ -1092,6 +1100,39 @@ void sqliteDropTable(Parse *pParse, Token *pName, int isView){ sqliteViewResetAll(db); } +/* +** This routine constructs a P3 string suitable for an OP_MakeIdxKey +** opcode and adds that P3 string to the most recently inserted instruction +** in the virtual machine. The P3 string consists of a single character +** for each column in the index pIdx of table pTab. If the column uses +** a numeric sort order, then the P3 string character corresponding to +** that column is 'n'. If the column uses a text sort order, then the +** P3 string is 't'. See the OP_MakeIdxKey opcode documentation for +** additional information. See also the sqliteAddKeyType() routine. +*/ +void sqliteAddIdxKeyType(Vdbe *v, Index *pIdx){ + char *zType; + Table *pTab; + int i, n; + assert( pIdx!=0 && pIdx->pTable!=0 ); + pTab = pIdx->pTable; + n = pIdx->nColumn; + zType = sqliteMalloc( n+1 ); + if( zType==0 ) return; + for(i=0; iaiColumn[i]; + assert( iCol>=0 && iColnCol ); + if( (pTab->aCol[iCol].sortOrder & SQLITE_SO_TYPEMASK)==SQLITE_SO_TEXT ){ + zType[i] = 't'; + }else{ + zType[i] = 'n'; + } + } + zType[n] = 0; + sqliteVdbeChangeP3(v, -1, zType, n); + sqliteFree(zType); +} + /* ** Create a new index for an SQL table. pIndex is the name of the index ** and pTable is the name of the table that is to be indexed. Both will @@ -1355,6 +1396,7 @@ void sqliteCreateIndex( sqliteVdbeAddOp(v, OP_Column, 2, pIndex->aiColumn[i]); } sqliteVdbeAddOp(v, OP_MakeIdxKey, pIndex->nColumn, 0); + if( db->file_format>=3 ) sqliteAddIdxKeyType(v, pIndex); sqliteVdbeAddOp(v, OP_IdxPut, 1, pIndex->onError!=OE_None); sqliteVdbeAddOp(v, OP_Next, 2, lbl1); sqliteVdbeResolveLabel(v, lbl2); diff --git a/src/delete.c b/src/delete.c index 1dfc7f2443..8e91e25eed 100644 --- a/src/delete.c +++ b/src/delete.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle DELETE FROM statements. ** -** $Id: delete.c,v 1.38 2002/06/19 14:27:05 drh Exp $ +** $Id: delete.c,v 1.39 2002/07/05 21:42:37 drh Exp $ */ #include "sqliteInt.h" @@ -261,7 +261,7 @@ void sqliteDeleteFrom( } /* Delete the row */ - sqliteGenerateRowDelete(v, pTab, base, pParse->trigStack==0); + sqliteGenerateRowDelete(db, v, pTab, base, pParse->trigStack==0); /* If there are row triggers, close all cursors then invoke ** the AFTER triggers @@ -329,6 +329,7 @@ delete_from_cleanup: ** entries that point to that record. */ void sqliteGenerateRowDelete( + sqlite *db, /* The database containing the index */ Vdbe *v, /* Generate code into this VDBE */ Table *pTab, /* Table containing the row to be deleted */ int base, /* Cursor number for the table */ @@ -336,7 +337,7 @@ void sqliteGenerateRowDelete( ){ int addr; addr = sqliteVdbeAddOp(v, OP_NotExists, base, 0); - sqliteGenerateRowIndexDelete(v, pTab, base, 0); + sqliteGenerateRowIndexDelete(db, v, pTab, base, 0); sqliteVdbeAddOp(v, OP_Delete, base, count); sqliteVdbeChangeP2(v, addr, sqliteVdbeCurrentAddr(v)); } @@ -358,6 +359,7 @@ void sqliteGenerateRowDelete( ** deleted. */ void sqliteGenerateRowIndexDelete( + sqlite *db, /* The database containing the index */ Vdbe *v, /* Generate code into this VDBE */ Table *pTab, /* Table containing the row to be deleted */ int base, /* Cursor number for the table */ @@ -379,6 +381,7 @@ void sqliteGenerateRowIndexDelete( } } sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0); + if( db->file_format>=3 ) sqliteAddIdxKeyType(v, pIdx); sqliteVdbeAddOp(v, OP_IdxDelete, base+i, 0); } } diff --git a/src/insert.c b/src/insert.c index ee5b31f92d..a6b2e858ed 100644 --- a/src/insert.c +++ b/src/insert.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle INSERT statements in SQLite. ** -** $Id: insert.c,v 1.62 2002/06/19 20:32:44 drh Exp $ +** $Id: insert.c,v 1.63 2002/07/05 21:42:37 drh Exp $ */ #include "sqliteInt.h" @@ -616,6 +616,7 @@ void sqliteGenerateConstraintChecks( } } jumpInst1 = sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0); + if( pParse->db->file_format>=3 ) sqliteAddIdxKeyType(v, pIdx); onError = pIdx->onError; if( onError==OE_None ) continue; if( overrideError!=OE_Default ){ @@ -640,7 +641,7 @@ void sqliteGenerateConstraintChecks( break; } case OE_Replace: { - sqliteGenerateRowDelete(v, pTab, base, 0); + sqliteGenerateRowDelete(pParse->db, v, pTab, base, 0); if( isUpdate ){ sqliteVdbeAddOp(v, OP_Dup, nCol+extra+1+hasTwoRecnos, 1); sqliteVdbeAddOp(v, OP_MoveTo, base, 0); diff --git a/src/parse.y b/src/parse.y index 0eadf3570c..6a2e3dc86f 100644 --- a/src/parse.y +++ b/src/parse.y @@ -14,7 +14,7 @@ ** the parser. Lemon will also generate a header file containing ** numeric codes for all of the tokens. ** -** @(#) $Id: parse.y,v 1.76 2002/07/01 12:27:09 drh Exp $ +** @(#) $Id: parse.y,v 1.77 2002/07/05 21:42:37 drh Exp $ */ %token_prefix TK_ %token_type {Token} @@ -394,9 +394,9 @@ sortlist(A) ::= sortlist(X) COMMA sortitem(Y) collate(C) sortorder(Z). { A = sqliteExprListAppend(X,Y,0); if( A ) A->a[A->nExpr-1].sortOrder = C+Z; } -sortlist(A) ::= sortitem(Y) sortorder(Z). { +sortlist(A) ::= sortitem(Y) collate(C) sortorder(Z). { A = sqliteExprListAppend(0,Y,0); - if( A ) A->a[0].sortOrder = Z; + if( A ) A->a[0].sortOrder = C+Z; } sortitem(A) ::= expr(X). {A = X;} diff --git a/src/select.c b/src/select.c index 92fa302a52..882e8885c3 100644 --- a/src/select.c +++ b/src/select.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** -** $Id: select.c,v 1.102 2002/06/29 02:20:08 drh Exp $ +** $Id: select.c,v 1.103 2002/07/05 21:42:37 drh Exp $ */ #include "sqliteInt.h" @@ -315,7 +315,24 @@ static void pushOntoSorter(Parse *pParse, Vdbe *v, ExprList *pOrderBy){ zSortOrder = sqliteMalloc( pOrderBy->nExpr + 1 ); if( zSortOrder==0 ) return; for(i=0; inExpr; i++){ - zSortOrder[i] = pOrderBy->a[i].sortOrder ? '-' : '+'; + 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; + }else if( pParse->db->file_format>=3 ){ + type = sqliteExprType(pOrderBy->a[i].pExpr); + }else{ + type = SQLITE_SO_NUM; + } + if( (order & SQLITE_SO_DIRMASK)==SQLITE_SO_ASC ){ + c = type==SQLITE_SO_TEXT ? 'A' : '+'; + }else{ + c = type==SQLITE_SO_TEXT ? 'D' : '-'; + } + zSortOrder[i] = c; sqliteExprCode(pParse, pOrderBy->a[i].pExpr); } zSortOrder[pOrderBy->nExpr] = 0; @@ -325,13 +342,37 @@ static void pushOntoSorter(Parse *pParse, Vdbe *v, ExprList *pOrderBy){ sqliteVdbeAddOp(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 sqliteAddIdxKeyType() routine. +*/ +void sqliteAddKeyType(Vdbe *v, ExprList *pEList){ + int nColumn = pEList->nExpr; + char *zType = sqliteMalloc( nColumn+1 ); + int i; + if( zType==0 ) return; + for(i=0; ia[i].pExpr)==SQLITE_SO_NUM ? 'n' : 't'; + } + zType[i] = 0; + sqliteVdbeChangeP3(v, -1, zType, nColumn); + sqliteFree(zType); +} + /* ** This routine generates the code for the inside of the inner loop ** of a SELECT. ** -** The pEList is used to determine the values for each column in the -** result row. Except if pEList==NULL, then we just read nColumn -** elements from the srcTab table. +** If srcTab and nColumn are both zero, then the pEList expressions +** are evaluated in order to get the data for this row. If nColumn>0 +** then data is pulled from srcTab and pEList is used only to get the +** datatypes for each column. */ static int selectInnerLoop( Parse *pParse, /* The parser context */ @@ -348,7 +389,9 @@ static int selectInnerLoop( ){ Vdbe *v = pParse->pVdbe; int i; + if( v==0 ) return 0; + assert( pEList!=0 ); /* If there was a LIMIT clause on the SELECT statement, then do the check ** to see if this row should be output. @@ -366,15 +409,15 @@ static int selectInnerLoop( /* Pull the requested columns. */ - if( pEList ){ - for(i=0; inExpr; i++){ - sqliteExprCode(pParse, pEList->a[i].pExpr); - } - nColumn = pEList->nExpr; - }else{ + if( nColumn>0 ){ for(i=0; inExpr; + for(i=0; inExpr; i++){ + sqliteExprCode(pParse, pEList->a[i].pExpr); + } } /* If the DISTINCT keyword was present on the SELECT statement @@ -386,6 +429,7 @@ static int selectInnerLoop( sqliteVdbeAddOp(v, OP_IsNull, -pEList->nExpr, sqliteVdbeCurrentAddr(v)+7); #endif sqliteVdbeAddOp(v, OP_MakeKey, pEList->nExpr, 1); + if( pParse->db->file_format>=3 ) sqliteAddKeyType(v, pEList); sqliteVdbeAddOp(v, OP_Distinct, distinct, sqliteVdbeCurrentAddr(v)+3); sqliteVdbeAddOp(v, OP_Pop, pEList->nExpr+1, 0); sqliteVdbeAddOp(v, OP_Goto, 0, iContinue); @@ -1119,7 +1163,7 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){ iCont = sqliteVdbeMakeLabel(v); sqliteVdbeAddOp(v, OP_Rewind, unionTab, iBreak); iStart = sqliteVdbeCurrentAddr(v); - rc = selectInnerLoop(pParse, p, 0, unionTab, p->pEList->nExpr, + rc = selectInnerLoop(pParse, p, p->pEList, unionTab, p->pEList->nExpr, p->pOrderBy, -1, eDest, iParm, iCont, iBreak); if( rc ) return 1; @@ -1175,7 +1219,7 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){ sqliteVdbeAddOp(v, OP_Rewind, tab1, iBreak); iStart = sqliteVdbeAddOp(v, OP_FullKey, tab1, 0); sqliteVdbeAddOp(v, OP_NotFound, tab2, iCont); - rc = selectInnerLoop(pParse, p, 0, tab1, p->pEList->nExpr, + rc = selectInnerLoop(pParse, p, p->pEList, tab1, p->pEList->nExpr, p->pOrderBy, -1, eDest, iParm, iCont, iBreak); if( rc ) return 1; @@ -1547,7 +1591,7 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){ eList.a = &eListItem; eList.a[0].pExpr = pExpr; cont = sqliteVdbeMakeLabel(v); - selectInnerLoop(pParse, p, &eList, base, 1, 0, -1, eDest, iParm, cont, cont); + selectInnerLoop(pParse, p, &eList, 0, 0, 0, -1, eDest, iParm, cont, cont); sqliteVdbeResolveLabel(v, cont); sqliteVdbeAddOp(v, OP_Close, base, 0); return 1; @@ -1914,6 +1958,7 @@ int sqliteSelect( sqliteExprCode(pParse, pGroupBy->a[i].pExpr); } sqliteVdbeAddOp(v, OP_MakeKey, pGroupBy->nExpr, 0); + if( pParse->db->file_format>=3 ) sqliteAddKeyType(v, pGroupBy); lbl1 = sqliteVdbeMakeLabel(v); sqliteVdbeAddOp(v, OP_AggFocus, 0, lbl1); for(i=0; inAgg; i++){ diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 5f842e0c03..7b7e142321 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.133 2002/06/29 02:20:09 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.134 2002/07/05 21:42:37 drh Exp $ */ #include "sqlite.h" #include "hash.h" @@ -871,6 +871,8 @@ void sqliteIdListDelete(IdList*); void sqliteSrcListDelete(SrcList*); void sqliteCreateIndex(Parse*, Token*, Token*, IdList*, int, Token*, Token*); void sqliteDropIndex(Parse*, Token*); +void sqliteAddKeyType(Vdbe*, ExprList*); +void sqliteAddIdxKeyType(Vdbe*, Index*); int sqliteSelect(Parse*, Select*, int, int, Select*, int, int*); Select *sqliteSelectNew(ExprList*,SrcList*,Expr*,ExprList*,Expr*,ExprList*, int,int,int); @@ -909,8 +911,8 @@ char *sqlite_mprintf(const char *, ...); int sqliteExprIsConstant(Expr*); int sqliteExprIsInteger(Expr*, int*); int sqliteIsRowid(const char*); -void sqliteGenerateRowDelete(Vdbe*, Table*, int, int); -void sqliteGenerateRowIndexDelete(Vdbe*, Table*, int, char*); +void sqliteGenerateRowDelete(sqlite*, Vdbe*, Table*, int, int); +void sqliteGenerateRowIndexDelete(sqlite*, Vdbe*, Table*, int, char*); void sqliteGenerateConstraintChecks(Parse*,Table*,int,char*,int,int,int,int); void sqliteCompleteInsertion(Parse*, Table*, int, char*, int, int); void sqliteBeginWriteOperation(Parse*, int); diff --git a/src/update.c b/src/update.c index 0a6f6db203..656b8edfd9 100644 --- a/src/update.c +++ b/src/update.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle UPDATE statements. ** -** $Id: update.c,v 1.46 2002/06/29 02:20:09 drh Exp $ +** $Id: update.c,v 1.47 2002/07/05 21:42:37 drh Exp $ */ #include "sqliteInt.h" @@ -319,7 +319,7 @@ void sqliteUpdate( /* Delete the old indices for the current record. */ - sqliteGenerateRowIndexDelete(v, pTab, base, aIdxUsed); + sqliteGenerateRowIndexDelete(db, v, pTab, base, aIdxUsed); /* If changing the record number, delete the old record. */ diff --git a/src/util.c b/src/util.c index 007dd5aa1d..21736e9ea3 100644 --- a/src/util.c +++ b/src/util.c @@ -14,7 +14,7 @@ ** This file contains functions for allocating memory, comparing ** strings, and stuff like that. ** -** $Id: util.c,v 1.46 2002/06/14 20:58:45 drh Exp $ +** $Id: util.c,v 1.47 2002/07/05 21:42:37 drh Exp $ */ #include "sqliteInt.h" #include @@ -705,11 +705,15 @@ int sqliteCompare(const char *atext, const char *btext){ ** returns negative, zero, or positive if the first argument is less ** than, equal to, or greater than the first. (Result is a-b). ** -** Every string begins with either a "+" or "-" character. If the -** character is "-" then the return value is negated. This is done -** to implement a sort in descending order. +** Each string begins with one of the characters "+", "-", "A", "D". +** This character determines the sort order and collating sequence: ** -** For sorting purposes, pur numeric strings (strings for which the +** + Sort numerically in ascending order +** - Sort numerically in descending order +** A Sort as strings in ascending order +** D Sort as strings in descending order. +** +** For the "+" and "-" sorting, pure numeric strings (strings for which the ** isNum() function above returns TRUE) always compare less than strings ** that are not pure numerics. Within non-numeric strings, substrings ** of digits compare in numerical order. Finally, case is used only @@ -721,6 +725,10 @@ int sqliteCompare(const char *atext, const char *btext){ ** lexigraphical order. This routine does the additional processing ** to sort substrings of digits into numerical order and to use case ** only as a tie-breaker. +** +** The special rules above apply only to numeric sorting, when the +** prefix is "+" or "-". If the prefix is "A" or "D" then plain old +** "strcmp()" is used for the comparison. */ int sqliteSortCompare(const char *a, const char *b){ int len; @@ -728,6 +736,7 @@ int sqliteSortCompare(const char *a, const char *b){ int isNumA, isNumB; while( res==0 && *a && *b ){ + assert( a[0]==b[0] ); if( a[1]==0 ){ res = -1; break; @@ -735,41 +744,46 @@ int sqliteSortCompare(const char *a, const char *b){ res = +1; break; } - isNumA = sqliteIsNumber(&a[1]); - isNumB = sqliteIsNumber(&b[1]); - if( isNumA ){ - double rA, rB; - if( !isNumB ){ - res = -1; - break; - } - rA = atof(&a[1]); - rB = atof(&b[1]); - if( rArB ){ + if( a[0]=='A' || a[0]=='D' ){ + res = strcmp(&a[1],&b[1]); + if( res ) break; + }else{ + isNumA = sqliteIsNumber(&a[1]); + isNumB = sqliteIsNumber(&b[1]); + if( isNumA ){ + double rA, rB; + if( !isNumB ){ + res = -1; + break; + } + rA = atof(&a[1]); + rB = atof(&b[1]); + if( rArB ){ + res = +1; + break; + } + }else if( isNumB ){ res = +1; break; - } - }else if( isNumB ){ - res = +1; - break; - }else{ - res = sortStrCmp(&a[1],&b[1],0); - if( res==0 ){ - res = sortStrCmp(&a[1],&b[1],1); - } - if( res!=0 ){ - break; + }else{ + res = sortStrCmp(&a[1],&b[1],0); + if( res==0 ){ + res = sortStrCmp(&a[1],&b[1],1); + } + if( res!=0 ){ + break; + } } } len = strlen(&a[1]) + 2; a += len; b += len; } - if( *a=='-' ) res = -res; + if( *a=='-' || *a=='D' ) res = -res; return res; } diff --git a/src/vdbe.c b/src/vdbe.c index 83b36d90ce..3700a4baa6 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -30,7 +30,7 @@ ** But other routines are also provided to help in building up ** a program instruction by instruction. ** -** $Id: vdbe.c,v 1.163 2002/06/29 02:20:09 drh Exp $ +** $Id: vdbe.c,v 1.164 2002/07/05 21:42:37 drh Exp $ */ #include "sqliteInt.h" #include @@ -2632,7 +2632,7 @@ case OP_MakeRecord: { ** P3 is a string that is P1 characters long. Each character is either ** an 'n' or a 't' to indicates if the argument should be numeric or ** text. The first character corresponds to the lowest element on the -** stack. +** stack. If P3 is NULL then all arguments are assumed to be numeric. ** ** See also: MakeIdxKey, SortMakeKey */ @@ -2661,7 +2661,7 @@ case OP_MakeRecord: { ** P3 is a string that is P1 characters long. Each character is either ** an 'n' or a 't' to indicates if the argument should be numeric or ** text. The first character corresponds to the lowest element on the -** stack. +** stack. If P3 is null then all arguments are assumed to be numeric. ** ** See also: MakeKey, SortMakeKey */ diff --git a/test/table.test b/test/table.test index 6c8c00bb78..c4b432070f 100644 --- a/test/table.test +++ b/test/table.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this file is testing the CREATE TABLE statement. # -# $Id: table.test,v 1.17 2002/06/02 18:19:00 drh Exp $ +# $Id: table.test,v 1.18 2002/07/05 21:42:38 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -434,6 +434,31 @@ do_test table-10.8 { } } {0 {}} - +# Test for the "typeof" function. +# +do_test table-11.1 { + execsql { + CREATE TABLE t7( + a integer primary key, + b number(5,10), + c character varying (8), + d VARCHAR(9), + e clob, + f BLOB, + g Text, + h + ); + INSERT INTO t7(a) VALUES(1); + SELECT typeof(a), typeof(b), typeof(c), typeof(d), + typeof(e), typeof(f), typeof(g), typeof(h) + FROM t7 LIMIT 1; + } +} {numeric numeric text text text text text numeric} +do_test table-11.2 { + execsql { + SELECT typeof(a+b), typeof(a||b), typeof(c+d), typeof(c||d) + FROM t7 LIMIT 1; + } +} {numeric text numeric text} finish_test