]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix the schemalint.tcl script to handle identifiers that require quoting.
authordan <dan@noemail.net>
Mon, 30 Nov 2015 18:17:55 +0000 (18:17 +0000)
committerdan <dan@noemail.net>
Mon, 30 Nov 2015 18:17:55 +0000 (18:17 +0000)
FossilOrigin-Name: 451e0fafbe5b7e9c67d9b584d5e16796c3196881

manifest
manifest.uuid
src/where.c
test/schemalint.test
tool/schemalint.tcl

index bff04194923de6df16f374aaba15b628c9702335..16b150e61df68f8f78ad084559b28423186724f9 100644 (file)
--- 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
index ed4290e83d28aaaae5e26ddcc16a8404adb515c4..f83d5d89f678fefcf355a2ea0c926b33d840f23f 100644 (file)
@@ -1 +1 @@
-d3aa067c830e98f2074630c4613c557b0ce90a57
\ No newline at end of file
+451e0fafbe5b7e9c67d9b584d5e16796c3196881
\ No newline at end of file
index 4ba35d6ac93f4b1e0703d3f3c58739bfc35b88d6..49e9fc83820cfc20a0c102d9dbb2f21e54ebd8da 100644 (file)
@@ -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; iCol<nCol; iCol++){
           if( iCol==(sizeof(Bitmask)*8-1) ) break;
           if( pItem->colUsed & ((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")
               );
index d354c1fdd75b8b47c8ced592c8248b4b7403f586..7e0eba494d406e515a6d88f61353c3418b978953 100644 (file)
@@ -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
 
index 7ed74f90540d28d2cc6b6c54cfedef55513618c8..b6ebd4390d5ba4e66beeed3346587170d5410624 100644 (file)
@@ -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.