diff --git a/manifest b/manifest index aafc8db59d..244bbf8c03 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Update\sthe\ssessions\sbranch\swith\sall\sthe\slatest\schanges\sfrom\strunk. -D 2012-05-04T23:31:14.883 +C Merge\sin\sthe\swindows\sAV-defense\senhancements\sfor\sopen()\sand\sthe\stable\nconstraint\sparser\sfixes\sfor\slegacy\sschemas,\sall\sfrom\strunk. +D 2012-05-10T12:17:18.151 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 2f37e468503dbe79d35c9f6dffcf3fae1ae9ec20 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -172,10 +172,10 @@ F src/os.h 59beba555b65a450bd1d804220532971d4299f60 F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04 F src/os_os2.c 4a75888ba3dfc820ad5e8177025972d74d7f2440 F src/os_unix.c 424d46e0edab969293c2223f09923b2178171f47 -F src/os_win.c 5e9e933a412ab35de2a6506b3c6a8295b31b309e +F src/os_win.c 412d6434133c7c81dc48b7702f3ea5e61c309e5c F src/pager.c bb5635dde0b152797836d1c72275284724bb563c F src/pager.h ef1eaf8593e78f73885c1dfac27ad83bee23bdc5 -F src/parse.y eb054bb40a5bf90d3422a01ed0e5df229461727a +F src/parse.y de06f412a4b3a2978071215f657fd1cd70700444 F src/pcache.c f8043b433a57aba85384a531e3937a804432a346 F src/pcache.h 1b5dcc3dc8103d03e625b177023ee67764fa6b7c F src/pcache1.c b30b1c35908346ecc43d8d9d17f2ddf6817f8f60 @@ -187,7 +187,7 @@ F src/resolve.c 748e75299faff345f34f0e5bd02a2bac8aa69fcd F src/rowset.c f6a49f3e9579428024662f6e2931832511f831a1 F src/select.c d7b9018b7dd2e821183d69477ab55c39b8272335 F src/shell.c 04399b2f9942bd02ed5ffee3b84bcdb39c52a1e6 -F src/sqlite.h.in ad55acc42422c461719f3adaee434836ab00677b +F src/sqlite.h.in 786cc6ee67ac7e19bfcbba5b840fffae449efe02 F src/sqlite3ext.h 6904f4aadf976f95241311fbffb00823075d9477 F src/sqliteInt.h 572c5e6aca50256bdbc34919ece5f660dabf25cc F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d @@ -327,7 +327,7 @@ F test/capi3c.test 01f197d73f4d4d66316483662f475cab7ab5bd60 F test/capi3d.test 17b57ca28be3e37e14c2ba8f787d292d84b724a1 F test/capi3e.test f7408dda65c92b9056199fdc180f893015f83dde F test/cast.test 4c275cbdc8202d6f9c54a3596701719868ac7dc3 -F test/check.test 06795c188bf1776673fd2ac0787aa1c7238970d8 +F test/check.test 193f47ed43a8d29aca12b30cd30ceb105fbe710d F test/coalesce.test cee0dccb9fbd2d494b77234bccf9dc6c6786eb91 F test/collate1.test e3eaa48c21e150814be1a7b852d2a8af24458d04 F test/collate2.test 04cebe4a033be319d6ddbb3bbc69464e01700b49 @@ -679,6 +679,7 @@ F test/schema.test 8f7999be894260f151adf15c2c7540f1c6d6a481 F test/schema2.test 906408621ea881fdb496d878b1822572a34e32c5 F test/schema3.test 1bc1008e1f8cb5654b248c55f27249366eb7ed38 F test/schema4.test e6a66e20cc69f0e306667c08be7fda3d11707dc5 +F test/schema5.test b583e6e24adef3dce804bed040f24dd5fe789159 F test/securedel.test 87a2561151af1f1e349071a89fdd77059f50113c F test/select1.test deba017eed9daa5af33de868676c997e7eebb931 F test/select2.test 352480e0e9c66eda9c3044e412abdf5be0215b56 @@ -702,11 +703,11 @@ F test/shared6.test 866bb4982c45ce216c61ded5e8fde4e7e2f3ffa9 F test/shared7.test 960760bc8d03e1419e70dea69cf41db62853616e F test/shared_err.test 91e26ec4f3fbe07951967955585137e2f18993de F test/sharedlock.test ffa0a3c4ac192145b310f1254f8afca4d553eabf -F test/shell1.test 7dcd612b0018ddad783647d984fffa76791ffd3d w tool/shell1.test -F test/shell2.test 037d6ad16e873354195d30bb2dc4b5321788154a w tool/shell2.test -F test/shell3.test 9196c42772d575685e722c92b4b39053c6ebba59 w tool/shell3.test -F test/shell4.test aa4eef8118b412d1a01477a53426ece169ea86a9 w tool/shell4.test -F test/shell5.test fa2188bbb13fe2d183fd04a5f7b512650c35ef5d w tool/shell5.test +F test/shell1.test 7dcd612b0018ddad783647d984fffa76791ffd3d +F test/shell2.test 037d6ad16e873354195d30bb2dc4b5321788154a +F test/shell3.test 9196c42772d575685e722c92b4b39053c6ebba59 +F test/shell4.test aa4eef8118b412d1a01477a53426ece169ea86a9 +F test/shell5.test fa2188bbb13fe2d183fd04a5f7b512650c35ef5d F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3 F test/shrink.test 8c70f62b6e8eb4d54533de6d65bd06b1b9a17868 F test/sidedelete.test f0ad71abe6233e3b153100f3b8d679b19a488329 @@ -1008,7 +1009,7 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/warnings-clang.sh a8a0a3babda96dfb1ff51adda3cbbf3dfb7266c2 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 -P 2b7a91e61794ce9ffe210bad584454e52c79924e bfa61e781cb442be641486e7e55a1518e888d830 -R bed2e7cce64395c916783d9e3080c791 +P 0f347fbfc7d8821f56f1ae0d1a9472a375631e65 38bf90af1ede6ee64ef7be66392e895e60c9126e +R 21dedc1a34649558aea7c289d84ec993 U drh -Z 95959a45df2928e15269c2ba6866d087 +Z bf3857ddf912fd88e60d600cf99c392f diff --git a/manifest.uuid b/manifest.uuid index 80a7fa99b7..594a95aba4 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -0f347fbfc7d8821f56f1ae0d1a9472a375631e65 \ No newline at end of file +323570b8bd52c7e1b0c8c7a0e4f57f6fdebead11 \ No newline at end of file diff --git a/src/os_win.c b/src/os_win.c index 358b70c128..fcfe0118ed 100644 --- a/src/os_win.c +++ b/src/os_win.c @@ -3031,6 +3031,35 @@ static int getTempname(int nBuf, char *zBuf){ return SQLITE_OK; } +/* +** Return TRUE if the named file is really a directory. Return false if +** it is something other than a directory, or if there is any kind of memory +** allocation failure. +*/ +static int winIsDir(const void *zConverted){ + DWORD attr; + int rc = 0; + DWORD lastErrno; + + if( isNT() ){ + int cnt = 0; + WIN32_FILE_ATTRIBUTE_DATA sAttrData; + memset(&sAttrData, 0, sizeof(sAttrData)); + while( !(rc = osGetFileAttributesExW((LPCWSTR)zConverted, + GetFileExInfoStandard, + &sAttrData)) && retryIoerr(&cnt, &lastErrno) ){} + if( !rc ){ + return 0; /* Invalid name? */ + } + attr = sAttrData.dwFileAttributes; +#if SQLITE_OS_WINCE==0 + }else{ + attr = osGetFileAttributesA((char*)zConverted); +#endif + } + return (attr!=INVALID_FILE_ATTRIBUTES) && (attr&FILE_ATTRIBUTE_DIRECTORY); +} + /* ** Open a file. */ @@ -3137,6 +3166,11 @@ static int winOpen( return SQLITE_IOERR_NOMEM; } + if( winIsDir(zConverted) ){ + sqlite3_free(zConverted); + return SQLITE_CANTOPEN_ISDIR; + } + if( isReadWrite ){ dwDesiredAccess = GENERIC_READ | GENERIC_WRITE; }else{ @@ -3186,11 +3220,9 @@ static int winOpen( dwCreationDisposition, dwFlagsAndAttributes, NULL))==INVALID_HANDLE_VALUE && - retryIoerr(&cnt, &lastErrno) ){} -/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. -** Since the ANSI version of these Windows API do not exist for WINCE, -** it's important to not reference them for WINCE builds. -*/ + retryIoerr(&cnt, &lastErrno) ){ + /* Noop */ + } #if SQLITE_OS_WINCE==0 }else{ while( (h = osCreateFileA((LPCSTR)zConverted, @@ -3199,7 +3231,9 @@ static int winOpen( dwCreationDisposition, dwFlagsAndAttributes, NULL))==INVALID_HANDLE_VALUE && - retryIoerr(&cnt, &lastErrno) ){} + retryIoerr(&cnt, &lastErrno) ){ + /* Noop */ + } #endif } @@ -3279,6 +3313,7 @@ static int winDelete( ){ int cnt = 0; int rc; + DWORD attr; DWORD lastErrno; void *zConverted; UNUSED_PARAMETER(pVfs); @@ -3290,20 +3325,50 @@ static int winDelete( return SQLITE_IOERR_NOMEM; } if( isNT() ){ - rc = 1; - while( osGetFileAttributesW(zConverted)!=INVALID_FILE_ATTRIBUTES && - (rc = osDeleteFileW(zConverted))==0 && retryIoerr(&cnt, &lastErrno) ){} - rc = rc ? SQLITE_OK : SQLITE_ERROR; + do { + attr = osGetFileAttributesW(zConverted); + if ( attr==INVALID_FILE_ATTRIBUTES ){ + rc = SQLITE_OK; /* Already gone? */ + break; + } + if ( attr&FILE_ATTRIBUTE_DIRECTORY ){ + rc = SQLITE_ERROR; /* Files only. */ + break; + } + if ( osDeleteFileW(zConverted) ){ + rc = SQLITE_OK; /* Deleted OK. */ + break; + } + if ( !retryIoerr(&cnt, &lastErrno) ){ + rc = SQLITE_ERROR; /* No more retries. */ + break; + } + } while(1); /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. ** Since the ANSI version of these Windows API do not exist for WINCE, ** it's important to not reference them for WINCE builds. */ #if SQLITE_OS_WINCE==0 }else{ - rc = 1; - while( osGetFileAttributesA(zConverted)!=INVALID_FILE_ATTRIBUTES && - (rc = osDeleteFileA(zConverted))==0 && retryIoerr(&cnt, &lastErrno) ){} - rc = rc ? SQLITE_OK : SQLITE_ERROR; + do { + attr = osGetFileAttributesA(zConverted); + if ( attr==INVALID_FILE_ATTRIBUTES ){ + rc = SQLITE_OK; /* Already gone? */ + break; + } + if ( attr&FILE_ATTRIBUTE_DIRECTORY ){ + rc = SQLITE_ERROR; /* Files only. */ + break; + } + if ( osDeleteFileA(zConverted) ){ + rc = SQLITE_OK; /* Deleted OK. */ + break; + } + if ( !retryIoerr(&cnt, &lastErrno) ){ + rc = SQLITE_ERROR; /* No more retries. */ + break; + } + } while(1); #endif } if( rc ){ diff --git a/src/parse.y b/src/parse.y index 49406e1e76..8b5635c674 100644 --- a/src/parse.y +++ b/src/parse.y @@ -185,6 +185,7 @@ column(A) ::= columnid(X) type carglist. { columnid(A) ::= nm(X). { sqlite3AddColumn(pParse,&X); A = X; + pParse->constraintName.n = 0; } @@ -273,10 +274,9 @@ signed ::= minus_num. // "carglist" is a list of additional constraints that come after the // column name and column type in a CREATE TABLE statement. // -carglist ::= carglist cname ccons. +carglist ::= carglist ccons. carglist ::= . -cname ::= CONSTRAINT nm(X). {pParse->constraintName = X;} -cname ::= . {pParse->constraintName.n = 0;} +ccons ::= CONSTRAINT nm(X). {pParse->constraintName = X;} ccons ::= DEFAULT term(X). {sqlite3AddDefaultValue(pParse,&X);} ccons ::= DEFAULT LP expr(X) RP. {sqlite3AddDefaultValue(pParse,&X);} ccons ::= DEFAULT PLUS term(X). {sqlite3AddDefaultValue(pParse,&X);} @@ -339,10 +339,13 @@ init_deferred_pred_opt(A) ::= . {A = 0;} init_deferred_pred_opt(A) ::= INITIALLY DEFERRED. {A = 1;} init_deferred_pred_opt(A) ::= INITIALLY IMMEDIATE. {A = 0;} -conslist_opt(A) ::= . {A.n = 0; A.z = 0;} -conslist_opt(A) ::= COMMA(X) conslist. {A = X;} +conslist_opt(A) ::= . {A.n = 0; A.z = 0;} +conslist_opt(A) ::= COMMA(X) conslist cname. {A = X;} conslist ::= conslist COMMA cname tcons. +conslist ::= conslist cname tcons. conslist ::= cname tcons. +cname ::= . {pParse->constraintName.n = 0;} +cname ::= CONSTRAINT nm(X). {pParse->constraintName = X;} tcons ::= PRIMARY KEY LP idxlist(X) autoinc(I) RP onconf(R). {sqlite3AddPrimaryKey(pParse,X,R,I,0);} tcons ::= UNIQUE LP idxlist(X) RP onconf(R). diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 035cf64376..6bb92ee9d8 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -453,6 +453,7 @@ int sqlite3_exec( #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) #define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8)) +#define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8)) #define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8)) #define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8)) #define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8)) diff --git a/test/check.test b/test/check.test index 4d1a44117d..bf0b770a00 100644 --- a/test/check.test +++ b/test/check.test @@ -153,6 +153,48 @@ do_test check-2.6 { } } {1 {constraint three failed}} +# Undocumented behavior: The CONSTRAINT name clause can follow a constraint. +# Such a clause is ignored. But the parser must accept it for backwards +# compatibility. +# +do_test check-2.10 { + execsql { + CREATE TABLE t2b( + x INTEGER CHECK( typeof(coalesce(x,0))=='integer' ) CONSTRAINT one, + y TEXT PRIMARY KEY constraint two, + z INTEGER, + UNIQUE(x,z) constraint three + ); + } +} {} +do_test check-2.11 { + catchsql { + INSERT INTO t2b VALUES('xyzzy','hi',5); + } +} {1 {constraint failed}} +do_test check-2.12 { + execsql { + CREATE TABLE t2c( + x INTEGER CONSTRAINT x_one CONSTRAINT x_two + CHECK( typeof(coalesce(x,0))=='integer' ) + CONSTRAINT x_two CONSTRAINT x_three, + y INTEGER, z INTEGER, + CONSTRAINT u_one UNIQUE(x,y,z) CONSTRAINT u_two + ); + } +} {} +do_test check-2.13 { + catchsql { + INSERT INTO t2c VALUES('xyzzy',7,8); + } +} {1 {constraint x_two failed}} +do_test check-2.cleanup { + execsql { + DROP TABLE IF EXISTS t2b; + DROP TABLE IF EXISTS t2c; + } +} {} + ifcapable subquery { do_test check-3.1 { catchsql { diff --git a/test/schema5.test b/test/schema5.test new file mode 100644 index 0000000000..532ba7703a --- /dev/null +++ b/test/schema5.test @@ -0,0 +1,52 @@ +# 2010 September 28 +# +# 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 checks corner cases in the CREATE TABLE syntax to make +# sure that legacy syntax (syntax that is disallowed according to the +# syntax diagrams) is still accepted, so that older databases that use +# that syntax can still be read. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +# Table constraints should be separated by commas, but they do not have +# to be. +# +do_test schema5-1.1 { + db eval { + CREATE TABLE t1(a,b,c, PRIMARY KEY(a) UNIQUE (a) CONSTRAINT one); + INSERT INTO t1 VALUES(1,2,3); + SELECT * FROM t1; + } +} {1 2 3} +do_test schema5-1.2 { + catchsql {INSERT INTO t1 VALUES(1,3,4);} +} {1 {column a is not unique}} +do_test schema5-1.3 { + db eval { + DROP TABLE t1; + CREATE TABLE t1(a,b,c, + CONSTRAINT one PRIMARY KEY(a) CONSTRAINT two CHECK(b<10) UNIQUE(b) + CONSTRAINT three + ); + INSERT INTO t1 VALUES(1,2,3); + SELECT * FROM t1; + } +} {1 2 3} +do_test schema5-1.4 { + catchsql {INSERT INTO t1 VALUES(10,11,12);} +} {1 {constraint two failed}} + + + + +finish_test