]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix for #3719. When synthesizing a CREATE TABLE statement as as result of a "CREATE...
authordanielk1977 <danielk1977@noemail.net>
Sat, 14 Mar 2009 08:37:23 +0000 (08:37 +0000)
committerdanielk1977 <danielk1977@noemail.net>
Sat, 14 Mar 2009 08:37:23 +0000 (08:37 +0000)
FossilOrigin-Name: 7c6437efe0a0e935cfa8041bd6b94070c8654fa4

manifest
manifest.uuid
src/build.c
test/table.test

index 1f51465ab9b5d1562582827bed86c890b81bfa92..569d7fa1d265e77dcaf7958fca69e8d89b119fb6 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Do\snot\soverrun\sa\sbuffer\sin\sthe\sgenfkey\scode\s(now\spart\sof\sshell.c).\sFix\sfor\s#3722.\s(CVS\s6344)
-D 2009-03-13T15:32:53
+C Fix\sfor\s#3719.\sWhen\ssynthesizing\sa\sCREATE\sTABLE\sstatement\sas\sas\sresult\sof\sa\s"CREATE\sTABLE\sAS",\squote\sthe\scolumn\stype\snames\sunless\sthey\sare\ssimple\sidentifiers\sor\ssimple\sidentifiers\sfollowed\sby\sone\sor\stwo\sdimensions\s(e.g.\s"VARCHAR(10)").\s(CVS\s6345)
+D 2009-03-14T08:37:24
 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
 F Makefile.in d64baddbf55cdf33ff030e14da837324711a4ef7
 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@@ -106,7 +106,7 @@ F src/btmutex.c 341502bc496dc0840dcb00cde65680fb0e85c3ab
 F src/btree.c 6e7501d7a207dcc15b099e67231bc8cc86ef7fe9
 F src/btree.h 96a019c9f28da38e79940512d7800e419cd8c702
 F src/btreeInt.h 0a4884e6152d7cae9c741e91b830064c19fd2c05
-F src/build.c 741240c8d6a54201fa8757db1ee6efba71be59a2
+F src/build.c 7e5e93011bab2f142cb03faa72bb64ff30e321fc
 F src/callback.c 09c6fedc77a45db99ba25a75d61382830314b357
 F src/complete.c cb14e06dbe79dee031031f0d9e686ff306afe07c
 F src/date.c 0d804df3bbda46329946a01ff5c75c3f4f135218
@@ -547,7 +547,7 @@ F test/subquery.test b524f57c9574b2c0347045b4510ef795d4686796
 F test/subselect.test d24fd8757daf97dafd2e889c73ea4c4272dcf4e4
 F test/substr.test 18f57c4ca8a598805c4d64e304c418734d843c1a
 F test/sync.test ded6b39d8d8ca3c0c5518516c6371b3316d3e3a3
-F test/table.test 0aac9468b69d2683e68ee2682cdae28d82a453ec
+F test/table.test bf1bc3d9634342a3470bdf64b6190e7445b6b8a6
 F test/tableapi.test 505031f15b18a750184d967d2c896cf88fcc969c
 F test/tclsqlite.test 413a8a887d89ea8fa7055e8d118ffb03b0a4c91a
 F test/tempdb.test b88ac8a19823cf771d742bf61eef93ef337c06b1
@@ -704,7 +704,7 @@ F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81
 F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
-P 03679857a320517a7b89e5214e948bce9af896a9
-R 6c05748751f4494b7f4484ee342f5594
+P 943b11fb188835f0c62b6064b084192b1bbe1c0c
+R 80daaf5cc0fe3707a03f09e098f3c65b
 U danielk1977
-Z 81f620610e97249eb47012ea10670973
+Z e47d0a979c492c3c4fa5d4292c1f1fd6
index 6c600ae9ae11a90ef054107ded4d613af9610158..53c80d75ddab3738c3a19814fc9e75fd1d2ccd09 100644 (file)
@@ -1 +1 @@
-943b11fb188835f0c62b6064b084192b1bbe1c0c
\ No newline at end of file
+7c6437efe0a0e935cfa8041bd6b94070c8654fa4
\ No newline at end of file
index 446a6903fd08ace25485350d7f3a077eed753b9e..4103e3cb25b90fa9063422319f58cb02520b7b8f 100644 (file)
@@ -22,7 +22,7 @@
 **     COMMIT
 **     ROLLBACK
 **
-** $Id: build.c,v 1.521 2009/02/28 10:47:42 danielk1977 Exp $
+** $Id: build.c,v 1.522 2009/03/14 08:37:24 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 
@@ -1330,18 +1330,100 @@ static int identLength(const char *z){
 }
 
 /*
-** Write an identifier onto the end of the given string.  Add
-** quote characters as needed.
+** This function is a wrapper around sqlite3GetToken() used by 
+** isValidDimension(). This function differs from sqlite3GetToken() in
+** that:
+**
+**   * Whitespace is ignored, and
+**   * The output variable *peToken is set to 0 if the end of the
+**     nul-terminated input string is reached.
+*/
+static int getTokenNoSpace(unsigned char *z, int *peToken){
+  int n = 0;
+  while( sqlite3Isspace(z[n]) ) n++;
+  if( !z[n] ){
+    *peToken = 0;
+    return 0;
+  }
+  return n + sqlite3GetToken(&z[n], peToken);
+}
+
+/*
+** Parameter z points to a nul-terminated string. Return true if, when
+** whitespace is ignored, the contents of this string matches one of 
+** the following patterns:
+**
+**     ""
+**     "(number)"
+**     "(number,number)"
 */
-static void identPut(char *z, int *pIdx, char *zSignedIdent){
+static int isValidDimension(unsigned char *z){
+  int eToken;
+  int n = 0;
+  n += getTokenNoSpace(&z[n], &eToken);
+  if( eToken ){
+    if( eToken!=TK_LP ) return 0;
+    n += getTokenNoSpace(&z[n], &eToken);
+    if( eToken==TK_PLUS || eToken==TK_MINUS ){
+      n += getTokenNoSpace(&z[n], &eToken);
+    }
+    if( eToken!=TK_INTEGER && eToken!=TK_FLOAT ) return 0;
+    n += getTokenNoSpace(&z[n], &eToken);
+    if( eToken==TK_COMMA ){
+      n += getTokenNoSpace(&z[n], &eToken);
+      if( eToken==TK_PLUS || eToken==TK_MINUS ){
+        n += getTokenNoSpace(&z[n], &eToken);
+      }
+      if( eToken!=TK_INTEGER && eToken!=TK_FLOAT ) return 0;
+      n += getTokenNoSpace(&z[n], &eToken);
+    }
+    if( eToken!=TK_RP ) return 0;
+    getTokenNoSpace(&z[n], &eToken);
+  }
+  if( eToken ) return 0;
+  return 1;
+}
+
+/*
+** The first parameter is a pointer to an output buffer. The second 
+** parameter is a pointer to an integer that contains the offset at
+** which to write into the output buffer. This function copies the
+** nul-terminated string pointed to by the third parameter, zSignedIdent,
+** to the specified offset in the buffer and updates *pIdx to refer
+** to the first byte after the last byte written before returning.
+** 
+** If the string zSignedIdent consists entirely of alpha-numeric
+** characters, does not begin with a digit and is not an SQL keyword,
+** then it is copied to the output buffer exactly as it is. Otherwise,
+** it is quoted using double-quotes.
+*/
+static void identPut(char *z, int *pIdx, char *zSignedIdent, int isTypename){
   unsigned char *zIdent = (unsigned char*)zSignedIdent;
   int i, j, needQuote;
   i = *pIdx;
+
   for(j=0; zIdent[j]; j++){
     if( !sqlite3Isalnum(zIdent[j]) && zIdent[j]!='_' ) break;
   }
-  needQuote =  zIdent[j]!=0 || sqlite3Isdigit(zIdent[0])
-                  || sqlite3KeywordCode(zIdent, j)!=TK_ID;
+  needQuote = sqlite3Isdigit(zIdent[0]) || sqlite3KeywordCode(zIdent, j)!=TK_ID;
+  if( !needQuote ){
+    if( isTypename ){
+      /* If this is a type-name, allow a little more flexibility. In SQLite,
+      ** a type-name is specified as:
+      **
+      **   ids [ids] [(number [, number])]
+      **
+      ** where "ids" is either a quoted string or a simple identifier (in the
+      ** above notation, [] means optional). It is a bit tricky to check
+      ** for all cases, but it is good to avoid unnecessarily quoting common
+      ** typenames like VARCHAR(10).
+      */
+      needQuote = !isValidDimension(&zIdent[j]);
+    }else{
+      needQuote = zIdent[j];
+    }
+  }
+
   if( needQuote ) z[i++] = '"';
   for(j=0; zIdent[j]; j++){
     z[i++] = zIdent[j];
@@ -1367,7 +1449,7 @@ static char *createTableStmt(sqlite3 *db, Table *p){
     n += identLength(pCol->zName);
     z = pCol->zType;
     if( z ){
-      n += (sqlite3Strlen30(z) + 1);
+      n += identLength(z);
     }
   }
   n += identLength(p->zName);
@@ -1388,18 +1470,17 @@ static char *createTableStmt(sqlite3 *db, Table *p){
   }
   sqlite3_snprintf(n, zStmt, "CREATE TABLE ");
   k = sqlite3Strlen30(zStmt);
-  identPut(zStmt, &k, p->zName);
+  identPut(zStmt, &k, p->zName, 0);
   zStmt[k++] = '(';
   for(pCol=p->aCol, i=0; i<p->nCol; i++, pCol++){
     sqlite3_snprintf(n-k, &zStmt[k], zSep);
     k += sqlite3Strlen30(&zStmt[k]);
     zSep = zSep2;
-    identPut(zStmt, &k, pCol->zName);
+    identPut(zStmt, &k, pCol->zName, 0);
     if( (z = pCol->zType)!=0 ){
       zStmt[k++] = ' ';
       assert( (int)(sqlite3Strlen30(z)+k+1)<=n );
-      sqlite3_snprintf(n-k, &zStmt[k], "%s", z);
-      k += sqlite3Strlen30(z);
+      identPut(zStmt, &k, z, 1);
     }
   }
   sqlite3_snprintf(n-k, &zStmt[k], "%s", zEnd);
index 880a6cbaeeac707758b593e90270749991a0f396..55508e92d98145f60e0bc8f8f3f10018a840a7b2 100644 (file)
@@ -11,7 +11,7 @@
 # This file implements regression tests for SQLite library.  The
 # focus of this file is testing the CREATE TABLE statement.
 #
-# $Id: table.test,v 1.49 2009/01/16 11:04:58 danielk1977 Exp $
+# $Id: table.test,v 1.50 2009/03/14 08:37:24 danielk1977 Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -399,6 +399,37 @@ do_test table-8.8 {
   }
 } {1 {no such table: no_such_table}}
 
+do_test table-8.9 {
+  execsql {
+    CREATE TABLE t10("col.1" [char.3]);
+    CREATE TABLE t11 AS SELECT * FROM t10;
+    SELECT sql FROM sqlite_master WHERE name = 't11';
+  }
+} {{CREATE TABLE t11("col.1" "char.3")}}
+do_test table-8.10 {
+  execsql {
+    CREATE TABLE t12(
+      a INTEGER,
+      b VARCHAR(10),
+      c VARCHAR(1,10),
+      d VARCHAR(+1,-10),
+      e VARCHAR (+1,-10),
+      f "VARCHAR (+1,-10, 5)",
+      g BIG INTEGER
+    );
+    CREATE TABLE t13 AS SELECT * FROM t12;
+    SELECT sql FROM sqlite_master WHERE name = 't13';
+  }
+} {{CREATE TABLE t13(
+  a INTEGER,
+  b VARCHAR(10),
+  c VARCHAR(1,10),
+  d VARCHAR(+1,-10),
+  e VARCHAR (+1,-10),
+  f "VARCHAR (+1,-10, 5)",
+  g "BIG INTEGER"
+)}}
+
 # Make sure we cannot have duplicate column names within a table.
 #
 do_test table-9.1 {