From 06d1c149c7709b4e4e09ae72fc14c0b4bae32c84 Mon Sep 17 00:00:00 2001 From: Mark Brand Date: Wed, 13 Nov 2013 11:38:18 +0100 Subject: update bundled sqlite to 3.8.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Id75bf901c9014419eddbe2d0e5a75ee274b17914 Reviewed-by: Friedemann Kleint Reviewed-by: Konstantin Ritt Reviewed-by: Fatih Aşıcı Reviewed-by: Mark Brand --- src/3rdparty/sqlite/shell.c | 547 +++++++++++++++++++++++++++++--------------- 1 file changed, 357 insertions(+), 190 deletions(-) (limited to 'src/3rdparty/sqlite/shell.c') diff --git a/src/3rdparty/sqlite/shell.c b/src/3rdparty/sqlite/shell.c index 1be2871fed..41ea56492e 100644 --- a/src/3rdparty/sqlite/shell.c +++ b/src/3rdparty/sqlite/shell.c @@ -53,7 +53,6 @@ # include #endif #if !defined(HAVE_EDITLINE) && (!defined(HAVE_READLINE) || HAVE_READLINE!=1) -# define readline(p) local_getline(p,stdin,0) # define add_history(X) # define read_history(X) # define write_history(X) @@ -65,13 +64,18 @@ #define isatty(h) _isatty(h) #define access(f,m) _access((f),(m)) #undef popen -#define popen(a,b) _popen((a),(b)) +#define popen _popen #undef pclose -#define pclose(x) _pclose(x) +#define pclose _pclose #else /* Make sure isatty() has a prototype. */ extern int isatty(int); + +/* popen and pclose are not C89 functions and so are sometimes omitted from +** the header */ +extern FILE *popen(const char*,const char*); +extern int pclose(FILE*); #endif #if defined(_WIN32_WCE) @@ -332,23 +336,13 @@ static void shellstaticFunc( ** to the text. NULL is returned at end of file, or if malloc() ** fails. ** -** The interface is like "readline" but no command-line editing -** is done. +** If zLine is not NULL then it is a malloced buffer returned from +** a previous call to this routine that may be reused. */ -static char *local_getline(char *zPrompt, FILE *in, int csvFlag){ - char *zLine; - int nLine; - int n; - int inQuote = 0; +static char *local_getline(char *zLine, FILE *in){ + int nLine = zLine==0 ? 0 : 100; + int n = 0; - if( zPrompt && *zPrompt ){ - printf("%s",zPrompt); - fflush(stdout); - } - nLine = 100; - zLine = malloc( nLine ); - if( zLine==0 ) return 0; - n = 0; while( 1 ){ if( n+100>nLine ){ nLine = nLine*2 + 100; @@ -363,42 +357,48 @@ static char *local_getline(char *zPrompt, FILE *in, int csvFlag){ zLine[n] = 0; break; } - while( zLine[n] ){ - if( zLine[n]=='"' ) inQuote = !inQuote; - n++; - } - if( n>0 && zLine[n-1]=='\n' && (!inQuote || !csvFlag) ){ + while( zLine[n] ) n++; + if( n>0 && zLine[n-1]=='\n' ){ n--; if( n>0 && zLine[n-1]=='\r' ) n--; zLine[n] = 0; break; } } - zLine = realloc( zLine, n+1 ); return zLine; } /* ** Retrieve a single line of input text. ** -** zPrior is a string of prior text retrieved. If not the empty -** string, then issue a continuation prompt. +** If in==0 then read from standard input and prompt before each line. +** If isContinuation is true, then a continuation prompt is appropriate. +** If isContinuation is zero, then the main prompt should be used. +** +** If zPrior is not NULL then it is a buffer from a prior call to this +** routine that can be reused. +** +** The result is stored in space obtained from malloc() and must either +** be freed by the caller or else passed back into this routine via the +** zPrior argument for reuse. */ -static char *one_input_line(const char *zPrior, FILE *in){ +static char *one_input_line(FILE *in, char *zPrior, int isContinuation){ char *zPrompt; char *zResult; if( in!=0 ){ - return local_getline(0, in, 0); - } - if( zPrior && zPrior[0] ){ - zPrompt = continuePrompt; + zResult = local_getline(zPrior, in); }else{ - zPrompt = mainPrompt; - } - zResult = readline(zPrompt); + zPrompt = isContinuation ? continuePrompt : mainPrompt; #if defined(HAVE_READLINE) && HAVE_READLINE==1 - if( zResult && *zResult ) add_history(zResult); + free(zPrior); + zResult = readline(zPrompt); + if( zResult && *zResult ) add_history(zResult); +#else + printf("%s", zPrompt); + fflush(stdout); + zResult = local_getline(zPrior, stdin); #endif + } return zResult; } @@ -554,7 +554,7 @@ static void output_c_string(FILE *out, const char *z){ }else if( c=='\r' ){ fputc('\\', out); fputc('r', out); - }else if( !isprint(c) ){ + }else if( !isprint(c&0xff) ){ fprintf(out, "\\%03o", c&0xff); }else{ fputc(c, out); @@ -974,7 +974,7 @@ static int run_table_dump_query( rc = sqlite3_prepare(p->db, zSelect, -1, &pSelect, 0); if( rc!=SQLITE_OK || !pSelect ){ fprintf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db)); - p->nErr++; + if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++; return rc; } rc = sqlite3_step(pSelect); @@ -1001,7 +1001,7 @@ static int run_table_dump_query( rc = sqlite3_finalize(pSelect); if( rc!=SQLITE_OK ){ fprintf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db)); - p->nErr++; + if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++; } return rc; } @@ -1109,6 +1109,8 @@ static int display_stats( fprintf(pArg->out, "Sort Operations: %d\n", iCur); iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_AUTOINDEX, bReset); fprintf(pArg->out, "Autoindex Inserts: %d\n", iCur); + iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_VM_STEP, bReset); + fprintf(pArg->out, "Virtual Machine Steps: %d\n", iCur); } return 0; @@ -1192,7 +1194,7 @@ static int shell_exec( char **azCols = (char **)pData; /* Names of result columns */ char **azVals = &azCols[nCol]; /* Results */ int *aiTypes = (int *)&azVals[nCol]; /* Result types */ - int i; + int i, x; assert(sizeof(int) <= sizeof(char *)); /* save off ptrs to column names */ for(i=0; imode==MODE_Insert ){ + azVals[i] = ""; + }else{ + azVals[i] = (char*)sqlite3_column_text(pStmt, i); + } if( !azVals[i] && (aiTypes[i]!=SQLITE_NULL) ){ rc = SQLITE_NOMEM; break; /* from for */ @@ -1278,7 +1284,7 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){ if( strcmp(zTable, "sqlite_sequence")==0 ){ zPrepStmt = "DELETE FROM sqlite_sequence;\n"; - }else if( strcmp(zTable, "sqlite_stat1")==0 ){ + }else if( sqlite3_strglob("sqlite_stat?", zTable)==0 ){ fprintf(p->out, "ANALYZE sqlite_master;\n"); }else if( strncmp(zTable, "sqlite_", 7)==0 ){ return 0; @@ -1490,6 +1496,7 @@ static void open_db(struct callback_data *p){ ** \t -> tab ** \n -> newline ** \r -> carriage return +** \" -> " ** \NNN -> ascii character NNN in octal ** \\ -> backslash */ @@ -1505,6 +1512,8 @@ static void resolve_backslashes(char *z){ c = '\t'; }else if( c=='r' ){ c = '\r'; + }else if( c=='\\' ){ + c = '\\'; }else if( c>='0' && c<='7' ){ c -= '0'; if( z[i+1]>='0' && z[i+1]<='7' ){ @@ -1523,21 +1532,14 @@ static void resolve_backslashes(char *z){ } /* -** Interpret zArg as a boolean value. Return either 0 or 1. -*/ -static int booleanValue(char *zArg){ - int i; - for(i=0; zArg[i]>='0' && zArg[i]<='9'; i++){} - if( i>0 && zArg[i]==0 ) return atoi(zArg); - if( sqlite3_stricmp(zArg, "on")==0 || sqlite3_stricmp(zArg,"yes")==0 ){ - return 1; - } - if( sqlite3_stricmp(zArg, "off")==0 || sqlite3_stricmp(zArg,"no")==0 ){ - return 0; - } - fprintf(stderr, "ERROR: Not a boolean value: \"%s\". Assuming \"no\".\n", - zArg); - return 0; +** Return the value of a hexadecimal digit. Return -1 if the input +** is not a hex digit. +*/ +static int hexDigitValue(char c){ + if( c>='0' && c<='9' ) return c - '0'; + if( c>='a' && c<='f' ) return c - 'a' + 10; + if( c>='A' && c<='F' ) return c - 'A' + 10; + return -1; } /* @@ -1564,11 +1566,20 @@ static sqlite3_int64 integerValue(const char *zArg){ }else if( zArg[0]=='+' ){ zArg++; } - while( isdigit(zArg[0]) ){ - v = v*10 + zArg[0] - '0'; - zArg++; + if( zArg[0]=='0' && zArg[1]=='x' ){ + int x; + zArg += 2; + while( (x = hexDigitValue(zArg[0]))>=0 ){ + v = (v<<4) + x; + zArg++; + } + }else{ + while( IsDigit(zArg[0]) ){ + v = v*10 + zArg[0] - '0'; + zArg++; + } } - for(i=0; i=0; i++){} + }else{ + for(i=0; zArg[i]>='0' && zArg[i]<='9'; i++){} + } + if( i>0 && zArg[i]==0 ) return (int)(integerValue(zArg) & 0xffffffff); + if( sqlite3_stricmp(zArg, "on")==0 || sqlite3_stricmp(zArg,"yes")==0 ){ + return 1; + } + if( sqlite3_stricmp(zArg, "off")==0 || sqlite3_stricmp(zArg,"no")==0 ){ + return 0; + } + fprintf(stderr, "ERROR: Not a boolean value: \"%s\". Assuming \"no\".\n", + zArg); + return 0; +} + /* ** Close an output file, assuming it is not stderr or stdout */ @@ -1623,6 +1657,105 @@ static void test_breakpoint(void){ nCall++; } +/* +** An object used to read a CSV file +*/ +typedef struct CSVReader CSVReader; +struct CSVReader { + const char *zFile; /* Name of the input file */ + FILE *in; /* Read the CSV text from this input stream */ + char *z; /* Accumulated text for a field */ + int n; /* Number of bytes in z */ + int nAlloc; /* Space allocated for z[] */ + int nLine; /* Current line number */ + int cTerm; /* Character that terminated the most recent field */ + int cSeparator; /* The separator character. (Usually ",") */ +}; + +/* Append a single byte to z[] */ +static void csv_append_char(CSVReader *p, int c){ + if( p->n+1>=p->nAlloc ){ + p->nAlloc += p->nAlloc + 100; + p->z = sqlite3_realloc(p->z, p->nAlloc); + if( p->z==0 ){ + fprintf(stderr, "out of memory\n"); + exit(1); + } + } + p->z[p->n++] = (char)c; +} + +/* Read a single field of CSV text. Compatible with rfc4180 and extended +** with the option of having a separator other than ",". +** +** + Input comes from p->in. +** + Store results in p->z of length p->n. Space to hold p->z comes +** from sqlite3_malloc(). +** + Use p->cSep as the separator. The default is ",". +** + Keep track of the line number in p->nLine. +** + Store the character that terminates the field in p->cTerm. Store +** EOF on end-of-file. +** + Report syntax errors on stderr +*/ +static char *csv_read_one_field(CSVReader *p){ + int c, pc; + int cSep = p->cSeparator; + p->n = 0; + c = fgetc(p->in); + if( c==EOF || seenInterrupt ){ + p->cTerm = EOF; + return 0; + } + if( c=='"' ){ + int startLine = p->nLine; + int cQuote = c; + pc = 0; + while( 1 ){ + c = fgetc(p->in); + if( c=='\n' ) p->nLine++; + if( c==cQuote ){ + if( pc==cQuote ){ + pc = 0; + continue; + } + } + if( (c==cSep && pc==cQuote) + || (c=='\n' && pc==cQuote) + || (c=='\n' && pc=='\r' && p->n>=2 && p->z[p->n-2]==cQuote) + || (c==EOF && pc==cQuote) + ){ + do{ p->n--; }while( p->z[p->n]!=cQuote ); + p->cTerm = c; + break; + } + if( pc==cQuote && c!='\r' ){ + fprintf(stderr, "%s:%d: unescaped %c character\n", + p->zFile, p->nLine, cQuote); + } + if( c==EOF ){ + fprintf(stderr, "%s:%d: unterminated %c-quoted field\n", + p->zFile, startLine, cQuote); + p->cTerm = EOF; + break; + } + csv_append_char(p, c); + pc = c; + } + }else{ + while( c!=EOF && c!=cSep && c!='\n' ){ + csv_append_char(p, c); + c = fgetc(p->in); + } + if( c=='\n' ){ + p->nLine++; + if( p->n>1 && p->z[p->n-1]=='\r' ) p->n--; + } + p->cTerm = c; + } + if( p->z ) p->z[p->n] = 0; + return p->z; +} + /* ** If an input line begins with "." then invoke this routine to ** process that line. @@ -1644,7 +1777,10 @@ static int do_meta_command(char *zLine, struct callback_data *p){ if( zLine[i]=='\'' || zLine[i]=='"' ){ int delim = zLine[i++]; azArg[nArg++] = &zLine[i]; - while( zLine[i] && zLine[i]!=delim ){ i++; } + while( zLine[i] && zLine[i]!=delim ){ + if( zLine[i]=='\\' && delim=='"' && zLine[i+1]!=0 ) i++; + i++; + } if( zLine[i]==delim ){ zLine[i++] = 0; } @@ -1665,7 +1801,6 @@ static int do_meta_command(char *zLine, struct callback_data *p){ if( c=='b' && n>=3 && strncmp(azArg[0], "backup", n)==0 ){ const char *zDestFile = 0; const char *zDb = 0; - const char *zKey = 0; sqlite3 *pDest; sqlite3_backup *pBackup; int j; @@ -1673,9 +1808,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){ const char *z = azArg[j]; if( z[0]=='-' ){ while( z[0]=='-' ) z++; - if( strcmp(z,"key")==0 && jdb, zDb); if( pBackup==0 ){ @@ -1808,7 +1936,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){ }else if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){ - if( nArg>1 && (rc = atoi(azArg[1]))!=0 ) exit(rc); + if( nArg>1 && (rc = (int)integerValue(azArg[1]))!=0 ) exit(rc); rc = 2; }else @@ -1861,48 +1989,98 @@ static int do_meta_command(char *zLine, struct callback_data *p){ if( c=='i' && strncmp(azArg[0], "import", n)==0 && nArg==3 ){ char *zTable = azArg[2]; /* Insert data into this table */ - char *zFile = azArg[1]; /* The file from which to extract data */ + 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 needCommit; /* True to COMMIT or ROLLBACK at end */ int nSep; /* Number of bytes in p->separator[] */ char *zSql; /* An SQL statement */ - char *zLine; /* A single line of input from the file */ - char **azCol; /* zLine[] broken up into columns */ - char *zCommit; /* How to commit changes */ - FILE *in; /* The input file */ - int lineno = 0; /* Line number of input file */ + CSVReader sCsv; /* Reader context */ + int (*xCloser)(FILE*); /* Procedure to close th3 connection */ + seenInterrupt = 0; + memset(&sCsv, 0, sizeof(sCsv)); open_db(p); nSep = strlen30(p->separator); if( nSep==0 ){ fprintf(stderr, "Error: non-null separator required for import\n"); return 1; } + if( nSep>1 ){ + fprintf(stderr, "Error: multi-character separators not allowed" + " for import\n"); + return 1; + } + 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", 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"); + 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 ){ + char *zCreate = sqlite3_mprintf("CREATE TABLE %s", zTable); + 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); + 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)); + 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 = malloc( nByte + 20 + nCol*2 ); + zSql = sqlite3_malloc( nByte*2 + 20 + nCol*2 ); if( zSql==0 ){ fprintf(stderr, "Error: out of memory\n"); + xCloser(sCsv.in); return 1; } - sqlite3_snprintf(nByte+20, zSql, "INSERT INTO %s VALUES(?", zTable); + sqlite3_snprintf(nByte+20, zSql, "INSERT INTO \"%w\" VALUES(?", zTable); j = strlen30(zSql); for(i=1; idb, zSql, -1, &pStmt, 0); - free(zSql); + sqlite3_free(zSql); if( rc ){ fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db)); if (pStmt) sqlite3_finalize(pStmt); + xCloser(sCsv.in); return 1; } - in = fopen(zFile, "rb"); - if( in==0 ){ - fprintf(stderr, "Error: cannot open \"%s\"\n", zFile); - sqlite3_finalize(pStmt); - return 1; - } - azCol = malloc( sizeof(azCol[0])*(nCol+1) ); - if( azCol==0 ){ - fprintf(stderr, "Error: out of memory\n"); - fclose(in); - sqlite3_finalize(pStmt); - return 1; - } - sqlite3_exec(p->db, "BEGIN", 0, 0, 0); - zCommit = "COMMIT"; - while( (zLine = local_getline(0, in, 1))!=0 ){ - char *z, c; - int inQuote = 0; - lineno++; - azCol[0] = zLine; - for(i=0, z=zLine; (c = *z)!=0; z++){ - if( c=='"' ) inQuote = !inQuote; - if( c=='\n' ) lineno++; - if( !inQuote && c==p->separator[0] && strncmp(z,p->separator,nSep)==0 ){ - *z = 0; + needCommit = sqlite3_get_autocommit(db); + if( needCommit ) sqlite3_exec(db, "BEGIN", 0, 0, 0); + do{ + int startLine = sCsv.nLine; + for(i=0; i=nCol ){ + sqlite3_step(pStmt); + rc = sqlite3_reset(pStmt); + if( rc!=SQLITE_OK ){ + fprintf(stderr, "%s:%d: INSERT failed: %s\n", sCsv.zFile, startLine, + sqlite3_errmsg(db)); } - sqlite3_bind_text(pStmt, i+1, azCol[i], -1, SQLITE_STATIC); - } - sqlite3_step(pStmt); - rc = sqlite3_reset(pStmt); - free(zLine); - if( rc!=SQLITE_OK ){ - fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db)); - zCommit = "ROLLBACK"; - rc = 1; - break; /* from while */ } - } /* end while */ - free(azCol); - fclose(in); + }while( sCsv.cTerm!=EOF ); + + xCloser(sCsv.in); + sqlite3_free(sCsv.z); sqlite3_finalize(pStmt); - sqlite3_exec(p->db, zCommit, 0, 0, 0); + if( needCommit ) sqlite3_exec(db, "COMMIT", 0, 0, 0); }else if( c=='i' && strncmp(azArg[0], "indices", n)==0 && nArg<3 ){ @@ -2305,6 +2456,29 @@ static int do_meta_command(char *zLine, struct callback_data *p){ } }else +#ifdef SQLITE_DEBUG + /* Undocumented commands for internal testing. Subject to change + ** without notice. */ + if( c=='s' && n>=10 && strncmp(azArg[0], "selftest-", 9)==0 ){ + if( strncmp(azArg[0]+9, "boolean", n-9)==0 ){ + int i, v; + for(i=1; iout, "%s: %d 0x%x\n", azArg[i], v, v); + } + } + if( strncmp(azArg[0]+9, "integer", n-9)==0 ){ + int i; sqlite3_int64 v; + for(i=1; iout, "%s", zBuf); + } + } + }else +#endif + if( c=='s' && strncmp(azArg[0], "separator", n)==0 && nArg==2 ){ sqlite3_snprintf(sizeof(p->separator), p->separator, "%.*s", (int)sizeof(p->separator)-1, azArg[1]); @@ -2458,7 +2632,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){ } } } - if( testctrl<0 ) testctrl = atoi(azArg[1]); + if( testctrl<0 ) testctrl = (int)integerValue(azArg[1]); if( (testctrlSQLITE_TESTCTRL_LAST) ){ fprintf(stderr,"Error: invalid testctrl option: %s\n", azArg[1]); }else{ @@ -2492,7 +2666,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){ /* sqlite3_test_control(int, uint) */ case SQLITE_TESTCTRL_PENDING_BYTE: if( nArg==3 ){ - unsigned int opt = (unsigned int)integerValue(azArg[2]); + unsigned int opt = (unsigned int)integerValue(azArg[2]); rc = sqlite3_test_control(testctrl, opt); fprintf(p->out, "%d (0x%08x)\n", rc, rc); } else { @@ -2505,7 +2679,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){ case SQLITE_TESTCTRL_ASSERT: case SQLITE_TESTCTRL_ALWAYS: if( nArg==3 ){ - int opt = atoi(azArg[2]); + int opt = booleanValue(azArg[2]); rc = sqlite3_test_control(testctrl, opt); fprintf(p->out, "%d (0x%08x)\n", rc, rc); } else { @@ -2542,7 +2716,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){ if( c=='t' && n>4 && strncmp(azArg[0], "timeout", n)==0 && nArg==2 ){ open_db(p); - sqlite3_busy_timeout(p->db, atoi(azArg[1])); + sqlite3_busy_timeout(p->db, (int)integerValue(azArg[1])); }else if( HAS_TIMER && c=='t' && n>=5 && strncmp(azArg[0], "timer", n)==0 @@ -2592,7 +2766,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){ int j; assert( nArg<=ArraySize(azArg) ); for(j=1; jcolWidth); j++){ - p->colWidth[j-1] = atoi(azArg[j]); + p->colWidth[j-1] = (int)integerValue(azArg[j]); } }else @@ -2609,7 +2783,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){ ** Return TRUE if a semicolon occurs anywhere in the first N characters ** of string z[]. */ -static int _contains_semicolon(const char *z, int N){ +static int line_contains_semicolon(const char *z, int N){ int i; for(i=0; iout); - free(zLine); - zLine = one_input_line(zSql, in); + zLine = one_input_line(in, zLine, nSql>0); if( zLine==0 ){ /* End of input */ if( stdin_is_interactive ) printf("\n"); @@ -2704,7 +2879,7 @@ static int process_input(struct callback_data *p, FILE *in){ seenInterrupt = 0; } lineno++; - if( (zSql==0 || zSql[0]==0) && _all_whitespace(zLine) ) continue; + if( nSql==0 && _all_whitespace(zLine) ) continue; if( zLine && zLine[0]=='.' && nSql==0 ){ if( p->echoOn ) printf("%s\n", zLine); rc = do_meta_command(zLine, p); @@ -2715,35 +2890,32 @@ static int process_input(struct callback_data *p, FILE *in){ } continue; } - if( _is_command_terminator(zLine) && _is_complete(zSql, nSql) ){ + if( line_is_command_terminator(zLine) && line_is_complete(zSql, nSql) ){ memcpy(zLine,";",2); } + nLine = strlen30(zLine); + if( nSql+nLine+2>=nAlloc ){ + nAlloc = nSql+nLine+100; + zSql = realloc(zSql, nAlloc); + if( zSql==0 ){ + fprintf(stderr, "Error: out of memory\n"); + exit(1); + } + } nSqlPrior = nSql; - if( zSql==0 ){ + if( nSql==0 ){ int i; for(i=0; zLine[i] && IsSpace(zLine[i]); i++){} - if( zLine[i]!=0 ){ - nSql = strlen30(zLine); - zSql = malloc( nSql+3 ); - if( zSql==0 ){ - fprintf(stderr, "Error: out of memory\n"); - exit(1); - } - memcpy(zSql, zLine, nSql+1); - startline = lineno; - } + assert( nAlloc>0 && zSql!=0 ); + memcpy(zSql, zLine+i, nLine+1-i); + startline = lineno; + nSql = nLine-i; }else{ - int len = strlen30(zLine); - zSql = realloc( zSql, nSql + len + 4 ); - if( zSql==0 ){ - fprintf(stderr,"Error: out of memory\n"); - exit(1); - } zSql[nSql++] = '\n'; - memcpy(&zSql[nSql], zLine, len+1); - nSql += len; + memcpy(zSql+nSql, zLine, nLine+1); + nSql += nLine; } - if( zSql && _contains_semicolon(&zSql[nSqlPrior], nSql-nSqlPrior) + if( nSql && line_contains_semicolon(&zSql[nSqlPrior], nSql-nSqlPrior) && sqlite3_complete(zSql) ){ p->cnt = 0; open_db(p); @@ -2767,16 +2939,12 @@ static int process_input(struct callback_data *p, FILE *in){ } errCnt++; } - free(zSql); - zSql = 0; nSql = 0; - }else if( zSql && _all_whitespace(zSql) ){ - free(zSql); - zSql = 0; + }else if( nSql && _all_whitespace(zSql) ){ nSql = 0; } } - if( zSql ){ + if( nSql ){ if( !_all_whitespace(zSql) ){ fprintf(stderr, "Error: incomplete SQL: %s\n", zSql); } @@ -3024,7 +3192,6 @@ int main(int argc, char **argv){ stdin_is_interactive = 0; }else if( strcmp(z,"-heap")==0 ){ #if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5) - int j, c; const char *zSize; sqlite3_int64 szHeap; -- cgit v1.2.3