Hi,
I created a patch which adds "-bail" and ".bail" commands to the sqlite3
shell. When bail is enabled, the shell will exit with a non-zero return
code immediately upon encountering the first SQL error. This is useful
when you pass a number of commands to the shell non-interactively and
wish to, for example, abandon a transaction if any errors occur. It's
also useful because the calling program receives an indication of
success or failure. Bail mode works for standard input, init files,
.read commands and, for completeness, interactively.
Patch is against 3.3.7. I hope someone finds it of use.
Jim
--
[EMAIL PROTECTED] / 0x43340710 / 517B C658 D2CB 260D 3E1F 5ED1 6DB3 FBB9 4334
0710
--- sqlite-3.3.7/src/shell.c.orig 2006-10-17 13:45:56.000000000 -0500
+++ sqlite-3.3.7/src/shell.c 2006-10-17 18:17:35.000000000 -0500
@@ -224,6 +224,7 @@
FILE *out; /* Write results here */
int mode; /* An output mode setting */
int showHeader; /* True to show column names in List or Column mode */
+ int bail; /* True to bail out on first SQL error */
char *zDestTable; /* Name of destination table when MODE_Insert */
char separator[20]; /* Separator character for MODE_List */
int colWidth[100]; /* Requested width of each column when in column
mode*/
@@ -754,6 +755,7 @@
** Text of a help message
*/
static char zHelp[] =
+ ".bail ON|OFF Bail out upon encountering an SQL error\n"
".databases List names and files of attached databases\n"
".dump ?TABLE? ... Dump the database in an SQL text format\n"
".echo ON|OFF Turn command echo on or off\n"
@@ -790,7 +792,7 @@
;
/* 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
@@ -889,6 +891,25 @@
if( nArg==0 ) return rc;
n = strlen(azArg[0]);
c = azArg[0][0];
+
+ if( c=='b' && strncmp(azArg[0], "bail", n)==0 ){
+ int j;
+ 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) {
+ p->bail = val;
+ }
+ }else
+
if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 ){
struct callback_data data;
char *zErrMsg = 0;
@@ -1246,8 +1267,10 @@
if( alt==0 ){
fprintf(stderr,"can't open \"%s\"\n", azArg[1]);
}else{
- process_input(p, alt);
+ int rc = process_input(p, alt);
fclose(alt);
+ if (rc)
+ exit(1);
}
}else
@@ -1320,6 +1343,7 @@
if( c=='s' && strncmp(azArg[0], "show", n)==0){
int i;
+ fprintf(p->out,"%9.9s: %s\n","bail", p->bail ? "on" : "off");
fprintf(p->out,"%9.9s: %s\n","echo", p->echoOn ? "on" : "off");
fprintf(p->out,"%9.9s: %s\n","explain", p->explainPrev.valid ? "on"
:"off");
fprintf(p->out,"%9.9s: %s\n","headers", p->showHeader ? "on" : "off");
@@ -1470,7 +1494,7 @@
** is saved only if input is interactive. An interrupt signal will
** cause this routine to exit immediately, unless input is interactive.
*/
-static void process_input(struct callback_data *p, FILE *in){
+static int process_input(struct callback_data *p, FILE *in){
char *zLine;
char *zSql = 0;
int nSql = 0;
@@ -1529,6 +1553,10 @@
}else{
printf("SQL error: %s\n", sqlite3_errmsg(p->db));
}
+ if (p->bail) {
+ free(zSql);
+ return rc;
+ }
}
free(zSql);
zSql = 0;
@@ -1538,7 +1566,11 @@
if( zSql ){
if( !_all_whitespace(zSql) ) printf("Incomplete SQL: %s\n", zSql);
free(zSql);
+ if (p->bail) {
+ return SQLITE_ERROR;
+ }
}
+ return SQLITE_OK;
}
/*
@@ -1589,7 +1621,7 @@
** Read input from the file given by sqliterc_override. Or if that
** parameter is NULL, take input from ~/.sqliterc
*/
-static void process_sqliterc(
+static int process_sqliterc(
struct callback_data *p, /* Configuration data */
const char *sqliterc_override /* Name of config file. NULL to use default
*/
){
@@ -1597,12 +1629,13 @@
const char *sqliterc = sqliterc_override;
char *zBuf = 0;
FILE *in = NULL;
+ int rc = 0;
if (sqliterc == NULL) {
home_dir = find_home_dir();
if( home_dir==0 ){
fprintf(stderr,"%s: cannot locate your home directory!\n", Argv0);
- return;
+ return 0;
}
zBuf = malloc(strlen(home_dir) + 15);
if( zBuf==0 ){
@@ -1618,11 +1651,11 @@
if( isatty(fileno(stdout)) ){
printf("Loading resources from %s\n",sqliterc);
}
- process_input(p,in);
+ rc = process_input(p,in);
fclose(in);
}
free(zBuf);
- return;
+ return rc;
}
/*
@@ -1631,6 +1664,7 @@
static const char zOptions[] =
" -init filename read/process named file\n"
" -echo print commands before execution\n"
+ " -bail bail out immediately on first SQL error\n"
" -[no]header turn headers on or off\n"
" -column set output mode to 'column'\n"
" -html set output mode to HTML\n"
@@ -1659,6 +1693,7 @@
data->mode = MODE_List;
strcpy(data->separator,"|");
data->showHeader = 0;
+ data->bail = 0;
strcpy(mainPrompt,"sqlite> ");
strcpy(continuePrompt," ...> ");
}
@@ -1669,6 +1704,7 @@
const char *zInitFile = 0;
char *zFirstCmd = 0;
int i;
+ int rc;
#ifdef __MACOS__
argc = ccommand(&argv);
@@ -1734,7 +1770,9 @@
** is given on the command line, look for a file named ~/.sqliterc and
** try to process it.
*/
- process_sqliterc(&data,zInitFile);
+ rc = process_sqliterc(&data,zInitFile);
+ if (rc)
+ exit(1); /* fatal SQL error while processing */
/* Make a second pass through the command-line argument and set
** options. This second pass is delayed until after the initialization
@@ -1765,7 +1803,12 @@
data.showHeader = 0;
}else if( strcmp(z,"-echo")==0 ){
data.echoOn = 1;
- }else if( strcmp(z,"-version")==0 ){
+ }else if( strcmp(z,"-bail")==0 ){
+ /* Note: To affect init file processing, you must issue the
+ * .bail meta-command inside the init file itself. */
+ data.bail = 1;
+ }
+ else if( strcmp(z,"-version")==0 ){
printf("%s\n", sqlite3_libversion());
return 0;
}else if( strcmp(z,"-help")==0 ){
@@ -1798,6 +1841,8 @@
if( isatty(fileno(stdout)) && isatty(fileno(stdin)) ){
char *zHome;
char *zHistory = 0;
+ int rc;
+
printf(
"SQLite version %s\n"
"Enter \".help\" for instructions\n",
@@ -1810,15 +1855,19 @@
#if defined(HAVE_READLINE) && HAVE_READLINE==1
if( zHistory ) read_history(zHistory);
#endif
- process_input(&data, 0);
+ rc = process_input(&data, 0);
if( zHistory ){
stifle_history(100);
write_history(zHistory);
free(zHistory);
}
free(zHome);
+ if (rc)
+ exit(1);
}else{
- process_input(&data, stdin);
+ int rc = process_input(&data, stdin);
+ if (rc)
+ exit(1);
}
}
set_table_name(&data, 0);
-----------------------------------------------------------------------------
To unsubscribe, send email to [EMAIL PROTECTED]
-----------------------------------------------------------------------------