/ Check-in [ca72be86]
Login
SQLite training in Houston TX on 2019-11-05 (details)
Part of the 2019 Tcl Conference

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

Overview
Comment:Make sure every co-routines has its own set of temporary registers and does not share temporaries, since a co-routine might expect the content of a temporary register to be preserved across an OP_Yield. Proposed fix for ticket [d06a25c84454a].
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: ca72be8618e5d466d6f35819ca8bbd2b84269959
User & Date: drh 2016-02-09 02:12:20
References
2016-02-09
14:12 Fixed ticket [d06a25c8]: Incorrect result from a UNION with an ORDER BY plus 6 other changes artifact: 1ef35260 user: drh
Context
2016-02-09
16:09
Code simplification: ALTER TABLE ADD COLUMN always upgrades the file_format to 4 if is not there already. No need to upgrade to only 2 or 3 since format 4 has now been supported for over 10 years. check-in: e1d8ec85 user: drh tags: trunk
15:50
Merge recent fixes and enhancements from trunk. check-in: f0734017 user: drh tags: apple-osx
15:44
Merge enhancements and fixes from trunk. check-in: f040a5bb user: drh tags: sessions
15:10
Merge latest trunk changes with this branch. check-in: 1a4182ee user: dan tags: schemalint
02:12
Make sure every co-routines has its own set of temporary registers and does not share temporaries, since a co-routine might expect the content of a temporary register to be preserved across an OP_Yield. Proposed fix for ticket [d06a25c84454a]. check-in: ca72be86 user: drh tags: trunk
2016-02-08
20:45
Fix spelling error in MSVC makefile comments. check-in: 6eab74c9 user: mistachkin tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Show Whitespace Changes Patch

Changes to src/build.c.

  1950   1950         sqlite3VdbeAddOp3(v, OP_OpenWrite, 1, pParse->regRoot, iDb);
  1951   1951         sqlite3VdbeChangeP5(v, OPFLAG_P2ISREG);
  1952   1952         pParse->nTab = 2;
  1953   1953         addrTop = sqlite3VdbeCurrentAddr(v) + 1;
  1954   1954         sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop);
  1955   1955         sqlite3SelectDestInit(&dest, SRT_Coroutine, regYield);
  1956   1956         sqlite3Select(pParse, pSelect, &dest);
  1957         -      sqlite3VdbeAddOp1(v, OP_EndCoroutine, regYield);
         1957  +      sqlite3VdbeEndCoroutine(v, regYield);
  1958   1958         sqlite3VdbeJumpHere(v, addrTop - 1);
  1959   1959         if( pParse->nErr ) return;
  1960   1960         pSelTab = sqlite3ResultSetOfSelect(pParse, pSelect);
  1961   1961         if( pSelTab==0 ) return;
  1962   1962         assert( p->aCol==0 );
  1963   1963         p->nCol = pSelTab->nCol;
  1964   1964         p->aCol = pSelTab->aCol;

Changes to src/insert.c.

   681    681       sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop);
   682    682       sqlite3SelectDestInit(&dest, SRT_Coroutine, regYield);
   683    683       dest.iSdst = bIdListInOrder ? regData : 0;
   684    684       dest.nSdst = pTab->nCol;
   685    685       rc = sqlite3Select(pParse, pSelect, &dest);
   686    686       regFromSelect = dest.iSdst;
   687    687       if( rc || db->mallocFailed || pParse->nErr ) goto insert_cleanup;
   688         -    sqlite3VdbeAddOp1(v, OP_EndCoroutine, regYield);
          688  +    sqlite3VdbeEndCoroutine(v, regYield);
   689    689       sqlite3VdbeJumpHere(v, addrTop - 1);                       /* label B: */
   690    690       assert( pSelect->pEList );
   691    691       nColumn = pSelect->pEList->nExpr;
   692    692   
   693    693       /* Set useTempTable to TRUE if the result of the SELECT statement
   694    694       ** should be written into a temporary table (template 4).  Set to
   695    695       ** FALSE if each output row of the SELECT can be written directly into

Changes to src/select.c.

  2948   2948     */
  2949   2949     addrSelectA = sqlite3VdbeCurrentAddr(v) + 1;
  2950   2950     addr1 = sqlite3VdbeAddOp3(v, OP_InitCoroutine, regAddrA, 0, addrSelectA);
  2951   2951     VdbeComment((v, "left SELECT"));
  2952   2952     pPrior->iLimit = regLimitA;
  2953   2953     explainSetInteger(iSub1, pParse->iNextSelectId);
  2954   2954     sqlite3Select(pParse, pPrior, &destA);
  2955         -  sqlite3VdbeAddOp1(v, OP_EndCoroutine, regAddrA);
         2955  +  sqlite3VdbeEndCoroutine(v, regAddrA);
  2956   2956     sqlite3VdbeJumpHere(v, addr1);
  2957   2957   
  2958   2958     /* Generate a coroutine to evaluate the SELECT statement on 
  2959   2959     ** the right - the "B" select
  2960   2960     */
  2961   2961     addrSelectB = sqlite3VdbeCurrentAddr(v) + 1;
  2962   2962     addr1 = sqlite3VdbeAddOp3(v, OP_InitCoroutine, regAddrB, 0, addrSelectB);
................................................................................
  2965   2965     savedOffset = p->iOffset;
  2966   2966     p->iLimit = regLimitB;
  2967   2967     p->iOffset = 0;  
  2968   2968     explainSetInteger(iSub2, pParse->iNextSelectId);
  2969   2969     sqlite3Select(pParse, p, &destB);
  2970   2970     p->iLimit = savedLimit;
  2971   2971     p->iOffset = savedOffset;
  2972         -  sqlite3VdbeAddOp1(v, OP_EndCoroutine, regAddrB);
         2972  +  sqlite3VdbeEndCoroutine(v, regAddrB);
  2973   2973   
  2974   2974     /* Generate a subroutine that outputs the current row of the A
  2975   2975     ** select as the next output row of the compound select.
  2976   2976     */
  2977   2977     VdbeNoopComment((v, "Output routine for A"));
  2978   2978     addrOutA = generateOutputSubroutine(pParse,
  2979   2979                    p, &destA, pDest, regOutA,
................................................................................
  4986   4986         pItem->addrFillSub = addrTop;
  4987   4987         sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn);
  4988   4988         explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
  4989   4989         sqlite3Select(pParse, pSub, &dest);
  4990   4990         pItem->pTab->nRowLogEst = sqlite3LogEst(pSub->nSelectRow);
  4991   4991         pItem->fg.viaCoroutine = 1;
  4992   4992         pItem->regResult = dest.iSdst;
  4993         -      sqlite3VdbeAddOp1(v, OP_EndCoroutine, pItem->regReturn);
         4993  +      sqlite3VdbeEndCoroutine(v, pItem->regReturn);
  4994   4994         sqlite3VdbeJumpHere(v, addrTop-1);
  4995   4995         sqlite3ClearTempRegCache(pParse);
  4996   4996       }else{
  4997   4997         /* Generate a subroutine that will fill an ephemeral table with
  4998   4998         ** the content of this subquery.  pItem->addrFillSub will point
  4999   4999         ** to the address of the generated subroutine.  pItem->regReturn
  5000   5000         ** is a register allocated to hold the subroutine return address

Changes to src/vdbe.h.

   176    176   int sqlite3VdbeGoto(Vdbe*,int);
   177    177   int sqlite3VdbeLoadString(Vdbe*,int,const char*);
   178    178   void sqlite3VdbeMultiLoad(Vdbe*,int,const char*,...);
   179    179   int sqlite3VdbeAddOp3(Vdbe*,int,int,int,int);
   180    180   int sqlite3VdbeAddOp4(Vdbe*,int,int,int,int,const char *zP4,int);
   181    181   int sqlite3VdbeAddOp4Dup8(Vdbe*,int,int,int,int,const u8*,int);
   182    182   int sqlite3VdbeAddOp4Int(Vdbe*,int,int,int,int,int);
          183  +void sqlite3VdbeEndCoroutine(Vdbe*,int);
   183    184   #if defined(SQLITE_DEBUG) && !defined(SQLITE_TEST_REALLOC_STRESS)
   184    185     void sqlite3VdbeVerifyNoMallocRequired(Vdbe *p, int N);
   185    186   #else
   186    187   # define sqlite3VdbeVerifyNoMallocRequired(A,B)
   187    188   #endif
   188    189   VdbeOp *sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp, int iLineno);
   189    190   void sqlite3VdbeAddParseSchemaOp(Vdbe*,int,char*);

Changes to src/vdbeaux.c.

   319    319     int p3,             /* The P3 operand */
   320    320     int p4              /* The P4 operand as an integer */
   321    321   ){
   322    322     int addr = sqlite3VdbeAddOp3(p, op, p1, p2, p3);
   323    323     sqlite3VdbeChangeP4(p, addr, SQLITE_INT_TO_PTR(p4), P4_INT32);
   324    324     return addr;
   325    325   }
          326  +
          327  +/* Insert the end of a co-routine
          328  +*/
          329  +void sqlite3VdbeEndCoroutine(Vdbe *v, int regYield){
          330  +  sqlite3VdbeAddOp1(v, OP_EndCoroutine, regYield);
          331  +
          332  +  /* Clear the temporary register cache, thereby ensuring that each
          333  +  ** co-routine has its own independent set of registers, because co-routines
          334  +  ** might expect their registers to be preserved across an OP_Yield, and
          335  +  ** that could cause problems if two or more co-routines are using the same
          336  +  ** temporary register.
          337  +  */
          338  +  v->pParse->nTempReg = 0;
          339  +  v->pParse->nRangeReg = 0;
          340  +}
   326    341   
   327    342   /*
   328    343   ** Create a new symbolic label for an instruction that has yet to be
   329    344   ** coded.  The symbolic label is really just a negative number.  The
   330    345   ** label can be used as the P2 value of an operation.  Later, when
   331    346   ** the label is resolved to a specific address, the VDBE will scan
   332    347   ** through its operation list and change all values of P2 which match

Changes to test/select4.test.

   911    911   } {123 456}
   912    912   do_execsql_test select4-14.16 {
   913    913     VALUES(1),(2),(3),(4) UNION ALL SELECT 5 LIMIT 99;
   914    914   } {1 2 3 4 5}
   915    915   do_execsql_test select4-14.17 {
   916    916     VALUES(1),(2),(3),(4) UNION ALL SELECT 5 LIMIT 3;
   917    917   } {1 2 3}
          918  +
          919  +# Ticket https://www.sqlite.org/src/info/d06a25c84454a372
          920  +# Incorrect answer due to two co-routines using the same registers and expecting
          921  +# those register values to be preserved across a Yield.
          922  +#
          923  +do_execsql_test select4-15.1 {
          924  +  DROP TABLE IF EXISTS tx;
          925  +  CREATE TABLE tx(id INTEGER PRIMARY KEY, a, b);
          926  +  INSERT INTO tx(a,b) VALUES(33,456);
          927  +  INSERT INTO tx(a,b) VALUES(33,789);
          928  +
          929  +  SELECT DISTINCT t0.id, t0.a, t0.b
          930  +    FROM tx AS t0, tx AS t1
          931  +   WHERE t0.a=t1.a AND t1.a=33 AND t0.b=456
          932  +  UNION
          933  +  SELECT DISTINCT t0.id, t0.a, t0.b
          934  +    FROM tx AS t0, tx AS t1
          935  +   WHERE t0.a=t1.a AND t1.a=33 AND t0.b=789
          936  +   ORDER BY 1;
          937  +} {1 33 456 2 33 789}
   918    938   
   919    939   finish_test