]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
CLI's .import column rename made more minimal, and reports renames. auto-column
authorlarrybr <larrybr@noemail.net>
Mon, 14 Feb 2022 01:12:46 +0000 (01:12 +0000)
committerlarrybr <larrybr@noemail.net>
Mon, 14 Feb 2022 01:12:46 +0000 (01:12 +0000)
FossilOrigin-Name: c626cff7f99ec502ebd46f9cdafc3d088697544ef5d6559b6b3ae85679b4f9fa

manifest
manifest.uuid
src/shell.c.in
test/shell5.test

index c8b221ba39da0403b70798980d638cad0011bf25..057eff377724e063a8fc59329900fd03f92807e1 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Sync\sw/trunk,\sfix\szAutoColumns\splacement\sblunder,\sall\sto\spass\sall\sTCL\stests
-D 2022-02-13T22:18:22.163
+C CLI's\s.import\scolumn\srename\smade\smore\sminimal,\sand\sreports\srenames.
+D 2022-02-14T01:12:46.316
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -553,7 +553,7 @@ F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c
 F src/resolve.c ea935b87d6fb36c78b70cdc7b28561dc8f33f2ef37048389549c7b5ef9b0ba5e
 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
 F src/select.c 3baa9dd8cf240654773c7974e2bcce398ac9dd24419c36684156963defe43b35
-F src/shell.c.in 233a5c7f0ee9a9d1b88f1caed538d813390bb474082d9d74504d846ccb49f31e x
+F src/shell.c.in 1289a2e10f48e75956700f61aac63beff7f05988ac7a4c701800b9f0e9adad4e x
 F src/sqlite.h.in 7047c4b60fa550264d6363bb1d983540e7828fb19d2d1e5aa43b52ca13144807
 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
 F src/sqlite3ext.h a95cb9ed106e3d39e2118e4dcc15a14faec3fa50d0093425083d340d9dfd96e6
@@ -1392,7 +1392,7 @@ F test/shell1.test b224e0793c5f48aa3749e65d8c64b93a30731bd206f2e41e6c5f1bee1bdb1
 F test/shell2.test 89e4b2db062d52baed75022227b462d085cff495809de1699652779d8e0257d6
 F test/shell3.test a50628ab1d78d90889d9d3f32fb2c084ee15674771e96afe954aaa0accd1de3c
 F test/shell4.test 8f6c0fce4abed19a8a7f7262517149812a04caa905d01bdc8f5e92573504b759
-F test/shell5.test 1be5454b8376e363f99cd0947ab43e1121e5b802c067d1fe7089e3461de1421d x
+F test/shell5.test 3be444397eb1e91619ce289a6216a8df9ac690cc45d5e9595f60e750a944161f x
 F test/shell6.test 1ceb51b2678c472ba6cf1e5da96679ce8347889fe2c3bf93a0e0fa73f00b00d3
 F test/shell7.test 115132f66d0463417f408562cc2cf534f6bbc6d83a6d50f0072a9eb171bae97f
 F test/shell8.test 388471d16e4de767333107e30653983f186232c0e863f4490bb230419e830aae
@@ -1944,8 +1944,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 433e5ead2b711d1e3b0b62cf8cb5a8a65e2474c68ef2173317ed4323fc8bdc58 bf8dbfd499e732f14c7a8efee527e8ce155937dbb2a3e85213f8aa64ac497189
-R d0a4f648a76dcc064c4b8040fefbc80a
+P 67dc59f46d742ad69742fb34540a3074af163a3f1a0f9093f83db2276bf944ca
+R ef7ea611e7a4e14ff938dd85400a84e0
 U larrybr
-Z 9500253e6d614600afa73cc694266a23
+Z 0a705a46f17a261142cf326cb58d0cbc
 # Remove this line to create a well-formed Fossil manifest.
index 505f134e8fb3f87439328e777be4a0d65614f910..3fdeeb0533f3008debc6b27f1baf7901cac10059 100644 (file)
@@ -1 +1 @@
-67dc59f46d742ad69742fb34540a3074af163a3f1a0f9093f83db2276bf944ca
\ No newline at end of file
+c626cff7f99ec502ebd46f9cdafc3d088697544ef5d6559b6b3ae85679b4f9fa
\ No newline at end of file
index 66428b72b611b035990f322a6c41474f54c5ea6a..dba42e817f939a71613406460f0a4f55482e56c9 100755 (executable)
@@ -7830,8 +7830,9 @@ static int recoverDatabaseCmd(ShellState *pState, int nArg, char **azArg){
  *   (a) The db was not initialized and zCol==0 (There are no columns.)
  *   (b) zCol!=0  (Column was added, db initialized as needed.)
  * The 3rd argument, pRenamed, references an out parameter. If the
- * pointer is non-zero, its referent will be set to 1 if renaming was
- * necessary, or set to 0 if none was done.
+ * pointer is non-zero, its referent will be set to a summary of renames
+ * done if renaming was necessary, or set to 0 if none was done. The out
+ * string (if any) must be sqlite3_free()'ed by the caller.
  */
 #ifdef SHELL_DEBUG
 #define rc_err_oom_die(rc) \
@@ -7862,12 +7863,17 @@ static const char *zCOL_DB = ":memory:";
 # define AUTOCOLUMN_SEP SHELL_STRINGIFY(SHELL_AUTOCOLUMN_SEP)
 #endif
 
-static char *zAutoColumn(const char *zColNew, sqlite3 **pDb, int *pRenamed){
+static char *zAutoColumn(const char *zColNew, sqlite3 **pDb, char **pzRenamed){
   /* Queries and D{D,M}L used here */
   static const char * const zTabMake = "\
 CREATE TABLE ColNames(\
  cpos INTEGER PRIMARY KEY,\
- name TEXT, nlen INT, chop INT, reps INT, suff TEXT)\
+ name TEXT, nlen INT, chop INT, reps INT, suff TEXT);\
+CREATE VIEW RepeatedNames AS \
+SELECT DISTINCT t.name FROM ColNames t \
+WHERE t.name COLLATE NOCASE IN (\
+ SELECT o.name FROM ColNames o WHERE o.cpos<>t.cpos\
+);\
 ";
   static const char * const zTabFill = "\
 INSERT INTO ColNames(name,nlen,chop,reps,suff)\
@@ -7877,6 +7883,7 @@ INSERT INTO ColNames(name,nlen,chop,reps,suff)\
 SELECT count(DISTINCT (substring(name,1,nlen-chop)||suff) COLLATE NOCASE)\
  <count(name) FROM ColNames\
 ";
+#ifdef SHELL_COLUMN_RENAME_CLEAN
   static const char * const zDedoctor = "\
 UPDATE ColNames SET chop=iif(\
   (substring(name,nlen,1) BETWEEN '0' AND '9')\
@@ -7885,6 +7892,7 @@ UPDATE ColNames SET chop=iif(\
  0\
 )\
 ";
+#endif
   static const char * const zSetReps = "\
 UPDATE ColNames AS t SET reps=\
 (SELECT count(*) FROM ColNames d \
@@ -7898,11 +7906,40 @@ SELECT CAST(ceil(log(count(*)+0.5)) AS INT) FROM ColNames \
 ";
 #endif
   static const char * const zRenameRank =
-#ifndef SHELL_COLUMN_RENAME_DML
+#ifdef SHELL_COLUMN_RENAME_CLEAN
     "UPDATE ColNames AS t SET suff="
     "iif(reps>1, printf('%c%0*d', '"AUTOCOLUMN_SEP"', $1, cpos), '')"
-#else
-    SHELL_COLUMN_RENAME_DML
+#else /* ...RENAME_MINIMAL_ONE_PASS */
+"WITH Lzn(nlz) AS (" /* Find minimum extraneous leading 0's for uniqueness */
+"  SELECT 0 AS nlz"
+"  UNION"
+"  SELECT nlz+1 AS nlz FROM Lzn"
+"  WHERE EXISTS("
+"   SELECT 1"
+"   FROM ColNames t, ColNames o"
+"   WHERE"
+"    iif(t.name IN (SELECT * FROM RepeatedNames),"
+"     printf('%s"AUTOCOLUMN_SEP"%s',"
+"      t.name, substring(printf('%.*c%0.*d',nlz+1,'0',$1,t.cpos),2)),"
+"     t.name"
+"    )"
+"    ="
+"    iif(o.name IN (SELECT * FROM RepeatedNames),"
+"     printf('%s"AUTOCOLUMN_SEP"%s',"
+"      o.name, substring(printf('%.*c%0.*d',nlz+1,'0',$1,o.cpos),2)),"
+"     o.name"
+"    )"
+"    COLLATE NOCASE"
+"    AND o.cpos<>t.cpos"
+"   GROUP BY t.cpos"
+"  )"
+") UPDATE Colnames AS t SET"
+" chop = 0," /* No chopping, never touch incoming names. */
+" suff = iif(name IN (SELECT * FROM RepeatedNames),"
+"  printf('"AUTOCOLUMN_SEP"%s', substring("
+"   printf('%.*c%0.*d',(SELECT max(nlz) FROM Lzn)+1,'0',1,t.cpos),2)),"
+"  ''"
+" )"
 #endif
     ;
   static const char * const zCollectVar = "\
@@ -7916,7 +7953,12 @@ FROM (\
  SELECT cpos, printf('\"%w\"',printf('%.*s%s', nlen-chop,name,suff)) AS cname \
  FROM ColNames ORDER BY cpos\
 )";
-
+  static const char * const zRenamesDone =
+    "SELECT group_concat("
+    " printf('\"%w\" to \"%w\"',name,printf('%.*s%s', nlen-chop, name, suff)),"
+    " ','||x'0a')"
+    "FROM ColNames WHERE suff<>'' OR chop!=0"
+    ;
   int rc;
   sqlite3_stmt *pStmt = 0;
   assert(pDb!=0);
@@ -7926,7 +7968,8 @@ FROM (\
       if( SQLITE_OK!=sqlite3_open(zCOL_DB, pDb) ) return 0;
 #ifdef SHELL_COLFIX_DB
       if(*zCOL_DB!=':')
-        sqlite3_exec(*pDb,"drop table if exists ColNames",0,0,0);
+        sqlite3_exec(*pDb,"drop table if exists ColNames;"
+                     "drop view if exists RepeatedNames;",0,0,0);
 #endif
       rc = sqlite3_exec(*pDb, zTabMake, 0, 0, 0);
       rc_err_oom_die(rc);
@@ -7952,8 +7995,10 @@ FROM (\
 # define nDigits 2
 #endif
     if( hasDupes ){
+#ifdef SHELL_COLUMN_RENAME_CLEAN
       rc = sqlite3_exec(*pDb, zDedoctor, 0, 0, 0);
       rc_err_oom_die(rc);
+#endif
       rc = sqlite3_exec(*pDb, zSetReps, 0, 0, 0);
       rc_err_oom_die(rc);
       rc = sqlite3_prepare_v2(*pDb, zRenameRank, -1, &pStmt, 0);
@@ -7972,7 +8017,17 @@ FROM (\
     }else{
       zColsSpec = 0;
     }
-    if( pRenamed!=0 ) *pRenamed = hasDupes;
+    if( pzRenamed!=0 ){
+      if( !hasDupes ) *pzRenamed = 0;
+      else{
+        sqlite3_finalize(pStmt);
+        if( SQLITE_OK==sqlite3_prepare_v2(*pDb, zRenamesDone, -1, &pStmt, 0)
+            && SQLITE_ROW==sqlite3_step(pStmt) ){
+          *pzRenamed = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 0));
+        }else
+          *pzRenamed = 0;
+      }
+    }
     sqlite3_finalize(pStmt);
     sqlite3_close(*pDb);
     *pDb = 0;
@@ -8929,17 +8984,18 @@ static int do_meta_command(char *zLine, ShellState *p){
       char *zCreate = sqlite3_mprintf("CREATE TABLE \"%w\".\"%w\"",
                                       zSchema, zTable);
       sqlite3 *dbCols = 0;
-      int renamed = 0;
+      char *zRenames = 0;
       char *zColDefs;
       while( xRead(&sCtx) ){
         zAutoColumn(sCtx.z, &dbCols, 0);
         if( sCtx.cTerm!=sCtx.cColSep ) break;
       }
-      zColDefs = zAutoColumn(0, &dbCols, &renamed);
-      if( renamed!=0 ){
+      zColDefs = zAutoColumn(0, &dbCols, &zRenames);
+      if( zRenames!=0 ){
         utf8_printf((stdin_is_interactive && p->in==stdin)? p->out : stderr,
-                    "Columns renamed during .import %s due to duplicates.\n",
-                    sCtx.zFile);
+                    "Columns renamed during .import %s due to duplicates:\n"
+                    "%s\n", sCtx.zFile, zRenames);
+        sqlite3_free(zRenames);
       }
       assert(dbCols==0);
       if( zColDefs==0 ){
index 55fce187fa22d8360246acb90960d52f7fc3e708..7599edbbe2e24a0962830d9661d02e6395989ca2 100755 (executable)
@@ -484,20 +484,26 @@ CREATE TABLE t8(a, b, c);
 do_test shell5-5.1 {
   set out [open shell5.csv w]
   fconfigure $out -translation lf
-  puts $out {"","x","x","y","z","z_0"}
-  puts $out {0,"ex2","ex3","wye4","zee5","zee6"}
+  puts $out {"","x","x","y","z","z_0","z_5","z"}
+  puts $out {0,"x2","x3","y4","z5","z6","z7","z8"}
   close $out
   forcedelete test.db
   catchcmd test.db {.import -csv shell5.csv t1
 .mode line
 SELECT * FROM t1;}
 } {1 {    ? = 0
-  x_2 = ex2
-  x_3 = ex3
-    y = wye4
-  z_5 = zee5
-  z_6 = zee6
-Columns renamed during .import shell5.csv due to duplicates.}}
+ x_02 = x2
+ x_03 = x3
+    y = y4
+ z_05 = z5
+  z_0 = z6
+  z_5 = z7
+ z_08 = z8
+Columns renamed during .import shell5.csv due to duplicates:
+"x" to "x_02",
+"x" to "x_03",
+"z" to "z_05",
+"z" to "z_08"}}
 
 do_test shell5-5.1 {
   set out [open shell5.csv w]
@@ -513,6 +519,10 @@ SELECT * FROM t1;}
 cow_2 = lll
 CoW_3 = ulu
 cOw_4 = lul
-Columns renamed during .import shell5.csv due to duplicates.}}
+Columns renamed during .import shell5.csv due to duplicates:
+"COW" to "COW_1",
+"cow" to "cow_2",
+"CoW" to "CoW_3",
+"cOw" to "cOw_4"}}
 
 finish_test