aboutsummaryrefslogtreecommitdiff
path: root/src/shell.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/shell.c')
-rw-r--r--src/shell.c143
1 files changed, 67 insertions, 76 deletions
diff --git a/src/shell.c b/src/shell.c
index 7b8a8ad7f..4a59c667a 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -53,7 +53,6 @@
# include <readline/history.h>
#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)
@@ -337,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;
@@ -368,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;
}
@@ -1995,6 +1990,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
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 */
CSVReader sCsv; /* Reader context */
@@ -2096,6 +2092,8 @@ static int do_meta_command(char *zLine, struct callback_data *p){
xCloser(sCsv.in);
return 1;
}
+ needCommit = sqlite3_get_autocommit(db);
+ if( needCommit ) sqlite3_exec(db, "BEGIN", 0, 0, 0);
do{
int startLine = sCsv.nLine;
for(i=0; i<nCol; i++){
@@ -2132,7 +2130,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
xCloser(sCsv.in);
sqlite3_free(sCsv.z);
sqlite3_finalize(pStmt);
- sqlite3_exec(p->db, "COMMIT", 0, 0, 0);
+ if( needCommit ) sqlite3_exec(db, "COMMIT", 0, 0, 0);
}else
if( c=='i' && strncmp(azArg[0], "indices", n)==0 && nArg<3 ){
@@ -2781,7 +2779,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; i<N; i++){ if( z[i]==';' ) return 1; }
return 0;
@@ -2816,7 +2814,7 @@ static int _all_whitespace(const char *z){
** than a semi-colon. The SQL Server style "go" command is understood
** as is the Oracle "/".
*/
-static int _is_command_terminator(const char *zLine){
+static int line_is_command_terminator(const char *zLine){
while( IsSpace(zLine[0]) ){ zLine++; };
if( zLine[0]=='/' && _all_whitespace(&zLine[1]) ){
return 1; /* Oracle */
@@ -2832,7 +2830,7 @@ static int _is_command_terminator(const char *zLine){
** Return true if zSql is a complete SQL statement. Return false if it
** ends in the middle of a string literal or C-style comment.
*/
-static int _is_complete(char *zSql, int nSql){
+static int line_is_complete(char *zSql, int nSql){
int rc;
if( zSql==0 ) return 1;
zSql[nSql] = ';';
@@ -2852,20 +2850,21 @@ static int _is_complete(char *zSql, int nSql){
** Return the number of errors.
*/
static int process_input(struct callback_data *p, FILE *in){
- char *zLine = 0;
- char *zSql = 0;
- int nSql = 0;
- int nSqlPrior = 0;
- char *zErrMsg;
- int rc;
- int errCnt = 0;
- int lineno = 0;
- int startline = 0;
+ char *zLine = 0; /* A single input line */
+ char *zSql = 0; /* Accumulated SQL text */
+ int nLine; /* Length of current line */
+ int nSql = 0; /* Bytes of zSql[] used */
+ int nAlloc = 0; /* Allocated zSql[] space */
+ int nSqlPrior = 0; /* Bytes of zSql[] used by prior line */
+ char *zErrMsg; /* Error message returned */
+ int rc; /* Error code */
+ int errCnt = 0; /* Number of errors seen */
+ int lineno = 0; /* Current line number */
+ int startline = 0; /* Line number for start of current input */
while( errCnt==0 || !bail_on_error || (in==0 && stdin_is_interactive) ){
fflush(p->out);
- 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");
@@ -2876,7 +2875,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);
@@ -2887,35 +2886,31 @@ 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;
- }
+ 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);
@@ -2939,16 +2934,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);
}