diff options
author | drh <> | 2021-08-19 16:29:33 +0000 |
---|---|---|
committer | drh <> | 2021-08-19 16:29:33 +0000 |
commit | 71c770fbda6683780c314ad5ebfa3be3c0c2c718 (patch) | |
tree | ea312c7c7b5863acc2ce5325d2726db08b14226b /src | |
parent | 9e1209d111aab64242aec299b347e60492556761 (diff) | |
download | sqlite-71c770fbda6683780c314ad5ebfa3be3c0c2c718.tar.gz sqlite-71c770fbda6683780c314ad5ebfa3be3c0c2c718.zip |
Improved comments. Fewer opcodes for integrity_check on strict tables.
FossilOrigin-Name: 4ee57fb588b41ab76649c605f57c7bcf5b7b638435af458d69f69a8ccbb121e8
Diffstat (limited to 'src')
-rw-r--r-- | src/build.c | 12 | ||||
-rw-r--r-- | src/global.c | 12 | ||||
-rw-r--r-- | src/insert.c | 44 | ||||
-rw-r--r-- | src/pragma.c | 21 | ||||
-rw-r--r-- | src/vdbe.c | 43 |
5 files changed, 93 insertions, 39 deletions
diff --git a/src/build.c b/src/build.c index bf9746de0..783b9b7ec 100644 --- a/src/build.c +++ b/src/build.c @@ -2592,7 +2592,15 @@ void sqlite3EndTable( if( p->tnum==1 ) p->tabFlags |= TF_Readonly; } - /* Do not allow COLTYPE_CUSTOM in STRICT mode */ + /* Special processing for tables that include the STRICT keyword: + ** + ** * Do not allow custom column datatypes. Every column must have + ** a datatype that is one of INT, INTEGER, REAL, TEXT, or BLOB. + ** + ** * If a PRIMARY KEY is defined, other than the INTEGER PRIMARY KEY, + ** then all columns of the PRIMARY KEY must have a NOT NULL + ** constraint. + */ if( tabOpts & TF_Strict ){ int ii; p->tabFlags |= TF_Strict; @@ -2609,8 +2617,6 @@ void sqlite3EndTable( && p->iPKey!=ii && pCol->notNull == OE_None ){ - /* Primary key columns other than the IPK may not be NULL - ** in strict mode */ pCol->notNull = OE_Abort; p->tabFlags |= TF_HasNotNull; } diff --git a/src/global.c b/src/global.c index 98793fbd3..091310c93 100644 --- a/src/global.c +++ b/src/global.c @@ -351,6 +351,18 @@ const char sqlite3StrBINARY[] = "BINARY"; /* ** Standard typenames. These names must match the COLTYPE_* definitions. ** Adjust the SQLITE_N_STDTYPE value if adding or removing entries. +** +** sqlite3StdType[] The actual names of the datatypes. +** +** sqlite3StdTypeLen[] The length (in bytes) of each entry +** in sqlite3StdType[]. +** +** sqlite3StdTypeAffinity[] The affinity associated with each entry +** in sqlite3StdType[]. +** +** sqlite3StdTypeMap[] The type value (as returned from +** sqlite3_column_type() or sqlite3_value_type()) +** for each entry in sqlite3StdType[]. */ const unsigned char sqlite3StdTypeLen[] = { 4, 3, 7, 4, 4 }; const char sqlite3StdTypeAffinity[] = { diff --git a/src/insert.c b/src/insert.c index 1148257ad..9617e54e7 100644 --- a/src/insert.c +++ b/src/insert.c @@ -110,24 +110,44 @@ const char *sqlite3IndexAffinityStr(sqlite3 *db, Index *pIdx){ } /* +** Make changes to the evolving bytecode to do affinity transformations +** of values that are about to be gathered into a row for table pTab. +** +** For ordinary (legacy, non-strict) tables: +** ----------------------------------------- +** ** Compute the affinity string for table pTab, if it has not already been ** computed. As an optimization, omit trailing SQLITE_AFF_BLOB affinities. ** -** If the affinity exists (if it is not entirely SQLITE_AFF_BLOB values) and -** if iReg>0 then code an OP_Affinity opcode that will set the affinities -** for register iReg and following. Or if affinities exists and iReg==0, +** If the affinity string is empty (because it was all SQLITE_AFF_BLOB entries +** which were then optimized out) then this routine becomes a no-op. +** +** Otherwise if iReg>0 then code an OP_Affinity opcode that will set the +** affinities for register iReg and following. Or if iReg==0, ** then just set the P4 operand of the previous opcode (which should be ** an OP_MakeRecord) to the affinity string. ** ** A column affinity string has one character per column: ** -** Character Column affinity -** ------------------------------ -** 'A' BLOB -** 'B' TEXT -** 'C' NUMERIC -** 'D' INTEGER -** 'E' REAL +** Character Column affinity +** --------- --------------- +** 'A' BLOB +** 'B' TEXT +** 'C' NUMERIC +** 'D' INTEGER +** 'E' REAL +** +** For STRICT tables: +** ------------------ +** +** Generate an appropropriate OP_TypeCheck opcode that will verify the +** datatypes against the column definitions in pTab. If iReg==0, that +** means an OP_MakeRecord opcode has already been generated and should be +** the last opcode generated. The new OP_TypeCheck needs to be inserted +** before the OP_MakeRecord. The new OP_TypeCheck should use the same +** register set as the OP_MakeRecord. If iReg>0 then register iReg is +** the first of a series of registers that will form the new record. +** Apply the type checking to that array of registers. */ void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){ int i, j; @@ -140,6 +160,8 @@ void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){ VdbeOp *pPrev; sqlite3VdbeAppendP4(v, pTab, P4_TABLE); pPrev = sqlite3VdbeGetOp(v, -1); + assert( pPrev!=0 ); + assert( pPrev->opcode==OP_MakeRecord || sqlite3VdbeDb(v)->mallocFailed ); pPrev->opcode = OP_TypeCheck; sqlite3VdbeAddOp3(v, OP_MakeRecord, pPrev->p1, pPrev->p2, pPrev->p3); }else{ @@ -175,6 +197,8 @@ void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){ if( iReg ){ sqlite3VdbeAddOp4(v, OP_Affinity, iReg, i, 0, zColAff, i); }else{ + assert( sqlite3VdbeGetOp(v, -1)->opcode==OP_MakeRecord + || sqlite3VdbeDb(v)->mallocFailed ); sqlite3VdbeChangeP4(v, -1, zColAff, i); } } diff --git a/src/pragma.c b/src/pragma.c index 39095d82d..dd1aaf978 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -1675,6 +1675,7 @@ void sqlite3Pragma( /* Sanity check on record header decoding */ sqlite3VdbeAddOp3(v, OP_Column, iDataCur, pTab->nNVCol-1,3); sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG); + VdbeComment((v, "(right-most column)")); } /* Verify that all NOT NULL columns really are NOT NULL. At the ** same time verify the type of the content of STRICT tables */ @@ -1682,37 +1683,37 @@ void sqlite3Pragma( for(j=0; j<pTab->nCol; j++){ char *zErr; Column *pCol = pTab->aCol + j; - int endLabel; + int doError, jmp2; if( j==pTab->iPKey ) continue; if( pCol->notNull==0 && !bStrict ) continue; - endLabel = bStrict ? sqlite3VdbeMakeLabel(pParse) : 0; + doError = bStrict ? sqlite3VdbeMakeLabel(pParse) : 0; sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, j, 3); if( sqlite3VdbeGetOp(v,-1)->opcode==OP_Column ){ sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG); } if( pCol->notNull ){ - int jmp2; jmp2 = sqlite3VdbeAddOp1(v, OP_NotNull, 3); VdbeCoverage(v); zErr = sqlite3MPrintf(db, "NULL value in %s.%s", pTab->zName, pCol->zCnName); sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC); - integrityCheckResultRow(v); - if( bStrict ) sqlite3VdbeGoto(v, endLabel); + if( bStrict ){ + sqlite3VdbeGoto(v, doError); + }else{ + integrityCheckResultRow(v); + } sqlite3VdbeJumpHere(v, jmp2); } if( pTab->tabFlags & TF_Strict ){ - if( pCol->notNull==0 ){ - sqlite3VdbeAddOp2(v, OP_IsNull, 3, endLabel); VdbeCoverage(v); - } - sqlite3VdbeAddOp3(v, OP_IfType, 3, endLabel, + jmp2 = sqlite3VdbeAddOp3(v, OP_IsNullOrType, 3, 0, sqlite3StdTypeMap[pCol->eCType-1]); VdbeCoverage(v); zErr = sqlite3MPrintf(db, "non-%s value in %s.%s", sqlite3StdType[pCol->eCType-1], pTab->zName, pTab->aCol[j].zCnName); sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC); + sqlite3VdbeResolveLabel(v, doError); integrityCheckResultRow(v); - sqlite3VdbeResolveLabel(v, endLabel); + sqlite3VdbeJumpHere(v, jmp2); } } /* Verify CHECK constraints */ diff --git a/src/vdbe.c b/src/vdbe.c index 01da0a956..690687a05 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -2502,6 +2502,22 @@ case OP_IsNull: { /* same as TK_ISNULL, jump, in1 */ break; } +/* Opcode: IsNullOrType P1 P2 P3 * * +** Synopsis: if typeof(r[P1]) IN (P3,5) goto P2 +** +** Jump to P2 if the value in register P1 is NULL or has a datatype P3. +** P3 is an integer which should be one of SQLITE_INTEGER, SQLITE_FLOAT, +** SQLITE_BLOB, SQLITE_NULL, or SQLITE_TEXT. +*/ +case OP_IsNullOrType: { /* jump, in1 */ + int doTheJump; + pIn1 = &aMem[pOp->p1]; + doTheJump = (pIn1->flags & MEM_Null)!=0 || sqlite3_value_type(pIn1)==pOp->p3; + VdbeBranchTaken( doTheJump, 2); + if( doTheJump ) goto jump_to_p2; + break; +} + /* Opcode: ZeroOrNull P1 P2 P3 * * ** Synopsis: r[P2] = 0 OR NULL ** @@ -2534,22 +2550,6 @@ case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */ break; } -/* Opcode: IfType P1 P2 P3 * * -** Synopsis: if typeof(r[P1])!=P3 goto P2 -** -** Jump to P2 if the value in register has a datatype given by P3. -** P3 is an integer which should be one of SQLITE_INTEGER, SQLITE_FLOAT, -** SQLITE_BLOB, SQLITE_NULL, or SQLITE_TEXT. -*/ -case OP_IfType: { /* jump, in1 */ - int doTheJump; - pIn1 = &aMem[pOp->p1]; - doTheJump = sqlite3_value_type(pIn1)==pOp->p3; - VdbeBranchTaken( doTheJump, 2); - if( doTheJump ) goto jump_to_p2; - break; -} - /* Opcode: IfNullRow P1 P2 P3 * * ** Synopsis: if P1.nullRow then r[P3]=NULL, goto P2 ** @@ -2896,6 +2896,16 @@ op_column_corrupt: ** This opcode is similar to OP_Affinity except that this opcode ** forces the register type to the Table column type. This is used ** to implement "strict affinity". +** +** Preconditions: +** +** <ul> +** <li> P2 should be the number of non-virtual columns in the +** table of P4. +** <li> Table P4 should be a STRICT table. +** </ul> +** +** If any precondition is false, an assertion fault occurs. */ case OP_TypeCheck: { Table *pTab; @@ -2905,6 +2915,7 @@ case OP_TypeCheck: { assert( pOp->p4type==P4_TABLE ); pTab = pOp->p4.pTab; assert( pTab->tabFlags & TF_Strict ); + assert( pTab->nNVCol==pOp->p2 ); aCol = pTab->aCol; pIn1 = &aMem[pOp->p1]; for(i=0; i<pTab->nCol; i++){ |