/ Check-in [1e64dd78]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Do away with the "multi-register pseudo-table" abstration. Instead, just use an OP_SCopy to load results directory from the result registers of the co-routine.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 1e64dd782a126f48d78c43a664844a41d0e6334e
User & Date: drh 2014-02-08 23:20:32
References
2014-04-03
16:29
Use OP_Copy instead of OP_SCopy when moving results out of a subquery, to prevent the subquery results from changing out from under the outer query. Fix for ticket [98825a79ce1456]. Problem introduced by check-in [1e64dd782a126f48d78]. check-in: d5513dfa user: drh tags: trunk
16:16
Use OP_Copy instead of OP_SCopy when moving results out of a subquery, to prevent the subquery results from changing out from under the outer query. Fix for ticket [98825a79ce1456]. Problem introduced by check-in [1e64dd782a126f48d78]. check-in: ec6a0624 user: drh tags: branch-3.8.4
15:17 New ticket [98825a79] Incorrect result from a DISTINCT + GROUP BY + ORDER BY query. artifact: b556e7c9 user: drh
Context
2014-02-09
00:18
Add a new "testset" to the speedtest1 program: The sudoku solver. check-in: 4677ef2f user: drh tags: trunk
2014-02-08
23:20
Do away with the "multi-register pseudo-table" abstration. Instead, just use an OP_SCopy to load results directory from the result registers of the co-routine. check-in: 1e64dd78 user: drh tags: trunk
19:12
Change the OP_Found opcode so that it expands zero-blobs prior to comparing them. Fix for ticket [fccbde530a6583b] check-in: e2303d1b user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/select.c.

  4537   4537         /* Implement a co-routine that will return a single row of the result
  4538   4538         ** set on each invocation.
  4539   4539         */
  4540   4540         int addrTop = sqlite3VdbeCurrentAddr(v)+1;
  4541   4541         pItem->regReturn = ++pParse->nMem;
  4542   4542         sqlite3VdbeAddOp3(v, OP_InitCoroutine, pItem->regReturn, 0, addrTop);
  4543   4543         VdbeComment((v, "%s", pItem->pTab->zName));
  4544         -      sqlite3VdbeAddOp1(v, OP_OpenPseudo, pItem->iCursor);
  4545         -      sqlite3VdbeChangeP5(v, 1);
  4546   4544         pItem->addrFillSub = addrTop;
  4547   4545         sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn);
  4548   4546         explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
  4549   4547         sqlite3Select(pParse, pSub, &dest);
  4550   4548         pItem->pTab->nRowEst = (unsigned)pSub->nSelectRow;
  4551   4549         pItem->viaCoroutine = 1;
  4552         -      sqlite3VdbeChangeP2(v, addrTop, dest.iSdst);
  4553         -      sqlite3VdbeChangeP3(v, addrTop, dest.nSdst);
         4550  +      pItem->regResult = dest.iSdst;
  4554   4551         sqlite3VdbeAddOp1(v, OP_EndCoroutine, pItem->regReturn);
  4555   4552         sqlite3VdbeJumpHere(v, addrTop-1);
  4556   4553         sqlite3ClearTempRegCache(pParse);
  4557   4554       }else{
  4558   4555         /* Generate a subroutine that will fill an ephemeral table with
  4559   4556         ** the content of this subquery.  pItem->addrFillSub will point
  4560   4557         ** to the address of the generated subroutine.  pItem->regReturn

Changes to src/sqliteInt.h.

  2015   2015       char *zDatabase;  /* Name of database holding this table */
  2016   2016       char *zName;      /* Name of the table */
  2017   2017       char *zAlias;     /* The "B" part of a "A AS B" phrase.  zName is the "A" */
  2018   2018       Table *pTab;      /* An SQL table corresponding to zName */
  2019   2019       Select *pSelect;  /* A SELECT statement used in place of a table name */
  2020   2020       int addrFillSub;  /* Address of subroutine to manifest a subquery */
  2021   2021       int regReturn;    /* Register holding return address of addrFillSub */
         2022  +    int regResult;    /* Registers holding results of a co-routine */
  2022   2023       u8 jointype;      /* Type of join between this able and the previous */
  2023   2024       unsigned notIndexed :1;    /* True if there is a NOT INDEXED clause */
  2024   2025       unsigned isCorrelated :1;  /* True if sub-query is correlated */
  2025   2026       unsigned viaCoroutine :1;  /* Implemented as a co-routine */
  2026   2027       unsigned isRecursive :1;   /* True for recursive reference in WITH */
  2027   2028   #ifndef SQLITE_OMIT_EXPLAIN
  2028   2029       u8 iSelectId;     /* If pSelect!=0, the id of the sub-select in EQP */

Changes to src/vdbe.c.

  2277   2277     rc = sqlite3VdbeCursorMoveto(pC);
  2278   2278     if( rc ) goto abort_due_to_error;
  2279   2279     if( pC->cacheStatus!=p->cacheCtr || (pOp->p5&OPFLAG_CLEARCACHE)!=0 ){
  2280   2280       if( pC->nullRow ){
  2281   2281         if( pCrsr==0 ){
  2282   2282           assert( pC->pseudoTableReg>0 );
  2283   2283           pReg = &aMem[pC->pseudoTableReg];
  2284         -        if( pC->multiPseudo ){
  2285         -          sqlite3VdbeMemShallowCopy(pDest, pReg+p2, MEM_Ephem);
  2286         -          Deephemeralize(pDest);
  2287         -          goto op_column_out;
  2288         -        }
  2289   2284           assert( pReg->flags & MEM_Blob );
  2290   2285           assert( memIsValid(pReg) );
  2291   2286           pC->payloadSize = pC->szRow = avail = pReg->n;
  2292   2287           pC->aRow = (u8*)pReg->z;
  2293   2288         }else{
  2294   2289           MemSetTypeFlag(pDest, MEM_Null);
  2295   2290           goto op_column_out;
................................................................................
  3350   3345     pCx->pKeyInfo = pOp->p4.pKeyInfo;
  3351   3346     assert( pCx->pKeyInfo->db==db );
  3352   3347     assert( pCx->pKeyInfo->enc==ENC(db) );
  3353   3348     rc = sqlite3VdbeSorterInit(db, pCx);
  3354   3349     break;
  3355   3350   }
  3356   3351   
  3357         -/* Opcode: OpenPseudo P1 P2 P3 * P5
         3352  +/* Opcode: OpenPseudo P1 P2 P3 * *
  3358   3353   ** Synopsis: content in r[P2@P3]
  3359   3354   **
  3360   3355   ** Open a new cursor that points to a fake table that contains a single
  3361         -** row of data.  The content of that one row in the content of memory
  3362         -** register P2 when P5==0.  In other words, cursor P1 becomes an alias for the 
  3363         -** MEM_Blob content contained in register P2.  When P5==1, then the
  3364         -** row is represented by P3 consecutive registers beginning with P2.
         3356  +** row of data.  The content of that one row is the content of memory
         3357  +** register P2.  In other words, cursor P1 becomes an alias for the 
         3358  +** MEM_Blob content contained in register P2.
  3365   3359   **
  3366   3360   ** A pseudo-table created by this opcode is used to hold a single
  3367   3361   ** row output from the sorter so that the row can be decomposed into
  3368   3362   ** individual columns using the OP_Column opcode.  The OP_Column opcode
  3369   3363   ** is the only cursor opcode that works with a pseudo-table.
  3370   3364   **
  3371   3365   ** P3 is the number of fields in the records that will be stored by
................................................................................
  3377   3371     assert( pOp->p1>=0 );
  3378   3372     assert( pOp->p3>=0 );
  3379   3373     pCx = allocateCursor(p, pOp->p1, pOp->p3, -1, 0);
  3380   3374     if( pCx==0 ) goto no_mem;
  3381   3375     pCx->nullRow = 1;
  3382   3376     pCx->pseudoTableReg = pOp->p2;
  3383   3377     pCx->isTable = 1;
  3384         -  pCx->multiPseudo = pOp->p5;
         3378  +  assert( pOp->p5==0 );
  3385   3379     break;
  3386   3380   }
  3387   3381   
  3388   3382   /* Opcode: Close P1 * * * *
  3389   3383   **
  3390   3384   ** Close a cursor previously opened as P1.  If P1 is not
  3391   3385   ** currently open, this instruction is a no-op.

Changes to src/vdbeInt.h.

    71     71     i8 iDb;               /* Index of cursor database in db->aDb[] (or -1) */
    72     72     u8 nullRow;           /* True if pointing to a row with no data */
    73     73     u8 rowidIsValid;      /* True if lastRowid is valid */
    74     74     u8 deferredMoveto;    /* A call to sqlite3BtreeMoveto() is needed */
    75     75     Bool useRandomRowid:1;/* Generate new record numbers semi-randomly */
    76     76     Bool isTable:1;       /* True if a table requiring integer keys */
    77     77     Bool isOrdered:1;     /* True if the underlying table is BTREE_UNORDERED */
    78         -  Bool multiPseudo:1;   /* Multi-register pseudo-cursor */
    79     78     sqlite3_vtab_cursor *pVtabCursor;  /* The cursor for a virtual table */
    80     79     i64 seqCount;         /* Sequence counter */
    81     80     i64 movetoTarget;     /* Argument to the deferred sqlite3BtreeMoveto() */
    82     81     i64 lastRowid;        /* Rowid being deleted by OP_Delete */
    83     82     VdbeSorter *pSorter;  /* Sorter object for OP_SorterOpen cursors */
    84     83   
    85     84     /* Cached information about the header for the data record that the

Changes to src/where.c.

  5831   5831     /* The "break" point is here, just past the end of the outer loop.
  5832   5832     ** Set it.
  5833   5833     */
  5834   5834     sqlite3VdbeResolveLabel(v, pWInfo->iBreak);
  5835   5835   
  5836   5836     assert( pWInfo->nLevel<=pTabList->nSrc );
  5837   5837     for(i=0, pLevel=pWInfo->a; i<pWInfo->nLevel; i++, pLevel++){
         5838  +    int k, last;
         5839  +    VdbeOp *pOp;
  5838   5840       Index *pIdx = 0;
  5839   5841       struct SrcList_item *pTabItem = &pTabList->a[pLevel->iFrom];
  5840   5842       Table *pTab = pTabItem->pTab;
  5841   5843       assert( pTab!=0 );
  5842   5844       pLoop = pLevel->pWLoop;
         5845  +
         5846  +    /* For a co-routine, change all OP_Column references to the table of
         5847  +    ** the co-routine into OP_SCopy of result contained in a register.
         5848  +    ** OP_Rowid becomes OP_Null.
         5849  +    */
         5850  +    if( pTabItem->viaCoroutine ){
         5851  +      last = sqlite3VdbeCurrentAddr(v);
         5852  +      k = pLevel->addrBody;
         5853  +      pOp = sqlite3VdbeGetOp(v, k);
         5854  +      for(; k<last; k++, pOp++){
         5855  +        if( pOp->p1!=pLevel->iTabCur ) continue;
         5856  +        if( pOp->opcode==OP_Column ){
         5857  +          pOp->opcode = OP_SCopy;
         5858  +          pOp->p1 = pOp->p2 + pTabItem->regResult;
         5859  +          pOp->p2 = pOp->p3;
         5860  +          pOp->p3 = 0;
         5861  +        }else if( pOp->opcode==OP_Rowid ){
         5862  +          pOp->opcode = OP_Null;
         5863  +          pOp->p1 = 0;
         5864  +          pOp->p3 = 0;
         5865  +        }
         5866  +      }
         5867  +      continue;
         5868  +    }
  5843   5869   
  5844   5870       /* Close all of the cursors that were opened by sqlite3WhereBegin.
  5845   5871       ** Except, do not close cursors that will be reused by the OR optimization
  5846   5872       ** (WHERE_OMIT_OPEN_CLOSE).  And do not close the OP_OpenWrite cursors
  5847   5873       ** created for the ONEPASS optimization.
  5848   5874       */
  5849   5875       if( (pTab->tabFlags & TF_Ephemeral)==0
................................................................................
  5875   5901       */
  5876   5902       if( pLoop->wsFlags & (WHERE_INDEXED|WHERE_IDX_ONLY) ){
  5877   5903         pIdx = pLoop->u.btree.pIndex;
  5878   5904       }else if( pLoop->wsFlags & WHERE_MULTI_OR ){
  5879   5905         pIdx = pLevel->u.pCovidx;
  5880   5906       }
  5881   5907       if( pIdx && !db->mallocFailed ){
  5882         -      int k, last;
  5883         -      VdbeOp *pOp;
  5884         -
  5885   5908         last = sqlite3VdbeCurrentAddr(v);
  5886   5909         k = pLevel->addrBody;
  5887   5910         pOp = sqlite3VdbeGetOp(v, k);
  5888   5911         for(; k<last; k++, pOp++){
  5889   5912           if( pOp->p1!=pLevel->iTabCur ) continue;
  5890   5913           if( pOp->opcode==OP_Column ){
  5891   5914             int x = pOp->p2;