/ Check-in [fb9044d1]
Login

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

Overview
Comment:Add the logic to keep partial indices up to date through DML statements and when new partial indices are created. This new logic is untested except to verify that it does not interfere with full indices.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | partial-indices
Files: files | file ages | folders
SHA1: fb9044d15ad4fd6ae4a38858c0c0e6fe9d4faa25
User & Date: drh 2013-08-01 01:14:43
Context
2013-08-01
03:36
Test cases and bug fixes for the partial index logic. check-in: 6b73ae7c user: drh tags: partial-indices
01:14
Add the logic to keep partial indices up to date through DML statements and when new partial indices are created. This new logic is untested except to verify that it does not interfere with full indices. check-in: fb9044d1 user: drh tags: partial-indices
2013-07-31
23:22
Add logic to the query planner to only use partial indices if the WHERE clause constrains the search to rows covered by the partial index. This is just infrastructure. The key routine, sqlite3ExprImpliesExpr(), is currently a no-op so that partial indices will never be used. check-in: 8ca3eac1 user: drh tags: partial-indices
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/build.c.

  2370   2370     Table *pTab = pIndex->pTable;  /* The table that is indexed */
  2371   2371     int iTab = pParse->nTab++;     /* Btree cursor used for pTab */
  2372   2372     int iIdx = pParse->nTab++;     /* Btree cursor used for pIndex */
  2373   2373     int iSorter;                   /* Cursor opened by OpenSorter (if in use) */
  2374   2374     int addr1;                     /* Address of top of loop */
  2375   2375     int addr2;                     /* Address to jump to for next iteration */
  2376   2376     int tnum;                      /* Root page of index */
         2377  +  int iPartIdxLabel;             /* Jump to this label to skip a row */
  2377   2378     Vdbe *v;                       /* Generate code into this virtual machine */
  2378   2379     KeyInfo *pKey;                 /* KeyInfo for index */
  2379   2380     int regRecord;                 /* Register holding assemblied index record */
  2380   2381     sqlite3 *db = pParse->db;      /* The database connection */
  2381   2382     int iDb = sqlite3SchemaToIndex(db, pIndex->pSchema);
  2382   2383   
  2383   2384   #ifndef SQLITE_OMIT_AUTHORIZATION
................................................................................
  2409   2410   
  2410   2411     /* Open the table. Loop through all rows of the table, inserting index
  2411   2412     ** records into the sorter. */
  2412   2413     sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead);
  2413   2414     addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iTab, 0);
  2414   2415     regRecord = sqlite3GetTempReg(pParse);
  2415   2416   
  2416         -  sqlite3GenerateIndexKey(pParse, pIndex, iTab, regRecord, 1);
         2417  +  sqlite3GenerateIndexKey(pParse, pIndex, iTab, regRecord, 1, &iPartIdxLabel);
  2417   2418     sqlite3VdbeAddOp2(v, OP_SorterInsert, iSorter, regRecord);
         2419  +  sqlite3VdbeResolveLabel(v, iPartIdxLabel);
  2418   2420     sqlite3VdbeAddOp2(v, OP_Next, iTab, addr1+1);
  2419   2421     sqlite3VdbeJumpHere(v, addr1);
  2420   2422     addr1 = sqlite3VdbeAddOp2(v, OP_SorterSort, iSorter, 0);
  2421   2423     if( pIndex->onError!=OE_None ){
  2422   2424       int j2 = sqlite3VdbeCurrentAddr(v) + 3;
  2423   2425       sqlite3VdbeAddOp2(v, OP_Goto, 0, j2);
  2424   2426       addr2 = sqlite3VdbeCurrentAddr(v);
................................................................................
  2839   2841     ** we don't want to recreate it.
  2840   2842     **
  2841   2843     ** If pTblName==0 it means this index is generated as a primary key
  2842   2844     ** or UNIQUE constraint of a CREATE TABLE statement.  Since the table
  2843   2845     ** has just been created, it contains no data and the index initialization
  2844   2846     ** step can be skipped.
  2845   2847     */
  2846         -  else{ /* if( db->init.busy==0 ) */
         2848  +  else if( pParse->nErr==0 ){
  2847   2849       Vdbe *v;
  2848   2850       char *zStmt;
  2849   2851       int iMem = ++pParse->nMem;
  2850   2852   
  2851   2853       v = sqlite3GetVdbe(pParse);
  2852   2854       if( v==0 ) goto exit_create_index;
  2853   2855   

Changes to src/delete.c.

   587    587     Table *pTab,       /* Table containing the row to be deleted */
   588    588     int iCur,          /* Cursor number for the table */
   589    589     int *aRegIdx       /* Only delete if aRegIdx!=0 && aRegIdx[i]>0 */
   590    590   ){
   591    591     int i;
   592    592     Index *pIdx;
   593    593     int r1;
          594  +  int iPartIdxLabel;
          595  +  Vdbe *v = pParse->pVdbe;
   594    596   
   595    597     for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
   596    598       if( aRegIdx!=0 && aRegIdx[i-1]==0 ) continue;
   597         -    r1 = sqlite3GenerateIndexKey(pParse, pIdx, iCur, 0, 0);
   598         -    sqlite3VdbeAddOp3(pParse->pVdbe, OP_IdxDelete, iCur+i, r1,pIdx->nColumn+1);
          599  +    r1 = sqlite3GenerateIndexKey(pParse, pIdx, iCur, 0, 0, &iPartIdxLabel);
          600  +    sqlite3VdbeAddOp3(v, OP_IdxDelete, iCur+i, r1, pIdx->nColumn+1);
          601  +    sqlite3VdbeResolveLabel(v, iPartIdxLabel);
   599    602     }
   600    603   }
   601    604   
   602    605   /*
   603    606   ** Generate code that will assemble an index key and put it in register
   604    607   ** regOut.  The key with be for index pIdx which is an index on pTab.
   605    608   ** iCur is the index of a cursor open on the pTab table and pointing to
   606    609   ** the entry that needs indexing.
   607    610   **
   608    611   ** Return a register number which is the first in a block of
   609    612   ** registers that holds the elements of the index key.  The
   610    613   ** block of registers has already been deallocated by the time
   611    614   ** this routine returns.
          615  +**
          616  +** If *piPartIdxLabel is not NULL, fill it in with a label and jump
          617  +** to that label if pIdx is a partial index that should be skipped.
          618  +** A partial index should be skipped if its WHERE clause evaluates
          619  +** to false or null.  If pIdx is not a partial index, *piPartIdxLabel
          620  +** will be set to zero which is an empty label that is ignored by
          621  +** sqlite3VdbeResolveLabel().
   612    622   */
   613    623   int sqlite3GenerateIndexKey(
   614         -  Parse *pParse,     /* Parsing context */
   615         -  Index *pIdx,       /* The index for which to generate a key */
   616         -  int iCur,          /* Cursor number for the pIdx->pTable table */
   617         -  int regOut,        /* Write the new index key to this register */
   618         -  int doMakeRec      /* Run the OP_MakeRecord instruction if true */
          624  +  Parse *pParse,       /* Parsing context */
          625  +  Index *pIdx,         /* The index for which to generate a key */
          626  +  int iCur,            /* Cursor number for the pIdx->pTable table */
          627  +  int regOut,          /* Write the new index key to this register */
          628  +  int doMakeRec,       /* Run the OP_MakeRecord instruction if true */
          629  +  int *piPartIdxLabel  /* OUT: Jump to this label to skip partial index */
   619    630   ){
   620    631     Vdbe *v = pParse->pVdbe;
   621    632     int j;
   622    633     Table *pTab = pIdx->pTable;
   623    634     int regBase;
   624    635     int nCol;
   625    636   
          637  +  if( piPartIdxLabel ){
          638  +    if( pIdx->pPartIdxWhere ){
          639  +      *piPartIdxLabel = sqlite3VdbeMakeLabel(v);
          640  +      pParse->iPartIdxTab = iCur;
          641  +      sqlite3ExprIfFalse(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel, 
          642  +                         SQLITE_JUMPIFNULL);
          643  +    }else{
          644  +      *piPartIdxLabel = 0;
          645  +    }
          646  +  }
   626    647     nCol = pIdx->nColumn;
   627    648     regBase = sqlite3GetTempRange(pParse, nCol+1);
   628    649     sqlite3VdbeAddOp2(v, OP_Rowid, iCur, regBase+nCol);
   629    650     for(j=0; j<nCol; j++){
   630    651       int idx = pIdx->aiColumn[j];
   631    652       if( idx==pTab->iPKey ){
   632    653         sqlite3VdbeAddOp2(v, OP_SCopy, regBase+nCol, regBase+j);

Changes to src/expr.c.

  2358   2358           sqlite3VdbeAddOp3(v, OP_Column, pAggInfo->sortingIdxPTab,
  2359   2359                                 pCol->iSorterColumn, target);
  2360   2360           break;
  2361   2361         }
  2362   2362         /* Otherwise, fall thru into the TK_COLUMN case */
  2363   2363       }
  2364   2364       case TK_COLUMN: {
  2365         -      if( pExpr->iTable<0 ){
  2366         -        /* This only happens when coding check constraints */
  2367         -        assert( pParse->ckBase>0 );
  2368         -        inReg = pExpr->iColumn + pParse->ckBase;
  2369         -      }else{
  2370         -        inReg = sqlite3ExprCodeGetColumn(pParse, pExpr->pTab,
  2371         -                                 pExpr->iColumn, pExpr->iTable, target,
  2372         -                                 pExpr->op2);
         2365  +      int iTab = pExpr->iTable;
         2366  +      if( iTab<0 ){
         2367  +        if( pParse->ckBase>0 ){
         2368  +          /* Generating CHECK constraints or inserting into partial index */
         2369  +          inReg = pExpr->iColumn + pParse->ckBase;
         2370  +          break;
         2371  +        }else{
         2372  +          /* Deleting from a partial index */
         2373  +          iTab = pParse->iPartIdxTab;
         2374  +        }
  2373   2375         }
         2376  +      inReg = sqlite3ExprCodeGetColumn(pParse, pExpr->pTab,
         2377  +                               pExpr->iColumn, iTab, target,
         2378  +                               pExpr->op2);
  2374   2379         break;
  2375   2380       }
  2376   2381       case TK_INTEGER: {
  2377   2382         codeInteger(pParse, pExpr, 0, target);
  2378   2383         break;
  2379   2384       }
  2380   2385   #ifndef SQLITE_OMIT_FLOATING_POINT

Changes to src/insert.c.

  1375   1375     /* Test all UNIQUE constraints by creating entries for each UNIQUE
  1376   1376     ** index and making sure that duplicate entries do not already exist.
  1377   1377     ** Add the new records to the indices as we go.
  1378   1378     */
  1379   1379     for(iCur=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, iCur++){
  1380   1380       int regIdx;
  1381   1381       int regR;
         1382  +    int addrSkipRow = 0;
  1382   1383   
  1383   1384       if( aRegIdx[iCur]==0 ) continue;  /* Skip unused indices */
         1385  +
         1386  +    if( pIdx->pPartIdxWhere ){
         1387  +      sqlite3VdbeAddOp2(v, OP_Null, 0, aRegIdx[iCur]);
         1388  +      addrSkipRow = sqlite3VdbeMakeLabel(v);
         1389  +      pParse->ckBase = regData;
         1390  +      sqlite3ExprIfFalse(pParse, pIdx->pPartIdxWhere, addrSkipRow,
         1391  +                         SQLITE_JUMPIFNULL);
         1392  +      pParse->ckBase = 0;
         1393  +    }
  1384   1394   
  1385   1395       /* Create a key for accessing the index entry */
  1386   1396       regIdx = sqlite3GetTempRange(pParse, pIdx->nColumn+1);
  1387   1397       for(i=0; i<pIdx->nColumn; i++){
  1388   1398         int idx = pIdx->aiColumn[i];
  1389   1399         if( idx==pTab->iPKey ){
  1390   1400           sqlite3VdbeAddOp2(v, OP_SCopy, regRowid, regIdx+i);
................................................................................
  1466   1476               pParse, pTab, baseCur, regR, 0, pTrigger, OE_Replace
  1467   1477           );
  1468   1478           seenReplace = 1;
  1469   1479           break;
  1470   1480         }
  1471   1481       }
  1472   1482       sqlite3VdbeJumpHere(v, j3);
         1483  +    sqlite3VdbeResolveLabel(v, addrSkipRow);
  1473   1484       sqlite3ReleaseTempReg(pParse, regR);
  1474   1485     }
  1475   1486     
  1476   1487     if( pbMayReplace ){
  1477   1488       *pbMayReplace = seenReplace;
  1478   1489     }
  1479   1490   }
................................................................................
  1495   1506     int *aRegIdx,       /* Register used by each index.  0 for unused indices */
  1496   1507     int isUpdate,       /* True for UPDATE, False for INSERT */
  1497   1508     int appendBias,     /* True if this is likely to be an append */
  1498   1509     int useSeekResult   /* True to set the USESEEKRESULT flag on OP_[Idx]Insert */
  1499   1510   ){
  1500   1511     int i;
  1501   1512     Vdbe *v;
  1502         -  int nIdx;
  1503   1513     Index *pIdx;
  1504   1514     u8 pik_flags;
  1505   1515     int regData;
  1506   1516     int regRec;
  1507   1517   
  1508   1518     v = sqlite3GetVdbe(pParse);
  1509   1519     assert( v!=0 );
  1510   1520     assert( pTab->pSelect==0 );  /* This table is not a VIEW */
  1511         -  for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){}
  1512         -  for(i=nIdx-1; i>=0; i--){
         1521  +  for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
  1513   1522       if( aRegIdx[i]==0 ) continue;
         1523  +    if( pIdx->pPartIdxWhere ){
         1524  +      sqlite3VdbeAddOp2(v, OP_IsNull, aRegIdx[i], sqlite3VdbeCurrentAddr(v)+2);
         1525  +    }
  1514   1526       sqlite3VdbeAddOp2(v, OP_IdxInsert, baseCur+i+1, aRegIdx[i]);
  1515   1527       if( useSeekResult ){
  1516   1528         sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
  1517   1529       }
  1518   1530     }
  1519   1531     regData = regRowid + 1;
  1520   1532     regRec = sqlite3GetTempReg(pParse);
................................................................................
  1608   1620   ** for index pDest in an insert transfer optimization.  The rules
  1609   1621   ** for a compatible index:
  1610   1622   **
  1611   1623   **    *   The index is over the same set of columns
  1612   1624   **    *   The same DESC and ASC markings occurs on all columns
  1613   1625   **    *   The same onError processing (OE_Abort, OE_Ignore, etc)
  1614   1626   **    *   The same collating sequence on each column
         1627  +**    *   The index has the exact same WHERE clause
  1615   1628   */
  1616   1629   static int xferCompatibleIndex(Index *pDest, Index *pSrc){
  1617   1630     int i;
  1618   1631     assert( pDest && pSrc );
  1619   1632     assert( pDest->pTable!=pSrc->pTable );
  1620   1633     if( pDest->nColumn!=pSrc->nColumn ){
  1621   1634       return 0;   /* Different number of columns */
................................................................................
  1629   1642       }
  1630   1643       if( pSrc->aSortOrder[i]!=pDest->aSortOrder[i] ){
  1631   1644         return 0;   /* Different sort orders */
  1632   1645       }
  1633   1646       if( !xferCompatibleCollation(pSrc->azColl[i],pDest->azColl[i]) ){
  1634   1647         return 0;   /* Different collating sequences */
  1635   1648       }
         1649  +  }
         1650  +  if( sqlite3ExprCompare(pSrc->pPartIdxWhere, pDest->pPartIdxWhere) ){
         1651  +    return 0;     /* Different WHERE clauses */
  1636   1652     }
  1637   1653   
  1638   1654     /* If no test above fails then the indices must be compatible */
  1639   1655     return 1;
  1640   1656   }
  1641   1657   
  1642   1658   /*

Changes to src/pragma.c.

  1428   1428           sqlite3VdbeAddOp2(v, OP_Halt, 0, 0);
  1429   1429           sqlite3VdbeJumpHere(v, addr);
  1430   1430           sqlite3OpenTableAndIndices(pParse, pTab, 1, OP_OpenRead);
  1431   1431           sqlite3VdbeAddOp2(v, OP_Integer, 0, 2);  /* reg(2) will count entries */
  1432   1432           loopTop = sqlite3VdbeAddOp2(v, OP_Rewind, 1, 0);
  1433   1433           sqlite3VdbeAddOp2(v, OP_AddImm, 2, 1);   /* increment entry count */
  1434   1434           for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
  1435         -          int jmp2;
         1435  +          int jmp2, jmp3;
  1436   1436             int r1;
  1437   1437             static const VdbeOpList idxErr[] = {
  1438   1438               { OP_AddImm,      1, -1,  0},
  1439   1439               { OP_String8,     0,  3,  0},    /* 1 */
  1440   1440               { OP_Rowid,       1,  4,  0},
  1441   1441               { OP_String8,     0,  5,  0},    /* 3 */
  1442   1442               { OP_String8,     0,  6,  0},    /* 4 */
................................................................................
  1443   1443               { OP_Concat,      4,  3,  3},
  1444   1444               { OP_Concat,      5,  3,  3},
  1445   1445               { OP_Concat,      6,  3,  3},
  1446   1446               { OP_ResultRow,   3,  1,  0},
  1447   1447               { OP_IfPos,       1,  0,  0},    /* 9 */
  1448   1448               { OP_Halt,        0,  0,  0},
  1449   1449             };
  1450         -          r1 = sqlite3GenerateIndexKey(pParse, pIdx, 1, 3, 0);
         1450  +          r1 = sqlite3GenerateIndexKey(pParse, pIdx, 1, 3, 0, &jmp3);
  1451   1451             jmp2 = sqlite3VdbeAddOp4Int(v, OP_Found, j+2, 0, r1, pIdx->nColumn+1);
  1452   1452             addr = sqlite3VdbeAddOpList(v, ArraySize(idxErr), idxErr);
  1453   1453             sqlite3VdbeChangeP4(v, addr+1, "rowid ", P4_STATIC);
  1454   1454             sqlite3VdbeChangeP4(v, addr+3, " missing from index ", P4_STATIC);
  1455   1455             sqlite3VdbeChangeP4(v, addr+4, pIdx->zName, P4_TRANSIENT);
  1456   1456             sqlite3VdbeJumpHere(v, addr+9);
  1457   1457             sqlite3VdbeJumpHere(v, jmp2);
         1458  +          sqlite3VdbeResolveLabel(v, jmp3);
  1458   1459           }
  1459   1460           sqlite3VdbeAddOp2(v, OP_Next, 1, loopTop+1);
  1460   1461           sqlite3VdbeJumpHere(v, loopTop);
  1461   1462           for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
  1462   1463             static const VdbeOpList cntIdx[] = {
  1463   1464                { OP_Integer,      0,  3,  0},
  1464   1465                { OP_Rewind,       0,  0,  0},  /* 1 */

Changes to src/sqliteInt.h.

  2200   2200     int iRangeReg;       /* First register in temporary register block */
  2201   2201     int nErr;            /* Number of errors seen */
  2202   2202     int nTab;            /* Number of previously allocated VDBE cursors */
  2203   2203     int nMem;            /* Number of memory cells used so far */
  2204   2204     int nSet;            /* Number of sets used so far */
  2205   2205     int nOnce;           /* Number of OP_Once instructions so far */
  2206   2206     int ckBase;          /* Base register of data during check constraints */
         2207  +  int iPartIdxTab;     /* Table corresponding to a partial index */
  2207   2208     int iCacheLevel;     /* ColCache valid when aColCache[].iLevel<=iCacheLevel */
  2208   2209     int iCacheCnt;       /* Counter used to generate aColCache[].lru values */
  2209   2210     struct yColCache {
  2210   2211       int iTable;           /* Table cursor number */
  2211   2212       int iColumn;          /* Table column number */
  2212   2213       u8 tempReg;           /* iReg is a temp register that needs to be freed */
  2213   2214       int iLevel;           /* Nesting level */
................................................................................
  2858   2859   int sqlite3ExprIsInteger(Expr*, int*);
  2859   2860   int sqlite3ExprCanBeNull(const Expr*);
  2860   2861   void sqlite3ExprCodeIsNullJump(Vdbe*, const Expr*, int, int);
  2861   2862   int sqlite3ExprNeedsNoAffinityChange(const Expr*, char);
  2862   2863   int sqlite3IsRowid(const char*);
  2863   2864   void sqlite3GenerateRowDelete(Parse*, Table*, int, int, int, Trigger *, int);
  2864   2865   void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int*);
  2865         -int sqlite3GenerateIndexKey(Parse*, Index*, int, int, int);
         2866  +int sqlite3GenerateIndexKey(Parse*, Index*, int, int, int, int*);
  2866   2867   void sqlite3GenerateConstraintChecks(Parse*,Table*,int,int,
  2867   2868                                        int*,int,int,int,int,int*);
  2868   2869   void sqlite3CompleteInsertion(Parse*, Table*, int, int, int*, int, int, int);
  2869   2870   int sqlite3OpenTableAndIndices(Parse*, Table*, int, int);
  2870   2871   void sqlite3BeginWriteOperation(Parse*, int, int);
  2871   2872   void sqlite3MultiWrite(Parse*);
  2872   2873   void sqlite3MayAbort(Parse*);

Changes to src/update.c.

   242    242     for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){}
   243    243     if( nIdx>0 ){
   244    244       aRegIdx = sqlite3DbMallocRaw(db, sizeof(Index*) * nIdx );
   245    245       if( aRegIdx==0 ) goto update_cleanup;
   246    246     }
   247    247     for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
   248    248       int reg;
   249         -    if( hasFK || chngRowid ){
          249  +    if( hasFK || chngRowid || pIdx->pPartIdxWhere ){
   250    250         reg = ++pParse->nMem;
   251    251       }else{
   252    252         reg = 0;
   253    253         for(i=0; i<pIdx->nColumn; i++){
   254    254           if( aXRef[pIdx->aiColumn[i]]>=0 ){
   255    255             reg = ++pParse->nMem;
   256    256             break;

Changes to src/vdbeaux.c.

   246    246   ** Resolve label "x" to be the address of the next instruction to
   247    247   ** be inserted.  The parameter "x" must have been obtained from
   248    248   ** a prior call to sqlite3VdbeMakeLabel().
   249    249   */
   250    250   void sqlite3VdbeResolveLabel(Vdbe *p, int x){
   251    251     int j = -1-x;
   252    252     assert( p->magic==VDBE_MAGIC_INIT );
   253         -  assert( j>=0 && j<p->nLabel );
   254         -  if( p->aLabel ){
          253  +  assert( j<p->nLabel );
          254  +  if( j>=0 && p->aLabel ){
   255    255       p->aLabel[j] = p->nOp;
   256    256     }
   257    257   }
   258    258   
   259    259   /*
   260    260   ** Mark the VDBE as one that can only be run one time.
   261    261   */

Changes to src/where.c.

  2231   2231     sqlite3VdbeAddOp4(v, OP_OpenAutoindex, pLevel->iIdxCur, nColumn+1, 0,
  2232   2232                       (char*)pKeyinfo, P4_KEYINFO_HANDOFF);
  2233   2233     VdbeComment((v, "for %s", pTable->zName));
  2234   2234   
  2235   2235     /* Fill the automatic index with content */
  2236   2236     addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, pLevel->iTabCur);
  2237   2237     regRecord = sqlite3GetTempReg(pParse);
  2238         -  sqlite3GenerateIndexKey(pParse, pIdx, pLevel->iTabCur, regRecord, 1);
         2238  +  sqlite3GenerateIndexKey(pParse, pIdx, pLevel->iTabCur, regRecord, 1, 0);
  2239   2239     sqlite3VdbeAddOp2(v, OP_IdxInsert, pLevel->iIdxCur, regRecord);
  2240   2240     sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
  2241   2241     sqlite3VdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop+1);
  2242   2242     sqlite3VdbeChangeP5(v, SQLITE_STMTSTATUS_AUTOINDEX);
  2243   2243     sqlite3VdbeJumpHere(v, addrTop);
  2244   2244     sqlite3ReleaseTempReg(pParse, regRecord);
  2245   2245