/ Check-in [e6650e16]
Login

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

Overview
Comment:Replace the OP_IsUnique opcode with OP_NoConflict. This code simplification might be useful to move onto trunk even if this branch is never merged.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | omit-rowid
Files: files | file ages | folders
SHA1: e6650e16dd11327afd25961b2feb29ec8778c2ca
User & Date: drh 2013-10-26 13:36:51
Context
2013-10-26
15:40
Work on the UPDATE and INSERT logic. This is an incremental check-in so that can switch over to trunk to work on an unrelated issue there. check-in: 086ec2a1 user: drh tags: omit-rowid
13:36
Replace the OP_IsUnique opcode with OP_NoConflict. This code simplification might be useful to move onto trunk even if this branch is never merged. check-in: e6650e16 user: drh tags: omit-rowid
00:58
Minor refactoring of variable names and fixes to comments in insert.c. check-in: ae61a343 user: drh tags: omit-rowid
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/insert.c.

  1388   1388     /* Test all UNIQUE constraints by creating entries for each UNIQUE
  1389   1389     ** index and making sure that duplicate entries do not already exist.
  1390   1390     ** Add the new records to the indices as we go.
  1391   1391     */
  1392   1392     for(iCur=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, iCur++){
  1393   1393       int regIdx;
  1394   1394       int regR;
  1395         -    int addrSkipRow = 0;
         1395  +    int addrSkipRow = sqlite3VdbeMakeLabel(v);
  1396   1396   
  1397   1397       if( aRegIdx[iCur]==0 ) continue;  /* Skip unused indices */
  1398   1398   
  1399   1399       if( pIdx->pPartIdxWhere ){
  1400   1400         sqlite3VdbeAddOp2(v, OP_Null, 0, aRegIdx[iCur]);
  1401         -      addrSkipRow = sqlite3VdbeMakeLabel(v);
  1402   1401         pParse->ckBase = regData;
  1403   1402         sqlite3ExprIfFalse(pParse, pIdx->pPartIdxWhere, addrSkipRow,
  1404   1403                            SQLITE_JUMPIFNULL);
  1405   1404         pParse->ckBase = 0;
  1406   1405       }
  1407   1406   
  1408   1407       /* Create a key for accessing the index entry */
................................................................................
  1434   1433       if( seenReplace ){
  1435   1434         if( onError==OE_Ignore ) onError = OE_Replace;
  1436   1435         else if( onError==OE_Fail ) onError = OE_Abort;
  1437   1436       }
  1438   1437       
  1439   1438       /* Check to see if the new index entry will be unique */
  1440   1439       regR = sqlite3GetTempReg(pParse);
  1441         -    sqlite3VdbeAddOp2(v, OP_SCopy, regOldRowid, regR);
  1442         -    j3 = sqlite3VdbeAddOp4Int(v, OP_IsUnique, baseCur+iCur+1, 0, regR, regIdx);
         1440  +    sqlite3VdbeAddOp4Int(v, OP_NoConflict, baseCur+iCur+1, addrSkipRow,
         1441  +                         regIdx, pIdx->nKeyCol);
         1442  +    sqlite3VdbeAddOp2(v, OP_IdxRowid, baseCur+iCur+1, regR);
         1443  +    sqlite3VdbeAddOp3(v, OP_Eq, regR, addrSkipRow, regOldRowid);
  1443   1444       sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nKeyCol+1);
  1444   1445   
  1445   1446       /* Generate code that executes if the new index entry is not unique */
  1446   1447       assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail
  1447   1448           || onError==OE_Ignore || onError==OE_Replace );
  1448   1449       switch( onError ){
  1449   1450         case OE_Rollback:
................................................................................
  1486   1487           sqlite3GenerateRowDelete(
  1487   1488               pParse, pTab, pTrigger, baseCur, regR, 0, 0, OE_Replace
  1488   1489           );
  1489   1490           seenReplace = 1;
  1490   1491           break;
  1491   1492         }
  1492   1493       }
  1493         -    sqlite3VdbeJumpHere(v, j3);
  1494   1494       sqlite3VdbeResolveLabel(v, addrSkipRow);
  1495   1495       sqlite3ReleaseTempReg(pParse, regR);
  1496   1496     }
  1497   1497     
  1498   1498     if( pbMayReplace ){
  1499   1499       *pbMayReplace = seenReplace;
  1500   1500     }

Changes to src/sqliteInt.h.

  1538   1538   ** This structure holds a record that has already been disassembled
  1539   1539   ** into its constituent fields.
  1540   1540   */
  1541   1541   struct UnpackedRecord {
  1542   1542     KeyInfo *pKeyInfo;  /* Collation and sort-order information */
  1543   1543     u16 nField;         /* Number of entries in apMem[] */
  1544   1544     u8 flags;           /* Boolean settings.  UNPACKED_... below */
  1545         -  i64 rowid;          /* Used by UNPACKED_PREFIX_SEARCH */
  1546   1545     Mem *aMem;          /* Values */
  1547   1546   };
  1548   1547   
  1549   1548   /*
  1550   1549   ** Allowed values of UnpackedRecord.flags
  1551   1550   */
  1552   1551   #define UNPACKED_INCRKEY       0x01  /* Make this key an epsilon larger */
  1553   1552   #define UNPACKED_PREFIX_MATCH  0x02  /* A prefix match is considered OK */
  1554         -#define UNPACKED_PREFIX_SEARCH 0x04  /* Ignore final (rowid) field */
  1555   1553   
  1556   1554   /*
  1557   1555   ** Each SQL index is represented in memory by an
  1558   1556   ** instance of the following structure.
  1559   1557   **
  1560   1558   ** The columns of the table that are to be indexed are described
  1561   1559   ** by the aiColumn[] field of this structure.  For example, suppose

Changes to src/vdbe.c.

  3612   3612   ** If P4==0 then register P3 holds a blob constructed by MakeRecord.  If
  3613   3613   ** P4>0 then register P3 is the first of P4 registers that form an unpacked
  3614   3614   ** record.
  3615   3615   **
  3616   3616   ** Cursor P1 is on an index btree.  If the record identified by P3 and P4
  3617   3617   ** is a prefix of any entry in P1 then a jump is made to P2 and
  3618   3618   ** P1 is left pointing at the matching entry.
         3619  +**
         3620  +** See also: NotFound, NoConflict, NotExists. SeekGe
  3619   3621   */
  3620   3622   /* Opcode: NotFound P1 P2 P3 P4 *
  3621   3623   **
  3622   3624   ** If P4==0 then register P3 holds a blob constructed by MakeRecord.  If
  3623   3625   ** P4>0 then register P3 is the first of P4 registers that form an unpacked
  3624   3626   ** record.
  3625   3627   ** 
  3626   3628   ** Cursor P1 is on an index btree.  If the record identified by P3 and P4
  3627   3629   ** is not the prefix of any entry in P1 then a jump is made to P2.  If P1 
  3628   3630   ** does contain an entry whose prefix matches the P3/P4 record then control
  3629   3631   ** falls through to the next instruction and P1 is left pointing at the
  3630   3632   ** matching entry.
  3631   3633   **
  3632         -** See also: Found, NotExists, IsUnique
         3634  +** See also: Found, NotExists, NoConflict
  3633   3635   */
         3636  +/* Opcode: NoConflict P1 P2 P3 P4 *
         3637  +**
         3638  +** If P4==0 then register P3 holds a blob constructed by MakeRecord.  If
         3639  +** P4>0 then register P3 is the first of P4 registers that form an unpacked
         3640  +** record.
         3641  +** 
         3642  +** Cursor P1 is on an index btree.  If the record identified by P3 and P4
         3643  +** contains any NULL value, jump immediately to P2.  If all terms of the
         3644  +** record are not-NULL then a check is done to determine if any row in the
         3645  +** P1 index btree has a matching key prefix.  If there are no matches, jump
         3646  +** immediately to P2.  If there is a match, fall through and leave the P1
         3647  +** cursor pointing to the matching row.
         3648  +**
         3649  +** This opcode is similar to OP_NotFound with the exceptions that the
         3650  +** branch is always taken if any part of the search key input is NULL.
         3651  +**
         3652  +** See also: NotFound, Found, NotExists
         3653  +*/
         3654  +case OP_NoConflict:     /* jump, in3 */
  3634   3655   case OP_NotFound:       /* jump, in3 */
  3635   3656   case OP_Found: {        /* jump, in3 */
  3636   3657     int alreadyExists;
         3658  +  int ii;
  3637   3659     VdbeCursor *pC;
  3638   3660     int res;
  3639   3661     char *pFree;
  3640   3662     UnpackedRecord *pIdxKey;
  3641   3663     UnpackedRecord r;
  3642   3664     char aTempRec[ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem)*3 + 7];
  3643   3665   
  3644   3666   #ifdef SQLITE_TEST
  3645         -  sqlite3_found_count++;
         3667  +  if( pOp->opcode!=OP_NoConflict ) sqlite3_found_count++;
  3646   3668   #endif
  3647   3669   
  3648   3670     alreadyExists = 0;
  3649   3671     assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  3650   3672     assert( pOp->p4type==P4_INT32 );
  3651   3673     pC = p->apCsr[pOp->p1];
  3652   3674     assert( pC!=0 );
................................................................................
  3668   3690             pC->pKeyInfo, aTempRec, sizeof(aTempRec), &pFree
  3669   3691         ); 
  3670   3692         if( pIdxKey==0 ) goto no_mem;
  3671   3693         assert( pIn3->flags & MEM_Blob );
  3672   3694         assert( (pIn3->flags & MEM_Zero)==0 );  /* zeroblobs already expanded */
  3673   3695         sqlite3VdbeRecordUnpack(pC->pKeyInfo, pIn3->n, pIn3->z, pIdxKey);
  3674   3696         pIdxKey->flags |= UNPACKED_PREFIX_MATCH;
         3697  +    }
         3698  +    if( pOp->opcode==OP_NoConflict ){
         3699  +      /* For the OP_NoConflict opcode, take the jump if any of the
         3700  +      ** input fields are NULL, since any key with a NULL will not
         3701  +      ** conflict */
         3702  +      for(ii=0; ii<r.nField; ii++){
         3703  +        if( r.aMem[ii].flags & MEM_Null ){
         3704  +          pc = pOp->p2 - 1;
         3705  +          break;
         3706  +        }
         3707  +      }
  3675   3708       }
  3676   3709       rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, pIdxKey, 0, 0, &res);
  3677   3710       if( pOp->p4.i==0 ){
  3678   3711         sqlite3DbFree(db, pFree);
  3679   3712       }
  3680   3713       if( rc!=SQLITE_OK ){
  3681   3714         break;
................................................................................
  3686   3719       pC->cacheStatus = CACHE_STALE;
  3687   3720     }
  3688   3721     if( pOp->opcode==OP_Found ){
  3689   3722       if( alreadyExists ) pc = pOp->p2 - 1;
  3690   3723     }else{
  3691   3724       if( !alreadyExists ) pc = pOp->p2 - 1;
  3692   3725     }
  3693         -  break;
  3694         -}
  3695         -
  3696         -/* Opcode: IsUnique P1 P2 P3 P4 *
  3697         -**
  3698         -** Cursor P1 is open on an index b-tree - that is to say, a btree which
  3699         -** no data and where the key are records generated by OP_MakeRecord with
  3700         -** the list field being the integer ROWID of the entry that the index
  3701         -** entry refers to.
  3702         -**
  3703         -** The P3 register contains an integer record number. Call this record 
  3704         -** number R. Register P4 is the first in a set of N contiguous registers
  3705         -** that make up an unpacked index key that can be used with cursor P1.
  3706         -** The value of N can be inferred from the cursor. N includes the rowid
  3707         -** value appended to the end of the index record. This rowid value may
  3708         -** or may not be the same as R.
  3709         -**
  3710         -** If any of the N registers beginning with register P4 contains a NULL
  3711         -** value, jump immediately to P2.
  3712         -**
  3713         -** Otherwise, this instruction checks if cursor P1 contains an entry
  3714         -** where the first (N-1) fields match but the rowid value at the end
  3715         -** of the index entry is not R. If there is no such entry, control jumps
  3716         -** to instruction P2. Otherwise, the rowid of the conflicting index
  3717         -** entry is copied to register P3 and control falls through to the next
  3718         -** instruction.
  3719         -**
  3720         -** See also: NotFound, NotExists, Found
  3721         -*/
  3722         -case OP_IsUnique: {        /* jump, in3 */
  3723         -  u16 ii;
  3724         -  VdbeCursor *pCx;
  3725         -  BtCursor *pCrsr;
  3726         -  u16 nField;
  3727         -  Mem *aMx;
  3728         -  UnpackedRecord r;                  /* B-Tree index search key */
  3729         -  i64 R;                             /* Rowid stored in register P3 */
  3730         -
  3731         -  pIn3 = &aMem[pOp->p3];
  3732         -  aMx = &aMem[pOp->p4.i];
  3733         -  /* Assert that the values of parameters P1 and P4 are in range. */
  3734         -  assert( pOp->p4type==P4_INT32 );
  3735         -  assert( pOp->p4.i>0 && pOp->p4.i<=(p->nMem-p->nCursor) );
  3736         -  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  3737         -
  3738         -  /* Find the index cursor. */
  3739         -  pCx = p->apCsr[pOp->p1];
  3740         -  assert( pCx->deferredMoveto==0 );
  3741         -  pCx->seekResult = 0;
  3742         -  pCx->cacheStatus = CACHE_STALE;
  3743         -  pCrsr = pCx->pCursor;
  3744         -
  3745         -  /* If any of the values are NULL, take the jump. */
  3746         -  nField = pCx->pKeyInfo->nField;
  3747         -  for(ii=0; ii<nField; ii++){
  3748         -    if( aMx[ii].flags & MEM_Null ){
  3749         -      pc = pOp->p2 - 1;
  3750         -      pCrsr = 0;
  3751         -      break;
  3752         -    }
  3753         -  }
  3754         -  assert( (aMx[nField].flags & MEM_Null)==0 );
  3755         -
  3756         -  if( pCrsr!=0 ){
  3757         -    /* Populate the index search key. */
  3758         -    r.pKeyInfo = pCx->pKeyInfo;
  3759         -    r.nField = nField + 1;
  3760         -    r.flags = UNPACKED_PREFIX_SEARCH;
  3761         -    r.aMem = aMx;
  3762         -#ifdef SQLITE_DEBUG
  3763         -    { int i; for(i=0; i<r.nField; i++) assert( memIsValid(&r.aMem[i]) ); }
  3764         -#endif
  3765         -
  3766         -    /* Extract the value of R from register P3. */
  3767         -    sqlite3VdbeMemIntegerify(pIn3);
  3768         -    R = pIn3->u.i;
  3769         -
  3770         -    /* Search the B-Tree index. If no conflicting record is found, jump
  3771         -    ** to P2. Otherwise, copy the rowid of the conflicting record to
  3772         -    ** register P3 and fall through to the next instruction.  */
  3773         -    rc = sqlite3BtreeMovetoUnpacked(pCrsr, &r, 0, 0, &pCx->seekResult);
  3774         -    if( (r.flags & UNPACKED_PREFIX_SEARCH) || r.rowid==R ){
  3775         -      pc = pOp->p2 - 1;
  3776         -    }else{
  3777         -      pIn3->u.i = r.rowid;
  3778         -    }
  3779         -  }
  3780   3726     break;
  3781   3727   }
  3782   3728   
  3783   3729   /* Opcode: NotExists P1 P2 P3 * *
  3784   3730   **
  3785   3731   ** P1 is the index of a cursor open on an SQL table btree (with integer
  3786   3732   ** keys).  P3 is an integer rowid.  If P1 does not contain a record with

Changes to src/vdbeaux.c.

  3056   3056       d1 += sqlite3VdbeSerialGet(&aKey1[d1], serial_type1, &mem1);
  3057   3057   
  3058   3058       /* Do the comparison
  3059   3059       */
  3060   3060       rc = sqlite3MemCompare(&mem1, &pPKey2->aMem[i], pKeyInfo->aColl[i]);
  3061   3061       if( rc!=0 ){
  3062   3062         assert( mem1.zMalloc==0 );  /* See comment below */
  3063         -
  3064         -      /* Invert the result if we are using DESC sort order. */
  3065   3063         if( pKeyInfo->aSortOrder[i] ){
  3066         -        rc = -rc;
         3064  +        rc = -rc;  /* Invert the result for DESC sort order. */
  3067   3065         }
  3068         -    
  3069         -      /* If the PREFIX_SEARCH flag is set and all fields except the final
  3070         -      ** rowid field were equal, then clear the PREFIX_SEARCH flag and set 
  3071         -      ** pPKey2->rowid to the value of the rowid field in (pKey1, nKey1).
  3072         -      ** This is used by the OP_IsUnique opcode.
  3073         -      */
  3074         -      if( (pPKey2->flags & UNPACKED_PREFIX_SEARCH) && i==(pPKey2->nField-1) ){
  3075         -        assert( idx1==szHdr1 && rc );
  3076         -        assert( mem1.flags & MEM_Int );
  3077         -        pPKey2->flags &= ~UNPACKED_PREFIX_SEARCH;
  3078         -        pPKey2->rowid = mem1.u.i;
  3079         -      }
  3080         -    
  3081   3066         return rc;
  3082   3067       }
  3083   3068       i++;
  3084   3069     }
  3085   3070   
  3086   3071     /* No memory allocation is ever used on mem1.  Prove this using
  3087   3072     ** the following assert().  If the assert() fails, it indicates a