diff options
author | drh <drh@noemail.net> | 2015-08-24 15:39:42 +0000 |
---|---|---|
committer | drh <drh@noemail.net> | 2015-08-24 15:39:42 +0000 |
commit | bc622bc045a919b491be2d1ba0c56fd5fd7ff22f (patch) | |
tree | 10b75608eb02240f45844d85bdb23ece7e3bae2d | |
parent | 80d874083b38c5e24d854a76ab07b791fb0dc2cb (diff) | |
download | sqlite-bc622bc045a919b491be2d1ba0c56fd5fd7ff22f.tar.gz sqlite-bc622bc045a919b491be2d1ba0c56fd5fd7ff22f.zip |
Disallow the use of COLLATE clauses and the ASC and DESC keywords within
foreign key constraints and in the argument list to common table expressions.
FossilOrigin-Name: 83cbc4d8761498647794affffa961a4fca311be7
-rw-r--r-- | manifest | 19 | ||||
-rw-r--r-- | manifest.uuid | 2 | ||||
-rw-r--r-- | src/build.c | 35 | ||||
-rw-r--r-- | src/expr.c | 15 | ||||
-rw-r--r-- | src/parse.y | 10 | ||||
-rw-r--r-- | src/sqliteInt.h | 4 | ||||
-rw-r--r-- | test/parser1.test | 58 |
7 files changed, 126 insertions, 17 deletions
@@ -1,5 +1,5 @@ -C Improvements\sto\sJSON\sstring\sdequoting. -D 2015-08-24T12:42:41.080 +C Disallow\sthe\suse\sof\sCOLLATE\sclauses\sand\sthe\sASC\sand\sDESC\skeywords\swithin\nforeign\skey\sconstraints\sand\sin\sthe\sargument\slist\sto\scommon\stable\sexpressions. +D 2015-08-24T15:39:42.405 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in e2218eb228374422969de7b1680eda6864affcef F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -282,14 +282,14 @@ F src/btmutex.c 45a968cc85afed9b5e6cf55bf1f42f8d18107f79 F src/btree.c f48b3ef91676c06a90a8832987ecef6b94c931ee F src/btree.h 969adc948e89e449220ff0ff724c94bb2a52e9f1 F src/btreeInt.h 8177c9ab90d772d6d2c6c517e05bed774b7c92c0 -F src/build.c 5eb5d055a1d1cdaaea25e01b12607aa894bc0911 +F src/build.c f49c55c1fba430c2d6af5039d0bf14de5ae6a427 F src/callback.c 7b44ce59674338ad48b0e84e7b72f935ea4f68b0 F src/complete.c addcd8160b081131005d5bc2d34adf20c1c5c92f F src/ctime.c 5a0b735dc95604766f5dac73973658eef782ee8b F src/date.c 8ec787fed4929d8ccdf6b1bc360fccc3e1d2ca58 F src/dbstat.c f402e77e25089c6003d0c60b3233b9b3947d599a F src/delete.c 8857a6f27560718f65d43bdbec86c967ae1f8dfa -F src/expr.c c34408e0ac1c57cf58ffa2003b339715ee9bda57 +F src/expr.c c05d67f1a03c097d5c29839d5a538cfde9c472ce F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c c9b63a217d86582c22121699a47f22f524608869 F src/func.c 824bea430d3a2b7dbc62806ad54da8fdb8ed9e3f @@ -326,7 +326,7 @@ F src/os_win.c 40b3af7a47eb1107d0d69e592bec345a3b7b798a F src/os_win.h eb7a47aa17b26b77eb97e4823f20a00b8bda12ca F src/pager.c aa916ca28606ccf4b6877dfc2b643ccbca86589f F src/pager.h 6d435f563b3f7fcae4b84433b76a6ac2730036e2 -F src/parse.y ad9af8552f6f340bd646577ca63356a6f82b6a7e +F src/parse.y b5e0a5f8bb9ec33a58aa34850b6fae46aac51fdd F src/pcache.c cde06aa50962595e412d497e22fd2e07878ba1f0 F src/pcache.h 9968603796240cdf83da7e7bef76edf90619cea9 F src/pcache1.c a3fe31b17e841ec70beee72a2c960e9c787a8857 @@ -342,7 +342,7 @@ F src/shell.c b1f91e60918df3a68efad1e3a11696b9a7e23d23 F src/sqlite.h.in 378bebc8fe6a88bade25e5f23b7e6123fdc64b00 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h f700e6a9dd1fdcccc9951ab022b366fb66b9e413 -F src/sqliteInt.h 89e68539d645db597366a91411468b51e73c21a0 +F src/sqliteInt.h 1741691824491c330dda1e49f370920bfd3aa230 F src/sqliteLimit.h 216557999cb45f2e3578ed53ebefe228d779cb46 F src/status.c f266ad8a2892d659b74f0f50cb6a88b6e7c12179 F src/table.c 51b46b2a62d1b3a959633d593b89bab5e2c9155e @@ -910,6 +910,7 @@ F test/pagerfault2.test caf4c7facb914fd3b03a17b31ae2b180c8d6ca1f F test/pagerfault3.test 1003fcda009bf48a8e22a516e193b6ef0dd1bbd8 F test/pageropt.test 6b8f6a123a5572c195ad4ae40f2987007923bbd6 F test/pagesize.test 5769fc62d8c890a83a503f67d47508dfdc543305 +F test/parser1.test 23867b6f2c4758c7774108826d9f17e9cd17bcde F test/pcache.test c8acbedd3b6fd0f9a7ca887a83b11d24a007972b F test/pcache2.test af7f3deb1a819f77a6d0d81534e97d1cf62cd442 F test/percentile.test 4243af26b8f3f4555abe166f723715a1f74c77ff @@ -1378,7 +1379,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P f0aba0e120074430cd7ad93291fcc97b8a25a054 -R 3625d17566ea8cc316dd4952d6bffb99 +P 196d66d34d9783622e6f2f79eafea1488fc6f5cf +R 2a74528f51d8172b5387a3b7f110bb2b U drh -Z 6090b9f6d755a9917a579931aff72e9d +Z ffc4f8e604c67b08cae8ed1eda808a43 diff --git a/manifest.uuid b/manifest.uuid index bf64eaf06..9ca8f1fa7 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -196d66d34d9783622e6f2f79eafea1488fc6f5cf
\ No newline at end of file +83cbc4d8761498647794affffa961a4fca311be7
\ No newline at end of file diff --git a/src/build.c b/src/build.c index e45908dc3..0a816b398 100644 --- a/src/build.c +++ b/src/build.c @@ -1321,7 +1321,7 @@ void sqlite3AddPrimaryKey( } if( nTerm==1 && zType && sqlite3StrICmp(zType, "INTEGER")==0 - && sortOrder==SQLITE_SO_ASC + && sortOrder!=SQLITE_SO_DESC ){ pTab->iPKey = iCol; pTab->keyConf = (u8)onError; @@ -2600,6 +2600,8 @@ void sqlite3CreateForeignKey( assert( pTo!=0 ); if( p==0 || IN_DECLARE_VTAB ) goto fk_end; + sqlite3RestrictColumnListSyntax(pParse, pFromCol); + sqlite3RestrictColumnListSyntax(pParse, pToCol); if( pFromCol==0 ){ int iCol = p->nCol-1; if( NEVER(iCol<0) ) goto fk_end; @@ -3038,7 +3040,8 @@ Index *sqlite3CreateIndex( if( pList==0 ) goto exit_create_index; pList->a[0].zName = sqlite3DbStrDup(pParse->db, pTab->aCol[pTab->nCol-1].zName); - pList->a[0].sortOrder = (u8)sortOrder; + assert( pList->nExpr==1 ); + sqlite3ExprListSetSortOrder(pList, sortOrder); } /* Figure out how many bytes of space are required to store explicitly @@ -4283,6 +4286,32 @@ KeyInfo *sqlite3KeyInfoOfIndex(Parse *pParse, Index *pIdx){ return pKey; } +/* +** Generate a syntax error if the expression list provided contains +** any COLLATE or ASC or DESC keywords. +** +** Some legacy versions of SQLite allowed constructs like: +** +** CREATE TABLE x(..., FOREIGN KEY(x COLLATE binary DESC) REFERENCES...); +** ^^^^^^^^^^^^^^^^^^^ +** +** The COLLATE and sort order terms were ignored. To prevent compatibility +** problems in case something like this appears in a legacy sqlite_master +** table, only enforce the restriction on new SQL statements, not when +** parsing the schema out of the sqlite_master table. +*/ +void sqlite3RestrictColumnListSyntax(Parse *pParse, ExprList *p){ + int i; + if( p==0 || pParse->db->init.busy ) return; + for(i=0; i<p->nExpr; i++){ + if( p->a[i].pExpr!=0 || p->a[i].bDefinedSO ){ + sqlite3ErrorMsg(pParse, "syntax error after column name \"%w\"", + p->a[i].zName); + return; + } + } +} + #ifndef SQLITE_OMIT_CTE /* ** This routine is invoked once per CTE by the parser while parsing a @@ -4299,6 +4328,8 @@ With *sqlite3WithAdd( With *pNew; char *zName; + sqlite3RestrictColumnListSyntax(pParse, pArglist); + /* Check that the CTE name is unique within this WITH clause. If ** not, store an error in the Parse structure. */ zName = sqlite3NameFromToken(pParse->db, pName); diff --git a/src/expr.c b/src/expr.c index 04cd36ea7..1c57ecc6f 100644 --- a/src/expr.c +++ b/src/expr.c @@ -1161,6 +1161,21 @@ no_mem: } /* +** Set the sort order for the last element on the given ExprList. +*/ +void sqlite3ExprListSetSortOrder(ExprList *p, int iSortOrder){ + if( p==0 ) return; + assert( SQLITE_SO_UNDEFINED<0 && SQLITE_SO_ASC>=0 && SQLITE_SO_DESC>0 ); + assert( p->nExpr>0 ); + if( iSortOrder<0 ){ + assert( p->a[p->nExpr-1].sortOrder==SQLITE_SO_ASC ); + return; + } + p->a[p->nExpr-1].sortOrder = (u8)iSortOrder; + p->a[p->nExpr-1].bDefinedSO = 1; +} + +/* ** Set the ExprList.a[].zName element of the most recently added item ** on the expression list. ** diff --git a/src/parse.y b/src/parse.y index 3d186b28a..bc193ec1f 100644 --- a/src/parse.y +++ b/src/parse.y @@ -680,18 +680,18 @@ orderby_opt(A) ::= . {A = 0;} orderby_opt(A) ::= ORDER BY sortlist(X). {A = X;} sortlist(A) ::= sortlist(X) COMMA expr(Y) sortorder(Z). { A = sqlite3ExprListAppend(pParse,X,Y.pExpr); - if( A ) A->a[A->nExpr-1].sortOrder = (u8)Z; + sqlite3ExprListSetSortOrder(A,Z); } sortlist(A) ::= expr(Y) sortorder(Z). { A = sqlite3ExprListAppend(pParse,0,Y.pExpr); - if( A && ALWAYS(A->a) ) A->a[0].sortOrder = (u8)Z; + sqlite3ExprListSetSortOrder(A,Z); } %type sortorder {int} sortorder(A) ::= ASC. {A = SQLITE_SO_ASC;} sortorder(A) ::= DESC. {A = SQLITE_SO_DESC;} -sortorder(A) ::= . {A = SQLITE_SO_ASC;} +sortorder(A) ::= . {A = SQLITE_SO_UNDEFINED;} %type groupby_opt {ExprList*} %destructor groupby_opt {sqlite3ExprListDelete(pParse->db, $$);} @@ -1229,14 +1229,14 @@ idxlist(A) ::= idxlist(X) COMMA nm(Y) collate(C) sortorder(Z). { A = sqlite3ExprListAppend(pParse,X, p); sqlite3ExprListSetName(pParse,A,&Y,1); sqlite3ExprListCheckLength(pParse, A, "index"); - if( A ) A->a[A->nExpr-1].sortOrder = (u8)Z; + sqlite3ExprListSetSortOrder(A,Z); } idxlist(A) ::= nm(Y) collate(C) sortorder(Z). { Expr *p = sqlite3ExprAddCollateToken(pParse, 0, &C, 1); A = sqlite3ExprListAppend(pParse,0, p); sqlite3ExprListSetName(pParse, A, &Y, 1); sqlite3ExprListCheckLength(pParse, A, "index"); - if( A ) A->a[A->nExpr-1].sortOrder = (u8)Z; + sqlite3ExprListSetSortOrder(A,Z); } %type collate {Token} diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 96a770021..18a0fd705 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1525,6 +1525,7 @@ struct CollSeq { */ #define SQLITE_SO_ASC 0 /* Sort in ascending order */ #define SQLITE_SO_DESC 1 /* Sort in ascending order */ +#define SQLITE_SO_UNDEFINED -1 /* No sort order specified */ /* ** Column affinity types. @@ -2189,6 +2190,7 @@ struct ExprList { unsigned done :1; /* A flag to indicate when processing is finished */ unsigned bSpanIsTab :1; /* zSpan holds DB.TABLE.COLUMN */ unsigned reusable :1; /* Constant expression is reusable */ + unsigned bDefinedSO :1; /* True if either DESC or ASC keywords present */ union { struct { u16 iOrderByCol; /* For ORDER BY, column number in result set */ @@ -3244,6 +3246,7 @@ Expr *sqlite3ExprFunction(Parse*,ExprList*, Token*); void sqlite3ExprAssignVarNumber(Parse*, Expr*); void sqlite3ExprDelete(sqlite3*, Expr*); ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*); +void sqlite3ExprListSetSortOrder(ExprList*,int); void sqlite3ExprListSetName(Parse*,ExprList*,Token*,int); void sqlite3ExprListSetSpan(Parse*,ExprList*,ExprSpan*); void sqlite3ExprListDelete(sqlite3*, ExprList*); @@ -3755,6 +3758,7 @@ const char *sqlite3JournalModename(int); int sqlite3Checkpoint(sqlite3*, int, int, int*, int*); int sqlite3WalDefaultHook(void*,sqlite3*,const char*,int); #endif +void sqlite3RestrictColumnListSyntax(Parse*,ExprList*); #ifndef SQLITE_OMIT_CTE With *sqlite3WithAdd(Parse*,With*,Token*,ExprList*,Select*); void sqlite3WithDelete(sqlite3*,With*); diff --git a/test/parser1.test b/test/parser1.test new file mode 100644 index 000000000..f4c3227f8 --- /dev/null +++ b/test/parser1.test @@ -0,0 +1,58 @@ +# 2014-08-24 +# +# 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 script is testing details of the SQL language parser. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +do_catchsql_test parser1-1.1 { + CREATE TABLE t1( + a TEXT PRIMARY KEY, + b TEXT, + FOREIGN KEY(b COLLATE nocase DESC) REFERENCES t1(a COLLATE binary ASC) + ); +} {1 {syntax error after column name "a"}} +do_execsql_test parser1-1.2 { + CREATE TABLE t1( + a TEXT PRIMARY KEY, + b TEXT, + FOREIGN KEY(b) REFERENCES t1(a) + ); + INSERT INTO t1 VALUES('abc',NULL),('xyz','abc'); + PRAGMA writable_schema=on; + UPDATE sqlite_master SET sql='CREATE TABLE t1( + a TEXT PRIMARY KEY, + b TEXT, + FOREIGN KEY(b COLLATE nocase) REFERENCES t1(a) + )' WHERE name='t1'; + SELECT name FROM sqlite_master WHERE sql LIKE '%collate%'; +} {t1} +sqlite3 db2 test.db +do_test parser1-1.3 { + sqlite3 db2 test.db + db2 eval {SELECT * FROM t1 ORDER BY 1} +} {abc {} xyz abc} + + +do_catchsql_test parser1-2.1 { + WITH RECURSIVE + c(x COLLATE binary) AS (VALUES(1) UNION SELECT x+1 FROM c WHERE x<5) + SELECT x FROM c; +} {1 {syntax error after column name "x"}} +do_catchsql_test parser1-2.2 { + WITH RECURSIVE + c(x ASC) AS (VALUES(1) UNION SELECT x+1 FROM c WHERE x<5) + SELECT x FROM c; +} {1 {syntax error after column name "x"}} + +finish_test |