From: larrybr Date: Sat, 12 Feb 2022 02:15:37 +0000 (+0000) Subject: Sync w/trunk, allow build-time override of auto-column decorating character X-Git-Tag: version-3.38.0~15^2~4 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=78138397b5c4e6c2cfbf9a9a37baf741725cead7;p=thirdparty%2Fsqlite.git Sync w/trunk, allow build-time override of auto-column decorating character FossilOrigin-Name: caaef4c592c980889efb349fa73b61303ec493172d90cd67d54ffde0855e4138 --- 78138397b5c4e6c2cfbf9a9a37baf741725cead7 diff --cc manifest index 855f924c60,903db79b3e..505325b6ec --- a/manifest +++ b/manifest @@@ -1,5 -1,5 +1,5 @@@ - 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 @@@ -553,7 -553,7 +553,7 @@@ F src/random.c 097dc8b31b8fba5a9aca1697 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 @@@ -1944,8 -1944,8 +1944,8 @@@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a9 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. diff --cc manifest.uuid index 3b9c4fbbf2,476053a91b..1a92c95aa0 --- a/manifest.uuid +++ b/manifest.uuid @@@ -1,1 -1,1 +1,1 @@@ - 8b6ca9304bff9a5b2897a6517ce77e4cd32f337b6c849b73ead5f757228d8ac8 -ca22a64e6f05a6688974f4cff1a0ff2c873aad1947f3cf6ffaeee8bb074b2627 ++caaef4c592c980889efb349fa73b61303ec493172d90cd67d54ffde0855e4138 diff --cc src/shell.c.in index 6bd271c206,35e99989f5..65b842db9a --- a/src/shell.c.in +++ b/src/shell.c.in @@@ -23,10 -23,10 +23,10 @@@ ** 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 /* @@@ -7223,168 -7223,6 +7223,182 @@@ static char *shellMPrintf(int *pRc, con return z; } + +/* + * 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)\ + 0 \ ++ 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('_%0*d', $1, cpos), '')\ ++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