/ Check-in [266a99f7]
Login

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

Overview
Comment:Add new testcase() macros and fix a bug that was revealed when trying to cover all the new test cases.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | upsert
Files: files | file ages | folders
SHA3-256: 266a99f7c068aadbd08157d1d495a428109ad7a32d872f8026e8db0f89c40f91
User & Date: drh 2018-04-18 01:34:39
Context
2018-04-18
15:33
Fix the build for SQLITE_OMIT_UPSERT Closed-Leaf check-in: 32956519 user: drh tags: upsert
01:34
Add new testcase() macros and fix a bug that was revealed when trying to cover all the new test cases. check-in: 266a99f7 user: drh tags: upsert
2018-04-17
21:59
Remove unreachable branches. 100% MC/DC in TH3 now. check-in: 558865d5 user: drh tags: upsert
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/expr.c.

1822
1823
1824
1825
1826
1827
1828

1829
1830
1831
1832
1833
1834
1835
      testcase( pExpr->op==TK_AGG_COLUMN );
      if( pWalker->eCode==3 && pExpr->iTable==pWalker->u.iCur ){
        return WRC_Continue;
      }
      /* Fall through */
    case TK_IF_NULL_ROW:
    case TK_REGISTER:

      testcase( pExpr->op==TK_IF_NULL_ROW );
      pWalker->eCode = 0;
      return WRC_Abort;
    case TK_VARIABLE:
      if( pWalker->eCode==5 ){
        /* Silently convert bound parameters that appear inside of CREATE
        ** statements into a NULL when parsing the CREATE statement text out







>







1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
      testcase( pExpr->op==TK_AGG_COLUMN );
      if( pWalker->eCode==3 && pExpr->iTable==pWalker->u.iCur ){
        return WRC_Continue;
      }
      /* Fall through */
    case TK_IF_NULL_ROW:
    case TK_REGISTER:
      testcase( pExpr->op==TK_REGISTER );
      testcase( pExpr->op==TK_IF_NULL_ROW );
      pWalker->eCode = 0;
      return WRC_Abort;
    case TK_VARIABLE:
      if( pWalker->eCode==5 ){
        /* Silently convert bound parameters that appear inside of CREATE
        ** statements into a NULL when parsing the CREATE statement text out

Changes to src/insert.c.

1167
1168
1169
1170
1171
1172
1173
1174
1175

1176
1177
1178
1179
1180
1181
1182
1183

1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
....
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
....
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
....
1515
1516
1517
1518
1519
1520
1521



1522
1523
1524
1525
1526
1527
1528
....
1574
1575
1576
1577
1578
1579
1580

1581
1582
1583
1584
1585
1586
1587
....
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
....
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690









1691
1692
1693
1694
1695
1696
1697
....
1772
1773
1774
1775
1776
1777
1778



1779
1780
1781
1782
1783
1784
1785
1786
1787
1788

1789
1790
1791
1792
1793
1794
1795
....
1808
1809
1810
1811
1812
1813
1814



1815
1816
1817
1818
1819
1820
1821
** some OP_Goto operations so that the rowid and upsert constraints occur
** in the correct order relative to other constraints.
*/
typedef struct ConstraintAddr ConstraintAddr;
struct ConstraintAddr {
  int ipkTop;          /* Subroutine for rowid constraint check */
  int upsertTop;       /* Label for upsert constraint check subroutine */
  int ipkBtm;          /* Return opcode rowid constraint check */
  int upsertBtm;       /* upsert constraint returns to this label */

};

/*
** Generate any OP_Goto operations needed to cause constraints to be
** run that haven't already been run.
*/
static void reorderConstraintChecks(Vdbe *v, ConstraintAddr *p){
  if( p->upsertTop ){

    sqlite3VdbeGoto(v, p->upsertTop);
    VdbeComment((v, "call upsert subroutine"));
    sqlite3VdbeResolveLabel(v, p->upsertBtm);
    p->upsertTop = 0;
  }
  if( p->ipkTop ){
    sqlite3VdbeGoto(v, p->ipkTop);
    VdbeComment((v, "call rowid constraint-check subroutine"));
    sqlite3VdbeJumpHere(v, p->ipkBtm);
    p->ipkTop = 0;
  }
}

/*
** Generate code to do constraint checks prior to an INSERT or an UPDATE
................................................................................

  isUpdate = regOldData!=0;
  db = pParse->db;
  v = sqlite3GetVdbe(pParse);
  assert( v!=0 );
  assert( pTab->pSelect==0 );  /* This table is not a VIEW */
  nCol = pTab->nCol;
  sAddr.ipkTop = 0;
  sAddr.upsertTop = 0;
  
  /* pPk is the PRIMARY KEY index for WITHOUT ROWID tables and NULL for
  ** normal rowid tables.  nPkField is the number of key fields in the 
  ** pPk index or 1 for a rowid table.  In other words, nPkField is the
  ** number of fields in the true primary key of the table. */
  if( HasRowid(pTab) ){
    pPk = 0;
................................................................................
      assert( pUpsert->pUpsertSet==0 );
      overrideError = OE_Ignore;
      pUpsert = 0;
    }else if( (pUpIdx = pUpsert->pUpsertIdx)!=0 ){
      /* If the constraint-target is on some column other than
      ** then ROWID, then we might need to move the UPSERT around
      ** so that it occurs in the correct order. */
      sAddr.upsertTop = sqlite3VdbeMakeLabel(v);
      sAddr.upsertBtm = sqlite3VdbeMakeLabel(v);
    }
  }

  /* If rowid is changing, make sure the new rowid does not previously
  ** exist in the table.
  */
................................................................................
      default: {
        onError = OE_Abort;
        /* Fall thru into the next case */
      }
      case OE_Rollback:
      case OE_Abort:
      case OE_Fail: {



        sqlite3RowidConstraint(pParse, onError, pTab);
        break;
      }
      case OE_Replace: {
        /* If there are DELETE triggers on this table and the
        ** recursive-triggers flag is set, call GenerateRowDelete() to
        ** remove the conflicting row from the table. This will fire
................................................................................
#ifndef SQLITE_OMIT_UPSERT
      case OE_Update: {
        sqlite3UpsertDoUpdate(pParse, pUpsert, pTab, 0, iDataCur);
        /* Fall through */
      }
#endif
      case OE_Ignore: {

        sqlite3VdbeGoto(v, ignoreDest);
        break;
      }
    }
    sqlite3VdbeResolveLabel(v, addrRowidOk);
    if( sAddr.ipkTop ){
      sAddr.ipkBtm = sqlite3VdbeAddOp0(v, OP_Goto);
................................................................................
    int addrUniqueOk;    /* Jump here if the UNIQUE constraint is satisfied */

    if( aRegIdx[ix]==0 ) continue;  /* Skip indices that do not change */
    if( pUpIdx==pIdx ){
      addrUniqueOk = sAddr.upsertBtm;
      upsertBypass = sqlite3VdbeGoto(v, 0);
      VdbeComment((v, "Skip upsert subroutine"));
      sqlite3VdbeResolveLabel(v, sAddr.upsertTop);
    }else{
      addrUniqueOk = sqlite3VdbeMakeLabel(v);
    }
    VdbeNoopComment((v, "uniqueness check for %s", pIdx->zName));
    if( bAffinityDone==0 ){
      sqlite3TableAffinity(v, pTab, regNewData+1);
      bAffinityDone = 1;
................................................................................
      continue;  /* pIdx is not a UNIQUE index */
    }
    if( overrideError!=OE_Default ){
      onError = overrideError;
    }else if( onError==OE_Default ){
      onError = OE_Abort;
    }
    if( onError==OE_Replace ){
      reorderConstraintChecks(v, &sAddr);
    }

    /* Figure out if the upsert clause applies to this index */
    if( pUpIdx==pIdx ){
      if( pUpsert->pUpsertSet==0 ){
        onError = OE_Ignore;  /* DO NOTHING is the same as INSERT OR IGNORE */
      }else{
        onError = OE_Update;  /* DO UPDATE */
      }
    }










    /* Collision detection may be omitted if all of the following are true:
    **   (1) The conflict resolution algorithm is REPLACE
    **   (2) The table is a WITHOUT ROWID table
    **   (3) There are no secondary indexes on the table
    **   (4) No delete triggers need to be fired if there is a conflict
    **   (5) No FK constraint counters need to be updated if a conflict occurs.
................................................................................
    /* Generate code that executes if the new index entry is not unique */
    assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail
        || onError==OE_Ignore || onError==OE_Replace || onError==OE_Update );
    switch( onError ){
      case OE_Rollback:
      case OE_Abort:
      case OE_Fail: {



        sqlite3UniqueConstraint(pParse, onError, pIdx);
        break;
      }
#ifndef SQLITE_OMIT_UPSERT
      case OE_Update: {
        sqlite3UpsertDoUpdate(pParse, pUpsert, pTab, pIdx, iIdxCur+ix);
        /* Fall through */
      }
#endif
      case OE_Ignore: {

        sqlite3VdbeGoto(v, ignoreDest);
        break;
      }
      default: {
        Trigger *pTrigger = 0;
        assert( onError==OE_Replace );
        sqlite3MultiWrite(pParse);
................................................................................
    }else{
      sqlite3VdbeResolveLabel(v, addrUniqueOk);
    }
    sqlite3ExprCachePop(pParse);
    if( regR!=regIdx ) sqlite3ReleaseTempRange(pParse, regR, nPkField);

  }



  reorderConstraintChecks(v, &sAddr);
  
  *pbMayReplace = seenReplace;
  VdbeModuleComment((v, "END: GenCnstCks(%d)", seenReplace));
}

#ifdef SQLITE_ENABLE_NULL_TRIM







|

>








>







|







 







|
<







 







|







 







>
>
>







 







>







 







|







 







<
<
<









>
>
>
>
>
>
>
>
>







 







>
>
>










>







 







>
>
>







1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
....
1313
1314
1315
1316
1317
1318
1319
1320

1321
1322
1323
1324
1325
1326
1327
....
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
....
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
....
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
....
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
....
1677
1678
1679
1680
1681
1682
1683



1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
....
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
....
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
** some OP_Goto operations so that the rowid and upsert constraints occur
** in the correct order relative to other constraints.
*/
typedef struct ConstraintAddr ConstraintAddr;
struct ConstraintAddr {
  int ipkTop;          /* Subroutine for rowid constraint check */
  int upsertTop;       /* Label for upsert constraint check subroutine */
  int upsertTop2;      /* Copy of upsertTop not cleared by the call */
  int upsertBtm;       /* upsert constraint returns to this label */
  int ipkBtm;          /* Return opcode rowid constraint check */
};

/*
** Generate any OP_Goto operations needed to cause constraints to be
** run that haven't already been run.
*/
static void reorderConstraintChecks(Vdbe *v, ConstraintAddr *p){
  if( p->upsertTop ){
    testcase( sqlite3VdbeLabelHasBeenResolved(v, p->upsertTop) );
    sqlite3VdbeGoto(v, p->upsertTop);
    VdbeComment((v, "call upsert subroutine"));
    sqlite3VdbeResolveLabel(v, p->upsertBtm);
    p->upsertTop = 0;
  }
  if( p->ipkTop ){
    sqlite3VdbeGoto(v, p->ipkTop);
    VdbeComment((v, "call rowid unique-check subroutine"));
    sqlite3VdbeJumpHere(v, p->ipkBtm);
    p->ipkTop = 0;
  }
}

/*
** Generate code to do constraint checks prior to an INSERT or an UPDATE
................................................................................

  isUpdate = regOldData!=0;
  db = pParse->db;
  v = sqlite3GetVdbe(pParse);
  assert( v!=0 );
  assert( pTab->pSelect==0 );  /* This table is not a VIEW */
  nCol = pTab->nCol;
  memset(&sAddr, 0, sizeof(sAddr));

  
  /* pPk is the PRIMARY KEY index for WITHOUT ROWID tables and NULL for
  ** normal rowid tables.  nPkField is the number of key fields in the 
  ** pPk index or 1 for a rowid table.  In other words, nPkField is the
  ** number of fields in the true primary key of the table. */
  if( HasRowid(pTab) ){
    pPk = 0;
................................................................................
      assert( pUpsert->pUpsertSet==0 );
      overrideError = OE_Ignore;
      pUpsert = 0;
    }else if( (pUpIdx = pUpsert->pUpsertIdx)!=0 ){
      /* If the constraint-target is on some column other than
      ** then ROWID, then we might need to move the UPSERT around
      ** so that it occurs in the correct order. */
      sAddr.upsertTop = sAddr.upsertTop2 = sqlite3VdbeMakeLabel(v);
      sAddr.upsertBtm = sqlite3VdbeMakeLabel(v);
    }
  }

  /* If rowid is changing, make sure the new rowid does not previously
  ** exist in the table.
  */
................................................................................
      default: {
        onError = OE_Abort;
        /* Fall thru into the next case */
      }
      case OE_Rollback:
      case OE_Abort:
      case OE_Fail: {
        testcase( onError==OE_Rollback );
        testcase( onError==OE_Abort );
        testcase( onError==OE_Fail );
        sqlite3RowidConstraint(pParse, onError, pTab);
        break;
      }
      case OE_Replace: {
        /* If there are DELETE triggers on this table and the
        ** recursive-triggers flag is set, call GenerateRowDelete() to
        ** remove the conflicting row from the table. This will fire
................................................................................
#ifndef SQLITE_OMIT_UPSERT
      case OE_Update: {
        sqlite3UpsertDoUpdate(pParse, pUpsert, pTab, 0, iDataCur);
        /* Fall through */
      }
#endif
      case OE_Ignore: {
        testcase( onError==OE_Ignore );
        sqlite3VdbeGoto(v, ignoreDest);
        break;
      }
    }
    sqlite3VdbeResolveLabel(v, addrRowidOk);
    if( sAddr.ipkTop ){
      sAddr.ipkBtm = sqlite3VdbeAddOp0(v, OP_Goto);
................................................................................
    int addrUniqueOk;    /* Jump here if the UNIQUE constraint is satisfied */

    if( aRegIdx[ix]==0 ) continue;  /* Skip indices that do not change */
    if( pUpIdx==pIdx ){
      addrUniqueOk = sAddr.upsertBtm;
      upsertBypass = sqlite3VdbeGoto(v, 0);
      VdbeComment((v, "Skip upsert subroutine"));
      sqlite3VdbeResolveLabel(v, sAddr.upsertTop2);
    }else{
      addrUniqueOk = sqlite3VdbeMakeLabel(v);
    }
    VdbeNoopComment((v, "uniqueness check for %s", pIdx->zName));
    if( bAffinityDone==0 ){
      sqlite3TableAffinity(v, pTab, regNewData+1);
      bAffinityDone = 1;
................................................................................
      continue;  /* pIdx is not a UNIQUE index */
    }
    if( overrideError!=OE_Default ){
      onError = overrideError;
    }else if( onError==OE_Default ){
      onError = OE_Abort;
    }




    /* Figure out if the upsert clause applies to this index */
    if( pUpIdx==pIdx ){
      if( pUpsert->pUpsertSet==0 ){
        onError = OE_Ignore;  /* DO NOTHING is the same as INSERT OR IGNORE */
      }else{
        onError = OE_Update;  /* DO UPDATE */
      }
    }

    /* Invoke subroutines to handle IPK replace and upsert prior to running
    ** the first REPLACE constraint check. */
    if( onError==OE_Replace ){
      testcase( sAddr.ipkTop );
      testcase( sAddr.upsertTop
             && sqlite3VdbeLabelHasBeenResolved(v,sAddr.upsertTop) );
      reorderConstraintChecks(v, &sAddr);
    }

    /* Collision detection may be omitted if all of the following are true:
    **   (1) The conflict resolution algorithm is REPLACE
    **   (2) The table is a WITHOUT ROWID table
    **   (3) There are no secondary indexes on the table
    **   (4) No delete triggers need to be fired if there is a conflict
    **   (5) No FK constraint counters need to be updated if a conflict occurs.
................................................................................
    /* Generate code that executes if the new index entry is not unique */
    assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail
        || onError==OE_Ignore || onError==OE_Replace || onError==OE_Update );
    switch( onError ){
      case OE_Rollback:
      case OE_Abort:
      case OE_Fail: {
        testcase( onError==OE_Rollback );
        testcase( onError==OE_Abort );
        testcase( onError==OE_Fail );
        sqlite3UniqueConstraint(pParse, onError, pIdx);
        break;
      }
#ifndef SQLITE_OMIT_UPSERT
      case OE_Update: {
        sqlite3UpsertDoUpdate(pParse, pUpsert, pTab, pIdx, iIdxCur+ix);
        /* Fall through */
      }
#endif
      case OE_Ignore: {
        testcase( onError==OE_Ignore );
        sqlite3VdbeGoto(v, ignoreDest);
        break;
      }
      default: {
        Trigger *pTrigger = 0;
        assert( onError==OE_Replace );
        sqlite3MultiWrite(pParse);
................................................................................
    }else{
      sqlite3VdbeResolveLabel(v, addrUniqueOk);
    }
    sqlite3ExprCachePop(pParse);
    if( regR!=regIdx ) sqlite3ReleaseTempRange(pParse, regR, nPkField);

  }
  testcase( sAddr.ipkTop!=0 );
  testcase( sAddr.upsertTop
         && sqlite3VdbeLabelHasBeenResolved(v,sAddr.upsertTop) );
  reorderConstraintChecks(v, &sAddr);
  
  *pbMayReplace = seenReplace;
  VdbeModuleComment((v, "END: GenCnstCks(%d)", seenReplace));
}

#ifdef SQLITE_ENABLE_NULL_TRIM

Changes to src/resolve.c.

342
343
344
345
346
347
348

349
350
351
352
353
354
355
          /* IMP: R-51414-32910 */
          iCol = -1;
        }
        if( iCol<pTab->nCol ){
          cnt++;
#ifndef SQLITE_OMIT_UPSERT
          if( pExpr->iTable==2 ){

            pExpr->iTable = pNC->uNC.pUpsert->regData + iCol;
            eNewExprOp = TK_REGISTER;
          }else
#endif /* SQLITE_OMIT_UPSERT */
          {
#ifndef SQLITE_OMIT_TRIGGER
            if( iCol<0 ){







>







342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
          /* IMP: R-51414-32910 */
          iCol = -1;
        }
        if( iCol<pTab->nCol ){
          cnt++;
#ifndef SQLITE_OMIT_UPSERT
          if( pExpr->iTable==2 ){
            testcase( iCol==(-1) );
            pExpr->iTable = pNC->uNC.pUpsert->regData + iCol;
            eNewExprOp = TK_REGISTER;
          }else
#endif /* SQLITE_OMIT_UPSERT */
          {
#ifndef SQLITE_OMIT_TRIGGER
            if( iCol<0 ){

Changes to src/trigger.c.

428
429
430
431
432
433
434

435

436
437
438
439
440
441
442
  pTriggerStep = triggerStepAllocate(db, TK_INSERT, pTableName, zStart, zEnd);
  if( pTriggerStep ){
    pTriggerStep->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE);
    pTriggerStep->pIdList = pColumn;
    pTriggerStep->pUpsert = pUpsert;
    pTriggerStep->orconf = orconf;
  }else{

    sqlite3IdListDelete(db, pColumn);

    sqlite3UpsertDelete(db, pUpsert);
  }
  sqlite3SelectDelete(db, pSelect);

  return pTriggerStep;
}








>

>







428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
  pTriggerStep = triggerStepAllocate(db, TK_INSERT, pTableName, zStart, zEnd);
  if( pTriggerStep ){
    pTriggerStep->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE);
    pTriggerStep->pIdList = pColumn;
    pTriggerStep->pUpsert = pUpsert;
    pTriggerStep->orconf = orconf;
  }else{
    testcase( pColumn );
    sqlite3IdListDelete(db, pColumn);
    testcase( pUpsert );
    sqlite3UpsertDelete(db, pUpsert);
  }
  sqlite3SelectDelete(db, pSelect);

  return pTriggerStep;
}

Changes to src/vdbe.h.

216
217
218
219
220
221
222



223
224
225
226
227
228
229
void sqlite3VdbeRunOnlyOnce(Vdbe*);
void sqlite3VdbeReusable(Vdbe*);
void sqlite3VdbeDelete(Vdbe*);
void sqlite3VdbeClearObject(sqlite3*,Vdbe*);
void sqlite3VdbeMakeReady(Vdbe*,Parse*);
int sqlite3VdbeFinalize(Vdbe*);
void sqlite3VdbeResolveLabel(Vdbe*, int);



int sqlite3VdbeCurrentAddr(Vdbe*);
#ifdef SQLITE_DEBUG
  int sqlite3VdbeAssertMayAbort(Vdbe *, int);
#endif
void sqlite3VdbeResetStepResult(Vdbe*);
void sqlite3VdbeRewind(Vdbe*);
int sqlite3VdbeReset(Vdbe*);







>
>
>







216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
void sqlite3VdbeRunOnlyOnce(Vdbe*);
void sqlite3VdbeReusable(Vdbe*);
void sqlite3VdbeDelete(Vdbe*);
void sqlite3VdbeClearObject(sqlite3*,Vdbe*);
void sqlite3VdbeMakeReady(Vdbe*,Parse*);
int sqlite3VdbeFinalize(Vdbe*);
void sqlite3VdbeResolveLabel(Vdbe*, int);
#ifdef SQLITE_COVERAGE_TEST
  int sqlite3VdbeLabelHasBeenResolved(Vdbe*,int);
#endif
int sqlite3VdbeCurrentAddr(Vdbe*);
#ifdef SQLITE_DEBUG
  int sqlite3VdbeAssertMayAbort(Vdbe *, int);
#endif
void sqlite3VdbeResetStepResult(Vdbe*);
void sqlite3VdbeRewind(Vdbe*);
int sqlite3VdbeReset(Vdbe*);

Changes to src/vdbeaux.c.

398
399
400
401
402
403
404













405
406
407
408
409
410
411
    }
#endif
    assert( p->aLabel[j]==(-1) ); /* Labels may only be resolved once */
    p->aLabel[j] = v->nOp;
  }
}














/*
** Mark the VDBE as one that can only be run one time.
*/
void sqlite3VdbeRunOnlyOnce(Vdbe *p){
  p->runOnlyOnce = 1;
}








>
>
>
>
>
>
>
>
>
>
>
>
>







398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
    }
#endif
    assert( p->aLabel[j]==(-1) ); /* Labels may only be resolved once */
    p->aLabel[j] = v->nOp;
  }
}

#ifdef SQLITE_COVERAGE_TEST
/*
** Return TRUE if and only if the label x has already been resolved.
** Return FALSE (zero) if label x is still unresolved.
**
** This routine is only used inside of testcase() macros, and so it
** only exists when measuring test coverage.
*/
int sqlite3VdbeLabelHasBeenResolved(Vdbe *v, int x){
  return v->pParse->aLabel && v->pParse->aLabel[ADDR(x)]>=0;
}
#endif /* SQLITE_COVERAGE_TEST */

/*
** Mark the VDBE as one that can only be run one time.
*/
void sqlite3VdbeRunOnlyOnce(Vdbe *p){
  p->runOnlyOnce = 1;
}