-C Omit\sthe\ssqlite3Apis\sconstant\sobject\swhen\scompiling\swith\nSQLITE_OMIT_LOAD_EXTENSION,\ssince\sit\sis\snot\sused.
-D 2016-09-15T19:15:19.226
+C Add\sthe\s".testcase"\sand\s".check"\sdot-commands\sin\sthe\sshell,\swhen\scompiled\nusing\sSQLITE_DEBUG.
+D 2016-09-15T21:35:24.532
F Makefile.in 6fd48ffcf7c2deea7499062d1f3747f986c19678
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
F Makefile.msc e1aa788e84f926e42239ee167c53f785bedacacd
F src/resolve.c 24f40fd0c3475821d1ad762a3f2c3455cc839b42
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
F src/select.c 244f9cc5e4662987cd2ef5c22d1b7027560f3425
-F src/shell.c de7c7e98846cacbfbe062cbd98bca899dfb720e3
+F src/shell.c 89a3adbfcaac17070372ce631161bbbf21ec2010
F src/sqlite.h.in 46ed821aeed0ba45559fb15597d9a400083154a2
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 8648034aa702469afb553231677306cc6492a1ae
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P b9f5bdbf40ac6382e48f09ebcd53cc908e065527
-R 1e31cb38dfd2c7bbbb492df3fcbfb729
+P 7b10461370828b9c57acaaaea518031d53986fa3
+R 1d8691a695a03272769e683d2ed4d0b4
U drh
-Z 8ce374e092d6c15d6e5f3b801f1063a4
+Z 15bb0e2011d42f4d3abf5a593439e046
".bail on|off Stop after hitting an error. Default OFF\n"
".binary on|off Turn binary output on or off. Default OFF\n"
".changes on|off Show number of rows changed by SQL\n"
+#ifdef SQLITE_DEBUG
+ ".check GLOB Fail if output since .testcase does not match\n"
+#endif
".clone NEWDB Clone data into NEWDB from the existing database\n"
".databases List names and files of attached databases\n"
".dbinfo ?DB? Show status information about the database\n"
".tables ?TABLE? List names of tables\n"
" If TABLE specified, only list tables matching\n"
" LIKE pattern TABLE.\n"
+#ifdef SQLITE_DEBUG
+ ".testcase Begin redirecting output to 'testcase-out.txt'\n"
+#endif
".timeout MS Try opening locked tables for MS milliseconds\n"
".timer on|off Turn SQL timer on or off\n"
".trace FILE|off Output each SQL statement as it is run\n"
/* Forward reference */
static int process_input(ShellState *p, FILE *in);
+
+
+/*
+** Read the content of a file into memory obtained from sqlite3_malloc64().
+** The caller is responsible for freeing the memory.
+**
+** NULL is returned if any error is encountered.
+*/
+static char *readFile(const char *zName){
+ FILE *in = fopen(zName, "rb");
+ long nIn;
+ char *pBuf;
+ if( in==0 ) return 0;
+ fseek(in, 0, SEEK_END);
+ nIn = ftell(in);
+ rewind(in);
+ pBuf = sqlite3_malloc64( nIn );
+ if( pBuf==0 ) return 0;
+ if( 1!=fread(pBuf, nIn, 1, in) ){
+ sqlite3_free(pBuf);
+ return 0;
+ }
+ return pBuf;
+}
+
/*
** Implementation of the "readfile(X)" SQL function. The entire content
** of the file named X is read and returned as a BLOB. NULL is returned
sqlite3_value **argv
){
const char *zName;
- FILE *in;
- long nIn;
void *pBuf;
UNUSED_PARAMETER(argc);
zName = (const char*)sqlite3_value_text(argv[0]);
if( zName==0 ) return;
- in = fopen(zName, "rb");
- if( in==0 ) return;
- fseek(in, 0, SEEK_END);
- nIn = ftell(in);
- rewind(in);
- pBuf = sqlite3_malloc64( nIn );
- if( pBuf && 1==fread(pBuf, nIn, 1, in) ){
- sqlite3_result_blob(context, pBuf, nIn, sqlite3_free);
- }else{
- sqlite3_free(pBuf);
- }
- fclose(in);
+ pBuf = readFile(zName);
+ if( pBuf ) sqlite3_result_blob(context, pBuf, -1, sqlite3_free);
}
/*
return 1;
}
+#ifdef SQLITE_DEBUG
+/*
+** Compare the pattern in zGlob[] against the text in z[]. Return TRUE
+** if they match and FALSE (0) if they do not match.
+**
+** Globbing rules:
+**
+** '*' Matches any sequence of zero or more characters.
+**
+** '?' Matches exactly one character.
+**
+** [...] Matches one character from the enclosed list of
+** characters.
+**
+** [^...] Matches one character not in the enclosed list.
+**
+** '#' Matches any sequence of one or more digits with an
+** optional + or - sign in front
+**
+** ' ' Any span of whitespace matches any other span of
+** whitespace.
+**
+** Extra whitespace at the end of z[] is ignored.
+*/
+static int testcase_glob(const char *zGlob, const char *z){
+ int c, c2;
+ int invert;
+ int seen;
+
+ while( (c = (*(zGlob++)))!=0 ){
+ if( IsSpace(c) ){
+ if( !IsSpace(*z) ) return 0;
+ while( IsSpace(*zGlob) ) zGlob++;
+ while( IsSpace(*z) ) z++;
+ }else if( c=='*' ){
+ while( (c=(*(zGlob++))) == '*' || c=='?' ){
+ if( c=='?' && (*(z++))==0 ) return 0;
+ }
+ if( c==0 ){
+ return 1;
+ }else if( c=='[' ){
+ while( *z && testcase_glob(zGlob-1,z)==0 ){
+ z++;
+ }
+ return (*z)!=0;
+ }
+ while( (c2 = (*(z++)))!=0 ){
+ while( c2!=c ){
+ c2 = *(z++);
+ if( c2==0 ) return 0;
+ }
+ if( testcase_glob(zGlob,z) ) return 1;
+ }
+ return 0;
+ }else if( c=='?' ){
+ if( (*(z++))==0 ) return 0;
+ }else if( c=='[' ){
+ int prior_c = 0;
+ seen = 0;
+ invert = 0;
+ c = *(z++);
+ if( c==0 ) return 0;
+ c2 = *(zGlob++);
+ if( c2=='^' ){
+ invert = 1;
+ c2 = *(zGlob++);
+ }
+ if( c2==']' ){
+ if( c==']' ) seen = 1;
+ c2 = *(zGlob++);
+ }
+ while( c2 && c2!=']' ){
+ if( c2=='-' && zGlob[0]!=']' && zGlob[0]!=0 && prior_c>0 ){
+ c2 = *(zGlob++);
+ if( c>=prior_c && c<=c2 ) seen = 1;
+ prior_c = 0;
+ }else{
+ if( c==c2 ){
+ seen = 1;
+ }
+ prior_c = c2;
+ }
+ c2 = *(zGlob++);
+ }
+ if( c2==0 || (seen ^ invert)==0 ) return 0;
+ }else if( c=='#' ){
+ if( (z[0]=='-' || z[0]=='+') && IsDigit(z[1]) ) z++;
+ if( !IsDigit(z[0]) ) return 0;
+ z++;
+ while( IsDigit(z[0]) ){ z++; }
+ }else{
+ if( c!=(*(z++)) ) return 0;
+ }
+ }
+ while( IsSpace(*z) ){ z++; }
+ return *z==0;
+}
+#endif /* defined(SQLITE_DEBUG) */
+
+
/*
** Compare the string as a command-line option with either one or two
** initial "-" characters.
}
}else
+#ifdef SQLITE_DEBUG
+ /* Cancel output redirection, if it is currently set (by .testcase)
+ ** Then read the content of the testcase-out.txt file and compare against
+ ** azArg[1]. If there are differences, report an error and exit.
+ */
+ if( c=='c' && n>=3 && strncmp(azArg[0], "check", n)==0 ){
+ char *zRes = 0;
+ output_reset(p);
+ if( nArg!=2 ){
+ raw_printf(stderr, "Usage: .check GLOB-PATTERN\n");
+ rc = 1;
+ }else if( (zRes = readFile("testcase-out.txt"))==0 ){
+ raw_printf(stderr, "Error: cannot read 'testcase-out.txt'\n");
+ rc = 2;
+ }else if( testcase_glob(azArg[1],zRes)==0 ){
+ raw_printf(stderr, ".check failed\n Expected: [%s]\n Got: [%s]\n",
+ azArg[1], zRes);
+ rc = 2;
+ }
+ sqlite3_free(zRes);
+ }else
+#endif
+
if( c=='c' && strncmp(azArg[0], "clone", n)==0 ){
if( nArg==2 ){
tryToClone(p, azArg[1]);
sqlite3_free(azResult);
}else
+#ifdef SQLITE_DEBUG
+ /* Begin redirecting output to the file "testcase-out.txt" */
+ if( c=='t' && strcmp(azArg[0],"testcase")==0 ){
+ output_reset(p);
+ p->out = output_file_open("testcase-out.txt");
+ if( p->out==0 ){
+ utf8_printf(stderr, "Error: cannot open 'testcase-out.txt'\n");
+ }
+ }else
+#endif
+
if( c=='t' && n>=8 && strncmp(azArg[0], "testctrl", n)==0 && nArg>=2 ){
static const struct {
const char *zCtrlName; /* Name of a test-control option */