/ Check-in [28aa1f4e]
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:Add a complicated assert() to check that statement transactions are opened when required.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 28aa1f4ea8dad56ffedb31d6c2bc27c1d6be2407
User & Date: dan 2009-09-09 11:37:20
Context
2009-09-09
11:43
Add a test case to show that 29ab7be99f is fixed. check-in: 135d656a user: dan tags: trunk
11:37
Add a complicated assert() to check that statement transactions are opened when required. check-in: 28aa1f4e user: dan tags: trunk
2009-09-08
19:15
Combine the OP_Statement and OP_Transaction opcodes. check-in: aec9dbd8 user: dan tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

configure became executable.


Changes to src/build.c.

   134    134     if( pParse->nested ) return;
   135    135     if( pParse->nErr ) return;
   136    136   
   137    137     /* Begin by generating some termination code at the end of the
   138    138     ** vdbe program
   139    139     */
   140    140     v = sqlite3GetVdbe(pParse);
          141  +  assert( pParse->isMultiWrite==0 || sqlite3VdbeMayAbort(v)==pParse->mayAbort );
   141    142     if( v ){
   142    143       sqlite3VdbeAddOp0(v, OP_Halt);
   143    144   
   144    145       /* The cookie mask contains one bit for each database file open.
   145    146       ** (Bit 0 is for main, bit 1 is for temp, and so forth.)  Bits are
   146    147       ** set for each database that is used.  Generate code to start a
   147    148       ** transaction on each used database and to verify the schema cookie

Changes to src/vdbe.h.

   185    185   int sqlite3VdbeMakeLabel(Vdbe*);
   186    186   void sqlite3VdbeDelete(Vdbe*);
   187    187   void sqlite3VdbeMakeReady(Vdbe*,int,int,int,int,int,int);
   188    188   int sqlite3VdbeFinalize(Vdbe*);
   189    189   void sqlite3VdbeResolveLabel(Vdbe*, int);
   190    190   int sqlite3VdbeCurrentAddr(Vdbe*);
   191    191   #ifdef SQLITE_DEBUG
          192  +  int sqlite3VdbeMayAbort(Vdbe*);
   192    193     void sqlite3VdbeTrace(Vdbe*,FILE*);
   193    194   #endif
   194    195   void sqlite3VdbeResetStepResult(Vdbe*);
   195    196   int sqlite3VdbeReset(Vdbe*);
   196    197   void sqlite3VdbeSetNumCols(Vdbe*,int);
   197    198   int sqlite3VdbeSetColName(Vdbe*, int, int, const char *, void(*)(void*));
   198    199   void sqlite3VdbeCountChanges(Vdbe*);

Changes to src/vdbeaux.c.

   235    235     int j = -1-x;
   236    236     assert( p->magic==VDBE_MAGIC_INIT );
   237    237     assert( j>=0 && j<p->nLabel );
   238    238     if( p->aLabel ){
   239    239       p->aLabel[j] = p->nOp;
   240    240     }
   241    241   }
          242  +
          243  +#ifdef SQLITE_DEBUG
          244  +
          245  +/*
          246  +** The following type and function are used to iterate through all opcodes
          247  +** in a Vdbe main program and each of the sub-programs (triggers) it may 
          248  +** invoke directly or indirectly. It should be used as follows:
          249  +**
          250  +**   Op *pOp;
          251  +**   VdbeOpIter sIter;
          252  +**
          253  +**   memset(&sIter, 0, sizeof(sIter));
          254  +**   sIter.v = v;                            // v is of type Vdbe* 
          255  +**   while( (pOp = opIterNext(&sIter)) ){
          256  +**     // Do something with pOp
          257  +**   }
          258  +**   sqlite3DbFree(v->db, sIter.apSub);
          259  +** 
          260  +*/
          261  +typedef struct VdbeOpIter VdbeOpIter;
          262  +struct VdbeOpIter {
          263  +  Vdbe *v;                   /* Vdbe to iterate through the opcodes of */
          264  +  SubProgram **apSub;        /* Array of subprograms */
          265  +  int nSub;                  /* Number of entries in apSub */
          266  +  int iAddr;                 /* Address of next instruction to return */
          267  +  int iSub;                  /* 0 = main program, 1 = first sub-program etc. */
          268  +};
          269  +static Op *opIterNext(VdbeOpIter *p){
          270  +  Vdbe *v = p->v;
          271  +  Op *pRet = 0;
          272  +  Op *aOp;
          273  +  int nOp;
          274  +
          275  +  if( p->iSub<=p->nSub ){
          276  +
          277  +    if( p->iSub==0 ){
          278  +      aOp = v->aOp;
          279  +      nOp = v->nOp;
          280  +    }else{
          281  +      aOp = p->apSub[p->iSub-1]->aOp;
          282  +      nOp = p->apSub[p->iSub-1]->nOp;
          283  +    }
          284  +    assert( p->iAddr<nOp );
          285  +
          286  +    pRet = &aOp[p->iAddr];
          287  +    p->iAddr++;
          288  +    if( p->iAddr==nOp ){
          289  +      p->iSub++;
          290  +      p->iAddr = 0;
          291  +    }
          292  +  
          293  +    if( pRet->p4type==P4_SUBPROGRAM ){
          294  +      int nByte = (p->nSub+1)*sizeof(SubProgram*);
          295  +      int j;
          296  +      for(j=0; j<p->nSub; j++){
          297  +        if( p->apSub[j]==pRet->p4.pProgram ) break;
          298  +      }
          299  +      if( j==p->nSub ){
          300  +        p->apSub = sqlite3DbReallocOrFree(v->db, p->apSub, nByte);
          301  +        if( !p->apSub ){
          302  +          pRet = 0;
          303  +        }else{
          304  +          p->apSub[p->nSub++] = pRet->p4.pProgram;
          305  +        }
          306  +      }
          307  +    }
          308  +  }
          309  +
          310  +  return pRet;
          311  +}
          312  +
          313  +/*
          314  +** Return true if the program stored in the VM passed as an argument may
          315  +** throw an ABORT exception (causing the statement, but not transaction
          316  +** to be rolled back). This condition is true if the main program or any
          317  +** sub-programs contains any of the following:
          318  +**
          319  +**   *  OP_Halt with P1=SQLITE_CONSTRAINT and P2=OE_Abort.
          320  +**   *  OP_HaltIfNull with P1=SQLITE_CONSTRAINT and P2=OE_Abort.
          321  +**   *  OP_Destroy
          322  +**   *  OP_VUpdate
          323  +**   *  OP_VRename
          324  +**
          325  +** This function is only used as part of an assert() statement. 
          326  +*/
          327  +int sqlite3VdbeMayAbort(Vdbe *v){
          328  +  int mayAbort = 0;
          329  +  Op *pOp;
          330  +  VdbeOpIter sIter;
          331  +  memset(&sIter, 0, sizeof(sIter));
          332  +  sIter.v = v;
          333  +
          334  +  while( (pOp = opIterNext(&sIter))!=0 ){
          335  +    int opcode = pOp->opcode;
          336  +    if( opcode==OP_Destroy || opcode==OP_VUpdate || opcode==OP_VRename 
          337  +     || ((opcode==OP_Halt || opcode==OP_HaltIfNull) 
          338  +      && (pOp->p1==SQLITE_CONSTRAINT && pOp->p2==OE_Abort))
          339  +    ){
          340  +      mayAbort = 1;
          341  +      break;
          342  +    }
          343  +  }
          344  +
          345  +  sqlite3DbFree(v->db, sIter.apSub);
          346  +  return mayAbort;
          347  +}
          348  +#endif
   242    349   
   243    350   /*
   244    351   ** Loop through the program looking for P2 values that are negative
   245    352   ** on jump instructions.  Each such value is a label.  Resolve the
   246    353   ** label by setting the P2 value to its correct non-zero value.
   247    354   **
   248    355   ** This routine is called once after all opcodes have been inserted.