mirror of https://github.com/sqlite/sqlite
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:
parent
c926afbc2d
commit
c9b84a1fb1
26
manifest
26
manifest
|
@ -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
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
43c5aff5d078bce9292683cd40311e0dcc81ac14
|
cbbc858d973c2d515c6a2464981316549a241b73
|
39
src/build.c
39
src/build.c
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
158
src/expr.c
158
src/expr.c
|
@ -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;
|
||||||
|
|
61
src/func.c
61
src/func.c
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
18
src/main.c
18
src/main.c
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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*);
|
||||||
|
|
202
src/vdbe.c
202
src/vdbe.c
|
@ -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]);
|
||||||
|
|
36
src/vdbe.h
36
src/vdbe.h
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue