diff --git a/manifest b/manifest index 5fab331f65..ef7cc85598 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Rename\sthe\sColumn.eType\sfield\sto\sColumn.eCType\s-\swith\san\sextra\s"C". -D 2021-08-18T12:05:22.798 +C What\swould\sit\sbe\slike\sif\syou\scould\sadd\sthe\skeyword\s"STRICT"\safter\sa\sCREATE\nTABLE\sstatement\sto\scause\sthe\stable\sto\s(1)\sallow\sonly\sa\sfew\swell-defined\ndatatypes,\s(2)\srigidly\senforce\sthose\stypes,\s(3)\srequire\sNOT\sNULL\son\sPK\ncolumns,\s(4)\salways\senforce\sforeign\skey\sconstraint,\sand\sso\sforth?\s\sThis\nbranch\sseeks\sto\sexplore\sthat\squestion. +D 2021-08-18T13:13:58.021 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -488,7 +488,7 @@ F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 F src/btree.c e204a9c8fb4fe5dbb910a863ba487f4af9b5c501254ec4ccbfcdd6b1f65b7fb4 F src/btree.h 74d64b8f28cfa4a894d14d4ed64fa432cd697b98b61708d4351482ae15913e22 F src/btreeInt.h 7bc15a24a02662409ebcd6aeaa1065522d14b7fda71573a2b0568b458f514ae0 -F src/build.c 0374faa35f0920c51147a20bb3462fae22310f2acaf29721ca99821fc7232548 +F src/build.c bf8b4f6f4fb9620eedadaa9513a2682b9ff80c643285f56d9ea34105dc3c2e2b F src/callback.c d0b853dd413255d2e337b34545e54d888ea02f20da5ad0e63585b389624c4a6c F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/ctime.c 8159d5f706551861c18ec6c8f6bdf105e15ea00367f05d9ab65d31a1077facc1 @@ -533,7 +533,7 @@ F src/os_win.c 77d39873836f1831a9b0b91894fec45ab0e9ca8e067dc8c549e1d1eca1566fe9 F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a F src/pager.c 95c255256b13827caf038c8f963d334784073f38ab6ef9d70371d9d04f3c43e0 F src/pager.h 4bf9b3213a4b2bebbced5eaa8b219cf25d4a82f385d093cd64b7e93e5285f66f -F src/parse.y 0ba0baec5de6921ec8ba8bbcf1018969144ef29d26112e17539d8fbb1662e3eb +F src/parse.y 86aa016b281f61d7664dd8cb7808cab8114d14cfaf362a9b9fc9ead8f33546b7 F src/pcache.c 385ff064bca69789d199a98e2169445dc16e4291fa807babd61d4890c3b34177 F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586 F src/pcache1.c 54881292a9a5db202b2c0ac541c5e3ef9a5e8c4f1c1383adb2601d5499a60e65 @@ -549,7 +549,7 @@ F src/shell.c.in f795a4ae3c35631f5edcfa754c7824ff1d8a75b23a07e22e664b50f82e82634 F src/sqlite.h.in 43fcf0fe2af04081f420a906fc020bde1243851ba44b0aa567a27f94bf8c3145 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h e97f4e9b509408fea4c4e9bef5a41608dfac343b4d3c7a990dedde1e19af9510 -F src/sqliteInt.h a65ddfb177549c82dcd1374a2f23260328eb65ced55b50843419386177e159be +F src/sqliteInt.h 25581e591444d7be1eda83890a8828b28b8ff4c65ffd85a15acd4f0820260821 F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657 F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 @@ -1425,6 +1425,7 @@ F test/stat.test 15a3106eddedfc882f64bc09f237b4169be4b92dd57c93031b8ff8b13af3e7c F test/statfault.test f525a7bf633e50afd027700e9a486090684b1ac1 F test/stmt.test 54ed2cc0764bf3e48a058331813c3dbd19fc1d0827c3d8369914a5d8f564ec75 F test/stmtvtab1.test 6873dfb24f8e79cbb5b799b95c2e4349060eb7a3b811982749a84b359468e2d5 +F test/strict1.test d84d23c8b2e2742277d943db3a56d2cf0d886ad9bb4de46228aa6c7c676f6553 F test/subjournal.test 8d4e2572c0ee9a15549f0d8e40863161295107e52f07a3e8012a2e1fdd093c49 F test/subquery.test d7268d193dd33d5505df965399d3a594e76ae13f F test/subquery2.test 90cf944b9de8204569cf656028391e4af1ccc8c0cc02d4ef38ee3be8de1ffb12 @@ -1920,7 +1921,10 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 7cca80808cef192fe0479477056a028e230a164fd368e72100def065d424ca2c -R b66c8f57a17fe88d4036ed4eb83a05fb +P b9b0dcd5af072c22f2ce71cf9584b5b572fbcfbce6410a7d703b586adb8938ba +R d1aed29af5d2a129b155039aa4e933b3 +T *branch * strict-tables +T *sym-strict-tables * +T -sym-trunk * U drh -Z 2628ebdae9db72c0a61ecc0e228d76e8 +Z d972776960407c2f55c8c38fcd2522b6 diff --git a/manifest.uuid b/manifest.uuid index e1f9e77716..cbd5beb27c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b9b0dcd5af072c22f2ce71cf9584b5b572fbcfbce6410a7d703b586adb8938ba \ No newline at end of file +78732b9f98936693ae29c85a692c35a84c7d065aec79903af34b08d18f10a5e6 \ No newline at end of file diff --git a/src/build.c b/src/build.c index 69717edd23..72520cc79a 100644 --- a/src/build.c +++ b/src/build.c @@ -2554,7 +2554,7 @@ void sqlite3EndTable( Parse *pParse, /* Parse context */ Token *pCons, /* The ',' token after the last column defn. */ Token *pEnd, /* The ')' before options in the CREATE TABLE */ - u8 tabOpts, /* Extra table options. Usually 0. */ + u32 tabOpts, /* Extra table options. Usually 0. */ Select *pSelect /* Select from a "CREATE ... AS SELECT" */ ){ Table *p; /* The new table */ @@ -2590,6 +2590,21 @@ void sqlite3EndTable( if( p->tnum==1 ) p->tabFlags |= TF_Readonly; } + /* Do not allow COLTYPE_CUSTOM in STRICT mode */ + if( tabOpts & TF_Strict ){ + int ii; + p->tabFlags |= TF_Strict; + for(ii=0; iinCol; ii++){ + if( p->aCol[ii].eCType==COLTYPE_CUSTOM ){ + sqlite3ErrorMsg(pParse, + "unknown datatype for %s.%s: \"%s\"", + p->zName, p->aCol[ii].zCnName, sqlite3ColumnType(p->aCol+ii, "") + ); + return; + } + } + } + assert( (p->tabFlags & TF_HasPrimaryKey)==0 || p->iPKey>=0 || sqlite3PrimaryKeyIndex(p)!=0 ); assert( (p->tabFlags & TF_HasPrimaryKey)!=0 diff --git a/src/parse.y b/src/parse.y index 24c539bdb3..08657f93be 100644 --- a/src/parse.y +++ b/src/parse.y @@ -196,16 +196,19 @@ ifnotexists(A) ::= IF NOT EXISTS. {A = 1;} temp(A) ::= TEMP. {A = pParse->db->init.busy==0;} %endif SQLITE_OMIT_TEMPDB temp(A) ::= . {A = 0;} -create_table_args ::= LP columnlist conslist_opt(X) RP(E) table_options(F). { +create_table_args ::= LP columnlist conslist_opt(X) RP(E) table_option_set(F). { sqlite3EndTable(pParse,&X,&E,F,0); } create_table_args ::= AS select(S). { sqlite3EndTable(pParse,0,0,0,S); sqlite3SelectDelete(pParse->db, S); } -%type table_options {int} -table_options(A) ::= . {A = 0;} -table_options(A) ::= WITHOUT nm(X). { +%type table_option_set {u32} +%type table_option {u32} +table_option_set(A) ::= . {A = 0;} +table_option_set(A) ::= table_option(A). +table_option_set(A) ::= table_option_set(X) COMMA table_option(Y). {A = X|Y;} +table_option(A) ::= WITHOUT nm(X). { if( X.n==5 && sqlite3_strnicmp(X.z,"rowid",5)==0 ){ A = TF_WithoutRowid | TF_NoVisibleRowid; }else{ @@ -213,6 +216,14 @@ table_options(A) ::= WITHOUT nm(X). { sqlite3ErrorMsg(pParse, "unknown table option: %.*s", X.n, X.z); } } +table_option(A) ::= nm(X). { + if( X.n==6 && sqlite3_strnicmp(X.z,"strict",6)==0 ){ + A = TF_Strict; + }else{ + A = 0; + sqlite3ErrorMsg(pParse, "unknown table option: %.*s", X.n, X.z); + } +} columnlist ::= columnlist COMMA columnname carglist. columnlist ::= columnname carglist. columnname(A) ::= nm(A) typetoken(Y). {sqlite3AddColumn(pParse,A,Y);} diff --git a/src/sqliteInt.h b/src/sqliteInt.h index ade7399d85..5a3acfd035 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -2284,6 +2284,7 @@ struct Table { #define TF_HasStat4 0x00002000 /* STAT4 info available for this table */ #define TF_Ephemeral 0x00004000 /* An ephemeral table */ #define TF_Eponymous 0x00008000 /* An eponymous virtual table */ +#define TF_Strict 0x00010000 /* STRICT mode */ /* ** Allowed values for Table.eTabType @@ -4435,7 +4436,7 @@ void sqlite3AddCheckConstraint(Parse*, Expr*, const char*, const char*); void sqlite3AddDefaultValue(Parse*,Expr*,const char*,const char*); void sqlite3AddCollateType(Parse*, Token*); void sqlite3AddGenerated(Parse*,Expr*,Token*); -void sqlite3EndTable(Parse*,Token*,Token*,u8,Select*); +void sqlite3EndTable(Parse*,Token*,Token*,u32,Select*); void sqlite3AddReturning(Parse*,ExprList*); int sqlite3ParseUri(const char*,const char*,unsigned int*, sqlite3_vfs**,char**,char **); diff --git a/test/strict1.test b/test/strict1.test new file mode 100644 index 0000000000..303ec30922 --- /dev/null +++ b/test/strict1.test @@ -0,0 +1,41 @@ +# 2021-08-18 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# +# This file implements regression tests for SQLite library. The +# focus of this file is testing STRICT tables. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix strict1 + +# STRICT tables have on a limited number of allowed datatypes. +# +do_catchsql_test strict1-1.1 { + CREATE TABLE t1(a) STRICT; +} {1 {unknown datatype for t1.a: ""}} +do_catchsql_test strict1-1.2 { + CREATE TABLE t1(a PRIMARY KEY) STRICT, WITHOUT ROWID; +} {1 {unknown datatype for t1.a: ""}} +do_catchsql_test strict1-1.3 { + CREATE TABLE t1(a PRIMARY KEY) WITHOUT ROWID, STRICT; +} {1 {unknown datatype for t1.a: ""}} +do_catchsql_test strict1-1.4 { + CREATE TABLE t1(a BANJO PRIMARY KEY) WITHOUT ROWID, STRICT; +} {1 {unknown datatype for t1.a: "BANJO"}} +do_catchsql_test strict1-1.5 { + CREATE TABLE t1(a TEXT PRIMARY KEY, b INT, c INTEGER, d REAL, e BLOB, f DATE) strict; +} {1 {unknown datatype for t1.f: "DATE"}} +do_catchsql_test strict1-1.6 { + CREATE TABLE t1(a TEXT PRIMARY KEY, b INT, c INTEGER, d REAL, e BLOB, f TEXT(50)) WITHOUT ROWID, STRICT; +} {1 {unknown datatype for t1.f: "TEXT(50)"}} + +finish_test