mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-27 20:41:58 +03:00
More changes to support the new types model. Compound SELECTs are currently
broken. (CVS 1389) FossilOrigin-Name: 0f6c9b05e688e281fa168aacdd867db408df2863
This commit is contained in:
26
manifest
26
manifest
@ -1,5 +1,5 @@
|
|||||||
C Fix\sa\sbug\smeant\sreal\snumbers\swith\sa\snegative\ssign\swere\sbeing\sstored\sas\nstrings\sby\sdefault\s(instead\sof\sIEEE\sfloats).\s(CVS\s1388)
|
C More\schanges\sto\ssupport\sthe\snew\stypes\smodel.\sCompound\sSELECTs\sare\scurrently\nbroken.\s(CVS\s1389)
|
||||||
D 2004-05-16T22:55:28
|
D 2004-05-17T10:48:58
|
||||||
F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a
|
F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a
|
||||||
F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
|
F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
|
||||||
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
|
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
|
||||||
@ -31,11 +31,11 @@ F src/copy.c 4d2038602fd0549d80c59bda27d96f13ea9b5e29
|
|||||||
F src/date.c 0eb0a89960bb45c7f7e768748605a7a97b0c8064
|
F src/date.c 0eb0a89960bb45c7f7e768748605a7a97b0c8064
|
||||||
F src/delete.c ea8212a44b5c0dad8fb1794fe7297654f7ed05f9
|
F src/delete.c ea8212a44b5c0dad8fb1794fe7297654f7ed05f9
|
||||||
F src/encode.c a876af473d1d636faa3dca51c7571f2e007eea37
|
F src/encode.c a876af473d1d636faa3dca51c7571f2e007eea37
|
||||||
F src/expr.c 05fbd5df274b61fd70c216375e2fbd407e475ae7
|
F src/expr.c d39afb30c76c2f67fb5ffdfe530ed709c5009786
|
||||||
F src/func.c cfbb7096efb58e2857e3b312a8958a12774b625a
|
F src/func.c cfbb7096efb58e2857e3b312a8958a12774b625a
|
||||||
F src/hash.c 440c2f8cb373ee1b4e13a0988489c7cd95d55b6f
|
F src/hash.c 440c2f8cb373ee1b4e13a0988489c7cd95d55b6f
|
||||||
F src/hash.h 762d95f1e567664d1eafc1687de755626be962fb
|
F src/hash.h 762d95f1e567664d1eafc1687de755626be962fb
|
||||||
F src/insert.c 76e13b736391a342bd0fc152ade2558588322868
|
F src/insert.c 656a648a7ab06a647a3bc5453d6a69f4fbd568e3
|
||||||
F src/main.c 4b82d7e78f4c9799343b02740a5ba9768d5e464d
|
F src/main.c 4b82d7e78f4c9799343b02740a5ba9768d5e464d
|
||||||
F src/md5.c 8e39fdae6d8776b87558e91dcc94740c9b635a9c
|
F src/md5.c 8e39fdae6d8776b87558e91dcc94740c9b635a9c
|
||||||
F src/os.c ddcda92f7fd71b4513c57c1ec797917f206d504e
|
F src/os.c ddcda92f7fd71b4513c57c1ec797917f206d504e
|
||||||
@ -46,10 +46,10 @@ F src/parse.y d0258aa3cc8b0c5742b07b699d10fa98f3caea7d
|
|||||||
F src/pragma.c 351836bce186f4eee45a32868b7a379c22ac344a
|
F src/pragma.c 351836bce186f4eee45a32868b7a379c22ac344a
|
||||||
F src/printf.c ef750e8e2398ca7e8b58be991075f08c6a7f0e53
|
F src/printf.c ef750e8e2398ca7e8b58be991075f08c6a7f0e53
|
||||||
F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3
|
F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3
|
||||||
F src/select.c ca99ae4db14a45a436ec51d3e6bd48d44a3efb3c
|
F src/select.c b62bb2507df4bfac45f808ac9de9a2af99b9ff28
|
||||||
F src/shell.c 0c4662e13bfbfd3d13b066c5859cc97ad2f95d21
|
F src/shell.c 0c4662e13bfbfd3d13b066c5859cc97ad2f95d21
|
||||||
F src/sqlite.h.in 799c5e726296ec7bc20e6407cdf4df0e0bc00c0c
|
F src/sqlite.h.in 799c5e726296ec7bc20e6407cdf4df0e0bc00c0c
|
||||||
F src/sqliteInt.h bc118a7a701afb954f4cd2110cd0986478e1a741
|
F src/sqliteInt.h ac5fe07df6cf0a4c935e5a88bc14bc620e4f1591
|
||||||
F src/table.c af14284fa36c8d41f6829e3f2819dce07d3e2de2
|
F src/table.c af14284fa36c8d41f6829e3f2819dce07d3e2de2
|
||||||
F src/tclsqlite.c fbf0fac73624ae246551a6c671f1de0235b5faa1
|
F src/tclsqlite.c fbf0fac73624ae246551a6c671f1de0235b5faa1
|
||||||
F src/test1.c 12ef76b8aaba4408422f21f269256b630d4dd627
|
F src/test1.c 12ef76b8aaba4408422f21f269256b630d4dd627
|
||||||
@ -63,11 +63,11 @@ F src/update.c 04492438aee57a6be5a8a8e54e3add12c1d598ca
|
|||||||
F src/utf.c fc799748d43fe1982d157b871e3e420a19c85d4f
|
F src/utf.c fc799748d43fe1982d157b871e3e420a19c85d4f
|
||||||
F src/util.c f9511ffba78e6cf71a28774c2820d7750b5bacdf
|
F src/util.c f9511ffba78e6cf71a28774c2820d7750b5bacdf
|
||||||
F src/vacuum.c c134702e023db8778e6be59ac0ea7b02315b5476
|
F src/vacuum.c c134702e023db8778e6be59ac0ea7b02315b5476
|
||||||
F src/vdbe.c c2feeaaf0c3c49326c5c702ad34bcc71f6c728c0
|
F src/vdbe.c e8fd1b095f83336519b862b9e79765e3e4493d80
|
||||||
F src/vdbe.h 94457ca73bae972dc61bca33a4dccc2e6e14e2f8
|
F src/vdbe.h 94457ca73bae972dc61bca33a4dccc2e6e14e2f8
|
||||||
F src/vdbeInt.h 311c2a046ea419781d0ef331198b7b0a65eebc92
|
F src/vdbeInt.h 311c2a046ea419781d0ef331198b7b0a65eebc92
|
||||||
F src/vdbeaux.c bd259da3ae52cd4f6febb0c83f60c0b9170f3ebb
|
F src/vdbeaux.c 394bde6b1715e28b869d55e5cd90682d87f527e4
|
||||||
F src/where.c 610fadd08c5a25c2aa3bdd8700c3173de64298d0
|
F src/where.c 76a820b814d7ae0bd6b4110aafafce29fd534dfc
|
||||||
F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242
|
F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242
|
||||||
F test/attach.test cb9b884344e6cfa5e165965d5b1adea679a24c83
|
F test/attach.test cb9b884344e6cfa5e165965d5b1adea679a24c83
|
||||||
F test/attach2.test 7c388dee63a4c1997695c3d41957f32ce784ac56
|
F test/attach2.test 7c388dee63a4c1997695c3d41957f32ce784ac56
|
||||||
@ -145,7 +145,7 @@ F test/trigger2.test 0767ab30cb5a2c8402c8524f3d566b410b6f5263
|
|||||||
F test/trigger3.test a95ccace88291449f5eae7139ec438a42f90654d
|
F test/trigger3.test a95ccace88291449f5eae7139ec438a42f90654d
|
||||||
F test/trigger4.test 542afce45774e8f8e1130b96b8675f414d6e4bd8
|
F test/trigger4.test 542afce45774e8f8e1130b96b8675f414d6e4bd8
|
||||||
F test/types.test 5d877a84e148defced602e401ed6ef07778de237
|
F test/types.test 5d877a84e148defced602e401ed6ef07778de237
|
||||||
F test/types2.test bc684cc2a75edb240f9fd49275f3cacb025c0f1e
|
F test/types2.test b9b528e5ec6c5d8ee149ff27d48a23ce3f6075d9
|
||||||
F test/unique.test 0e38d4cc7affeef2527720d1dafd1f6870f02f2b
|
F test/unique.test 0e38d4cc7affeef2527720d1dafd1f6870f02f2b
|
||||||
F test/update.test b29bd9061a1150426dab6959806fcc73a41b1217
|
F test/update.test b29bd9061a1150426dab6959806fcc73a41b1217
|
||||||
F test/vacuum.test a2a44544df719666efb51afbfeb6062fd59a672a
|
F test/vacuum.test a2a44544df719666efb51afbfeb6062fd59a672a
|
||||||
@ -192,7 +192,7 @@ F www/sqlite.tcl 3c83b08cf9f18aa2d69453ff441a36c40e431604
|
|||||||
F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da
|
F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da
|
||||||
F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1
|
F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1
|
||||||
F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4
|
F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4
|
||||||
P 6c73544bfacb891aae8d6124a2903ccff616494b
|
P 9321e7426337e04064b5791c48dd5fc3c1eecaa2
|
||||||
R 501dab3e6d7516a92cf6493947aae309
|
R 9e09205970304eba71ff10d90be26268
|
||||||
U danielk1977
|
U danielk1977
|
||||||
Z d2d630c4c8ff164b94b4f7249daadaaf
|
Z 80bb342777e861c5628fead0ab144825
|
||||||
|
@ -1 +1 @@
|
|||||||
9321e7426337e04064b5791c48dd5fc3c1eecaa2
|
0f6c9b05e688e281fa168aacdd867db408df2863
|
222
src/expr.c
222
src/expr.c
@ -12,11 +12,39 @@
|
|||||||
** 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.120 2004/05/16 22:55:28 danielk1977 Exp $
|
** $Id: expr.c,v 1.121 2004/05/17 10:48:58 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
|
char const *sqlite3AffinityString(char affinity){
|
||||||
|
switch( affinity ){
|
||||||
|
case SQLITE_AFF_INTEGER: return "i";
|
||||||
|
case SQLITE_AFF_NUMERIC: return "n";
|
||||||
|
case SQLITE_AFF_TEXT: return "t";
|
||||||
|
case SQLITE_AFF_NONE: return "o";
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Return the 'affinity' of the expression pExpr if any.
|
||||||
|
**
|
||||||
|
** If pExpr is a column, a reference to a column via an 'AS' alias,
|
||||||
|
** or a sub-select with a column as the return value, then the
|
||||||
|
** affinity of that column is returned. Otherwise, 0x00 is returned,
|
||||||
|
** indicating no affinity for the expression.
|
||||||
|
**
|
||||||
|
** i.e. the WHERE clause expresssions in the following statements all
|
||||||
|
** have an affinity:
|
||||||
|
**
|
||||||
|
** CREATE TABLE t1(a);
|
||||||
|
** SELECT * FROM t1 WHERE a;
|
||||||
|
** SELECT a AS b FROM t1 WHERE b;
|
||||||
|
** SELECT * FROM t1 WHERE (select a from t1);
|
||||||
|
*/
|
||||||
static char exprAffinity(Expr *pExpr){
|
static char exprAffinity(Expr *pExpr){
|
||||||
if( pExpr->op==TK_AS ){
|
if( pExpr->op==TK_AS ){
|
||||||
return exprAffinity(pExpr->pLeft);
|
return exprAffinity(pExpr->pLeft);
|
||||||
@ -27,6 +55,64 @@ static char exprAffinity(Expr *pExpr){
|
|||||||
return pExpr->affinity;
|
return pExpr->affinity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char sqlite3CompareAffinity(Expr *pExpr, char aff2){
|
||||||
|
char aff1 = exprAffinity(pExpr);
|
||||||
|
if( aff1 && aff2 ){
|
||||||
|
/* Both sides of the comparison are columns. If one has numeric or
|
||||||
|
** integer affinity, use that. Otherwise use no affinity.
|
||||||
|
*/
|
||||||
|
if( aff1==SQLITE_AFF_INTEGER || aff2==SQLITE_AFF_INTEGER ){
|
||||||
|
return SQLITE_AFF_INTEGER;
|
||||||
|
}else if( aff1==SQLITE_AFF_NUMERIC || aff2==SQLITE_AFF_NUMERIC ){
|
||||||
|
return SQLITE_AFF_NUMERIC;
|
||||||
|
}else{
|
||||||
|
return SQLITE_AFF_NONE;
|
||||||
|
}
|
||||||
|
}else if( !aff1 && !aff2 ){
|
||||||
|
/* Neither side of the comparison is a column. Use numeric affinity
|
||||||
|
** for the comparison.
|
||||||
|
*/
|
||||||
|
return SQLITE_AFF_NUMERIC;
|
||||||
|
}else{
|
||||||
|
/* One side is a column, the other is not. Use the columns affinity. */
|
||||||
|
return (aff1 + aff2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static char comparisonAffinity(Expr *pExpr){
|
||||||
|
char aff;
|
||||||
|
assert( pExpr->op==TK_EQ || pExpr->op==TK_IN || pExpr->op==TK_LT ||
|
||||||
|
pExpr->op==TK_GT || pExpr->op==TK_GE || pExpr->op==TK_LE ||
|
||||||
|
pExpr->op==TK_NE );
|
||||||
|
assert( pExpr->pLeft );
|
||||||
|
aff = exprAffinity(pExpr->pLeft);
|
||||||
|
if( pExpr->pRight ){
|
||||||
|
aff = sqlite3CompareAffinity(pExpr->pRight, aff);
|
||||||
|
}
|
||||||
|
else if( pExpr->pSelect ){
|
||||||
|
aff = sqlite3CompareAffinity(pExpr->pSelect->pEList->a[0].pExpr, aff);
|
||||||
|
}
|
||||||
|
else if( !aff ){
|
||||||
|
aff = SQLITE_AFF_NUMERIC;
|
||||||
|
}
|
||||||
|
return aff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** pExpr is a comparison expression, eg. '=', '<', IN(...) etc.
|
||||||
|
** idx_affinity is the affinity of an indexed column. Return true
|
||||||
|
** if the index with affinity idx_affinity may be used to implement
|
||||||
|
** the comparison in pExpr.
|
||||||
|
*/
|
||||||
|
int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity){
|
||||||
|
char aff = comparisonAffinity(pExpr);
|
||||||
|
return
|
||||||
|
(aff==SQLITE_AFF_NONE) ||
|
||||||
|
(aff==SQLITE_AFF_NUMERIC && idx_affinity==SQLITE_AFF_INTEGER) ||
|
||||||
|
(aff==SQLITE_AFF_INTEGER && idx_affinity==SQLITE_AFF_NUMERIC) ||
|
||||||
|
(aff==idx_affinity);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Return the P1 value that should be used for a binary comparison
|
** Return the P1 value that should be used for a binary comparison
|
||||||
** opcode (OP_Eq, OP_Ge etc.) used to compare pExpr1 and pExpr2.
|
** opcode (OP_Eq, OP_Ge etc.) used to compare pExpr1 and pExpr2.
|
||||||
@ -34,27 +120,9 @@ static char exprAffinity(Expr *pExpr){
|
|||||||
** P1 value to tell the opcode to jump if either expression
|
** P1 value to tell the opcode to jump if either expression
|
||||||
** evaluates to NULL.
|
** evaluates to NULL.
|
||||||
*/
|
*/
|
||||||
int binaryCompareP1(Expr *pExpr1, Expr *pExpr2, int jumpIfNull){
|
static int binaryCompareP1(Expr *pExpr1, Expr *pExpr2, int jumpIfNull){
|
||||||
char aff1 = exprAffinity(pExpr1);
|
char aff = exprAffinity(pExpr2);
|
||||||
char aff2 = exprAffinity(pExpr2);
|
return (((int)sqlite3CompareAffinity(pExpr1, aff))<<8)+(jumpIfNull?1:0);
|
||||||
|
|
||||||
if( aff1 && aff2 ){
|
|
||||||
/* Both sides of the comparison are columns. If one has numeric or
|
|
||||||
** integer affinity, use that. Otherwise use no affinity.
|
|
||||||
*/
|
|
||||||
if( aff1==SQLITE_AFF_INTEGER || aff2==SQLITE_AFF_INTEGER ){
|
|
||||||
aff1 = SQLITE_AFF_INTEGER;
|
|
||||||
}else
|
|
||||||
if( aff1==SQLITE_AFF_NUMERIC || aff2==SQLITE_AFF_NUMERIC ){
|
|
||||||
aff1 = SQLITE_AFF_NUMERIC;
|
|
||||||
}else{
|
|
||||||
aff1 = SQLITE_AFF_NONE;
|
|
||||||
}
|
|
||||||
}else if( !aff1 ){
|
|
||||||
aff1 = aff2;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (((int)aff1)<<8)+(jumpIfNull?1:0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -728,30 +796,59 @@ int sqlite3ExprResolveIds(
|
|||||||
}
|
}
|
||||||
|
|
||||||
case TK_IN: {
|
case TK_IN: {
|
||||||
|
char affinity;
|
||||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||||
if( v==0 ) return 1;
|
if( v==0 ) return 1;
|
||||||
if( sqlite3ExprResolveIds(pParse, pSrcList, pEList, pExpr->pLeft) ){
|
if( sqlite3ExprResolveIds(pParse, pSrcList, pEList, pExpr->pLeft) ){
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
affinity = exprAffinity(pExpr->pLeft);
|
||||||
|
|
||||||
|
/* Whether this is an 'x IN(SELECT...)' or an 'x IN(<exprlist>)'
|
||||||
|
** expression it is handled the same way. A temporary table is
|
||||||
|
** filled with single-field index keys representing the results
|
||||||
|
** from the SELECT or the <exprlist>.
|
||||||
|
**
|
||||||
|
** If the 'x' expression is a column value, or the SELECT...
|
||||||
|
** statement returns a column value, then the affinity of that
|
||||||
|
** column is used to build the index keys. If both 'x' and the
|
||||||
|
** SELECT... statement are columns, then numeric affinity is used
|
||||||
|
** if either column has NUMERIC or INTEGER affinity. If neither
|
||||||
|
** 'x' nor the SELECT... statement are columns, then numeric affinity
|
||||||
|
** is used.
|
||||||
|
*/
|
||||||
|
pExpr->iTable = pParse->nTab++;
|
||||||
|
sqlite3VdbeAddOp(v, OP_OpenTemp, pExpr->iTable, 1);
|
||||||
|
|
||||||
if( pExpr->pSelect ){
|
if( pExpr->pSelect ){
|
||||||
/* Case 1: expr IN (SELECT ...)
|
/* Case 1: expr IN (SELECT ...)
|
||||||
**
|
**
|
||||||
** Generate code to write the results of the select into a temporary
|
** Generate code to write the results of the select into the temporary
|
||||||
** table. The cursor number of the temporary table has already
|
** table allocated and opened above.
|
||||||
** been put in iTable by sqlite3ExprResolveInSelect().
|
|
||||||
*/
|
*/
|
||||||
pExpr->iTable = pParse->nTab++;
|
int iParm = pExpr->iTable + (((int)affinity)<<16);
|
||||||
sqlite3VdbeAddOp(v, OP_OpenTemp, pExpr->iTable, 1);
|
assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable );
|
||||||
sqlite3Select(pParse, pExpr->pSelect, SRT_Set, pExpr->iTable, 0,0,0);
|
sqlite3Select(pParse, pExpr->pSelect, SRT_Set, iParm, 0, 0, 0);
|
||||||
}else if( pExpr->pList ){
|
}else if( pExpr->pList ){
|
||||||
/* Case 2: expr IN (exprlist)
|
/* Case 2: expr IN (exprlist)
|
||||||
**
|
**
|
||||||
** Create a set to put the exprlist values in. The Set id is stored
|
** For each expression, build an index key from the evaluation and
|
||||||
** in iTable.
|
** store it in the temporary table. If <expr> is a column, then use
|
||||||
|
** that columns affinity when building index keys. If <expr> is not
|
||||||
|
** a column, use numeric affinity.
|
||||||
*/
|
*/
|
||||||
int i, iSet;
|
int i;
|
||||||
|
char const *affStr;
|
||||||
|
if( !affinity ){
|
||||||
|
affinity = SQLITE_AFF_NUMERIC;
|
||||||
|
}
|
||||||
|
affStr = sqlite3AffinityString(affinity);
|
||||||
|
|
||||||
|
/* Loop through each expression in <exprlist>. */
|
||||||
for(i=0; i<pExpr->pList->nExpr; i++){
|
for(i=0; i<pExpr->pList->nExpr; i++){
|
||||||
Expr *pE2 = pExpr->pList->a[i].pExpr;
|
Expr *pE2 = pExpr->pList->a[i].pExpr;
|
||||||
|
|
||||||
|
/* Check that the expression is constant and valid. */
|
||||||
if( !sqlite3ExprIsConstant(pE2) ){
|
if( !sqlite3ExprIsConstant(pE2) ){
|
||||||
sqlite3ErrorMsg(pParse,
|
sqlite3ErrorMsg(pParse,
|
||||||
"right-hand side of IN operator must be constant");
|
"right-hand side of IN operator must be constant");
|
||||||
@ -760,27 +857,12 @@ int sqlite3ExprResolveIds(
|
|||||||
if( sqlite3ExprCheck(pParse, pE2, 0, 0) ){
|
if( sqlite3ExprCheck(pParse, pE2, 0, 0) ){
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
iSet = pExpr->iTable = pParse->nSet++;
|
/* Evaluate the expression and insert it into the temp table */
|
||||||
for(i=0; i<pExpr->pList->nExpr; i++){
|
sqlite3ExprCode(pParse, pE2);
|
||||||
Expr *pE2 = pExpr->pList->a[i].pExpr;
|
sqlite3VdbeOp3(v, OP_MakeKey, 1, 0, affStr, P3_STATIC);
|
||||||
switch( pE2->op ){
|
sqlite3VdbeAddOp(v, OP_String, 0, 0);
|
||||||
case TK_FLOAT:
|
sqlite3VdbeAddOp(v, OP_PutStrKey, pExpr->iTable, 0);
|
||||||
case TK_INTEGER:
|
|
||||||
case TK_STRING: {
|
|
||||||
int addr;
|
|
||||||
assert( pE2->token.z );
|
|
||||||
addr = sqlite3VdbeOp3(v, OP_SetInsert, iSet, 0,
|
|
||||||
pE2->token.z, pE2->token.n);
|
|
||||||
sqlite3VdbeDequoteP3(v, addr);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
sqlite3ExprCode(pParse, pE2);
|
|
||||||
sqlite3VdbeAddOp(v, OP_SetInsert, iSet, 0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1127,12 +1209,6 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
|
|||||||
sqlite3ExprCode(pParse, pExpr->pRight);
|
sqlite3ExprCode(pParse, pExpr->pRight);
|
||||||
sqlite3VdbeAddOp(v, op, p1, 0);
|
sqlite3VdbeAddOp(v, op, p1, 0);
|
||||||
break;
|
break;
|
||||||
#if 0
|
|
||||||
if( sqlite3ExprType(pExpr)==SQLITE_SO_TEXT ){
|
|
||||||
op += 6; /* Convert numeric opcodes to text opcodes */
|
|
||||||
}
|
|
||||||
/* Fall through into the next case */
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
case TK_AND:
|
case TK_AND:
|
||||||
case TK_OR:
|
case TK_OR:
|
||||||
@ -1225,19 +1301,29 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
|
|||||||
}
|
}
|
||||||
case TK_IN: {
|
case TK_IN: {
|
||||||
int addr;
|
int addr;
|
||||||
|
char const *affStr;
|
||||||
|
|
||||||
|
/* Figure out the affinity to use to create a key from the results
|
||||||
|
** of the expression. affinityStr stores a static string suitable for
|
||||||
|
** P3 of OP_MakeKey.
|
||||||
|
*/
|
||||||
|
affStr = sqlite3AffinityString(comparisonAffinity(pExpr));
|
||||||
|
|
||||||
sqlite3VdbeAddOp(v, OP_Integer, 1, 0);
|
sqlite3VdbeAddOp(v, OP_Integer, 1, 0);
|
||||||
|
|
||||||
|
/* Code the <expr> from "<expr> IN (...)". The temporary table
|
||||||
|
** pExpr->iTable contains the values that make up the (...) set.
|
||||||
|
*/
|
||||||
sqlite3ExprCode(pParse, pExpr->pLeft);
|
sqlite3ExprCode(pParse, pExpr->pLeft);
|
||||||
addr = sqlite3VdbeCurrentAddr(v);
|
addr = sqlite3VdbeCurrentAddr(v);
|
||||||
sqlite3VdbeAddOp(v, OP_NotNull, -1, addr+4);
|
sqlite3VdbeAddOp(v, OP_NotNull, -1, addr+4); /* addr + 0 */
|
||||||
sqlite3VdbeAddOp(v, OP_Pop, 2, 0);
|
sqlite3VdbeAddOp(v, OP_Pop, 2, 0);
|
||||||
sqlite3VdbeAddOp(v, OP_String, 0, 0);
|
sqlite3VdbeAddOp(v, OP_String, 0, 0);
|
||||||
sqlite3VdbeAddOp(v, OP_Goto, 0, addr+6);
|
sqlite3VdbeAddOp(v, OP_Goto, 0, addr+7);
|
||||||
if( pExpr->pSelect ){
|
sqlite3VdbeOp3(v, OP_MakeKey, 1, 0, affStr, P3_STATIC); /* addr + 4 */
|
||||||
sqlite3VdbeAddOp(v, OP_Found, pExpr->iTable, addr+6);
|
sqlite3VdbeAddOp(v, OP_Found, pExpr->iTable, addr+7);
|
||||||
}else{
|
sqlite3VdbeAddOp(v, OP_AddImm, -1, 0); /* addr + 6 */
|
||||||
sqlite3VdbeAddOp(v, OP_SetFound, pExpr->iTable, addr+6);
|
|
||||||
}
|
|
||||||
sqlite3VdbeAddOp(v, OP_AddImm, -1, 0);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TK_BETWEEN: {
|
case TK_BETWEEN: {
|
||||||
@ -1407,6 +1493,7 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
|||||||
sqlite3VdbeAddOp(v, op, 1, dest);
|
sqlite3VdbeAddOp(v, op, 1, dest);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#if 0
|
||||||
case TK_IN: {
|
case TK_IN: {
|
||||||
int addr;
|
int addr;
|
||||||
sqlite3ExprCode(pParse, pExpr->pLeft);
|
sqlite3ExprCode(pParse, pExpr->pLeft);
|
||||||
@ -1421,6 +1508,7 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
case TK_BETWEEN: {
|
case TK_BETWEEN: {
|
||||||
int addr;
|
int addr;
|
||||||
sqlite3ExprCode(pParse, pExpr->pLeft);
|
sqlite3ExprCode(pParse, pExpr->pLeft);
|
||||||
@ -1500,6 +1588,7 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
|||||||
sqlite3VdbeAddOp(v, op, 1, dest);
|
sqlite3VdbeAddOp(v, op, 1, dest);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#if 0
|
||||||
case TK_IN: {
|
case TK_IN: {
|
||||||
int addr;
|
int addr;
|
||||||
sqlite3ExprCode(pParse, pExpr->pLeft);
|
sqlite3ExprCode(pParse, pExpr->pLeft);
|
||||||
@ -1514,6 +1603,7 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
case TK_BETWEEN: {
|
case TK_BETWEEN: {
|
||||||
int addr;
|
int addr;
|
||||||
sqlite3ExprCode(pParse, pExpr->pLeft);
|
sqlite3ExprCode(pParse, pExpr->pLeft);
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
** This file contains C code routines that are called by the parser
|
** This file contains C code routines that are called by the parser
|
||||||
** to handle INSERT statements in SQLite.
|
** to handle INSERT statements in SQLite.
|
||||||
**
|
**
|
||||||
** $Id: insert.c,v 1.99 2004/05/16 11:15:38 danielk1977 Exp $
|
** $Id: insert.c,v 1.100 2004/05/17 10:48:58 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@ -30,12 +30,12 @@
|
|||||||
*/
|
*/
|
||||||
void sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){
|
void sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){
|
||||||
if( !pIdx->zColAff ){
|
if( !pIdx->zColAff ){
|
||||||
/* The first time a column affinity string for a particular table is
|
/* The first time a column affinity string for a particular index is
|
||||||
** required, it is allocated and populated here. It is then stored as
|
** required, it is allocated and populated here. It is then stored as
|
||||||
** a member of the Table structure for subsequent use.
|
** a member of the Index structure for subsequent use.
|
||||||
**
|
**
|
||||||
** The column affinity string will eventually be deleted by
|
** The column affinity string will eventually be deleted by
|
||||||
** sqliteDeleteIndex() when the Table structure itself is cleaned
|
** sqliteDeleteIndex() when the Index structure itself is cleaned
|
||||||
** up.
|
** up.
|
||||||
*/
|
*/
|
||||||
int n;
|
int n;
|
||||||
|
20
src/select.c
20
src/select.c
@ -12,7 +12,7 @@
|
|||||||
** This file contains C code routines that are called by the parser
|
** This file contains C code routines that are called by the parser
|
||||||
** to handle SELECT statements in SQLite.
|
** to handle SELECT statements in SQLite.
|
||||||
**
|
**
|
||||||
** $Id: select.c,v 1.164 2004/05/11 06:55:14 danielk1977 Exp $
|
** $Id: select.c,v 1.165 2004/05/17 10:48:58 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@ -479,6 +479,7 @@ static int selectInnerLoop(
|
|||||||
case SRT_Set: {
|
case SRT_Set: {
|
||||||
int addr1 = sqlite3VdbeCurrentAddr(v);
|
int addr1 = sqlite3VdbeCurrentAddr(v);
|
||||||
int addr2;
|
int addr2;
|
||||||
|
|
||||||
assert( nColumn==1 );
|
assert( nColumn==1 );
|
||||||
sqlite3VdbeAddOp(v, OP_NotNull, -1, addr1+3);
|
sqlite3VdbeAddOp(v, OP_NotNull, -1, addr1+3);
|
||||||
sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
|
sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
|
||||||
@ -486,8 +487,13 @@ static int selectInnerLoop(
|
|||||||
if( pOrderBy ){
|
if( pOrderBy ){
|
||||||
pushOntoSorter(pParse, v, pOrderBy);
|
pushOntoSorter(pParse, v, pOrderBy);
|
||||||
}else{
|
}else{
|
||||||
|
char const *affStr;
|
||||||
|
char aff = (iParm>>16)&0xFF;
|
||||||
|
aff = sqlite3CompareAffinity(pEList->a[0].pExpr, aff);
|
||||||
|
affStr = sqlite3AffinityString(aff);
|
||||||
|
sqlite3VdbeOp3(v, OP_MakeKey, 1, 1, affStr, P3_STATIC);
|
||||||
sqlite3VdbeAddOp(v, OP_String, 0, 0);
|
sqlite3VdbeAddOp(v, OP_String, 0, 0);
|
||||||
sqlite3VdbeAddOp(v, OP_PutStrKey, iParm, 0);
|
sqlite3VdbeAddOp(v, OP_PutStrKey, (iParm&0x0000FFFF), 0);
|
||||||
}
|
}
|
||||||
sqlite3VdbeChangeP2(v, addr2, sqlite3VdbeCurrentAddr(v));
|
sqlite3VdbeChangeP2(v, addr2, sqlite3VdbeCurrentAddr(v));
|
||||||
break;
|
break;
|
||||||
@ -593,8 +599,9 @@ static void generateSortTail(
|
|||||||
sqlite3VdbeAddOp(v, OP_NotNull, -1, sqlite3VdbeCurrentAddr(v)+3);
|
sqlite3VdbeAddOp(v, OP_NotNull, -1, sqlite3VdbeCurrentAddr(v)+3);
|
||||||
sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
|
sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
|
||||||
sqlite3VdbeAddOp(v, OP_Goto, 0, sqlite3VdbeCurrentAddr(v)+3);
|
sqlite3VdbeAddOp(v, OP_Goto, 0, sqlite3VdbeCurrentAddr(v)+3);
|
||||||
|
sqlite3VdbeOp3(v, OP_MakeKey, 1, 1, "n", P3_STATIC);
|
||||||
sqlite3VdbeAddOp(v, OP_String, 0, 0);
|
sqlite3VdbeAddOp(v, OP_String, 0, 0);
|
||||||
sqlite3VdbeAddOp(v, OP_PutStrKey, iParm, 0);
|
sqlite3VdbeAddOp(v, OP_PutStrKey, (iParm&0x0000FFFF), 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SRT_Mem: {
|
case SRT_Mem: {
|
||||||
@ -799,7 +806,7 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){
|
|||||||
char zBuf[30];
|
char zBuf[30];
|
||||||
sprintf(zBuf,"_%d",++cnt);
|
sprintf(zBuf,"_%d",++cnt);
|
||||||
n = strlen(zBuf);
|
n = strlen(zBuf);
|
||||||
sqlite3SetNString(&aCol[i].zName, pR->token.z, pR->token.n, zBuf, n,0);
|
sqlite3SetNString(&aCol[i].zName, pR->token.z, pR->token.n, zBuf,n,0);
|
||||||
j = -1;
|
j = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -810,6 +817,9 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){
|
|||||||
sprintf(zBuf, "column%d", i+1);
|
sprintf(zBuf, "column%d", i+1);
|
||||||
pTab->aCol[i].zName = sqliteStrDup(zBuf);
|
pTab->aCol[i].zName = sqliteStrDup(zBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Affinity is always NONE, as there is no type name. */
|
||||||
|
pTab->aCol[i].affinity = SQLITE_AFF_NONE;
|
||||||
}
|
}
|
||||||
pTab->iPKey = -1;
|
pTab->iPKey = -1;
|
||||||
return pTab;
|
return pTab;
|
||||||
@ -1942,7 +1952,7 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
|
|||||||
**
|
**
|
||||||
** SRT_Mem Store first result in memory cell iParm
|
** SRT_Mem Store first result in memory cell iParm
|
||||||
**
|
**
|
||||||
** SRT_Set Store results as keys of a table with cursor iParm
|
** SRT_Set Store results as keys of table iParm.
|
||||||
**
|
**
|
||||||
** SRT_Union Store results as a key in a temporary table iParm
|
** SRT_Union Store results as a key in a temporary table iParm
|
||||||
**
|
**
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
*************************************************************************
|
*************************************************************************
|
||||||
** Internal interface definitions for SQLite.
|
** Internal interface definitions for SQLite.
|
||||||
**
|
**
|
||||||
** @(#) $Id: sqliteInt.h,v 1.234 2004/05/16 11:15:39 danielk1977 Exp $
|
** @(#) $Id: sqliteInt.h,v 1.235 2004/05/17 10:48:58 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "sqlite.h"
|
#include "sqlite.h"
|
||||||
@ -1306,4 +1306,6 @@ int sqlite3VarintLen(u64 v);
|
|||||||
char sqlite3AffinityType(const char *, int);
|
char sqlite3AffinityType(const char *, int);
|
||||||
void sqlite3IndexAffinityStr(Vdbe *, Index *);
|
void sqlite3IndexAffinityStr(Vdbe *, Index *);
|
||||||
void sqlite3TableAffinityStr(Vdbe *, Table *);
|
void sqlite3TableAffinityStr(Vdbe *, Table *);
|
||||||
|
char sqlite3CompareAffinity(Expr *pExpr, char aff2);
|
||||||
|
char const *sqlite3AffinityString(char affinity);
|
||||||
|
int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity);
|
||||||
|
86
src/vdbe.c
86
src/vdbe.c
@ -43,7 +43,7 @@
|
|||||||
** in this file for details. If in doubt, do not deviate from existing
|
** in this file for details. If in doubt, do not deviate from existing
|
||||||
** commenting and indentation practices when changing or adding code.
|
** commenting and indentation practices when changing or adding code.
|
||||||
**
|
**
|
||||||
** $Id: vdbe.c,v 1.295 2004/05/16 11:57:28 danielk1977 Exp $
|
** $Id: vdbe.c,v 1.296 2004/05/17 10:48:58 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
@ -1379,16 +1379,10 @@ mismatch:
|
|||||||
** operand is NULL (and thus if the result is unknown) then take the jump
|
** operand is NULL (and thus if the result is unknown) then take the jump
|
||||||
** only if the least significant byte of P1 is 0x01.
|
** only if the least significant byte of P1 is 0x01.
|
||||||
**
|
**
|
||||||
** The second least significant byte of P1 determines whether any
|
** The second least significant byte of P1 must be an affinity character -
|
||||||
** conversions are applied to the two values before the comparison is made.
|
** 'n', 't', 'i' or 'o' - or 0x00. An attempt is made to coerce both values
|
||||||
** If this byte is 0x00, and one of the values being compared is numeric
|
** according to the affinity before the comparison is made. If the byte is
|
||||||
** and the other text, an attempt is made to convert the text value to
|
** 0x00, then numeric affinity is used.
|
||||||
** a numeric form.
|
|
||||||
**
|
|
||||||
** If the second least significant byte of P1 is not 0x00, then it must
|
|
||||||
** be an affinity character - 'n', 't', 'i' or 'o'. In this case an
|
|
||||||
** attempt is made to coerce both values according to the affinity before
|
|
||||||
** the comparison is made.
|
|
||||||
**
|
**
|
||||||
** Once any conversions have taken place, and neither value is NULL,
|
** Once any conversions have taken place, and neither value is NULL,
|
||||||
** the values are compared. If both values are blobs, or both are text,
|
** the values are compared. If both values are blobs, or both are text,
|
||||||
@ -1527,13 +1521,9 @@ case OP_Ge: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
affinity = (pOp->p1>>8)&0xFF;
|
affinity = (pOp->p1>>8)&0xFF;
|
||||||
if( !affinity && (flags&(MEM_Real|MEM_Int)) ){
|
if( affinity=='\0' ) affinity = 'n';
|
||||||
affinity = SQLITE_AFF_NUMERIC;
|
applyAffinity(pNos, affinity);
|
||||||
}
|
applyAffinity(pTos, affinity);
|
||||||
if( affinity ){
|
|
||||||
applyAffinity(pNos, affinity);
|
|
||||||
applyAffinity(pTos, affinity);
|
|
||||||
}
|
|
||||||
|
|
||||||
res = sqlite3MemCompare(pNos, pTos);
|
res = sqlite3MemCompare(pNos, pTos);
|
||||||
switch( pOp->opcode ){
|
switch( pOp->opcode ){
|
||||||
@ -2401,11 +2391,7 @@ case OP_MakeIdxKey: {
|
|||||||
*/
|
*/
|
||||||
for(pRec=pData0; pRec<=pTos; pRec++){
|
for(pRec=pData0; pRec<=pTos; pRec++){
|
||||||
u64 serial_type;
|
u64 serial_type;
|
||||||
if( zAffinity ){
|
applyAffinity(pRec, zAffinity[pRec-pData0]);
|
||||||
applyAffinity(pRec, zAffinity[pRec-pData0]);
|
|
||||||
}else{
|
|
||||||
applyAffinity(pRec, SQLITE_SO_NUM);
|
|
||||||
}
|
|
||||||
if( pRec->flags&MEM_Null ){
|
if( pRec->flags&MEM_Null ){
|
||||||
containsNull = 1;
|
containsNull = 1;
|
||||||
}
|
}
|
||||||
@ -2837,7 +2823,8 @@ case OP_OpenTemp: {
|
|||||||
rc = sqlite3BtreeCreateTable(pCx->pBt, &pgno, BTREE_ZERODATA);
|
rc = sqlite3BtreeCreateTable(pCx->pBt, &pgno, BTREE_ZERODATA);
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
assert( pgno==MASTER_ROOT+1 );
|
assert( pgno==MASTER_ROOT+1 );
|
||||||
rc = sqlite3BtreeCursor(pCx->pBt, pgno, 1, 0, 0, &pCx->pCursor);
|
rc = sqlite3BtreeCursor(pCx->pBt, pgno, 1, sqlite3VdbeKeyCompare,
|
||||||
|
pCx, &pCx->pCursor);
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
rc = sqlite3BtreeCursor(pCx->pBt, MASTER_ROOT, 1, 0, 0, &pCx->pCursor);
|
rc = sqlite3BtreeCursor(pCx->pBt, MASTER_ROOT, 1, 0, 0, &pCx->pCursor);
|
||||||
@ -3546,6 +3533,57 @@ case OP_Recno: {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Opcode: IdxColumn P1 * *
|
||||||
|
**
|
||||||
|
** P1 is a cursor opened on an index. Push the first field from the
|
||||||
|
** current index key onto the stack.
|
||||||
|
*/
|
||||||
|
case OP_IdxColumn: {
|
||||||
|
char *zData;
|
||||||
|
i64 n;
|
||||||
|
u64 serial_type;
|
||||||
|
int len;
|
||||||
|
int freeZData = 0;
|
||||||
|
BtCursor *pCsr;
|
||||||
|
|
||||||
|
assert( 0==p->apCsr[pOp->p1]->intKey );
|
||||||
|
pCsr = p->apCsr[pOp->p1]->pCursor;
|
||||||
|
rc = sqlite3BtreeKeySize(pCsr, &n);
|
||||||
|
if( rc!=SQLITE_OK ){
|
||||||
|
goto abort_due_to_error;
|
||||||
|
}
|
||||||
|
if( n>10 ) n = 10;
|
||||||
|
|
||||||
|
zData = (char *)sqlite3BtreeKeyFetch(pCsr, n);
|
||||||
|
assert( zData );
|
||||||
|
|
||||||
|
len = sqlite3GetVarint(zData, &serial_type);
|
||||||
|
n = sqlite3VdbeSerialTypeLen(serial_type);
|
||||||
|
|
||||||
|
zData = (char *)sqlite3BtreeKeyFetch(pCsr, len+n);
|
||||||
|
if( !zData ){
|
||||||
|
zData = (char *)sqliteMalloc(n);
|
||||||
|
if( !zData ){
|
||||||
|
rc = SQLITE_NOMEM;
|
||||||
|
goto abort_due_to_error;
|
||||||
|
}
|
||||||
|
rc = sqlite3BtreeKey(pCsr, len, n, zData);
|
||||||
|
if( rc!=SQLITE_OK ){
|
||||||
|
sqliteFree(zData);
|
||||||
|
goto abort_due_to_error;
|
||||||
|
}
|
||||||
|
freeZData = 1;
|
||||||
|
len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pTos++;
|
||||||
|
sqlite3VdbeSerialGet(&zData[len], serial_type, pTos);
|
||||||
|
if( freeZData ){
|
||||||
|
sqliteFree(zData);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* Opcode: FullKey P1 * *
|
/* Opcode: FullKey P1 * *
|
||||||
**
|
**
|
||||||
** Extract the complete key from the record that cursor P1 is currently
|
** Extract the complete key from the record that cursor P1 is currently
|
||||||
|
@ -1458,8 +1458,6 @@ int sqlite3VdbeKeyCompare(
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return_result:
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
54
src/where.c
54
src/where.c
@ -12,7 +12,7 @@
|
|||||||
** This module contains C code that generates VDBE code used to process
|
** This module contains C code that generates VDBE code used to process
|
||||||
** the WHERE clause of SQL statements.
|
** the WHERE clause of SQL statements.
|
||||||
**
|
**
|
||||||
** $Id: where.c,v 1.94 2004/05/16 11:15:41 danielk1977 Exp $
|
** $Id: where.c,v 1.95 2004/05/17 10:48:58 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@ -536,8 +536,10 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
&& (aExpr[j].prereqRight & loopMask)==aExpr[j].prereqRight ){
|
&& (aExpr[j].prereqRight & loopMask)==aExpr[j].prereqRight ){
|
||||||
int iColumn = aExpr[j].p->pLeft->iColumn;
|
int iColumn = aExpr[j].p->pLeft->iColumn;
|
||||||
int k;
|
int k;
|
||||||
|
char idxaff = pIdx->pTable->aCol[iColumn].affinity;
|
||||||
for(k=0; k<pIdx->nColumn; k++){
|
for(k=0; k<pIdx->nColumn; k++){
|
||||||
if( pIdx->aiColumn[k]==iColumn ){
|
if( pIdx->aiColumn[k]==iColumn
|
||||||
|
&& sqlite3IndexAffinityOk(aExpr[j].p, idxaff) ){
|
||||||
switch( aExpr[j].p->op ){
|
switch( aExpr[j].p->op ){
|
||||||
case TK_IN: {
|
case TK_IN: {
|
||||||
if( k==0 ) inMask |= 1;
|
if( k==0 ) inMask |= 1;
|
||||||
@ -571,8 +573,10 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
&& (aExpr[j].prereqLeft & loopMask)==aExpr[j].prereqLeft ){
|
&& (aExpr[j].prereqLeft & loopMask)==aExpr[j].prereqLeft ){
|
||||||
int iColumn = aExpr[j].p->pRight->iColumn;
|
int iColumn = aExpr[j].p->pRight->iColumn;
|
||||||
int k;
|
int k;
|
||||||
|
char idxaff = pIdx->pTable->aCol[iColumn].affinity;
|
||||||
for(k=0; k<pIdx->nColumn; k++){
|
for(k=0; k<pIdx->nColumn; k++){
|
||||||
if( pIdx->aiColumn[k]==iColumn ){
|
if( pIdx->aiColumn[k]==iColumn
|
||||||
|
&& sqlite3IndexAffinityOk(aExpr[j].p, idxaff) ){
|
||||||
switch( aExpr[j].p->op ){
|
switch( aExpr[j].p->op ){
|
||||||
case TK_EQ: {
|
case TK_EQ: {
|
||||||
eqMask |= 1<<k;
|
eqMask |= 1<<k;
|
||||||
@ -720,16 +724,10 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
Expr *pX = aExpr[k].p;
|
Expr *pX = aExpr[k].p;
|
||||||
if( pX->op!=TK_IN ){
|
if( pX->op!=TK_IN ){
|
||||||
sqlite3ExprCode(pParse, aExpr[k].p->pRight);
|
sqlite3ExprCode(pParse, aExpr[k].p->pRight);
|
||||||
}else if( pX->pList ){
|
|
||||||
sqlite3VdbeAddOp(v, OP_SetFirst, pX->iTable, brk);
|
|
||||||
pLevel->inOp = OP_SetNext;
|
|
||||||
pLevel->inP1 = pX->iTable;
|
|
||||||
pLevel->inP2 = sqlite3VdbeCurrentAddr(v);
|
|
||||||
}else{
|
}else{
|
||||||
assert( pX->pSelect );
|
|
||||||
sqlite3VdbeAddOp(v, OP_Rewind, pX->iTable, brk);
|
sqlite3VdbeAddOp(v, OP_Rewind, pX->iTable, brk);
|
||||||
sqlite3VdbeAddOp(v, OP_KeyAsData, pX->iTable, 1);
|
sqlite3VdbeAddOp(v, OP_KeyAsData, pX->iTable, 1);
|
||||||
pLevel->inP2 = sqlite3VdbeAddOp(v, OP_FullKey, pX->iTable, 0);
|
pLevel->inP2 = sqlite3VdbeAddOp(v, OP_IdxColumn, pX->iTable, 0);
|
||||||
pLevel->inOp = OP_Next;
|
pLevel->inOp = OP_Next;
|
||||||
pLevel->inP1 = pX->iTable;
|
pLevel->inP1 = pX->iTable;
|
||||||
}
|
}
|
||||||
@ -758,27 +756,22 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
&& (aExpr[k].prereqRight & loopMask)==aExpr[k].prereqRight
|
&& (aExpr[k].prereqRight & loopMask)==aExpr[k].prereqRight
|
||||||
&& pX->pLeft->iColumn==pIdx->aiColumn[j]
|
&& pX->pLeft->iColumn==pIdx->aiColumn[j]
|
||||||
){
|
){
|
||||||
if( pX->op==TK_EQ ){
|
char idxaff = pIdx->pTable->aCol[pX->pLeft->iColumn].affinity;
|
||||||
sqlite3ExprCode(pParse, pX->pRight);
|
if( sqlite3IndexAffinityOk(aExpr[k].p, idxaff) ){
|
||||||
aExpr[k].p = 0;
|
if( pX->op==TK_EQ ){
|
||||||
break;
|
sqlite3ExprCode(pParse, pX->pRight);
|
||||||
}
|
aExpr[k].p = 0;
|
||||||
if( pX->op==TK_IN && nColumn==1 ){
|
break;
|
||||||
if( pX->pList ){
|
}
|
||||||
sqlite3VdbeAddOp(v, OP_SetFirst, pX->iTable, brk);
|
if( pX->op==TK_IN && nColumn==1 ){
|
||||||
pLevel->inOp = OP_SetNext;
|
|
||||||
pLevel->inP1 = pX->iTable;
|
|
||||||
pLevel->inP2 = sqlite3VdbeCurrentAddr(v);
|
|
||||||
}else{
|
|
||||||
assert( pX->pSelect );
|
|
||||||
sqlite3VdbeAddOp(v, OP_Rewind, pX->iTable, brk);
|
sqlite3VdbeAddOp(v, OP_Rewind, pX->iTable, brk);
|
||||||
sqlite3VdbeAddOp(v, OP_KeyAsData, pX->iTable, 1);
|
sqlite3VdbeAddOp(v, OP_KeyAsData, pX->iTable, 1);
|
||||||
pLevel->inP2 = sqlite3VdbeAddOp(v, OP_FullKey, pX->iTable, 0);
|
pLevel->inP2 = sqlite3VdbeAddOp(v, OP_IdxColumn, pX->iTable, 0);
|
||||||
pLevel->inOp = OP_Next;
|
pLevel->inOp = OP_Next;
|
||||||
pLevel->inP1 = pX->iTable;
|
pLevel->inP1 = pX->iTable;
|
||||||
|
aExpr[k].p = 0;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
aExpr[k].p = 0;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( aExpr[k].idxRight==iCur
|
if( aExpr[k].idxRight==iCur
|
||||||
@ -786,9 +779,12 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
&& (aExpr[k].prereqLeft & loopMask)==aExpr[k].prereqLeft
|
&& (aExpr[k].prereqLeft & loopMask)==aExpr[k].prereqLeft
|
||||||
&& aExpr[k].p->pRight->iColumn==pIdx->aiColumn[j]
|
&& aExpr[k].p->pRight->iColumn==pIdx->aiColumn[j]
|
||||||
){
|
){
|
||||||
sqlite3ExprCode(pParse, aExpr[k].p->pLeft);
|
char idxaff = pIdx->pTable->aCol[pX->pRight->iColumn].affinity;
|
||||||
aExpr[k].p = 0;
|
if( sqlite3IndexAffinityOk(aExpr[k].p, idxaff) ){
|
||||||
break;
|
sqlite3ExprCode(pParse, aExpr[k].p->pLeft);
|
||||||
|
aExpr[k].p = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
133
test/types2.test
133
test/types2.test
@ -12,7 +12,7 @@
|
|||||||
# of this file is testing the interaction of manifest types, type affinity
|
# of this file is testing the interaction of manifest types, type affinity
|
||||||
# and comparison expressions.
|
# and comparison expressions.
|
||||||
#
|
#
|
||||||
# $Id: types2.test,v 1.1 2004/05/16 11:15:42 danielk1977 Exp $
|
# $Id: types2.test,v 1.2 2004/05/17 10:48:58 danielk1977 Exp $
|
||||||
|
|
||||||
set testdir [file dirname $argv0]
|
set testdir [file dirname $argv0]
|
||||||
source $testdir/tester.tcl
|
source $testdir/tester.tcl
|
||||||
@ -21,9 +21,16 @@ source $testdir/tester.tcl
|
|||||||
#
|
#
|
||||||
# types2-1.*: The '=' operator in the absence of an index.
|
# types2-1.*: The '=' operator in the absence of an index.
|
||||||
# types2-2.*: The '=' operator implemented using an index.
|
# types2-2.*: The '=' operator implemented using an index.
|
||||||
# types2-2.*: The '<' operator implemented using an index.
|
# types2-3.*: The '<' operator implemented using an index.
|
||||||
# types2-3.*: The '>' operator in the absense of an index.
|
# types2-4.*: The '>' operator in the absence of an index.
|
||||||
|
# types2-5.*: The 'IN(x, y...)' operator in the absence of an index.
|
||||||
|
# types2-6.*: The 'IN(x, y...)' operator with an index.
|
||||||
|
# types2-7.*: The 'IN(SELECT...)' operator in the absence of an index.
|
||||||
|
# types2-8.*: The 'IN(SELECT...)' operator with an index.
|
||||||
#
|
#
|
||||||
|
# All tests test the operators using literals and columns, but no
|
||||||
|
# other types of expressions. All expressions except columns are
|
||||||
|
# handled similarly in the implementation.
|
||||||
|
|
||||||
execsql {
|
execsql {
|
||||||
CREATE TABLE t1(
|
CREATE TABLE t1(
|
||||||
@ -51,11 +58,12 @@ proc test_bool {testname vars expr res} {
|
|||||||
do_test $t.3 "execsql {SELECT 1 FROM t1 WHERE NOT ($e)}" [expr $r?"":"1"]
|
do_test $t.3 "execsql {SELECT 1 FROM t1 WHERE NOT ($e)}" [expr $r?"":"1"]
|
||||||
}
|
}
|
||||||
|
|
||||||
# Compare literals against literals
|
# Compare literals against literals. This should always use a numeric
|
||||||
|
# comparison.
|
||||||
test_bool types2-1.1 "" {500 = 500.0} 1
|
test_bool types2-1.1 "" {500 = 500.0} 1
|
||||||
test_bool types2-1.2 "" {'500' = 500.0} 1
|
test_bool types2-1.2 "" {'500' = 500.0} 1
|
||||||
test_bool types2-1.3 "" {500 = '500.0'} 1
|
test_bool types2-1.3 "" {500 = '500.0'} 1
|
||||||
test_bool types2-1.4 "" {'500' = '500.0'} 0
|
test_bool types2-1.4 "" {'500' = '500.0'} 1
|
||||||
|
|
||||||
# Compare literals against a column with TEXT affinity
|
# Compare literals against a column with TEXT affinity
|
||||||
test_bool types2-1.5 {t1=500} {500 = t1} 1
|
test_bool types2-1.5 {t1=500} {500 = t1} 1
|
||||||
@ -148,11 +156,11 @@ test_boolset types2-3.2 {o < 20.0} {1 2}
|
|||||||
test_boolset types2-3.3 {o < '20'} {1 2 3 4 5 6 9 10}
|
test_boolset types2-3.3 {o < '20'} {1 2 3 4 5 6 9 10}
|
||||||
test_boolset types2-3.3 {o < '20.0'} {1 2 3 4 5 6 7 9 10}
|
test_boolset types2-3.3 {o < '20.0'} {1 2 3 4 5 6 7 9 10}
|
||||||
|
|
||||||
# Compare literals against literals
|
# Compare literals against literals (always a numeric comparison).
|
||||||
test_bool types2-4.1 "" {500 > 60.0} 1
|
test_bool types2-4.1 "" {500 > 60.0} 1
|
||||||
test_bool types2-4.2 "" {'500' > 60.0} 1
|
test_bool types2-4.2 "" {'500' > 60.0} 1
|
||||||
test_bool types2-4.3 "" {500 > '60.0'} 1
|
test_bool types2-4.3 "" {500 > '60.0'} 1
|
||||||
test_bool types2-4.4 "" {'500' > '60.0'} 0
|
test_bool types2-4.4 "" {'500' > '60.0'} 1
|
||||||
|
|
||||||
# Compare literals against a column with TEXT affinity
|
# Compare literals against a column with TEXT affinity
|
||||||
test_bool types2-4.5 {t1=500.0} {t1 > 500} 1
|
test_bool types2-4.5 {t1=500.0} {t1 > 500} 1
|
||||||
@ -184,6 +192,117 @@ test_bool types2-4.26 {o1='500'} {'500' > o1} 0
|
|||||||
test_bool types2-4.27 {o1='500'} {500.0 > o1} 0
|
test_bool types2-4.27 {o1='500'} {500.0 > o1} 0
|
||||||
test_bool types2-4.28 {o1='500'} {'500.0' > o1} 1
|
test_bool types2-4.28 {o1='500'} {'500.0' > o1} 1
|
||||||
|
|
||||||
|
# types2-5.* - The 'IN (x, y....)' operator with no index.
|
||||||
|
#
|
||||||
|
# Compare literals against literals (always a numeric comparison).
|
||||||
|
test_bool types2-5.1 {} {(NULL IN ('10.0', 20)) ISNULL} 1
|
||||||
|
test_bool types2-5.2 {} {10 IN ('10.0', 20)} 1
|
||||||
|
test_bool types2-5.3 {} {'10' IN ('10.0', 20)} 1
|
||||||
|
test_bool types2-5.4 {} {10 IN (10.0, 20)} 1
|
||||||
|
test_bool types2-5.5 {} {'10.0' IN (10, 20)} 1
|
||||||
|
|
||||||
|
# Compare literals against a column with TEXT affinity
|
||||||
|
test_bool types2-5.6 {t1='10.0'} {t1 IN (10.0, 20)} 1
|
||||||
|
test_bool types2-5.7 {t1='10.0'} {t1 IN (10, 20)} 0
|
||||||
|
test_bool types2-5.8 {t1='10'} {t1 IN (10.0, 20)} 0
|
||||||
|
test_bool types2-5.9 {t1='10'} {t1 IN (20, '10.0')} 0
|
||||||
|
test_bool types2-5.10 {t1=10} {t1 IN (20, '10')} 1
|
||||||
|
|
||||||
|
# Compare literals against a column with NUMERIC affinity
|
||||||
|
test_bool types2-5.11 {n1='10.0'} {n1 IN (10.0, 20)} 1
|
||||||
|
test_bool types2-5.12 {n1='10.0'} {n1 IN (10, 20)} 1
|
||||||
|
test_bool types2-5.13 {n1='10'} {n1 IN (10.0, 20)} 1
|
||||||
|
test_bool types2-5.14 {n1='10'} {n1 IN (20, '10.0')} 1
|
||||||
|
test_bool types2-5.15 {n1=10} {n1 IN (20, '10')} 1
|
||||||
|
|
||||||
|
# Compare literals against a column with affinity NONE
|
||||||
|
test_bool types2-5.16 {o1='10.0'} {o1 IN (10.0, 20)} 0
|
||||||
|
test_bool types2-5.17 {o1='10.0'} {o1 IN (10, 20)} 0
|
||||||
|
test_bool types2-5.18 {o1='10'} {o1 IN (10.0, 20)} 0
|
||||||
|
test_bool types2-5.19 {o1='10'} {o1 IN (20, '10.0')} 0
|
||||||
|
test_bool types2-5.20 {o1=10} {o1 IN (20, '10')} 0
|
||||||
|
test_bool types2-5.21 {o1='10.0'} {o1 IN (10, 20, '10.0')} 1
|
||||||
|
test_bool types2-5.22 {o1='10'} {o1 IN (10.0, 20, '10')} 1
|
||||||
|
test_bool types2-5.23 {o1=10} {n1 IN (20, '10', 10)} 1
|
||||||
|
|
||||||
|
# Tests named types2-6.* use the same infrastructure as the types2-2.*
|
||||||
|
# tests. The contents of the vals array is repeated here for easy
|
||||||
|
# reference.
|
||||||
|
#
|
||||||
|
# set vals [list 10 10.0 '10' '10.0' 20 20.0 '20' '20.0' 30 30.0 '30' '30.0']
|
||||||
|
# 1 2 3 4 5 6 7 8 9 10 11 12
|
||||||
|
|
||||||
|
test_boolset types2-6.1 {o IN ('10', 30)} {3 9 10}
|
||||||
|
test_boolset types2-6.2 {o IN (20.0, 30.0)} {5 6 9 10}
|
||||||
|
test_boolset types2-6.3 {t IN ('10', 30)} {1 3 9 11}
|
||||||
|
test_boolset types2-6.4 {t IN (20.0, 30.0)} {6 8 10 12}
|
||||||
|
test_boolset types2-6.5 {n IN ('10', 30)} {1 2 3 4 9 10 11 12}
|
||||||
|
test_boolset types2-6.6 {n IN (20.0, 30.0)} {5 6 7 8 9 10 11 12}
|
||||||
|
test_boolset types2-6.7 {i IN ('10', 30)} {1 2 3 4 9 10 11 12}
|
||||||
|
test_boolset types2-6.8 {i IN (20.0, 30.0)} {5 6 7 8 9 10 11 12}
|
||||||
|
|
||||||
|
# Also test than IN(x, y, z) works on a rowid:
|
||||||
|
test_boolset types2-6.9 {rowid IN (1, 6, 10)} {1 6 10}
|
||||||
|
|
||||||
|
# Tests types2-7.* concentrate on expressions of the form
|
||||||
|
# "x IN (SELECT...)" with no index.
|
||||||
|
execsql {
|
||||||
|
CREATE TABLE t3(i INTEGER, n NUMERIC, t TEXT, o);
|
||||||
|
INSERT INTO t3 VALUES(1, 1, 1, 1);
|
||||||
|
INSERT INTO t3 VALUES(2, 2, 2, 2);
|
||||||
|
INSERT INTO t3 VALUES(3, 3, 3, 3);
|
||||||
|
INSERT INTO t3 VALUES('1', '1', '1', '1');
|
||||||
|
INSERT INTO t3 VALUES('1.0', '1.0', '1.0', '1.0');
|
||||||
|
}
|
||||||
|
|
||||||
|
test_bool types2-7.1 {i1=1} {i1 IN (SELECT i FROM t3)} 1
|
||||||
|
test_bool types2-7.2 {i1='2.0'} {i1 IN (SELECT i FROM t3)} 1
|
||||||
|
test_bool types2-7.3 {i1='2.0'} {i1 IN (SELECT n FROM t3)} 1
|
||||||
|
test_bool types2-7.4 {i1='2.0'} {i1 IN (SELECT t FROM t3)} 1
|
||||||
|
test_bool types2-7.5 {i1='2.0'} {i1 IN (SELECT o FROM t3)} 1
|
||||||
|
|
||||||
|
test_bool types2-7.6 {n1=1} {n1 IN (SELECT n FROM t3)} 1
|
||||||
|
test_bool types2-7.7 {n1='2.0'} {n1 IN (SELECT i FROM t3)} 1
|
||||||
|
test_bool types2-7.8 {n1='2.0'} {n1 IN (SELECT n FROM t3)} 1
|
||||||
|
test_bool types2-7.9 {n1='2.0'} {n1 IN (SELECT t FROM t3)} 1
|
||||||
|
test_bool types2-7.10 {n1='2.0'} {n1 IN (SELECT o FROM t3)} 1
|
||||||
|
|
||||||
|
test_bool types2-7.6 {t1=1} {t1 IN (SELECT t FROM t3)} 1
|
||||||
|
test_bool types2-7.7 {t1='2.0'} {t1 IN (SELECT t FROM t3)} 0
|
||||||
|
test_bool types2-7.8 {t1='2.0'} {t1 IN (SELECT n FROM t3)} 1
|
||||||
|
test_bool types2-7.9 {t1='2.0'} {t1 IN (SELECT i FROM t3)} 1
|
||||||
|
test_bool types2-7.10 {t1='2.0'} {t1 IN (SELECT o FROM t3)} 0
|
||||||
|
test_bool types2-7.11 {t1='1.0'} {t1 IN (SELECT t FROM t3)} 1
|
||||||
|
test_bool types2-7.12 {t1='1.0'} {t1 IN (SELECT o FROM t3)} 1
|
||||||
|
|
||||||
|
test_bool types2-7.13 {o1=2} {o1 IN (SELECT o FROM t3)} 1
|
||||||
|
test_bool types2-7.14 {o1='2'} {o1 IN (SELECT o FROM t3)} 0
|
||||||
|
test_bool types2-7.15 {o1='2'} {o1 IN (SELECT o||'' FROM t3)} 1
|
||||||
|
|
||||||
|
# set vals [list 10 10.0 '10' '10.0' 20 20.0 '20' '20.0' 30 30.0 '30' '30.0']
|
||||||
|
# 1 2 3 4 5 6 7 8 9 10 11 12
|
||||||
|
execsql {
|
||||||
|
CREATE TABLE t4(i INTEGER, n NUMERIC, t TEXT, o);
|
||||||
|
INSERT INTO t4 VALUES(10, 20, 20, 30);
|
||||||
|
}
|
||||||
|
test_boolset types2-8.1 {i IN (SELECT i FROM t4)} {1 2 3 4}
|
||||||
|
test_boolset types2-8.2 {n IN (SELECT i FROM t4)} {1 2 3 4}
|
||||||
|
test_boolset types2-8.3 {t IN (SELECT i FROM t4)} {1 2 3 4}
|
||||||
|
test_boolset types2-8.4 {o IN (SELECT i FROM t4)} {1 2 3 4}
|
||||||
|
test_boolset types2-8.5 {i IN (SELECT t FROM t4)} {5 6 7 8}
|
||||||
|
test_boolset types2-8.6 {n IN (SELECT t FROM t4)} {5 6 7 8}
|
||||||
|
test_boolset types2-8.7 {t IN (SELECT t FROM t4)} {5 7}
|
||||||
|
test_boolset types2-8.8 {o IN (SELECT t FROM t4)} {7}
|
||||||
|
test_boolset types2-8.9 {i IN (SELECT o FROM t4)} {9 10 11 12}
|
||||||
|
test_boolset types2-8.6 {n IN (SELECT o FROM t4)} {9 10 11 12}
|
||||||
|
test_boolset types2-8.7 {t IN (SELECT o FROM t4)} {9 11}
|
||||||
|
test_boolset types2-8.8 {o IN (SELECT o FROM t4)} {9 10}
|
||||||
|
|
||||||
finish_test
|
finish_test
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user