/ Check-in [6bb1b1bc]
Login

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 | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 6bb1b1bc1858028b743a4f660d42d5e9595dc022
User & Date: drh 2008-01-05 18:48:24
Context
2008-01-06
00:25
Registerify the SRT_Subroutine destination for SELECT results. (CVS 4690) check-in: 8201f717 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: 6bb1b1bc user: drh tags: trunk
18:44
Fix a memory leak introduced with #4687. (CVS 4688) check-in: 2b98b0fc user: danielk1977 tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/build.c.

    18     18   **     CREATE INDEX
    19     19   **     DROP INDEX
    20     20   **     creating ID lists
    21     21   **     BEGIN TRANSACTION
    22     22   **     COMMIT
    23     23   **     ROLLBACK
    24     24   **
    25         -** $Id: build.c,v 1.459 2008/01/05 05:20:10 drh Exp $
           25  +** $Id: build.c,v 1.460 2008/01/05 18:48:24 drh Exp $
    26     26   */
    27     27   #include "sqliteInt.h"
    28     28   #include <ctype.h>
    29     29   
    30     30   /*
    31     31   ** This routine is called when a new SQL statement is beginning to
    32     32   ** be parsed.  Initialize the pParse structure as needed.
................................................................................
  1487   1487       **
  1488   1488       ** A shared-cache write-lock is not required to write to the new table,
  1489   1489       ** as a schema-lock must have already been obtained to create it. Since
  1490   1490       ** a schema-lock excludes all other database users, the write-lock would
  1491   1491       ** be redundant.
  1492   1492       */
  1493   1493       if( pSelect ){
  1494         -      SelectDest dest = {SRT_Table, 1, 0};
         1494  +      SelectDest dest = {SRT_Table, 0, 1};
  1495   1495         Table *pSelTab;
  1496   1496         sqlite3VdbeAddOp0(v, OP_Copy);
  1497   1497         sqlite3VdbeAddOp3(v, OP_OpenWrite, 1, 0, iDb);
  1498   1498         pParse->nTab = 2;
  1499   1499         sqlite3Select(pParse, pSelect, &dest, 0, 0, 0, 0);
  1500   1500         sqlite3VdbeAddOp1(v, OP_Close, 1);
  1501   1501         if( pParse->nErr==0 ){

Changes to src/select.c.

     8      8   **    May you find forgiveness for yourself and forgive others.
     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12     12   ** This file contains C code routines that are called by the parser
    13     13   ** to handle SELECT statements in SQLite.
    14     14   **
    15         -** $Id: select.c,v 1.388 2008/01/05 18:44:29 danielk1977 Exp $
           15  +** $Id: select.c,v 1.389 2008/01/05 18:48:24 drh Exp $
    16     16   */
    17     17   #include "sqliteInt.h"
    18     18   
    19     19   
    20     20   /*
    21     21   ** Delete all the content of a Select structure but do not deallocate
    22     22   ** the select structure itself.
................................................................................
   459    459   ** A jump to addrRepeat is made and the N+1 values are popped from the
   460    460   ** stack if the top N elements are not distinct.
   461    461   */
   462    462   static void codeDistinct(
   463    463     Vdbe *v,           /* Generate code into this VM */
   464    464     int iTab,          /* A sorting index used to test for distinctness */
   465    465     int addrRepeat,    /* Jump to here if not distinct */
          466  +  int N,             /* Number of elements */
   466    467     int iMem           /* First element */
   467    468   ){
   468         -  sqlite3VdbeAddOp2(v, OP_RegMakeRec, iMem, 0);
          469  +  sqlite3VdbeAddOp2(v, OP_RegMakeRec, iMem, N);
   469    470     sqlite3VdbeAddOp2(v, OP_Distinct, iTab, sqlite3VdbeCurrentAddr(v)+3);
   470    471     sqlite3VdbeAddOp2(v, OP_Pop, 1, 0);
   471    472     sqlite3VdbeAddOp2(v, OP_Goto, 0, addrRepeat);
   472    473     VdbeComment((v, "skip indistinct records"));
   473    474     sqlite3VdbeAddOp2(v, OP_IdxInsert, iTab, 0);
   474    475   }
   475    476   
................................................................................
   537    538     /* Pull the requested columns.
   538    539     */
   539    540     if( nColumn>0 ){
   540    541       n = nColumn;
   541    542     }else{
   542    543       n = pEList->nExpr;
   543    544     }
   544         -  iMem = ++pParse->nMem;
   545         -  pParse->nMem += n+1;
   546         -  sqlite3VdbeAddOp2(v, OP_Integer, n, iMem);
          545  +  iMem = pParse->nMem+1;
          546  +  pParse->nMem += n;
   547    547     if( nColumn>0 ){
   548    548       for(i=0; i<nColumn; i++){
   549         -      sqlite3VdbeAddOp3(v, OP_Column, srcTab, i, iMem+i+1);
          549  +      sqlite3VdbeAddOp3(v, OP_Column, srcTab, i, iMem+i);
   550    550       }
   551    551     }else if( eDest!=SRT_Exists ){
   552    552       /* If the destination is an EXISTS(...) expression, the actual
   553    553       ** values returned by the SELECT are not required.
   554    554       */
   555    555       for(i=0; i<n; i++){
   556         -      sqlite3ExprCode(pParse, pEList->a[i].pExpr, iMem+i+1);
          556  +      sqlite3ExprCode(pParse, pEList->a[i].pExpr, iMem+i);
   557    557       }
   558    558     }
   559    559     nColumn = n;
   560    560   
   561    561     /* If the DISTINCT keyword was present on the SELECT statement
   562    562     ** and this row has been seen before, then do not make this row
   563    563     ** part of the result.
   564    564     */
   565    565     if( hasDistinct ){
   566    566       assert( pEList!=0 );
   567    567       assert( pEList->nExpr==nColumn );
   568         -    codeDistinct(v, distinct, iContinue, iMem);
          568  +    codeDistinct(v, distinct, iContinue, nColumn, iMem);
   569    569       if( pOrderBy==0 ){
   570    570         codeOffset(v, p, iContinue, nColumn);
   571    571       }
   572    572     }
   573    573   
   574    574     if( checkForMultiColumnSelectError(pParse, pDest, pEList->nExpr) ){
   575    575       return 0;
................................................................................
   577    577   
   578    578     switch( eDest ){
   579    579       /* In this mode, write each query result to the key of the temporary
   580    580       ** table iParm.
   581    581       */
   582    582   #ifndef SQLITE_OMIT_COMPOUND_SELECT
   583    583       case SRT_Union: {
   584         -      sqlite3VdbeAddOp2(v, OP_RegMakeRec, iMem, 0);
          584  +      sqlite3VdbeAddOp2(v, OP_RegMakeRec, iMem, nColumn);
   585    585         if( aff ){
   586    586           sqlite3VdbeChangeP4(v, -1, aff, P4_STATIC);
   587    587         }
   588    588         sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, 0);
   589    589         break;
   590    590       }
   591    591   
   592    592       /* Construct a record from the query result, but instead of
   593    593       ** saving that record, use it as a key to delete elements from
   594    594       ** the temporary table iParm.
   595    595       */
   596    596       case SRT_Except: {
   597    597         int addr;
   598         -      addr = sqlite3VdbeAddOp2(v, OP_RegMakeRec, iMem, 0);
          598  +      addr = sqlite3VdbeAddOp2(v, OP_RegMakeRec, iMem, nColumn);
   599    599         sqlite3VdbeChangeP4(v, -1, aff, P4_STATIC);
   600    600         sqlite3VdbeAddOp2(v, OP_NotFound, iParm, addr+3);
   601    601         sqlite3VdbeAddOp2(v, OP_Delete, iParm, 0);
   602    602         break;
   603    603       }
   604    604   #endif
   605    605   
   606    606       /* Store the result as data using a unique key.
   607    607       */
   608    608       case SRT_Table:
   609    609       case SRT_EphemTab: {
   610         -      sqlite3VdbeAddOp2(v, OP_RegMakeRec, iMem, 0);
          610  +      sqlite3VdbeAddOp2(v, OP_RegMakeRec, iMem, nColumn);
   611    611         if( pOrderBy ){
   612    612           pushOntoSorter(pParse, pOrderBy, p);
   613    613         }else{
   614    614           sqlite3VdbeAddOp1(v, OP_NewRowid, iParm);
   615    615           sqlite3VdbeAddOp2(v, OP_Pull, 1, 0);
   616    616           sqlite3CodeInsert(pParse, iParm, OPFLAG_APPEND);
   617    617         }
................................................................................
   623    623       ** then there should be a single item on the stack.  Write this
   624    624       ** item into the set table with bogus data.
   625    625       */
   626    626       case SRT_Set: {
   627    627         int addr2;
   628    628   
   629    629         assert( nColumn==1 );
   630         -      addr2 = sqlite3VdbeAddOp2(v, OP_IfMemNull, iMem+1, 0);
          630  +      addr2 = sqlite3VdbeAddOp2(v, OP_IfMemNull, iMem, 0);
   631    631         p->affinity = sqlite3CompareAffinity(pEList->a[0].pExpr, pDest->affinity);
   632    632         if( pOrderBy ){
   633    633           /* At first glance you would think we could optimize out the
   634    634           ** ORDER BY in this case since the order of entries in the set
   635    635           ** does not matter.  But there might be a LIMIT clause, in which
   636    636           ** case the order does matter */
   637         -        sqlite3VdbeAddOp2(v, OP_SCopy, iMem+1, 0);
          637  +        sqlite3VdbeAddOp2(v, OP_SCopy, iMem, 0);
   638    638           pushOntoSorter(pParse, pOrderBy, p);
   639    639         }else{
   640         -        sqlite3VdbeAddOp4(v, OP_RegMakeRec, iMem, 0, 0, &p->affinity, 1);
          640  +        sqlite3VdbeAddOp4(v, OP_RegMakeRec, iMem, 1, 0, &p->affinity, 1);
   641    641           sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, 0);
   642    642         }
   643    643         sqlite3VdbeJumpHere(v, addr2);
   644    644         break;
   645    645       }
   646    646   
   647    647       /* If any row exist in the result set, record that fact and abort.
................................................................................
   654    654   
   655    655       /* If this is a scalar select that is part of an expression, then
   656    656       ** store the results in the appropriate memory cell and break out
   657    657       ** of the scan loop.
   658    658       */
   659    659       case SRT_Mem: {
   660    660         assert( nColumn==1 );
   661         -      sqlite3VdbeAddOp2(v, OP_SCopy, iMem+1, 0);
          661  +      sqlite3VdbeAddOp2(v, OP_SCopy, iMem, 0);
   662    662         if( pOrderBy ){
   663    663           pushOntoSorter(pParse, pOrderBy, p);
   664    664         }else{
   665    665           sqlite3VdbeAddOp2(v, OP_Move, 0, iParm);
   666    666           /* The LIMIT clause will jump out of the loop for us */
   667    667         }
   668    668         break;
................................................................................
   672    672       /* Send the data to the callback function or to a subroutine.  In the
   673    673       ** case of a subroutine, the subroutine itself is responsible for
   674    674       ** popping the data from the stack.
   675    675       */
   676    676       case SRT_Subroutine:
   677    677       case SRT_Callback: {
   678    678         if( pOrderBy ){
   679         -        sqlite3VdbeAddOp2(v, OP_RegMakeRec, iMem, 0);
          679  +        sqlite3VdbeAddOp2(v, OP_RegMakeRec, iMem, nColumn);
   680    680           pushOntoSorter(pParse, pOrderBy, p);
   681    681         }else if( eDest==SRT_Subroutine ){
   682         -        for(i=0; i<nColumn; i++) sqlite3VdbeAddOp2(v, OP_SCopy, iMem+i+1, 0);
          682  +        for(i=0; i<nColumn; i++) sqlite3VdbeAddOp2(v, OP_SCopy, iMem+i, 0);
   683    683           sqlite3VdbeAddOp2(v, OP_Gosub, 0, iParm);
   684    684         }else{
   685         -        sqlite3VdbeAddOp2(v, OP_ResultRow, iMem+1, nColumn);
          685  +        sqlite3VdbeAddOp2(v, OP_ResultRow, iMem, nColumn);
   686    686         }
   687    687         break;
   688    688       }
   689    689   
   690    690   #if !defined(SQLITE_OMIT_TRIGGER)
   691    691       /* Discard the results.  This is used for SELECT statements inside
   692    692       ** the body of a TRIGGER.  The purpose of such selects is to call

Changes to src/sqliteInt.h.

     7      7   **    May you do good and not evil.
     8      8   **    May you find forgiveness for yourself and forgive others.
     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12     12   ** Internal interface definitions for SQLite.
    13     13   **
    14         -** @(#) $Id: sqliteInt.h,v 1.639 2008/01/05 17:39:30 danielk1977 Exp $
           14  +** @(#) $Id: sqliteInt.h,v 1.640 2008/01/05 18:48:24 drh Exp $
    15     15   */
    16     16   #ifndef _SQLITEINT_H_
    17     17   #define _SQLITEINT_H_
    18     18   
    19     19   /*
    20     20   ** The macro unlikely() is a hint that surrounds a boolean
    21     21   ** expression that is usually false.  Macro likely() surrounds
................................................................................
  1349   1349   
  1350   1350   /*
  1351   1351   ** A structure used to customize the behaviour of sqlite3Select(). See
  1352   1352   ** comments above sqlite3Select() for details.
  1353   1353   */
  1354   1354   typedef struct SelectDest SelectDest;
  1355   1355   struct SelectDest {
  1356         -  int eDest;        /* How to dispose of the results */
         1356  +  u8 eDest;         /* How to dispose of the results */
         1357  +  u8 affinity;      /* Affinity used when eDest==SRT_Set */
  1357   1358     int iParm;        /* A parameter used by the eDest disposal method */
  1358         -  int affinity;     /* Affinity used when eDest==SRT_Set */
  1359   1359   };
  1360   1360   
  1361   1361   /*
  1362   1362   ** An SQL parser context.  A copy of this structure is passed through
  1363   1363   ** the parser and down into all the parser action routine in order to
  1364   1364   ** carry around information that is global to the entire parse.
  1365   1365   **

Changes to src/vdbe.c.

    39     39   **
    40     40   ** Various scripts scan this source file in order to generate HTML
    41     41   ** documentation, headers files, or other derived files.  The formatting
    42     42   ** of the code in this file is, therefore, important.  See other comments
    43     43   ** in this file for details.  If in doubt, do not deviate from existing
    44     44   ** commenting and indentation practices when changing or adding code.
    45     45   **
    46         -** $Id: vdbe.c,v 1.684 2008/01/05 16:29:28 drh Exp $
           46  +** $Id: vdbe.c,v 1.685 2008/01/05 18:48:24 drh Exp $
    47     47   */
    48     48   #include "sqliteInt.h"
    49     49   #include <ctype.h>
    50     50   #include "vdbeInt.h"
    51     51   
    52     52   /*
    53     53   ** The following global variable is incremented every time a cursor
................................................................................
  2126   2126       }
  2127   2127     }
  2128   2128     if( pOp->p1>0 ){
  2129   2129       popStack(&pTos, pOp->p1);
  2130   2130     }
  2131   2131     break;
  2132   2132   }
         2133  +
         2134  +/* Opcode: AnyNull P1 P2 P3 * *
         2135  +**
         2136  +** Check P3 registers beginning with P1.  If any are NULL then jump
         2137  +** to P2.
         2138  +*/
         2139  +case OP_AnyNull: {            /* no-push, jump, in1 */
         2140  +  int n = pOp->p3;
         2141  +  assert( n>0 && pOp->p1+n<=p->nMem );
         2142  +  while( n>0 ){
         2143  +    if( pIn1->flags & MEM_Null ){
         2144  +      pc = pOp->p2-1;
         2145  +      break;
         2146  +    }
         2147  +    n--;
         2148  +    pIn1++;
         2149  +  }
         2150  +  break;
         2151  +}
  2133   2152   
  2134   2153   /* Opcode: NotNull P1 P2 *
  2135   2154   **
  2136   2155   ** Jump to P2 if the top abs(P1) values on the stack are all not NULL.  
  2137   2156   ** Regardless of whether or not the jump is taken, pop the stack
  2138   2157   ** P1 times if P1 is greater than zero.  But if P1 is negative,
  2139   2158   ** leave the stack unchanged.
................................................................................
  2459   2478   **
  2460   2479   ** This opcode works just OP_MakeRecord except that it reads an extra
  2461   2480   ** integer from the stack (thus reading a total of abs(P1+1) entries)
  2462   2481   ** and appends that extra integer to the end of the record as a varint.
  2463   2482   ** This results in an index key.
  2464   2483   */
  2465   2484   /*
  2466         -** Opcode: RegMakeRec P1 P2 P4
         2485  +** Opcode: RegMakeRec P1 P2 P3 P4 *
  2467   2486   **
  2468         -** Works like OP_MakeRecord except data is taken from registers
  2469         -** rather than from the stack.  The P1 register is an integer which
  2470         -** is the number of register to use in building the new record.
  2471         -** Data is taken from P1+1, P1+2, ..., P1+mem[P1].
         2487  +** Builds a record like OP_MakeRecord.  But the data is taken from
         2488  +** P2 registers beginning with P1:  P1, P1+1, P1+2, ..., P1+P2-1.
         2489  +** The result is written into P3 or pushed onto the stack if P3 is zero.
         2490  +** There is no jump on NULL - that can be done with a separate
         2491  +** OP_AnyNull opcode.
  2472   2492   */
  2473   2493   /*
  2474   2494   ** Opcode: RegMakeIRec P1 P2 P4
  2475   2495   **
  2476   2496   ** Works like OP_MakeIdxRec except data is taken from registers
  2477   2497   ** rather than from the stack.  The P1 register is an integer which
  2478   2498   ** is the number of register to use in building the new record.
................................................................................
  2522   2542       assert( pOp->opcode==OP_MakeRecord || pOp->opcode==OP_MakeIdxRec );
  2523   2543       leaveOnStack = 1;
  2524   2544       nField = -pOp->p1;
  2525   2545     }else{
  2526   2546       leaveOnStack = 0;
  2527   2547       nField = pOp->p1;
  2528   2548     }
  2529         -  jumpIfNull = pOp->p2;
  2530   2549     addRowid = pOp->opcode==OP_MakeIdxRec || pOp->opcode==OP_RegMakeIRec;
  2531   2550     zAffinity = pOp->p4.z;
  2532   2551   
  2533   2552     if( pOp->opcode==OP_RegMakeRec || pOp->opcode==OP_RegMakeIRec ){
  2534         -    Mem *pCount;
  2535         -    assert( nField>0 && nField<=p->nMem );
  2536         -    pCount = &p->aMem[nField];
  2537         -    assert( pCount->flags & MEM_Int );
  2538         -    assert( pCount->u.i>0 && pCount->u.i+nField<=p->nMem );
         2553  +    assert( nField>0 && pOp->p2>0 && pOp->p2+nField<=p->nMem );
         2554  +    pData0 = &p->aMem[nField];
         2555  +    nField = pOp->p2;
  2539   2556       leaveOnStack = 1;
  2540         -    nField = pCount->u.i;
  2541         -    pData0 = &pCount[1];
         2557  +    jumpIfNull = 0;
  2542   2558       pLast = &pData0[nField-1];
  2543   2559     }else{
         2560  +    jumpIfNull = pOp->p2;
  2544   2561       pData0 = &pTos[1-nField];
  2545   2562       pLast = pTos;
  2546   2563       assert( pData0>=p->aStack );
  2547   2564     }
  2548   2565     containsNull = 0;
  2549   2566     file_format = p->minWriteFileFormat;
  2550   2567   
................................................................................
  2626   2643     }
  2627   2644     assert( i==nByte );
  2628   2645   
  2629   2646     /* Pop entries off the stack if required. Push the new record on. */
  2630   2647     if( !leaveOnStack ){
  2631   2648       popStack(&pTos, nField+addRowid);
  2632   2649     }
  2633         -  pTos++;
  2634         -  pTos->n = nByte;
         2650  +  if( pOp->p3==0 ){
         2651  +    pOut = ++pTos;
         2652  +  }else{
         2653  +    pOut = &p->aMem[pOp->p3];
         2654  +    Release(pOut);
         2655  +  }
         2656  +  pOut->n = nByte;
  2635   2657     if( nByte<=sizeof(zTemp) ){
  2636   2658       assert( zNewRecord==(unsigned char *)zTemp );
  2637         -    pTos->z = pTos->zShort;
  2638         -    memcpy(pTos->zShort, zTemp, nByte);
  2639         -    pTos->flags = MEM_Blob | MEM_Short;
         2659  +    pOut->z = pOut->zShort;
         2660  +    memcpy(pOut->zShort, zTemp, nByte);
         2661  +    pOut->flags = MEM_Blob | MEM_Short;
  2640   2662     }else{
  2641   2663       assert( zNewRecord!=(unsigned char *)zTemp );
  2642         -    pTos->z = (char*)zNewRecord;
  2643         -    pTos->flags = MEM_Blob | MEM_Dyn;
  2644         -    pTos->xDel = 0;
         2664  +    pOut->z = (char*)zNewRecord;
         2665  +    pOut->flags = MEM_Blob | MEM_Dyn;
         2666  +    pOut->xDel = 0;
  2645   2667     }
  2646   2668     if( nZero ){
  2647         -    pTos->u.i = nZero;
  2648         -    pTos->flags |= MEM_Zero;
         2669  +    pOut->u.i = nZero;
         2670  +    pOut->flags |= MEM_Zero;
  2649   2671     }
  2650         -  pTos->enc = SQLITE_UTF8;  /* In case the blob is ever converted to text */
         2672  +  pOut->enc = SQLITE_UTF8;  /* In case the blob is ever converted to text */
  2651   2673   
  2652   2674     /* If a NULL was encountered and jumpIfNull is non-zero, take the jump. */
  2653   2675     if( jumpIfNull && containsNull ){
  2654   2676       pc = jumpIfNull - 1;
  2655   2677     }
  2656   2678     break;
  2657   2679   }