| | @@ -1581,13 +1581,15 @@ |
| 1581 | 1581 | ** (3) z[] does not looks like a numeric literal |
| 1582 | 1582 | */ |
| 1583 | 1583 | static int qrfRelaxable(Qrf *p, const char *z){ |
| 1584 | 1584 | size_t i, n; |
| 1585 | 1585 | if( z[0]=='\'' || qrfSpace(z[0]) ) return 0; |
| 1586 | | - if( z[0]==0 && (p->spec.zNull==0 || p->spec.zNull[0]==0) ) return 0; |
| 1586 | + if( z[0]==0 ){ |
| 1587 | + return (p->spec.zNull!=0 && p->spec.zNull[0]!=0); |
| 1588 | + } |
| 1587 | 1589 | n = strlen(z); |
| 1588 | | - if( z[n-1]=='\'' || qrfSpace(z[n-1]) ) return 0; |
| 1590 | + if( n==0 || z[n-1]=='\'' || qrfSpace(z[n-1]) ) return 0; |
| 1589 | 1591 | if( p->spec.zNull && strcmp(p->spec.zNull,z)==0 ) return 0; |
| 1590 | 1592 | i = (z[0]=='-' || z[0]=='+'); |
| 1591 | 1593 | if( strcmp(z+i,"Inf")==0 ) return 0; |
| 1592 | 1594 | if( !qrfDigit(z[i]) ) return 1; |
| 1593 | 1595 | i++; |
| | @@ -10180,15 +10182,22 @@ |
| 10180 | 10182 | } |
| 10181 | 10183 | return pRe->zErr; |
| 10182 | 10184 | } |
| 10183 | 10185 | |
| 10184 | 10186 | /* |
| 10185 | | -** Compute a reasonable limit on the length of the REGEXP NFA. |
| 10187 | +** The value of LIMIT_MAX_PATTERN_LENGTH. |
| 10186 | 10188 | */ |
| 10187 | 10189 | static int re_maxlen(sqlite3_context *context){ |
| 10188 | 10190 | sqlite3 *db = sqlite3_context_db_handle(context); |
| 10189 | | - return 75 + sqlite3_limit(db, SQLITE_LIMIT_LIKE_PATTERN_LENGTH,-1)/2; |
| 10191 | + return sqlite3_limit(db, SQLITE_LIMIT_LIKE_PATTERN_LENGTH,-1); |
| 10192 | +} |
| 10193 | + |
| 10194 | +/* |
| 10195 | +** Maximum NFA size given a maximum pattern length. |
| 10196 | +*/ |
| 10197 | +static int re_maxnfa(int mxlen){ |
| 10198 | + return 75+mxlen/2; |
| 10190 | 10199 | } |
| 10191 | 10200 | |
| 10192 | 10201 | /* |
| 10193 | 10202 | ** Implementation of the regexp() SQL function. This function implements |
| 10194 | 10203 | ** the build-in REGEXP operator. The first argument to the function is the |
| | @@ -10210,14 +10219,21 @@ |
| 10210 | 10219 | int setAux = 0; /* True to invoke sqlite3_set_auxdata() */ |
| 10211 | 10220 | |
| 10212 | 10221 | (void)argc; /* Unused */ |
| 10213 | 10222 | pRe = sqlite3_get_auxdata(context, 0); |
| 10214 | 10223 | if( pRe==0 ){ |
| 10224 | + int mxLen = re_maxlen(context); |
| 10225 | + int nPattern; |
| 10215 | 10226 | zPattern = (const char*)sqlite3_value_text(argv[0]); |
| 10216 | 10227 | if( zPattern==0 ) return; |
| 10217 | | - zErr = re_compile(&pRe, zPattern, re_maxlen(context), |
| 10218 | | - sqlite3_user_data(context)!=0); |
| 10228 | + nPattern = sqlite3_value_bytes(argv[0]); |
| 10229 | + if( nPattern>mxLen ){ |
| 10230 | + zErr = "REGEXP pattern too big"; |
| 10231 | + }else{ |
| 10232 | + zErr = re_compile(&pRe, zPattern, re_maxnfa(mxLen), |
| 10233 | + sqlite3_user_data(context)!=0); |
| 10234 | + } |
| 10219 | 10235 | if( zErr ){ |
| 10220 | 10236 | re_free(pRe); |
| 10221 | 10237 | sqlite3_result_error(context, zErr, -1); |
| 10222 | 10238 | return; |
| 10223 | 10239 | } |
| | @@ -10279,11 +10295,11 @@ |
| 10279 | 10295 | "ATSTART", |
| 10280 | 10296 | }; |
| 10281 | 10297 | |
| 10282 | 10298 | zPattern = (const char*)sqlite3_value_text(argv[0]); |
| 10283 | 10299 | if( zPattern==0 ) return; |
| 10284 | | - zErr = re_compile(&pRe, zPattern, re_maxlen(context), |
| 10300 | + zErr = re_compile(&pRe, zPattern, re_maxnfa(re_maxlen(context)), |
| 10285 | 10301 | sqlite3_user_data(context)!=0); |
| 10286 | 10302 | if( zErr ){ |
| 10287 | 10303 | re_free(pRe); |
| 10288 | 10304 | sqlite3_result_error(context, zErr, -1); |
| 10289 | 10305 | return; |
| | @@ -24178,11 +24194,10 @@ |
| 24178 | 24194 | ** instance of the following structure. |
| 24179 | 24195 | */ |
| 24180 | 24196 | typedef struct ShellState ShellState; |
| 24181 | 24197 | struct ShellState { |
| 24182 | 24198 | sqlite3 *db; /* The database */ |
| 24183 | | - int iCompat; /* Compatibility date YYYYMMDD */ |
| 24184 | 24199 | u8 openMode; /* SHELL_OPEN_NORMAL, _APPENDVFS, or _ZIPFILE */ |
| 24185 | 24200 | u8 doXdgOpen; /* Invoke start/open/xdg-open in output_reset() */ |
| 24186 | 24201 | u8 nEqpLevel; /* Depth of the EQP output graph */ |
| 24187 | 24202 | u8 eTraceType; /* SHELL_TRACE_* value for type of trace */ |
| 24188 | 24203 | u8 bSafeMode; /* True to prohibit unsafe operations */ |
| | @@ -24570,18 +24585,17 @@ |
| 24570 | 24585 | p->mode.mFlags = mFlags; |
| 24571 | 24586 | } |
| 24572 | 24587 | } |
| 24573 | 24588 | |
| 24574 | 24589 | /* |
| 24575 | | -** Set the mode to the default according to p->iCompat. It assumed |
| 24576 | | -** that the mode has already been freed and zeroed prior to calling |
| 24577 | | -** this routine. |
| 24590 | +** Set the mode to the default. It assumed that the mode has |
| 24591 | +** already been freed and zeroed prior to calling this routine. |
| 24578 | 24592 | */ |
| 24579 | 24593 | static void modeDefault(ShellState *p){ |
| 24580 | 24594 | p->mode.spec.iVersion = 1; |
| 24581 | 24595 | p->mode.autoExplain = 1; |
| 24582 | | - if( p->iCompat>=20251115 && (stdin_is_interactive || stdout_is_console) ){ |
| 24596 | + if( stdin_is_interactive || stdout_is_console ){ |
| 24583 | 24597 | modeChange(p, MODE_TTY); |
| 24584 | 24598 | }else{ |
| 24585 | 24599 | modeChange(p, MODE_BATCH); |
| 24586 | 24600 | } |
| 24587 | 24601 | } |
| | @@ -26604,12 +26618,12 @@ |
| 26604 | 26618 | ".bail on|off Stop after hitting an error. Default OFF", |
| 26605 | 26619 | #ifndef SQLITE_SHELL_FIDDLE |
| 26606 | 26620 | ".cd DIRECTORY Change the working directory to DIRECTORY", |
| 26607 | 26621 | #endif |
| 26608 | 26622 | ".changes on|off Show number of rows changed by SQL", |
| 26623 | + ".check OPTIONS ... Verify the results of a .testcase", |
| 26609 | 26624 | #ifndef SQLITE_SHELL_FIDDLE |
| 26610 | | - ".check GLOB Fail if output since .testcase does not match", |
| 26611 | 26625 | ".clone NEWDB Clone data into NEWDB from the existing database", |
| 26612 | 26626 | #endif |
| 26613 | 26627 | ".connection [close] [#] Open or close an auxiliary database connection", |
| 26614 | 26628 | ".crlf ?on|off? Whether or not to use \\r\\n line endings", |
| 26615 | 26629 | ".databases List names and files of attached databases", |
| | @@ -26785,13 +26799,11 @@ |
| 26785 | 26799 | " vmstep Show the virtual machine step count only", |
| 26786 | 26800 | #if !defined(SQLITE_NOHAVE_SYSTEM) && !defined(SQLITE_SHELL_FIDDLE) |
| 26787 | 26801 | ".system CMD ARGS... Run CMD ARGS... in a system shell", |
| 26788 | 26802 | #endif |
| 26789 | 26803 | ".tables ?TABLE? List names of tables matching LIKE pattern TABLE", |
| 26790 | | -#ifndef SQLITE_SHELL_FIDDLE |
| 26791 | | - ",testcase NAME Begin redirecting output to 'testcase-out.txt'", |
| 26792 | | -#endif |
| 26804 | + ".testcase NAME Begin a test case.", |
| 26793 | 26805 | ",testctrl CMD ... Run various sqlite3_test_control() operations", |
| 26794 | 26806 | " Run \".testctrl\" with no arguments for details", |
| 26795 | 26807 | ".timeout MS Try opening locked tables for MS milliseconds", |
| 26796 | 26808 | ".timer on|off Turn SQL timer on or off", |
| 26797 | 26809 | #ifndef SQLITE_OMIT_TRACE |
| | @@ -26930,23 +26942,17 @@ |
| 26930 | 26942 | " --bom Prepend a byte-order mark to the output\n" |
| 26931 | 26943 | " -e Accumulate output in a temporary text file then\n" |
| 26932 | 26944 | " launch a text editor when the redirection ends.\n" |
| 26933 | 26945 | " --error-prefix X Use X as the left-margin prefix for error messages.\n" |
| 26934 | 26946 | " Set to an empty string to restore the default.\n" |
| 26935 | | -" --glob GLOB Raise an error if the memory buffer does not match\n" |
| 26936 | | -" the GLOB pattern.\n" |
| 26937 | | -" --keep Continue using the same \"memory\" buffer. Do not\n" |
| 26938 | | -" reset it or delete it. Useful in combination with\n" |
| 26939 | | -" --glob, --not-glob, and/or --verify.\n" |
| 26940 | | -" ---notglob GLOB Raise an error if the memory buffer does not match\n" |
| 26941 | | -" the GLOB pattern.\n" |
| 26947 | +" --keep Keep redirecting output to its current destination.\n" |
| 26948 | +" Use this option in combination with --show or\n" |
| 26949 | +" with --error-prefix when you do not want to stop\n" |
| 26950 | +" a current redirection.\n" |
| 26942 | 26951 | " --plain Use plain text rather than HTML tables with -w\n" |
| 26943 | | -" --show Write the memory buffer to the screen, for debugging.\n" |
| 26944 | | -" --verify ENDMARK Read subsequent lines of text until the first line\n" |
| 26945 | | -" that matches ENDMARK. Discard the ENDMARK. Compare\n" |
| 26946 | | -" the text against the accumulated output in memory and\n" |
| 26947 | | -" raise an error if there are any differences.\n" |
| 26952 | +" --show Show output text captured by .testcase or by\n" |
| 26953 | +" redirecting to \"memory\".\n" |
| 26948 | 26954 | " -w Show the output in a web browser. Output is\n" |
| 26949 | 26955 | " written into a temporary HTML file until the\n" |
| 26950 | 26956 | " redirect ends, then the web browser is launched.\n" |
| 26951 | 26957 | " Query results are shown as HTML tables, unless\n" |
| 26952 | 26958 | " the --plain is used too.\n" |
| | @@ -26970,10 +26976,40 @@ |
| 26970 | 26976 | " file in a web browser\n" |
| 26971 | 26977 | " -x Show the output in a spreadsheet. Output is\n" |
| 26972 | 26978 | " written to a temp file as CSV then the spreadsheet\n" |
| 26973 | 26979 | " is launched when\n" |
| 26974 | 26980 | }, |
| 26981 | + { ".check", |
| 26982 | +"USAGE: .check [OPTIONS] PATTERN\n" |
| 26983 | +"\n" |
| 26984 | +"Verify results of commands since the most recent .testcase command.\n" |
| 26985 | +"Restore output to the console, unless --keep is used.\n" |
| 26986 | +"\n" |
| 26987 | +"If PATTERN starts with \"<<ENDMARK\" then the actual pattern is taken from\n" |
| 26988 | +"subsequent lines of text up to the first line that begins with ENDMARK.\n" |
| 26989 | +"All pattern lines and the ENDMARK are discarded.\n" |
| 26990 | +"\n" |
| 26991 | +"Options:\n" |
| 26992 | +" --error-prefix TEXT Change error message prefix text to TEXT\n" |
| 26993 | +" --exact Do an exact comparison including leading and\n" |
| 26994 | +" trailing whitespace.\n" |
| 26995 | +" --glob Treat PATTERN as a GLOB\n" |
| 26996 | +" --keep Do not reset the testcase. More .check commands\n" |
| 26997 | +" will follow.\n" |
| 26998 | +" --notglob Output should not match PATTERN\n" |
| 26999 | +" --show Write testcase output to the screen, for debugging.\n" |
| 27000 | + }, |
| 27001 | + { ".testcase", |
| 27002 | +"USAGE: .testcase [OPTIONS] NAME\n" |
| 27003 | +"\n" |
| 27004 | +"Start a new test case identified by NAME. All output\n" |
| 27005 | +"through the next \".check\" command is captured for comparison. See the\n" |
| 27006 | +"\".check\" commandn for additional informatioon.\n" |
| 27007 | +"\n" |
| 27008 | +"Options:\n" |
| 27009 | +" --error-prefix TEXT Change error message prefix text to TEXT\n" |
| 27010 | + }, |
| 26975 | 27011 | }; |
| 26976 | 27012 | |
| 26977 | 27013 | /* |
| 26978 | 27014 | ** Return a pointer to usage text for zCmd, or NULL if none exists. |
| 26979 | 27015 | */ |
| | @@ -27193,10 +27229,56 @@ |
| 27193 | 27229 | if( sqlite3_strglob(pSession->azFilter[i], zTab)==0 ) return 0; |
| 27194 | 27230 | } |
| 27195 | 27231 | return 1; |
| 27196 | 27232 | } |
| 27197 | 27233 | #endif |
| 27234 | + |
| 27235 | +/* |
| 27236 | +** Return the size of the named file in bytes. Or return a negative |
| 27237 | +** number if the file does not exist. |
| 27238 | +*/ |
| 27239 | +static sqlite3_int64 fileSize(const char *zFile){ |
| 27240 | +#if defined(_WIN32) || defined(WIN32) |
| 27241 | + struct _stat64 x; |
| 27242 | + if( _stat64(zFile, &x)!=0 ) return -1; |
| 27243 | + return (sqlite3_int64)x.st_size; |
| 27244 | +#else |
| 27245 | + struct stat x; |
| 27246 | + if( stat(zFile, &x)!=0 ) return -1; |
| 27247 | + return (sqlite3_int64)x.st_size; |
| 27248 | +#endif |
| 27249 | +} |
| 27250 | + |
| 27251 | +/* |
| 27252 | +** Return true if zFile is an SQLite database. |
| 27253 | +** |
| 27254 | +** Algorithm: |
| 27255 | +** * If the file does not exist -> return false |
| 27256 | +** * If the size of the file is not a multiple of 512 -> return false |
| 27257 | +** * If sqlite3_open() fails -> return false |
| 27258 | +** * if sqlite3_prepare() or sqlite3_step() fails -> return false |
| 27259 | +** * Otherwise -> return true |
| 27260 | +*/ |
| 27261 | +static int isDatabaseFile(const char *zFile, int openFlags){ |
| 27262 | + sqlite3 *db = 0; |
| 27263 | + sqlite3_stmt *pStmt = 0; |
| 27264 | + int rc; |
| 27265 | + sqlite3_int64 sz = fileSize(zFile); |
| 27266 | + if( sz<512 || (sz%512)!=0 ) return 0; |
| 27267 | + if( sqlite3_open_v2(zFile, &db, openFlags, 0)==SQLITE_OK |
| 27268 | + && sqlite3_prepare_v2(db,"SELECT count(*) FROM sqlite_schema",-1,&pStmt,0) |
| 27269 | + ==SQLITE_OK |
| 27270 | + && sqlite3_step(pStmt)==SQLITE_ROW |
| 27271 | + ){ |
| 27272 | + rc = 1; |
| 27273 | + }else{ |
| 27274 | + rc = 0; |
| 27275 | + } |
| 27276 | + sqlite3_finalize(pStmt); |
| 27277 | + sqlite3_close(db); |
| 27278 | + return rc; |
| 27279 | +} |
| 27198 | 27280 | |
| 27199 | 27281 | /* |
| 27200 | 27282 | ** Try to deduce the type of file for zName based on its content. Return |
| 27201 | 27283 | ** one of the SHELL_OPEN_* constants. |
| 27202 | 27284 | ** |
| | @@ -27206,24 +27288,16 @@ |
| 27206 | 27288 | ** the type cannot be determined from content. |
| 27207 | 27289 | */ |
| 27208 | 27290 | int deduceDatabaseType(const char *zName, int dfltZip, int openFlags){ |
| 27209 | 27291 | FILE *f; |
| 27210 | 27292 | size_t n; |
| 27211 | | - sqlite3 *db = 0; |
| 27212 | | - sqlite3_stmt *pStmt = 0; |
| 27213 | 27293 | int rc = SHELL_OPEN_UNSPEC; |
| 27214 | 27294 | char zBuf[100]; |
| 27215 | 27295 | if( access(zName,0)!=0 ) goto database_type_by_name; |
| 27216 | | - if( sqlite3_open_v2(zName, &db, openFlags, 0)==SQLITE_OK |
| 27217 | | - && sqlite3_prepare_v2(db,"SELECT count(*) FROM sqlite_schema",-1,&pStmt,0) |
| 27218 | | - ==SQLITE_OK |
| 27219 | | - && sqlite3_step(pStmt)==SQLITE_ROW |
| 27220 | | - ){ |
| 27296 | + if( isDatabaseFile(zName, openFlags) ){ |
| 27221 | 27297 | rc = SHELL_OPEN_NORMAL; |
| 27222 | 27298 | } |
| 27223 | | - sqlite3_finalize(pStmt); |
| 27224 | | - sqlite3_close(db); |
| 27225 | 27299 | if( rc==SHELL_OPEN_NORMAL ) return SHELL_OPEN_NORMAL; |
| 27226 | 27300 | f = sqlite3_fopen(zName, "rb"); |
| 27227 | 27301 | if( f==0 ) goto database_type_by_name; |
| 27228 | 27302 | n = fread(zBuf, 16, 1, f); |
| 27229 | 27303 | if( n==1 && memcmp(zBuf, "SQLite format 3", 16)==0 ){ |
| | @@ -27253,10 +27327,37 @@ |
| 27253 | 27327 | }else{ |
| 27254 | 27328 | rc = SHELL_OPEN_NORMAL; |
| 27255 | 27329 | } |
| 27256 | 27330 | return rc; |
| 27257 | 27331 | } |
| 27332 | + |
| 27333 | +/* |
| 27334 | +** If the text in z[] is the name of a readable file and that file appears |
| 27335 | +** to contain SQL text and/or dot-commands, then return true. If z[] is |
| 27336 | +** not a file, or if the file is unreadable, or if the file is a database |
| 27337 | +** or anything else that is not SQL text and dot-commands, then return false. |
| 27338 | +** |
| 27339 | +** If the bLeaveUninit flag is set, then be sure to leave SQLite in an |
| 27340 | +** uninitialized state. This means invoking sqlite3_shutdown() after any |
| 27341 | +** SQLite API is used. |
| 27342 | +** |
| 27343 | +** Some amount of guesswork is involved in this decision. |
| 27344 | +*/ |
| 27345 | +static int isScriptFile(const char *z, int bLeaveUninit){ |
| 27346 | + sqlite3_int64 sz = fileSize(z); |
| 27347 | + if( sz<=0 ) return 0; |
| 27348 | + if( (sz%512)==0 ){ |
| 27349 | + int rc = isDatabaseFile(z, SQLITE_OPEN_READONLY); |
| 27350 | + if( bLeaveUninit ){ |
| 27351 | + sqlite3_shutdown(); |
| 27352 | + } |
| 27353 | + if( rc ) return 0; /* Is a database */ |
| 27354 | + } |
| 27355 | + if( sqlite3_strlike("%.sql",z,0)==0 ) return 1; |
| 27356 | + if( sqlite3_strlike("%.txt",z,0)==0 ) return 1; |
| 27357 | + return 0; |
| 27358 | +} |
| 27258 | 27359 | |
| 27259 | 27360 | #ifndef SQLITE_OMIT_DESERIALIZE |
| 27260 | 27361 | /* |
| 27261 | 27362 | ** Reconstruct an in-memory database using the output from the "dbtotxt" |
| 27262 | 27363 | ** program. Read content from the file in p->aAuxDb[].zDbFilename. |
| | @@ -31328,23 +31429,17 @@ |
| 31328 | 31429 | ** --bom Prepend a byte-order mark to the output |
| 31329 | 31430 | ** -e Accumulate output in a temporary text file then |
| 31330 | 31431 | ** launch a text editor when the redirection ends. |
| 31331 | 31432 | ** --error-prefix X Use X as the left-margin prefix for error messages. |
| 31332 | 31433 | ** Set to an empty string to restore the default. |
| 31333 | | -** --glob GLOB Raise an error if the memory buffer does not match |
| 31334 | | -** the GLOB pattern. |
| 31335 | | -** --keep Continue using the same "memory" buffer. Do not |
| 31336 | | -** reset it or delete it. Useful in combination with |
| 31337 | | -** --glob, --not-glob, and/or --verify. |
| 31338 | | -** ---notglob GLOB Raise an error if the memory buffer does not match |
| 31339 | | -** the GLOB pattern. |
| 31434 | +** --keep Keep redirecting output to its current destination. |
| 31435 | +** Use this option in combination with --show or |
| 31436 | +** with --error-prefix when you do not want to stop |
| 31437 | +** a current redirection. |
| 31340 | 31438 | ** --plain Use plain text rather than HTML tables with -w |
| 31341 | | -** --show Write the memory buffer to the screen, for debugging. |
| 31342 | | -** --verify ENDMARK Read subsequent lines of text until the first line |
| 31343 | | -** that matches ENDMARK. Discard the ENDMARK. Compare |
| 31344 | | -** the text against the accumulated output in memory and |
| 31345 | | -** raise an error if there are any differences. |
| 31439 | +** --show Show output text captured by .testcase or by |
| 31440 | +** redirecting to "memory". |
| 31346 | 31441 | ** -w Show the output in a web browser. Output is |
| 31347 | 31442 | ** written into a temporary HTML file until the |
| 31348 | 31443 | ** redirect ends, then the web browser is launched. |
| 31349 | 31444 | ** Query results are shown as HTML tables, unless |
| 31350 | 31445 | ** the --plain is used too. |
| | @@ -31382,13 +31477,11 @@ |
| 31382 | 31477 | char *zFile = 0; /* The FILE argument */ |
| 31383 | 31478 | int i; /* Loop counter */ |
| 31384 | 31479 | int eMode = 0; /* 0: .outout/.once, 'x'=.excel, 'w'=.www */ |
| 31385 | 31480 | int bOnce = 0; /* 0: .output, 1: .once, 2: .excel/.www */ |
| 31386 | 31481 | int bPlain = 0; /* --plain option */ |
| 31387 | | - int bKeep = 0; /* --keep option */ |
| 31388 | | - char *zCheck = 0; /* Argument to --glob, --notglob, --verify */ |
| 31389 | | - int eCheck = 0; /* 1: --glob, 2: --notglob, 3: --verify */ |
| 31482 | + int bKeep = 0; /* Keep redirecting */ |
| 31390 | 31483 | static const char *zBomUtf8 = "\357\273\277"; |
| 31391 | 31484 | const char *zBom = 0; |
| 31392 | 31485 | char c = azArg[0][0]; |
| 31393 | 31486 | int n = strlen30(azArg[0]); |
| 31394 | 31487 | |
| | @@ -31410,36 +31503,21 @@ |
| 31410 | 31503 | zBom = zBomUtf8; |
| 31411 | 31504 | }else if( cli_strcmp(z,"-plain")==0 ){ |
| 31412 | 31505 | bPlain = 1; |
| 31413 | 31506 | }else if( c=='o' && z[0]=='1' && z[1]!=0 && z[2]==0 |
| 31414 | 31507 | && (z[1]=='x' || z[1]=='e' || z[1]=='w') ){ |
| 31415 | | - if( bKeep || eMode || eCheck ){ |
| 31508 | + if( bKeep || eMode ){ |
| 31416 | 31509 | dotCmdError(p, i, "incompatible with prior options",0); |
| 31417 | 31510 | goto dotCmdOutput_error; |
| 31418 | 31511 | } |
| 31419 | 31512 | eMode = z[1]; |
| 31420 | | - }else if( cli_strcmp(z,"-keep")==0 ){ |
| 31421 | | - bKeep = 1; |
| 31422 | 31513 | }else if( cli_strcmp(z,"-show")==0 ){ |
| 31423 | 31514 | if( cli_output_capture ){ |
| 31424 | 31515 | sqlite3_fprintf(stdout, "%s", sqlite3_str_value(cli_output_capture)); |
| 31425 | 31516 | } |
| 31517 | + }else if( cli_strcmp(z,"-keep")==0 ){ |
| 31426 | 31518 | bKeep = 1; |
| 31427 | | - }else if( cli_strcmp(z,"-glob")==0 |
| 31428 | | - || cli_strcmp(z,"-notglob")==0 |
| 31429 | | - || cli_strcmp(z,"-verify")==0 |
| 31430 | | - ){ |
| 31431 | | - if( eCheck || eMode ){ |
| 31432 | | - dotCmdError(p, i, "incompatible with prior options",0); |
| 31433 | | - goto dotCmdOutput_error; |
| 31434 | | - } |
| 31435 | | - if( i+1>=nArg ){ |
| 31436 | | - dotCmdError(p, i, "missing argument", 0); |
| 31437 | | - goto dotCmdOutput_error; |
| 31438 | | - } |
| 31439 | | - zCheck = azArg[++i]; |
| 31440 | | - eCheck = z[1]=='g' ? 1 : z[1]=='n' ? 2 : 3; |
| 31441 | 31519 | }else if( optionMatch(z,"error-prefix") ){ |
| 31442 | 31520 | if( i+1>=nArg ){ |
| 31443 | 31521 | dotCmdError(p, i, "missing argument", 0); |
| 31444 | 31522 | return 1; |
| 31445 | 31523 | } |
| | @@ -31450,11 +31528,11 @@ |
| 31450 | 31528 | dotCmdError(p, i, "unknown option", 0); |
| 31451 | 31529 | sqlite3_free(zFile); |
| 31452 | 31530 | return 1; |
| 31453 | 31531 | } |
| 31454 | 31532 | }else if( zFile==0 && eMode==0 ){ |
| 31455 | | - if( bKeep || eCheck ){ |
| 31533 | + if( bKeep ){ |
| 31456 | 31534 | dotCmdError(p, i, "incompatible with prior options",0); |
| 31457 | 31535 | goto dotCmdOutput_error; |
| 31458 | 31536 | } |
| 31459 | 31537 | if( cli_strcmp(z, "memory")==0 && bOnce ){ |
| 31460 | 31538 | dotCmdError(p, 0, "cannot redirect to \"memory\"", 0); |
| | @@ -31486,53 +31564,10 @@ |
| 31486 | 31564 | if( bOnce ){ |
| 31487 | 31565 | p->nPopOutput = 2; |
| 31488 | 31566 | }else{ |
| 31489 | 31567 | p->nPopOutput = 0; |
| 31490 | 31568 | } |
| 31491 | | - if( eCheck ){ |
| 31492 | | - char *zTest; |
| 31493 | | - if( cli_output_capture ){ |
| 31494 | | - zTest = sqlite3_str_value(cli_output_capture); |
| 31495 | | - }else{ |
| 31496 | | - zTest = ""; |
| 31497 | | - } |
| 31498 | | - p->nTestRun++; |
| 31499 | | - if( eCheck==3 ){ |
| 31500 | | - int nCheck = strlen30(zCheck); |
| 31501 | | - sqlite3_str *pPattern = sqlite3_str_new(p->db); |
| 31502 | | - char *zPattern; |
| 31503 | | - sqlite3_int64 iStart = p->lineno; |
| 31504 | | - char zLine[2000]; |
| 31505 | | - while( sqlite3_fgets(zLine,sizeof(zLine),p->in) ){ |
| 31506 | | - if( strchr(zLine,'\n') ) p->lineno++; |
| 31507 | | - if( cli_strncmp(zCheck,zLine,nCheck)==0 ) break; |
| 31508 | | - sqlite3_str_appendall(pPattern, zLine); |
| 31509 | | - } |
| 31510 | | - zPattern = sqlite3_str_finish(pPattern); |
| 31511 | | - if( cli_strcmp(zPattern,zTest)!=0 ){ |
| 31512 | | - sqlite3_fprintf(stderr, |
| 31513 | | - "%s:%lld: --verify does matches prior output\n", |
| 31514 | | - p->zInFile, iStart); |
| 31515 | | - p->nTestErr++; |
| 31516 | | - } |
| 31517 | | - sqlite3_free(zPattern); |
| 31518 | | - }else{ |
| 31519 | | - char *zGlob = sqlite3_mprintf("*%s*", zCheck); |
| 31520 | | - if( eCheck==1 && sqlite3_strglob(zGlob, zTest)!=0 ){ |
| 31521 | | - sqlite3_fprintf(stderr, |
| 31522 | | - "%s:%lld: --glob \"%s\" does not match prior output\n", |
| 31523 | | - p->zInFile, p->lineno, zCheck); |
| 31524 | | - p->nTestErr++; |
| 31525 | | - }else if( eCheck==2 && sqlite3_strglob(zGlob, zTest)==0 ){ |
| 31526 | | - sqlite3_fprintf(stderr, |
| 31527 | | - "%s:%lld: --notglob \"%s\" matches prior output\n", |
| 31528 | | - p->zInFile, p->lineno, zCheck); |
| 31529 | | - p->nTestErr++; |
| 31530 | | - } |
| 31531 | | - sqlite3_free(zGlob); |
| 31532 | | - } |
| 31533 | | - } |
| 31534 | 31569 | if( !bKeep ) output_reset(p); |
| 31535 | 31570 | #ifndef SQLITE_NOHAVE_SYSTEM |
| 31536 | 31571 | if( eMode=='e' || eMode=='x' || eMode=='w' ){ |
| 31537 | 31572 | p->doXdgOpen = 1; |
| 31538 | 31573 | modePush(p); |
| | @@ -31609,10 +31644,200 @@ |
| 31609 | 31644 | |
| 31610 | 31645 | dotCmdOutput_error: |
| 31611 | 31646 | sqlite3_free(zFile); |
| 31612 | 31647 | return 1; |
| 31613 | 31648 | } |
| 31649 | + |
| 31650 | +/* |
| 31651 | +** DOT-COMMAND: .check |
| 31652 | +** USAGE: .check [OPTIONS] PATTERN |
| 31653 | +** |
| 31654 | +** Verify results of commands since the most recent .testcase command. |
| 31655 | +** Restore output to the console, unless --keep is used. |
| 31656 | +** |
| 31657 | +** If PATTERN starts with "<<ENDMARK" then the actual pattern is taken from |
| 31658 | +** subsequent lines of text up to the first line that begins with ENDMARK. |
| 31659 | +** All pattern lines and the ENDMARK are discarded. |
| 31660 | +** |
| 31661 | +** Options: |
| 31662 | +** --error-prefix TEXT Change error message prefix text to TEXT |
| 31663 | +** --exact Do an exact comparison including leading and |
| 31664 | +** trailing whitespace. |
| 31665 | +** --glob Treat PATTERN as a GLOB |
| 31666 | +** --keep Do not reset the testcase. More .check commands |
| 31667 | +** will follow. |
| 31668 | +** --notglob Output should not match PATTERN |
| 31669 | +** --show Write testcase output to the screen, for debugging. |
| 31670 | +*/ |
| 31671 | +static int dotCmdCheck(ShellState *p){ |
| 31672 | + int nArg = p->dot.nArg; /* Number of arguments */ |
| 31673 | + char **azArg = p->dot.azArg; /* Text of the arguments */ |
| 31674 | + int i; /* Loop counter */ |
| 31675 | + int k; /* Result of pickStr() */ |
| 31676 | + char *zTest; /* Textcase result */ |
| 31677 | + int bKeep = 0; /* --keep option */ |
| 31678 | + char *zCheck = 0; /* PATTERN argument */ |
| 31679 | + char *zPattern = 0; /* Actual test pattern */ |
| 31680 | + int eCheck = 0; /* 1: --glob, 2: --notglob, 3: --exact */ |
| 31681 | + int isOk; /* True if results are OK */ |
| 31682 | + sqlite3_int64 iStart = p->lineno; /* Line number of .check statement */ |
| 31683 | + |
| 31684 | + if( p->zTestcase[0]==0 ){ |
| 31685 | + dotCmdError(p, 0, "no .testcase is active", 0); |
| 31686 | + return 1; |
| 31687 | + } |
| 31688 | + for(i=1; i<nArg; i++){ |
| 31689 | + char *z = azArg[i]; |
| 31690 | + if( z[0]=='-' && z[1]=='-' && z[2]!=0 ) z++; |
| 31691 | + if( cli_strcmp(z,"-keep")==0 ){ |
| 31692 | + bKeep = 1; |
| 31693 | + }else if( cli_strcmp(z,"-show")==0 ){ |
| 31694 | + if( cli_output_capture ){ |
| 31695 | + sqlite3_fprintf(stdout, "%s", sqlite3_str_value(cli_output_capture)); |
| 31696 | + } |
| 31697 | + bKeep = 1; |
| 31698 | + }else if( z[0]=='-' |
| 31699 | + && (k = pickStr(&z[1],0,"glob","notglob","exact",""))>=0 |
| 31700 | + ){ |
| 31701 | + if( eCheck && eCheck!=k+1 ){ |
| 31702 | + dotCmdError(p, i, "incompatible with prior options",0); |
| 31703 | + return 1; |
| 31704 | + } |
| 31705 | + eCheck = k+1; |
| 31706 | + }else if( zCheck ){ |
| 31707 | + dotCmdError(p, i, "unknown option", 0); |
| 31708 | + return 1; |
| 31709 | + }else{ |
| 31710 | + zCheck = azArg[i]; |
| 31711 | + } |
| 31712 | + } |
| 31713 | + if( zCheck==0 ){ |
| 31714 | + dotCmdError(p, 0, "no PATTERN specified", 0); |
| 31715 | + return 1; |
| 31716 | + } |
| 31717 | + if( cli_output_capture ){ |
| 31718 | + zTest = sqlite3_str_value(cli_output_capture); |
| 31719 | + shell_check_oom(zTest); |
| 31720 | + }else{ |
| 31721 | + zTest = ""; |
| 31722 | + } |
| 31723 | + p->nTestRun++; |
| 31724 | + if( zCheck[0]=='<' && zCheck[1]=='<' && zCheck[2]!=0 ){ |
| 31725 | + int nCheck = strlen30(zCheck); |
| 31726 | + sqlite3_str *pPattern = sqlite3_str_new(p->db); |
| 31727 | + char zLine[2000]; |
| 31728 | + while( sqlite3_fgets(zLine,sizeof(zLine),p->in) ){ |
| 31729 | + if( strchr(zLine,'\n') ) p->lineno++; |
| 31730 | + if( cli_strncmp(&zCheck[2],zLine,nCheck-2)==0 ) break; |
| 31731 | + sqlite3_str_appendall(pPattern, zLine); |
| 31732 | + } |
| 31733 | + zPattern = sqlite3_str_finish(pPattern); |
| 31734 | + if( zPattern==0 ){ |
| 31735 | + zPattern = sqlite3_mprintf(""); |
| 31736 | + } |
| 31737 | + }else{ |
| 31738 | + zPattern = zCheck; |
| 31739 | + } |
| 31740 | + shell_check_oom(zPattern); |
| 31741 | + switch( eCheck ){ |
| 31742 | + case 1: { |
| 31743 | + char *zGlob = sqlite3_mprintf("*%s*", zPattern); |
| 31744 | + isOk = testcase_glob(zGlob, zTest)!=0; |
| 31745 | + sqlite3_free(zGlob); |
| 31746 | + break; |
| 31747 | + } |
| 31748 | + case 2: { |
| 31749 | + char *zGlob = sqlite3_mprintf("*%s*", zPattern); |
| 31750 | + isOk = testcase_glob(zGlob, zTest)==0; |
| 31751 | + sqlite3_free(zGlob); |
| 31752 | + break; |
| 31753 | + } |
| 31754 | + case 3: { |
| 31755 | + isOk = cli_strcmp(zTest,zPattern)==0; |
| 31756 | + break; |
| 31757 | + } |
| 31758 | + default: { |
| 31759 | + /* Skip leading and trailing \n and \r on both pattern and test output */ |
| 31760 | + const char *z1 = zPattern; |
| 31761 | + const char *z2 = zTest; |
| 31762 | + size_t n1, n2; |
| 31763 | + while( z1[0]=='\n' || z1[0]=='\r' ) z1++; |
| 31764 | + n1 = strlen(z1); |
| 31765 | + while( n1>0 && (z1[n1-1]=='\n' || z1[n1-1]=='\r') ) n1--; |
| 31766 | + while( z2[0]=='\n' || z2[0]=='\r' ) z2++; |
| 31767 | + n2 = strlen(z2); |
| 31768 | + while( n2>0 && (z2[n2-1]=='\n' || z2[n2-1]=='\r') ) n2--; |
| 31769 | + isOk = n1==n2 && memcmp(z1,z2,n1)==0; |
| 31770 | + break; |
| 31771 | + } |
| 31772 | + } |
| 31773 | + if( !isOk ){ |
| 31774 | + sqlite3_fprintf(stderr, |
| 31775 | + "%s:%lld: .check failed for testcase %s\n", |
| 31776 | + p->zInFile, iStart, p->zTestcase); |
| 31777 | + p->nTestErr++; |
| 31778 | + sqlite3_fprintf(stderr, "Expected: [%s]\n", zPattern); |
| 31779 | + sqlite3_fprintf(stderr, "Got: [%s]\n", zTest); |
| 31780 | + } |
| 31781 | + if( zPattern!=zCheck ){ |
| 31782 | + sqlite3_free(zPattern); |
| 31783 | + } |
| 31784 | + if( !bKeep ){ |
| 31785 | + output_reset(p); |
| 31786 | + p->zTestcase[0] = 0; |
| 31787 | + } |
| 31788 | + return 0; |
| 31789 | +} |
| 31790 | + |
| 31791 | +/* |
| 31792 | +** DOT-COMMAND: .testcase |
| 31793 | +** USAGE: .testcase [OPTIONS] NAME |
| 31794 | +** |
| 31795 | +** Start a new test case identified by NAME. All output |
| 31796 | +** through the next ".check" command is captured for comparison. See the |
| 31797 | +** ".check" commandn for additional informatioon. |
| 31798 | +** |
| 31799 | +** Options: |
| 31800 | +** --error-prefix TEXT Change error message prefix text to TEXT |
| 31801 | +*/ |
| 31802 | +static int dotCmdTestcase(ShellState *p){ |
| 31803 | + int nArg = p->dot.nArg; /* Number of arguments */ |
| 31804 | + char **azArg = p->dot.azArg; /* Text of the arguments */ |
| 31805 | + int i; /* Loop counter */ |
| 31806 | + const char *zName = 0; /* Testcase name */ |
| 31807 | + |
| 31808 | + for(i=1; i<nArg; i++){ |
| 31809 | + char *z = azArg[i]; |
| 31810 | + if( z[0]=='-' && z[1]=='-' && z[2]!=0 ) z++; |
| 31811 | + if( optionMatch(z,"error-prefix") ){ |
| 31812 | + if( i+1>=nArg ){ |
| 31813 | + dotCmdError(p, i, "missing argument", 0); |
| 31814 | + return 1; |
| 31815 | + } |
| 31816 | + free(p->zErrPrefix); |
| 31817 | + i++; |
| 31818 | + p->zErrPrefix = azArg[i][0]==0 ? 0 : strdup(azArg[i]); |
| 31819 | + }else if( zName ){ |
| 31820 | + dotCmdError(p, i, "unknown option", 0); |
| 31821 | + return 1; |
| 31822 | + }else{ |
| 31823 | + zName = azArg[i]; |
| 31824 | + } |
| 31825 | + } |
| 31826 | + output_reset(p); |
| 31827 | + if( cli_output_capture ){ |
| 31828 | + sqlite3_str_free(cli_output_capture); |
| 31829 | + } |
| 31830 | + cli_output_capture = sqlite3_str_new(0); |
| 31831 | + if( zName ){ |
| 31832 | + sqlite3_snprintf(sizeof(p->zTestcase), p->zTestcase, "%s", zName); |
| 31833 | + }else{ |
| 31834 | + sqlite3_snprintf(sizeof(p->zTestcase), p->zTestcase, "%s:%lld", |
| 31835 | + p->zInFile, p->lineno); |
| 31836 | + } |
| 31837 | + return 0; |
| 31838 | +} |
| 31614 | 31839 | |
| 31615 | 31840 | /* |
| 31616 | 31841 | ** Enlarge the space allocated in p->dot so that it can hold more |
| 31617 | 31842 | ** than nArg parsed command-line arguments. |
| 31618 | 31843 | */ |
| | @@ -31641,11 +31866,11 @@ |
| 31641 | 31866 | free(p->dot.zCopy); |
| 31642 | 31867 | z = p->dot.zCopy = strdup(zLine); |
| 31643 | 31868 | shell_check_oom(z); |
| 31644 | 31869 | szLine = strlen(z); |
| 31645 | 31870 | while( szLine>0 && IsSpace(z[szLine-1]) ) szLine--; |
| 31646 | | - if( szLine>0 && z[szLine-1]==';' && p->iCompat>=20251115 ){ |
| 31871 | + if( szLine>0 && z[szLine-1]==';' ){ |
| 31647 | 31872 | szLine--; |
| 31648 | 31873 | while( szLine>0 && IsSpace(z[szLine-1]) ) szLine--; |
| 31649 | 31874 | } |
| 31650 | 31875 | z[szLine] = 0; |
| 31651 | 31876 | parseDotRealloc(p, 2); |
| | @@ -31861,35 +32086,17 @@ |
| 31861 | 32086 | eputz("Usage: .changes on|off\n"); |
| 31862 | 32087 | rc = 1; |
| 31863 | 32088 | } |
| 31864 | 32089 | }else |
| 31865 | 32090 | |
| 31866 | | -#ifndef SQLITE_SHELL_FIDDLE |
| 31867 | 32091 | /* Cancel output redirection, if it is currently set (by .testcase) |
| 31868 | 32092 | ** Then read the content of the testcase-out.txt file and compare against |
| 31869 | 32093 | ** azArg[1]. If there are differences, report an error and exit. |
| 31870 | 32094 | */ |
| 31871 | 32095 | if( c=='c' && n>=3 && cli_strncmp(azArg[0], "check", n)==0 ){ |
| 31872 | | - char *zRes = 0; |
| 31873 | | - output_reset(p); |
| 31874 | | - if( nArg!=2 ){ |
| 31875 | | - eputz("Usage: .check GLOB-PATTERN\n"); |
| 31876 | | - rc = 2; |
| 31877 | | - }else if( (zRes = readFile("testcase-out.txt", 0))==0 ){ |
| 31878 | | - rc = 2; |
| 31879 | | - }else if( testcase_glob(azArg[1],zRes)==0 ){ |
| 31880 | | - cli_printf(stderr, |
| 31881 | | - "testcase-%s FAILED\n Expected: [%s]\n Got: [%s]\n", |
| 31882 | | - p->zTestcase, azArg[1], zRes); |
| 31883 | | - rc = 1; |
| 31884 | | - }else{ |
| 31885 | | - cli_printf(p->out, "testcase-%s ok\n", p->zTestcase); |
| 31886 | | - p->nCheck++; |
| 31887 | | - } |
| 31888 | | - sqlite3_free(zRes); |
| 32096 | + rc = dotCmdCheck(p); |
| 31889 | 32097 | }else |
| 31890 | | -#endif /* !defined(SQLITE_SHELL_FIDDLE) */ |
| 31891 | 32098 | |
| 31892 | 32099 | #ifndef SQLITE_SHELL_FIDDLE |
| 31893 | 32100 | if( c=='c' && cli_strncmp(azArg[0], "clone", n)==0 ){ |
| 31894 | 32101 | failIfSafeMode(p, "cannot run .clone in safe mode"); |
| 31895 | 32102 | if( nArg==2 ){ |
| | @@ -32521,14 +32728,14 @@ |
| 32521 | 32728 | sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 0, 1); |
| 32522 | 32729 | goto meta_command_exit; |
| 32523 | 32730 | } |
| 32524 | 32731 | zSql = sqlite3_mprintf( |
| 32525 | 32732 | "SELECT rootpage, 0 FROM sqlite_schema" |
| 32526 | | - " WHERE name='%q' AND type='index'" |
| 32733 | + " WHERE type='index' AND lower(name)=lower('%q')" |
| 32527 | 32734 | "UNION ALL " |
| 32528 | 32735 | "SELECT rootpage, 1 FROM sqlite_schema" |
| 32529 | | - " WHERE name='%q' AND type='table'" |
| 32736 | + " WHERE type='table' AND lower(name)=lower('%q')" |
| 32530 | 32737 | " AND sql LIKE '%%without%%rowid%%'", |
| 32531 | 32738 | azArg[1], azArg[1] |
| 32532 | 32739 | ); |
| 32533 | 32740 | sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); |
| 32534 | 32741 | sqlite3_free(zSql); |
| | @@ -32682,13 +32889,14 @@ |
| 32682 | 32889 | goto meta_command_exit; |
| 32683 | 32890 | } |
| 32684 | 32891 | if( nArg==3 ){ |
| 32685 | 32892 | sqlite3_limit(p->db, aLimit[iLimit].limitCode, |
| 32686 | 32893 | (int)integerValue(azArg[2])); |
| 32894 | + }else{ |
| 32895 | + cli_printf(stdout, "%20s %d\n", aLimit[iLimit].zLimitName, |
| 32896 | + sqlite3_limit(p->db, aLimit[iLimit].limitCode, -1)); |
| 32687 | 32897 | } |
| 32688 | | - cli_printf(stdout, "%20s %d\n", aLimit[iLimit].zLimitName, |
| 32689 | | - sqlite3_limit(p->db, aLimit[iLimit].limitCode, -1)); |
| 32690 | 32898 | } |
| 32691 | 32899 | }else |
| 32692 | 32900 | |
| 32693 | 32901 | if( c=='l' && n>2 && cli_strncmp(azArg[0], "lint", n)==0 ){ |
| 32694 | 32902 | open_db(p, 0); |
| | @@ -34017,25 +34225,15 @@ |
| 34017 | 34225 | sqlite3_str_free(pSql); |
| 34018 | 34226 | modePop(p); |
| 34019 | 34227 | if( rc ) return shellDatabaseError(p->db); |
| 34020 | 34228 | }else |
| 34021 | 34229 | |
| 34022 | | -#ifndef SQLITE_SHELL_FIDDLE |
| 34023 | | - /* Begin redirecting output to the file "testcase-out.txt" */ |
| 34230 | + /* Set the p->zTestcase name and begin redirecting output into |
| 34231 | + ** the cli_output_capture sqlite3_str */ |
| 34024 | 34232 | if( c=='t' && cli_strcmp(azArg[0],"testcase")==0 ){ |
| 34025 | | - output_reset(p); |
| 34026 | | - p->out = output_file_open(p, "testcase-out.txt"); |
| 34027 | | - if( p->out==0 ){ |
| 34028 | | - eputz("Error: cannot open 'testcase-out.txt'\n"); |
| 34029 | | - } |
| 34030 | | - if( nArg>=2 ){ |
| 34031 | | - sqlite3_snprintf(sizeof(p->zTestcase), p->zTestcase, "%s", azArg[1]); |
| 34032 | | - }else{ |
| 34033 | | - sqlite3_snprintf(sizeof(p->zTestcase), p->zTestcase, "?"); |
| 34034 | | - } |
| 34233 | + rc = dotCmdTestcase(p); |
| 34035 | 34234 | }else |
| 34036 | | -#endif /* !defined(SQLITE_SHELL_FIDDLE) */ |
| 34037 | 34235 | |
| 34038 | 34236 | #ifndef SQLITE_UNTESTABLE |
| 34039 | 34237 | if( c=='t' && n>=8 && cli_strncmp(azArg[0], "testctrl", n)==0 ){ |
| 34040 | 34238 | static const struct { |
| 34041 | 34239 | const char *zCtrlName; /* Name of a test-control option */ |
| | @@ -35351,11 +35549,10 @@ |
| 35351 | 35549 | " -bail stop after hitting an error\n" |
| 35352 | 35550 | " -batch force batch I/O\n" |
| 35353 | 35551 | " -box set output mode to 'box'\n" |
| 35354 | 35552 | " -cmd COMMAND run \"COMMAND\" before reading stdin\n" |
| 35355 | 35553 | " -column set output mode to 'column'\n" |
| 35356 | | - " -compat YYYYMMDD set default options for date YYYYMMDD\n" |
| 35357 | 35554 | " -csv set output mode to 'csv'\n" |
| 35358 | 35555 | #if !defined(SQLITE_OMIT_DESERIALIZE) |
| 35359 | 35556 | " -deserialize open the database using sqlite3_deserialize()\n" |
| 35360 | 35557 | #endif |
| 35361 | 35558 | " -echo print inputs before execution\n" |
| | @@ -35435,15 +35632,10 @@ |
| 35435 | 35632 | /* |
| 35436 | 35633 | ** Initialize the state information in data |
| 35437 | 35634 | */ |
| 35438 | 35635 | static void main_init(ShellState *p) { |
| 35439 | 35636 | memset(p, 0, sizeof(*p)); |
| 35440 | | -#if defined(COMPATIBILITY_DATE) |
| 35441 | | - p->iCompat = COMPATIBILITY_DATE; |
| 35442 | | -#else |
| 35443 | | - p->iCompat = 20251116; |
| 35444 | | -#endif |
| 35445 | 35637 | p->pAuxDb = &p->aAuxDb[0]; |
| 35446 | 35638 | p->shellFlgs = SHFLG_Lookaside; |
| 35447 | 35639 | sqlite3_config(SQLITE_CONFIG_LOG, shellLog, p); |
| 35448 | 35640 | #if !defined(SQLITE_SHELL_FIDDLE) |
| 35449 | 35641 | verify_uninitialized(); |
| | @@ -35637,11 +35829,11 @@ |
| 35637 | 35829 | SQLITE_SHELL_DBNAME_PROC(&data.pAuxDb->zDbFilename); |
| 35638 | 35830 | warnInmemoryDb = 0; |
| 35639 | 35831 | } |
| 35640 | 35832 | #endif |
| 35641 | 35833 | |
| 35642 | | - /* Do an initial pass through the command-line argument to locate |
| 35834 | + /* Do an initial pass through the command-line arguments to locate |
| 35643 | 35835 | ** the name of the database file, the name of the initialization file, |
| 35644 | 35836 | ** the size of the alternative malloc heap, options affecting commands |
| 35645 | 35837 | ** or SQL run from the command line, and the first command to execute. |
| 35646 | 35838 | */ |
| 35647 | 35839 | #ifndef SQLITE_SHELL_FIDDLE |
| | @@ -35649,11 +35841,11 @@ |
| 35649 | 35841 | #endif |
| 35650 | 35842 | for(i=1; i<argc; i++){ |
| 35651 | 35843 | char *z; |
| 35652 | 35844 | z = argv[i]; |
| 35653 | 35845 | if( z[0]!='-' || i>nOptsEnd ){ |
| 35654 | | - if( data.aAuxDb->zDbFilename==0 ){ |
| 35846 | + if( data.aAuxDb->zDbFilename==0 && !isScriptFile(z,1) ){ |
| 35655 | 35847 | data.aAuxDb->zDbFilename = z; |
| 35656 | 35848 | }else{ |
| 35657 | 35849 | /* Excess arguments are interpreted as SQL (or dot-commands) and |
| 35658 | 35850 | ** mean that nothing is read from stdin */ |
| 35659 | 35851 | readStdin = 0; |
| | @@ -35694,15 +35886,10 @@ |
| 35694 | 35886 | if( n<2 ){ |
| 35695 | 35887 | sqlite3_fprintf(stderr,"minimum --screenwidth is 2\n"); |
| 35696 | 35888 | exit(1); |
| 35697 | 35889 | } |
| 35698 | 35890 | stdout_tty_width = n; |
| 35699 | | - }else if( cli_strcmp(z,"-compat")==0 ){ |
| 35700 | | - data.iCompat = atoi(cmdline_option_value(argc, argv, ++i)); |
| 35701 | | - modeFree(&data.mode); |
| 35702 | | - memset(&data.mode, 0, sizeof(data.mode)); |
| 35703 | | - modeDefault(&data); |
| 35704 | 35891 | }else if( cli_strcmp(z,"-utf8")==0 ){ |
| 35705 | 35892 | }else if( cli_strcmp(z,"-no-utf8")==0 ){ |
| 35706 | 35893 | }else if( cli_strcmp(z,"-no-rowid-in-view")==0 ){ |
| 35707 | 35894 | int val = 0; |
| 35708 | 35895 | sqlite3_config(SQLITE_CONFIG_ROWID_IN_VIEW, &val); |
| | @@ -35889,11 +36076,11 @@ |
| 35889 | 36076 | ** is given on the command line, look for a file named ~/.sqliterc and |
| 35890 | 36077 | ** try to process it. |
| 35891 | 36078 | */ |
| 35892 | 36079 | if( !noInit ) process_sqliterc(&data,zInitFile); |
| 35893 | 36080 | |
| 35894 | | - /* Make a second pass through the command-line argument and set |
| 36081 | + /* Make a second pass through the command-line arguments and set |
| 35895 | 36082 | ** options. This second pass is delayed until after the initialization |
| 35896 | 36083 | ** file is processed so that the command-line arguments will override |
| 35897 | 36084 | ** settings in the initialization file. |
| 35898 | 36085 | */ |
| 35899 | 36086 | for(i=1; i<argc; i++){ |
| | @@ -36015,12 +36202,10 @@ |
| 36015 | 36202 | stdin_is_interactive = 1; |
| 36016 | 36203 | }else if( cli_strcmp(z,"-batch")==0 ){ |
| 36017 | 36204 | /* already handled */ |
| 36018 | 36205 | }else if( cli_strcmp(z,"-screenwidth")==0 ){ |
| 36019 | 36206 | i++; |
| 36020 | | - }else if( cli_strcmp(z,"-compat")==0 ){ |
| 36021 | | - i++; |
| 36022 | 36207 | }else if( cli_strcmp(z,"-utf8")==0 ){ |
| 36023 | 36208 | /* already handled */ |
| 36024 | 36209 | }else if( cli_strcmp(z,"-no-utf8")==0 ){ |
| 36025 | 36210 | /* already handled */ |
| 36026 | 36211 | }else if( cli_strcmp(z,"-no-rowid-in-view")==0 ){ |
| | @@ -36116,11 +36301,22 @@ |
| 36116 | 36301 | ** command-line inputs, except for the argToSkip argument which contains |
| 36117 | 36302 | ** the database filename. |
| 36118 | 36303 | */ |
| 36119 | 36304 | for(i=0; i<nCmd; i++){ |
| 36120 | 36305 | echo_group_input(&data, azCmd[i]); |
| 36121 | | - if( azCmd[i][0]=='.' ){ |
| 36306 | + if( isScriptFile(azCmd[i],0) ){ |
| 36307 | + FILE *inSaved = data.in; |
| 36308 | + i64 savedLineno = data.lineno; |
| 36309 | + int res = 1; |
| 36310 | + if( (data.in = openChrSource(azCmd[i]))!=0 ){ |
| 36311 | + res = process_input(&data, azCmd[i]); |
| 36312 | + fclose(data.in); |
| 36313 | + } |
| 36314 | + data.in = inSaved; |
| 36315 | + data.lineno = savedLineno; |
| 36316 | + if( res ) i = nCmd; |
| 36317 | + }else if( azCmd[i][0]=='.' ){ |
| 36122 | 36318 | char *zErrCtx = malloc( 64 ); |
| 36123 | 36319 | shell_check_oom(zErrCtx); |
| 36124 | 36320 | sqlite3_snprintf(64,zErrCtx,"argv[%i]:",aiCmd[i]); |
| 36125 | 36321 | data.zInFile = "<cmdline>"; |
| 36126 | 36322 | data.zErrPrefix = zErrCtx; |
| 36127 | 36323 | |