Index: src/shell.c ================================================================== --- src/shell.c +++ src/shell.c @@ -1993,22 +1993,22 @@ } }else if( c=='i' && strncmp(azArg[0], "import", n)==0 && nArg==3 ){ char *zTable = azArg[2]; /* Insert data into this table */ + char *zFile = azArg[1]; /* Name of file to extra content from */ sqlite3_stmt *pStmt = NULL; /* A statement */ int nCol; /* Number of columns in the table */ int nByte; /* Number of bytes in an SQL string */ int i, j; /* Loop counters */ int nSep; /* Number of bytes in p->separator[] */ char *zSql; /* An SQL statement */ CSVReader sCsv; /* Reader context */ + int (*xCloser)(FILE*); /* Procedure to close th3 connection */ seenInterrupt = 0; memset(&sCsv, 0, sizeof(sCsv)); - sCsv.zFile = azArg[1]; - sCsv.nLine = 1; open_db(p); nSep = strlen30(p->separator); if( nSep==0 ){ fprintf(stderr, "Error: non-null separator required for import\n"); return 1; @@ -2016,20 +2016,29 @@ if( nSep>1 ){ fprintf(stderr, "Error: multi-character separators not allowed" " for import\n"); return 1; } - sCsv.in = fopen(sCsv.zFile, "rb"); + sCsv.zFile = zFile; + sCsv.nLine = 1; + if( sCsv.zFile[0]=='|' ){ + sCsv.in = popen(sCsv.zFile+1, "r"); + sCsv.zFile = ""; + xCloser = pclose; + }else{ + sCsv.in = fopen(sCsv.zFile, "rb"); + xCloser = fclose; + } if( sCsv.in==0 ){ - fprintf(stderr, "Error: cannot open \"%s\"\n", sCsv.zFile); + fprintf(stderr, "Error: cannot open \"%s\"\n", zFile); return 1; } sCsv.cSeparator = p->separator[0]; zSql = sqlite3_mprintf("SELECT * FROM %s", zTable); if( zSql==0 ){ fprintf(stderr, "Error: out of memory\n"); - fclose(sCsv.in); + xCloser(sCsv.in); return 1; } nByte = strlen30(zSql); rc = sqlite3_prepare(p->db, zSql, -1, &pStmt, 0); if( rc && sqlite3_strglob("no such table: *", sqlite3_errmsg(db))==0 ){ @@ -2037,38 +2046,45 @@ char cSep = '('; while( csv_read_one_field(&sCsv) ){ zCreate = sqlite3_mprintf("%z%c\n \"%s\" TEXT", zCreate, cSep, sCsv.z); cSep = ','; if( sCsv.cTerm!=sCsv.cSeparator ) break; + } + if( cSep=='(' ){ + sqlite3_free(zCreate); + sqlite3_free(sCsv.z); + xCloser(sCsv.in); + fprintf(stderr,"%s: empty file\n", sCsv.zFile); + return 1; } zCreate = sqlite3_mprintf("%z\n)", zCreate); rc = sqlite3_exec(p->db, zCreate, 0, 0, 0); sqlite3_free(zCreate); if( rc ){ fprintf(stderr, "CREATE TABLE %s(...) failed: %s\n", zTable, sqlite3_errmsg(db)); sqlite3_free(sCsv.z); - fclose(sCsv.in); + xCloser(sCsv.in); return 1; } rc = sqlite3_prepare(p->db, zSql, -1, &pStmt, 0); } sqlite3_free(zSql); if( rc ){ if (pStmt) sqlite3_finalize(pStmt); fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db)); - fclose(sCsv.in); + xCloser(sCsv.in); return 1; } nCol = sqlite3_column_count(pStmt); sqlite3_finalize(pStmt); pStmt = 0; if( nCol==0 ) return 0; /* no columns, no error */ zSql = sqlite3_malloc( nByte*2 + 20 + nCol*2 ); if( zSql==0 ){ fprintf(stderr, "Error: out of memory\n"); - fclose(sCsv.in); + xCloser(sCsv.in); return 1; } sqlite3_snprintf(nByte+20, zSql, "INSERT INTO \"%w\" VALUES(?", zTable); j = strlen30(zSql); for(i=1; idb, zSql, -1, &pStmt, 0); sqlite3_free(zSql); if( rc ){ fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db)); if (pStmt) sqlite3_finalize(pStmt); - fclose(sCsv.in); + xCloser(sCsv.in); return 1; } do{ int startLine = sCsv.nLine; for(i=0; idb, "COMMIT", 0, 0, 0); }else Index: test/shell5.test ================================================================== --- test/shell5.test +++ test/shell5.test @@ -213,11 +213,11 @@ set res [catchcmd "test.db" {.import shell5.csv t2 SELECT COUNT(*) FROM t2;}] } {0 1} # try importing a large number of rows -set rows 99999 +set rows 9999 do_test shell5-1.7.1 { set in [open shell5.csv w] puts $in a for {set i 1} {$i<=$rows} {incr i} { puts $in $i @@ -225,7 +225,21 @@ close $in set res [catchcmd "test.db" {.mode csv .import shell5.csv t3 SELECT COUNT(*) FROM t3;}] } [list 0 $rows] + +# Inport from a pipe. (Unix only, as it requires "awk") +if {$tcl_platform(platform)=="unix"} { + do_test shell5-1.8 { + file delete -force test.db + catchcmd test.db {.mode csv +.import "|awk 'END{print \"x,y\";for(i=1;i<=5;i++){print i \",this is \" i}}'" t1 +SELECT * FROM t1;} + } {0 {1,"this is 1" +2,"this is 2" +3,"this is 3" +4,"this is 4" +5,"this is 5"}} +} finish_test