Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Difference From 066febe8931c5d90 To 2da1f8e45eb0cb1e
2022-02-11
| ||
13:40 | Upon .import column renaming, issue message saying so. Test this. (check-in: 8b6ca9304b user: larrybr tags: auto-column) | |
01:21 | CLI auto-column rename revamped after forum discussion. (check-in: 2da1f8e45e user: larrybr tags: auto-column) | |
2022-02-10
| ||
03:21 | A CLI feature. auto .import (new table) columns. WIP (check-in: 7e3be36dfc user: larrybr tags: auto-column) | |
02:09 | Create new branch named "auto-column" (check-in: 066febe893 user: larrybr tags: auto-column) | |
01:01 | Fix a typo in documentation. No code changes. (check-in: e97c6ad4c9 user: drh tags: trunk) | |
Changes to src/shell.c.in.
︙ | ︙ | |||
5747 5748 5749 5750 5751 5752 5753 | p->outfile[0] = 0; p->out = stdout; } /* ** Run an SQL command and return the single integer result. */ | | | | 5747 5748 5749 5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 5761 5762 5763 5764 | p->outfile[0] = 0; p->out = stdout; } /* ** Run an SQL command and return the single integer result. */ static int db_int(sqlite3 *db, const char *zSql){ sqlite3_stmt *pStmt; int res = 0; sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){ res = sqlite3_column_int(pStmt,0); } sqlite3_finalize(pStmt); return res; } |
︙ | ︙ | |||
5855 5856 5857 5858 5859 5860 5861 | }else if( strcmp(zDb,"temp")==0 ){ zSchemaTab = sqlite3_mprintf("%s", "sqlite_temp_schema"); }else{ zSchemaTab = sqlite3_mprintf("\"%w\".sqlite_schema", zDb); } for(i=0; i<ArraySize(aQuery); i++){ char *zSql = sqlite3_mprintf(aQuery[i].zSql, zSchemaTab); | | | 5855 5856 5857 5858 5859 5860 5861 5862 5863 5864 5865 5866 5867 5868 5869 | }else if( strcmp(zDb,"temp")==0 ){ zSchemaTab = sqlite3_mprintf("%s", "sqlite_temp_schema"); }else{ zSchemaTab = sqlite3_mprintf("\"%w\".sqlite_schema", zDb); } for(i=0; i<ArraySize(aQuery); i++){ char *zSql = sqlite3_mprintf(aQuery[i].zSql, zSchemaTab); int val = db_int(p->db, zSql); sqlite3_free(zSql); utf8_printf(p->out, "%-20s %d\n", aQuery[i].zName, val); } sqlite3_free(zSchemaTab); sqlite3_file_control(p->db, zDb, SQLITE_FCNTL_DATA_VERSION, &iDataVersion); utf8_printf(p->out, "%-20s %u\n", "data version", iDataVersion); return 0; |
︙ | ︙ | |||
7218 7219 7220 7221 7222 7223 7224 7225 7226 7227 7228 7229 7230 7231 | va_end(ap); if( z==0 ){ *pRc = SQLITE_NOMEM; } } return z; } /* ** When running the ".recover" command, each output table, and the special ** orphaned row table if it is required, is represented by an instance ** of the following struct. */ typedef struct RecoverTable RecoverTable; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 7218 7219 7220 7221 7222 7223 7224 7225 7226 7227 7228 7229 7230 7231 7232 7233 7234 7235 7236 7237 7238 7239 7240 7241 7242 7243 7244 7245 7246 7247 7248 7249 7250 7251 7252 7253 7254 7255 7256 7257 7258 7259 7260 7261 7262 7263 7264 7265 7266 7267 7268 7269 7270 7271 7272 7273 7274 7275 7276 7277 7278 7279 7280 7281 7282 7283 7284 7285 7286 7287 7288 7289 7290 7291 7292 7293 7294 7295 7296 7297 7298 7299 7300 7301 7302 7303 7304 7305 7306 7307 7308 7309 7310 7311 7312 7313 7314 7315 7316 7317 7318 7319 7320 7321 7322 7323 7324 7325 7326 7327 7328 7329 7330 7331 7332 7333 7334 7335 7336 7337 7338 7339 7340 7341 7342 7343 7344 7345 7346 7347 7348 7349 7350 7351 7352 7353 7354 7355 7356 7357 7358 7359 7360 7361 7362 7363 7364 7365 7366 7367 7368 7369 7370 7371 7372 7373 7374 7375 7376 7377 7378 7379 7380 7381 7382 7383 7384 7385 7386 7387 7388 7389 | va_end(ap); if( z==0 ){ *pRc = SQLITE_NOMEM; } } 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.) */ #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 static char *zAutoColumn(const char *zColNew, sqlite3 **pDb){ /* 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 nc<length(name) and substring(name, nc, 1)='_'\ )\ UNION ALL\ SELECT cpos, name, chop+1 AS chop, nlen \ FROM chopping \ WHERE instr('_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), '')\ "; 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; } 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 ** of the following struct. */ typedef struct RecoverTable RecoverTable; |
︙ | ︙ | |||
8763 8764 8765 8766 8767 8768 8769 | } nByte = strlen30(zSql); rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); import_append_char(&sCtx, 0); /* To ensure sCtx.z is allocated */ if( rc && sqlite3_strglob("no such table: *", sqlite3_errmsg(p->db))==0 ){ char *zCreate = sqlite3_mprintf("CREATE TABLE \"%w\".\"%w\"", zSchema, zTable); | > | | < > > | | | 8921 8922 8923 8924 8925 8926 8927 8928 8929 8930 8931 8932 8933 8934 8935 8936 8937 8938 8939 8940 8941 8942 8943 8944 8945 8946 8947 8948 8949 8950 | } nByte = strlen30(zSql); rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); import_append_char(&sCtx, 0); /* To ensure sCtx.z is allocated */ if( rc && sqlite3_strglob("no such table: *", sqlite3_errmsg(p->db))==0 ){ char *zCreate = sqlite3_mprintf("CREATE TABLE \"%w\".\"%w\"", zSchema, zTable); sqlite3 *dbCols = 0; char *zColDefs; while( xRead(&sCtx) ){ zAutoColumn(sCtx.z, &dbCols); if( sCtx.cTerm!=sCtx.cColSep ) break; } zColDefs = zAutoColumn(0, &dbCols); assert(dbCols==0); if( zColDefs==0 ){ sqlite3_free(zCreate); import_cleanup(&sCtx); utf8_printf(stderr,"%s: empty file\n", sCtx.zFile); rc = 1; goto meta_command_exit; } zCreate = sqlite3_mprintf("%z%z\n", zCreate, zColDefs); if( eVerbose>=1 ){ utf8_printf(p->out, "%s\n", zCreate); } rc = sqlite3_exec(p->db, zCreate, 0, 0, 0); if( rc ){ utf8_printf(stderr, "%s failed:\n%s\n", zCreate, sqlite3_errmsg(p->db)); sqlite3_free(zCreate); |
︙ | ︙ |
Changes to test/shell1.test.
︙ | ︙ | |||
589 590 591 592 593 594 595 | } catchcmd "test.db" ".schema" } {0 {CREATE TABLE t1(x); CREATE VIEW v2 AS SELECT x+1 AS y FROM t1 /* v2(y) */; CREATE VIEW v1 AS SELECT y+1 FROM v2 /* v1("y+1") */;}} | > | | 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 | } catchcmd "test.db" ".schema" } {0 {CREATE TABLE t1(x); CREATE VIEW v2 AS SELECT x+1 AS y FROM t1 /* v2(y) */; CREATE VIEW v1 AS SELECT y+1 FROM v2 /* v1("y+1") */;}} catch {db eval {DROP VIEW v1; DROP VIEW v2; DROP TABLE t1;}} } # .separator STRING Change column separator used by output and .import do_test shell1-3.22.1 { catchcmd "test.db" ".separator" } {1 {Usage: .separator COL ?ROW?}} do_test shell1-3.22.2 { |
︙ | ︙ |