]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add tests to e_createtable.test. Allow a table to be created if there is an index...
authordan <dan@noemail.net>
Tue, 28 Sep 2010 17:37:28 +0000 (17:37 +0000)
committerdan <dan@noemail.net>
Tue, 28 Sep 2010 17:37:28 +0000 (17:37 +0000)
FossilOrigin-Name: 6251e587403eed822b9011ed25a3a807e8fa2a6f

manifest
manifest.uuid
src/build.c
test/e_createtable.test
test/tester.tcl

index 539232dd11aca986722df08821738654c4cecefa..d33d4dc49bf4c1350fce0686165407d4b65ba149 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Disallow\sstatements\sof\sthe\sform\s"CREATE\sTEMP\sTABLE\smain.t1\s...".
-D 2010-09-28T15:55:48
+C Add\stests\sto\se_createtable.test.\sAllow\sa\stable\sto\sbe\screated\sif\sthere\sis\san\sindex\sof\sthe\ssame\sname\sin\sa\sdifferent\sattached\sdatabase.
+D 2010-09-28T17:37:28
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in c599a15d268b1db2aeadea19df2adc3bf2eb6bee
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -121,7 +121,7 @@ F src/btmutex.c 96a12f50f7a17475155971a241d85ec5171573ff
 F src/btree.c d878577184112d982d00ea05afcc7487cd9f06f5
 F src/btree.h 2d1a83ad509047e8cc314fda7e054f99ff52414d
 F src/btreeInt.h c424f2f131cc61ddf130f9bd736b3df12c8a51f0
-F src/build.c 907385634c73be72acabfd902dfa6f65a429d8c0
+F src/build.c 0451673aeae6606d349c8760a0606ab9523a6fb4
 F src/callback.c a1d1b1c9c85415dff013af033e2fed9c8382d33b
 F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
 F src/ctime.c 4f3aadad62c6c9f0d4e5a96718516ac4e3c598df
@@ -348,7 +348,7 @@ F test/descidx2.test 9f1a0c83fd57f8667c82310ca21b30a350888b5d
 F test/descidx3.test fe720e8b37d59f4cef808b0bf4e1b391c2e56b6f
 F test/diskfull.test 0cede7ef9d8f415d9d3944005c76be7589bb5ebb
 F test/distinctagg.test 1a6ef9c87a58669438fc771450d7a72577417376
-F test/e_createtable.test 2b3257a5b74a4993574f321fb85f063ce1d38241
+F test/e_createtable.test 089acf08bb2ecae3858f1ecdc2fe1705e906a408
 F test/e_delete.test 55d868b647acc091c261a10b9b0cb0ab660a6acb
 F test/e_expr.test 164e87c1d7b40ceb47c57c3bffa384c81d009aa7
 F test/e_fkey.test 6721a741c6499b3ab7e5385923233343c8f1ad05
@@ -642,7 +642,7 @@ F test/tclsqlite.test 8c154101e704170c2be10f137a5499ac2c6da8d3
 F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c
 F test/temptable.test f42121a0d29a62f00f93274464164177ab1cc24a
 F test/temptrigger.test b0273db072ce5f37cf19140ceb1f0d524bbe9f05
-F test/tester.tcl 5a9b8727747f76c18e3a1bf3f0ed16f57a546265
+F test/tester.tcl 74d64ca2730b512b2adaa5e74a07533f7ac6ad9e
 F test/thread001.test a3e6a7254d1cb057836cb3145b60c10bf5b7e60f
 F test/thread002.test afd20095e6e845b405df4f2c920cb93301ca69db
 F test/thread003.test b824d4f52b870ae39fc5bae4d8070eca73085dca
@@ -868,7 +868,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
-P 890816c52d688f01be9a8abd8b4c9375eed4de7e
-R bb6d7614396bfdf34c844eda2125719d
+P dd1b34bab7edaaedd985882f6e16b16940a46d38
+R 9a005e09da83e134e84a9a0916725a2c
 U dan
-Z 79640b932b15b5e171373f446f6cc41b
+Z d38832569685f81301ba56b0f91fcdf4
index ab199256299396d31a9b00d5189ca763ba7c23b1..65a806ae8ba1b4e7afba556b5990f5087ea31b5c 100644 (file)
@@ -1 +1 @@
-dd1b34bab7edaaedd985882f6e16b16940a46d38
\ No newline at end of file
+6251e587403eed822b9011ed25a3a807e8fa2a6f
\ No newline at end of file
index edc70dc916728f9f74bf673b76c8e6e832f9d65d..0f02cc7fb5ac72d3ea7701eaa60d7f23e491dcf3 100644 (file)
@@ -776,17 +776,18 @@ void sqlite3StartTable(
   ** collisions.
   */
   if( !IN_DECLARE_VTAB ){
+    char *zDb = db->aDb[iDb].zName;
     if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
       goto begin_table_error;
     }
-    pTable = sqlite3FindTable(db, zName, db->aDb[iDb].zName);
+    pTable = sqlite3FindTable(db, zName, zDb);
     if( pTable ){
       if( !noErr ){
         sqlite3ErrorMsg(pParse, "table %T already exists", pName);
       }
       goto begin_table_error;
     }
-    if( sqlite3FindIndex(db, zName, 0)!=0 && (iDb==0 || !db->init.busy) ){
+    if( sqlite3FindIndex(db, zName, zDb)!=0 && (iDb==0 || !db->init.busy) ){
       sqlite3ErrorMsg(pParse, "there is already an index named %s", zName);
       goto begin_table_error;
     }
index 3f328b3ecb647d9f21f1f04d7bd7ceec52b8f299..26f4313d54021ed89cd819f7edece6641f9cd8f8 100644 (file)
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
 
+# Test organization:
+#
+#   e_createtable-0.*: Test that the syntax diagrams are correct.
+#
+#   e_createtable-1.*: Test statements related to table and database names, 
+#       the TEMP and TEMPORARY keywords, and the IF NOT EXISTS clause.
+#
+#
+#
+
 proc do_createtable_tests {nm args} {
   uplevel do_select_tests [list e_createtable-$nm] $args
 }
@@ -308,4 +318,272 @@ do_createtable_tests 0.6.1 -repair {
   )} {}
 }
 
+#-------------------------------------------------------------------------
+# Test cases e_createtable-1.* - test statements related to table and
+# database names, the TEMP and TEMPORARY keywords, and the IF NOT EXISTS
+# clause.
+#
+drop_all_tables
+forcedelete test.db2 test.db3
+
+do_execsql_test e_createtable-1.0 {
+  ATTACH 'test.db2' AS auxa;
+  ATTACH 'test.db3' AS auxb;
+} {}
+
+# EVIDENCE-OF: R-17899-04554 Table names that begin with "sqlite_" are
+# reserved for internal use. It is an error to attempt to create a table
+# with a name that starts with "sqlite_".
+#
+do_createtable_tests 1.1.1 -error {
+  object name reserved for internal use: %s
+} {
+  1    "CREATE TABLE sqlite_abc(a, b, c)"        sqlite_abc
+  2    "CREATE TABLE temp.sqlite_helloworld(x)"  sqlite_helloworld
+  3    {CREATE TABLE auxa."sqlite__"(x, y)}      sqlite__
+  4    {CREATE TABLE auxb."sqlite_"(z)}          sqlite_
+  5    {CREATE TABLE "SQLITE_TBL"(z)}            SQLITE_TBL
+}
+do_createtable_tests 1.1.2 {
+  1    "CREATE TABLE sqlit_abc(a, b, c)"         {}
+  2    "CREATE TABLE temp.sqlitehelloworld(x)"   {}
+  3    {CREATE TABLE auxa."sqlite"(x, y)}        {}
+  4    {CREATE TABLE auxb."sqlite-"(z)}          {}
+  5    {CREATE TABLE "SQLITE-TBL"(z)}            {}
+}
+
+
+proc table_list {} {
+  set res [list]
+  db eval { pragma database_list } a {
+    set dbname $a(name)
+    set master $a(name).sqlite_master
+    if {$dbname == "temp"} { set master sqlite_temp_master }
+    lappend res $dbname [
+      db eval "SELECT DISTINCT tbl_name FROM $master ORDER BY tbl_name"
+    ]
+  }
+  set res
+}
+
+# EVIDENCE-OF: R-10195-31023 If a <database-name> is specified, it
+# must be either "main", "temp", or the name of an attached database.
+#
+# EVIDENCE-OF: R-39822-07822 In this case the new table is created in
+# the named database.
+#
+#   Test cases 1.2.* test the first of the two requirements above. The
+#   second is verified by cases 1.3.*.
+#
+do_createtable_tests 1.2.1 -error {
+  unknown database %s
+} {
+  1    "CREATE TABLE george.t1(a, b)"            george
+  2    "CREATE TABLE _.t1(a, b)"                 _
+}
+do_createtable_tests 1.2.2 {
+  1    "CREATE TABLE main.abc(a, b, c)"          {}
+  2    "CREATE TABLE temp.helloworld(x)"         {}
+  3    {CREATE TABLE auxa."t 1"(x, y)}           {}
+  4    {CREATE TABLE auxb.xyz(z)}                {}
+}
+drop_all_tables
+do_createtable_tests 1.3 -tclquery {
+  unset -nocomplain X
+  array set X [table_list]
+  list $X(main) $X(temp) $X(auxa) $X(auxb)
+} {
+  1    "CREATE TABLE main.abc(a, b, c)"  {abc {} {} {}}
+  2    "CREATE TABLE main.t1(a, b, c)"   {{abc t1} {} {} {}}
+  3    "CREATE TABLE temp.tmp(a, b, c)"  {{abc t1} tmp {} {}}
+  4    "CREATE TABLE auxb.tbl(x, y)"     {{abc t1} tmp {} tbl}
+  5    "CREATE TABLE auxb.t1(k, v)"      {{abc t1} tmp {} {t1 tbl}}
+  6    "CREATE TABLE auxa.next(c, d)"    {{abc t1} tmp next {t1 tbl}}
+}
+
+# EVIDENCE-OF: R-18895-27365 If the "TEMP" or "TEMPORARY" keyword occurs
+# between the "CREATE" and "TABLE" then the new table is created in the
+# temp database.
+#
+drop_all_tables
+do_createtable_tests 1.4 -tclquery {
+  unset -nocomplain X
+  array set X [table_list]
+  list $X(main) $X(temp) $X(auxa) $X(auxb)
+} {
+  1    "CREATE TEMP TABLE t1(a, b)"      {{} t1 {} {}}
+  2    "CREATE TEMPORARY TABLE t2(a, b)" {{} {t1 t2} {} {}}
+}
+
+# EVIDENCE-OF: R-49439-47561 It is an error to specify both a
+# <database-name> and the TEMP or TEMPORARY keyword, unless the
+# <database-name> is "temp".
+#
+drop_all_tables
+do_createtable_tests 1.5.1 -error {
+  temporary table name must be unqualified
+} {
+  1    "CREATE TEMP TABLE main.t1(a, b)"        {}
+  2    "CREATE TEMPORARY TABLE auxa.t2(a, b)"   {}
+  3    "CREATE TEMP TABLE auxb.t3(a, b)"        {}
+  4    "CREATE TEMPORARY TABLE main.xxx(x)"     {}
+}
+drop_all_tables
+do_createtable_tests 1.5.2 -tclquery {
+  unset -nocomplain X
+  array set X [table_list]
+  list $X(main) $X(temp) $X(auxa) $X(auxb)
+} {
+  1    "CREATE TEMP TABLE temp.t1(a, b)"        {{} t1 {} {}}
+  2    "CREATE TEMPORARY TABLE temp.t2(a, b)"   {{} {t1 t2} {} {}}
+  3    "CREATE TEMP TABLE TEMP.t3(a, b)"        {{} {t1 t2 t3} {} {}}
+  4    "CREATE TEMPORARY TABLE TEMP.xxx(x)"     {{} {t1 t2 t3 xxx} {} {}}
+}
+
+# EVIDENCE-OF: R-00917-09393 If no database name is specified and the
+# TEMP keyword is not present then the table is created in the main
+# database.
+#
+drop_all_tables
+do_createtable_tests 1.6 -tclquery {
+  unset -nocomplain X
+  array set X [table_list]
+  list $X(main) $X(temp) $X(auxa) $X(auxb)
+} {
+  1    "CREATE TABLE t1(a, b)"   {t1 {} {} {}}
+  2    "CREATE TABLE t2(a, b)"   {{t1 t2} {} {} {}}
+  3    "CREATE TABLE t3(a, b)"   {{t1 t2 t3} {} {} {}}
+  4    "CREATE TABLE xxx(x)"     {{t1 t2 t3 xxx} {} {} {}}
+}
+
+drop_all_tables
+do_execsql_test e_createtable-1.7.0 {
+  CREATE TABLE t1(x, y);
+  CREATE INDEX i1 ON t1(x);
+  CREATE VIEW  v1 AS SELECT * FROM t1;
+
+  CREATE TABLE auxa.tbl1(x, y);
+  CREATE INDEX auxa.idx1 ON tbl1(x);
+  CREATE VIEW auxa.view1 AS SELECT * FROM tbl1;
+} {}
+
+# EVIDENCE-OF: R-01232-54838 It is usually an error to attempt to create
+# a new table in a database that already contains a table, index or view
+# of the same name.
+#
+#   Test cases 1.7.1.* verify that creating a table in a database with a
+#   table/index/view of the same name does fail. 1.7.2.* tests that creating
+#   a table with the same name as a table/index/view in a different database
+#   is Ok.
+#
+do_createtable_tests 1.7.1 -error { %s } {
+  1    "CREATE TABLE t1(a, b)"   {{table t1 already exists}}
+  2    "CREATE TABLE i1(a, b)"   {{there is already an index named i1}}
+  3    "CREATE TABLE v1(a, b)"   {{table v1 already exists}}
+  4    "CREATE TABLE auxa.tbl1(a, b)"   {{table tbl1 already exists}}
+  5    "CREATE TABLE auxa.idx1(a, b)"   {{there is already an index named idx1}}
+  6    "CREATE TABLE auxa.view1(a, b)"  {{table view1 already exists}}
+}
+do_createtable_tests 1.7.2 {
+  1    "CREATE TABLE auxa.t1(a, b)"   {}
+  2    "CREATE TABLE auxa.i1(a, b)"   {}
+  3    "CREATE TABLE auxa.v1(a, b)"   {}
+  4    "CREATE TABLE tbl1(a, b)"      {}
+  5    "CREATE TABLE idx1(a, b)"      {}
+  6    "CREATE TABLE view1(a, b)"     {}
+}
+
+# EVIDENCE-OF: R-33917-24086 However, if the "IF NOT EXISTS" clause is
+# specified as part of the CREATE TABLE statement and a table or view of
+# the same name already exists, the CREATE TABLE command simply has no
+# effect (and no error message is returned).
+#
+drop_all_tables
+do_execsql_test e_createtable-1.8.0 {
+  CREATE TABLE t1(x, y);
+  CREATE INDEX i1 ON t1(x);
+  CREATE VIEW  v1 AS SELECT * FROM t1;
+  CREATE TABLE auxa.tbl1(x, y);
+  CREATE INDEX auxa.idx1 ON tbl1(x);
+  CREATE VIEW auxa.view1 AS SELECT * FROM tbl1;
+} {}
+do_createtable_tests 1.8 {
+  1    "CREATE TABLE IF NOT EXISTS t1(a, b)"          {}
+  2    "CREATE TABLE IF NOT EXISTS auxa.tbl1(a, b)"   {}
+  3    "CREATE TABLE IF NOT EXISTS v1(a, b)"          {}
+  4    "CREATE TABLE IF NOT EXISTS auxa.view1(a, b)"  {}
+}
+
+# EVIDENCE-OF: R-16465-40078 An error is still returned if the table
+# cannot be created because of an existing index, even if the "IF NOT
+# EXISTS" clause is specified.
+#
+do_createtable_tests 1.9 -error { %s } {
+  1    "CREATE TABLE IF NOT EXISTS i1(a, b)"   
+       {{there is already an index named i1}}
+  2    "CREATE TABLE IF NOT EXISTS auxa.idx1(a, b)"   
+       {{there is already an index named idx1}}
+}
+
+# EVIDENCE-OF: R-05513-33819 It is not an error to create a table that
+# has the same name as an existing trigger.
+#
+drop_all_tables
+do_execsql_test e_createtable-1.10.0 {
+  CREATE TABLE t1(x, y);
+  CREATE TABLE auxb.t2(x, y);
+
+  CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN
+    SELECT 1;
+  END;
+  CREATE TRIGGER auxb.tr2 AFTER INSERT ON t2 BEGIN
+    SELECT 1;
+  END;
+} {}
+do_createtable_tests 1.10 {
+  1    "CREATE TABLE tr1(a, b)"          {}
+  2    "CREATE TABLE tr2(a, b)"          {}
+  3    "CREATE TABLE auxb.tr1(a, b)"     {}
+  4    "CREATE TABLE auxb.tr2(a, b)"     {}
+}
+
+# EVIDENCE-OF: R-22283-14179 Tables are removed using the DROP TABLE
+# statement.
+#
+drop_all_tables
+do_execsql_test e_createtable-1.11.0 {
+  CREATE TABLE t1(a, b);
+  CREATE TABLE t2(a, b);
+  CREATE TABLE auxa.t3(a, b);
+  CREATE TABLE auxa.t4(a, b);
+} {}
+
+do_execsql_test e_createtable-1.11.1.1 {
+  SELECT * FROM t1;
+  SELECT * FROM t2;
+  SELECT * FROM t3;
+  SELECT * FROM t4;
+} {}
+do_execsql_test  e_createtable-1.11.1.2 { DROP TABLE t1 } {}
+do_catchsql_test e_createtable-1.11.1.3 { 
+  SELECT * FROM t1 
+} {1 {no such table: t1}}
+do_execsql_test  e_createtable-1.11.1.4 { DROP TABLE t3 } {}
+do_catchsql_test e_createtable-1.11.1.5 { 
+  SELECT * FROM t3 
+} {1 {no such table: t3}}
+
+do_execsql_test e_createtable-1.11.2.1 {
+  SELECT name FROM sqlite_master;
+  SELECT name FROM auxa.sqlite_master;
+} {t2 t4}
+do_execsql_test  e_createtable-1.11.2.2 { DROP TABLE t2 } {}
+do_execsql_test  e_createtable-1.11.2.3 { DROP TABLE t4 } {}
+do_execsql_test e_createtable-1.11.2.4 {
+  SELECT name FROM sqlite_master;
+  SELECT name FROM auxa.sqlite_master;
+} {}
+
+
 finish_test
+
index c88181c6554b843b1b5ef7480c9349ed4fd8eaf0..5ad3d91e63d46a2960f001f7057a71e5f30cb18f 100644 (file)
@@ -351,6 +351,7 @@ proc do_catchsql_test {testname sql result} {
 #   -errorformat FMTSTRING
 #   -count
 #   -query SQL
+#   -tclquery TCL
 #   -repair TCL
 #
 proc do_select_tests {prefix args} {
@@ -360,14 +361,16 @@ proc do_select_tests {prefix args} {
 
   set errfmt ""
   set countonly 0
-  set query ""
+  set tclquery ""
   set repair ""
 
   for {set i 0} {$i < [llength $switches]} {incr i} {
     set s [lindex $switches $i]
     set n [string length $s]
     if {$n>=2 && [string equal -length $n $s "-query"]} {
-      set query [lindex $switches [incr i]]
+      set tclquery [list execsql [lindex $switches [incr i]]]
+    } elseif {$n>=2 && [string equal -length $n $s "-tclquery"]} {
+      set tclquery [lindex $switches [incr i]]
     } elseif {$n>=2 && [string equal -length $n $s "-errorformat"]} {
       set errfmt [lindex $switches [incr i]]
     } elseif {$n>=2 && [string equal -length $n $s "-repair"]} {
@@ -389,12 +392,10 @@ proc do_select_tests {prefix args} {
 
   eval $repair
   foreach {tn sql res} $testlist {
-    if {$query != ""} {
+    if {$tclquery != ""} {
       execsql $sql
-      set sql $query
-    }
-
-    if {$countonly} {
+      uplevel do_test ${prefix}.$tn [list $tclquery] [list [list {*}$res]]
+    } elseif {$countonly} {
       set nRow 0
       db eval $sql {incr nRow}
       uplevel do_test ${prefix}.$tn [list [list set {} $nRow]] [list $res]
@@ -671,23 +672,26 @@ proc stepsql {dbptr sql} {
 
 # Delete a file or directory
 #
-proc forcedelete {filename} {
-  # On windows, sometimes even a [file delete -force] can fail just after
-  # a file is closed. The cause is usually "tag-alongs" - programs like
-  # anti-virus software, automatic backup tools and various explorer
-  # extensions that keep a file open a little longer than we expect, causing
-  # the delete to fail.
-  #
-  # The solution is to wait a short amount of time before retrying the delete.
-  #
-  set nRetry  50                  ;# Maximum number of retries.
-  set nDelay 100                  ;# Delay in ms before retrying.
-  for {set i 0} {$i<$nRetry} {incr i} {
-    set rc [catch {file delete -force $filename} msg]
-    if {$rc==0} break
-    after $nDelay
+proc forcedelete {args} {
+  foreach filename $args {
+    # On windows, sometimes even a [file delete -force] can fail just after
+    # a file is closed. The cause is usually "tag-alongs" - programs like
+    # anti-virus software, automatic backup tools and various explorer
+    # extensions that keep a file open a little longer than we expect, causing
+    # the delete to fail.
+    #
+    # The solution is to wait a short amount of time before retrying the 
+    # delete.
+    #
+    set nRetry  50                  ;# Maximum number of retries.
+    set nDelay 100                  ;# Delay in ms before retrying.
+    for {set i 0} {$i<$nRetry} {incr i} {
+      set rc [catch {file delete -force $filename} msg]
+      if {$rc==0} break
+      after $nDelay
+    }
+    if {$rc} { error $msg }
   }
-  if {$rc} { error $msg }
 }
 
 # Do an integrity check of the entire database
@@ -1188,9 +1192,9 @@ proc drop_all_tables {{db db}} {
     }
     foreach {t type} [$db eval "
       SELECT name, type FROM $master
-      WHERE type IN('table', 'view') AND name NOT like 'sqlite_%'
+      WHERE type IN('table', 'view') AND name NOT LIKE 'sqliteX_%' ESCAPE 'X'
     "] {
-      $db eval "DROP $type $t"
+      $db eval "DROP $type \"$t\""
     }
   }
   ifcapable trigger&&foreignkey {