From: drh Date: Sat, 25 Dec 2004 01:03:13 +0000 (+0000) Subject: Fix ticket #1046 by removing code and simplifying the query optimizer. X-Git-Tag: version-3.6.10~3980 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=e6f85e71e92e4eb97f328d450402e5defd6e0f08;p=thirdparty%2Fsqlite.git Fix ticket #1046 by removing code and simplifying the query optimizer. Remarkably, this simplification also makes the optimizer do a better job. Ticket #1051 was fixed as a side-effect. (CVS 2172) FossilOrigin-Name: 5fd1f4711885e3dd6fb2c2700287f78bb0ea178a --- diff --git a/manifest b/manifest index 1effda3b28..07e2fb3c46 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sPRAGMA\s'temp_store_directory'.\s\sAdded\sos_*.c\sfunction\nsqlite3OsIsDirWritable(),\ssplit\spragma.c\schangeTempStorage()\sfunction\sinto\ninvalidateTempStorage().\s(CVS\s2171) -D 2004-12-20T19:01:32 +C Fix\sticket\s#1046\sby\sremoving\scode\sand\ssimplifying\sthe\squery\soptimizer.\nRemarkably,\sthis\ssimplification\salso\smakes\sthe\soptimizer\sdo\sa\sbetter\sjob.\nTicket\s#1051\swas\sfixed\sas\sa\sside-effect.\s(CVS\s2172) +D 2004-12-25T01:03:14 F Makefile.in 02a184d734a2b4bbbc1ecc2e3ef504fcb13de069 F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457 F README a01693e454a00cc117967e3f9fdab2d4d52e9bc1 @@ -34,7 +34,7 @@ F src/btree.h 861e40b759a195ba63819740e484390012cf81ab F src/build.c af1296e8a21a406b4f4c4f1e1365e075071219f3 F src/cursor.c f883813759742068890b1f699335872bfa8fdf41 F src/date.c 65536e7ea04fdde6e0551264fca15966966e171f -F src/delete.c 6debe7893fa09bb5b386df0f26165f13132423e6 +F src/delete.c 5e5bcf0092b146a399e571d1e704b3b22633d2d0 F src/expr.c d718509e56f58b06bc5f9b46afb295675334d544 F src/func.c b668e5ad043176049454c95a6a780367a0e8f6bb F src/hash.c a97721a55440b7bea31ffe471bb2f6b4123cddd5 @@ -56,13 +56,13 @@ F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b F src/pager.c 7b4dc9a94228efde924f1d9f4b7751f332da4587 F src/pager.h 9eba8c53dd91eae7f3f90743b2ee242da02a9862 F src/parse.y ceba179b9703657180963568f54b0e75f33e36e1 -F src/pragma.c 639a7e7ef0999211aafa1f3d474ecc7241033cb9 +F src/pragma.c 0394f9361a497b7f74c1e5909bfc95a1f5bf0ce4 F src/printf.c 3d20b21cfecadacecac3fb7274e746cb81d3d357 F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3 -F src/select.c ac6610b4b2c5bd5ffc46536b760dacc420119dac +F src/select.c 080c0d1d684ff6154a2f042347f34bc07e50590c F src/shell.c e8f4f486cbf6e60d81173146ac8a6522c930fa51 F src/sqlite.h.in 0d5e48e506845b74a845c9470e01d3f472b59611 -F src/sqliteInt.h a922cfd13711c68538684619fb15a4d262b12b9d +F src/sqliteInt.h ef924e4a1a4b69d68f01af3242ab080de6069131 F src/table.c 25b3ff2b39b7d87e8d4a5da0713d68dfc06cbee9 F src/tclsqlite.c 3a4044ef609565c8cc51e887d8b96933ba9f3b5c F src/test1.c b7d94c54e58f95452387a5cabdf98b2be8059f29 @@ -72,17 +72,17 @@ F src/test4.c 7c6b9fc33dd1f3f93c7f1ee6e5e6d016afa6c1df F src/test5.c 64f08b2a50ef371a1bd68ff206829e7b1b9997f5 F src/tokenize.c 2ad3d1ae1a0a70746db0b31a0a74f58050a3c39a F src/trigger.c 98f3b07c08ba01b34cff139ef9687883d325ae8e -F src/update.c aa92fa2203b2233008dd75a1e97c4b441be24a7f +F src/update.c 0979397c41ac29c54fe0cc687a356d8629a633af F src/utf.c e45ce11be6922408cd381561721f6cca7d3b992a -F src/util.c 4a8db4e97a3cfda12ad8dda3e77dd2d00ad1de5e +F src/util.c 29f43c4a7b9ff29302f7899f793be6836b6cd7f9 F src/vacuum.c 705256e1111521fa04f0029de7f1667bc131d015 -F src/vdbe.c caeb3f88d9a027d300c8fd27cf885ca964e5354e +F src/vdbe.c 40ab8e30eca1ed0e5d9e17b6d835660edf14c7c2 F src/vdbe.h 067ca8d6750ba4f69a50284765e5883dee860181 F src/vdbeInt.h 0f74561e629af86172de7cdf0ecaea014c51696c F src/vdbeapi.c 0cf3bdc1072616bedc8eec7fc22e3f5a169d33fd F src/vdbeaux.c a7c4c90786e2633b38f2d89f3dc49aed747454e4 F src/vdbemem.c 5876c8abf4374fef671f4fd8dc333ef3fc95a2f0 -F src/where.c e4a34a8fd159d5ca59f87bb689bb513f1a2620df +F src/where.c 5307677f772a7b44628e65383c30697dee9a63f3 F tclinstaller.tcl 36478c3bbfc5b93ceac42d94e3c736937b808432 F test/all.test 929bfa932b55e75c96fe2203f7650ba451c1862c F test/alter.test 95c57a4f461fa81293e0dccef7f83889aadb169a @@ -263,7 +263,7 @@ F www/tclsqlite.tcl e73f8f8e5f20e8277619433f7970060ab01088fc F www/vdbe.tcl 095f106d93875c94b47367384ebc870517431618 F www/version3.tcl 092a01f5ef430d2c4acc0ae558d74c4bb89638a0 F www/whentouse.tcl fdacb0ba2d39831e8a6240d05a490026ad4c4e4c -P e5aa489453bf31126da6473ef93c89ec27935cde -R 80852dba2ab3f55be612ddeeffa02604 -U tpoindex -Z 5d44d728827caef4bb2a5da252002b6d +P 772e22cbd69463be41c2e73b4fd4eb33946193c4 +R 1a0697c736404780d6feff68a7939368 +U drh +Z 1ae722789e543e8f74d632edf76f862b diff --git a/manifest.uuid b/manifest.uuid index a08b47c486..8e9d964100 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -772e22cbd69463be41c2e73b4fd4eb33946193c4 \ No newline at end of file +5fd1f4711885e3dd6fb2c2700287f78bb0ea178a \ No newline at end of file diff --git a/src/delete.c b/src/delete.c index 41dbca16dd..f786bdd78a 100644 --- a/src/delete.c +++ b/src/delete.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** in order to generate code for DELETE FROM statements. ** -** $Id: delete.c,v 1.93 2004/12/14 03:34:34 drh Exp $ +** $Id: delete.c,v 1.94 2004/12/25 01:03:14 drh Exp $ */ #include "sqliteInt.h" @@ -225,11 +225,12 @@ void sqlite3DeleteFrom( /* Begin the database scan */ - pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 1, 0, 0); + pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0); if( pWInfo==0 ) goto delete_from_cleanup; - /* Remember the key of every item to be deleted. + /* Remember the rowid of every item to be deleted. */ + sqlite3VdbeAddOp(v, OP_Recno, iCur, 0); sqlite3VdbeAddOp(v, OP_ListWrite, 0, 0); if( db->flags & SQLITE_CountRows ){ sqlite3VdbeAddOp(v, OP_AddImm, 1, 0); diff --git a/src/pragma.c b/src/pragma.c index 5589e9317d..51f7f43a20 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -11,7 +11,7 @@ ************************************************************************* ** This file contains code used to implement the PRAGMA command. ** -** $Id: pragma.c,v 1.80 2004/12/20 19:01:33 tpoindex Exp $ +** $Id: pragma.c,v 1.81 2004/12/25 01:03:14 drh Exp $ */ #include "sqliteInt.h" #include @@ -389,14 +389,14 @@ void sqlite3Pragma( if( sqlite3_temp_directory ){ if( strlen(sqlite3_temp_directory) < strlen(zRight) + 1){ sqlite3FreeX(sqlite3_temp_directory); - sqlite3_temp_directory = sqlite3Malloc( strlen(zRight) + 1 ); + sqlite3_temp_directory = sqliteMalloc( strlen(zRight) + 1 ); if( sqlite3_temp_directory==0 ){ goto pragma_out; } sqlite3_temp_directory[0] = '\0'; } }else{ - sqlite3_temp_directory = sqlite3Malloc( strlen(zRight) + 1 ); + sqlite3_temp_directory = sqliteMalloc( strlen(zRight) + 1 ); if( sqlite3_temp_directory==0 ){ goto pragma_out; } diff --git a/src/select.c b/src/select.c index a2a4d5e342..a889fc58eb 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.218 2004/12/16 21:09:17 drh Exp $ +** $Id: select.c,v 1.219 2004/12/25 01:03:14 drh Exp $ */ #include "sqliteInt.h" @@ -2549,7 +2549,7 @@ int sqlite3Select( /* Begin the database scan */ - pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, + pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pGroupBy ? 0 : &pOrderBy, p->pFetch); if( pWInfo==0 ) goto select_end; diff --git a/src/sqliteInt.h b/src/sqliteInt.h index fbfd184b70..35b1bad172 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.348 2004/12/19 00:11:35 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.349 2004/12/25 01:03:14 drh Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ @@ -1359,7 +1359,7 @@ void sqlite3OpenTableForReading(Vdbe*, int iCur, Table*); void sqlite3OpenTable(Vdbe*, int iCur, Table*, int); void sqlite3DeleteFrom(Parse*, SrcList*, Expr*); void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int); -WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, int, ExprList**, Fetch*); +WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, ExprList**, Fetch*); void sqlite3WhereEnd(WhereInfo*); void sqlite3ExprCode(Parse*, Expr*); void sqlite3ExprCodeAndCache(Parse*, Expr*); diff --git a/src/update.c b/src/update.c index 134b481551..d3929984e9 100644 --- a/src/update.c +++ b/src/update.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle UPDATE statements. ** -** $Id: update.c,v 1.99 2004/12/07 15:41:49 drh Exp $ +** $Id: update.c,v 1.100 2004/12/25 01:03:14 drh Exp $ */ #include "sqliteInt.h" @@ -227,11 +227,12 @@ void sqlite3Update( /* Begin the database scan */ - pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 1, 0, 0); + pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0); if( pWInfo==0 ) goto update_cleanup; /* Remember the index of every item to be updated. */ + sqlite3VdbeAddOp(v, OP_Recno, iCur, 0); sqlite3VdbeAddOp(v, OP_ListWrite, 0, 0); /* End the database scan loop. diff --git a/src/util.c b/src/util.c index 8994dfd611..55d792485f 100644 --- a/src/util.c +++ b/src/util.c @@ -14,7 +14,7 @@ ** This file contains functions for allocating memory, comparing ** strings, and stuff like that. ** -** $Id: util.c,v 1.122 2004/11/20 19:18:01 drh Exp $ +** $Id: util.c,v 1.123 2004/12/25 01:03:14 drh Exp $ */ #include "sqliteInt.h" #include @@ -872,6 +872,7 @@ int sqlite3GetVarint32(const unsigned char *p, u32 *v){ u32 x; int n; unsigned char c; +#if 0 if( ((c = p[0]) & 0x80)==0 ){ *v = c; return 1; @@ -882,6 +883,18 @@ int sqlite3GetVarint32(const unsigned char *p, u32 *v){ return 2; } x = (x<<7) | (c & 0x7f); +#else + if( ((signed char*)p)[0]>=0 ){ + *v = p[0]; + return 1; + } + x = p[0] & 0x7f; + if( ((signed char*)p)[1]>=0 ){ + *v = (x<<7) | p[1]; + return 2; + } + x = (x<<7) | (p[1] & 0x7f); +#endif n = 2; do{ x = (x<<7) | ((c = p[n++])&0x7f); diff --git a/src/vdbe.c b/src/vdbe.c index d38c5f11ad..711899e3da 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -43,7 +43,7 @@ ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** -** $Id: vdbe.c,v 1.434 2004/12/19 00:11:35 drh Exp $ +** $Id: vdbe.c,v 1.435 2004/12/25 01:03:14 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -641,6 +641,9 @@ case OP_Halt: { ** The integer value P1 is pushed onto the stack. If P3 is not zero ** then it is assumed to be a string representation of the same integer. ** If P1 is zero and P3 is not zero, then the value is derived from P3. +** +** If the value cannot be represented as a 32-bits then its value +** will be in P3. */ case OP_Integer: { pTos++; @@ -1100,7 +1103,7 @@ divide_by_zero: ** P3 is a pointer to a CollSeq struct. If the next call to a user function ** or aggregate calls sqlite3GetFuncCollSeq(), this collation sequence will ** be returned. This is used by the built-in min(), max() and nullif() -** built-in functions. +** functions. ** ** The interface used by the implementation of the aforementioned functions ** to retrieve the collation sequence set by this opcode is not available diff --git a/src/where.c b/src/where.c index e1998624fa..d8c8aecdd7 100644 --- a/src/where.c +++ b/src/where.c @@ -16,7 +16,7 @@ ** so is applicable. Because this module is responsible for selecting ** indices, you might also think of this module as the "query optimizer". ** -** $Id: where.c,v 1.123 2004/12/19 00:11:35 drh Exp $ +** $Id: where.c,v 1.124 2004/12/25 01:03:14 drh Exp $ */ #include "sqliteInt.h" @@ -525,6 +525,11 @@ static void codeEqualityTerm( ** And so forth. This routine generates code to open those VDBE cursors ** and sqlite3WhereEnd() generates the code to close them. ** +** The code that sqlite3WhereBegin() generates leaves the cursors named +** in pTabList pointing at their appropriate entries. The [...] code +** can use OP_Column and OP_Recno opcodes on these cursors to extra +** data from the various tables of the loop. +** ** If the WHERE clause is empty, the foreach loops must each scan their ** entire tables. Thus a three-way join is an O(N^3) operation. But if ** the tables have indices and there are terms in the WHERE clause that @@ -575,7 +580,6 @@ WhereInfo *sqlite3WhereBegin( Parse *pParse, /* The parser context */ SrcList *pTabList, /* A list of all tables to be scanned */ Expr *pWhere, /* The WHERE clause */ - int pushKey, /* If TRUE, leave the table key on the stack */ ExprList **ppOrderBy, /* An ORDER BY clause, or NULL */ Fetch *pFetch /* Initial location of cursors. NULL otherwise */ ){ @@ -585,7 +589,6 @@ WhereInfo *sqlite3WhereBegin( int brk, cont = 0; /* Addresses used during code generation */ int nExpr; /* Number of subexpressions in the WHERE clause */ Bitmask loopMask; /* One bit set for each outer loop */ - int haveRowid = 0; /* True if the ROWID is on the stack */ ExprInfo *pTerm; /* A single term in the WHERE clause; ptr to aExpr[] */ ExprMaskSet maskSet; /* The expression mask set */ int iDirectEq[BMS]; /* Term of the form ROWID==X for the N-th table */ @@ -595,11 +598,6 @@ WhereInfo *sqlite3WhereBegin( struct SrcList_item *pTabItem; /* A single entry from pTabList */ WhereLevel *pLevel; /* A single level in the pWInfo list */ - /* pushKey is only allowed if there is a single table (as in an INSERT or - ** UPDATE statement) - */ - assert( pushKey==0 || pTabList->nSrc==1 ); - /* Split the WHERE clause into separate subexpressions where each ** subexpression is separated by an AND operator. If the aExpr[] ** array fills up, the last entry might point to an expression which @@ -996,7 +994,6 @@ WhereInfo *sqlite3WhereBegin( cont = pLevel->cont = sqlite3VdbeMakeLabel(v); sqlite3VdbeAddOp(v, OP_MustBeInt, 1, brk); sqlite3VdbeAddOp(v, OP_NotExists, iCur, brk); - haveRowid = 0; pLevel->op = OP_Noop; }else if( pIdx!=0 && pLevel->score>3 && (pLevel->score&0x0c)==0 ){ /* Case 2: There is an index and all terms of the WHERE clause that @@ -1050,11 +1047,9 @@ WhereInfo *sqlite3WhereBegin( } sqlite3VdbeAddOp(v, OP_RowKey, iIdxCur, 0); sqlite3VdbeAddOp(v, OP_IdxIsNull, nColumn, cont); - if( omitTable ){ - haveRowid = 0; - }else{ + if( !omitTable ){ sqlite3VdbeAddOp(v, OP_IdxRecno, iIdxCur, 0); - haveRowid = 1; + sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0); } pLevel->p1 = iIdxCur; pLevel->p2 = start; @@ -1115,7 +1110,6 @@ WhereInfo *sqlite3WhereBegin( sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0); sqlite3VdbeAddOp(v, testOp, 0, brk); } - haveRowid = 0; }else if( pIdx==0 ){ /* Case 4: There is no usable index. We must do a complete ** scan of the entire database table. @@ -1137,7 +1131,6 @@ WhereInfo *sqlite3WhereBegin( start = sqlite3VdbeCurrentAddr(v); pLevel->p1 = iCur; pLevel->p2 = start; - haveRowid = 0; }else{ /* Case 5: The WHERE clause term that refers to the right-most ** column of the index is an inequality. For example, if @@ -1287,11 +1280,9 @@ WhereInfo *sqlite3WhereBegin( } sqlite3VdbeAddOp(v, OP_RowKey, iIdxCur, 0); sqlite3VdbeAddOp(v, OP_IdxIsNull, nEqColumn + ((score&4)!=0), cont); - if( omitTable ){ - haveRowid = 0; - }else{ + if( !omitTable ){ sqlite3VdbeAddOp(v, OP_IdxRecno, iIdxCur, 0); - haveRowid = 1; + sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0); } /* Record the instruction used to terminate the loop. @@ -1311,14 +1302,6 @@ WhereInfo *sqlite3WhereBegin( if( pLevel->iLeftJoin && !ExprHasProperty(pTerm->p,EP_FromJoin) ){ continue; } - if( haveRowid ){ - haveRowid = 0; - if( omitTable ){ - sqlite3VdbeAddOp(v, OP_Pop, 1, 0); - }else{ - sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0); - } - } sqlite3ExprIfFalse(pParse, pTerm->p, cont, 1); pTerm->p = 0; } @@ -1335,33 +1318,12 @@ WhereInfo *sqlite3WhereBegin( for(pTerm=aExpr, j=0; jp==0 ) continue; if( (pTerm->prereqAll & loopMask)!=pTerm->prereqAll ) continue; - if( haveRowid ){ - /* Cannot happen. "haveRowid" can only be true if pushKey is true - ** an pushKey can only be true for DELETE and UPDATE and there are - ** no outer joins with DELETE and UPDATE. - */ - assert( 0 ); - haveRowid = 0; - sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0); - } sqlite3ExprIfFalse(pParse, pTerm->p, cont, 1); pTerm->p = 0; } } - - if( haveRowid && (inSrc-1 || !pushKey) ){ - haveRowid = 0; - if( omitTable ){ - sqlite3VdbeAddOp(v, OP_Pop, 1, 0); - }else{ - sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0); - } - } } pWInfo->iContinue = cont; - if( pushKey && !haveRowid ){ - sqlite3VdbeAddOp(v, OP_Recno, pTabList->a[0].iCursor, 0); - } freeMaskSet(&maskSet); return pWInfo; }