Index: src/shell.c.in ================================================================== --- src/shell.c.in +++ src/shell.c.in @@ -5749,14 +5749,14 @@ } /* ** Run an SQL command and return the single integer result. */ -static int db_int(ShellState *p, const char *zSql){ +static int db_int(sqlite3 *db, const char *zSql){ sqlite3_stmt *pStmt; int res = 0; - sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 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; @@ -5857,11 +5857,11 @@ }else{ zSchemaTab = sqlite3_mprintf("\"%w\".sqlite_schema", zDb); } for(i=0; idb, 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); @@ -7220,10 +7220,168 @@ *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)\ + 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); - char cSep = '('; + sqlite3 *dbCols = 0; + char *zColDefs; while( xRead(&sCtx) ){ - zCreate = sqlite3_mprintf("%z%c\n \"%w\" TEXT", zCreate, cSep, sCtx.z); - cSep = ','; + zAutoColumn(sCtx.z, &dbCols); if( sCtx.cTerm!=sCtx.cColSep ) break; } - if( cSep=='(' ){ + 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\n)", zCreate); + 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 ){ Index: test/shell1.test ================================================================== --- test/shell1.test +++ test/shell1.test @@ -591,11 +591,12 @@ } {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") */;}} -db eval {DROP VIEW v1; DROP VIEW v2; DROP TABLE t1;} + + 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"