From: drh Date: Sun, 29 Aug 2004 16:25:03 +0000 (+0000) Subject: Corrections to transient table handling in compound select statments. X-Git-Tag: version-3.6.10~4234 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=8cdbf83690848730994287c845a41284e1fb4225;p=thirdparty%2Fsqlite.git Corrections to transient table handling in compound select statments. Tickets #826 and #875. (CVS 1912) FossilOrigin-Name: 9cc765be4611a248cfcce1243fd1bbeaf5202968 --- diff --git a/manifest b/manifest index ab7fa379dd..b6c5ca1d30 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Progress\stoward\sfixing\siproblems\swith\scompound\sselects.\s(CVS\s1911) -D 2004-08-29T01:31:05 +C Corrections\sto\stransient\stable\shandling\sin\scompound\sselect\sstatments.\nTickets\s#826\sand\s#875.\s(CVS\s1912) +D 2004-08-29T16:25:04 F Makefile.in 65a7c43fcaf9a710d62f120b11b6e435eeb4a450 F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd @@ -58,7 +58,7 @@ F src/parse.y 581a2ce014b843506805b2470c02b7865ad034d5 F src/pragma.c a7cea75286fcff6666a5412b04478fcf0ecef5c4 F src/printf.c 17b28a1eedfe8129b05de981719306c18c3f1327 F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3 -F src/select.c 5fa9db32e24f4c0f0ead43cfa59a6cfc3a452a15 +F src/select.c 400b2dcc8e05c0101a65a370f7ebb33c9c85f0b3 F src/shell.c 42f65424a948f197f389e13bc7aaa3cf24dafd0c F src/sqlite.h.in d619f3dd276845c2ff3fbeaed1d037563fc419f0 F src/sqliteInt.h c7ed161ecc40f9fd0f080fbcc00e34bd7d6735ee @@ -162,6 +162,7 @@ F test/select3.test 9de435aa84fc406708cd8dc1b1d60e7f27cea685 F test/select4.test 86e72fc3b07de4fe11439aa419e37db3c49467e2 F test/select5.test 94db800bbeff2e426c0175e07f7a71d4617853b5 F test/select6.test 7a4c572ada0c2f969cecacd76f1f5c1533a22bbb +F test/select7.test c71c822a82c80bbd55558b4b69d35442dfe22ffd F test/sort.test 35e9d6bd6930969050606c8feb9c6745469720e3 F test/subselect.test 50f98723f00e97b1839d36410ee63597ca82d775 F test/table.test fd9a0f4992230e4ca89cd37ae3191a12750df1d0 @@ -244,7 +245,7 @@ F www/tclsqlite.tcl 560ecd6a916b320e59f2917317398f3d59b7cc25 F www/vdbe.tcl 59288db1ac5c0616296b26dce071c36cb611dfe9 F www/version3.tcl 092a01f5ef430d2c4acc0ae558d74c4bb89638a0 F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4 -P d50c47b4995bd9b58e1293aa6513361cffc6babe -R e1fb8ddf0dd95f67094014c0c3248f2f +P 307478593d5d96b79386da222c7742ea2eaa5467 +R dce15d87c754e08c36b4d1c93058acb6 U drh -Z 1e45c8abb4ae3be9c92dd0026a2f0205 +Z c4c7da99c7cb81b57cec03f3f74114d2 diff --git a/manifest.uuid b/manifest.uuid index bcecb81456..7dafc57062 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -307478593d5d96b79386da222c7742ea2eaa5467 \ No newline at end of file +9cc765be4611a248cfcce1243fd1bbeaf5202968 \ No newline at end of file diff --git a/src/select.c b/src/select.c index 8cf658b7f1..565fd9038d 100644 --- a/src/select.c +++ b/src/select.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** -** $Id: select.c,v 1.204 2004/08/29 01:31:05 drh Exp $ +** $Id: select.c,v 1.205 2004/08/29 16:25:04 drh Exp $ */ #include "sqliteInt.h" @@ -1280,30 +1280,11 @@ static int openTempIndex(Parse *pParse, Select *p, int iTab, int keyAsData){ } /* -** FIX ME: -** + Omit the ppOpenTemp parameter from multiSelectOpenTempAddr(). -** + Attach pOpenList to the right-most term always. -** + Make sure Select.ppOpenTemp is initialized to NULL +** Add the address "addr" to the set of all OpenTemp opcode addresses +** that are being accumulated in p->ppOpenTemp. */ - -/* -** Add the address "addr" to the set of all opcode addresses contained -** in the pOpenTemp list for the whole compound select. If no pOpenTemp -** list has been created yet, then create a new one and make *ppOpenTemp -** point to it. If the pOpenTemp list already exists, leave *ppOpenTemp -** unchanged and just add the new address to the existing list. -*/ -static int multiSelectOpenTempAddr(Select *p, int addr, IdList **ppOpenTemp){ - IdList *pList; - if( !p->ppOpenTemp ){ - /* Create a new list */ - *ppOpenTemp = sqlite3IdListAppend(0, 0); - p->ppOpenTemp = ppOpenTemp; - }else{ - /* Add a new element onto the end of the existing list */ - *p->ppOpenTemp = sqlite3IdListAppend(*p->ppOpenTemp, 0); - } - pList = *p->ppOpenTemp; +static int multiSelectOpenTempAddr(Select *p, int addr){ + IdList *pList = *p->ppOpenTemp = sqlite3IdListAppend(*p->ppOpenTemp, 0); if( pList==0 ){ return SQLITE_NOMEM; } @@ -1373,6 +1354,9 @@ static int multiSelect( Select *pPrior; /* Another SELECT immediately to our left */ Vdbe *v; /* Generate code to this VDBE */ IdList *pOpenTemp = 0;/* OP_OpenTemp opcodes that need a KeyInfo */ + int aAddr[5]; /* Addresses of SetNumColumns operators */ + int nAddr = 0; /* Number used */ + int nCol; /* Number of columns in the result set */ /* Make sure there is no ORDER BY or LIMIT clause on prior SELECTs. Only ** the last (right-most) SELECT in the series may have an ORDER BY or LIMIT. @@ -1403,7 +1387,11 @@ static int multiSelect( goto multi_select_end; } - /* PART OF FIX: + /* If *p this is the right-most select statement, then initialize + ** p->ppOpenTemp to point to pOpenTemp. If *p is not the right most + ** statement then p->ppOpenTemp will have already been initialized + ** by a prior call to this same procedure. Pass along the pOpenTemp + ** pointer to pPrior, the next statement to our left. */ if( p->ppOpenTemp==0 ){ p->ppOpenTemp = &pOpenTemp; @@ -1415,15 +1403,8 @@ static int multiSelect( if( eDest==SRT_TempTable ){ assert( p->pEList ); sqlite3VdbeAddOp(v, OP_OpenTemp, iParm, 0); - - /* FIX ME: - ** p->pEList->nExpr might contain a "*" and so might not be the - ** correct number. Go ahead and code the SetNumColumns instruction - ** here, but also record its address. Change the P2 value of the - ** instruction to the number of columns after sqlite3Select() has - ** been called to code the subquery and has modified pEList->nExpr - ** to be the correct value. */ - sqlite3VdbeAddOp(v, OP_SetNumColumns, iParm, p->pEList->nExpr); + assert( nAddr==0 ); + aAddr[nAddr++] = sqlite3VdbeAddOp(v, OP_SetNumColumns, iParm, 0); eDest = SRT_Table; } @@ -1434,7 +1415,6 @@ static int multiSelect( if( p->pOrderBy==0 ){ pPrior->nLimit = p->nLimit; pPrior->nOffset = p->nOffset; - /* pPrior->ppOpenTemp = p->ppOpenTemp; // FIX */ rc = sqlite3Select(pParse, pPrior, eDest, iParm, 0, 0, 0, aff); if( rc ){ goto multi_select_end; @@ -1480,25 +1460,23 @@ static int multiSelect( } addr = sqlite3VdbeAddOp(v, OP_OpenTemp, unionTab, 0); if( p->op!=TK_ALL ){ - rc = multiSelectOpenTempAddr(p, addr, &pOpenTemp); + rc = multiSelectOpenTempAddr(p, addr); if( rc!=SQLITE_OK ){ goto multi_select_end; } sqlite3VdbeAddOp(v, OP_KeyAsData, unionTab, 1); } + assert( nAddrpEList ); } /* Code the SELECT statements to our left */ - /* pPrior->ppOpenTemp = p->ppOpenTemp; // FIX */ rc = sqlite3Select(pParse, pPrior, priorOp, unionTab, 0, 0, 0, aff); if( rc ){ goto multi_select_end; } - if( p->op==TK_ALL ){ - sqlite3VdbeAddOp(v, OP_SetNumColumns, unionTab, pPrior->pEList->nExpr); - } /* Code the current SELECT statement */ @@ -1570,16 +1548,17 @@ static int multiSelect( } addr = sqlite3VdbeAddOp(v, OP_OpenTemp, tab1, 0); - rc = multiSelectOpenTempAddr(p, addr, &pOpenTemp); + rc = multiSelectOpenTempAddr(p, addr); if( rc!=SQLITE_OK ){ goto multi_select_end; } sqlite3VdbeAddOp(v, OP_KeyAsData, tab1, 1); + assert( nAddrpEList ); /* Code the SELECTs to our left into temporary table "tab1". */ - /* pPrior->ppOpenTemp = p->ppOpenTemp; // FIX */ rc = sqlite3Select(pParse, pPrior, SRT_Union, tab1, 0, 0, 0, aff); if( rc ){ goto multi_select_end; @@ -1588,11 +1567,13 @@ static int multiSelect( /* Code the current SELECT into temporary table "tab2" */ addr = sqlite3VdbeAddOp(v, OP_OpenTemp, tab2, 0); - rc = multiSelectOpenTempAddr(p, addr, &pOpenTemp); + rc = multiSelectOpenTempAddr(p, addr); if( rc!=SQLITE_OK ){ goto multi_select_end; } sqlite3VdbeAddOp(v, OP_KeyAsData, tab2, 1); + assert( nAddrpPrior = 0; nLimit = p->nLimit; p->nLimit = -1; @@ -1634,6 +1615,10 @@ static int multiSelect( break; } } + + /* Make sure all SELECTs in the statement have the same number of elements + ** in their result sets. + */ assert( p->pEList && pPrior->pEList ); if( p->pEList->nExpr!=pPrior->pEList->nExpr ){ sqlite3ErrorMsg(pParse, "SELECTs to the left and right of %s" @@ -1642,16 +1627,29 @@ static int multiSelect( goto multi_select_end; } + /* Set the number of columns in temporary tables + */ + nCol = p->pEList->nExpr; + while( nAddr>0 ){ + nAddr--; + sqlite3VdbeChangeP2(v, aAddr[nAddr], nCol); + } + /* Compute collating sequences used by either the ORDER BY clause or ** by any temporary tables needed to implement the compound select. ** Attach the KeyInfo structure to all temporary tables. Invoke the ** ORDER BY processing if there is an ORDER BY clause. + ** + ** This section is run by the right-most SELECT statement only. + ** SELECT statements to the left always skip this part. The right-most + ** SELECT might also skip this part if it has no ORDER BY clause and + ** no temp tables are required. */ if( p->pOrderBy || (pOpenTemp && pOpenTemp->nId>0) ){ - int nCol = p->pEList->nExpr; /* Number of columns in the result set */ int i; /* Loop counter */ KeyInfo *pKeyInfo; /* Collating sequence for the result set */ + assert( p->ppOpenTemp == &pOpenTemp ); pKeyInfo = sqliteMalloc(sizeof(*pKeyInfo)+nCol*sizeof(CollSeq*)); if( !pKeyInfo ){ rc = SQLITE_NOMEM; @@ -2369,21 +2367,6 @@ int sqlite3Select( generateColumnNames(pParse, pTabList, pEList); } - /* If the destination is SRT_Union, then set the number of columns in - ** the records that will be inserted into the temporary table. The caller - ** couldn't do this, in case the select statement is of the form - ** "SELECT * FROM ....". - ** - ** We need to do this before we start inserting records into the - ** temporary table (which has had OP_KeyAsData executed on it), because - ** it is required by the key comparison function. So do it now, even - ** though this means that OP_SetNumColumns may be executed on the same - ** cursor more than once. - */ - if( eDest==SRT_Union ){ - sqlite3VdbeAddOp(v, OP_SetNumColumns, iParm, pEList->nExpr); - } - /* Generate code for all sub-queries in the FROM clause */ for(i=0; inSrc; i++){ diff --git a/test/select7.test b/test/select7.test new file mode 100644 index 0000000000..ae91b1b8e8 --- /dev/null +++ b/test/select7.test @@ -0,0 +1,50 @@ +# 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 compute SELECT statements and nested +# views. +# +# $Id: select7.test,v 1.1 2004/08/29 16:25:04 drh Exp $ + + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +# A 3-way INTERSECT. Ticket #875 +do_test select7-1.1 { + execsql { + create temp table t1(x); + insert into t1 values('amx'); + insert into t1 values('anx'); + insert into t1 values('amy'); + insert into t1 values('bmy'); + select * from t1 where x like 'a__' + intersect select * from t1 where x like '_m_' + intersect select * from t1 where x like '__x'; + } +} {amx} + + +# Nested views do not handle * properly. Ticket #826. +# +do_test select7-2.1 { + execsql { + CREATE TABLE x(id integer primary key, a TEXT NULL); + INSERT INTO x (a) VALUES ('first'); + CREATE TABLE tempx(id integer primary key, a TEXT NULL); + INSERT INTO tempx (a) VALUES ('t-first'); + CREATE VIEW tv1 AS SELECT x.id, tx.id FROM x JOIN tempx tx ON tx.id=x.id; + CREATE VIEW tv1b AS SELECT x.id, tx.id FROM x JOIN tempx tx on tx.id=x.id; + CREATE VIEW tv2 AS SELECT * FROM tv1 UNION SELECT * FROM tv1b; + SELECT * FROM tv2; + } +} {1 1} + + +finish_test