/ Check-in [62289f27]
Login

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

Overview
Comment:Add the ".testcase" and ".check" dot-commands in the shell, when compiled using SQLITE_DEBUG.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 62289f27ee276090a855982bd8216a465e7d0a27
User & Date: drh 2016-09-15 21:35:24
Context
2016-09-16
00:26
In the command-line shell, add the --new option to the ".open" command. Also, report the current database filename as part of the ".show" command. check-in: 8e5c9203 user: drh tags: trunk
2016-09-15
21:35
Add the ".testcase" and ".check" dot-commands in the shell, when compiled using SQLITE_DEBUG. check-in: 62289f27 user: drh tags: trunk
19:15
Omit the sqlite3Apis constant object when compiling with SQLITE_OMIT_LOAD_EXTENSION, since it is not used. check-in: 7b104613 user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/shell.c.

  2132   2132   */
  2133   2133   static char zHelp[] =
  2134   2134     ".auth ON|OFF           Show authorizer callbacks\n"
  2135   2135     ".backup ?DB? FILE      Backup DB (default \"main\") to FILE\n"
  2136   2136     ".bail on|off           Stop after hitting an error.  Default OFF\n"
  2137   2137     ".binary on|off         Turn binary output on or off.  Default OFF\n"
  2138   2138     ".changes on|off        Show number of rows changed by SQL\n"
         2139  +#ifdef SQLITE_DEBUG
         2140  +  ".check GLOB            Fail if output since .testcase does not match\n"
         2141  +#endif
  2139   2142     ".clone NEWDB           Clone data into NEWDB from the existing database\n"
  2140   2143     ".databases             List names and files of attached databases\n"
  2141   2144     ".dbinfo ?DB?           Show status information about the database\n"
  2142   2145     ".dump ?TABLE? ...      Dump the database in an SQL text format\n"
  2143   2146     "                         If TABLE specified, only dump tables matching\n"
  2144   2147     "                         LIKE pattern TABLE.\n"
  2145   2148     ".echo on|off           Turn command echo on or off\n"
................................................................................
  2192   2195     ".shell CMD ARGS...     Run CMD ARGS... in a system shell\n"
  2193   2196     ".show                  Show the current values for various settings\n"
  2194   2197     ".stats ?on|off?        Show stats or turn stats on or off\n"
  2195   2198     ".system CMD ARGS...    Run CMD ARGS... in a system shell\n"
  2196   2199     ".tables ?TABLE?        List names of tables\n"
  2197   2200     "                         If TABLE specified, only list tables matching\n"
  2198   2201     "                         LIKE pattern TABLE.\n"
         2202  +#ifdef SQLITE_DEBUG
         2203  +  ".testcase              Begin redirecting output to 'testcase-out.txt'\n"
         2204  +#endif
  2199   2205     ".timeout MS            Try opening locked tables for MS milliseconds\n"
  2200   2206     ".timer on|off          Turn SQL timer on or off\n"
  2201   2207     ".trace FILE|off        Output each SQL statement as it is run\n"
  2202   2208     ".vfsinfo ?AUX?         Information about the top-level VFS\n"
  2203   2209     ".vfslist               List all available VFSes\n"
  2204   2210     ".vfsname ?AUX?         Print the name of the VFS stack\n"
  2205   2211     ".width NUM1 NUM2 ...   Set column widths for \"column\" mode\n"
................................................................................
  2228   2234     );
  2229   2235   }
  2230   2236   #endif
  2231   2237   
  2232   2238   
  2233   2239   /* Forward reference */
  2234   2240   static int process_input(ShellState *p, FILE *in);
         2241  +
         2242  +
         2243  +/*
         2244  +** Read the content of a file into memory obtained from sqlite3_malloc64().
         2245  +** The caller is responsible for freeing the memory.
         2246  +**
         2247  +** NULL is returned if any error is encountered.
         2248  +*/
         2249  +static char *readFile(const char *zName){
         2250  +  FILE *in = fopen(zName, "rb");
         2251  +  long nIn;
         2252  +  char *pBuf;
         2253  +  if( in==0 ) return 0;
         2254  +  fseek(in, 0, SEEK_END);
         2255  +  nIn = ftell(in);
         2256  +  rewind(in);
         2257  +  pBuf = sqlite3_malloc64( nIn );
         2258  +  if( pBuf==0 ) return 0;
         2259  +  if( 1!=fread(pBuf, nIn, 1, in) ){
         2260  +    sqlite3_free(pBuf);
         2261  +    return 0;
         2262  +  }
         2263  +  return pBuf;
         2264  +}
         2265  +
  2235   2266   /*
  2236   2267   ** Implementation of the "readfile(X)" SQL function.  The entire content
  2237   2268   ** of the file named X is read and returned as a BLOB.  NULL is returned
  2238   2269   ** if the file does not exist or is unreadable.
  2239   2270   */
  2240   2271   static void readfileFunc(
  2241   2272     sqlite3_context *context,
  2242   2273     int argc,
  2243   2274     sqlite3_value **argv
  2244   2275   ){
  2245   2276     const char *zName;
  2246         -  FILE *in;
  2247         -  long nIn;
  2248   2277     void *pBuf;
  2249   2278   
  2250   2279     UNUSED_PARAMETER(argc);
  2251   2280     zName = (const char*)sqlite3_value_text(argv[0]);
  2252   2281     if( zName==0 ) return;
  2253         -  in = fopen(zName, "rb");
  2254         -  if( in==0 ) return;
  2255         -  fseek(in, 0, SEEK_END);
  2256         -  nIn = ftell(in);
  2257         -  rewind(in);
  2258         -  pBuf = sqlite3_malloc64( nIn );
  2259         -  if( pBuf && 1==fread(pBuf, nIn, 1, in) ){
  2260         -    sqlite3_result_blob(context, pBuf, nIn, sqlite3_free);
  2261         -  }else{
  2262         -    sqlite3_free(pBuf);
  2263         -  }
  2264         -  fclose(in);
         2282  +  pBuf = readFile(zName);
         2283  +  if( pBuf ) sqlite3_result_blob(context, pBuf, -1, sqlite3_free);
  2265   2284   }
  2266   2285   
  2267   2286   /*
  2268   2287   ** Implementation of the "writefile(X,Y)" SQL function.  The argument Y
  2269   2288   ** is written into file X.  The number of bytes written is returned.  Or
  2270   2289   ** NULL is returned if something goes wrong, such as being unable to open
  2271   2290   ** file X for writing.
................................................................................
  3058   3077   /*
  3059   3078   ** Print an out-of-memory message to stderr and return 1.
  3060   3079   */
  3061   3080   static int shellNomemError(void){
  3062   3081     raw_printf(stderr, "Error: out of memory\n");
  3063   3082     return 1;
  3064   3083   }
         3084  +
         3085  +#ifdef SQLITE_DEBUG
         3086  +/*
         3087  +** Compare the pattern in zGlob[] against the text in z[].  Return TRUE
         3088  +** if they match and FALSE (0) if they do not match.
         3089  +**
         3090  +** Globbing rules:
         3091  +**
         3092  +**      '*'       Matches any sequence of zero or more characters.
         3093  +**
         3094  +**      '?'       Matches exactly one character.
         3095  +**
         3096  +**     [...]      Matches one character from the enclosed list of
         3097  +**                characters.
         3098  +**
         3099  +**     [^...]     Matches one character not in the enclosed list.
         3100  +**
         3101  +**      '#'       Matches any sequence of one or more digits with an
         3102  +**                optional + or - sign in front
         3103  +**
         3104  +**      ' '       Any span of whitespace matches any other span of
         3105  +**                whitespace.
         3106  +**
         3107  +** Extra whitespace at the end of z[] is ignored.
         3108  +*/
         3109  +static int testcase_glob(const char *zGlob, const char *z){
         3110  +  int c, c2;
         3111  +  int invert;
         3112  +  int seen;
         3113  +
         3114  +  while( (c = (*(zGlob++)))!=0 ){
         3115  +    if( IsSpace(c) ){
         3116  +      if( !IsSpace(*z) ) return 0;
         3117  +      while( IsSpace(*zGlob) ) zGlob++;
         3118  +      while( IsSpace(*z) ) z++;
         3119  +    }else if( c=='*' ){
         3120  +      while( (c=(*(zGlob++))) == '*' || c=='?' ){
         3121  +        if( c=='?' && (*(z++))==0 ) return 0;
         3122  +      }
         3123  +      if( c==0 ){
         3124  +        return 1;
         3125  +      }else if( c=='[' ){
         3126  +        while( *z && testcase_glob(zGlob-1,z)==0 ){
         3127  +          z++;
         3128  +        }
         3129  +        return (*z)!=0;
         3130  +      }
         3131  +      while( (c2 = (*(z++)))!=0 ){
         3132  +        while( c2!=c ){
         3133  +          c2 = *(z++);
         3134  +          if( c2==0 ) return 0;
         3135  +        }
         3136  +        if( testcase_glob(zGlob,z) ) return 1;
         3137  +      }
         3138  +      return 0;
         3139  +    }else if( c=='?' ){
         3140  +      if( (*(z++))==0 ) return 0;
         3141  +    }else if( c=='[' ){
         3142  +      int prior_c = 0;
         3143  +      seen = 0;
         3144  +      invert = 0;
         3145  +      c = *(z++);
         3146  +      if( c==0 ) return 0;
         3147  +      c2 = *(zGlob++);
         3148  +      if( c2=='^' ){
         3149  +        invert = 1;
         3150  +        c2 = *(zGlob++);
         3151  +      }
         3152  +      if( c2==']' ){
         3153  +        if( c==']' ) seen = 1;
         3154  +        c2 = *(zGlob++);
         3155  +      }
         3156  +      while( c2 && c2!=']' ){
         3157  +        if( c2=='-' && zGlob[0]!=']' && zGlob[0]!=0 && prior_c>0 ){
         3158  +          c2 = *(zGlob++);
         3159  +          if( c>=prior_c && c<=c2 ) seen = 1;
         3160  +          prior_c = 0;
         3161  +        }else{
         3162  +          if( c==c2 ){
         3163  +            seen = 1;
         3164  +          }
         3165  +          prior_c = c2;
         3166  +        }
         3167  +        c2 = *(zGlob++);
         3168  +      }
         3169  +      if( c2==0 || (seen ^ invert)==0 ) return 0;
         3170  +    }else if( c=='#' ){
         3171  +      if( (z[0]=='-' || z[0]=='+') && IsDigit(z[1]) ) z++;
         3172  +      if( !IsDigit(z[0]) ) return 0;
         3173  +      z++;
         3174  +      while( IsDigit(z[0]) ){ z++; }
         3175  +    }else{
         3176  +      if( c!=(*(z++)) ) return 0;
         3177  +    }
         3178  +  }
         3179  +  while( IsSpace(*z) ){ z++; }
         3180  +  return *z==0;
         3181  +}
         3182  +#endif /* defined(SQLITE_DEBUG) */
         3183  +
  3065   3184   
  3066   3185   /*
  3067   3186   ** Compare the string as a command-line option with either one or two
  3068   3187   ** initial "-" characters.
  3069   3188   */
  3070   3189   static int optionMatch(const char *zStr, const char *zOpt){
  3071   3190     if( zStr[0]!='-' ) return 0;
................................................................................
  3220   3339       if( nArg==2 ){
  3221   3340         p->countChanges = booleanValue(azArg[1]);
  3222   3341       }else{
  3223   3342         raw_printf(stderr, "Usage: .changes on|off\n");
  3224   3343         rc = 1;
  3225   3344       }
  3226   3345     }else
         3346  +
         3347  +#ifdef SQLITE_DEBUG
         3348  +  /* Cancel output redirection, if it is currently set (by .testcase)
         3349  +  ** Then read the content of the testcase-out.txt file and compare against
         3350  +  ** azArg[1].  If there are differences, report an error and exit.
         3351  +  */
         3352  +  if( c=='c' && n>=3 && strncmp(azArg[0], "check", n)==0 ){
         3353  +    char *zRes = 0;
         3354  +    output_reset(p);
         3355  +    if( nArg!=2 ){
         3356  +      raw_printf(stderr, "Usage: .check GLOB-PATTERN\n");
         3357  +      rc = 1;
         3358  +    }else if( (zRes = readFile("testcase-out.txt"))==0 ){
         3359  +      raw_printf(stderr, "Error: cannot read 'testcase-out.txt'\n");
         3360  +      rc = 2;
         3361  +    }else if( testcase_glob(azArg[1],zRes)==0 ){
         3362  +      raw_printf(stderr, ".check failed\n Expected: [%s]\n      Got: [%s]\n",
         3363  +                 azArg[1], zRes);
         3364  +      rc = 2;
         3365  +    }
         3366  +    sqlite3_free(zRes);
         3367  +  }else
         3368  +#endif
  3227   3369   
  3228   3370     if( c=='c' && strncmp(azArg[0], "clone", n)==0 ){
  3229   3371       if( nArg==2 ){
  3230   3372         tryToClone(p, azArg[1]);
  3231   3373       }else{
  3232   3374         raw_printf(stderr, "Usage: .clone FILENAME\n");
  3233   3375         rc = 1;
................................................................................
  4490   4632           raw_printf(p->out, "\n");
  4491   4633         }
  4492   4634       }
  4493   4635   
  4494   4636       for(ii=0; ii<nRow; ii++) sqlite3_free(azResult[ii]);
  4495   4637       sqlite3_free(azResult);
  4496   4638     }else
         4639  +
         4640  +#ifdef SQLITE_DEBUG
         4641  +  /* Begin redirecting output to the file "testcase-out.txt" */
         4642  +  if( c=='t' && strcmp(azArg[0],"testcase")==0 ){
         4643  +    output_reset(p);
         4644  +    p->out = output_file_open("testcase-out.txt");
         4645  +    if( p->out==0 ){
         4646  +      utf8_printf(stderr, "Error: cannot open 'testcase-out.txt'\n");
         4647  +    }
         4648  +  }else
         4649  +#endif
  4497   4650   
  4498   4651     if( c=='t' && n>=8 && strncmp(azArg[0], "testctrl", n)==0 && nArg>=2 ){
  4499   4652       static const struct {
  4500   4653          const char *zCtrlName;   /* Name of a test-control option */
  4501   4654          int ctrlCode;            /* Integer code for that option */
  4502   4655       } aCtrl[] = {
  4503   4656         { "prng_save",             SQLITE_TESTCTRL_PRNG_SAVE              },