This patch contains the beginnings of the data-typing infrastructure.

The new build-in TypeOf() function is added.  New opcodes for doing
pure text comparisons are added.  Most changes are disabled pending
the 2.6.0 release. (CVS 632)

FossilOrigin-Name: cbbc858d973c2d515c6a2464981316549a241b73
This commit is contained in:
drh 2002-06-20 11:36:48 +00:00
parent c926afbc2d
commit c9b84a1fb1
10 changed files with 497 additions and 85 deletions

View File

@ -1,5 +1,5 @@
C Fix\sfor\sticket\s#73:\sThe\sORDER\sBY\sclause\sis\ssignificant\sfor\ssubqueries.\nThis\spasses\sall\sregression\stests,\sbut\smore\stesting\sis\sneeded\sto\sexercise\nall\spaths\sthrough\sthe\snew\scode.\s(CVS\s631) C This\spatch\scontains\sthe\sbeginnings\sof\sthe\sdata-typing\sinfrastructure.\nThe\snew\sbuild-in\sTypeOf()\sfunction\sis\sadded.\s\sNew\sopcodes\sfor\sdoing\npure\stext\scomparisons\sare\sadded.\s\sMost\schanges\sare\sdisabled\spending\nthe\s2.6.0\srelease.\s(CVS\s632)
D 2002-06-20T03:38:26 D 2002-06-20T11:36:49
F Makefile.in 6291a33b87d2a395aafd7646ee1ed562c6f2c28c F Makefile.in 6291a33b87d2a395aafd7646ee1ed562c6f2c28c
F Makefile.template 4e11752e0b5c7a043ca50af4296ec562857ba495 F Makefile.template 4e11752e0b5c7a043ca50af4296ec562857ba495
F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0 F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0
@ -20,15 +20,15 @@ F sqlite.1 83f4a9d37bdf2b7ef079a82d54eaf2e3509ee6ea
F src/TODO af7f3cab0228e34149cf98e073aa83d45878e7e6 F src/TODO af7f3cab0228e34149cf98e073aa83d45878e7e6
F src/btree.c 8b86be8f234c1c5dab3186f69cee2544ec9d7257 F src/btree.c 8b86be8f234c1c5dab3186f69cee2544ec9d7257
F src/btree.h 8abeabfe6e0b1a990b64fa457592a6482f6674f3 F src/btree.h 8abeabfe6e0b1a990b64fa457592a6482f6674f3
F src/build.c f4633493f57660587c35c76dc7948f5da691a718 F src/build.c 95eac6ce4ae2871388d49066c78dd0657ce40a1f
F src/delete.c 44c45460b1e03033756e35adc6d569ffbf30b725 F src/delete.c 44c45460b1e03033756e35adc6d569ffbf30b725
F src/encode.c 346b12b46148506c32038524b95c4631ab46d760 F src/encode.c 346b12b46148506c32038524b95c4631ab46d760
F src/expr.c ec0689af4e355356df47dc1514ff17523d2f9c71 F src/expr.c cb50a72c491954d58be2f182366e45a1e252bf2e
F src/func.c b8d0fd3011f53ea0e46b6bab857612eb36b5d1ea F src/func.c 5eae8227a8b0d276a64d51a3880a6e86f238fedf
F src/hash.c 6a6236b89c8c060c65dabd300a1c8ce7c10edb72 F src/hash.c 6a6236b89c8c060c65dabd300a1c8ce7c10edb72
F src/hash.h cd0433998bc1a3759d244e1637fe5a3c13b53bf8 F src/hash.h cd0433998bc1a3759d244e1637fe5a3c13b53bf8
F src/insert.c 4bb40ed9dbaba4516fc2abbcff3f08d5687b073c F src/insert.c 4bb40ed9dbaba4516fc2abbcff3f08d5687b073c
F src/main.c 07f56387147f00e69eea7cea369071452bc4706f F src/main.c d026463c501a7eaf740494dfab0faae09980c224
F src/md5.c 0ae1f3e2cac92d06fc6246d1b4b8f61a2fe66d3b F src/md5.c 0ae1f3e2cac92d06fc6246d1b4b8f61a2fe66d3b
F src/os.c 9cc40c5384baba4a85e160e67807645ca98ba3cc F src/os.c 9cc40c5384baba4a85e160e67807645ca98ba3cc
F src/os.h 4a361fccfbc4e7609b3e1557f604f94c1e96ad10 F src/os.h 4a361fccfbc4e7609b3e1557f604f94c1e96ad10
@ -40,8 +40,8 @@ F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe
F src/select.c 3eadcde4c74341d8ee7db69948cbcb16df9ae9fc F src/select.c 3eadcde4c74341d8ee7db69948cbcb16df9ae9fc
F src/shell.c 1d22fe870ee852cfb975fd000dbe3973713d0a15 F src/shell.c 1d22fe870ee852cfb975fd000dbe3973713d0a15
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
F src/sqlite.h.in 0038faa6d642de06b91143ee65a131bd831d020b F src/sqlite.h.in 7c8882e352cb70818cfaf9bdb5b1b3bee81ef144
F src/sqliteInt.h 1e9904f9baa536333d9d1168e075abf96426baad F src/sqliteInt.h 16ccbf72dd823d5764b475353927410ec272305e
F src/table.c eed2098c9b577aa17f8abe89313a9c4413f57d63 F src/table.c eed2098c9b577aa17f8abe89313a9c4413f57d63
F src/tclsqlite.c 9300c9606a38bc0c75d6c0bc8a6197ab979353d1 F src/tclsqlite.c 9300c9606a38bc0c75d6c0bc8a6197ab979353d1
F src/test1.c 5cc4f0bbf38237e04e1b2077e285b41bfb4c4cbf F src/test1.c 5cc4f0bbf38237e04e1b2077e285b41bfb4c4cbf
@ -52,8 +52,8 @@ F src/tokenize.c ac4c46f190346b87da54ec3e2605d160af80c619
F src/trigger.c 21342af6ac031fece39c8fc6eabd1739ca5327c1 F src/trigger.c 21342af6ac031fece39c8fc6eabd1739ca5327c1
F src/update.c 6f6a4dcd71cd9ff730b7f12c83de5498cde4924f F src/update.c 6f6a4dcd71cd9ff730b7f12c83de5498cde4924f
F src/util.c 876b259f9186e84b944b72e793dd3dad50e63e95 F src/util.c 876b259f9186e84b944b72e793dd3dad50e63e95
F src/vdbe.c 7d9bb3701ea00576c5d5fb3f3de63af7b7304241 F src/vdbe.c c33572f803b853c50c22f84d6dfa6922ec79bf6b
F src/vdbe.h fba15f3280688f6f32f11d1042078e3c557bac43 F src/vdbe.h 9b6e632bfa5d52507130f1ae456ef2c01bc0be7e
F src/where.c 1fdb7aca26c1963eb42615a95e0fc2978eec566a F src/where.c 1fdb7aca26c1963eb42615a95e0fc2978eec566a
F test/all.test e4d3821eeba751829b419cd47814bd20af4286d1 F test/all.test e4d3821eeba751829b419cd47814bd20af4286d1
F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578 F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578
@ -137,7 +137,7 @@ F www/speed.tcl da8afcc1d3ccc5696cfb388a68982bc3d9f7f00f
F www/sqlite.tcl 8b5884354cb615049aed83039f8dfe1552a44279 F www/sqlite.tcl 8b5884354cb615049aed83039f8dfe1552a44279
F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331 F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331
F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218 F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
P d599f75b659809a6e5eee09b0e9e6e90bde5af1e P 43c5aff5d078bce9292683cd40311e0dcc81ac14
R 086d9eb833675513d9039b13c48320be R 581584e0b7a6ff65ed6ebc56fea3ccf6
U drh U drh
Z 8d182409003e8da6cfa46f473fde17e7 Z 063bdfea24283b4aeee93e932e657f35

View File

@ -1 +1 @@
43c5aff5d078bce9292683cd40311e0dcc81ac14 cbbc858d973c2d515c6a2464981316549a241b73

View File

@ -25,7 +25,7 @@
** ROLLBACK ** ROLLBACK
** PRAGMA ** PRAGMA
** **
** $Id: build.c,v 1.96 2002/06/17 17:07:20 drh Exp $ ** $Id: build.c,v 1.97 2002/06/20 11:36:49 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include <ctype.h> #include <ctype.h>
@ -504,6 +504,7 @@ void sqliteAddColumn(Parse *pParse, Token *pName){
Table *p; Table *p;
int i; int i;
char *z = 0; char *z = 0;
Column *pCol;
if( (p = pParse->pNewTable)==0 ) return; if( (p = pParse->pNewTable)==0 ) return;
sqliteSetNString(&z, pName->z, pName->n, 0); sqliteSetNString(&z, pName->z, pName->n, 0);
if( z==0 ) return; if( z==0 ) return;
@ -522,8 +523,11 @@ void sqliteAddColumn(Parse *pParse, Token *pName){
if( aNew==0 ) return; if( aNew==0 ) return;
p->aCol = aNew; p->aCol = aNew;
} }
memset(&p->aCol[p->nCol], 0, sizeof(p->aCol[0])); pCol = &p->aCol[p->nCol];
p->aCol[p->nCol++].zName = z; memset(pCol, 0, sizeof(p->aCol[0]));
pCol->zName = z;
pCol->sortOrder = SQLITE_SO_NUM;
p->nCol++;
} }
/* /*
@ -554,10 +558,12 @@ void sqliteAddColumnType(Parse *pParse, Token *pFirst, Token *pLast){
int i, j; int i, j;
int n; int n;
char *z, **pz; char *z, **pz;
Column *pCol;
if( (p = pParse->pNewTable)==0 ) return; if( (p = pParse->pNewTable)==0 ) return;
i = p->nCol-1; i = p->nCol-1;
if( i<0 ) return; if( i<0 ) return;
pz = &p->aCol[i].zType; pCol = &p->aCol[i];
pz = &pCol->zType;
n = pLast->n + Addr(pLast->z) - Addr(pFirst->z); n = pLast->n + Addr(pLast->z) - Addr(pFirst->z);
sqliteSetNString(pz, pFirst->z, n, 0); sqliteSetNString(pz, pFirst->z, n, 0);
z = *pz; z = *pz;
@ -568,6 +574,31 @@ void sqliteAddColumnType(Parse *pParse, Token *pFirst, Token *pLast){
z[j++] = c; z[j++] = c;
} }
z[j] = 0; z[j] = 0;
pCol->sortOrder = SQLITE_SO_NUM;
for(i=0; z[i]; i++){
switch( z[i] ){
case 'c':
case 'C': {
if( sqliteStrNICmp(&z[i],"char",4)==0 ||
sqliteStrNICmp(&z[i],"clob",4)==0 ){
pCol->sortOrder = SQLITE_SO_TEXT;
return;
}
break;
}
case 'x':
case 'X': {
if( i>=2 && sqliteStrNICmp(&z[i-2],"text",4)==0 ){
pCol->sortOrder = SQLITE_SO_TEXT;
return;
}
break;
}
default: {
break;
}
}
}
} }
/* /*

View File

@ -12,7 +12,7 @@
** This file contains routines used for analyzing expressions and ** This file contains routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions in SQLite. ** for generating VDBE code that evaluates expressions in SQLite.
** **
** $Id: expr.c,v 1.72 2002/06/17 17:07:20 drh Exp $ ** $Id: expr.c,v 1.73 2002/06/20 11:36:49 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include <ctype.h> #include <ctype.h>
@ -460,8 +460,10 @@ int sqliteExprResolveIds(
if( j==pTab->iPKey ){ if( j==pTab->iPKey ){
/* Substitute the record number for the INTEGER PRIMARY KEY */ /* Substitute the record number for the INTEGER PRIMARY KEY */
pExpr->iColumn = -1; pExpr->iColumn = -1;
pExpr->dataType = SQLITE_SO_NUM;
}else{ }else{
pExpr->iColumn = j; pExpr->iColumn = j;
pExpr->dataType = pTab->aCol[j].sortOrder & SQLITE_SO_TYPEMASK;
} }
pExpr->op = TK_COLUMN; pExpr->op = TK_COLUMN;
} }
@ -485,6 +487,7 @@ int sqliteExprResolveIds(
pExpr->iTable = base; pExpr->iTable = base;
cnt = 1 + (pTabList->nSrc>1); cnt = 1 + (pTabList->nSrc>1);
pExpr->op = TK_COLUMN; pExpr->op = TK_COLUMN;
pExpr->dataType = SQLITE_SO_NUM;
} }
sqliteFree(z); sqliteFree(z);
if( cnt==0 && pExpr->token.z[0]!='"' ){ if( cnt==0 && pExpr->token.z[0]!='"' ){
@ -546,6 +549,7 @@ int sqliteExprResolveIds(
}else{ }else{
pExpr->iColumn = j; pExpr->iColumn = j;
} }
pExpr->dataType = pTab->aCol[j].sortOrder & SQLITE_SO_TYPEMASK;
} }
} }
} }
@ -568,10 +572,12 @@ int sqliteExprResolveIds(
if( t ){ if( t ){
int j; int j;
for(j=0; j < pTriggerStack->pTab->nCol; j++) { Table *pTab = pTriggerStack->pTab;
if( sqliteStrICmp(pTriggerStack->pTab->aCol[j].zName, zRight)==0 ){ for(j=0; j < pTab->nCol; j++) {
if( sqliteStrICmp(pTab->aCol[j].zName, zRight)==0 ){
cnt++; cnt++;
pExpr->iColumn = j; pExpr->iColumn = j;
pExpr->dataType = pTab->aCol[j].sortOrder & SQLITE_SO_TYPEMASK;
} }
} }
} }
@ -580,6 +586,7 @@ int sqliteExprResolveIds(
if( cnt==0 && cntTab==1 && sqliteIsRowid(zRight) ){ if( cnt==0 && cntTab==1 && sqliteIsRowid(zRight) ){
cnt = 1; cnt = 1;
pExpr->iColumn = -1; pExpr->iColumn = -1;
pExpr->dataType = SQLITE_SO_NUM;
} }
sqliteFree(zLeft); sqliteFree(zLeft);
sqliteFree(zRight); sqliteFree(zRight);
@ -714,10 +721,11 @@ int sqliteExprCheck(Parse *pParse, Expr *pExpr, int allowAgg, int *pIsAgg){
if( pExpr==0 ) return 0; if( pExpr==0 ) return 0;
switch( pExpr->op ){ switch( pExpr->op ){
case TK_FUNCTION: { case TK_FUNCTION: {
int n = pExpr->pList ? pExpr->pList->nExpr : 0; int n = pExpr->pList ? pExpr->pList->nExpr : 0; /* Number of arguments */
int no_such_func = 0; int no_such_func = 0; /* True if no such function exists */
int wrong_num_args = 0; int is_type_of = 0; /* True if is the special TypeOf() function */
int is_agg = 0; int wrong_num_args = 0; /* True if wrong number of arguments */
int is_agg = 0; /* True if is an aggregate function */
int i; int i;
FuncDef *pDef; FuncDef *pDef;
@ -727,7 +735,12 @@ int sqliteExprCheck(Parse *pParse, Expr *pExpr, int allowAgg, int *pIsAgg){
pDef = sqliteFindFunction(pParse->db, pDef = sqliteFindFunction(pParse->db,
pExpr->token.z, pExpr->token.n, -1, 0); pExpr->token.z, pExpr->token.n, -1, 0);
if( pDef==0 ){ if( pDef==0 ){
no_such_func = 1; if( n==1 && pExpr->token.n==6
&& sqliteStrNICmp(pExpr->token.z, "typeof", 6)==0 ){
is_type_of = 1;
}else {
no_such_func = 1;
}
}else{ }else{
wrong_num_args = 1; wrong_num_args = 1;
} }
@ -758,6 +771,37 @@ int sqliteExprCheck(Parse *pParse, Expr *pExpr, int allowAgg, int *pIsAgg){
nErr = sqliteExprCheck(pParse, pExpr->pList->a[i].pExpr, nErr = sqliteExprCheck(pParse, pExpr->pList->a[i].pExpr,
allowAgg && !is_agg, pIsAgg); allowAgg && !is_agg, pIsAgg);
} }
if( pDef==0 ){
if( is_type_of ){
pExpr->op = TK_STRING;
if( sqliteExprType(pExpr->pList->a[0].pExpr)==SQLITE_SO_NUM ){
pExpr->token.z = "numeric";
pExpr->token.n = 7;
}else{
pExpr->token.z = "text";
pExpr->token.n = 4;
}
}
}else if( pDef->dataType>=0 ){
if( pDef->dataType<n ){
pExpr->dataType =
sqliteExprType(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( sqliteExprType(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;
}
} }
default: { default: {
if( pExpr->pLeft ){ if( pExpr->pLeft ){
@ -780,6 +824,78 @@ int sqliteExprCheck(Parse *pParse, Expr *pExpr, int allowAgg, int *pIsAgg){
return nErr; return nErr;
} }
/*
** Return either SQLITE_SO_NUM or SQLITE_SO_TEXT to indicate whether the
** given expression should sort as numeric values or as text.
**
** The sqliteExprResolveIds() and sqliteExprCheck() routines must have
** both been called on the expression before it is passed to this routine.
*/
int sqliteExprType(Expr *p){
if( p==0 ) return SQLITE_SO_NUM;
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_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:
return SQLITE_SO_NUM;
case TK_STRING:
case TK_NULL:
case TK_CONCAT:
return SQLITE_SO_TEXT;
case TK_LT:
case TK_LE:
case TK_GT:
case TK_GE:
case TK_NE:
case TK_EQ:
if( sqliteExprType(p->pLeft)==SQLITE_SO_NUM ){
return SQLITE_SO_NUM;
}
p = p->pRight;
break;
case TK_AS:
p = p->pLeft;
break;
case TK_COLUMN:
case TK_FUNCTION:
case TK_AGG_FUNCTION:
return p->dataType;
case TK_SELECT:
assert( p->pSelect );
assert( p->pSelect->pEList );
assert( p->pSelect->pEList->nExpr>0 );
p = p->pSelect->pEList->a[0].pExpr;
break;
default:
assert( p->op==TK_ABORT ); /* Can't Happen */
break;
}
return SQLITE_SO_NUM;
}
/* /*
** Generate code into the current Vdbe to evaluate the given ** Generate code into the current Vdbe to evaluate the given
** expression and leave the result on the top of stack. ** expression and leave the result on the top of stack.
@ -856,6 +972,17 @@ void sqliteExprCode(Parse *pParse, Expr *pExpr){
sqliteVdbeAddOp(v, OP_String, 0, 0); sqliteVdbeAddOp(v, OP_String, 0, 0);
break; break;
} }
case TK_LT:
case TK_LE:
case TK_GT:
case TK_GE:
case TK_NE:
case TK_EQ: {
if( pParse->db->file_format>=3 && sqliteExprType(pExpr)==SQLITE_SO_TEXT ){
op += 6; /* Convert numeric opcodes to text opcodes */
}
/* Fall through into the next case */
}
case TK_AND: case TK_AND:
case TK_OR: case TK_OR:
case TK_PLUS: case TK_PLUS:
@ -864,13 +991,7 @@ void sqliteExprCode(Parse *pParse, Expr *pExpr){
case TK_REM: case TK_REM:
case TK_BITAND: case TK_BITAND:
case TK_BITOR: case TK_BITOR:
case TK_SLASH: case TK_SLASH: {
case TK_LT:
case TK_LE:
case TK_GT:
case TK_GE:
case TK_NE:
case TK_EQ: {
sqliteExprCode(pParse, pExpr->pLeft); sqliteExprCode(pParse, pExpr->pLeft);
sqliteExprCode(pParse, pExpr->pRight); sqliteExprCode(pParse, pExpr->pRight);
sqliteVdbeAddOp(v, op, 0, 0); sqliteVdbeAddOp(v, op, 0, 0);
@ -1090,6 +1211,9 @@ void sqliteExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
case TK_EQ: { case TK_EQ: {
sqliteExprCode(pParse, pExpr->pLeft); sqliteExprCode(pParse, pExpr->pLeft);
sqliteExprCode(pParse, pExpr->pRight); sqliteExprCode(pParse, pExpr->pRight);
if( pParse->db->file_format>=3 && sqliteExprType(pExpr)==SQLITE_SO_TEXT ){
op += 6; /* Convert numeric opcodes to text opcodes */
}
sqliteVdbeAddOp(v, op, jumpIfNull, dest); sqliteVdbeAddOp(v, op, jumpIfNull, dest);
break; break;
} }
@ -1180,6 +1304,9 @@ void sqliteExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
case TK_GE: case TK_GE:
case TK_NE: case TK_NE:
case TK_EQ: { case TK_EQ: {
if( pParse->db->file_format>=3 && sqliteExprType(pExpr)==SQLITE_SO_TEXT ){
op += 6; /* Convert numeric opcodes to text opcodes */
}
sqliteExprCode(pParse, pExpr->pLeft); sqliteExprCode(pParse, pExpr->pLeft);
sqliteExprCode(pParse, pExpr->pRight); sqliteExprCode(pParse, pExpr->pRight);
sqliteVdbeAddOp(v, op, jumpIfNull, dest); sqliteVdbeAddOp(v, op, jumpIfNull, dest);
@ -1395,6 +1522,7 @@ FuncDef *sqliteFindFunction(
if( p==0 && createFlag && (p = sqliteMalloc(sizeof(*p)))!=0 ){ if( p==0 && createFlag && (p = sqliteMalloc(sizeof(*p)))!=0 ){
p->nArg = nArg; p->nArg = nArg;
p->pNext = pFirst; p->pNext = pFirst;
p->dataType = pFirst ? pFirst->dataType : SQLITE_NUMERIC;
sqliteHashInsert(&db->aFunc, zName, nName, (void*)p); sqliteHashInsert(&db->aFunc, zName, nName, (void*)p);
} }
return p; return p;

View File

@ -16,7 +16,7 @@
** sqliteRegisterBuildinFunctions() found at the bottom of the file. ** sqliteRegisterBuildinFunctions() found at the bottom of the file.
** All other code has file scope. ** All other code has file scope.
** **
** $Id: func.c,v 1.20 2002/06/09 10:14:19 drh Exp $ ** $Id: func.c,v 1.21 2002/06/20 11:36:49 drh Exp $
*/ */
#include <ctype.h> #include <ctype.h>
#include <math.h> #include <math.h>
@ -416,42 +416,44 @@ void sqliteRegisterBuiltinFunctions(sqlite *db){
static struct { static struct {
char *zName; char *zName;
int nArg; int nArg;
int dataType;
void (*xFunc)(sqlite_func*,int,const char**); void (*xFunc)(sqlite_func*,int,const char**);
} aFuncs[] = { } aFuncs[] = {
{ "min", -1, minFunc }, { "min", -1, SQLITE_ARGS, minFunc },
{ "min", 0, 0 }, { "min", 0, 0, 0 },
{ "max", -1, maxFunc }, { "max", -1, SQLITE_ARGS, maxFunc },
{ "max", 0, 0 }, { "max", 0, 0, 0 },
{ "length", 1, lengthFunc }, { "length", 1, SQLITE_NUMERIC, lengthFunc },
{ "substr", 3, substrFunc }, { "substr", 3, SQLITE_TEXT, substrFunc },
{ "abs", 1, absFunc }, { "abs", 1, SQLITE_NUMERIC, absFunc },
{ "round", 1, roundFunc }, { "round", 1, SQLITE_NUMERIC, roundFunc },
{ "round", 2, roundFunc }, { "round", 2, SQLITE_NUMERIC, roundFunc },
{ "upper", 1, upperFunc }, { "upper", 1, SQLITE_TEXT, upperFunc },
{ "lower", 1, lowerFunc }, { "lower", 1, SQLITE_TEXT, lowerFunc },
{ "coalesce", -1, ifnullFunc }, { "coalesce", -1, SQLITE_ARGS, ifnullFunc },
{ "coalesce", 0, 0 }, { "coalesce", 0, 0, 0 },
{ "coalesce", 1, 0 }, { "coalesce", 1, 0, 0 },
{ "ifnull", 2, ifnullFunc }, { "ifnull", 2, SQLITE_ARGS, ifnullFunc },
{ "random", -1, randomFunc }, { "random", -1, SQLITE_NUMERIC, randomFunc },
{ "like", 2, likeFunc }, { "like", 2, SQLITE_NUMERIC, likeFunc },
{ "glob", 2, globFunc }, { "glob", 2, SQLITE_NUMERIC, globFunc },
{ "nullif", 2, nullifFunc }, { "nullif", 2, SQLITE_ARGS, nullifFunc },
}; };
static struct { static struct {
char *zName; char *zName;
int nArg; int nArg;
int dataType;
void (*xStep)(sqlite_func*,int,const char**); void (*xStep)(sqlite_func*,int,const char**);
void (*xFinalize)(sqlite_func*); void (*xFinalize)(sqlite_func*);
} aAggs[] = { } aAggs[] = {
{ "min", 1, minStep, minMaxFinalize }, { "min", 1, 0, minStep, minMaxFinalize },
{ "max", 1, maxStep, minMaxFinalize }, { "max", 1, 0, maxStep, minMaxFinalize },
{ "sum", 1, sumStep, sumFinalize }, { "sum", 1, SQLITE_NUMERIC, sumStep, sumFinalize },
{ "avg", 1, sumStep, avgFinalize }, { "avg", 1, SQLITE_NUMERIC, sumStep, avgFinalize },
{ "count", 0, countStep, countFinalize }, { "count", 0, SQLITE_NUMERIC, countStep, countFinalize },
{ "count", 1, countStep, countFinalize }, { "count", 1, SQLITE_NUMERIC, countStep, countFinalize },
#if 0 #if 0
{ "stddev", 1, stdDevStep, stdDevFinalize }, { "stddev", 1, SQLITE_NUMERIC, stdDevStep, stdDevFinalize },
#endif #endif
}; };
int i; int i;
@ -459,11 +461,16 @@ void sqliteRegisterBuiltinFunctions(sqlite *db){
for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){ for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){
sqlite_create_function(db, aFuncs[i].zName, sqlite_create_function(db, aFuncs[i].zName,
aFuncs[i].nArg, aFuncs[i].xFunc, 0); aFuncs[i].nArg, aFuncs[i].xFunc, 0);
if( aFuncs[i].xFunc ){
sqlite_function_type(db, aFuncs[i].zName, aFuncs[i].dataType);
}
} }
sqlite_create_function(db, "last_insert_rowid", 0, sqlite_create_function(db, "last_insert_rowid", 0,
last_insert_rowid, db); last_insert_rowid, db);
sqlite_function_type(db, "last_insert_rowid", SQLITE_NUMERIC);
for(i=0; i<sizeof(aAggs)/sizeof(aAggs[0]); i++){ for(i=0; i<sizeof(aAggs)/sizeof(aAggs[0]); i++){
sqlite_create_aggregate(db, aAggs[i].zName, sqlite_create_aggregate(db, aAggs[i].zName,
aAggs[i].nArg, aAggs[i].xStep, aAggs[i].xFinalize, 0); aAggs[i].nArg, aAggs[i].xStep, aAggs[i].xFinalize, 0);
sqlite_function_type(db, aAggs[i].zName, aAggs[i].dataType);
} }
} }

View File

@ -14,7 +14,7 @@
** other files are for internal use by SQLite and should not be ** other files are for internal use by SQLite and should not be
** accessed by users of the library. ** accessed by users of the library.
** **
** $Id: main.c,v 1.80 2002/06/16 18:21:44 drh Exp $ ** $Id: main.c,v 1.81 2002/06/20 11:36:49 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include "os.h" #include "os.h"
@ -51,6 +51,11 @@ int sqliteInitCallback(void *pDb, int argc, char **argv, char **azColName){
break; break;
} }
case 'f': { /* File format */ case 'f': { /* File format */
/*
** file_format==1 Version 2.1.0.
** file_format==2 Version 2.2.0. Integer primary key.
** file_format==3 Version 2.6.0. Separate text and numeric datatypes.
*/
db->file_format = atoi(argv[3]); db->file_format = atoi(argv[3]);
break; break;
} }
@ -827,3 +832,14 @@ int sqlite_create_aggregate(
p->pUserData = pUserData; p->pUserData = pUserData;
return 0; return 0;
} }
/*
** Change the datatype for all functions with a given name.
*/
int sqlite_function_type(sqlite *db, const char *zName, int dataType){
FuncDef *p = (FuncDef*)sqliteHashFind(&db->aFunc, zName, strlen(zName));
while( p ){
p->dataType = dataType;
p = p->pNext;
}
}

View File

@ -12,7 +12,7 @@
** This header file defines the interface that the SQLite library ** This header file defines the interface that the SQLite library
** presents to client programs. ** presents to client programs.
** **
** @(#) $Id: sqlite.h.in,v 1.31 2002/05/10 05:44:56 drh Exp $ ** @(#) $Id: sqlite.h.in,v 1.32 2002/06/20 11:36:50 drh Exp $
*/ */
#ifndef _SQLITE_H_ #ifndef _SQLITE_H_
#define _SQLITE_H_ #define _SQLITE_H_
@ -426,6 +426,27 @@ int sqlite_create_aggregate(
void *pUserData /* Available via the sqlite_user_data() call */ void *pUserData /* Available via the sqlite_user_data() call */
); );
/*
** Use the following routine to define the datatype returned by a
** user-defined function. The second argument can be one of the
** constants SQLITE_NUMERIC, SQLITE_TEXT, or SQLITE_ARGS or it
** can be an integer greater than or equal to zero. The datatype
** will be numeric or text (the only two types supported) if the
** argument is SQLITE_NUMERIC or SQLITE_TEXT. If the argument is
** SQLITE_ARGS, then the datatype is numeric if any argument to the
** function is numeric and is text otherwise. If the second argument
** is an integer, then the datatype of the result is the same as the
** parameter to the function that corresponds to that integer.
*/
int sqlite_function_type(
sqlite *db, /* The database there the function is registered */
const char *zName, /* Name of the function */
int datatype /* The datatype for this function */
);
#define SQLITE_NUMERIC (-1)
#define SQLITE_TEXT (-2)
#define SQLITE_ARGS (-3)
/* /*
** The user function implementations call one of the following four routines ** The user function implementations call one of the following four routines
** in order to return their results. The first parameter to each of these ** in order to return their results. The first parameter to each of these

View File

@ -11,7 +11,7 @@
************************************************************************* *************************************************************************
** Internal interface definitions for SQLite. ** Internal interface definitions for SQLite.
** **
** @(#) $Id: sqliteInt.h,v 1.126 2002/06/19 14:27:05 drh Exp $ ** @(#) $Id: sqliteInt.h,v 1.127 2002/06/20 11:36:50 drh Exp $
*/ */
#include "sqlite.h" #include "sqlite.h"
#include "hash.h" #include "hash.h"
@ -176,7 +176,18 @@ typedef struct TriggerStep TriggerStep;
typedef struct TriggerStack TriggerStack; typedef struct TriggerStack TriggerStack;
/* /*
** Each database is an instance of the following structure ** Each database is an instance of the following structure.
**
** The sqlite.file_format is initialized by the database file
** and helps determines how the data in the database file is
** represented. This field allows newer versions of the library
** to read and write older databases. The various file formats
** are as follows:
**
** file_format==1 Version 2.1.0.
** file_format==2 Version 2.2.0. Add support for INTEGER PRIMARY KEY.
** file_format==3 Version 2.6.0. Add support for separate numeric and
** text datatypes.
*/ */
struct sqlite { struct sqlite {
Btree *pBe; /* The B*Tree backend */ Btree *pBe; /* The B*Tree backend */
@ -244,6 +255,7 @@ struct FuncDef {
void (*xStep)(sqlite_func*,int,const char**); /* Aggregate function step */ void (*xStep)(sqlite_func*,int,const char**); /* Aggregate function step */
void (*xFinalize)(sqlite_func*); /* Aggregate function finializer */ void (*xFinalize)(sqlite_func*); /* Aggregate function finializer */
int nArg; /* Number of arguments */ int nArg; /* Number of arguments */
int dataType; /* Datatype of the result */
void *pUserData; /* User data parameter */ void *pUserData; /* User data parameter */
FuncDef *pNext; /* Next function with same name */ FuncDef *pNext; /* Next function with same name */
}; };
@ -876,6 +888,7 @@ int sqliteGlobCompare(const unsigned char*,const unsigned char*);
int sqliteLikeCompare(const unsigned char*,const unsigned char*); int sqliteLikeCompare(const unsigned char*,const unsigned char*);
char *sqliteTableNameFromToken(Token*); char *sqliteTableNameFromToken(Token*);
int sqliteExprCheck(Parse*, Expr*, int, int*); int sqliteExprCheck(Parse*, Expr*, int, int*);
int sqliteExprType(Expr*);
int sqliteExprCompare(Expr*, Expr*); int sqliteExprCompare(Expr*, Expr*);
int sqliteFuncId(Token*); int sqliteFuncId(Token*);
int sqliteExprResolveIds(Parse*, int, SrcList*, ExprList*, Expr*); int sqliteExprResolveIds(Parse*, int, SrcList*, ExprList*, Expr*);

View File

@ -30,7 +30,7 @@
** But other routines are also provided to help in building up ** But other routines are also provided to help in building up
** a program instruction by instruction. ** a program instruction by instruction.
** **
** $Id: vdbe.c,v 1.156 2002/06/14 22:38:43 drh Exp $ ** $Id: vdbe.c,v 1.157 2002/06/20 11:36:50 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include <ctype.h> #include <ctype.h>
@ -1077,10 +1077,11 @@ static char *zOpName[] = { 0,
"Divide", "Remainder", "BitAnd", "BitOr", "Divide", "Remainder", "BitAnd", "BitOr",
"BitNot", "ShiftLeft", "ShiftRight", "AbsValue", "BitNot", "ShiftLeft", "ShiftRight", "AbsValue",
"Eq", "Ne", "Lt", "Le", "Eq", "Ne", "Lt", "Le",
"Gt", "Ge", "IsNull", "NotNull", "Gt", "Ge", "StrEq", "StrNe",
"Negative", "And", "Or", "Not", "StrLt", "StrLe", "StrGt", "StrGe",
"Concat", "Noop", "Function", "Limit", "IsNull", "NotNull", "Negative", "And",
"LimitCk", "Or", "Not", "Concat", "Noop",
"Function", "Limit", "LimitCk",
}; };
/* /*
@ -1992,6 +1993,11 @@ mismatch:
** If either operand is NULL (and thus if the result is unknown) then ** If either operand is NULL (and thus if the result is unknown) then
** take the jump if P1 is true. ** take the jump if P1 is true.
** **
** If both values are numeric, they are converted to doubles using atof()
** and compared for equality that way. Otherwise the strcmp() library
** routine is used for the comparison. For a pure text comparison
** use OP_StrEq.
**
** If P2 is zero, do not jump. Instead, push an integer 1 onto the ** If P2 is zero, do not jump. Instead, push an integer 1 onto the
** stack if the jump would have been taken, or a 0 if not. Push a ** stack if the jump would have been taken, or a 0 if not. Push a
** NULL if either operand was NULL. ** NULL if either operand was NULL.
@ -2004,6 +2010,11 @@ mismatch:
** If either operand is NULL (and thus if the result is unknown) then ** If either operand is NULL (and thus if the result is unknown) then
** take the jump if P1 is true. ** take the jump if P1 is true.
** **
** If both values are numeric, they are converted to doubles using atof()
** and compared in that format. Otherwise the strcmp() library
** routine is used for the comparison. For a pure text comparison
** use OP_StrNe.
**
** If P2 is zero, do not jump. Instead, push an integer 1 onto the ** If P2 is zero, do not jump. Instead, push an integer 1 onto the
** stack if the jump would have been taken, or a 0 if not. Push a ** stack if the jump would have been taken, or a 0 if not. Push a
** NULL if either operand was NULL. ** NULL if either operand was NULL.
@ -2018,6 +2029,12 @@ mismatch:
** If either operand is NULL (and thus if the result is unknown) then ** If either operand is NULL (and thus if the result is unknown) then
** take the jump if P1 is true. ** take the jump if P1 is true.
** **
** If both values are numeric, they are converted to doubles using atof()
** and compared in that format. Numeric values are always less than
** non-numeric values. If both operands are non-numeric, the strcmp() library
** routine is used for the comparison. For a pure text comparison
** use OP_StrLt.
**
** If P2 is zero, do not jump. Instead, push an integer 1 onto the ** If P2 is zero, do not jump. Instead, push an integer 1 onto the
** stack if the jump would have been taken, or a 0 if not. Push a ** stack if the jump would have been taken, or a 0 if not. Push a
** NULL if either operand was NULL. ** NULL if either operand was NULL.
@ -2031,6 +2048,12 @@ mismatch:
** If either operand is NULL (and thus if the result is unknown) then ** If either operand is NULL (and thus if the result is unknown) then
** take the jump if P1 is true. ** take the jump if P1 is true.
** **
** If both values are numeric, they are converted to doubles using atof()
** and compared in that format. Numeric values are always less than
** non-numeric values. If both operands are non-numeric, the strcmp() library
** routine is used for the comparison. For a pure text comparison
** use OP_StrLe.
**
** If P2 is zero, do not jump. Instead, push an integer 1 onto the ** If P2 is zero, do not jump. Instead, push an integer 1 onto the
** stack if the jump would have been taken, or a 0 if not. Push a ** stack if the jump would have been taken, or a 0 if not. Push a
** NULL if either operand was NULL. ** NULL if either operand was NULL.
@ -2044,6 +2067,12 @@ mismatch:
** If either operand is NULL (and thus if the result is unknown) then ** If either operand is NULL (and thus if the result is unknown) then
** take the jump if P1 is true. ** take the jump if P1 is true.
** **
** If both values are numeric, they are converted to doubles using atof()
** and compared in that format. Numeric values are always less than
** non-numeric values. If both operands are non-numeric, the strcmp() library
** routine is used for the comparison. For a pure text comparison
** use OP_StrGt.
**
** If P2 is zero, do not jump. Instead, push an integer 1 onto the ** If P2 is zero, do not jump. Instead, push an integer 1 onto the
** stack if the jump would have been taken, or a 0 if not. Push a ** stack if the jump would have been taken, or a 0 if not. Push a
** NULL if either operand was NULL. ** NULL if either operand was NULL.
@ -2057,6 +2086,12 @@ mismatch:
** If either operand is NULL (and thus if the result is unknown) then ** If either operand is NULL (and thus if the result is unknown) then
** take the jump if P1 is true. ** take the jump if P1 is true.
** **
** If both values are numeric, they are converted to doubles using atof()
** and compared in that format. Numeric values are always less than
** non-numeric values. If both operands are non-numeric, the strcmp() library
** routine is used for the comparison. For a pure text comparison
** use OP_StrGe.
**
** If P2 is zero, do not jump. Instead, push an integer 1 onto the ** If P2 is zero, do not jump. Instead, push an integer 1 onto the
** stack if the jump would have been taken, or a 0 if not. Push a ** stack if the jump would have been taken, or a 0 if not. Push a
** NULL if either operand was NULL. ** NULL if either operand was NULL.
@ -2116,6 +2151,145 @@ case OP_Ge: {
break; break;
} }
/* Opcode: StrEq P1 P2 *
**
** Pop the top two elements from the stack. If they are equal, then
** jump to instruction P2. Otherwise, continue to the next instruction.
**
** If either operand is NULL (and thus if the result is unknown) then
** take the jump if P1 is true.
**
** The strcmp() library routine is used for the comparison. For a
** numeric comparison, use OP_Eq.
**
** If P2 is zero, do not jump. Instead, push an integer 1 onto the
** stack if the jump would have been taken, or a 0 if not. Push a
** NULL if either operand was NULL.
*/
/* Opcode: StrNe P1 P2 *
**
** Pop the top two elements from the stack. If they are not equal, then
** jump to instruction P2. Otherwise, continue to the next instruction.
**
** If either operand is NULL (and thus if the result is unknown) then
** take the jump if P1 is true.
**
** The strcmp() library routine is used for the comparison. For a
** numeric comparison, use OP_Ne.
**
** If P2 is zero, do not jump. Instead, push an integer 1 onto the
** stack if the jump would have been taken, or a 0 if not. Push a
** NULL if either operand was NULL.
*/
/* Opcode: StrLt P1 P2 *
**
** Pop the top two elements from the stack. If second element (the
** next on stack) is less than the first (the top of stack), then
** jump to instruction P2. Otherwise, continue to the next instruction.
** In other words, jump if NOS<TOS.
**
** If either operand is NULL (and thus if the result is unknown) then
** take the jump if P1 is true.
**
** The strcmp() library routine is used for the comparison. For a
** numeric comparison, use OP_Lt.
**
** If P2 is zero, do not jump. Instead, push an integer 1 onto the
** stack if the jump would have been taken, or a 0 if not. Push a
** NULL if either operand was NULL.
*/
/* Opcode: StrLe P1 P2 *
**
** Pop the top two elements from the stack. If second element (the
** next on stack) is less than or equal to the first (the top of stack),
** then jump to instruction P2. In other words, jump if NOS<=TOS.
**
** If either operand is NULL (and thus if the result is unknown) then
** take the jump if P1 is true.
**
** The strcmp() library routine is used for the comparison. For a
** numeric comparison, use OP_Le.
**
** If P2 is zero, do not jump. Instead, push an integer 1 onto the
** stack if the jump would have been taken, or a 0 if not. Push a
** NULL if either operand was NULL.
*/
/* Opcode: StrGt P1 P2 *
**
** Pop the top two elements from the stack. If second element (the
** next on stack) is greater than the first (the top of stack),
** then jump to instruction P2. In other words, jump if NOS>TOS.
**
** If either operand is NULL (and thus if the result is unknown) then
** take the jump if P1 is true.
**
** The strcmp() library routine is used for the comparison. For a
** numeric comparison, use OP_Gt.
**
** If P2 is zero, do not jump. Instead, push an integer 1 onto the
** stack if the jump would have been taken, or a 0 if not. Push a
** NULL if either operand was NULL.
*/
/* Opcode: StrGe P1 P2 *
**
** Pop the top two elements from the stack. If second element (the next
** on stack) is greater than or equal to the first (the top of stack),
** then jump to instruction P2. In other words, jump if NOS>=TOS.
**
** If either operand is NULL (and thus if the result is unknown) then
** take the jump if P1 is true.
**
** The strcmp() library routine is used for the comparison. For a
** numeric comparison, use OP_Ge.
**
** If P2 is zero, do not jump. Instead, push an integer 1 onto the
** stack if the jump would have been taken, or a 0 if not. Push a
** NULL if either operand was NULL.
*/
case OP_StrEq:
case OP_StrNe:
case OP_StrLt:
case OP_StrLe:
case OP_StrGt:
case OP_StrGe: {
int tos = p->tos;
int nos = tos - 1;
int c;
VERIFY( if( nos<0 ) goto not_enough_stack; )
if( (aStack[nos].flags | aStack[tos].flags) & STK_Null ){
POPSTACK;
POPSTACK;
if( pOp->p2 ){
if( pOp->p1 ) pc = pOp->p2-1;
}else{
p->tos++;
aStack[nos].flags = STK_Null;
}
break;
}else{
if( Stringify(p, tos) || Stringify(p, nos) ) goto no_mem;
c = strcmp(zStack[nos], zStack[tos]);
}
switch( pOp->opcode ){
case OP_Eq: c = c==0; break;
case OP_Ne: c = c!=0; break;
case OP_Lt: c = c<0; break;
case OP_Le: c = c<=0; break;
case OP_Gt: c = c>0; break;
default: c = c>=0; break;
}
POPSTACK;
POPSTACK;
if( pOp->p2 ){
if( c ) pc = pOp->p2-1;
}else{
p->tos++;
aStack[nos].flags = STK_Int;
aStack[nos].i = c;
}
break;
}
/* Opcode: And * * * /* Opcode: And * * *
** **
** Pop two values off the stack. Take the logical AND of the ** Pop two values off the stack. Take the logical AND of the
@ -2435,7 +2609,7 @@ case OP_MakeRecord: {
break; break;
} }
/* Opcode: MakeKey P1 P2 * /* Opcode: MakeKey P1 P2 P3
** **
** Convert the top P1 entries of the stack into a single entry suitable ** Convert the top P1 entries of the stack into a single entry suitable
** for use as the key in an index. The top P1 records are ** for use as the key in an index. The top P1 records are
@ -2449,9 +2623,14 @@ case OP_MakeRecord: {
** data is popped off the stack first then the new key is pushed ** data is popped off the stack first then the new key is pushed
** back in its place. ** back in its place.
** **
** 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.
**
** See also: MakeIdxKey, SortMakeKey ** See also: MakeIdxKey, SortMakeKey
*/ */
/* Opcode: MakeIdxKey P1 P2 * /* Opcode: MakeIdxKey P1 P2 P3
** **
** Convert the top P1 entries of the stack into a single entry suitable ** Convert the top P1 entries of the stack into a single entry suitable
** for use as the key in an index. In addition, take one additional integer ** for use as the key in an index. In addition, take one additional integer
@ -2473,6 +2652,11 @@ case OP_MakeRecord: {
** guaranteed to be unique. This jump can be used to skip a subsequent ** guaranteed to be unique. This jump can be used to skip a subsequent
** uniqueness test. ** uniqueness test.
** **
** 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.
**
** See also: MakeKey, SortMakeKey ** See also: MakeKey, SortMakeKey
*/ */
case OP_MakeIdxKey: case OP_MakeIdxKey:
@ -2488,13 +2672,15 @@ case OP_MakeKey: {
nField = pOp->p1; nField = pOp->p1;
VERIFY( if( p->tos+1+addRowid<nField ) goto not_enough_stack; ) VERIFY( if( p->tos+1+addRowid<nField ) goto not_enough_stack; )
nByte = 0; nByte = 0;
for(i=p->tos-nField+1; i<=p->tos; i++){ for(j=0, i=p->tos-nField+1; i<=p->tos; i++, j++){
int flags = aStack[i].flags; int flags = aStack[i].flags;
int len; int len;
char *z; char *z;
if( flags & STK_Null ){ if( flags & STK_Null ){
nByte += 2; nByte += 2;
containsNull = 1; containsNull = 1;
}else if( pOp->p3 && pOp->p3[j]=='t' ){
Stringify(p, i);
}else if( flags & STK_Real ){ }else if( flags & STK_Real ){
z = aStack[i].z; z = aStack[i].z;
sqliteRealToSortable(aStack[i].r, &z[1]); sqliteRealToSortable(aStack[i].r, &z[1]);

View File

@ -15,7 +15,7 @@
** or VDBE. The VDBE implements an abstract machine that runs a ** or VDBE. The VDBE implements an abstract machine that runs a
** simple program to access and modify the underlying database. ** simple program to access and modify the underlying database.
** **
** $Id: vdbe.h,v 1.55 2002/06/14 22:38:43 drh Exp $ ** $Id: vdbe.h,v 1.56 2002/06/20 11:36:50 drh Exp $
*/ */
#ifndef _SQLITE_VDBE_H_ #ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_ #define _SQLITE_VDBE_H_
@ -187,27 +187,37 @@ typedef struct VdbeOp VdbeOp;
#define OP_ShiftLeft 102 #define OP_ShiftLeft 102
#define OP_ShiftRight 103 #define OP_ShiftRight 103
#define OP_AbsValue 104 #define OP_AbsValue 104
/* Note: The code generator assumes that OP_XX+6==OP_StrXX */
#define OP_Eq 105 #define OP_Eq 105
#define OP_Ne 106 #define OP_Ne 106
#define OP_Lt 107 #define OP_Lt 107
#define OP_Le 108 #define OP_Le 108
#define OP_Gt 109 #define OP_Gt 109
#define OP_Ge 110 #define OP_Ge 110
#define OP_IsNull 111 #define OP_StrEq 111
#define OP_NotNull 112 #define OP_StrNe 112
#define OP_Negative 113 #define OP_StrLt 113
#define OP_And 114 #define OP_StrLe 114
#define OP_Or 115 #define OP_StrGt 115
#define OP_Not 116 #define OP_StrGe 116
#define OP_Concat 117 /* Note: the code generator assumes that OP_XX+6==OP_StrXX */
#define OP_Noop 118
#define OP_Function 119
#define OP_Limit 120 #define OP_IsNull 117
#define OP_LimitCk 121 #define OP_NotNull 118
#define OP_Negative 119
#define OP_And 120
#define OP_Or 121
#define OP_Not 122
#define OP_Concat 123
#define OP_Noop 124
#define OP_Function 125
#define OP_Limit 126
#define OP_LimitCk 127
#define OP_MAX 121 #define OP_MAX 127
/* /*
** Prototypes for the VDBE interface. See comments on the implementation ** Prototypes for the VDBE interface. See comments on the implementation