Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Modify OP_RegMakeRec to take a base register and count and optionally store results in the register specified by P3. (CVS 4689) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
6bb1b1bc1858028b743a4f660d42d5e9 |
User & Date: | drh 2008-01-05 18:48:24.000 |
Context
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) | |
18:44 | Fix a memory leak introduced with #4687. (CVS 4688) (check-in: 2b98b0fca8 user: danielk1977 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.460 2008/01/05 18:48:24 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 | ** ** 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 = {SRT_Table, 0, 1}; Table *pSelTab; sqlite3VdbeAddOp0(v, OP_Copy); sqlite3VdbeAddOp3(v, OP_OpenWrite, 1, 0, iDb); pParse->nTab = 2; sqlite3Select(pParse, pSelect, &dest, 0, 0, 0, 0); sqlite3VdbeAddOp1(v, OP_Close, 1); if( pParse->nErr==0 ){ |
︙ | ︙ |
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.389 2008/01/05 18:48:24 drh Exp $ */ #include "sqliteInt.h" /* ** Delete all the content of a Select structure but do not deallocate ** the select structure itself. |
︙ | ︙ | |||
459 460 461 462 463 464 465 466 467 | ** A jump to addrRepeat is made and the N+1 values are popped from the ** stack if the top N elements are not distinct. */ static void codeDistinct( Vdbe *v, /* Generate code into this VM */ int iTab, /* A sorting index used to test for distinctness */ int addrRepeat, /* Jump to here if not distinct */ int iMem /* First element */ ){ | > | | 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 | ** A jump to addrRepeat is made and the N+1 values are popped from the ** stack if the top N elements are not distinct. */ static void codeDistinct( Vdbe *v, /* Generate code into this VM */ int iTab, /* A sorting index used to test for distinctness */ int addrRepeat, /* Jump to here if not distinct */ int N, /* Number of elements */ int iMem /* First element */ ){ sqlite3VdbeAddOp2(v, OP_RegMakeRec, iMem, N); sqlite3VdbeAddOp2(v, OP_Distinct, iTab, sqlite3VdbeCurrentAddr(v)+3); sqlite3VdbeAddOp2(v, OP_Pop, 1, 0); sqlite3VdbeAddOp2(v, OP_Goto, 0, addrRepeat); VdbeComment((v, "skip indistinct records")); sqlite3VdbeAddOp2(v, OP_IdxInsert, iTab, 0); } |
︙ | ︙ | |||
537 538 539 540 541 542 543 | /* Pull the requested columns. */ if( nColumn>0 ){ n = nColumn; }else{ n = pEList->nExpr; } | | | < | | | | | | | | | | | | | | 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 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 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 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 690 691 692 | /* Pull the requested columns. */ if( nColumn>0 ){ n = nColumn; }else{ n = pEList->nExpr; } 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. */ for(i=0; i<n; i++){ sqlite3ExprCode(pParse, pEList->a[i].pExpr, iMem+i); } } nColumn = n; /* If the DISTINCT keyword was present on the SELECT statement ** and this row has been seen before, then do not make this row ** part of the result. */ if( hasDistinct ){ assert( pEList!=0 ); assert( pEList->nExpr==nColumn ); codeDistinct(v, distinct, iContinue, nColumn, iMem); if( pOrderBy==0 ){ codeOffset(v, p, iContinue, nColumn); } } if( checkForMultiColumnSelectError(pParse, pDest, pEList->nExpr) ){ return 0; } switch( eDest ){ /* In this mode, write each query result to the key of the temporary ** table iParm. */ #ifndef SQLITE_OMIT_COMPOUND_SELECT case SRT_Union: { sqlite3VdbeAddOp2(v, OP_RegMakeRec, iMem, nColumn); if( aff ){ sqlite3VdbeChangeP4(v, -1, aff, P4_STATIC); } sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, 0); break; } /* Construct a record from the query result, but instead of ** saving that record, use it as a key to delete elements from ** the temporary table iParm. */ case SRT_Except: { int addr; addr = sqlite3VdbeAddOp2(v, OP_RegMakeRec, iMem, nColumn); sqlite3VdbeChangeP4(v, -1, aff, P4_STATIC); sqlite3VdbeAddOp2(v, OP_NotFound, iParm, addr+3); sqlite3VdbeAddOp2(v, OP_Delete, iParm, 0); break; } #endif /* Store the result as data using a unique key. */ case SRT_Table: case SRT_EphemTab: { sqlite3VdbeAddOp2(v, OP_RegMakeRec, iMem, nColumn); if( pOrderBy ){ pushOntoSorter(pParse, pOrderBy, p); }else{ sqlite3VdbeAddOp1(v, OP_NewRowid, iParm); sqlite3VdbeAddOp2(v, OP_Pull, 1, 0); sqlite3CodeInsert(pParse, iParm, OPFLAG_APPEND); } break; } #ifndef SQLITE_OMIT_SUBQUERY /* If we are creating a set for an "expr IN (SELECT ...)" construct, ** then there should be a single item on the stack. Write this ** item into the set table with bogus data. */ case SRT_Set: { int addr2; assert( nColumn==1 ); addr2 = sqlite3VdbeAddOp2(v, OP_IfMemNull, iMem, 0); p->affinity = sqlite3CompareAffinity(pEList->a[0].pExpr, pDest->affinity); if( pOrderBy ){ /* At first glance you would think we could optimize out the ** ORDER BY in this case since the order of entries in the set ** does not matter. But there might be a LIMIT clause, in which ** case the order does matter */ sqlite3VdbeAddOp2(v, OP_SCopy, iMem, 0); pushOntoSorter(pParse, pOrderBy, p); }else{ sqlite3VdbeAddOp4(v, OP_RegMakeRec, iMem, 1, 0, &p->affinity, 1); sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, 0); } sqlite3VdbeJumpHere(v, addr2); break; } /* If any row exist in the result set, record that fact and abort. */ case SRT_Exists: { sqlite3VdbeAddOp2(v, OP_Integer, 1, iParm); /* The LIMIT clause will terminate the loop for us */ break; } /* If this is a scalar select that is part of an expression, then ** store the results in the appropriate memory cell and break out ** of the scan loop. */ case SRT_Mem: { assert( nColumn==1 ); sqlite3VdbeAddOp2(v, OP_SCopy, iMem, 0); if( pOrderBy ){ pushOntoSorter(pParse, pOrderBy, p); }else{ sqlite3VdbeAddOp2(v, OP_Move, 0, iParm); /* The LIMIT clause will jump out of the loop for us */ } break; } #endif /* #ifndef SQLITE_OMIT_SUBQUERY */ /* Send the data to the callback function or to a subroutine. In the ** case of a subroutine, the subroutine itself is responsible for ** popping the data from the stack. */ case SRT_Subroutine: case SRT_Callback: { if( pOrderBy ){ sqlite3VdbeAddOp2(v, OP_RegMakeRec, iMem, nColumn); pushOntoSorter(pParse, pOrderBy, p); }else if( eDest==SRT_Subroutine ){ for(i=0; i<nColumn; i++) sqlite3VdbeAddOp2(v, OP_SCopy, iMem+i, 0); sqlite3VdbeAddOp2(v, OP_Gosub, 0, iParm); }else{ sqlite3VdbeAddOp2(v, OP_ResultRow, iMem, nColumn); } break; } #if !defined(SQLITE_OMIT_TRIGGER) /* Discard the results. This is used for SELECT statements inside ** the body of a TRIGGER. The purpose of such selects is to call |
︙ | ︙ |
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.640 2008/01/05 18:48:24 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 |
︙ | ︙ | |||
1349 1350 1351 1352 1353 1354 1355 | /* ** A structure used to customize the behaviour of sqlite3Select(). See ** comments above sqlite3Select() for details. */ typedef struct SelectDest SelectDest; struct SelectDest { | | > < | 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 | /* ** A structure used to customize the behaviour of sqlite3Select(). See ** 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. ** |
︙ | ︙ |
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.685 2008/01/05 18:48:24 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> #include "vdbeInt.h" /* ** The following global variable is incremented every time a cursor |
︙ | ︙ | |||
2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 | } } if( pOp->p1>0 ){ popStack(&pTos, pOp->p1); } break; } /* Opcode: NotNull P1 P2 * ** ** Jump to P2 if the top abs(P1) values on the stack are all not NULL. ** Regardless of whether or not the jump is taken, pop the stack ** P1 times if P1 is greater than zero. But if P1 is negative, ** leave the stack unchanged. | > > > > > > > > > > > > > > > > > > > | 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 | } } if( pOp->p1>0 ){ popStack(&pTos, pOp->p1); } break; } /* Opcode: AnyNull P1 P2 P3 * * ** ** Check P3 registers beginning with P1. If any are NULL then jump ** to P2. */ case OP_AnyNull: { /* no-push, jump, in1 */ int n = pOp->p3; assert( n>0 && pOp->p1+n<=p->nMem ); while( n>0 ){ if( pIn1->flags & MEM_Null ){ pc = pOp->p2-1; break; } n--; pIn1++; } break; } /* Opcode: NotNull P1 P2 * ** ** Jump to P2 if the top abs(P1) values on the stack are all not NULL. ** Regardless of whether or not the jump is taken, pop the stack ** P1 times if P1 is greater than zero. But if P1 is negative, ** leave the stack unchanged. |
︙ | ︙ | |||
2459 2460 2461 2462 2463 2464 2465 | ** ** This opcode works just OP_MakeRecord except that it reads an extra ** integer from the stack (thus reading a total of abs(P1+1) entries) ** and appends that extra integer to the end of the record as a varint. ** This results in an index key. */ /* | | | < < | > > > | 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 | ** ** This opcode works just OP_MakeRecord except that it reads an extra ** integer from the stack (thus reading a total of abs(P1+1) entries) ** and appends that extra integer to the end of the record as a varint. ** This results in an index key. */ /* ** Opcode: RegMakeRec P1 P2 P3 P4 * ** ** Builds a record like OP_MakeRecord. But the data is taken from ** P2 registers beginning with P1: P1, P1+1, P1+2, ..., P1+P2-1. ** The result is written into P3 or pushed onto the stack if P3 is zero. ** There is no jump on NULL - that can be done with a separate ** OP_AnyNull opcode. */ /* ** Opcode: RegMakeIRec P1 P2 P4 ** ** Works like OP_MakeIdxRec except data is taken from registers ** rather than from the stack. The P1 register is an integer which ** is the number of register to use in building the new record. |
︙ | ︙ | |||
2522 2523 2524 2525 2526 2527 2528 | assert( pOp->opcode==OP_MakeRecord || pOp->opcode==OP_MakeIdxRec ); leaveOnStack = 1; nField = -pOp->p1; }else{ leaveOnStack = 0; nField = pOp->p1; } | < < | | < | < | > | 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 | assert( pOp->opcode==OP_MakeRecord || pOp->opcode==OP_MakeIdxRec ); leaveOnStack = 1; nField = -pOp->p1; }else{ leaveOnStack = 0; nField = pOp->p1; } addRowid = pOp->opcode==OP_MakeIdxRec || pOp->opcode==OP_RegMakeIRec; zAffinity = pOp->p4.z; if( pOp->opcode==OP_RegMakeRec || pOp->opcode==OP_RegMakeIRec ){ assert( nField>0 && pOp->p2>0 && pOp->p2+nField<=p->nMem ); pData0 = &p->aMem[nField]; nField = pOp->p2; leaveOnStack = 1; jumpIfNull = 0; pLast = &pData0[nField-1]; }else{ jumpIfNull = pOp->p2; pData0 = &pTos[1-nField]; pLast = pTos; assert( pData0>=p->aStack ); } containsNull = 0; file_format = p->minWriteFileFormat; |
︙ | ︙ | |||
2626 2627 2628 2629 2630 2631 2632 | } assert( i==nByte ); /* Pop entries off the stack if required. Push the new record on. */ if( !leaveOnStack ){ popStack(&pTos, nField+addRowid); } | > | > > > > | | | | | | | | | | | 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 | } assert( i==nByte ); /* Pop entries off the stack if required. Push the new record on. */ if( !leaveOnStack ){ popStack(&pTos, nField+addRowid); } if( pOp->p3==0 ){ pOut = ++pTos; }else{ pOut = &p->aMem[pOp->p3]; Release(pOut); } pOut->n = nByte; if( nByte<=sizeof(zTemp) ){ assert( zNewRecord==(unsigned char *)zTemp ); pOut->z = pOut->zShort; memcpy(pOut->zShort, zTemp, nByte); pOut->flags = MEM_Blob | MEM_Short; }else{ assert( zNewRecord!=(unsigned char *)zTemp ); pOut->z = (char*)zNewRecord; pOut->flags = MEM_Blob | MEM_Dyn; 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; } |
︙ | ︙ |