]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
In the CLI, avoid unnecessary identifier quoting in the ".dump" output.
authordrh <drh@noemail.net>
Wed, 8 Mar 2017 12:25:18 +0000 (12:25 +0000)
committerdrh <drh@noemail.net>
Wed, 8 Mar 2017 12:25:18 +0000 (12:25 +0000)
Also add new ".dump" test cases.

FossilOrigin-Name: de65f907610a59e64cbf2214789c11f7117a86a6

manifest
manifest.uuid
src/shell.c
test/shell1.test

index 4a60c5aefa1b62a8656e7d0cedc91505df57872b..92484569a138b30e3d683d2452ac3bd869898f0e 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\sthe\s--preserve-rowids\soption\sto\sthe\s".dump"\scommand\sin\sthe\sCLI.
-D 2017-03-08T11:44:00.069
+C In\sthe\sCLI,\savoid\sunnecessary\sidentifier\squoting\sin\sthe\s".dump"\soutput.\nAlso\sadd\snew\s".dump"\stest\scases.
+D 2017-03-08T12:25:18.771
 F Makefile.in edb6bcdd37748d2b1c3422ff727c748df7ffe918
 F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
 F Makefile.msc a89ea37ab5928026001569f056973b9059492fe2
@@ -399,7 +399,7 @@ F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
 F src/resolve.c 3e518b962d932a997fae373366880fc028c75706
 F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
 F src/select.c d12f3539f80db38b09015561b569e0eb1c4b6c5f
-F src/shell.c c42c3031f715712a0cd47d8f08bd2d1dfec8baa0
+F src/shell.c d1ba571e8325f727f0c9571079e27b8a4595d6fd
 F src/sqlite.h.in 4d0c08f8640c586564a7032b259c5f69bf397850
 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
 F src/sqlite3ext.h 8648034aa702469afb553231677306cc6492a1ae
@@ -1110,7 +1110,7 @@ F test/sharedA.test 0cdf1a76dfa00e6beee66af5b534b1e8df2720f5
 F test/sharedB.test 16cc7178e20965d75278f410943109b77b2e645e
 F test/shared_err.test 2f2aee20db294b9924e81f6ccbe60f19e21e8506
 F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304
-F test/shell1.test 5df739ee2fe5c9dbbb2f9a0158b9723bda0910b8
+F test/shell1.test bc1ca4161e1f459c9cd412d3f21f4ee635cf2322
 F test/shell2.test e242a9912f44f4c23c3d1d802a83e934e84c853b
 F test/shell3.test 9b95ba643eaa228376f06a898fb410ee9b6e57c1
 F test/shell4.test 89ad573879a745974ff2df20ff97c5d6ffffbd5d
@@ -1563,7 +1563,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 961e79da73b4550b3e5b0f9a617133a76485db67
-R c754df2de2ef21ae6643ebeaf45e8d82
+P c60aee24714a47ce12ee2a4dcefb9f55211d3761
+R b3f6f7a6c1a0fc140ee14b2a6ca3bfe0
 U drh
-Z bce538a1e35be638681ea14d388ad037
+Z f9eff36eb51a780bc84edce006ee1256
index 7002a8bc75df3652aba8d21522312e091e378ff3..775616cedc7e59018d00b2b8d9c1b86de1be0495 100644 (file)
@@ -1 +1 @@
-c60aee24714a47ce12ee2a4dcefb9f55211d3761
\ No newline at end of file
+de65f907610a59e64cbf2214789c11f7117a86a6
\ No newline at end of file
index 07f977d46a31b440eaa889903ab7dc93d740a63d..321a39f54b2a94cc42acba24098fab000a2779ae 100644 (file)
@@ -555,6 +555,123 @@ static char *one_input_line(FILE *in, char *zPrior, int isContinuation){
   }
   return zResult;
 }
+/*
+** A variable length string to which one can append text.
+*/
+typedef struct ShellText ShellText;
+struct ShellText {
+  char *z;
+  int n;
+  int nAlloc;
+};
+
+/*
+** Initialize and destroy a ShellText object
+*/
+static void initText(ShellText *p){
+  memset(p, 0, sizeof(*p));
+}
+static void freeText(ShellText *p){
+  free(p->z);
+  initText(p);
+}
+
+/* zIn is either a pointer to a NULL-terminated string in memory obtained
+** from malloc(), or a NULL pointer. The string pointed to by zAppend is
+** added to zIn, and the result returned in memory obtained from malloc().
+** zIn, if it was not NULL, is freed.
+**
+** If the third argument, quote, is not '\0', then it is used as a
+** quote character for zAppend.
+*/
+static void appendText(ShellText *p, char const *zAppend, char quote){
+  int len;
+  int i;
+  int nAppend = strlen30(zAppend);
+
+  len = nAppend+p->n+1;
+  if( quote ){
+    len += 2;
+    for(i=0; i<nAppend; i++){
+      if( zAppend[i]==quote ) len++;
+    }
+  }
+
+  if( p->n+len>=p->nAlloc ){
+    p->nAlloc = p->nAlloc*2 + len + 20;
+    p->z = realloc(p->z, p->nAlloc);
+    if( p->z==0 ){
+      memset(p, 0, sizeof(*p));
+      return;
+    }
+  }
+
+  if( quote ){
+    char *zCsr = p->z+p->n;
+    *zCsr++ = quote;
+    for(i=0; i<nAppend; i++){
+      *zCsr++ = zAppend[i];
+      if( zAppend[i]==quote ) *zCsr++ = quote;
+    }
+    *zCsr++ = quote;
+    p->n = (int)(zCsr - p->z);
+    *zCsr = '\0';
+  }else{
+    memcpy(p->z+p->n, zAppend, nAppend);
+    p->n += nAppend;
+    p->z[p->n] = '\0';
+  }
+}
+
+/*
+** Attempt to determine if identifier zName needs to be quoted, either
+** because it contains non-alphanumeric characters, or because it is an
+** SQLite keyword.  Be conservative in this estimate:  When in doubt assume
+** that quoting is required.
+**
+** Return '"' if quoting is required.  Return 0 if no quoting is required.
+*/
+static char quoteChar(const char *zName){
+  /* All SQLite keywords, in alphabetical order */
+  static const char *azKeywords[] = {
+    "ABORT", "ACTION", "ADD", "AFTER", "ALL", "ALTER", "ANALYZE", "AND", "AS",
+    "ASC", "ATTACH", "AUTOINCREMENT", "BEFORE", "BEGIN", "BETWEEN", "BY",
+    "CASCADE", "CASE", "CAST", "CHECK", "COLLATE", "COLUMN", "COMMIT",
+    "CONFLICT", "CONSTRAINT", "CREATE", "CROSS", "CURRENT_DATE",
+    "CURRENT_TIME", "CURRENT_TIMESTAMP", "DATABASE", "DEFAULT", "DEFERRABLE",
+    "DEFERRED", "DELETE", "DESC", "DETACH", "DISTINCT", "DROP", "EACH",
+    "ELSE", "END", "ESCAPE", "EXCEPT", "EXCLUSIVE", "EXISTS", "EXPLAIN",
+    "FAIL", "FOR", "FOREIGN", "FROM", "FULL", "GLOB", "GROUP", "HAVING", "IF",
+    "IGNORE", "IMMEDIATE", "IN", "INDEX", "INDEXED", "INITIALLY", "INNER",
+    "INSERT", "INSTEAD", "INTERSECT", "INTO", "IS", "ISNULL", "JOIN", "KEY",
+    "LEFT", "LIKE", "LIMIT", "MATCH", "NATURAL", "NO", "NOT", "NOTNULL",
+    "NULL", "OF", "OFFSET", "ON", "OR", "ORDER", "OUTER", "PLAN", "PRAGMA",
+    "PRIMARY", "QUERY", "RAISE", "RECURSIVE", "REFERENCES", "REGEXP",
+    "REINDEX", "RELEASE", "RENAME", "REPLACE", "RESTRICT", "RIGHT",
+    "ROLLBACK", "ROW", "SAVEPOINT", "SELECT", "SET", "TABLE", "TEMP",
+    "TEMPORARY", "THEN", "TO", "TRANSACTION", "TRIGGER", "UNION", "UNIQUE",
+    "UPDATE", "USING", "VACUUM", "VALUES", "VIEW", "VIRTUAL", "WHEN", "WHERE",
+    "WITH", "WITHOUT",
+  };
+  int i, lwr, upr, mid, c;
+  if( !isalpha((unsigned char)zName[0]) && zName[0]!='_' ) return '"';
+  for(i=0; zName[i]; i++){
+    if( !isalnum((unsigned char)zName[i]) && zName[i]!='_' ) return '"';
+  }
+  lwr = 0;
+  upr = sizeof(azKeywords)/sizeof(azKeywords[0]) - 1;
+  while( lwr<=upr ){
+    mid = (lwr+upr)/2;
+    c = sqlite3_stricmp(azKeywords[mid], zName);
+    if( c==0 ) return '"';
+    if( c<0 ){
+      lwr = mid+1;
+    }else{
+      upr = mid-1;
+    }
+  }
+  return 0;
+}
 
 #if defined(SQLITE_ENABLE_SESSION)
 /*
@@ -1274,6 +1391,7 @@ static int callback(void *pArg, int nArg, char **azArg, char **azCol){
   return shell_callback(pArg, nArg, azArg, azCol, NULL);
 }
 
+
 /*
 ** Set the destination table field of the ShellState structure to
 ** the name of the table given.  Escape any quote characters in the
@@ -1281,7 +1399,7 @@ static int callback(void *pArg, int nArg, char **azArg, char **azCol){
 */
 static void set_table_name(ShellState *p, const char *zName){
   int i, n;
-  int needQuote;
+  int cQuote;
   char *z;
 
   if( p->zDestTable ){
@@ -1289,86 +1407,24 @@ static void set_table_name(ShellState *p, const char *zName){
     p->zDestTable = 0;
   }
   if( zName==0 ) return;
-  needQuote = !isalpha((unsigned char)*zName) && *zName!='_';
-  for(i=n=0; zName[i]; i++, n++){
-    if( !isalnum((unsigned char)zName[i]) && zName[i]!='_' ){
-      needQuote = 1;
-      if( zName[i]=='\'' ) n++;
-    }
-  }
-  if( needQuote ) n += 2;
+  cQuote = quoteChar(zName);
+  n = strlen30(zName);
+  if( cQuote ) n += 2;
   z = p->zDestTable = malloc( n+1 );
   if( z==0 ){
     raw_printf(stderr,"Error: out of memory\n");
     exit(1);
   }
   n = 0;
-  if( needQuote ) z[n++] = '\'';
+  if( cQuote ) z[n++] = cQuote;
   for(i=0; zName[i]; i++){
     z[n++] = zName[i];
-    if( zName[i]=='\'' ) z[n++] = '\'';
+    if( zName[i]==cQuote ) z[n++] = cQuote;
   }
-  if( needQuote ) z[n++] = '\'';
+  if( cQuote ) z[n++] = cQuote;
   z[n] = 0;
 }
 
-/*
-** A variable length string to which one can append text.
-*/
-typedef struct ShellString ShellString;
-struct ShellString {
-  char *z;
-  int n;
-  int nAlloc;
-};
-
-/* zIn is either a pointer to a NULL-terminated string in memory obtained
-** from malloc(), or a NULL pointer. The string pointed to by zAppend is
-** added to zIn, and the result returned in memory obtained from malloc().
-** zIn, if it was not NULL, is freed.
-**
-** If the third argument, quote, is not '\0', then it is used as a
-** quote character for zAppend.
-*/
-static void appendText(ShellString *p, char const *zAppend, char quote){
-  int len;
-  int i;
-  int nAppend = strlen30(zAppend);
-
-  len = nAppend+p->n+1;
-  if( quote ){
-    len += 2;
-    for(i=0; i<nAppend; i++){
-      if( zAppend[i]==quote ) len++;
-    }
-  }
-
-  if( p->n+len>=p->nAlloc ){
-    p->nAlloc = p->nAlloc*2 + len + 20;
-    p->z = realloc(p->z, p->nAlloc);
-    if( p->z==0 ){
-      memset(p, 0, sizeof(*p));
-      return;
-    }
-  }
-
-  if( quote ){
-    char *zCsr = p->z+p->n;
-    *zCsr++ = quote;
-    for(i=0; i<nAppend; i++){
-      *zCsr++ = zAppend[i];
-      if( zAppend[i]==quote ) *zCsr++ = quote;
-    }
-    *zCsr++ = quote;
-    p->n = (int)(zCsr - p->z);
-    *zCsr = '\0';
-  }else{
-    memcpy(p->z+p->n, zAppend, nAppend);
-    p->n += nAppend;
-    p->z[p->n] = '\0';
-  }
-}
-
 
 /*
 ** Execute a query statement that will generate SQL output.  Print
@@ -2131,9 +2187,6 @@ static char **tableColumnList(ShellState *p, const char *zTab){
   return azCol;
 }
 
-
-
-
 /*
 ** This is a different callback routine used for dumping the database.
 ** Each row received by this callback consists of a table name,
@@ -2177,8 +2230,8 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
   }
 
   if( strcmp(zType, "table")==0 ){
-    ShellString sSelect;
-    ShellString sTable;
+    ShellText sSelect;
+    ShellText sTable;
     char **azCol;
     int i;
     char *savedDestTable;
@@ -2192,8 +2245,8 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
 
     /* Always quote the table name, even if it appears to be pure ascii,
     ** in case it is a keyword. Ex:  INSERT INTO "table" ... */
-    memset(&sTable, 0, sizeof(sTable));
-    appendText(&sTable, zTable, '"');
+    initText(&sTable);
+    appendText(&sTable, zTable, quoteChar(zTable));
     /* If preserving the rowid, add a column list after the table name.
     ** In other words:  "INSERT INTO tab(rowid,a,b,c,...) VALUES(...)"
     ** instead of the usual "INSERT INTO tab VALUES(...)".
@@ -2203,27 +2256,27 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
       appendText(&sTable, azCol[0], 0);
       for(i=1; azCol[i]; i++){
         appendText(&sTable, ",", 0);
-        appendText(&sTable, azCol[i], '"');
+        appendText(&sTable, azCol[i], quoteChar(azCol[i]));
       }
       appendText(&sTable, ")", 0);
     }
 
     /* Build an appropriate SELECT statement */
-    memset(&sSelect, 0, sizeof(sSelect));
+    initText(&sSelect);
     appendText(&sSelect, "SELECT ", 0);
     if( azCol[0] ){
       appendText(&sSelect, azCol[0], 0);
       appendText(&sSelect, ",", 0);
     }
     for(i=1; azCol[i]; i++){
-      appendText(&sSelect, azCol[i], 0);
+      appendText(&sSelect, azCol[i], quoteChar(azCol[i]));
       if( azCol[i+1] ){
         appendText(&sSelect, ",", 0);
       }
     }
     freeColumnList(azCol);
     appendText(&sSelect, " FROM ", 0);
-    appendText(&sSelect, zTable, '"');
+    appendText(&sSelect, zTable, quoteChar(zTable));
 
     savedDestTable = p->zDestTable;
     savedMode = p->mode;
@@ -2232,8 +2285,8 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
     rc = shell_exec(p->db, sSelect.z, shell_callback, p, 0);
     p->zDestTable = savedDestTable;
     p->mode = savedMode;
-    free(sTable.z);
-    free(sSelect.z);
+    freeText(&sTable);
+    freeText(&sSelect);
     if( rc ) p->nErr++;
   }
   return 0;
index 0912fa424013ea84f883618c15f4bffc15949d05..7f282292c063b05ff694141ea69ffff3dbf9c2a2 100644 (file)
@@ -740,41 +740,46 @@ do_test shell1-4.1 {
 } {0 {PRAGMA foreign_keys=OFF;
 BEGIN TRANSACTION;
 CREATE TABLE t1(x);
-INSERT INTO "t1" VALUES(NULL);
-INSERT INTO "t1" VALUES('');
-INSERT INTO "t1" VALUES(1);
-INSERT INTO "t1" VALUES(2.25);
-INSERT INTO "t1" VALUES('hello');
-INSERT INTO "t1" VALUES(X'807f');
+INSERT INTO t1 VALUES(NULL);
+INSERT INTO t1 VALUES('');
+INSERT INTO t1 VALUES(1);
+INSERT INTO t1 VALUES(2.25);
+INSERT INTO t1 VALUES('hello');
+INSERT INTO t1 VALUES(X'807f');
 CREATE TABLE t3(x,y);
-INSERT INTO "t3" VALUES(1,NULL);
-INSERT INTO "t3" VALUES(2,'');
-INSERT INTO "t3" VALUES(3,1);
-INSERT INTO "t3" VALUES(4,2.25);
-INSERT INTO "t3" VALUES(5,'hello');
-INSERT INTO "t3" VALUES(6,X'807f');
+INSERT INTO t3 VALUES(1,NULL);
+INSERT INTO t3 VALUES(2,'');
+INSERT INTO t3 VALUES(3,1);
+INSERT INTO t3 VALUES(4,2.25);
+INSERT INTO t3 VALUES(5,'hello');
+INSERT INTO t3 VALUES(6,X'807f');
 COMMIT;}}
 
+# The --preserve-rowids option to .dump
+#
 do_test shell1-4.1.1 {
   catchcmd test.db {.dump --preserve-rowids}
 } {0 {PRAGMA foreign_keys=OFF;
 BEGIN TRANSACTION;
 CREATE TABLE t1(x);
-INSERT INTO "t1"(rowid,"x") VALUES(1,NULL);
-INSERT INTO "t1"(rowid,"x") VALUES(2,'');
-INSERT INTO "t1"(rowid,"x") VALUES(3,1);
-INSERT INTO "t1"(rowid,"x") VALUES(4,2.25);
-INSERT INTO "t1"(rowid,"x") VALUES(5,'hello');
-INSERT INTO "t1"(rowid,"x") VALUES(6,X'807f');
+INSERT INTO t1(rowid,x) VALUES(1,NULL);
+INSERT INTO t1(rowid,x) VALUES(2,'');
+INSERT INTO t1(rowid,x) VALUES(3,1);
+INSERT INTO t1(rowid,x) VALUES(4,2.25);
+INSERT INTO t1(rowid,x) VALUES(5,'hello');
+INSERT INTO t1(rowid,x) VALUES(6,X'807f');
 CREATE TABLE t3(x,y);
-INSERT INTO "t3"(rowid,"x","y") VALUES(1,1,NULL);
-INSERT INTO "t3"(rowid,"x","y") VALUES(2,2,'');
-INSERT INTO "t3"(rowid,"x","y") VALUES(3,3,1);
-INSERT INTO "t3"(rowid,"x","y") VALUES(4,4,2.25);
-INSERT INTO "t3"(rowid,"x","y") VALUES(5,5,'hello');
-INSERT INTO "t3"(rowid,"x","y") VALUES(6,6,X'807f');
+INSERT INTO t3(rowid,x,y) VALUES(1,1,NULL);
+INSERT INTO t3(rowid,x,y) VALUES(2,2,'');
+INSERT INTO t3(rowid,x,y) VALUES(3,3,1);
+INSERT INTO t3(rowid,x,y) VALUES(4,4,2.25);
+INSERT INTO t3(rowid,x,y) VALUES(5,5,'hello');
+INSERT INTO t3(rowid,x,y) VALUES(6,6,X'807f');
 COMMIT;}}
 
+# If the table contains an INTEGER PRIMARY KEY, do not record a separate
+# rowid column in the output.
+#
 do_test shell1-4.1.2 {
   db close
   forcedelete test2.db
@@ -788,14 +793,80 @@ do_test shell1-4.1.2 {
 } {0 {PRAGMA foreign_keys=OFF;
 BEGIN TRANSACTION;
 CREATE TABLE t1(x INTEGER PRIMARY KEY, y);
-INSERT INTO "t1" VALUES(1,NULL);
-INSERT INTO "t1" VALUES(2,'');
-INSERT INTO "t1" VALUES(3,1);
-INSERT INTO "t1" VALUES(4,2.25);
-INSERT INTO "t1" VALUES(5,'hello');
-INSERT INTO "t1" VALUES(6,X'807f');
+INSERT INTO t1 VALUES(1,NULL);
+INSERT INTO t1 VALUES(2,'');
+INSERT INTO t1 VALUES(3,1);
+INSERT INTO t1 VALUES(4,2.25);
+INSERT INTO t1 VALUES(5,'hello');
+INSERT INTO t1 VALUES(6,X'807f');
+COMMIT;}}
+
+# Verify that the table named [table] is correctly quoted and that
+# an INTEGER PRIMARY KEY DESC is not an alias for the rowid.
+#
+do_test shell1-4.1.3 {
+  db close
+  forcedelete test2.db
+  sqlite3 db test2.db
+  db eval {
+    CREATE TABLE [table](x INTEGER PRIMARY KEY DESC, y);
+    INSERT INTO [table] VALUES(1,null), (12,''), (23,1),
+                         (34,2.25), (45,'hello'), (56,x'807f');
+  }
+  catchcmd test2.db {.dump --preserve-rowids}
+} {0 {PRAGMA foreign_keys=OFF;
+BEGIN TRANSACTION;
+CREATE TABLE [table](x INTEGER PRIMARY KEY DESC, y);
+INSERT INTO "table"(rowid,x,y) VALUES(1,1,NULL);
+INSERT INTO "table"(rowid,x,y) VALUES(2,12,'');
+INSERT INTO "table"(rowid,x,y) VALUES(3,23,1);
+INSERT INTO "table"(rowid,x,y) VALUES(4,34,2.25);
+INSERT INTO "table"(rowid,x,y) VALUES(5,45,'hello');
+INSERT INTO "table"(rowid,x,y) VALUES(6,56,X'807f');
 COMMIT;}}
 
+# Do not record rowids for a WITHOUT ROWID table.  Also check correct quoting
+# of table names that contain odd characters.
+#
+do_test shell1-4.1.4 {
+  db close
+  forcedelete test2.db
+  sqlite3 db test2.db
+  db eval {
+    CREATE TABLE [ta<>ble](x INTEGER PRIMARY KEY, y) WITHOUT ROWID;
+    INSERT INTO [ta<>ble] VALUES(1,null), (12,''), (23,1),
+                         (34,2.25), (45,'hello'), (56,x'807f');
+  }
+  catchcmd test2.db {.dump --preserve-rowids}
+} {0 {PRAGMA foreign_keys=OFF;
+BEGIN TRANSACTION;
+CREATE TABLE [ta<>ble](x INTEGER PRIMARY KEY, y) WITHOUT ROWID;
+INSERT INTO "ta<>ble" VALUES(1,NULL);
+INSERT INTO "ta<>ble" VALUES(12,'');
+INSERT INTO "ta<>ble" VALUES(23,1);
+INSERT INTO "ta<>ble" VALUES(34,2.25);
+INSERT INTO "ta<>ble" VALUES(45,'hello');
+INSERT INTO "ta<>ble" VALUES(56,X'807f');
+COMMIT;}}
+
+# Do not record rowids if the rowid is inaccessible
+#
+do_test shell1-4.1.5 {
+  db close
+  forcedelete test2.db
+  sqlite3 db test2.db
+  db eval {
+    CREATE TABLE t1(_ROWID_,rowid,oid);
+    INSERT INTO t1 VALUES(1,null,'alpha'), (12,'',99), (23,1,x'b0b1b2');
+  }
+  catchcmd test2.db {.dump --preserve-rowids}
+} {0 {PRAGMA foreign_keys=OFF;
+BEGIN TRANSACTION;
+CREATE TABLE t1(_ROWID_,rowid,oid);
+INSERT INTO t1 VALUES(1,NULL,'alpha');
+INSERT INTO t1 VALUES(12,'',99);
+INSERT INTO t1 VALUES(23,1,X'b0b1b2');
+COMMIT;}}
 
 # Test the output of ".mode insert"
 #