Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Fix for ticket #147: Honor the ORDER BY and LIMIT clauses in a SELECT even if the destination of that SELECT is a subroutine call. (CVS 747) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
23fe36c7e88282f6d1b7547ab892ea88 |
User & Date: | drh 2002-09-08 17:23:42.000 |
Context
2002-09-12
| ||
14:08 | Update the SQL language documentation to talk about SELECT DISTINCT. (CVS 748) (check-in: ef7116751d user: drh tags: trunk) | |
2002-09-08
| ||
17:23 | Fix for ticket #147: Honor the ORDER BY and LIMIT clauses in a SELECT even if the destination of that SELECT is a subroutine call. (CVS 747) (check-in: 23fe36c7e8 user: drh tags: trunk) | |
00:04 | Modify the build process so that the VDBE opcode numbers and the table that contains the opcode names are both automatically generated. This makes it much easier to create new VDBE opcodes. (CVS 1727) (check-in: c4f0bb0238 user: drh tags: trunk) | |
Changes
Changes to main.mk.
︙ | ︙ | |||
137 138 139 140 141 142 143 | # This target creates a directory named "tsrc" and fills it with # copies of all of the C source code and header files needed to # build on the target system. Some of the C source code and header # files are automatically generated. This target takes care of # all that automatic generation. # | | | | 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 | # This target creates a directory named "tsrc" and fills it with # copies of all of the C source code and header files needed to # build on the target system. Some of the C source code and header # files are automatically generated. This target takes care of # all that automatic generation. # target_source: $(SRC) $(HDR) opcodes.c rm -rf tsrc mkdir tsrc cp $(SRC) $(HDR) tsrc rm tsrc/sqlite.h.in tsrc/parse.y cp parse.c opcodes.c tsrc # Rules to build the LEMON compiler generator # lemon: $(TOP)/tool/lemon.c $(TOP)/tool/lempar.c $(BCC) -o lemon $(TOP)/tool/lemon.c cp $(TOP)/tool/lempar.c . |
︙ | ︙ |
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.112 2002/09/08 17:23:43 drh Exp $ */ #include "sqliteInt.h" /* ** Allocate a new Select structure and return a pointer to that ** structure. */ |
︙ | ︙ | |||
520 521 522 523 524 525 526 | break; } /* Invoke a subroutine to handle the results. The subroutine itself ** is responsible for popping the results off of the stack. */ case SRT_Subroutine: { | > > > > | > | 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 | break; } /* Invoke a subroutine to handle the results. The subroutine itself ** is responsible for popping the results off of the stack. */ case SRT_Subroutine: { if( pOrderBy ){ sqliteVdbeAddOp(v, OP_MakeRecord, nColumn, 0); pushOntoSorter(pParse, v, pOrderBy); }else{ sqliteVdbeAddOp(v, OP_Gosub, 0, iParm); } break; } /* Discard the results. This is used for SELECT statements inside ** the body of a TRIGGER. The purpose of such selects is to call ** user-defined functions that have side effects. We do not care ** about the actual results of the select. |
︙ | ︙ | |||
588 589 590 591 592 593 594 595 596 597 598 599 600 601 | break; } case SRT_Mem: { assert( nColumn==1 ); sqliteVdbeAddOp(v, OP_MemStore, iParm, 1); sqliteVdbeAddOp(v, OP_Goto, 0, end); break; } default: { /* Do nothing */ break; } } sqliteVdbeAddOp(v, OP_Goto, 0, addr); | > > > > > > > > > | 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 | break; } case SRT_Mem: { assert( nColumn==1 ); sqliteVdbeAddOp(v, OP_MemStore, iParm, 1); sqliteVdbeAddOp(v, OP_Goto, 0, end); break; } case SRT_Subroutine: { int i; for(i=0; i<nColumn; i++){ sqliteVdbeAddOp(v, OP_Column, -1-i, i); } sqliteVdbeAddOp(v, OP_Gosub, 0, iParm); sqliteVdbeAddOp(v, OP_Pop, 1, 0); break; } default: { /* Do nothing */ break; } } sqliteVdbeAddOp(v, OP_Goto, 0, addr); |
︙ | ︙ |
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 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | ** 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. ** ** 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.177 2002/09/08 17:23:43 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> /* ** The makefile scans this source file and creates the following ** array of string constants which are the names of all VDBE opcodes. ** This array is defined in a separate source code file named opcode.c ** which is automatically generated by the makefile. */ extern char *sqliteOpcodeNames[]; /* ** The following global variable is incremented every time a cursor ** moves, either by the OP_MoveTo or the OP_Next opcode. The test ** procedures use this information to make sure that indices are ** working correctly. This variable has no function other than to ** help verify the correct operation of the library. */ int sqlite_search_count = 0; /* ** SQL is translated into a sequence of instructions to be ** executed by a virtual machine. Each instruction is an instance ** of the following structure. |
︙ | ︙ | |||
257 258 259 260 261 262 263 | Set *aSet; /* An array of sets */ int nCallback; /* Number of callbacks invoked so far */ int keylistStackDepth; /* The size of the "keylist" stack */ Keylist **keylistStack; /* The stack used by opcodes ListPush & ListPop */ }; /* | | | 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 | Set *aSet; /* An array of sets */ int nCallback; /* Number of callbacks invoked so far */ int keylistStackDepth; /* The size of the "keylist" stack */ Keylist **keylistStack; /* The stack used by opcodes ListPush & ListPop */ }; /* ** When debugging the code generator in a symbolic debugger, one can ** set the sqlite_vdbe_addop_trace to 1 and all opcodes will be printed ** as they are added to the instruction stream. */ #ifndef NDEBUG int sqlite_vdbe_addop_trace = 0; static void vdbePrintOp(FILE*, int, Op*); #endif |
︙ | ︙ | |||
367 368 369 370 371 372 373 | } p->aLabel[i] = -1; return -1-i; } /* ** Resolve label "x" to be the address of the next instruction to | | > | 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 | } p->aLabel[i] = -1; return -1-i; } /* ** Resolve label "x" to be the address of the next instruction to ** be inserted. The parameter "x" must have been obtained from ** a prior call to sqliteVdbeMakeLabel(). */ void sqliteVdbeResolveLabel(Vdbe *p, int x){ int j; if( x<0 && (-x)<=p->nLabel && p->aOp ){ if( p->aLabel[-1-x]==p->nOp ) return; assert( p->aLabel[-1-x]<0 ); p->aLabel[-1-x] = p->nOp; |
︙ | ︙ | |||
562 563 564 565 566 567 568 | /* ** The following group or routines are employed by installable functions ** to return their results. ** ** The sqlite_set_result_string() routine can be used to return a string ** value or to return a NULL. To return a NULL, pass in NULL for zResult. ** A copy is made of the string before this routine returns so it is safe | | | | | 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 | /* ** The following group or routines are employed by installable functions ** to return their results. ** ** The sqlite_set_result_string() routine can be used to return a string ** value or to return a NULL. To return a NULL, pass in NULL for zResult. ** A copy is made of the string before this routine returns so it is safe ** to pass in an ephemeral string. ** ** sqlite_set_result_error() works like sqlite_set_result_string() except ** that it signals a fatal error. The string argument, if any, is the ** error message. If the argument is NULL a generic substitute error message ** is used. ** ** The sqlite_set_result_int() and sqlite_set_result_double() set the return ** value of the user function to an integer or a double. ** ** These routines are defined here in vdbe.c because they depend on knowing ** the internals of the sqlite_func structure which is only defined in ** this source file. */ char *sqlite_set_result_string(sqlite_func *p, const char *zResult, int n){ assert( !p->isStep ); if( p->s.flags & STK_Dyn ){ sqliteFree(p->z); } if( zResult==0 ){ |
︙ | ︙ | |||
632 633 634 635 636 637 638 | } /* ** Extract the user data from a sqlite_func structure and return a ** pointer to it. ** ** This routine is defined here in vdbe.c because it depends on knowing | | | | | | | | 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 | } /* ** Extract the user data from a sqlite_func structure and return a ** pointer to it. ** ** This routine is defined here in vdbe.c because it depends on knowing ** the internals of the sqlite_func structure which is only defined in ** this source file. */ void *sqlite_user_data(sqlite_func *p){ assert( p && p->pFunc ); return p->pFunc->pUserData; } /* ** Allocate or return the aggregate context for a user function. A new ** context is allocated on the first call. Subsequent calls return the ** same context that was returned on prior calls. ** ** This routine is defined here in vdbe.c because it depends on knowing ** the internals of the sqlite_func structure which is only defined in ** this source file. */ void *sqlite_aggregate_context(sqlite_func *p, int nByte){ assert( p && p->pFunc && p->pFunc->xStep ); if( p->pAgg==0 ){ if( nByte<=NBFS ){ p->pAgg = (void*)p->z; }else{ p->pAgg = sqliteMalloc( nByte ); } } return p->pAgg; } /* ** Return the number of times the Step function of a aggregate has been ** called. ** ** This routine is defined here in vdbe.c because it depends on knowing ** the internals of the sqlite_func structure which is only defined in ** this source file. */ int sqlite_aggregate_count(sqlite_func *p){ assert( p && p->pFunc && p->pFunc->xStep ); return p->cnt; } /* |
︙ | ︙ | |||
719 720 721 722 723 724 725 | pAgg->apFunc = 0; pAgg->pCurrent = 0; pAgg->pSearch = 0; pAgg->nMem = 0; } /* | | > | 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 | pAgg->apFunc = 0; pAgg->pCurrent = 0; pAgg->pSearch = 0; pAgg->nMem = 0; } /* ** Insert a new aggregate element and make it the element that ** has focus. ** ** Return 0 on success and 1 if memory is exhausted. */ static int AggInsert(Agg *p, char *zKey, int nKey){ AggElem *pElem, *pOld; int i; pElem = sqliteMalloc( sizeof(AggElem) + nKey + |
︙ | ︙ | |||
1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 | ** What follows is a massive switch statement where each case implements a ** separate instruction in the virtual machine. If we follow the usual ** indentation conventions, each case should be indented by 6 spaces. But ** that is a lot of wasted space on the left margin. So the code within ** the switch statement will break with convention and be flush-left. Another ** big comment (similar to this one) will mark the point in the code where ** we transition back to normal indentation. *****************************************************************************/ /* Opcode: Goto * P2 * ** ** An unconditional jump to address P2. ** The next instruction executed will be ** the one at index P2 from the beginning of | > > > > > > > > > > > > > > > > > > | 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 | ** What follows is a massive switch statement where each case implements a ** separate instruction in the virtual machine. If we follow the usual ** indentation conventions, each case should be indented by 6 spaces. But ** that is a lot of wasted space on the left margin. So the code within ** the switch statement will break with convention and be flush-left. Another ** big comment (similar to this one) will mark the point in the code where ** we transition back to normal indentation. ** ** The formatting of each case is important. The makefile for SQLite ** generates two C files "opcodes.h" and "opcodes.c" by scanning this ** file looking for lines that begin with "case OP_". The opcodes.h files ** will be filled with #defines that give unique integer values to each ** opcode and the opcodes.c file is filled with an array of strings where ** each string is the symbolic name for the corresponding opcode. ** ** Documentation about VDBE opcodes is generated by scanning this file ** for lines of that contain "Opcode:". That line and all subsequent ** comment lines are used in the generation of the opcode.html documentation ** file. ** ** SUMMARY: ** ** Formatting is important to scripts that scan this file. ** Do not deviate from the formatting style currently in use. ** *****************************************************************************/ /* Opcode: Goto * P2 * ** ** An unconditional jump to address P2. ** The next instruction executed will be ** the one at index P2 from the beginning of |
︙ | ︙ | |||
1600 1601 1602 1603 1604 1605 1606 | break; } /* Opcode: Push P1 * * ** ** Overwrite the value of the P1-th element down on the ** stack (P1==0 is the top of the stack) with the value | | | 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 | break; } /* Opcode: Push P1 * * ** ** Overwrite the value of the P1-th element down on the ** stack (P1==0 is the top of the stack) with the value ** of the top of the stack. Then pop the top of the stack. */ case OP_Push: { int from = p->tos; int to = p->tos - pOp->p1; VERIFY( if( to<0 ) goto not_enough_stack; ) if( aStack[to].flags & STK_Dyn ){ |
︙ | ︙ | |||
3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 | ** the format of the data.) ** Push onto the stack the value of the P2-th column contained ** in the data. ** ** If the KeyAsData opcode has previously executed on this cursor, ** then the field might be extracted from the key rather than the ** data. */ case OP_Column: { int amt, offset, end, payloadSize; int i = pOp->p1; int p2 = pOp->p2; int tos = p->tos+1; Cursor *pC; BtCursor *pCrsr; int idxWidth; unsigned char aHdr[10]; | > > > > > > > < > > > > > | | < < < < > > | | | | | | | | | | | | | | | | | | | | | | > > > | > > > | | | | | | | | | | | | | | | | | | | | | > | > > > < | > > > | > > < < < | 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 | ** the format of the data.) ** Push onto the stack the value of the P2-th column contained ** in the data. ** ** If the KeyAsData opcode has previously executed on this cursor, ** then the field might be extracted from the key rather than the ** data. ** ** If P1 is negative, then the record is stored on the stack rather ** than in a table. For P1==-1, the top of the stack is used. ** For P1==-2, the next on the stack is used. And so forth. The ** value pushed is always just a pointer into the record which is ** stored further down on the stack. The column value is not copied. */ case OP_Column: { int amt, offset, end, payloadSize; int i = pOp->p1; int p2 = pOp->p2; int tos = p->tos+1; Cursor *pC; char *zRec; BtCursor *pCrsr; int idxWidth; unsigned char aHdr[10]; VERIFY( if( NeedStack(p, tos+1) ) goto no_mem; ) if( i<0 ){ VERIFY( if( tos+i<0 ) goto bad_instruction; ) VERIFY( if( (aStack[tos+i].flags & STK_Str)==0 ) goto bad_instruction; ) zRec = zStack[tos+i]; payloadSize = aStack[tos+i].n; }else if( VERIFY( i>=0 && i<p->nCursor && ) (pC = &p->aCsr[i])->pCursor!=0 ){ zRec = 0; pCrsr = pC->pCursor; if( pC->nullRow ){ payloadSize = 0; }else if( pC->keyAsData ){ sqliteBtreeKeySize(pCrsr, &payloadSize); }else{ sqliteBtreeDataSize(pCrsr, &payloadSize); } }else{ payloadSize = 0; } /* Figure out how many bytes in the column data and where the column ** data begins. */ if( payloadSize==0 ){ aStack[tos].flags = STK_Null; p->tos = tos; break; }else if( payloadSize<256 ){ idxWidth = 1; }else if( payloadSize<65536 ){ idxWidth = 2; }else{ idxWidth = 3; } /* Figure out where the requested column is stored and how big it is. */ if( payloadSize < idxWidth*(p2+1) ){ rc = SQLITE_CORRUPT; goto abort_due_to_error; } if( zRec ){ memcpy(aHdr, &zRec[idxWidth*p2], idxWidth*2); }else if( pC->keyAsData ){ sqliteBtreeKey(pCrsr, idxWidth*p2, idxWidth*2, (char*)aHdr); }else{ sqliteBtreeData(pCrsr, idxWidth*p2, idxWidth*2, (char*)aHdr); } offset = aHdr[0]; end = aHdr[idxWidth]; if( idxWidth>1 ){ offset |= aHdr[1]<<8; end |= aHdr[idxWidth+1]<<8; if( idxWidth>2 ){ offset |= aHdr[2]<<16; end |= aHdr[idxWidth+2]<<16; } } amt = end - offset; if( amt<0 || offset<0 || end>payloadSize ){ rc = SQLITE_CORRUPT; goto abort_due_to_error; } /* amt and offset now hold the offset to the start of data and the ** amount of data. Go get the data and put it on the stack. */ if( amt==0 ){ aStack[tos].flags = STK_Null; }else if( zRec ){ aStack[tos].flags = STK_Str | STK_Static; aStack[tos].n = amt; zStack[tos] = &zRec[offset]; }else{ if( amt<=NBFS ){ aStack[tos].flags = STK_Str; zStack[tos] = aStack[tos].z; aStack[tos].n = amt; }else{ char *z = sqliteMalloc( amt ); if( z==0 ) goto no_mem; aStack[tos].flags = STK_Str | STK_Dyn; zStack[tos] = z; aStack[tos].n = amt; } if( pC->keyAsData ){ sqliteBtreeKey(pCrsr, offset, amt, zStack[tos]); }else{ sqliteBtreeData(pCrsr, offset, amt, zStack[tos]); } } p->tos = tos; break; } /* Opcode: Recno P1 * * ** ** Push onto the stack an integer which is the first 4 bytes of the ** the key to the current entry in a sequential scan of the database ** file P1. The sequential scan should have been started using the ** Next opcode. */ |
︙ | ︙ |
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.6 2002/09/08 17:23:45 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Build some test data # set fd [open data1.txt w] |
︙ | ︙ | |||
113 114 115 116 117 118 119 120 | 'abcdefghijklmnopqrstuvwyxz ABCDEFGHIJKLMNOPQRSTUVWYXZ' || x || 'abcdefghijklmnopqrstuvwyxz ABCDEFGHIJKLMNOPQRSTUVWYXZ' || x AS y FROM t3 LIMIT 1000; SELECT x FROM t4 ORDER BY y DESC LIMIT 1 OFFSET 999; } } {1000} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 | 'abcdefghijklmnopqrstuvwyxz ABCDEFGHIJKLMNOPQRSTUVWYXZ' || x || 'abcdefghijklmnopqrstuvwyxz ABCDEFGHIJKLMNOPQRSTUVWYXZ' || x AS y FROM t3 LIMIT 1000; SELECT x FROM t4 ORDER BY y DESC LIMIT 1 OFFSET 999; } } {1000} do_test limit-5.1 { execsql { CREATE TABLE t5(x,y); INSERT INTO t5 SELECT x-y, x+y FROM t1 WHERE x BETWEEN 10 AND 15 ORDER BY x LIMIT 2; SELECT * FROM t5 ORDER BY x; } } {5 15 6 16} do_test limit-5.2 { execsql { DELETE FROM t5; INSERT INTO t5 SELECT x-y, x+y FROM t1 WHERE x BETWEEN 10 AND 15 ORDER BY x DESC LIMIT 2; SELECT * FROM t5 ORDER BY x; } } {9 19 10 20} do_test limit-5.3 { execsql { DELETE FROM t5; INSERT INTO t5 SELECT x-y, x+y FROM t1 WHERE x ORDER BY x DESC LIMIT 31; SELECT * FROM t5 ORDER BY x LIMIT 2; } } {-4 6 -3 7} do_test limit-5.4 { execsql { SELECT * FROM t5 ORDER BY x DESC, y DESC LIMIT 2; } } {21 41 21 39} do_test limit-5.5 { execsql { DELETE FROM t5; INSERT INTO t5 SELECT a.x*100+b.x, a.y*100+b.y FROM t1 AS a, t1 AS b ORDER BY 1, 2 LIMIT 1000; SELECT count(*), sum(x), sum(y), min(x), max(x), min(y), max(y) FROM t5; } } {1000 1528204 593161 0 3107 505 1005} finish_test |