aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <>2021-08-19 16:29:33 +0000
committerdrh <>2021-08-19 16:29:33 +0000
commit71c770fbda6683780c314ad5ebfa3be3c0c2c718 (patch)
treeea312c7c7b5863acc2ce5325d2726db08b14226b /src
parent9e1209d111aab64242aec299b347e60492556761 (diff)
downloadsqlite-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.c12
-rw-r--r--src/global.c12
-rw-r--r--src/insert.c44
-rw-r--r--src/pragma.c21
-rw-r--r--src/vdbe.c43
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++){