diff options
author | drh <drh@noemail.net> | 2002-07-05 21:42:36 +0000 |
---|---|---|
committer | drh <drh@noemail.net> | 2002-07-05 21:42:36 +0000 |
commit | 38640e15af4c00270c20bdf980225e2a6f7423b5 (patch) | |
tree | 1b9058300f5925b8c907d679b9c9a23e4e6b5943 /src | |
parent | 2f2c01e51d09713efafb1e600e0136595acb77c4 (diff) | |
download | sqlite-38640e15af4c00270c20bdf980225e2a6f7423b5.tar.gz sqlite-38640e15af4c00270c20bdf980225e2a6f7423b5.zip |
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
Diffstat (limited to 'src')
-rw-r--r-- | src/build.c | 44 | ||||
-rw-r--r-- | src/delete.c | 9 | ||||
-rw-r--r-- | src/insert.c | 5 | ||||
-rw-r--r-- | src/parse.y | 6 | ||||
-rw-r--r-- | src/select.c | 73 | ||||
-rw-r--r-- | src/sqliteInt.h | 8 | ||||
-rw-r--r-- | src/update.c | 4 | ||||
-rw-r--r-- | src/util.c | 78 | ||||
-rw-r--r-- | src/vdbe.c | 6 |
9 files changed, 170 insertions, 63 deletions
diff --git a/src/build.c b/src/build.c index 47bdf12d9..9f1aa9cd2 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 <ctype.h> @@ -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 || @@ -1093,6 +1101,39 @@ void sqliteDropTable(Parse *pParse, Token *pName, int isView){ } /* +** 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; i<n; i++){ + int iCol = pIdx->aiColumn[i]; + assert( iCol>=0 && iCol<pTab->nCol ); + 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 ** be NULL for a primary key or an index that is created to satisfy a @@ -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 1dfc7f244..8e91e25ee 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 ee5b31f92..a6b2e858e 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 0eadf3570..6a2e3dc86 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 92fa302a5..882e8885c 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; i<pOrderBy->nExpr; 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; @@ -326,12 +343,36 @@ static void pushOntoSorter(Parse *pParse, Vdbe *v, ExprList *pOrderBy){ } /* +** 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; i<nColumn; i++){ + zType[i] = sqliteExprType(pEList->a[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; i<pEList->nExpr; i++){ - sqliteExprCode(pParse, pEList->a[i].pExpr); - } - nColumn = pEList->nExpr; - }else{ + if( nColumn>0 ){ for(i=0; i<nColumn; i++){ sqliteVdbeAddOp(v, OP_Column, srcTab, i); } + }else{ + nColumn = pEList->nExpr; + for(i=0; i<pEList->nExpr; 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; i<pParse->nAgg; i++){ diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 5f842e0c0..7b7e14232 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 0a6f6db20..656b8edfd 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 007dd5aa1..21736e9ea 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 <stdarg.h> @@ -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( rA<rB ){ - res = -1; - break; - } - if( rA>rB ){ - res = +1; - break; - } - }else if( isNumB ){ - res = +1; - break; + if( a[0]=='A' || a[0]=='D' ){ + res = strcmp(&a[1],&b[1]); + if( res ) break; }else{ - res = sortStrCmp(&a[1],&b[1],0); - if( res==0 ){ - res = sortStrCmp(&a[1],&b[1],1); - } - if( res!=0 ){ + 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( rA<rB ){ + res = -1; + break; + } + if( rA>rB ){ + 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; + } } } 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 83b36d90c..3700a4baa 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 <ctype.h> @@ -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 */ |