Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Registerify the SRT_Subroutine destination for SELECT results. (CVS 4690) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
8201f71729c3afbb41764cea3cda65b0 |
User & Date: | drh 2008-01-06 00:25:22.000 |
Context
2008-01-07
| ||
10:16 | Comment changes in select.c. (CVS 4691) (check-in: 38020592f1 user: danielk1977 tags: trunk) | |
2008-01-06
| ||
00:25 | Registerify the SRT_Subroutine destination for SELECT results. (CVS 4690) (check-in: 8201f71729 user: drh tags: trunk) | |
2008-01-05
| ||
18:48 | Modify OP_RegMakeRec to take a base register and count and optionally store results in the register specified by P3. (CVS 4689) (check-in: 6bb1b1bc18 user: drh tags: trunk) | |
Changes
Changes to src/build.c.
︙ | ︙ | |||
18 19 20 21 22 23 24 | ** CREATE INDEX ** DROP INDEX ** creating ID lists ** BEGIN TRANSACTION ** COMMIT ** ROLLBACK ** | | | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | ** CREATE INDEX ** DROP INDEX ** creating ID lists ** BEGIN TRANSACTION ** COMMIT ** ROLLBACK ** ** $Id: build.c,v 1.461 2008/01/06 00:25:22 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> /* ** This routine is called when a new SQL statement is beginning to ** be parsed. Initialize the pParse structure as needed. |
︙ | ︙ | |||
1487 1488 1489 1490 1491 1492 1493 | ** ** A shared-cache write-lock is not required to write to the new table, ** as a schema-lock must have already been obtained to create it. Since ** a schema-lock excludes all other database users, the write-lock would ** be redundant. */ if( pSelect ){ | | > > | 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 | ** ** A shared-cache write-lock is not required to write to the new table, ** as a schema-lock must have already been obtained to create it. Since ** a schema-lock excludes all other database users, the write-lock would ** be redundant. */ if( pSelect ){ SelectDest dest; Table *pSelTab; sqlite3VdbeAddOp0(v, OP_Copy); sqlite3VdbeAddOp3(v, OP_OpenWrite, 1, 0, iDb); pParse->nTab = 2; sqlite3SelectDestInit(&dest, SRT_Table, 1); sqlite3Select(pParse, pSelect, &dest, 0, 0, 0, 0); sqlite3VdbeAddOp1(v, OP_Close, 1); if( pParse->nErr==0 ){ pSelTab = sqlite3ResultSetOfSelect(pParse, 0, pSelect); if( pSelTab==0 ) return; assert( p->aCol==0 ); p->nCol = pSelTab->nCol; |
︙ | ︙ |
Changes to src/delete.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 C code routines that are called by the parser ** in order to generate code for DELETE FROM statements. ** | | | 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 C code routines that are called by the parser ** in order to generate code for DELETE FROM statements. ** ** $Id: delete.c,v 1.152 2008/01/06 00:25:22 drh Exp $ */ #include "sqliteInt.h" /* ** Look up every table that is named in pSrc. If any table is not found, ** add an error message to pParse->zErrMsg and return NULL. If all tables ** are found, return a pointer to the last table. |
︙ | ︙ | |||
257 258 259 260 261 262 263 | sqlite3VdbeJumpHere(v, iGoto); } /* If we are trying to delete from a view, realize that view into ** a ephemeral table. */ if( isView ){ | | > > | | | 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 | sqlite3VdbeJumpHere(v, iGoto); } /* If we are trying to delete from a view, realize that view into ** a ephemeral table. */ if( isView ){ SelectDest dest; Select *pView; pView = sqlite3SelectDup(db, pTab->pSelect); sqlite3SelectMask(pParse, pView, old_col_mask); sqlite3SelectDestInit(&dest, SRT_EphemTab, iCur); sqlite3Select(pParse, pView, &dest, 0, 0, 0, 0); sqlite3SelectDelete(pView); } /* Initialize the counter of the number of rows deleted, if ** we are counting rows. */ |
︙ | ︙ |
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.335 2008/01/06 00:25:22 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> /* ** Return the 'affinity' of the expression pExpr if any. ** |
︙ | ︙ | |||
1734 1735 1736 1737 1738 1739 1740 | if( pExpr->pSelect ){ /* Case 1: expr IN (SELECT ...) ** ** Generate code to write the results of the select into the temporary ** table allocated and opened above. */ | | > | > < | 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 | if( pExpr->pSelect ){ /* Case 1: expr IN (SELECT ...) ** ** Generate code to write the results of the select into the temporary ** table allocated and opened above. */ SelectDest dest; ExprList *pEList; sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable); dest.affinity = (int)affinity; assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable ); if( sqlite3Select(pParse, pExpr->pSelect, &dest, 0, 0, 0, 0) ){ return; } pEList = pExpr->pSelect->pEList; if( pEList && pEList->nExpr>0 ){ keyInfo.aColl[0] = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft, |
︙ | ︙ | |||
1799 1800 1801 1802 1803 1804 1805 | ** of the memory cell in iColumn. */ static const Token one = { (u8*)"1", 0, 1 }; Select *pSel; SelectDest dest; pSel = pExpr->pSelect; | | | 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 | ** of the memory cell in iColumn. */ static const Token one = { (u8*)"1", 0, 1 }; Select *pSel; SelectDest dest; pSel = pExpr->pSelect; sqlite3SelectDestInit(&dest, 0, ++pParse->nMem); if( pExpr->op==TK_SELECT ){ dest.eDest = SRT_Mem; sqlite3VdbeAddOp2(v, OP_Null, 0, dest.iParm); VdbeComment((v, "Init subquery result")); }else{ dest.eDest = SRT_Exists; sqlite3VdbeAddOp2(v, OP_Integer, 0, dest.iParm); |
︙ | ︙ |
Changes to src/insert.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 C code routines that are called by the parser ** to handle INSERT statements 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 C code routines that are called by the parser ** to handle INSERT statements in SQLite. ** ** $Id: insert.c,v 1.214 2008/01/06 00:25:22 drh Exp $ */ #include "sqliteInt.h" /* ** Set P4 of the most recently inserted opcode to a column affinity ** string for index pIdx. A column affinity string has one character ** for each column in the table, according to the affinity of the column: |
︙ | ︙ | |||
355 356 357 358 359 360 361 362 363 364 365 366 367 368 | int endOfLoop; /* Label for the end of the insertion loop */ int useTempTable = 0; /* Store SELECT results in intermediate table */ int srcTab = 0; /* Data comes from this temporary cursor if >=0 */ int iSelectLoop = 0; /* Address of code that implements the SELECT */ int iCleanup = 0; /* Address of the cleanup code */ int iInsertBlock = 0; /* Address of the subroutine used to insert data */ int iCntMem = 0; /* Memory cell used for the row counter */ int newIdx = -1; /* Cursor for the NEW table */ Db *pDb; /* The database containing table being inserted into */ int counterMem = 0; /* Memory cell holding AUTOINCREMENT counter */ int appendFlag = 0; /* True if the insert is likely to be an append */ int iDb; int nHidden = 0; | > | 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 | int endOfLoop; /* Label for the end of the insertion loop */ int useTempTable = 0; /* Store SELECT results in intermediate table */ int srcTab = 0; /* Data comes from this temporary cursor if >=0 */ int iSelectLoop = 0; /* Address of code that implements the SELECT */ int iCleanup = 0; /* Address of the cleanup code */ int iInsertBlock = 0; /* Address of the subroutine used to insert data */ int iCntMem = 0; /* Memory cell used for the row counter */ int iBaseReg; /* Base register for data */ int newIdx = -1; /* Cursor for the NEW table */ Db *pDb; /* The database containing table being inserted into */ int counterMem = 0; /* Memory cell holding AUTOINCREMENT counter */ int appendFlag = 0; /* True if the insert is likely to be an append */ int iDb; int nHidden = 0; |
︙ | ︙ | |||
467 468 469 470 471 472 473 | ** statement uses the the table that is being inserted into, then the ** subroutine is also coded here. That subroutine stores the SELECT ** results in a temporary table. (Template 3.) */ if( pSelect ){ /* Data is coming from a SELECT. Generate code to implement that SELECT */ | | > | > | 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 | ** statement uses the the table that is being inserted into, then the ** subroutine is also coded here. That subroutine stores the SELECT ** results in a temporary table. (Template 3.) */ if( pSelect ){ /* Data is coming from a SELECT. Generate code to implement that SELECT */ SelectDest dest; int rc, iInitCode; iInitCode = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0); iSelectLoop = sqlite3VdbeCurrentAddr(v); iInsertBlock = sqlite3VdbeMakeLabel(v); sqlite3SelectDestInit(&dest, SRT_Subroutine, iInsertBlock); /* Resolve the expressions in the SELECT statement and execute it. */ rc = sqlite3Select(pParse, pSelect, &dest, 0, 0, 0, 0); if( rc || pParse->nErr || db->mallocFailed ){ goto insert_cleanup; } iBaseReg = dest.iMem; iCleanup = sqlite3VdbeMakeLabel(v); sqlite3VdbeAddOp2(v, OP_Goto, 0, iCleanup); assert( pSelect->pEList ); nColumn = pSelect->pEList->nExpr; /* Set useTempTable to TRUE if the result of the SELECT statement ** should be written into a temporary table. Set to FALSE if each |
︙ | ︙ | |||
503 504 505 506 507 508 509 | if( useTempTable ){ /* Generate the subroutine that SELECT calls to process each row of ** the result. Store the result in a temporary table */ srcTab = pParse->nTab++; sqlite3VdbeResolveLabel(v, iInsertBlock); | | < | 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 | if( useTempTable ){ /* Generate the subroutine that SELECT calls to process each row of ** the result. Store the result in a temporary table */ srcTab = pParse->nTab++; sqlite3VdbeResolveLabel(v, iInsertBlock); sqlite3VdbeAddOp2(v, OP_RegMakeRec, iBaseReg, nColumn); sqlite3VdbeAddOp1(v, OP_NewRowid, srcTab); sqlite3VdbeAddOp2(v, OP_Pull, 1, 0); sqlite3CodeInsert(pParse, srcTab, OPFLAG_APPEND); sqlite3VdbeAddOp2(v, OP_Return, 0, 0); /* The following code runs first because the GOTO at the very top ** of the program jumps to it. Create the temporary table, then jump |
︙ | ︙ | |||
636 637 638 639 640 641 642 643 644 645 646 647 648 649 | if( useTempTable ){ iBreak = sqlite3VdbeMakeLabel(v); sqlite3VdbeAddOp2(v, OP_Rewind, srcTab, iBreak); iCont = sqlite3VdbeCurrentAddr(v); }else if( pSelect ){ sqlite3VdbeAddOp2(v, OP_Goto, 0, iSelectLoop); sqlite3VdbeResolveLabel(v, iInsertBlock); sqlite3VdbeAddOp2(v, OP_StackDepth, -1, 0); } /* Run the BEFORE and INSTEAD OF triggers, if there are any */ endOfLoop = sqlite3VdbeMakeLabel(v); if( triggers_exist & TRIGGER_BEFORE ){ | > | 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 | if( useTempTable ){ iBreak = sqlite3VdbeMakeLabel(v); sqlite3VdbeAddOp2(v, OP_Rewind, srcTab, iBreak); iCont = sqlite3VdbeCurrentAddr(v); }else if( pSelect ){ sqlite3VdbeAddOp2(v, OP_Goto, 0, iSelectLoop); sqlite3VdbeResolveLabel(v, iInsertBlock); sqlite3RegToStack(pParse, iBaseReg, nColumn); sqlite3VdbeAddOp2(v, OP_StackDepth, -1, 0); } /* Run the BEFORE and INSTEAD OF triggers, if there are any */ endOfLoop = sqlite3VdbeMakeLabel(v); if( triggers_exist & TRIGGER_BEFORE ){ |
︙ | ︙ |
Changes to src/select.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 C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** | | > > > > > > > > > > | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** ** $Id: select.c,v 1.390 2008/01/06 00:25:22 drh Exp $ */ #include "sqliteInt.h" /* ** Delete all the content of a Select structure but do not deallocate ** the select structure itself. */ static void clearSelect(Select *p){ sqlite3ExprListDelete(p->pEList); sqlite3SrcListDelete(p->pSrc); sqlite3ExprDelete(p->pWhere); sqlite3ExprListDelete(p->pGroupBy); sqlite3ExprDelete(p->pHaving); sqlite3ExprListDelete(p->pOrderBy); sqlite3SelectDelete(p->pPrior); sqlite3ExprDelete(p->pLimit); sqlite3ExprDelete(p->pOffset); } /* ** Initialize a SelectDest structure. */ void sqlite3SelectDestInit(SelectDest *pDest, int eDest, int iParm){ pDest->eDest = eDest; pDest->iParm = iParm; pDest->affinity = 0; pDest->iMem = 0; } /* ** Allocate a new Select structure and return a pointer to that ** structure. */ Select *sqlite3SelectNew( |
︙ | ︙ | |||
538 539 540 541 542 543 544 | /* Pull the requested columns. */ if( nColumn>0 ){ n = nColumn; }else{ n = pEList->nExpr; } | > > > | | > | 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 | /* Pull the requested columns. */ if( nColumn>0 ){ n = nColumn; }else{ n = pEList->nExpr; } if( pDest->iMem>0 ){ iMem = pDest->iMem; }else{ pDest->iMem = iMem = pParse->nMem+1; pParse->nMem += n; } if( nColumn>0 ){ for(i=0; i<nColumn; i++){ sqlite3VdbeAddOp3(v, OP_Column, srcTab, i, iMem+i); } }else if( eDest!=SRT_Exists ){ /* If the destination is an EXISTS(...) expression, the actual ** values returned by the SELECT are not required. |
︙ | ︙ | |||
675 676 677 678 679 680 681 | */ case SRT_Subroutine: case SRT_Callback: { if( pOrderBy ){ sqlite3VdbeAddOp2(v, OP_RegMakeRec, iMem, nColumn); pushOntoSorter(pParse, pOrderBy, p); }else if( eDest==SRT_Subroutine ){ | < | 689 690 691 692 693 694 695 696 697 698 699 700 701 702 | */ case SRT_Subroutine: case SRT_Callback: { if( pOrderBy ){ sqlite3VdbeAddOp2(v, OP_RegMakeRec, iMem, nColumn); pushOntoSorter(pParse, pOrderBy, p); }else if( eDest==SRT_Subroutine ){ sqlite3VdbeAddOp2(v, OP_Gosub, 0, iParm); }else{ sqlite3VdbeAddOp2(v, OP_ResultRow, iMem, nColumn); } break; } |
︙ | ︙ | |||
812 813 814 815 816 817 818 | } #endif case SRT_Callback: case SRT_Subroutine: { int i; sqlite3CodeInsert(pParse, pseudoTab, 0); for(i=0; i<nColumn; i++){ | | | | 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 | } #endif case SRT_Callback: case SRT_Subroutine: { int i; sqlite3CodeInsert(pParse, pseudoTab, 0); for(i=0; i<nColumn; i++){ sqlite3VdbeAddOp3(v, OP_Column, pseudoTab, i, pDest->iMem+i); } if( eDest==SRT_Callback ){ sqlite3VdbeAddOp2(v, OP_ResultRow, pDest->iMem, nColumn); }else{ sqlite3VdbeAddOp2(v, OP_Gosub, 0, iParm); } break; } default: { /* Do nothing */ |
︙ | ︙ | |||
1863 1864 1865 1866 1867 1868 1869 1870 | int rc = SQLITE_OK; /* Success code from a subroutine */ Select *pPrior; /* Another SELECT immediately to our left */ Vdbe *v; /* Generate code to this VDBE */ int nCol; /* Number of columns in the result set */ ExprList *pOrderBy; /* The ORDER BY clause on p */ int aSetP2[2]; /* Set P2 value of these op to number of columns */ int nSetP2 = 0; /* Number of slots in aSetP2[] used */ | > < | < < | 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 | int rc = SQLITE_OK; /* Success code from a subroutine */ Select *pPrior; /* Another SELECT immediately to our left */ Vdbe *v; /* Generate code to this VDBE */ int nCol; /* Number of columns in the result set */ ExprList *pOrderBy; /* The ORDER BY clause on p */ int aSetP2[2]; /* Set P2 value of these op to number of columns */ int nSetP2 = 0; /* Number of slots in aSetP2[] used */ SelectDest dest; /* Alternative data destination */ dest = *pDest; /* 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. */ if( p==0 || p->pPrior==0 ){ rc = 1; goto multi_select_end; |
︙ | ︙ | |||
1984 1985 1986 1987 1988 1989 1990 | createSortingIndex(pParse, p, pOrderBy); assert( p->pEList ); } /* Code the SELECT statements to our left */ assert( !pPrior->pOrderBy ); | | < | 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 | createSortingIndex(pParse, p, pOrderBy); assert( p->pEList ); } /* Code the SELECT statements to our left */ assert( !pPrior->pOrderBy ); sqlite3SelectDestInit(&uniondest, priorOp, unionTab); rc = sqlite3Select(pParse, pPrior, &uniondest, 0, 0, 0, aff); if( rc ){ goto multi_select_end; } /* Code the current SELECT statement */ |
︙ | ︙ | |||
2056 2057 2058 2059 2060 2061 2062 | break; } case TK_INTERSECT: { int tab1, tab2; int iCont, iBreak, iStart; Expr *pLimit, *pOffset; int addr; | | | 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 | break; } case TK_INTERSECT: { int tab1, tab2; int iCont, iBreak, iStart; Expr *pLimit, *pOffset; int addr; SelectDest intersectdest; /* INTERSECT is different from the others since it requires ** two temporary tables. Hence it has its own case. Begin ** by allocating the tables we will need. */ tab1 = pParse->nTab++; tab2 = pParse->nTab++; |
︙ | ︙ | |||
2078 2079 2080 2081 2082 2083 2084 | assert( p->addrOpenEphm[0] == -1 ); p->addrOpenEphm[0] = addr; p->pRightmost->usesEphm = 1; assert( p->pEList ); /* Code the SELECTs to our left into temporary table "tab1". */ | | | 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 | assert( p->addrOpenEphm[0] == -1 ); p->addrOpenEphm[0] = addr; p->pRightmost->usesEphm = 1; assert( p->pEList ); /* Code the SELECTs to our left into temporary table "tab1". */ sqlite3SelectDestInit(&intersectdest, SRT_Union, tab1); rc = sqlite3Select(pParse, pPrior, &intersectdest, 0, 0, 0, aff); if( rc ){ goto multi_select_end; } /* Code the current SELECT into temporary table "tab2" */ |
︙ | ︙ | |||
2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 | generateSortTail(pParse, p, v, p->pEList->nExpr, &dest); } sqlite3_free(pKeyInfo); } multi_select_end: return rc; } #endif /* SQLITE_OMIT_COMPOUND_SELECT */ #ifndef SQLITE_OMIT_VIEW /* Forward Declarations */ static void substExprList(sqlite3*, ExprList*, int, ExprList*); | > | 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 | generateSortTail(pParse, p, v, p->pEList->nExpr, &dest); } sqlite3_free(pKeyInfo); } multi_select_end: pDest->iMem = dest.iMem; return rc; } #endif /* SQLITE_OMIT_COMPOUND_SELECT */ #ifndef SQLITE_OMIT_VIEW /* Forward Declarations */ static void substExprList(sqlite3*, ExprList*, int, ExprList*); |
︙ | ︙ | |||
3248 3249 3250 3251 3252 3253 3254 | /* Generate code for all sub-queries in the FROM clause */ #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) for(i=0; i<pTabList->nSrc; i++){ const char *zSavedAuthContext = 0; int needRestoreContext; struct SrcList_item *pItem = &pTabList->a[i]; | | | | 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 | /* Generate code for all sub-queries in the FROM clause */ #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) for(i=0; i<pTabList->nSrc; i++){ const char *zSavedAuthContext = 0; int needRestoreContext; struct SrcList_item *pItem = &pTabList->a[i]; SelectDest dest; if( pItem->pSelect==0 || pItem->isPopulated ) continue; if( pItem->zName!=0 ){ zSavedAuthContext = pParse->zAuthContext; pParse->zAuthContext = pItem->zName; needRestoreContext = 1; }else{ needRestoreContext = 0; } #if defined(SQLITE_TEST) || SQLITE_MAX_EXPR_DEPTH>0 /* Increment Parse.nHeight by the height of the largest expression ** tree refered to by this, the parent select. The child select ** may contain expression trees of at most ** (SQLITE_MAX_EXPR_DEPTH-Parse.nHeight) height. This is a bit ** more conservative than necessary, but much easier than enforcing ** an exact limit. */ pParse->nHeight += sqlite3SelectExprHeight(p); #endif sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor); sqlite3Select(pParse, pItem->pSelect, &dest, p, i, &isAgg, 0); if( db->mallocFailed ){ goto select_end; } #if defined(SQLITE_TEST) || SQLITE_MAX_EXPR_DEPTH>0 pParse->nHeight -= sqlite3SelectExprHeight(p); #endif |
︙ | ︙ | |||
3643 3644 3645 3646 3647 3648 3649 | flag = minMaxQuery(pParse, p); if( flag ){ pMinMax = sqlite3ExprListDup(db, p->pEList->a[0].pExpr->pList); if( pMinMax ){ pMinMax->a[0].sortOrder = ((flag==ORDERBY_MIN)?0:1); pMinMax->a[0].pExpr->op = TK_COLUMN; | < | > | | 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 | flag = minMaxQuery(pParse, p); if( flag ){ pMinMax = sqlite3ExprListDup(db, p->pEList->a[0].pExpr->pList); if( pMinMax ){ pMinMax->a[0].sortOrder = ((flag==ORDERBY_MIN)?0:1); pMinMax->a[0].pExpr->op = TK_COLUMN; pDel = pMinMax; } } /* This case runs if the aggregate has no GROUP BY clause. The ** processing is much simpler since there is only a single row ** of output. */ resetAccumulator(pParse, &sAggInfo); pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pMinMax, flag); if( pWInfo==0 ){ sqlite3ExprListDelete(pDel); goto select_end; } updateAccumulator(pParse, &sAggInfo); if( !pMinMax && flag ){ sqlite3VdbeAddOp2(v, OP_Goto, 0, pWInfo->iBreak); VdbeComment((v, "%s() by index", (flag==ORDERBY_MIN?"min":"max"))); } |
︙ | ︙ |
Changes to src/sqliteInt.h.
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. ** ************************************************************************* ** Internal interface definitions for SQLite. ** | | | 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. ** ************************************************************************* ** Internal interface definitions for SQLite. ** ** @(#) $Id: sqliteInt.h,v 1.641 2008/01/06 00:25:22 drh Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ /* ** The macro unlikely() is a hint that surrounds a boolean ** expression that is usually false. Macro likely() surrounds |
︙ | ︙ | |||
1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 | ** comments above sqlite3Select() for details. */ typedef struct SelectDest SelectDest; struct SelectDest { u8 eDest; /* How to dispose of the results */ u8 affinity; /* Affinity used when eDest==SRT_Set */ int iParm; /* A parameter used by the eDest disposal method */ }; /* ** An SQL parser context. A copy of this structure is passed through ** the parser and down into all the parser action routine in order to ** carry around information that is global to the entire parse. ** | > | 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 | ** comments above sqlite3Select() for details. */ typedef struct SelectDest SelectDest; struct SelectDest { u8 eDest; /* How to dispose of the results */ u8 affinity; /* Affinity used when eDest==SRT_Set */ int iParm; /* A parameter used by the eDest disposal method */ int iMem; /* Base register where results are written */ }; /* ** An SQL parser context. A copy of this structure is passed through ** the parser and down into all the parser action routine in order to ** carry around information that is global to the entire parse. ** |
︙ | ︙ | |||
1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 | void sqlite3StrAccumAppend(StrAccum*,const char*,int); char *sqlite3StrAccumFinish(StrAccum*); void sqlite3StrAccumReset(StrAccum*); void sqlite3CodeInsert(Parse *, int, u8); int sqlite3StackToReg(Parse *, int); void sqlite3RegToStack(Parse *, int, int); /* ** The interface to the LEMON-generated parser */ void *sqlite3ParserAlloc(void*(*)(size_t)); void sqlite3ParserFree(void*, void(*)(void*)); void sqlite3Parser(void*, int, Token, Parse*); | > | 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 | void sqlite3StrAccumAppend(StrAccum*,const char*,int); char *sqlite3StrAccumFinish(StrAccum*); void sqlite3StrAccumReset(StrAccum*); void sqlite3CodeInsert(Parse *, int, u8); int sqlite3StackToReg(Parse *, int); void sqlite3RegToStack(Parse *, int, int); void sqlite3SelectDestInit(SelectDest*,int,int); /* ** The interface to the LEMON-generated parser */ void *sqlite3ParserAlloc(void*(*)(size_t)); void sqlite3ParserFree(void*, void(*)(void*)); void sqlite3Parser(void*, int, Token, Parse*); |
︙ | ︙ |
Changes to src/trigger.c.
︙ | ︙ | |||
693 694 695 696 697 698 699 | while( pTriggerStep ){ orconf = (orconfin == OE_Default)?pTriggerStep->orconf:orconfin; pParse->trigStack->orconf = orconf; switch( pTriggerStep->op ){ case TK_SELECT: { Select *ss = sqlite3SelectDup(db, pTriggerStep->pSelect); if( ss ){ | | > > | 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 | while( pTriggerStep ){ orconf = (orconfin == OE_Default)?pTriggerStep->orconf:orconfin; pParse->trigStack->orconf = orconf; switch( pTriggerStep->op ){ case TK_SELECT: { Select *ss = sqlite3SelectDup(db, pTriggerStep->pSelect); if( ss ){ SelectDest dest; sqlite3SelectDestInit(&dest, SRT_Discard, 0); sqlite3SelectResolve(pParse, ss, 0); sqlite3Select(pParse, ss, &dest, 0, 0, 0, 0); sqlite3SelectDelete(ss); } break; } case TK_UPDATE: { |
︙ | ︙ |
Changes to src/update.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 C code routines that are called by the parser ** to handle UPDATE statements. ** | | | 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 C code routines that are called by the parser ** to handle UPDATE statements. ** ** $Id: update.c,v 1.162 2008/01/06 00:25:22 drh Exp $ */ #include "sqliteInt.h" #ifndef SQLITE_OMIT_VIRTUALTABLE /* Forward declaration */ static void updateVirtualTable( Parse *pParse, /* The parsing context */ |
︙ | ︙ | |||
325 326 327 328 329 330 331 | } /* If we are trying to update a view, realize that view into ** a ephemeral table. */ if( isView ){ Select *pView; | | > | | 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 | } /* If we are trying to update a view, realize that view into ** a ephemeral table. */ if( isView ){ Select *pView; SelectDest dest; pView = sqlite3SelectDup(db, pTab->pSelect); sqlite3SelectMask(pParse, pView, old_col_mask|new_col_mask); sqlite3SelectDestInit(&dest, SRT_EphemTab, iCur); sqlite3Select(pParse, pView, &dest, 0, 0, 0, 0); sqlite3SelectDelete(pView); } /* Begin the database scan */ pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0); |
︙ | ︙ | |||
591 592 593 594 595 596 597 | Expr *pExpr; /* Temporary expression */ int ephemTab; /* Table holding the result of the SELECT */ int i; /* Loop counter */ int addr; /* Address of top of loop */ int iReg; /* First register in set passed to OP_VUpdate */ sqlite3 *db = pParse->db; /* Database connection */ const char *pVtab = (const char*)pTab->pVtab; | | | 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 | Expr *pExpr; /* Temporary expression */ int ephemTab; /* Table holding the result of the SELECT */ int i; /* Loop counter */ int addr; /* Address of top of loop */ int iReg; /* First register in set passed to OP_VUpdate */ sqlite3 *db = pParse->db; /* Database connection */ const char *pVtab = (const char*)pTab->pVtab; SelectDest dest; /* Construct the SELECT statement that will find the new values for ** all updated rows. */ pEList = sqlite3ExprListAppend(pParse, 0, sqlite3CreateIdExpr(pParse, "_rowid_"), 0); if( pRowid ){ |
︙ | ︙ | |||
622 623 624 625 626 627 628 | */ assert( v ); ephemTab = pParse->nTab++; sqlite3VdbeAddOp2(v, OP_OpenEphemeral, ephemTab, pTab->nCol+1+(pRowid!=0)); /* fill the ephemeral table */ | | | 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 | */ assert( v ); ephemTab = pParse->nTab++; sqlite3VdbeAddOp2(v, OP_OpenEphemeral, ephemTab, pTab->nCol+1+(pRowid!=0)); /* fill the ephemeral table */ sqlite3SelectDestInit(&dest, SRT_Table, ephemTab); sqlite3Select(pParse, pSelect, &dest, 0, 0, 0, 0); /* Generate code to scan the ephemeral table and call VUpdate. */ iReg = ++pParse->nMem; pParse->nMem += pTab->nCol+1; sqlite3VdbeAddOp2(v, OP_Rewind, ephemTab, 0); addr = sqlite3VdbeCurrentAddr(v); |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
39 40 41 42 43 44 45 | ** ** Various scripts scan this source file in order to generate HTML ** documentation, headers files, or other derived files. The formatting ** of the code in this file is, therefore, important. See other comments ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** | | | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | ** ** Various scripts scan this source file in order to generate HTML ** documentation, headers files, or other derived files. The formatting ** of the code in this file is, therefore, important. See other comments ** 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.686 2008/01/06 00:25:22 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> #include "vdbeInt.h" /* ** The following global variable is incremented every time a cursor |
︙ | ︙ | |||
2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 | pOut->xDel = 0; } if( nZero ){ pOut->u.i = nZero; pOut->flags |= MEM_Zero; } pOut->enc = SQLITE_UTF8; /* In case the blob is ever converted to text */ /* If a NULL was encountered and jumpIfNull is non-zero, take the jump. */ if( jumpIfNull && containsNull ){ pc = jumpIfNull - 1; } break; } | > | 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 | pOut->xDel = 0; } if( nZero ){ pOut->u.i = nZero; pOut->flags |= MEM_Zero; } pOut->enc = SQLITE_UTF8; /* In case the blob is ever converted to text */ REGISTER_TRACE(pOp->p3, pOut); /* If a NULL was encountered and jumpIfNull is non-zero, take the jump. */ if( jumpIfNull && containsNull ){ pc = jumpIfNull - 1; } break; } |
︙ | ︙ |
Changes to test/insert5.test.
︙ | ︙ | |||
8 9 10 11 12 13 14 | # May you share freely, never taking more than you give. # #*********************************************************************** # # The tests in this file ensure that a temporary table is used # when required by an "INSERT INTO ... SELECT ..." statement. # | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # May you share freely, never taking more than you give. # #*********************************************************************** # # The tests in this file ensure that a temporary table is used # when required by an "INSERT INTO ... SELECT ..." statement. # # $Id: insert5.test,v 1.4 2008/01/06 00:25:22 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !subquery { finish_test return |
︙ | ︙ | |||
48 49 50 51 52 53 54 | # Run the query. # do_test insert5-1.1 { execsql { INSERT INTO B SELECT * FROM B UNION ALL SELECT * FROM MAIN WHERE exists (select * FROM B WHERE B.Id = MAIN.Id); | | < | 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | # Run the query. # do_test insert5-1.1 { execsql { INSERT INTO B SELECT * FROM B UNION ALL SELECT * FROM MAIN WHERE exists (select * FROM B WHERE B.Id = MAIN.Id); SELECT * FROM B; } } {2 3 2 3 2 3} do_test insert5-2.1 { uses_temp_table { INSERT INTO b SELECT * FROM main } } {0} do_test insert5-2.2 { uses_temp_table { INSERT INTO b SELECT * FROM b } } {1} do_test insert5-2.3 { |
︙ | ︙ |