From: dan Date: Mon, 30 Nov 2015 18:17:55 +0000 (+0000) Subject: Fix the schemalint.tcl script to handle identifiers that require quoting. X-Git-Tag: version-3.22.0~147^2~62 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c45bf341afda3c3fddb297519292c11a9658a9d3;p=thirdparty%2Fsqlite.git Fix the schemalint.tcl script to handle identifiers that require quoting. FossilOrigin-Name: 451e0fafbe5b7e9c67d9b584d5e16796c3196881 --- diff --git a/manifest b/manifest index bff0419492..16b150e61d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C In\sthe\sCREATE\sINDEX\sstatements\soutput\sby\sschemalint.tcl,\savoid\sdeclaring\san\sexplicit\scollation\ssequence\sthat\sis\sthe\ssame\sas\sthe\scolumn's\sdefault. -D 2015-11-23T18:28:07.584 +C Fix\sthe\sschemalint.tcl\sscript\sto\shandle\sidentifiers\sthat\srequire\squoting. +D 2015-11-30T18:17:55.036 F Makefile.in d828db6afa6c1fa060d01e33e4674408df1942a1 F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434 F Makefile.msc e928e68168df69b353300ac87c10105206653a03 @@ -416,7 +416,7 @@ F src/vxworks.h c18586c8edc1bddbc15c004fa16aeb1e1342b4fb F src/wal.c 18b0ed49830cf04fe2d68224b41838a73ac6cd24 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 2e14d17f592d176b6dc879c33fbdec4fbccaa2ba -F src/where.c 5804902239731a7025240f4338d98cdc57315636 +F src/where.c be09f4a0513f885845ae481324c2e07603f88b38 F src/whereInt.h 7892bb54cf9ca0ae5c7e6094491b94c9286dc647 F src/wherecode.c 4c96182e7b25e4be54008dee2da5b9c2f8480b9b F src/whereexpr.c bd4877cd4dd11f6ab551ef0054535ca3c6224950 @@ -973,7 +973,7 @@ F test/schema2.test 906408621ea881fdb496d878b1822572a34e32c5 F test/schema3.test 1bc1008e1f8cb5654b248c55f27249366eb7ed38 F test/schema4.test e6a66e20cc69f0e306667c08be7fda3d11707dc5 F test/schema5.test 29699b4421f183c8f0e88bd28ce7d75d13ea653e -F test/schemalint.test 7fba0e262353c8c3dd5ee406cb11cf90f8b566fe +F test/schemalint.test cee9f375637fcc8c6e77d971abe044445c23e024 F test/securedel.test 21749c32ccc30f1ea9e4b9f33295a6521ec20fa0 F test/securedel2.test 2d54c28e46eb1fd6902089958b20b1b056c6f1c5 F test/select1.test be62204d2bd9a5a8a149e9974cfddce893d8f686 @@ -1381,7 +1381,7 @@ F tool/replace.tcl 7727c60a04299b65a92f5e1590896fea0f25b9e0 F tool/restore_jrnl.tcl 6957a34f8f1f0f8285e07536225ec3b292a9024a F tool/rollback-test.c 9fc98427d1e23e84429d7e6d07d9094fbdec65a5 F tool/run-speed-test.sh 0ae485af4fe9f826e2b494be8c81f8ca9e222a4a -F tool/schemalint.tcl ad61083d39cb40e848b9acc1273e4c487bb55cd7 +F tool/schemalint.tcl 2f44d0874061a948f6ef53505062db4ac9806cf7 F tool/showdb.c d4476e000a64eca9f5e2c2f68741e747b9778e8d F tool/showjournal.c 5bad7ae8784a43d2b270d953060423b8bd480818 F tool/showlocks.c 9920bcc64f58378ff1118caead34147201f48c68 @@ -1406,7 +1406,7 @@ F tool/vdbe_profile.tcl 246d0da094856d72d2c12efec03250d71639d19f F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 8f1ef0904d055b5510ec9043810ebf22a8c5e253 -R 4b9b445c1607ad5c9f9bdcf33b4eb416 +P d3aa067c830e98f2074630c4613c557b0ce90a57 +R aed657578ea11902053a31be3048325d U dan -Z 6d9149db2c512107280c4e32c490b8cb +Z 94438cf65b515737c9a10851485e87ac diff --git a/manifest.uuid b/manifest.uuid index ed4290e83d..f83d5d89f6 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d3aa067c830e98f2074630c4613c557b0ce90a57 \ No newline at end of file +451e0fafbe5b7e9c67d9b584d5e16796c3196881 \ No newline at end of file diff --git a/src/where.c b/src/where.c index 4ba35d6ac9..49e9fc8382 100644 --- a/src/where.c +++ b/src/where.c @@ -3942,7 +3942,8 @@ static char *whereAppendSingleTerm( pColl = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pX->pRight); if( zOp ){ - const char *zFmt = bOr ? "%z{{%s %s %s %lld}}" : "%z{%s %s %s %lld}"; + const char *zFmt = bOr ? "%z{{%s \"%w\" \"%w\" %lld}}" : + "%z{%s \"%w\" \"%w\" %lld}"; zBuf = whereAppendPrintf(db, zFmt, zIn, zOp, pTab->aCol[pTerm->u.leftColumn].zName, (pColl ? pColl->zName : "BINARY"), @@ -4025,7 +4026,7 @@ static void whereTraceBuilder( nCol = pTab->nCol; /* Append the table name to the buffer. */ - zBuf = whereAppendPrintf(db, "%s", pTab->zName); + zBuf = whereAppendPrintf(db, "\"%w\"", pTab->zName); /* Append the list of columns required to create a covering index */ zBuf = whereAppendPrintf(db, "%z {cols", zBuf); @@ -4033,7 +4034,8 @@ static void whereTraceBuilder( for(iCol=0; iColcolUsed & ((u64)1 << iCol) ){ - zBuf = whereAppendPrintf(db, "%z %s", zBuf, pTab->aCol[iCol].zName); + const char *zName = pTab->aCol[iCol].zName; + zBuf = whereAppendPrintf(db, "%z \"%w\"", zBuf, zName); } } } @@ -4054,7 +4056,7 @@ static void whereTraceBuilder( if( pExpr->op==TK_COLUMN && pExpr->iTable==pItem->iCursor ){ if( pExpr->iColumn>=0 ){ const char *zName = pTab->aCol[pExpr->iColumn].zName; - zBuf = whereAppendPrintf(db, "%z%s%s %s %s", zBuf, + zBuf = whereAppendPrintf(db, "%z%s\"%w\" \"%w\" %s", zBuf, bFirst ? " {orderby " : " ", zName, pColl->zName, (pOrderBy->a[i].sortOrder ? "DESC" : "ASC") ); diff --git a/test/schemalint.test b/test/schemalint.test index d354c1fdd7..7e0eba494d 100644 --- a/test/schemalint.test +++ b/test/schemalint.test @@ -27,33 +27,33 @@ do_execsql_test 1.0 { do_trace_test 1.1 { SELECT b, c, y, z FROM t1, t2 WHERE c=? AND z=? } { - {t1 {cols b c} {eq c BINARY 0}} - {t2 {cols y z} {eq z BINARY 0}} + {"t1" {cols "b" "c"} {eq "c" "BINARY" 0}} + {"t2" {cols "y" "z"} {eq "z" "BINARY" 0}} } do_trace_test 1.2 { SELECT a FROM t1 WHERE b>10 } { - {t1 {cols a b} {range b BINARY 0}} + {"t1" {cols "a" "b"} {range "b" "BINARY" 0}} } do_trace_test 1.3 { SELECT b FROM t1 WHERE b IN (10, 20, 30) } { - {t1 {cols b} {eq b BINARY 0}} + {"t1" {cols "b"} {eq "b" "BINARY" 0}} } do_trace_test 1.4 { SELECT * FROM t1, t2 WHERE x=a } { - {t1 {cols a b c} {eq a BINARY 2}} - {t2 {cols x y z} {eq x BINARY 1}} + {"t1" {cols "a" "b" "c"} {eq "a" "BINARY" 2}} + {"t2" {cols "x" "y" "z"} {eq "x" "BINARY" 1}} } do_trace_test 1.5 { SELECT * FROM t1 WHERE a IN (1, 2, 3) } { - {t1 {cols a b c} {eq a BINARY 0}} + {"t1" {cols "a" "b" "c"} {eq "a" "BINARY" 0}} } #----------------------------------------------------------------------- @@ -62,19 +62,19 @@ do_trace_test 1.5 { do_trace_test 2.1 { SELECT * FROM t1 WHERE a=? OR b=? } { - {t1 {cols a b c} {or {{eq a BINARY 0}} {{eq b BINARY 0}}}} + {"t1" {cols "a" "b" "c"} {or {{eq "a" "BINARY" 0}} {{eq "b" "BINARY" 0}}}} } do_trace_test 2.2 { SELECT * FROM t1 WHERE a=? OR (b=? AND c=?) } { - {t1 {cols a b c} {or {{eq a BINARY 0}} {{eq b BINARY 0} {eq c BINARY 0}}}} + {"t1" {cols "a" "b" "c"} {or {{eq "a" "BINARY" 0}} {{eq "b" "BINARY" 0} {eq "c" "BINARY" 0}}}} } do_trace_test 2.3 { SELECT * FROM t1 WHERE (a=? AND b=?) OR c=? } { - {t1 {cols a b c} {or {{eq c BINARY 0}} {{eq a BINARY 0} {eq b BINARY 0}}}} + {"t1" {cols "a" "b" "c"} {or {{eq "c" "BINARY" 0}} {{eq "a" "BINARY" 0} {eq "b" "BINARY" 0}}}} } #----------------------------------------------------------------------- @@ -82,19 +82,19 @@ do_trace_test 2.3 { # do_trace_test 3.1 { SELECT * FROM t1 ORDER BY a; -} {{t1 {cols a b c} {orderby a BINARY ASC}}} +} {{"t1" {cols "a" "b" "c"} {orderby "a" "BINARY" ASC}}} do_trace_test 3.2 { SELECT * FROM t1 WHERE a=? ORDER BY b; -} {{t1 {cols a b c} {eq a BINARY 0} {orderby b BINARY ASC}}} +} {{"t1" {cols "a" "b" "c"} {eq "a" "BINARY" 0} {orderby "b" "BINARY" ASC}}} do_trace_test 3.3 { SELECT min(a) FROM t1; -} {{t1 {cols a} {orderby a BINARY ASC}}} +} {{"t1" {cols "a"} {orderby "a" "BINARY" ASC}}} do_trace_test 3.4 { SELECT max(a) FROM t1; -} {{t1 {cols a} {orderby a BINARY DESC}}} +} {{"t1" {cols "a"} {orderby "a" "BINARY" DESC}}} finish_test diff --git a/tool/schemalint.tcl b/tool/schemalint.tcl index 7ed74f9054..b6ebd4390d 100644 --- a/tool/schemalint.tcl +++ b/tool/schemalint.tcl @@ -11,6 +11,41 @@ proc usage {} { exit } +# Return the quoted version of identfier $id. Quotes are only added if +# they are required by SQLite. +# +# This command currently assumes that quotes are required if the +# identifier contains any ASCII-range characters that are not +# alpha-numeric or underscores. +# +proc quote {id} { + if {[requires_quote $id]} { + set x [string map {\" \"\"} $id] + return "\"$x\"" + } + return $id +} +proc requires_quote {id} { + foreach c [split $id {}] { + if {[string is alnum $c]==0 && $c!="_"} { + return 1 + } + } + return 0 +} + +# The argument passed to this command is a Tcl list of identifiers. The +# value returned is the same list, except with each item quoted and the +# elements comma-separated. +# +proc list_to_sql {L} { + set ret [list] + foreach l $L { + lappend ret [quote $l] + } + join $ret ", " +} + proc process_cmdline_args {ctxvar argv} { upvar $ctxvar G set nArg [llength $argv] @@ -139,11 +174,11 @@ proc eqset_to_index {ctxvar aCollVar tname eqset {range {}}} { foreach {c collate dir} $rangeset { append idxname "_$c" - set coldef $c + set coldef [quote $c] if {[string compare -nocase $collate $aColl($c)]!=0} { append idxname [string tolower $collate] - append coldef " COLLATE $collate" + append coldef " COLLATE [quote $collate]" } if {$dir=="DESC"} { @@ -153,7 +188,7 @@ proc eqset_to_index {ctxvar aCollVar tname eqset {range {}}} { lappend lCols $coldef } - set create_index "CREATE INDEX $idxname ON ${tname}(" + set create_index "CREATE INDEX [quote $idxname] ON [quote $tname](" append create_index [join $lCols ", "] append create_index ");" @@ -185,12 +220,27 @@ proc expand_or_cons {L} { return $lRet } +#-------------------------------------------------------------------------- +# Argument $tname is the name of a table in the main database opened by +# database handle [db]. $arrayvar is the name of an array variable in the +# caller's context. This command populates the array with an entry mapping +# from column name to default collation sequence for each column of table +# $tname. For example, if a table is declared: +# +# CREATE TABLE t1(a COLLATE nocase, b, c COLLATE binary) +# +# the mapping is populated with: +# +# map(a) -> "nocase" +# map(b) -> "binary" +# map(c) -> "binary" +# proc sqlidx_get_coll_map {tname arrayvar} { upvar $arrayvar aColl set colnames [list] - db eval "PRAGMA table_info = $tname" x { lappend colnames $x(name) } - db eval "CREATE INDEX schemalint_test ON ${tname}([join $colnames ,])" - + set qname [quote $tname] + db eval "PRAGMA table_info = $qname" x { lappend colnames $x(name) } + db eval "CREATE INDEX schemalint_test ON ${qname}([list_to_sql $colnames])" db eval "PRAGMA index_xinfo = schemalint_test" x { set aColl($x(name)) $x(coll) } @@ -348,6 +398,7 @@ proc sqlidx_one_test {tn schema select expected} { sqlidx_init_context C sqlite3 db "" + db collate "a b c" [list string compare] db eval $schema lappend C(lSelect) $select analyze_selects C @@ -362,9 +413,14 @@ proc sqlidx_one_test {tn schema select expected} { } db close + + upvar nTest nTest + incr nTest } proc sqlidx_internal_tests {} { + set nTest 0 + # No indexes for a query with no constraints. sqlidx_one_test 0 { @@ -440,6 +496,58 @@ proc sqlidx_internal_tests {} { {CREATE INDEX t1_a ON t1(a);} } + # Tables with names that require quotes. + # + sqlidx_one_test 8.1 { + CREATE TABLE "t t"(a, b, c); + } { + SELECT * FROM "t t" WHERE a=? + } { + {CREATE INDEX "t t_a" ON "t t"(a);} + } + sqlidx_one_test 8.2 { + CREATE TABLE "t t"(a, b, c); + } { + SELECT * FROM "t t" WHERE b BETWEEN ? AND ? + } { + {CREATE INDEX "t t_b" ON "t t"(b);} + } + + # Columns with names that require quotes. + # + sqlidx_one_test 9.1 { + CREATE TABLE t3(a, "b b", c); + } { + SELECT * FROM t3 WHERE "b b" = ? + } { + {CREATE INDEX "t3_b b" ON t3("b b");} + } + sqlidx_one_test 9.2 { + CREATE TABLE t3(a, "b b", c); + } { + SELECT * FROM t3 ORDER BY "b b" + } { + {CREATE INDEX "t3_b b" ON t3("b b");} + } + + # Collations with names that require quotes. + # + sqlidx_one_test 10.1 { + CREATE TABLE t4(a, b, c); + } { + SELECT * FROM t4 ORDER BY c COLLATE "a b c" + } { + {CREATE INDEX "t4_ca b c" ON t4(c COLLATE "a b c");} + } + sqlidx_one_test 10.2 { + CREATE TABLE t4(a, b, c); + } { + SELECT * FROM t4 WHERE c = ? COLLATE "a b c" + } { + {CREATE INDEX "t4_ca b c" ON t4(c COLLATE "a b c");} + } + + puts "All $nTest tests passed" exit } # End of internal test code.