Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Allow the IN operator to take a list of arbitrary expressions on its right-hand side. The expressions no longer need to be constant. The current implementation seems to work but needs more testing and optimization. (CVS 2542) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
ba56478dd8bc2135749966ff55831fd4 |
User & Date: | drh 2005-07-08 18:25:26.000 |
Context
2005-07-09
| ||
02:16 | Make sure there is only one busy counter. Ticket #1315. (CVS 2543) (check-in: af2a0ba4a3 user: drh tags: trunk) | |
2005-07-08
| ||
18:25 | Allow the IN operator to take a list of arbitrary expressions on its right-hand side. The expressions no longer need to be constant. The current implementation seems to work but needs more testing and optimization. (CVS 2542) (check-in: ba56478dd8 user: drh tags: trunk) | |
17:13 | Change the name of the OpenTemp opcode to OpenVirtual which is more descriptive of what it does. (CVS 2541) (check-in: 3bb9ce5f20 user: drh tags: trunk) | |
Changes
Changes to src/expr.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. ** ** $Id: expr.c,v 1.211 2005/07/08 18:25:26 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> /* ** Return the 'affinity' of the expression pExpr if any. ** |
︙ | ︙ | |||
1234 1235 1236 1237 1238 1239 1240 | ** ** The first form is handled by creating a set holding the list ** of allowed values. The second form causes the SELECT to generate ** a temporary table. */ #ifndef SQLITE_OMIT_SUBQUERY void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){ | | > > > | > | < > > > < | > | | 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 | ** ** The first form is handled by creating a set holding the list ** of allowed values. The second form causes the SELECT to generate ** a temporary table. */ #ifndef SQLITE_OMIT_SUBQUERY void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){ int testAddr = 0; /* One-time test address */ Vdbe *v = sqlite3GetVdbe(pParse); if( v==0 ) return; /* This code must be run in its entirety every time it is encountered ** if any of the following is true: ** ** * The right-hand side is a correlated subquery ** * The right-hand side is an expression list containing variables ** * We are inside a trigger ** ** If all of the above are false, then we can run this code just once ** save the results, and reuse the same result on subsequent invocations. */ if( !ExprHasAnyProperty(pExpr, EP_VarSelect) && !pParse->trigStack ){ int mem = pParse->nMem++; sqlite3VdbeAddOp(v, OP_MemLoad, mem, 0); testAddr = sqlite3VdbeAddOp(v, OP_If, 0, 0); assert( testAddr>0 ); sqlite3VdbeAddOp(v, OP_Integer, 1, 0); sqlite3VdbeAddOp(v, OP_MemStore, mem, 1); } if( pExpr->pSelect ){ sqlite3VdbeAddOp(v, OP_AggContextPush, 0, 0); } switch( pExpr->op ){ case TK_IN: { char affinity; KeyInfo keyInfo; int addr; /* Address of OP_OpenVirtual instruction */ affinity = sqlite3ExprAffinity(pExpr->pLeft); /* Whether this is an 'x IN(SELECT...)' or an 'x IN(<exprlist>)' ** expression it is handled the same way. A virtual 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 |
︙ | ︙ | |||
1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 | ** ** For each expression, build an index key from the evaluation and ** 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; if( !affinity ){ affinity = SQLITE_AFF_NUMERIC; } keyInfo.aColl[0] = pExpr->pLeft->pColl; /* Loop through each expression in <exprlist>. */ | > > > | | | > > > > | | < | > > > > | 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 | ** ** For each expression, build an index key from the evaluation and ** 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; ExprList *pList = pExpr->pList; struct ExprList_item *pItem; if( !affinity ){ affinity = SQLITE_AFF_NUMERIC; } keyInfo.aColl[0] = pExpr->pLeft->pColl; /* Loop through each expression in <exprlist>. */ for(i=pList->nExpr, pItem=pList->a; i>0; i--, pItem++){ Expr *pE2 = pItem->pExpr; /* If the expression is not constant then we will need to ** disable the test that was generated above that makes sure ** this code only executes once. Because for a non-constant ** expression we need to rerun this code each time. */ if( testAddr>=0 && !sqlite3ExprIsConstant(pE2) ){ VdbeOp *aOp = sqlite3VdbeGetOp(v, testAddr-1); int i; for(i=0; i<4; i++){ aOp[i].opcode = OP_Noop; } testAddr = 0; } /* Evaluate the expression and insert it into the temp table */ sqlite3ExprCode(pParse, pE2); sqlite3VdbeOp3(v, OP_MakeRecord, 1, 0, &affinity, 1); sqlite3VdbeAddOp(v, OP_IdxInsert, pExpr->iTable, 0); } |
︙ | ︙ | |||
1360 1361 1362 1363 1364 1365 1366 | break; } } if( pExpr->pSelect ){ sqlite3VdbeAddOp(v, OP_AggContextPop, 0, 0); } | | | | 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 | break; } } if( pExpr->pSelect ){ sqlite3VdbeAddOp(v, OP_AggContextPop, 0, 0); } if( testAddr ){ sqlite3VdbeChangeP2(v, testAddr, sqlite3VdbeCurrentAddr(v)); } return; } #endif /* SQLITE_OMIT_SUBQUERY */ /* ** Generate an instruction that will put the integer describe by |
︙ | ︙ |
Changes to test/in.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 2001 September 15 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the IN and BETWEEN operator. # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # 2001 September 15 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the IN and BETWEEN operator. # # $Id: in.test,v 1.14 2005/07/08 18:25:26 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Generate the test data we will need for the first squences of tests. # do_test in-1.0 { |
︙ | ︙ | |||
77 78 79 80 81 82 83 | execsql {SELECT a FROM t1 WHERE b NOT IN (8,12,16,24,32) OR b=512 ORDER BY a} } {1 2 6 7 8 9 10} do_test in-2.5 { execsql {SELECT a+100*(b IN (8,16,24)) FROM t1 ORDER BY b} } {1 2 103 104 5 6 7 8 9 10} do_test in-2.6 { | | | < | < < > | | < | | < | 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | execsql {SELECT a FROM t1 WHERE b NOT IN (8,12,16,24,32) OR b=512 ORDER BY a} } {1 2 6 7 8 9 10} do_test in-2.5 { execsql {SELECT a+100*(b IN (8,16,24)) FROM t1 ORDER BY b} } {1 2 103 104 5 6 7 8 9 10} do_test in-2.6 { execsql {SELECT a FROM t1 WHERE b IN (b+8,64)} } {6} do_test in-2.7 { execsql {SELECT a FROM t1 WHERE b IN (max(5,10,b),20)} } {4 5 6 7 8 9 10} do_test in-2.8 { execsql {SELECT a FROM t1 WHERE b IN (8*2,64/2) ORDER BY b} } {4 5} do_test in-2.9 { execsql {SELECT a FROM t1 WHERE b IN (max(5,10),20)} } {} do_test in-2.10 { execsql {SELECT a FROM t1 WHERE min(0,b IN (a,30))} } {} do_test in-2.11 { set v [catch {execsql {SELECT a FROM t1 WHERE c IN (10,20)}} msg] lappend v $msg } {1 {no such column: c}} # Testing the IN operator where the right-hand side is a SELECT # |
︙ | ︙ |