Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Make the LIMIT clause work even if the destination of the SELECT is something other than a callback. (Ticket #66) (CVS 619) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
699cf362083043615eb88635a228bfa4 |
User & Date: | drh 2002-06-14 22:38:42.000 |
Context
2002-06-16
| ||
04:54 | Changed sqlite_mprintf_str to allow a NULL string parameter. Command template now is cmd FORMAT INT INT ?STRING?. When STRING omitted a NULL is passed to sqlite_mprintf. (CVS 620) (check-in: 8bc711571d user: chw tags: trunk) | |
2002-06-14
| ||
22:38 | Make the LIMIT clause work even if the destination of the SELECT is something other than a callback. (Ticket #66) (CVS 619) (check-in: 699cf36208 user: drh tags: trunk) | |
20:58 | Improvements to comments. No code changes. (CVS 618) (check-in: 7e10e60bb7 user: drh tags: trunk) | |
Changes
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 | ** 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.93 2002/06/14 22:38:42 drh Exp $ */ #include "sqliteInt.h" /* ** Allocate a new Select structure and return a pointer to that ** structure. */ |
︙ | ︙ | |||
290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 | ** ** The pEList is used to determine the values for each column in the ** result row. Except if pEList==NULL, then we just read nColumn ** elements from the srcTab table. */ static int selectInnerLoop( Parse *pParse, /* The parser context */ ExprList *pEList, /* List of values being extracted */ int srcTab, /* Pull data from this table */ int nColumn, /* Number of columns in the source table */ ExprList *pOrderBy, /* If not NULL, sort results using this key */ int distinct, /* If >=0, make sure results are distinct */ int eDest, /* How to dispose of the results */ int iParm, /* An argument to the disposal method */ int iContinue, /* Jump here to continue with next row */ int iBreak /* Jump here to break out of the inner loop */ ){ Vdbe *v = pParse->pVdbe; int i; if( v==0 ) return 0; /* Pull the requested columns. */ if( pEList ){ for(i=0; i<pEList->nExpr; i++){ sqliteExprCode(pParse, pEList->a[i].pExpr); } | > > > > > > > > > > > > > | 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 | ** ** The pEList is used to determine the values for each column in the ** result row. Except if pEList==NULL, then we just read nColumn ** elements from the srcTab table. */ static int selectInnerLoop( Parse *pParse, /* The parser context */ Select *p, /* The complete select statement being coded */ ExprList *pEList, /* List of values being extracted */ int srcTab, /* Pull data from this table */ int nColumn, /* Number of columns in the source table */ ExprList *pOrderBy, /* If not NULL, sort results using this key */ int distinct, /* If >=0, make sure results are distinct */ int eDest, /* How to dispose of the results */ int iParm, /* An argument to the disposal method */ int iContinue, /* Jump here to continue with next row */ int iBreak /* Jump here to break out of the inner loop */ ){ Vdbe *v = pParse->pVdbe; int i; if( v==0 ) return 0; /* If there was a LIMIT clause on the SELECT statement, then do the check ** to see if this row should be output. */ if( pOrderBy==0 ){ if( p->nOffset>0 ){ sqliteVdbeAddOp(v, OP_LimitCk, 1, iContinue); } if( p->nLimit>0 ){ sqliteVdbeAddOp(v, OP_LimitCk, 0, iBreak); } } /* Pull the requested columns. */ if( pEList ){ for(i=0; i<pEList->nExpr; i++){ sqliteExprCode(pParse, pEList->a[i].pExpr); } |
︙ | ︙ | |||
415 416 417 418 419 420 421 | if( eDest==SRT_Discard ){ sqliteVdbeAddOp(v, OP_Pop, nColumn, 0); }else /* If none of the above, send the data to the callback function. */ { | > | | > > > > > > | | 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 | if( eDest==SRT_Discard ){ sqliteVdbeAddOp(v, OP_Pop, nColumn, 0); }else /* If none of the above, send the data to the callback function. */ { assert( eDest==SRT_Callback ); sqliteVdbeAddOp(v, OP_Callback, nColumn, 0); } return 0; } /* ** If the inner loop was generated using a non-null pOrderBy argument, ** then the results were placed in a sorter. After the loop is terminated ** we need to run the sorter and output the results. The following ** routine generates the code needed to do that. */ static void generateSortTail(Select *p, Vdbe *v, int nColumn){ int end = sqliteVdbeMakeLabel(v); int addr; sqliteVdbeAddOp(v, OP_Sort, 0, 0); addr = sqliteVdbeAddOp(v, OP_SortNext, 0, end); if( p->nOffset>0 ){ sqliteVdbeAddOp(v, OP_LimitCk, 1, addr); } if( p->nLimit>0 ){ sqliteVdbeAddOp(v, OP_LimitCk, 0, end); } sqliteVdbeAddOp(v, OP_SortCallback, nColumn, 0); sqliteVdbeAddOp(v, OP_Goto, 0, addr); sqliteVdbeResolveLabel(v, end); sqliteVdbeAddOp(v, OP_SortReset, 0, 0); } /* ** Generate code that will tell the VDBE how many columns there |
︙ | ︙ | |||
971 972 973 974 975 976 977 | if( eDest==SRT_Callback ){ generateColumnNames(pParse, p->base, 0, p->pEList); } iBreak = sqliteVdbeMakeLabel(v); iCont = sqliteVdbeMakeLabel(v); sqliteVdbeAddOp(v, OP_Rewind, unionTab, iBreak); iStart = sqliteVdbeCurrentAddr(v); | | | | 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 | if( eDest==SRT_Callback ){ generateColumnNames(pParse, p->base, 0, p->pEList); } iBreak = sqliteVdbeMakeLabel(v); iCont = sqliteVdbeMakeLabel(v); sqliteVdbeAddOp(v, OP_Rewind, unionTab, iBreak); iStart = sqliteVdbeCurrentAddr(v); rc = selectInnerLoop(pParse, p, 0, unionTab, p->pEList->nExpr, p->pOrderBy, -1, eDest, iParm, iCont, iBreak); if( rc ) return 1; sqliteVdbeResolveLabel(v, iCont); sqliteVdbeAddOp(v, OP_Next, unionTab, iStart); sqliteVdbeResolveLabel(v, iBreak); sqliteVdbeAddOp(v, OP_Close, unionTab, 0); if( p->pOrderBy ){ generateSortTail(p, v, p->pEList->nExpr); } } break; } case TK_INTERSECT: { int tab1, tab2; int iCont, iBreak, iStart; |
︙ | ︙ | |||
1027 1028 1029 1030 1031 1032 1033 | generateColumnNames(pParse, p->base, 0, p->pEList); } iBreak = sqliteVdbeMakeLabel(v); iCont = sqliteVdbeMakeLabel(v); sqliteVdbeAddOp(v, OP_Rewind, tab1, iBreak); iStart = sqliteVdbeAddOp(v, OP_FullKey, tab1, 0); sqliteVdbeAddOp(v, OP_NotFound, tab2, iCont); | | | | 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 | generateColumnNames(pParse, p->base, 0, p->pEList); } iBreak = sqliteVdbeMakeLabel(v); iCont = sqliteVdbeMakeLabel(v); sqliteVdbeAddOp(v, OP_Rewind, tab1, iBreak); iStart = sqliteVdbeAddOp(v, OP_FullKey, tab1, 0); sqliteVdbeAddOp(v, OP_NotFound, tab2, iCont); rc = selectInnerLoop(pParse, p, 0, tab1, p->pEList->nExpr, p->pOrderBy, -1, eDest, iParm, iCont, iBreak); if( rc ) return 1; sqliteVdbeResolveLabel(v, iCont); sqliteVdbeAddOp(v, OP_Next, tab1, iStart); sqliteVdbeResolveLabel(v, iBreak); sqliteVdbeAddOp(v, OP_Close, tab2, 0); sqliteVdbeAddOp(v, OP_Close, tab1, 0); if( p->pOrderBy ){ generateSortTail(p, v, p->pEList->nExpr); } break; } } assert( p->pEList && pPrior->pEList ); if( p->pEList->nExpr!=pPrior->pEList->nExpr ){ sqliteSetString(&pParse->zErrMsg, "SELECTs to the left and right of ", |
︙ | ︙ | |||
1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 | ** (5) The subquery is not DISTINCT or the outer query does not use ** aggregates. ** ** (6) The subquery does not use aggregates or the outer query is not ** DISTINCT. ** ** (7) The subquery has a FROM clause. ** ** In this routine, the "p" parameter is a pointer to the outer query. ** The subquery is p->pSrc->a[iFrom]. isAgg is true if the outer query ** uses aggregates and subqueryIsAgg is true if the subquery uses aggregates. ** ** If flattening is not attempted, this routine is a no-op and return 0. ** If flattening is attempted this routine returns 1. | > > > > > > > > | 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 | ** (5) The subquery is not DISTINCT or the outer query does not use ** aggregates. ** ** (6) The subquery does not use aggregates or the outer query is not ** DISTINCT. ** ** (7) The subquery has a FROM clause. ** ** (8) The subquery does not use LIMIT or the outer query is not a join. ** ** (9) The subquery does not use LIMIT or the outer query does not use ** aggregates. ** ** (10) The subquery does not use aggregates or the outer query does not ** use LIMIT. ** ** In this routine, the "p" parameter is a pointer to the outer query. ** The subquery is p->pSrc->a[iFrom]. isAgg is true if the outer query ** uses aggregates and subqueryIsAgg is true if the subquery uses aggregates. ** ** If flattening is not attempted, this routine is a no-op and return 0. ** If flattening is attempted this routine returns 1. |
︙ | ︙ | |||
1203 1204 1205 1206 1207 1208 1209 | pSub = pSrc->a[iFrom].pSelect; assert( pSub!=0 ); if( isAgg && subqueryIsAgg ) return 0; if( subqueryIsAgg && pSrc->nSrc>1 ) return 0; pSubSrc = pSub->pSrc; assert( pSubSrc ); if( pSubSrc->nSrc!=1 ) return 0; | | | > | | 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 | pSub = pSrc->a[iFrom].pSelect; assert( pSub!=0 ); if( isAgg && subqueryIsAgg ) return 0; if( subqueryIsAgg && pSrc->nSrc>1 ) return 0; pSubSrc = pSub->pSrc; assert( pSubSrc ); if( pSubSrc->nSrc!=1 ) return 0; if( (pSub->isDistinct || pSub->nLimit>=0) && (pSrc->nSrc>1 || isAgg) ){ return 0; } if( (p->isDistinct || p->nLimit) && subqueryIsAgg ) return 0; /* If we reach this point, it means flattening is permitted for the ** i-th entry of the FROM clause in the outer query. */ iParent = p->base + iFrom; iSub = pSub->base; substExprList(p->pEList, iParent, pSub->pEList, iSub); |
︙ | ︙ | |||
1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 | }else{ substExpr(p->pWhere, iParent, pSub->pEList, iSub); if( pWhere ){ p->pWhere = sqliteExpr(TK_AND, p->pWhere, pWhere, 0); } } p->isDistinct = p->isDistinct || pSub->isDistinct; if( pSrc->a[iFrom].pTab && pSrc->a[iFrom].pTab->isTransient ){ sqliteDeleteTable(0, pSrc->a[iFrom].pTab); } pSrc->a[iFrom].pTab = pSubSrc->a[0].pTab; pSubSrc->a[0].pTab = 0; pSrc->a[iFrom].pSelect = pSubSrc->a[0].pSelect; pSubSrc->a[0].pSelect = 0; | > > > > > > > > | 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 | }else{ substExpr(p->pWhere, iParent, pSub->pEList, iSub); if( pWhere ){ p->pWhere = sqliteExpr(TK_AND, p->pWhere, pWhere, 0); } } p->isDistinct = p->isDistinct || pSub->isDistinct; if( pSub->nLimit>=0 ){ if( p->nLimit<0 ){ p->nLimit = pSub->nLimit; }else if( p->nLimit+p->nOffset > pSub->nLimit+pSub->nOffset ){ p->nLimit = pSub->nLimit + pSub->nOffset - p->nOffset; } } p->nOffset += pSub->nOffset; if( pSrc->a[iFrom].pTab && pSrc->a[iFrom].pTab->isTransient ){ sqliteDeleteTable(0, pSrc->a[iFrom].pTab); } pSrc->a[iFrom].pTab = pSubSrc->a[0].pTab; pSubSrc->a[0].pTab = 0; pSrc->a[iFrom].pSelect = pSubSrc->a[0].pSelect; pSubSrc->a[0].pSelect = 0; |
︙ | ︙ | |||
1382 1383 1384 1385 1386 1387 1388 | sqliteVdbeAddOp(v, OP_MoveTo, base, 0); } eList.nExpr = 1; memset(&eListItem, 0, sizeof(eListItem)); eList.a = &eListItem; eList.a[0].pExpr = pExpr; cont = sqliteVdbeMakeLabel(v); | | | 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 | sqliteVdbeAddOp(v, OP_MoveTo, base, 0); } eList.nExpr = 1; memset(&eListItem, 0, sizeof(eListItem)); eList.a = &eListItem; eList.a[0].pExpr = pExpr; cont = sqliteVdbeMakeLabel(v); selectInnerLoop(pParse, p, &eList, base, 1, 0, -1, eDest, iParm, cont, cont); sqliteVdbeResolveLabel(v, cont); sqliteVdbeAddOp(v, OP_Close, base, 0); return 1; } /* ** Generate code for the given SELECT statement. |
︙ | ︙ | |||
1716 1717 1718 1719 1720 1721 1722 | pWInfo = sqliteWhereBegin(pParse, p->base, pTabList, pWhere, 0); if( pWInfo==0 ) goto select_end; /* Use the standard inner loop if we are not dealing with ** aggregates */ if( !isAgg ){ | | | | 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 | pWInfo = sqliteWhereBegin(pParse, p->base, pTabList, pWhere, 0); if( pWInfo==0 ) goto select_end; /* Use the standard inner loop if we are not dealing with ** aggregates */ if( !isAgg ){ if( selectInnerLoop(pParse, p, pEList, 0, 0, pOrderBy, distinct, eDest, iParm, pWInfo->iContinue, pWInfo->iBreak) ){ goto select_end; } } /* If we are dealing with aggregates, then to the special aggregate ** processing. */ |
︙ | ︙ | |||
1775 1776 1777 1778 1779 1780 1781 | int endagg = sqliteVdbeMakeLabel(v); int startagg; startagg = sqliteVdbeAddOp(v, OP_AggNext, 0, endagg); pParse->useAgg = 1; if( pHaving ){ sqliteExprIfFalse(pParse, pHaving, startagg, 1); } | | | | | 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 | int endagg = sqliteVdbeMakeLabel(v); int startagg; startagg = sqliteVdbeAddOp(v, OP_AggNext, 0, endagg); pParse->useAgg = 1; if( pHaving ){ sqliteExprIfFalse(pParse, pHaving, startagg, 1); } if( selectInnerLoop(pParse, p, pEList, 0, 0, pOrderBy, distinct, eDest, iParm, startagg, endagg) ){ goto select_end; } sqliteVdbeAddOp(v, OP_Goto, 0, startagg); sqliteVdbeResolveLabel(v, endagg); sqliteVdbeAddOp(v, OP_Noop, 0, 0); pParse->useAgg = 0; } /* If there is an ORDER BY clause, then we need to sort the results ** and send them to the callback one by one. */ if( pOrderBy ){ generateSortTail(p, v, pEList->nExpr); } /* Issue a null callback if that is what the user wants. */ if( (pParse->db->flags & SQLITE_NullCallback)!=0 && eDest==SRT_Callback ){ sqliteVdbeAddOp(v, OP_NullCallback, pEList->nExpr, 0); |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
26 27 28 29 30 31 32 | ** type to the other occurs as necessary. ** ** Most of the code in this file is taken up by the sqliteVdbeExec() ** function which does the work of interpreting a VDBE program. ** But other routines are also provided to help in building up ** a program instruction by instruction. ** | | | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | ** type to the other occurs as necessary. ** ** Most of the code in this file is taken up by the sqliteVdbeExec() ** function which does the work of interpreting a VDBE program. ** But other routines are also provided to help in building up ** a program instruction by instruction. ** ** $Id: vdbe.c,v 1.156 2002/06/14 22:38:43 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> /* ** The following global variable is incremented every time a cursor ** moves, either by the OP_MoveTo or the OP_Next opcode. The test |
︙ | ︙ | |||
1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 | "Add", "AddImm", "Subtract", "Multiply", "Divide", "Remainder", "BitAnd", "BitOr", "BitNot", "ShiftLeft", "ShiftRight", "AbsValue", "Eq", "Ne", "Lt", "Le", "Gt", "Ge", "IsNull", "NotNull", "Negative", "And", "Or", "Not", "Concat", "Noop", "Function", "Limit", }; /* ** Given the name of an opcode, return its number. Return 0 if ** there is no match. ** ** This routine is used for testing and debugging. | > | 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 | "Add", "AddImm", "Subtract", "Multiply", "Divide", "Remainder", "BitAnd", "BitOr", "BitNot", "ShiftLeft", "ShiftRight", "AbsValue", "Eq", "Ne", "Lt", "Le", "Gt", "Ge", "IsNull", "NotNull", "Negative", "And", "Or", "Not", "Concat", "Noop", "Function", "Limit", "LimitCk", }; /* ** Given the name of an opcode, return its number. Return 0 if ** there is no match. ** ** This routine is used for testing and debugging. |
︙ | ︙ | |||
1581 1582 1583 1584 1585 1586 1587 | */ case OP_ColumnName: { p->azColName[pOp->p1] = pOp->p3 ? pOp->p3 : ""; p->nCallback = 0; break; } | | < < < < < < < < < < | | | | | | < < < < < < < | 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 | */ case OP_ColumnName: { p->azColName[pOp->p1] = pOp->p3 ? pOp->p3 : ""; p->nCallback = 0; break; } /* Opcode: Callback P1 * * ** ** Pop P1 values off the stack and form them into an array. Then ** invoke the callback function using the newly formed array as the ** 3rd parameter. */ case OP_Callback: { int i = p->tos - pOp->p1 + 1; int j; VERIFY( if( i<0 ) goto not_enough_stack; ) VERIFY( if( NeedStack(p, p->tos+2) ) goto no_mem; ) for(j=i; j<=p->tos; j++){ if( aStack[j].flags & STK_Null ){ zStack[j] = 0; }else{ if( Stringify(p, j) ) goto no_mem; } } zStack[p->tos+1] = 0; if( xCallback!=0 ){ if( sqliteSafetyOff(db) ) goto abort_due_to_misuse; if( xCallback(pArg, pOp->p1, &zStack[i], p->azColName)!=0 ){ rc = SQLITE_ABORT; } if( sqliteSafetyOn(db) ) goto abort_due_to_misuse; p->nCallback++; } PopStack(p, pOp->p1); if( sqlite_malloc_failed ) goto no_mem; break; } /* Opcode: NullCallback P1 * * |
︙ | ︙ | |||
3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 | ** of a SELECT statement. */ case OP_Limit: { p->iLimit = pOp->p1; p->iOffset = pOp->p2; break; } /* Opcode: ListWrite * * * ** ** Write the integer on the top of the stack ** into the temporary storage list. */ case OP_ListWrite: { | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 | ** of a SELECT statement. */ case OP_Limit: { p->iLimit = pOp->p1; p->iOffset = pOp->p2; break; } /* Opcode: LimitCk P1 P2 * ** ** If P1 is 1, then check to see if the offset counter (set by the ** P2 argument of OP_Limit) is positive. If the offset counter is ** positive then decrement the counter and jump immediately to P2. ** Otherwise fall straight through. ** ** If P1 is 0, then check the value of the limit counter (set by the ** P1 argument of OP_Limit). If the limit counter is negative or ** zero then jump immedately to P2. Otherwise decrement the limit ** counter and fall through. */ case OP_LimitCk: { if( pOp->p1 ){ if( p->iOffset ){ p->iOffset--; pc = pOp->p2 - 1; } }else{ if( p->iLimit>0 ){ p->iLimit--; }else{ pc = pOp->p2 - 1; } } break; } /* Opcode: ListWrite * * * ** ** Write the integer on the top of the stack ** into the temporary storage list. */ case OP_ListWrite: { |
︙ | ︙ | |||
4203 4204 4205 4206 4207 4208 4209 | sqliteFree(pSorter); }else{ pc = pOp->p2 - 1; } break; } | | < < < < < < < < < < | | | | | < < < < < < < < | 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 | sqliteFree(pSorter); }else{ pc = pOp->p2 - 1; } break; } /* Opcode: SortCallback P1 * * ** ** The top of the stack contains a callback record built using ** the SortMakeRec operation with the same P1 value as this ** instruction. Pop this record from the stack and invoke the ** callback on it. */ case OP_SortCallback: { int i = p->tos; VERIFY( if( i<0 ) goto not_enough_stack; ) if( xCallback!=0 ){ if( sqliteSafetyOff(db) ) goto abort_due_to_misuse; if( xCallback(pArg, pOp->p1, (char**)zStack[i], p->azColName)!=0 ){ rc = SQLITE_ABORT; } if( sqliteSafetyOn(db) ) goto abort_due_to_misuse; p->nCallback++; } POPSTACK; if( sqlite_malloc_failed ) goto no_mem; break; } |
︙ | ︙ |
Changes to src/vdbe.h.
︙ | ︙ | |||
11 12 13 14 15 16 17 | ************************************************************************* ** Header file for the Virtual DataBase Engine (VDBE) ** ** This header defines the interface to the virtual database engine ** or VDBE. The VDBE implements an abstract machine that runs a ** simple program to access and modify the underlying database. ** | | | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ************************************************************************* ** Header file for the Virtual DataBase Engine (VDBE) ** ** This header defines the interface to the virtual database engine ** or VDBE. The VDBE implements an abstract machine that runs a ** simple program to access and modify the underlying database. ** ** $Id: vdbe.h,v 1.55 2002/06/14 22:38:43 drh Exp $ */ #ifndef _SQLITE_VDBE_H_ #define _SQLITE_VDBE_H_ #include <stdio.h> /* ** A single VDBE is an opaque structure named "Vdbe". Only routines |
︙ | ︙ | |||
200 201 202 203 204 205 206 207 208 | #define OP_Or 115 #define OP_Not 116 #define OP_Concat 117 #define OP_Noop 118 #define OP_Function 119 #define OP_Limit 120 | > | | 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 | #define OP_Or 115 #define OP_Not 116 #define OP_Concat 117 #define OP_Noop 118 #define OP_Function 119 #define OP_Limit 120 #define OP_LimitCk 121 #define OP_MAX 121 /* ** Prototypes for the VDBE interface. See comments on the implementation ** for a description of what each of these routines does. */ Vdbe *sqliteVdbeCreate(sqlite*); void sqliteVdbeCreateCallback(Vdbe*, int*); |
︙ | ︙ |
Changes to src/where.c.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** This module contains C code that generates VDBE code used to process ** the WHERE clause of SQL statements. Also found here are subroutines ** to generate VDBE code to evaluate expressions. ** | | | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** This module contains C code that generates VDBE code used to process ** the WHERE clause of SQL statements. Also found here are subroutines ** to generate VDBE code to evaluate expressions. ** ** $Id: where.c,v 1.52 2002/06/14 22:38:43 drh Exp $ */ #include "sqliteInt.h" /* ** The query generator uses an array of instances of this structure to ** help it analyze the subexpressions of the WHERE clause. Each WHERE ** clause subexpression is separated from the others by an AND operator. |
︙ | ︙ | |||
254 255 256 257 258 259 260 261 262 263 264 265 266 267 | pWInfo->iBreak = sqliteVdbeMakeLabel(v); /* Special case: a WHERE clause that is constant. Evaluate the ** expression and either jump over all of the code or fall thru. */ if( pWhere && sqliteExprIsConstant(pWhere) ){ sqliteExprIfFalse(pParse, pWhere, pWInfo->iBreak, 1); } /* Split the WHERE clause into as many as 32 separate subexpressions ** where each subexpression is separated by an AND operator. Any additional ** subexpressions are attached in the aExpr[32] and will not enter ** into the query optimizer computations. 32 is chosen as the cutoff ** since that is the number of bits in an integer that we use for an | > | 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 | pWInfo->iBreak = sqliteVdbeMakeLabel(v); /* Special case: a WHERE clause that is constant. Evaluate the ** expression and either jump over all of the code or fall thru. */ if( pWhere && sqliteExprIsConstant(pWhere) ){ sqliteExprIfFalse(pParse, pWhere, pWInfo->iBreak, 1); pWhere = 0; } /* Split the WHERE clause into as many as 32 separate subexpressions ** where each subexpression is separated by an AND operator. Any additional ** subexpressions are attached in the aExpr[32] and will not enter ** into the query optimizer computations. 32 is chosen as the cutoff ** since that is the number of bits in an integer that we use for an |
︙ | ︙ |
Changes to test/limit.test.
︙ | ︙ | |||
8 9 10 11 12 13 14 | # 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 LIMIT ... OFFSET ... clause # of SELECT statements. # | | | 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. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the LIMIT ... OFFSET ... clause # of SELECT statements. # # $Id: limit.test,v 1.3 2002/06/14 22:38:43 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Build some test data # set fd [open data1.txt w] |
︙ | ︙ | |||
51 52 53 54 55 56 57 58 59 60 | } {} do_test limit-1.6 { execsql {SELECT * FROM t1 AS a, t1 AS b ORDER BY a.x, b.x LIMIT 5} } {0 5 0 5 0 5 1 5 0 5 2 5 0 5 3 5 0 5 4 5} do_test limit-1.7 { execsql {SELECT * FROM t1 AS a, t1 AS b ORDER BY a.x, b.x LIMIT 5 OFFSET 32} } {1 5 0 5 1 5 1 5 1 5 2 5 1 5 3 5 1 5 4 5} finish_test | > > > > > > > > > > > > > > > > > > | 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | } {} do_test limit-1.6 { execsql {SELECT * FROM t1 AS a, t1 AS b ORDER BY a.x, b.x LIMIT 5} } {0 5 0 5 0 5 1 5 0 5 2 5 0 5 3 5 0 5 4 5} do_test limit-1.7 { execsql {SELECT * FROM t1 AS a, t1 AS b ORDER BY a.x, b.x LIMIT 5 OFFSET 32} } {1 5 0 5 1 5 1 5 1 5 2 5 1 5 3 5 1 5 4 5} do_test limit-2.1 { execsql { CREATE VIEW v1 AS SELECT * FROM t1 LIMIT 2; SELECT count(*) FROM (SELECT * FROM v1); } } 2 do_test limit-2.2 { execsql { CREATE TABLE t2 AS SELECT * FROM t1 LIMIT 2; SELECT count(*) FROM t2; } } 2 do_test limit-2.3 { execsql { SELECT count(*) FROM t1 WHERE rowid IN (SELECT rowid FROM t1 LIMIT 2); } } 2 finish_test |
Changes to test/where.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 use of indices in WHERE clases. # | | | 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 use of indices in WHERE clases. # # $Id: where.test,v 1.8 2002/06/14 22:38:43 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Build some test data # do_test where-1.0 { |
︙ | ︙ | |||
245 246 247 248 249 250 251 | SELECT * FROM t1 WHERE 0 } } {0} do_test where-4.2 { count { SELECT * FROM t1 WHERE 1 LIMIT 1 } | | | 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 | SELECT * FROM t1 WHERE 0 } } {0} do_test where-4.2 { count { SELECT * FROM t1 WHERE 1 LIMIT 1 } } {1 0 4 1} do_test where-4.3 { execsql { SELECT 99 WHERE 0 } } {} do_test where-4.4 { execsql { |
︙ | ︙ |