mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-06 15:49:35 +03:00
Command-line shell enhancements. Bail out when errors are seen in
non-interactive mode. Override isatty() using -interactive or -batch command-line options. Report line number in error messages. Tickets #2009, #2045. (CVS 3490) FossilOrigin-Name: 3baa04cfb91039e27f642f6f78ef761b5770cb08
This commit is contained in:
14
manifest
14
manifest
@@ -1,5 +1,5 @@
|
|||||||
C Empty\squeries\sshould\sget\sno\sresults.\s\sMy\srecent\schange\n(\shttp://www.sqlite.org/cvstrac/chngview?cn=3486\s)\sbroke\stest\sfts2a-5.3.\nThis\schange\sshould\smake\sthe\sexpected\sresult\smore\sobvious.\s(CVS\s3489)
|
C Command-line\sshell\senhancements.\s\sBail\sout\swhen\serrors\sare\sseen\sin\nnon-interactive\smode.\s\sOverride\sisatty()\susing\s-interactive\sor\s-batch\ncommand-line\soptions.\s\sReport\sline\snumber\sin\serror\smessages.\nTickets\s#2009,\s#2045.\s(CVS\s3490)
|
||||||
D 2006-10-26T00:41:51
|
D 2006-10-26T14:25:58
|
||||||
F Makefile.in 4379c909d46b38b8c5db3533084601621d4f14b2
|
F Makefile.in 4379c909d46b38b8c5db3533084601621d4f14b2
|
||||||
F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935
|
F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935
|
||||||
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
|
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
|
||||||
@@ -94,7 +94,7 @@ F src/printf.c b179b6ed12f793e028dd169e2e2e2b2a37eedc63
|
|||||||
F src/random.c d40f8d356cecbd351ccfab6eaedd7ec1b54f5261
|
F src/random.c d40f8d356cecbd351ccfab6eaedd7ec1b54f5261
|
||||||
F src/select.c 6ba6d8ead43d0575ce1f8b418cc039f8f301389a
|
F src/select.c 6ba6d8ead43d0575ce1f8b418cc039f8f301389a
|
||||||
F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96
|
F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96
|
||||||
F src/shell.c 1c17cd03c9cc2ff618435156038f508c159ecf12
|
F src/shell.c 73cbdcb3cdc63bca7630dc1dfe41ab9ac90d98db
|
||||||
F src/sqlite.h.in bf935004029631fd93d119bcf2f7259b9cb9ad5e
|
F src/sqlite.h.in bf935004029631fd93d119bcf2f7259b9cb9ad5e
|
||||||
F src/sqlite3ext.h 2c2156cc32a158e2b7bd9042d42accf94bff2e40
|
F src/sqlite3ext.h 2c2156cc32a158e2b7bd9042d42accf94bff2e40
|
||||||
F src/sqliteInt.h 637ef229c3d8e0f98096ab31c496efdf5361d678
|
F src/sqliteInt.h 637ef229c3d8e0f98096ab31c496efdf5361d678
|
||||||
@@ -419,7 +419,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9
|
|||||||
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
|
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
|
||||||
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
|
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
|
||||||
F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513
|
F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513
|
||||||
P 5878add0839f9c5bec77caae2361ec20cb60b48b
|
P cde383eb467de0d752e94a22cd2f890c2dc599cc
|
||||||
R 3d9ce122beb09a00cd3fd7137dd66557
|
R 91d1f3065e90bb2f41c9cbd193a3305f
|
||||||
U shess
|
U drh
|
||||||
Z 4dba001cc239d0747f6caf0a916f48ed
|
Z 74126c296022fab53cfd540120f95a5c
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
cde383eb467de0d752e94a22cd2f890c2dc599cc
|
3baa04cfb91039e27f642f6f78ef761b5770cb08
|
||||||
119
src/shell.c
119
src/shell.c
@@ -12,7 +12,7 @@
|
|||||||
** This file contains code to implement the "sqlite" command line
|
** This file contains code to implement the "sqlite" command line
|
||||||
** utility for accessing SQLite databases.
|
** utility for accessing SQLite databases.
|
||||||
**
|
**
|
||||||
** $Id: shell.c,v 1.150 2006/09/25 13:09:23 drh Exp $
|
** $Id: shell.c,v 1.151 2006/10/26 14:25:58 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -60,6 +60,12 @@
|
|||||||
extern int isatty();
|
extern int isatty();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Threat stdin as an interactive input if the following variable
|
||||||
|
** is true. Otherwise, assume stdin is connected to a file or pipe.
|
||||||
|
*/
|
||||||
|
static int stdin_is_interactive = 1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** The following is the open SQLite database. We make a pointer
|
** The following is the open SQLite database. We make a pointer
|
||||||
** to this database a static variable so that it can be accessed
|
** to this database a static variable so that it can be accessed
|
||||||
@@ -184,10 +190,7 @@ static char *local_getline(char *zPrompt, FILE *in){
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Retrieve a single line of input text. "isatty" is true if text
|
** Retrieve a single line of input text.
|
||||||
** is coming from a terminal. In that case, we issue a prompt and
|
|
||||||
** attempt to use "readline" for command-line editing. If "isatty"
|
|
||||||
** is false, use "local_getline" instead of "readline" and issue no prompt.
|
|
||||||
**
|
**
|
||||||
** zPrior is a string of prior text retrieved. If not the empty
|
** zPrior is a string of prior text retrieved. If not the empty
|
||||||
** string, then issue a continuation prompt.
|
** string, then issue a continuation prompt.
|
||||||
@@ -793,7 +796,7 @@ static char zHelp[] =
|
|||||||
;
|
;
|
||||||
|
|
||||||
/* Forward reference */
|
/* Forward reference */
|
||||||
static void process_input(struct callback_data *p, FILE *in);
|
static int process_input(struct callback_data *p, FILE *in);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Make sure the database is open. If it is not, then open it. If
|
** Make sure the database is open. If it is not, then open it. If
|
||||||
@@ -853,6 +856,23 @@ static void resolve_backslashes(char *z){
|
|||||||
z[j] = 0;
|
z[j] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Interpret zArg as a boolean value. Return either 0 or 1.
|
||||||
|
*/
|
||||||
|
static int booleanValue(char *zArg){
|
||||||
|
int val = atoi(zArg);
|
||||||
|
int j;
|
||||||
|
for(j=0; zArg[j]; j++){
|
||||||
|
zArg[j] = tolower(zArg[j]);
|
||||||
|
}
|
||||||
|
if( strcmp(zArg,"on")==0 ){
|
||||||
|
val = 1;
|
||||||
|
}else if( strcmp(zArg,"yes")==0 ){
|
||||||
|
val = 1;
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** If an input line begins with "." then invoke this routine to
|
** If an input line begins with "." then invoke this routine to
|
||||||
** process that line.
|
** process that line.
|
||||||
@@ -957,18 +977,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
|||||||
}else
|
}else
|
||||||
|
|
||||||
if( c=='e' && strncmp(azArg[0], "echo", n)==0 && nArg>1 ){
|
if( c=='e' && strncmp(azArg[0], "echo", n)==0 && nArg>1 ){
|
||||||
int j;
|
p->echoOn = booleanValue(azArg[1]);
|
||||||
char *z = azArg[1];
|
|
||||||
int val = atoi(azArg[1]);
|
|
||||||
for(j=0; z[j]; j++){
|
|
||||||
z[j] = tolower((unsigned char)z[j]);
|
|
||||||
}
|
|
||||||
if( strcmp(z,"on")==0 ){
|
|
||||||
val = 1;
|
|
||||||
}else if( strcmp(z,"yes")==0 ){
|
|
||||||
val = 1;
|
|
||||||
}
|
|
||||||
p->echoOn = val;
|
|
||||||
}else
|
}else
|
||||||
|
|
||||||
if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){
|
if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){
|
||||||
@@ -976,18 +985,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
|||||||
}else
|
}else
|
||||||
|
|
||||||
if( c=='e' && strncmp(azArg[0], "explain", n)==0 ){
|
if( c=='e' && strncmp(azArg[0], "explain", n)==0 ){
|
||||||
int j;
|
int val = nArg>=2 ? booleanValue(azArg[1]) : 1;
|
||||||
static char zOne[] = "1";
|
|
||||||
char *z = nArg>=2 ? azArg[1] : zOne;
|
|
||||||
int val = atoi(z);
|
|
||||||
for(j=0; z[j]; j++){
|
|
||||||
z[j] = tolower((unsigned char)z[j]);
|
|
||||||
}
|
|
||||||
if( strcmp(z,"on")==0 ){
|
|
||||||
val = 1;
|
|
||||||
}else if( strcmp(z,"yes")==0 ){
|
|
||||||
val = 1;
|
|
||||||
}
|
|
||||||
if(val == 1) {
|
if(val == 1) {
|
||||||
if(!p->explainPrev.valid) {
|
if(!p->explainPrev.valid) {
|
||||||
p->explainPrev.valid = 1;
|
p->explainPrev.valid = 1;
|
||||||
@@ -1018,21 +1016,9 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
|||||||
}
|
}
|
||||||
}else
|
}else
|
||||||
|
|
||||||
if( c=='h' && (strncmp(azArg[0], "header", n)==0
|
if( c=='h' && (strncmp(azArg[0], "header", n)==0 ||
|
||||||
||
|
|
||||||
strncmp(azArg[0], "headers", n)==0 )&& nArg>1 ){
|
strncmp(azArg[0], "headers", n)==0 )&& nArg>1 ){
|
||||||
int j;
|
p->showHeader = booleanValue(azArg[1]);
|
||||||
char *z = azArg[1];
|
|
||||||
int val = atoi(azArg[1]);
|
|
||||||
for(j=0; z[j]; j++){
|
|
||||||
z[j] = tolower((unsigned char)z[j]);
|
|
||||||
}
|
|
||||||
if( strcmp(z,"on")==0 ){
|
|
||||||
val = 1;
|
|
||||||
}else if( strcmp(z,"yes")==0 ){
|
|
||||||
val = 1;
|
|
||||||
}
|
|
||||||
p->showHeader = val;
|
|
||||||
}else
|
}else
|
||||||
|
|
||||||
if( c=='h' && strncmp(azArg[0], "help", n)==0 ){
|
if( c=='h' && strncmp(azArg[0], "help", n)==0 ){
|
||||||
@@ -1482,18 +1468,26 @@ static int _is_command_terminator(const char *zLine){
|
|||||||
** is coming from a file or device. A prompt is issued and history
|
** is coming from a file or device. A prompt is issued and history
|
||||||
** is saved only if input is interactive. An interrupt signal will
|
** is saved only if input is interactive. An interrupt signal will
|
||||||
** cause this routine to exit immediately, unless input is interactive.
|
** cause this routine to exit immediately, unless input is interactive.
|
||||||
|
**
|
||||||
|
** Return the number of errors.
|
||||||
*/
|
*/
|
||||||
static void process_input(struct callback_data *p, FILE *in){
|
static int process_input(struct callback_data *p, FILE *in){
|
||||||
char *zLine;
|
char *zLine;
|
||||||
char *zSql = 0;
|
char *zSql = 0;
|
||||||
int nSql = 0;
|
int nSql = 0;
|
||||||
char *zErrMsg;
|
char *zErrMsg;
|
||||||
int rc;
|
int rc = 0;
|
||||||
|
int lineno = 0;
|
||||||
|
int startline = 0;
|
||||||
while( fflush(p->out), (zLine = one_input_line(zSql, in))!=0 ){
|
while( fflush(p->out), (zLine = one_input_line(zSql, in))!=0 ){
|
||||||
if( seenInterrupt ){
|
if( seenInterrupt ){
|
||||||
if( in!=0 ) break;
|
if( in!=0 ) break;
|
||||||
seenInterrupt = 0;
|
seenInterrupt = 0;
|
||||||
}
|
}
|
||||||
|
if( rc && (in!=0 || !stdin_is_interactive) ){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
lineno++;
|
||||||
if( p->echoOn ) printf("%s\n", zLine);
|
if( p->echoOn ) printf("%s\n", zLine);
|
||||||
if( (zSql==0 || zSql[0]==0) && _all_whitespace(zLine) ) continue;
|
if( (zSql==0 || zSql[0]==0) && _all_whitespace(zLine) ) continue;
|
||||||
if( zLine && zLine[0]=='.' && nSql==0 ){
|
if( zLine && zLine[0]=='.' && nSql==0 ){
|
||||||
@@ -1516,6 +1510,7 @@ static void process_input(struct callback_data *p, FILE *in){
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
strcpy(zSql, zLine);
|
strcpy(zSql, zLine);
|
||||||
|
startline = lineno;
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
int len = strlen(zLine);
|
int len = strlen(zLine);
|
||||||
@@ -1534,13 +1529,18 @@ static void process_input(struct callback_data *p, FILE *in){
|
|||||||
open_db(p);
|
open_db(p);
|
||||||
rc = sqlite3_exec(p->db, zSql, callback, p, &zErrMsg);
|
rc = sqlite3_exec(p->db, zSql, callback, p, &zErrMsg);
|
||||||
if( rc || zErrMsg ){
|
if( rc || zErrMsg ){
|
||||||
/* if( in!=0 && !p->echoOn ) printf("%s\n",zSql); */
|
char zPrefix[100];
|
||||||
|
if( in!=0 || !stdin_is_interactive ){
|
||||||
|
sprintf(zPrefix, "SQL error near line %d:", startline);
|
||||||
|
}else{
|
||||||
|
sprintf(zPrefix, "SQL error:");
|
||||||
|
}
|
||||||
if( zErrMsg!=0 ){
|
if( zErrMsg!=0 ){
|
||||||
printf("SQL error: %s\n", zErrMsg);
|
printf("%s %s\n", zPrefix, zErrMsg);
|
||||||
sqlite3_free(zErrMsg);
|
sqlite3_free(zErrMsg);
|
||||||
zErrMsg = 0;
|
zErrMsg = 0;
|
||||||
}else{
|
}else{
|
||||||
printf("SQL error: %s\n", sqlite3_errmsg(p->db));
|
printf("%s %s\n", zPrefix, sqlite3_errmsg(p->db));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free(zSql);
|
free(zSql);
|
||||||
@@ -1552,6 +1552,7 @@ static void process_input(struct callback_data *p, FILE *in){
|
|||||||
if( !_all_whitespace(zSql) ) printf("Incomplete SQL: %s\n", zSql);
|
if( !_all_whitespace(zSql) ) printf("Incomplete SQL: %s\n", zSql);
|
||||||
free(zSql);
|
free(zSql);
|
||||||
}
|
}
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1642,7 +1643,7 @@ static void process_sqliterc(
|
|||||||
}
|
}
|
||||||
in = fopen(sqliterc,"rb");
|
in = fopen(sqliterc,"rb");
|
||||||
if( in ){
|
if( in ){
|
||||||
if( isatty(fileno(stdout)) ){
|
if( stdin_is_interactive ){
|
||||||
printf("Loading resources from %s\n",sqliterc);
|
printf("Loading resources from %s\n",sqliterc);
|
||||||
}
|
}
|
||||||
process_input(p,in);
|
process_input(p,in);
|
||||||
@@ -1698,6 +1699,7 @@ int main(int argc, char **argv){
|
|||||||
const char *zInitFile = 0;
|
const char *zInitFile = 0;
|
||||||
char *zFirstCmd = 0;
|
char *zFirstCmd = 0;
|
||||||
int i;
|
int i;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
#ifdef __MACOS__
|
#ifdef __MACOS__
|
||||||
argc = ccommand(&argv);
|
argc = ccommand(&argv);
|
||||||
@@ -1705,6 +1707,7 @@ int main(int argc, char **argv){
|
|||||||
|
|
||||||
Argv0 = argv[0];
|
Argv0 = argv[0];
|
||||||
main_init(&data);
|
main_init(&data);
|
||||||
|
stdin_is_interactive = isatty(0);
|
||||||
|
|
||||||
/* Make sure we have a valid signal handler early, before anything
|
/* Make sure we have a valid signal handler early, before anything
|
||||||
** else is done.
|
** else is done.
|
||||||
@@ -1718,7 +1721,10 @@ int main(int argc, char **argv){
|
|||||||
** and the first command to execute.
|
** and the first command to execute.
|
||||||
*/
|
*/
|
||||||
for(i=1; i<argc-1; i++){
|
for(i=1; i<argc-1; i++){
|
||||||
|
char *z;
|
||||||
if( argv[i][0]!='-' ) break;
|
if( argv[i][0]!='-' ) break;
|
||||||
|
z = argv[i];
|
||||||
|
if( z[0]=='-' && z[1]=='-' ) z++;
|
||||||
if( strcmp(argv[i],"-separator")==0 || strcmp(argv[i],"-nullvalue")==0 ){
|
if( strcmp(argv[i],"-separator")==0 || strcmp(argv[i],"-nullvalue")==0 ){
|
||||||
i++;
|
i++;
|
||||||
}else if( strcmp(argv[i],"-init")==0 ){
|
}else if( strcmp(argv[i],"-init")==0 ){
|
||||||
@@ -1769,6 +1775,7 @@ int main(int argc, char **argv){
|
|||||||
*/
|
*/
|
||||||
for(i=1; i<argc && argv[i][0]=='-'; i++){
|
for(i=1; i<argc && argv[i][0]=='-'; i++){
|
||||||
char *z = argv[i];
|
char *z = argv[i];
|
||||||
|
if( z[1]=='-' ){ z++; }
|
||||||
if( strcmp(z,"-init")==0 ){
|
if( strcmp(z,"-init")==0 ){
|
||||||
i++;
|
i++;
|
||||||
}else if( strcmp(z,"-html")==0 ){
|
}else if( strcmp(z,"-html")==0 ){
|
||||||
@@ -1794,6 +1801,10 @@ int main(int argc, char **argv){
|
|||||||
}else if( strcmp(z,"-version")==0 ){
|
}else if( strcmp(z,"-version")==0 ){
|
||||||
printf("%s\n", sqlite3_libversion());
|
printf("%s\n", sqlite3_libversion());
|
||||||
return 0;
|
return 0;
|
||||||
|
}else if( strcmp(z,"-interactive")==0 ){
|
||||||
|
stdin_is_interactive = 1;
|
||||||
|
}else if( strcmp(z,"-batch")==0 ){
|
||||||
|
stdin_is_interactive = 0;
|
||||||
}else if( strcmp(z,"-help")==0 || strcmp(z, "--help")==0 ){
|
}else if( strcmp(z,"-help")==0 || strcmp(z, "--help")==0 ){
|
||||||
usage(1);
|
usage(1);
|
||||||
}else{
|
}else{
|
||||||
@@ -1821,7 +1832,7 @@ int main(int argc, char **argv){
|
|||||||
}else{
|
}else{
|
||||||
/* Run commands received from standard input
|
/* Run commands received from standard input
|
||||||
*/
|
*/
|
||||||
if( isatty(fileno(stdout)) && isatty(fileno(stdin)) ){
|
if( stdin_is_interactive ){
|
||||||
char *zHome;
|
char *zHome;
|
||||||
char *zHistory = 0;
|
char *zHistory = 0;
|
||||||
printf(
|
printf(
|
||||||
@@ -1836,7 +1847,7 @@ int main(int argc, char **argv){
|
|||||||
#if defined(HAVE_READLINE) && HAVE_READLINE==1
|
#if defined(HAVE_READLINE) && HAVE_READLINE==1
|
||||||
if( zHistory ) read_history(zHistory);
|
if( zHistory ) read_history(zHistory);
|
||||||
#endif
|
#endif
|
||||||
process_input(&data, 0);
|
rc = process_input(&data, 0);
|
||||||
if( zHistory ){
|
if( zHistory ){
|
||||||
stifle_history(100);
|
stifle_history(100);
|
||||||
write_history(zHistory);
|
write_history(zHistory);
|
||||||
@@ -1844,7 +1855,7 @@ int main(int argc, char **argv){
|
|||||||
}
|
}
|
||||||
free(zHome);
|
free(zHome);
|
||||||
}else{
|
}else{
|
||||||
process_input(&data, stdin);
|
rc = process_input(&data, stdin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
set_table_name(&data, 0);
|
set_table_name(&data, 0);
|
||||||
@@ -1853,5 +1864,5 @@ int main(int argc, char **argv){
|
|||||||
fprintf(stderr,"error closing database: %s\n", sqlite3_errmsg(db));
|
fprintf(stderr,"error closing database: %s\n", sqlite3_errmsg(db));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user