/ Check-in [517712d6]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Bring CVS output into more commonly accepted practice. Tickets #2030, #1573. Add command-line options -bail and ".bail" commands. Default behavior is to continue after encountering an error. Ticket #2045. (CVS 3491)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 517712d6fbc5ba5299942a54852298030f4d3381
User & Date: drh 2006-10-26 18:15:42
Context
2006-10-27
14:06
Changes directed toward optimizing IS NULL terms in WHERE clauses. (CVS 3492) check-in: 4d336e9e user: drh tags: trunk
2006-10-26
18:15
Bring CVS output into more commonly accepted practice. Tickets #2030, #1573. Add command-line options -bail and ".bail" commands. Default behavior is to continue after encountering an error. Ticket #2045. (CVS 3491) check-in: 517712d6 user: drh tags: trunk
14:25
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) check-in: 3baa04cf user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/shell.c.

     8      8   **    May you find forgiveness for yourself and forgive others.
     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12     12   ** This file contains code to implement the "sqlite" command line
    13     13   ** utility for accessing SQLite databases.
    14     14   **
    15         -** $Id: shell.c,v 1.151 2006/10/26 14:25:58 drh Exp $
           15  +** $Id: shell.c,v 1.152 2006/10/26 18:15:42 drh Exp $
    16     16   */
    17     17   #include <stdlib.h>
    18     18   #include <string.h>
    19     19   #include <stdio.h>
    20     20   #include <assert.h>
    21     21   #include "sqlite3.h"
    22     22   #include <ctype.h>
................................................................................
    56     56   # include <io.h>
    57     57   #else
    58     58   /* Make sure isatty() has a prototype.
    59     59   */
    60     60   extern int isatty();
    61     61   #endif
    62     62   
           63  +/*
           64  +** If the following flag is set, then command execution stops
           65  +** at an error if we are not interactive.
           66  +*/
           67  +static int bail_on_error = 0;
           68  +
    63     69   /*
    64     70   ** Threat stdin as an interactive input if the following variable
    65     71   ** is true.  Otherwise, assume stdin is connected to a file or pipe.
    66     72   */
    67     73   static int stdin_is_interactive = 1;
    68     74   
    69     75   /*
................................................................................
   349    355       }else{
   350    356         break;
   351    357       }
   352    358       z += i + 1;
   353    359     }
   354    360   }
   355    361   
          362  +/*
          363  +** If a field contains any character identified by a 1 in the following
          364  +** array, then the string must be quoted for CSV.
          365  +*/
          366  +static const char needCsvQuote[] = {
          367  +  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
          368  +  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
          369  +  1, 0, 1, 0, 0, 0, 0, 1,   0, 0, 0, 0, 0, 0, 0, 0, 
          370  +  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0, 
          371  +  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0, 
          372  +  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0, 
          373  +  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0, 
          374  +  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 1, 
          375  +  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
          376  +  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
          377  +  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
          378  +  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
          379  +  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
          380  +  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
          381  +  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
          382  +  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
          383  +};
          384  +
   356    385   /*
   357    386   ** Output a single term of CSV.  Actually, p->separator is used for
   358    387   ** the separator, which may or may not be a comma.  p->nullvalue is
   359    388   ** the null value.  Strings are quoted using ANSI-C rules.  Numbers
   360    389   ** appear outside of quotes.
   361    390   */
   362    391   static void output_csv(struct callback_data *p, const char *z, int bSep){
          392  +  FILE *out = p->out;
   363    393     if( z==0 ){
   364         -    fprintf(p->out,"%s",p->nullvalue);
   365         -  }else if( isNumber(z, 0) ){
   366         -    fprintf(p->out,"%s",z);
          394  +    fprintf(out,"%s",p->nullvalue);
   367    395     }else{
   368         -    output_c_string(p->out, z);
          396  +    int i;
          397  +    for(i=0; z[i]; i++){
          398  +      if( needCsvQuote[((unsigned char*)z)[i]] ){
          399  +        i = 0;
          400  +        break;
          401  +      }
          402  +    }
          403  +    if( i==0 ){
          404  +      putc('"', out);
          405  +      for(i=0; z[i]; i++){
          406  +        if( z[i]=='"' ) putc('"', out);
          407  +        putc(z[i], out);
          408  +      }
          409  +      putc('"', out);
          410  +    }else{
          411  +      fprintf(out, "%s", z);
          412  +    }
   369    413     }
   370    414     if( bSep ){
   371    415       fprintf(p->out, p->separator);
   372    416     }
   373    417   }
   374    418   
   375    419   #ifdef SIGINT
................................................................................
   908    952     }
   909    953   
   910    954     /* Process the input line.
   911    955     */
   912    956     if( nArg==0 ) return rc;
   913    957     n = strlen(azArg[0]);
   914    958     c = azArg[0][0];
          959  +  if( c=='b' && n>1 && strncmp(azArg[0], "bail", n)==0 && nArg>1 ){
          960  +    bail_on_error = booleanValue(azArg[1]);
          961  +  }else
          962  +
   915    963     if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 ){
   916    964       struct callback_data data;
   917    965       char *zErrMsg = 0;
   918    966       open_db(p);
   919    967       memcpy(&data, p, sizeof(data));
   920    968       data.showHeader = 1;
   921    969       data.mode = MODE_Column;
................................................................................
  1472   1520   ** Return the number of errors.
  1473   1521   */
  1474   1522   static int process_input(struct callback_data *p, FILE *in){
  1475   1523     char *zLine;
  1476   1524     char *zSql = 0;
  1477   1525     int nSql = 0;
  1478   1526     char *zErrMsg;
  1479         -  int rc = 0;
         1527  +  int rc;
         1528  +  int errCnt = 0;
  1480   1529     int lineno = 0;
  1481   1530     int startline = 0;
  1482         -  while( fflush(p->out), (zLine = one_input_line(zSql, in))!=0 ){
         1531  +
         1532  +  while( errCnt==0 || !bail_on_error || (in==0 && stdin_is_interactive) ){
         1533  +    fflush(p->out);
         1534  +    zLine = one_input_line(zSql, in);
         1535  +    if( zLine==0 ){
         1536  +      break;  /* We have reached EOF */
         1537  +    }
  1483   1538       if( seenInterrupt ){
  1484   1539         if( in!=0 ) break;
  1485   1540         seenInterrupt = 0;
  1486   1541       }
  1487         -    if( rc && (in!=0 || !stdin_is_interactive) ){
  1488         -      break;
  1489         -    }
  1490   1542       lineno++;
  1491   1543       if( p->echoOn ) printf("%s\n", zLine);
  1492   1544       if( (zSql==0 || zSql[0]==0) && _all_whitespace(zLine) ) continue;
  1493   1545       if( zLine && zLine[0]=='.' && nSql==0 ){
  1494         -      int rc = do_meta_command(zLine, p);
         1546  +      rc = do_meta_command(zLine, p);
  1495   1547         free(zLine);
  1496         -      if( rc ) break;
         1548  +      if( rc ){
         1549  +        errCnt++;
         1550  +      }
  1497   1551         continue;
  1498   1552       }
  1499   1553       if( _is_command_terminator(zLine) ){
  1500   1554         strcpy(zLine,";");
  1501   1555       }
  1502   1556       if( zSql==0 ){
  1503   1557         int i;
................................................................................
  1538   1592           if( zErrMsg!=0 ){
  1539   1593             printf("%s %s\n", zPrefix, zErrMsg);
  1540   1594             sqlite3_free(zErrMsg);
  1541   1595             zErrMsg = 0;
  1542   1596           }else{
  1543   1597             printf("%s %s\n", zPrefix, sqlite3_errmsg(p->db));
  1544   1598           }
         1599  +        errCnt++;
  1545   1600         }
  1546   1601         free(zSql);
  1547   1602         zSql = 0;
  1548   1603         nSql = 0;
  1549   1604       }
  1550   1605     }
  1551   1606     if( zSql ){
  1552   1607       if( !_all_whitespace(zSql) ) printf("Incomplete SQL: %s\n", zSql);
  1553   1608       free(zSql);
  1554   1609     }
  1555         -  return rc;
         1610  +  return errCnt;
  1556   1611   }
  1557   1612   
  1558   1613   /*
  1559   1614   ** Return a pathname which is the user's home directory.  A
  1560   1615   ** 0 return indicates an error of some kind.  Space to hold the
  1561   1616   ** resulting string is obtained from malloc().  The calling
  1562   1617   ** function should free the result.
................................................................................
  1656   1711   /*
  1657   1712   ** Show available command line options
  1658   1713   */
  1659   1714   static const char zOptions[] = 
  1660   1715     "   -init filename       read/process named file\n"
  1661   1716     "   -echo                print commands before execution\n"
  1662   1717     "   -[no]header          turn headers on or off\n"
         1718  +  "   -bail                stop after hitting an error\n"
         1719  +  "   -interactive         force interactive I/O\n"
         1720  +  "   -batch               force batch I/O\n"
  1663   1721     "   -column              set output mode to 'column'\n"
         1722  +  "   -csv                 set output mode to 'csv'\n"
  1664   1723     "   -html                set output mode to HTML\n"
  1665   1724     "   -line                set output mode to 'line'\n"
  1666   1725     "   -list                set output mode to 'list'\n"
  1667   1726     "   -separator 'x'       set output field separator (|)\n"
  1668   1727     "   -nullvalue 'text'    set text string for NULL values\n"
  1669   1728     "   -version             show SQLite version\n"
  1670   1729   ;
................................................................................
  1782   1841         data.mode = MODE_Html;
  1783   1842       }else if( strcmp(z,"-list")==0 ){
  1784   1843         data.mode = MODE_List;
  1785   1844       }else if( strcmp(z,"-line")==0 ){
  1786   1845         data.mode = MODE_Line;
  1787   1846       }else if( strcmp(z,"-column")==0 ){
  1788   1847         data.mode = MODE_Column;
         1848  +    }else if( strcmp(z,"-csv")==0 ){
         1849  +      data.mode = MODE_Csv;
         1850  +      strcpy(data.separator,",");
  1789   1851       }else if( strcmp(z,"-separator")==0 ){
  1790   1852         i++;
  1791   1853         sprintf(data.separator,"%.*s",(int)sizeof(data.separator)-1,argv[i]);
  1792   1854       }else if( strcmp(z,"-nullvalue")==0 ){
  1793   1855         i++;
  1794   1856         sprintf(data.nullvalue,"%.*s",(int)sizeof(data.nullvalue)-1,argv[i]);
  1795   1857       }else if( strcmp(z,"-header")==0 ){
  1796   1858         data.showHeader = 1;
  1797   1859       }else if( strcmp(z,"-noheader")==0 ){
  1798   1860         data.showHeader = 0;
  1799   1861       }else if( strcmp(z,"-echo")==0 ){
  1800   1862         data.echoOn = 1;
         1863  +    }else if( strcmp(z,"-bail")==0 ){
         1864  +      bail_on_error = 1;
  1801   1865       }else if( strcmp(z,"-version")==0 ){
  1802   1866         printf("%s\n", sqlite3_libversion());
  1803   1867         return 0;
  1804   1868       }else if( strcmp(z,"-interactive")==0 ){
  1805   1869         stdin_is_interactive = 1;
  1806   1870       }else if( strcmp(z,"-batch")==0 ){
  1807   1871         stdin_is_interactive = 0;