- C Upon\s.import\scolumn\srenaming,\sissue\smessage\ssaying\sso.\sTest\sthis.
- D 2022-02-11T13:40:25.959
-C Fix\sa\stest\sin\swithout_rowid1.test\sso\sthat\sit\sis\sdisabled\swithout\nALTER\sTABLE\ssupport,\sas\sit\suses\sALTER\sTABLE.
-D 2022-02-11T21:20:46.962
++C Sync\sw/trunk,\sallow\sbuild-time\soverride\sof\sauto-column\sdecorating\scharacter
++D 2022-02-12T02:15:37.064
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
F src/resolve.c ea935b87d6fb36c78b70cdc7b28561dc8f33f2ef37048389549c7b5ef9b0ba5e
F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
F src/select.c 3baa9dd8cf240654773c7974e2bcce398ac9dd24419c36684156963defe43b35
- F src/shell.c.in 4368f3d2a0e7866ed86c2877a4d839b8eb9b855142677b26356bb0003b656ef8
-F src/shell.c.in b800bf8e02d9b4fd97078b68ca4371048f7196fc63accaa99c3c5943f72c80a0
++F src/shell.c.in 910aa363580f8e75c9d62c03baef2dcec25d077b9f04dacfe61df33f85b0107d
F src/sqlite.h.in 7047c4b60fa550264d6363bb1d983540e7828fb19d2d1e5aa43b52ca13144807
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h a95cb9ed106e3d39e2118e4dcc15a14faec3fa50d0093425083d340d9dfd96e6
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
- P 2da1f8e45eb0cb1ead6049df6a31a903bfad5a7abd27e92cd3dac25fe355aec3
- R 3c587522ab1009a0f304c6f4fc9291c2
-P 3409fd4150df059d7308f79fa3672a330af9cefe2ad9120c3da5ef1413921e96
-R 11d69b7df4beb804da28e670c98327ec
-U drh
-Z 9996eb8f83b13066aef559fa4b83d323
++P 8b6ca9304bff9a5b2897a6517ce77e4cd32f337b6c849b73ead5f757228d8ac8 ca22a64e6f05a6688974f4cff1a0ff2c873aad1947f3cf6ffaeee8bb074b2627
++R f2657b8c4f3b23824e6168670f3c28c6
+U larrybr
- Z 6eda7b7abac4cc7637f7063a4d303de3
++Z 72b6123e2f6f8261fe59a92cab260c52
# Remove this line to create a well-formed Fossil manifest.
** If SQLITE_CUSTOM_INCLUDE=? is defined, its value names the #include
** file. Note that this macro has a like effect on sqlite3.c compilation.
*/
++# define SHELL_STRINGIFY_(f) #f
++# define SHELL_STRINGIFY(f) SHELL_STRINGIFY_(f)
#ifdef SQLITE_CUSTOM_INCLUDE
--# define INC_STRINGIFY_(f) #f
--# define INC_STRINGIFY(f) INC_STRINGIFY_(f)
--# include INC_STRINGIFY(SQLITE_CUSTOM_INCLUDE)
++# include SHELL_STRINGIFY(SQLITE_CUSTOM_INCLUDE)
#endif
/*
return z;
}
- WHERE nc<length(name) and substring(name, nc, 1)='_'\
+
+/*
+ * zAutoColumn(zCol, &db, ?) => Maybe init db, add column zCol to it.
+ * zAutoColumn(0, &db, ?) => (db!=0) Form columns spec for CREATE TABLE,
+ * close db and set it to 0, and return the columns spec, to later
+ * be sqlite3_free()'ed by the caller.
+ * The return is 0 when either:
+ * (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.
+ */
+#ifdef SHELL_DEBUG
+#define rc_err_oom_die(rc) \
+ if( rc==SQLITE_NOMEM ) shell_check_oom(0); \
+ else if(!(rc==SQLITE_OK||rc==SQLITE_DONE)) \
+ fprintf(stderr,"E:%d\n",rc), assert(0)
+#else
+static void rc_err_oom_die(int rc){
+ if( rc==SQLITE_NOMEM ) shell_check_oom(0);
+ assert(rc==SQLITE_OK||rc==SQLITE_DONE);
+}
+#endif
+
+#ifdef SHELL_COLFIX_DB /* If this is set, the DB can be in a file. */
+static char zCOL_DB[] = SHELL_COLFIX_DB;
+#else /* Otherwise, memory is faster/better for the transient DB. */
+static const char *zCOL_DB = ":memory:";
+#endif
+
++/* Define character (as C string) to separate generated column ordinal
++ * from protected part of incoming column names. This defaults to "_"
++ * so that incoming column identifiers that did not need not be quoted
++ * remain usable without being quoted. It must be one character.
++ */
++#ifndef SHELL_AUTOCOLUMN_SEP
++# define AUTOCOLUMN_SEP "_"
++#else
++# define AUTOCOLUMN_SEP SHELL_STRINGIFY(SHELL_AUTOCOLUMN_SEP)
++#endif
++
+static char *zAutoColumn(const char *zColNew, sqlite3 **pDb, int *pRenamed){
+ /* 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)\
+";
+ static const char const *zTabFill = "\
+INSERT INTO ColNames(name,nlen,chop,reps,suff)\
+ VALUES(iif(length(?1)>0,?1,'?'),max(length(?1),1),0,0,'')\
+";
+ static const char const *zHasDupes = "\
+SELECT count(DISTINCT substring(name,1,nlen-chop)||suff)\
+ <count(name) FROM ColNames\
+";
+ static const char const *zDedoctor = "\
+WITH chopped AS ( \
+ WITH RECURSIVE chopping(cpos, name, chop, nlen) AS ( \
+ SELECT cpos, name, 0, nlen FROM ColNames \
+ WHERE cpos IN ( \
+ WITH RECURSIVE choppable(nc, name, cpos) AS \
+ (SELECT nlen AS nc, name, cpos \
+ FROM ColNames \
+ UNION ALL \
+ SELECT nc-1 AS nc, name, cpos \
+ FROM choppable \
+ WHERE substring(name, nc, 1) BETWEEN '0' AND '9'\
+ ) SELECT cpos /*name*/ FROM choppable \
- WHERE instr('_0123456789', substring(name, nlen-chop, 1))>0 \
++ WHERE nc<length(name) and \
++ substring(name, nc, 1)='"AUTOCOLUMN_SEP"'\
+ )\
+ UNION ALL\
+ SELECT cpos, name, chop+1 AS chop, nlen \
+ FROM chopping \
- UPDATE ColNames AS t SET suff=iif(reps>1, printf('_%0*d', $1, cpos), '')\
++ WHERE \
++ instr('"AUTOCOLUMN_SEP"0123456789', substring(name, nlen-chop, 1))>0 \
+ )\
+ SELECT cpos, name, max(chop) AS chop FROM chopping s \
+ GROUP BY cpos \
+) UPDATE ColNames AS c \
+ SET chop=n.chop FROM chopped n WHERE c.cpos=n.cpos \
+";
+ static const char const *zSetReps = "\
+UPDATE ColNames AS t SET reps=\
+(SELECT count(*) FROM ColNames d \
+ WHERE substring(t.name,1,t.nlen-t.chop)=substring(d.name,1,d.nlen-d.chop)\
+)\
+";
+#ifdef SQLITE_ENABLE_MATH_FUNCTIONS
+ static const char const *zColDigits = "\
+SELECT CAST(ceil(log(count(*)+0.5)) AS INT) FROM ColNames \
+";
+#endif
+ static const char const *zRenameRank = "\
++UPDATE ColNames AS t SET \
++ suff=iif(reps>1, printf('"AUTOCOLUMN_SEP"%0*d', $1, cpos), '')\
+";
+ static const char const *zCollectVar = "\
+SELECT\
+ '('||\
+ group_concat(\
+ cname||' TEXT',\
+ ','||iif((cpos-1)%4>0, ' ', x'0a'||' '))\
+ ||')' AS ColsSpec \
+FROM (\
+ SELECT cpos, printf('\"%w\"',printf('%.*s%s', nlen-chop,name,suff)) AS cname \
+ FROM ColNames ORDER BY cpos\
+)";
+
+ int rc;
+ sqlite3_stmt *pStmt = 0;
+ assert(pDb!=0);
+ if( zColNew ){
+ /* Add initial or additional column. Init db if necessary. */
+ if( *pDb==0 ){
+ 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);
+#endif
+ rc = sqlite3_exec(*pDb, zTabMake, 0, 0, 0);
+ rc_err_oom_die(rc);
+ }
+ assert(*pDb!=0);
+ rc = sqlite3_prepare_v2(*pDb, zTabFill, -1, &pStmt, 0);
+ rc_err_oom_die(rc);
+ rc = sqlite3_bind_text(pStmt, 1, zColNew, -1, 0);
+ rc_err_oom_die(rc);
+ rc = sqlite3_step(pStmt);
+ rc_err_oom_die(rc);
+ sqlite3_finalize(pStmt);
+ return 0;
+ }else if( *pDb==0 ){
+ return 0;
+ }else{
+ /* Formulate the columns spec, close the DB, zero *pDb. */
+ char *zColsSpec = 0;
+ int hasDupes = db_int(*pDb, zHasDupes);
+#ifdef SQLITE_ENABLE_MATH_FUNCTIONS
+ int nDigits = (hasDupes)? db_int(*pDb, zColDigits) : 0;
+#else
+# define nDigits 2
+#endif
+ if( hasDupes ){
+ rc = sqlite3_exec(*pDb, zDedoctor, 0, 0, 0);
+ rc_err_oom_die(rc);
+ rc = sqlite3_exec(*pDb, zSetReps, 0, 0, 0);
+ rc_err_oom_die(rc);
+ rc = sqlite3_prepare_v2(*pDb, zRenameRank, -1, &pStmt, 0);
+ rc_err_oom_die(rc);
+ rc = sqlite3_bind_int(pStmt, 1, nDigits);
+ rc_err_oom_die(rc);
+ rc = sqlite3_step(pStmt);
+ sqlite3_finalize(pStmt);
+ assert(rc==SQLITE_DONE);
+ }
+ assert(db_int(*pDb, zHasDupes)==0); /* Consider: remove this */
+ rc = sqlite3_prepare_v2(*pDb, zCollectVar, -1, &pStmt, 0);
+ rc_err_oom_die(rc);
+ rc = sqlite3_step(pStmt);
+ if( rc==SQLITE_ROW ){
+ zColsSpec = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 0));
+ }else{
+ zColsSpec = 0;
+ }
+ if( pRenamed!=0 ) *pRenamed = hasDupes;
+ sqlite3_finalize(pStmt);
+ sqlite3_close(*pDb);
+ *pDb = 0;
+ return zColsSpec;
+ }
+}
+
+
/*
** When running the ".recover" command, each output table, and the special
** orphaned row table if it is required, is represented by an instance