SQLite

Check-in [419ce0ed89]
Login

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

Overview
Comment:Modify CLI to optionally display "stats".
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 419ce0ed89d10252492b2926817259899ee74e71
User & Date: shaneh 2010-07-28 16:05:35.000
Context
2010-07-28
17:01
Record the pcache allocation size statistics even for pcache overflow allocations. Adjust the wording on one of the stat output lines in the shell. (check-in: f9adf66ad5 user: drh tags: trunk)
16:05
Modify CLI to optionally display "stats". (check-in: 419ce0ed89 user: shaneh tags: trunk)
15:52
Lookaside memory is not used to store schemas. Change the SQLITE_DBSATUS_SCHEMA_USED documentation to reflect this fact. (check-in: 07abfd5268 user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/shell.c.
394
395
396
397
398
399
400

401
402
403
404
405
406
407
** An pointer to an instance of this structure is passed from
** the main program to the callback.  This is used to communicate
** state and mode information.
*/
struct callback_data {
  sqlite3 *db;           /* The database */
  int echoOn;            /* True to echo input commands */

  int cnt;               /* Number of records displayed so far */
  FILE *out;             /* Write results here */
  int mode;              /* An output mode setting */
  int writableSchema;    /* True if PRAGMA writable_schema=ON */
  int showHeader;        /* True to show column names in List or Column mode */
  char *zDestTable;      /* Name of destination table when MODE_Insert */
  char separator[20];    /* Separator character for MODE_List */







>







394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
** An pointer to an instance of this structure is passed from
** the main program to the callback.  This is used to communicate
** state and mode information.
*/
struct callback_data {
  sqlite3 *db;           /* The database */
  int echoOn;            /* True to echo input commands */
  int statsOn;           /* True to display memory stats before each finalize */
  int cnt;               /* Number of records displayed so far */
  FILE *out;             /* Write results here */
  int mode;              /* An output mode setting */
  int writableSchema;    /* True if PRAGMA writable_schema=ON */
  int showHeader;        /* True to show column names in List or Column mode */
  char *zDestTable;      /* Name of destination table when MODE_Insert */
  char separator[20];    /* Separator character for MODE_List */
956
957
958
959
960
961
962
















































































963
964
965
966
967
968
969
  int nErrMsg = 1+strlen30(sqlite3_errmsg(db));
  char *zErrMsg = sqlite3_malloc(nErrMsg);
  if( zErrMsg ){
    memcpy(zErrMsg, sqlite3_errmsg(db), nErrMsg);
  }
  return zErrMsg;
}

















































































/*
** Execute a statement or set of statements.  Print 
** any result rows/columns depending on the current mode 
** set via the supplied callback.
**
** This is very similar to SQLite's built-in sqlite3_exec() 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
  int nErrMsg = 1+strlen30(sqlite3_errmsg(db));
  char *zErrMsg = sqlite3_malloc(nErrMsg);
  if( zErrMsg ){
    memcpy(zErrMsg, sqlite3_errmsg(db), nErrMsg);
  }
  return zErrMsg;
}

/*
** Display memory stats.
*/
static int display_stats(
  sqlite3 *db,                /* Database to query */
  struct callback_data *pArg, /* Pointer to struct callback_data */
  int bReset                  /* True to reset the stats */
){
  int iCur;
  int iHiwtr;

  if( pArg && pArg->out ){
    
    iHiwtr = iCur = -1;
    sqlite3_status(SQLITE_STATUS_MEMORY_USED, &iCur, &iHiwtr, bReset);
    fprintf(pArg->out, "Mem Used (Excludes Scratch/Pcache):  %d (max %d) bytes\n", iCur, iHiwtr);
    iHiwtr = iCur = -1;
    sqlite3_status(SQLITE_STATUS_MALLOC_COUNT, &iCur, &iHiwtr, bReset);
    fprintf(pArg->out, "Number of Allocations:               %d (max %d)\n", iCur, iHiwtr);
/*
** Not currently used by the CLI.
**    iHiwtr = iCur = -1;
**    sqlite3_status(SQLITE_STATUS_PAGECACHE_USED, &iCur, &iHiwtr, bReset);
**    fprintf(pArg->out, "Number of Pcache Pages Used:         %d (max %d) pages\n", iCur, iHiwtr);
*/
    iHiwtr = iCur = -1;
    sqlite3_status(SQLITE_STATUS_PAGECACHE_OVERFLOW, &iCur, &iHiwtr, bReset);
    fprintf(pArg->out, "Number of Pcache Overflow Bytes:     %d (max %d) bytes\n", iCur, iHiwtr);
/*
** Not currently used by the CLI.
**    iHiwtr = iCur = -1;
**    sqlite3_status(SQLITE_STATUS_SCRATCH_USED, &iCur, &iHiwtr, bReset);
**    fprintf(pArg->out, "Number of Scratch Allocations Used:  %d (max %d)\n", iCur, iHiwtr);
*/
    iHiwtr = iCur = -1;
    sqlite3_status(SQLITE_STATUS_SCRATCH_OVERFLOW, &iCur, &iHiwtr, bReset);
    fprintf(pArg->out, "Number of Scratch Overflow Bytes:    %d (max %d) bytes\n", iCur, iHiwtr);
    iHiwtr = iCur = -1;
    sqlite3_status(SQLITE_STATUS_MALLOC_SIZE, &iCur, &iHiwtr, bReset);
    fprintf(pArg->out, "Largest Allocation:                  %d bytes\n", iHiwtr);
    iHiwtr = iCur = -1;
    sqlite3_status(SQLITE_STATUS_PAGECACHE_SIZE, &iCur, &iHiwtr, bReset);
    fprintf(pArg->out, "Largest Pcache Allocation:           %d bytes\n", iHiwtr);
    iHiwtr = iCur = -1;
    sqlite3_status(SQLITE_STATUS_SCRATCH_SIZE, &iCur, &iHiwtr, bReset);
    fprintf(pArg->out, "Largest Scratch Allocation:          %d bytes\n", iHiwtr);
#ifdef YYTRACKMAXSTACKDEPTH
    iHiwtr = iCur = -1;
    sqlite3_status(SQLITE_STATUS_PARSER_STACK, &iCur, &iHiwtr, bReset);
    fprintf(pArg->out, "Deepest Parser Stack:                %d (max %d)\n", iCur, iHiwtr);
#endif
  }

  if( pArg && pArg->out && db ){
    iHiwtr = iCur = -1;
    sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_USED, &iCur, &iHiwtr, bReset);
    fprintf(pArg->out, "Lookaside Slots Used:                %d (max %d)\n", iCur, iHiwtr);
    iHiwtr = iCur = -1;
    sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_USED, &iCur, &iHiwtr, bReset);
    fprintf(pArg->out, "Pcache Heap Usage:                   %d bytes\n", iCur); 
    iHiwtr = iCur = -1;
    sqlite3_db_status(db, SQLITE_DBSTATUS_SCHEMA_USED, &iCur, &iHiwtr, bReset);
    fprintf(pArg->out, "Schema Heap Usage:                   %d bytes\n", iCur); 
    iHiwtr = iCur = -1;
    sqlite3_db_status(db, SQLITE_DBSTATUS_STMT_USED, &iCur, &iHiwtr, bReset);
    fprintf(pArg->out, "Statement Heap/Lookaside Usage:      %d bytes\n", iCur); 
  }

  if( pArg && pArg->out && db && pArg->pStmt ){
    iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP, bReset);
    fprintf(pArg->out, "Fullscan Steps:                      %d\n", iCur);
    iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_SORT, bReset);
    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);
  }

  return 0;
}

/*
** Execute a statement or set of statements.  Print 
** any result rows/columns depending on the current mode 
** set via the supplied callback.
**
** This is very similar to SQLite's built-in sqlite3_exec() 
995
996
997
998
999
1000
1001
1002






1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
    }else{
      if( !pStmt ){
        /* this happens for a comment or white-space */
        zSql = zLeftover;
        while( isspace(zSql[0]) ) zSql++;
        continue;
      }







      /* echo the sql statement if echo on */
      if( pArg->echoOn ){
        const char *zStmtSql = sqlite3_sql(pStmt);
        fprintf(pArg->out,"%s\n", zStmtSql ? zStmtSql : zSql);
      }

      /* perform the first step.  this will tell us if we
      ** have a result set or not and how wide it is.
      */
      rc = sqlite3_step(pStmt);
      /* if we have a result set... */








>
>
>
>
>
>

|

|







1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
    }else{
      if( !pStmt ){
        /* this happens for a comment or white-space */
        zSql = zLeftover;
        while( isspace(zSql[0]) ) zSql++;
        continue;
      }

      /* save off the prepared statment handle and reset row count */
      if( pArg ){
        pArg->pStmt = pStmt;
        pArg->cnt = 0;
      }

      /* echo the sql statement if echo on */
      if( pArg && pArg->echoOn ){
        const char *zStmtSql = sqlite3_sql(pStmt);
        fprintf(pArg->out, "%s\n", zStmtSql ? zStmtSql : zSql);
      }

      /* perform the first step.  this will tell us if we
      ** have a result set or not and how wide it is.
      */
      rc = sqlite3_step(pStmt);
      /* if we have a result set... */
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
            int *aiTypes = (int *)&azVals[nCol]; /* Result types */
            int i;
            assert(sizeof(int) <= sizeof(char *)); 
            /* save off ptrs to column names */
            for(i=0; i<nCol; i++){
              azCols[i] = (char *)sqlite3_column_name(pStmt, i);
            }
            /* save off the prepared statment handle and reset row count */
            if( pArg ){
              pArg->pStmt = pStmt;
              pArg->cnt = 0;
            }
            do{
              /* extract the data and data types */
              for(i=0; i<nCol; i++){
                azVals[i] = (char *)sqlite3_column_text(pStmt, i);
                aiTypes[i] = sqlite3_column_type(pStmt, i);
                if( !azVals[i] && (aiTypes[i]!=SQLITE_NULL) ){
                  rc = SQLITE_NOMEM;







<
<
<
<
<







1112
1113
1114
1115
1116
1117
1118





1119
1120
1121
1122
1123
1124
1125
            int *aiTypes = (int *)&azVals[nCol]; /* Result types */
            int i;
            assert(sizeof(int) <= sizeof(char *)); 
            /* save off ptrs to column names */
            for(i=0; i<nCol; i++){
              azCols[i] = (char *)sqlite3_column_name(pStmt, i);
            }





            do{
              /* extract the data and data types */
              for(i=0; i<nCol; i++){
                azVals[i] = (char *)sqlite3_column_text(pStmt, i);
                aiTypes[i] = sqlite3_column_type(pStmt, i);
                if( !azVals[i] && (aiTypes[i]!=SQLITE_NULL) ){
                  rc = SQLITE_NOMEM;
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068





1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079





1080
1081
1082
1083
1084
1085
1086
                  rc = SQLITE_ABORT;
                }else{
                  rc = sqlite3_step(pStmt);
                }
              }
            } while( SQLITE_ROW == rc );
            sqlite3_free(pData);
            if( pArg ){
              pArg->pStmt = NULL;
            }
          }
        }else{
          do{
            rc = sqlite3_step(pStmt);
          } while( rc == SQLITE_ROW );
        }
      }






      /* Finalize the statement just executed. If this fails, save a 
      ** copy of the error message. Otherwise, set zSql to point to the
      ** next statement to execute. */
      rc = sqlite3_finalize(pStmt);
      if( rc==SQLITE_OK ){
        zSql = zLeftover;
        while( isspace(zSql[0]) ) zSql++;
      }else if( pzErrMsg ){
        *pzErrMsg = save_err_msg(db);
      }





    }
  } /* end while */

  return rc;
}









<
<
<







>
>
>
>
>











>
>
>
>
>







1134
1135
1136
1137
1138
1139
1140



1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
                  rc = SQLITE_ABORT;
                }else{
                  rc = sqlite3_step(pStmt);
                }
              }
            } while( SQLITE_ROW == rc );
            sqlite3_free(pData);



          }
        }else{
          do{
            rc = sqlite3_step(pStmt);
          } while( rc == SQLITE_ROW );
        }
      }

      /* print usage stats if stats on */
      if( pArg && pArg->statsOn ){
        display_stats(db, pArg, 0);
      }

      /* Finalize the statement just executed. If this fails, save a 
      ** copy of the error message. Otherwise, set zSql to point to the
      ** next statement to execute. */
      rc = sqlite3_finalize(pStmt);
      if( rc==SQLITE_OK ){
        zSql = zLeftover;
        while( isspace(zSql[0]) ) zSql++;
      }else if( pzErrMsg ){
        *pzErrMsg = save_err_msg(db);
      }

      /* clear saved stmt handle */
      if( pArg ){
        pArg->pStmt = NULL;
      }
    }
  } /* end while */

  return rc;
}


1252
1253
1254
1255
1256
1257
1258

1259
1260
1261
1262
1263
1264
1265
  ".read FILENAME         Execute SQL in FILENAME\n"
  ".restore ?DB? FILE     Restore content of DB (default \"main\") from FILE\n"
  ".schema ?TABLE?        Show the CREATE statements\n"
  "                         If TABLE specified, only show tables matching\n"
  "                         LIKE pattern TABLE.\n"
  ".separator STRING      Change separator used by output mode and .import\n"
  ".show                  Show the current values for various settings\n"

  ".tables ?TABLE?        List names of tables\n"
  "                         If TABLE specified, only list tables matching\n"
  "                         LIKE pattern TABLE.\n"
  ".timeout MS            Try opening locked tables for MS milliseconds\n"
  ".width NUM1 NUM2 ...   Set column widths for \"column\" mode\n"
;








>







1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
  ".read FILENAME         Execute SQL in FILENAME\n"
  ".restore ?DB? FILE     Restore content of DB (default \"main\") from FILE\n"
  ".schema ?TABLE?        Show the CREATE statements\n"
  "                         If TABLE specified, only show tables matching\n"
  "                         LIKE pattern TABLE.\n"
  ".separator STRING      Change separator used by output mode and .import\n"
  ".show                  Show the current values for various settings\n"
  ".stats ON|OFF          Turn stats on or off\n"
  ".tables ?TABLE?        List names of tables\n"
  "                         If TABLE specified, only list tables matching\n"
  "                         LIKE pattern TABLE.\n"
  ".timeout MS            Try opening locked tables for MS milliseconds\n"
  ".width NUM1 NUM2 ...   Set column widths for \"column\" mode\n"
;

1997
1998
1999
2000
2001
2002
2003

2004
2005
2006
2007
2008
2009




2010
2011
2012
2013
2014
2015
2016
      output_c_string(p->out, p->nullvalue);
      fprintf(p->out, "\n");
    fprintf(p->out,"%9.9s: %s\n","output",
            strlen30(p->outfile) ? p->outfile : "stdout");
    fprintf(p->out,"%9.9s: ", "separator");
      output_c_string(p->out, p->separator);
      fprintf(p->out, "\n");

    fprintf(p->out,"%9.9s: ","width");
    for (i=0;i<(int)ArraySize(p->colWidth) && p->colWidth[i] != 0;i++) {
      fprintf(p->out,"%d ",p->colWidth[i]);
    }
    fprintf(p->out,"\n");
  }else





  if( c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0 && nArg<3 ){
    char **azResult;
    int nRow;
    char *zErrMsg;
    open_db(p);
    if( nArg==1 ){







>






>
>
>
>







2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
      output_c_string(p->out, p->nullvalue);
      fprintf(p->out, "\n");
    fprintf(p->out,"%9.9s: %s\n","output",
            strlen30(p->outfile) ? p->outfile : "stdout");
    fprintf(p->out,"%9.9s: ", "separator");
      output_c_string(p->out, p->separator);
      fprintf(p->out, "\n");
    fprintf(p->out,"%9.9s: %s\n","stats", p->statsOn ? "on" : "off");
    fprintf(p->out,"%9.9s: ","width");
    for (i=0;i<(int)ArraySize(p->colWidth) && p->colWidth[i] != 0;i++) {
      fprintf(p->out,"%d ",p->colWidth[i]);
    }
    fprintf(p->out,"\n");
  }else

  if( c=='s' && strncmp(azArg[0], "stats", n)==0 && nArg>1 && nArg<3 ){
    p->statsOn = booleanValue(azArg[1]);
  }else

  if( c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0 && nArg<3 ){
    char **azResult;
    int nRow;
    char *zErrMsg;
    open_db(p);
    if( nArg==1 ){
2387
2388
2389
2390
2391
2392
2393

2394
2395
2396
2397
2398
2399
2400
  "   -batch               force batch I/O\n"
  "   -column              set output mode to 'column'\n"
  "   -csv                 set output mode to 'csv'\n"
  "   -html                set output mode to HTML\n"
  "   -line                set output mode to 'line'\n"
  "   -list                set output mode to 'list'\n"
  "   -separator 'x'       set output field separator (|)\n"

  "   -nullvalue 'text'    set text string for NULL values\n"
  "   -version             show SQLite version\n"
;
static void usage(int showDetail){
  fprintf(stderr,
      "Usage: %s [OPTIONS] FILENAME [SQL]\n"  
      "FILENAME is the name of an SQLite database. A new database is created\n"







>







2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
  "   -batch               force batch I/O\n"
  "   -column              set output mode to 'column'\n"
  "   -csv                 set output mode to 'csv'\n"
  "   -html                set output mode to HTML\n"
  "   -line                set output mode to 'line'\n"
  "   -list                set output mode to 'list'\n"
  "   -separator 'x'       set output field separator (|)\n"
  "   -stats               print memory stats before each finalize\n"
  "   -nullvalue 'text'    set text string for NULL values\n"
  "   -version             show SQLite version\n"
;
static void usage(int showDetail){
  fprintf(stderr,
      "Usage: %s [OPTIONS] FILENAME [SQL]\n"  
      "FILENAME is the name of an SQLite database. A new database is created\n"
2551
2552
2553
2554
2555
2556
2557


2558
2559
2560
2561
2562
2563
2564
                       "%.*s",(int)sizeof(data.nullvalue)-1,argv[i]);
    }else if( strcmp(z,"-header")==0 ){
      data.showHeader = 1;
    }else if( strcmp(z,"-noheader")==0 ){
      data.showHeader = 0;
    }else if( strcmp(z,"-echo")==0 ){
      data.echoOn = 1;


    }else if( strcmp(z,"-bail")==0 ){
      bail_on_error = 1;
    }else if( strcmp(z,"-version")==0 ){
      printf("%s\n", sqlite3_libversion());
      return 0;
    }else if( strcmp(z,"-interactive")==0 ){
      stdin_is_interactive = 1;







>
>







2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
                       "%.*s",(int)sizeof(data.nullvalue)-1,argv[i]);
    }else if( strcmp(z,"-header")==0 ){
      data.showHeader = 1;
    }else if( strcmp(z,"-noheader")==0 ){
      data.showHeader = 0;
    }else if( strcmp(z,"-echo")==0 ){
      data.echoOn = 1;
    }else if( strcmp(z,"-stats")==0 ){
      data.statsOn = 1;
    }else if( strcmp(z,"-bail")==0 ){
      bail_on_error = 1;
    }else if( strcmp(z,"-version")==0 ){
      printf("%s\n", sqlite3_libversion());
      return 0;
    }else if( strcmp(z,"-interactive")==0 ){
      stdin_is_interactive = 1;
Changes to tool/shell1.test.
173
174
175
176
177
178
179





180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
} {0 {}}
do_test shell1-1.14.3 {
  set res [catchcmd "-separator" ""]
  set rc [lindex $res 0]
  list $rc \
       [regexp {Error: missing argument for option: -separator} $res]
} {1 1}






# -nullvalue 'text'    set text string for NULL values
do_test shell1-1.15.1 {
  catchcmd "-nullvalue 'x' test.db" ""
} {0 {}}
do_test shell1-1.15.2 {
  catchcmd "-nullvalue x test.db" ""
} {0 {}}
do_test shell1-1.15.3 {
  set res [catchcmd "-nullvalue" ""]
  set rc [lindex $res 0]
  list $rc \
       [regexp {Error: missing argument for option: -nullvalue} $res]
} {1 1}

# -version             show SQLite version
do_test shell1-1.16.1 {
  catchcmd "-version test.db" "" 
} {0 3.7.0}

#----------------------------------------------------------------------------
# Test cases shell1-2.*: Basic "dot" command token parsing.
#

# check first token handling
do_test shell1-2.1.1 {







>
>
>
>
>


















|







173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
} {0 {}}
do_test shell1-1.14.3 {
  set res [catchcmd "-separator" ""]
  set rc [lindex $res 0]
  list $rc \
       [regexp {Error: missing argument for option: -separator} $res]
} {1 1}

# -stats               print memory stats before each finalize
do_test shell1-1.14b.1 {
  catchcmd "-stats test.db" "" 
} {0 {}}

# -nullvalue 'text'    set text string for NULL values
do_test shell1-1.15.1 {
  catchcmd "-nullvalue 'x' test.db" ""
} {0 {}}
do_test shell1-1.15.2 {
  catchcmd "-nullvalue x test.db" ""
} {0 {}}
do_test shell1-1.15.3 {
  set res [catchcmd "-nullvalue" ""]
  set rc [lindex $res 0]
  list $rc \
       [regexp {Error: missing argument for option: -nullvalue} $res]
} {1 1}

# -version             show SQLite version
do_test shell1-1.16.1 {
  catchcmd "-version test.db" "" 
} {0 3.7.1}

#----------------------------------------------------------------------------
# Test cases shell1-2.*: Basic "dot" command token parsing.
#

# check first token handling
do_test shell1-2.1.1 {
617
618
619
620
621
622
623

624
625
626
627
628
629
630















631
632
633
634
635
636
637
  list [regexp {echo:} $res] \
       [regexp {explain:} $res] \
       [regexp {headers:} $res] \
       [regexp {mode:} $res] \
       [regexp {nullvalue:} $res] \
       [regexp {output:} $res] \
       [regexp {separator:} $res] \

       [regexp {width:} $res]
} {1 1 1 1 1 1 1 1}
do_test shell1-3.23.2 {
  # too many arguments
  catchcmd "test.db" ".show BAD"
} {1 {Error: unknown command or invalid arguments:  "show". Enter ".help" for help}}
















# .tables ?TABLE?        List names of tables
#                          If TABLE specified, only list tables matching
#                          LIKE pattern TABLE.
do_test shell1-3.24.1 {
  catchcmd "test.db" ".tables"
} {0 {}}
do_test shell1-3.24.2 {







>

|





>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
  list [regexp {echo:} $res] \
       [regexp {explain:} $res] \
       [regexp {headers:} $res] \
       [regexp {mode:} $res] \
       [regexp {nullvalue:} $res] \
       [regexp {output:} $res] \
       [regexp {separator:} $res] \
       [regexp {stats:} $res] \
       [regexp {width:} $res]
} {1 1 1 1 1 1 1 1 1}
do_test shell1-3.23.2 {
  # too many arguments
  catchcmd "test.db" ".show BAD"
} {1 {Error: unknown command or invalid arguments:  "show". Enter ".help" for help}}

# .stats ON|OFF          Turn stats on or off
do_test shell1-3.23b.1 {
  catchcmd "test.db" ".stats"
} {1 {Error: unknown command or invalid arguments:  "stats". Enter ".help" for help}}
do_test shell1-3.23b.2 {
  catchcmd "test.db" ".stats ON"
} {0 {}}
do_test shell1-3.23b.3 {
  catchcmd "test.db" ".stats OFF"
} {0 {}}
do_test shell1-3.23b.4 {
  # too many arguments
  catchcmd "test.db" ".stats OFF BAD"
} {1 {Error: unknown command or invalid arguments:  "stats". Enter ".help" for help}}

# .tables ?TABLE?        List names of tables
#                          If TABLE specified, only list tables matching
#                          LIKE pattern TABLE.
do_test shell1-3.24.1 {
  catchcmd "test.db" ".tables"
} {0 {}}
do_test shell1-3.24.2 {
Added tool/shell4.test.
























































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# 2010 July 28
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#
# The focus of this file is testing the CLI shell tool.
#
# $Id: shell4.test,v 1.7 2009/07/17 16:54:48 shaneh Exp $
#

# Test plan:
#
#   shell4-1.*: Basic tests specific to the "stats" command.
#

package require sqlite3

set CLI "./sqlite3"

proc do_test {name cmd expected} {
  puts -nonewline "$name ..."
  set res [uplevel $cmd]
  if {$res eq $expected} {
    puts Ok
  } else {
    puts Error
    puts "  Got: $res"
    puts "  Expected: $expected"
    exit
  }
}

proc execsql {sql} {
  uplevel [list db eval $sql]
}

proc catchsql {sql} {
  set rc [catch {uplevel [list db eval $sql]} msg]
  list $rc $msg
}

proc catchcmd {db {cmd ""}} {
  global CLI
  set out [open cmds.txt w]
  puts $out $cmd
  close $out
  set line "exec $CLI $db < cmds.txt"
  set rc [catch { eval $line } msg]
  list $rc $msg
}

file delete -force test.db test.db.journal
sqlite3 db test.db

#----------------------------------------------------------------------------
# Test cases shell4-1.*: Tests specific to the "stats" command.
#

# should default to off
do_test shell4-1.1.1 {
  set res [catchcmd "test.db" ".show"]
  list [regexp {stats: off} $res]
} {1}

do_test shell4-1.1.2 {
  set res [catchcmd "test.db" ".show"]
  list [regexp {stats: on} $res]
} {0}

# -stats should turn it on
do_test shell4-1.2.1 {
  set res [catchcmd "-stats test.db" ".show"]
  list [regexp {stats: on} $res]
} {1}

do_test shell4-1.2.2 {
  set res [catchcmd "-stats test.db" ".show"]
  list [regexp {stats: off} $res]
} {0}

# .stats ON|OFF          Turn stats on or off
do_test shell4-1.3.1 {
  catchcmd "test.db" ".stats"
} {1 {Error: unknown command or invalid arguments:  "stats". Enter ".help" for help}}
do_test shell4-1.3.2 {
  catchcmd "test.db" ".stats ON"
} {0 {}}
do_test shell4-1.3.3 {
  catchcmd "test.db" ".stats OFF"
} {0 {}}
do_test shell4-1.3.4 {
  # too many arguments
  catchcmd "test.db" ".stats OFF BAD"
} {1 {Error: unknown command or invalid arguments:  "stats". Enter ".help" for help}}

# NB. whitespace is important
do_test shell4-1.4.1 {
  set res [catchcmd "test.db" {.show}]
  list [regexp {stats: off} $res]
} {1}

do_test shell4-1.4.2 {
  set res [catchcmd "test.db" {.stats ON
.show
}]
  list [regexp {stats: on} $res]
} {1}

do_test shell4-1.4.3 {
  set res [catchcmd "test.db" {.stats OFF
.show
}]
  list [regexp {stats: off} $res]
} {1}

# make sure stats not present when off
do_test shell4-1.5.1 {
  set res [catchcmd "test.db" {SELECT 1;}]
  list [regexp {Mem Used} $res] \
       [regexp {Heap Usage} $res] \
       [regexp {Autoindex Inserts} $res]
} {0 0 0}

# make sure stats are present when on
do_test shell4-1.5.2 {
  set res [catchcmd "test.db" {.stats ON
SELECT 1;
}]
  list [regexp {Mem Used} $res] \
       [regexp {Heap Usage} $res] \
       [regexp {Autoindex Inserts} $res]
} {1 1 1}

puts "CLI tests completed successfully"