1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-08 14:02:16 +03:00

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
This commit is contained in:
drh
2002-07-05 21:42:36 +00:00
parent 2f2c01e51d
commit 38640e15af
12 changed files with 213 additions and 81 deletions

View File

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

View File

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

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.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);

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

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

View File

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

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

View File

@@ -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 ){
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( rA<rB ){
res = -1;
break;
}
if( rA>rB ){
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;
}

View File

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