diff --git a/manifest b/manifest index c8b221ba39..057eff3777 100644 --- 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. diff --git a/manifest.uuid b/manifest.uuid index 505f134e8f..3fdeeb0533 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -67dc59f46d742ad69742fb34540a3074af163a3f1a0f9093f83db2276bf944ca \ No newline at end of file +c626cff7f99ec502ebd46f9cdafc3d088697544ef5d6559b6b3ae85679b4f9fa \ No newline at end of file diff --git a/src/shell.c.in b/src/shell.c.in index 66428b72b6..dba42e817f 100755 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -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)\ 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 ){ diff --git a/test/shell5.test b/test/shell5.test index 55fce187fa..7599edbbe2 100755 --- a/test/shell5.test +++ b/test/shell5.test @@ -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