From: larrybr Date: Thu, 9 Dec 2021 04:45:31 +0000 (+0000) Subject: Closer to passing all Tcl tests (with an odd failure) X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e1cb8f2639f6cbd891ac0e7f3738af3cf3505ebb;p=thirdparty%2Fsqlite.git Closer to passing all Tcl tests (with an odd failure) FossilOrigin-Name: 6956e989083462b6745276c45edcb03ac7ab9c31518e1f505bfae9e8f1cd2b2f --- diff --git a/manifest b/manifest index a6779bf78f..2f2e6685f8 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C For\sCLI,\sextensibility\srefinement\sand\ssmall\ssteps\stoward\sembedability -D 2021-12-07T23:02:06.142 +C Closer\sto\spassing\sall\sTcl\stests\s(with\san\sodd\sfailure) +D 2021-12-09T04:45:31.438 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -553,8 +553,8 @@ F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c F src/resolve.c 4a1db4aadd802683db40ca2dbbb268187bd195f10cbdb7206dbd8ac988795571 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 F src/select.c a7a3d9f54eb24821ec5f67f2e5589b68a5d42d46fc5849d7376886777d93a85a -F src/shell.c.in 39b615294d2ab0f3d536ee58d3f214260f5f05a6607403be2f4b4f9bde76a144 -F src/shext_linkage.h 3814c06a5367d68f58447ade09e62e430034c0e8301776a00d101097fec8e0c0 +F src/shell.c.in 5b021625a9a1cc483d264926f73faed57c3f44ed3868fb90631dee8444c49482 +F src/shext_linkage.h 1508132ce49c023d8ac445399fa275a01f27667f8686797051aefd1d6e8ae03a F src/sqlite.h.in 5cd209ac7dc4180f0e19292846f40440b8488015849ca0110c70b906b57d68f0 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 8ff2fd2c166150b2e48639f5e506fb44e29f1a3f65031710b9e89d1c126ac839 @@ -1382,11 +1382,11 @@ F test/sharedA.test 49d87ec54ab640fbbc3786ee3c01de94aaa482a3a9f834ad3fe92770eb69 F test/sharedB.test 16cc7178e20965d75278f410943109b77b2e645e F test/shared_err.test 32634e404a3317eeb94abc7a099c556a346fdb8fb3858dbe222a4cbb8926a939 F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304 -F test/shell1.test c354008b27c904f0166c2138abd7382013ea070b41114114ecbdfb32c726a807 -F test/shell2.test f00a0501c00583cbc46f7510e1d713366326b2b3e63d06d15937284171a8787c +F test/shell1.test f7cf041033277c0759aef303fcb42615e569163d23cc8e005deb37a9e29c419a +F test/shell2.test de123dd6be4b774b5ebdc81b29b3515c29c4a6a81bd5d2e1c38605d2f775a25a F test/shell3.test cb4b835a901742c9719437a89171172ecc4a8823ad97349af8e4e841e6f82566 F test/shell4.test 3ed6c4b42fd695efcbc25d69ef759dbb15855ca8e52ba6c5ee076f8b435f48be -F test/shell5.test 6e4aa0e531dcb8dcf74b7920a2a7442c6712d4dff8422bbc81f768f9dee8a0e3 +F test/shell5.test 596342db4ada597c6e021081a63f27be87eb5b1d8cf71028f3ec7dc17a8dd42e F test/shell6.test 1ceb51b2678c472ba6cf1e5da96679ce8347889fe2c3bf93a0e0fa73f00b00d3 F test/shell7.test 115132f66d0463417f408562cc2cf534f6bbc6d83a6d50f0072a9eb171bae97f F test/shell8.test 388471d16e4de767333107e30653983f186232c0e863f4490bb230419e830aae @@ -1936,7 +1936,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P a42fc4ac0804673fe05a8e73aa8ea8bbdf468b6857884a716518a8e5d8db1b17 -R 1d9fd67fab7ac9346e5d7ad9f044be52 +P ad9970bcb567822522c7ade3eb037cea34f7063ca2c8aa8255f95efc2d3a151a +R 0e0bcaff3be12fc0170b756b74e40946 U larrybr -Z d5470aed5062240658d4cb10e72d8599 +Z 2d67c5eaf96298415e54e025a60bff0e diff --git a/manifest.uuid b/manifest.uuid index cb301d8fb3..9e3562cddf 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ad9970bcb567822522c7ade3eb037cea34f7063ca2c8aa8255f95efc2d3a151a \ No newline at end of file +6956e989083462b6745276c45edcb03ac7ab9c31518e1f505bfae9e8f1cd2b2f \ No newline at end of file diff --git a/src/shell.c.in b/src/shell.c.in index efddc790f8..349409d29d 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -209,6 +209,9 @@ extern char *sqlite3_win32_utf8_to_mbcs_v2(const char *, int); extern LPWSTR sqlite3_win32_utf8_to_unicode(const char *zText); #endif +/* Get the shell extension interfaces and structs. */ +INCLUDE shext_linkage.h + /* For an embedded shell, allow the 3 standard streams to be specified. ** If used, these names will have to refer to something globally reachable. **/ @@ -1331,14 +1334,20 @@ static void shellPutsFunc( /* ** If in safe mode, print an error message described by the arguments -** and exit immediately. +** and "exit" without returning to the caller. This "exit" will occur +** immediately, as a process exit, for normal shell builds. When the +** shell is built with options to use it embedded, control returns to +** the caller of the shell's main, "do shell things" entry point. +** (TBD: Embedded exit arrangement) +** It is an error, (perhaps with only minor effect such as memory leak), +** for a meta-command to call this function while it holds resources. */ static void failIfSafeMode( ShellState *p, const char *zErrMsg, ... ){ - if( p->bSafeMode ){ + if( p->bSafeMode==1 ){ va_list ap; char *zMsg; va_start(ap, zErrMsg); @@ -3452,9 +3461,6 @@ static int expertFinish( return rc; } -#define NO_SUCH_COMMAND -0x7fff -#define INVALID_ARGS -0x7ffe - /* ** Implementation of ".expert" dot command. */ @@ -3972,6 +3978,20 @@ DISPATCH_CONFIG[ * Alternative is 0 and "%s\n" . */ +/* +** Output primary (single-line) help for a known command. +*/ +static void showPrimaryHelp(FILE *out, const char *zCmd){ + const char **pzH; + int nc = strlen30(zCmd); + for(pzH = azHelp; *pzH != 0; ++pzH){ + if( **pzH=='.' && strncmp(zCmd, (*pzH)+1, nc)==0 ){ + utf8_printf(out, HELP_TEXT_FMT, *pzH); + break; + } + } +} + /* ** Output various subsets of help text. These 5 are defined: ** 1. For all commands, primary help text only. @@ -6015,8 +6035,12 @@ static int arParseCommand( struct ArSwitch *pEnd = &aSwitch[nSwitch]; if( nArg<=1 ){ - utf8_printf(STD_ERR, "Wrong number of arguments. Usage:\n"); - return arUsage(STD_ERR); + utf8_printf(STD_ERR, "Error: Wrong number of arguments to \"%s\".\n", + azArg[0]); + if( stdin_is_interactive ){ + utf8_printf(STD_ERR, "Usage:\n"); + return arUsage(STD_ERR); + } }else{ char *z = azArg[1]; if( z[0]!='-' ){ @@ -6978,7 +7002,7 @@ static RecoverTable *recoverOrphanTable( } #endif /* !(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) */ -static int writeDb( char *azArg[], int nArg, ShellState *p ){ +static int writeDb( char *azArg[], int nArg, ShellState *p, char **pzErr ){ int rc = 0; const char *zDestFile = 0; const char *zDb = 0; @@ -6987,7 +7011,7 @@ static int writeDb( char *azArg[], int nArg, ShellState *p ){ int j; int bAsync = 0; const char *zVfs = 0; - failIfSafeMode(p, "cannot run .%s in safe mode", azArg[0]); + if( p->bSafeMode ) return SHELL_FORBIDDEN_OP; for(j=1; jbSafeMode ) return SHELL_FORBIDDEN_OP; return arDotCommand(p, 0, azArg, nArg); } @@ -7172,13 +7197,8 @@ COLLECT_HELP_TEXT[ ".bail on|off Stop after hitting an error. Default OFF", ]; DISPATCHABLE_COMMAND( bail 3 2 2 ){ - if( nArg==2 ){ - bail_on_error = booleanValue(azArg[1]); - return 0; - }else{ - raw_printf(STD_ERR, "Usage: .bail on|off\n"); - return 1; - } + bail_on_error = booleanValue(azArg[1]); + return 0; } /***************** @@ -7199,7 +7219,7 @@ DISPATCHABLE_COMMAND( binary 3 2 2 ){ DISPATCHABLE_COMMAND( cd ? 2 2 ){ int rc=0; - failIfSafeMode(p, "cannot run .cd in safe mode"); + if( p->bSafeMode ) return SHELL_FORBIDDEN_OP; #if defined(_WIN32) || defined(WIN32) wchar_t *z = sqlite3_win32_utf8_to_unicode(azArg[1]); rc = !SetCurrentDirectoryW(z); @@ -7244,15 +7264,15 @@ DISPATCHABLE_COMMAND( check 3 0 0 ){ int rc=0; output_reset(p); if( nArg!=2 ){ - raw_printf(STD_ERR, "Usage: .check GLOB-PATTERN\n"); - rc = 2; + return SHELL_INVALID_ARGS; }else if( (zRes = readFile("testcase-out.txt", 0))==0 ){ - raw_printf(STD_ERR, "Error: cannot read 'testcase-out.txt'\n"); + *pzErr = shellMPrintf(&rc, "Error: cannot read 'testcase-out.txt'"); rc = 2; }else if( testcase_glob(azArg[1],zRes)==0 ){ - utf8_printf(STD_ERR, - "testcase-%s FAILED\n Expected: [%s]\n Got: [%s]\n", - p->zTestcase, azArg[1], zRes); + *pzErr = + shellMPrintf(&rc, + "testcase-%s FAILED\n Expected: [%s]\n Got: [%s]\n", + p->zTestcase, azArg[1], zRes); rc = 1; }else{ utf8_printf(STD_OUT, "testcase-%s ok\n", p->zTestcase); @@ -7262,7 +7282,7 @@ DISPATCHABLE_COMMAND( check 3 0 0 ){ return rc; } DISPATCHABLE_COMMAND( clone ? 2 2 ){ - failIfSafeMode(p, "cannot run .clone in safe mode"); + if( p->bSafeMode ) return SHELL_FORBIDDEN_OP; tryToClone(p, azArg[1]); return 0; } @@ -7307,8 +7327,7 @@ DISPATCHABLE_COMMAND( connection ? 1 4 ){ p->aAuxDb[i].db = 0; } }else{ - raw_printf(STD_ERR, "Usage: .connection [close] [CONNECTION-NUMBER]\n"); - return 1; + return SHELL_INVALID_ARGS; } return 0; } @@ -7321,7 +7340,8 @@ COLLECT_HELP_TEXT[ ".dbconfig ?op? ?val? List or change sqlite3_db_config() options", ".dbinfo ?DB? Show status information about the database", ]; -DISPATCHABLE_COMMAND( databases 2 1 1 ){ +/* Allow garbage arguments on this, to be ignored. */ +DISPATCHABLE_COMMAND( databases 2 1 0 ){ int rc; char **azName = 0; int nName = 0; @@ -7330,7 +7350,7 @@ DISPATCHABLE_COMMAND( databases 2 1 1 ){ open_db(p, 0); rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0); if( rc ){ - utf8_printf(STD_ERR, "Error: %s\n", sqlite3_errmsg(p->db)); + *pzErr = sqlite3_mprintf("Error: %s\n", sqlite3_errmsg(p->db)); rc = 1; }else{ while( sqlite3_step(pStmt)==SQLITE_ROW ){ @@ -7394,8 +7414,10 @@ DISPATCHABLE_COMMAND( dbconfig 3 1 3 ){ if( nArg>1 ) break; } if( nArg>1 && ii==ArraySize(aDbConfig) ){ - utf8_printf(STD_ERR, "Error: unknown dbconfig \"%s\"\n", azArg[1]); - utf8_printf(STD_ERR, "Enter \".dbconfig\" with no arguments for a list\n"); + *pzErr = sqlite3_mprintf + ("Error: unknown dbconfig \"%s\"\n" + "Enter \".dbconfig\" with no arguments for a list\n", + azArg[1]); return 1; } return 0; @@ -7440,7 +7462,8 @@ DISPATCHABLE_COMMAND( dump ? 1 2 ){ if( z[0]=='-' ) z++; if( strcmp(z,"preserve-rowids")==0 ){ #ifdef SQLITE_OMIT_VIRTUALTABLE - raw_printf(STD_ERR, "The --preserve-rowids option is not compatible" + *pzErr = sqlite3_mprintf + ("The --preserve-rowids option is not compatible" " with SQLITE_OMIT_VIRTUALTABLE\n"); sqlite3_free(zLike); return 1; @@ -7455,7 +7478,8 @@ DISPATCHABLE_COMMAND( dump ? 1 2 ){ }else if( strcmp(z,"nosys")==0 ){ ShellSetFlag(p, SHFLG_DumpNoSys); }else{ - raw_printf(STD_ERR, "Unknown option \"%s\" on \".dump\"\n", azArg[i]); + *pzErr = sqlite3_mprintf + ("Unknown option \"%s\" on \".dump\"\n", azArg[i]); sqlite3_free(zLike); return 1; } @@ -7564,8 +7588,7 @@ DISPATCHABLE_COMMAND( eqp ? 0 0 ){ p->autoEQP = (u8)booleanValue(azArg[1]); } }else{ - raw_printf(STD_ERR, "Usage: .eqp off|on|trace|trigger|full\n"); - return 1; + return SHELL_INVALID_ARGS; } } @@ -7577,15 +7600,20 @@ COLLECT_HELP_TEXT[ ".expert Suggest indexes for queries", ".explain ?on|off|auto? Change the EXPLAIN formatting mode. Default: auto", ]; +DISPATCHABLE_COMMAND( expert ? 1 1 ){ + open_db(p, 0); + expertDotCommand(p, azArg, nArg); + return 0; +} DISPATCHABLE_COMMAND( explain ? 1 2 ){ /* The ".explain" command is automatic now. It is largely ** pointless, retained purely for backwards compatibility */ int val = 1; - if( nArg==2 ){ + if( nArg>1 ){ if( strcmp(azArg[1],"auto")==0 ){ val = 99; }else{ - val = booleanValue(azArg[1]); + val = booleanValue(azArg[1]); } } if( val==1 && p->mode!=MODE_Explain ){ @@ -7599,10 +7627,6 @@ DISPATCHABLE_COMMAND( explain ? 1 2 ){ if( p->mode==MODE_Explain ) p->mode = p->normalMode; p->autoExplain = 1; } -} -DISPATCHABLE_COMMAND( expert ? 1 1 ){ - open_db(p, 0); - expertDotCommand(p, azArg, nArg); return 0; } @@ -7626,19 +7650,20 @@ COLLECT_HELP_TEXT[ " -e Send output to the system text editor", " -x Send output as CSV to a spreadsheet (same as \".excel\")", ]; -static int outputRedirs(char *[], int, ShellState *, int bOnce, int eMode); +static int outputRedirs(char *[], int, ShellState *, + char **pzErr, int bOnce, int eMode); DISPATCHABLE_COMMAND( excel ? 1 2 ){ - return outputRedirs(azArg, nArg, p, 2, 'x'); + return outputRedirs(azArg, nArg, p, pzErr, 2, 'x'); } DISPATCHABLE_COMMAND( once ? 1 6 ){ - return outputRedirs(azArg, nArg, p, 1, 0); + return outputRedirs(azArg, nArg, p, pzErr, 1, 0); } DISPATCHABLE_COMMAND( output ? 1 6 ){ - return outputRedirs(azArg, nArg, p, 0, 0); + return outputRedirs(azArg, nArg, p, pzErr, 0, 0); } static int outputRedirs(char *azArg[], int nArg, ShellState *p, - int bOnce, int eMode){ + char **pzErr, int bOnce, int eMode){ /* bOnce => 0: .output, 1: .once, 2: .excel */ /* eMode => 'x' for excel, else 0 */ int rc = 0; @@ -7646,7 +7671,7 @@ static int outputRedirs(char *azArg[], int nArg, ShellState *p, int bTxtMode = 0; int i; int bBOM = 0; - failIfSafeMode(p, "cannot run .%s in safe mode", azArg[0]); + if( p->bSafeMode ) return SHELL_FORBIDDEN_OP; for(i=1; iout,"ERROR: unknown option: \"%s\". Usage:\n",azArg[i]); - showHelp(p->out, azArg[0]); - return 1; + *pzErr = sqlite3_mprintf(" unknown option: \"%s\"\n",azArg[i]); + return SHELL_INVALID_ARGS; } }else if( zFile==0 && eMode!='e' && eMode!='x' ){ zFile = sqlite3_mprintf("%s", z); @@ -7669,10 +7693,9 @@ static int outputRedirs(char *azArg[], int nArg, ShellState *p, break; } }else{ - utf8_printf(p->out,"ERROR: extra parameter: \"%s\". Usage:\n", azArg[i]); - showHelp(p->out, azArg[0]); + *pzErr = sqlite3_mprintf(" excess argument: \"%s\"\n", azArg[i]); sqlite3_free(zFile); - return 1; + return SHELL_INVALID_ARGS; } } if( zFile==0 ) zFile = sqlite3_mprintf("stdout"); @@ -7704,13 +7727,13 @@ static int outputRedirs(char *azArg[], int nArg, ShellState *p, #endif /* SQLITE_NOHAVE_SYSTEM */ if( zFile[0]=='|' ){ #ifdef SQLITE_OMIT_POPEN - raw_printf(STD_ERR, "Error: pipes are not supported in this OS\n"); + *pzErr = shellMPrintf(&rc, "Error: pipes are not supported in this OS\n"); rc = 1; p->out = STD_OUT; #else p->out = popen(zFile + 1, "w"); if( p->out==0 ){ - utf8_printf(STD_ERR,"Error: cannot open pipe \"%s\"\n", zFile + 1); + *pzErr = shellMPrintf(&rc, "Error: cannot open pipe \"%s\"\n", zFile + 1); p->out = STD_OUT; rc = 1; }else{ @@ -7722,7 +7745,8 @@ static int outputRedirs(char *azArg[], int nArg, ShellState *p, p->out = output_file_open(zFile, bTxtMode); if( p->out==0 ){ if( strcmp(zFile,"off")!=0 ){ - utf8_printf(STD_ERR,"Error: cannot write to \"%s\"\n", zFile); + *pzErr = shellMPrintf + (&rc, "Error: cannot write to \"%s\"\n", zFile); } p->out = STD_OUT; rc = 1; @@ -7903,8 +7927,7 @@ DISPATCHABLE_COMMAND( fullschema ? 1 2 ){ nArg = 1; } if( nArg!=1 ){ - raw_printf(STD_ERR, "Usage: .fullschema ?--indent?\n"); - return 1; + return SHELL_INVALID_ARGS; } open_db(p, 0); rc = sqlite3_exec(p->db, @@ -7945,7 +7968,7 @@ DISPATCHABLE_COMMAND( fullschema ? 1 2 ){ COLLECT_HELP_TEXT[ ".headers on|off Turn display of headers on or off", ]; -DISPATCHABLE_COMMAND( headers 6 1 2 ){ +DISPATCHABLE_COMMAND( headers 6 2 2 ){ p->showHeader = booleanValue(azArg[1]); p->shellFlgs |= SHFLG_HeaderSet; return 0; @@ -8013,7 +8036,7 @@ DISPATCHABLE_COMMAND( import ? 3 7 ){ int useOutputMode = 1; /* Use output mode to determine separators */ int rc = 0; - failIfSafeMode(p, "cannot run .import in safe mode"); + if(p->bSafeMode) return SHELL_FORBIDDEN_OP; memset(&sCtx, 0, sizeof(sCtx)); if( 0==(sCtx.z = sqlite3_malloc64(120)) ){ shell_out_of_memory(); @@ -8033,9 +8056,8 @@ DISPATCHABLE_COMMAND( import ? 3 7 ){ }else if( zTable==0 ){ zTable = z; }else{ - utf8_printf(p->out, "ERROR: extra argument: \"%s\". Usage:\n", z); - showHelp(p->out, "import"); - return 1; + *pzErr = sqlite3_mprintf(" surplus argument: \"%s\"\n", z); + return SHELL_INVALID_ARGS; } }else if( strcmp(z,"-v")==0 ){ eVerbose++; @@ -8052,38 +8074,35 @@ DISPATCHABLE_COMMAND( import ? 3 7 ){ xRead = csv_read_one_field; useOutputMode = 0; }else{ - utf8_printf(p->out, "ERROR: unknown option: \"%s\". Usage:\n", z); - showHelp(p->out, "import"); - return 1; + *pzErr = sqlite3_mprintf(" unknown option: \"%s\"", z); + return SHELL_INVALID_ARGS; } } if( zTable==0 ){ - utf8_printf(p->out, "ERROR: missing %s argument. Usage:\n", + *pzErr = sqlite3_mprintf(" missing %s argument.\n", zFile==0 ? "FILE" : "TABLE"); - showHelp(p->out, "import"); - return 1; + return SHELL_INVALID_ARGS; } seenInterrupt = 0; open_db(p, 0); if( useOutputMode ){ + const char *zYap = 0; /* If neither the --csv or --ascii options are specified, then set ** the column and row separator characters from the output mode. */ nSep = strlen30(p->colSeparator); if( nSep==0 ){ - raw_printf(STD_ERR, - "Error: non-null column separator required for import\n"); - return 1; + zYap = "Error: non-null column separator required for import"; } if( nSep>1 ){ - raw_printf(STD_ERR, - "Error: multi-character or multi-byte column separators" - " not allowed for import\n"); - return 1; + zYap = "Error: multi-character or multi-byte column separators" + " not allowed for import"; } nSep = strlen30(p->rowSeparator); if( nSep==0 ){ - raw_printf(STD_ERR, - "Error: non-null row separator required for import\n"); + zYap = "Error: non-null row separator required for import"; + } + if( zYap!=0 ){ + *pzErr = sqlite3_mprintf("%s\n", zYap); return 1; } if( nSep==2 && p->mode==MODE_Csv && strcmp(p->rowSeparator,SEP_CrLf)==0 ){ @@ -8095,8 +8114,8 @@ DISPATCHABLE_COMMAND( import ? 3 7 ){ nSep = strlen30(p->rowSeparator); } if( nSep>1 ){ - raw_printf(STD_ERR, "Error: multi-character row separators not allowed" - " for import\n"); + *pzErr = sqlite3_mprintf + ("Error: multi-character row separators not allowed for import\n"); return 1; } sCtx.cColSep = p->colSeparator[0]; @@ -8106,7 +8125,7 @@ DISPATCHABLE_COMMAND( import ? 3 7 ){ sCtx.nLine = 1; if( sCtx.zFile[0]=='|' ){ #ifdef SQLITE_OMIT_POPEN - raw_printf(STD_ERR, "Error: pipes are not supported in this OS\n"); + *pzErr = sqlite3_mprintf("Error: pipes are not supported in this OS\n"); return 1; #else sCtx.in = popen(sCtx.zFile+1, "r"); @@ -8118,7 +8137,7 @@ DISPATCHABLE_COMMAND( import ? 3 7 ){ sCtx.xCloser = fclose; } if( sCtx.in==0 ){ - utf8_printf(STD_ERR, "Error: cannot open \"%s\"\n", zFile); + *pzErr = sqlite3_mprintf("Error: cannot open \"%s\"\n", zFile); import_cleanup(&sCtx); return 1; } @@ -8155,7 +8174,7 @@ DISPATCHABLE_COMMAND( import ? 3 7 ){ if( cSep=='(' ){ sqlite3_free(zCreate); import_cleanup(&sCtx); - utf8_printf(STD_ERR,"%s: empty file\n", sCtx.zFile); + *pzErr = sqlite3_mprintf("%s: empty file\n", sCtx.zFile); return 1; } zCreate = sqlite3_mprintf("%z\n)", zCreate); @@ -8165,8 +8184,8 @@ DISPATCHABLE_COMMAND( import ? 3 7 ){ rc = sqlite3_exec(p->db, zCreate, 0, 0, 0); sqlite3_free(zCreate); if( rc ){ - utf8_printf(STD_ERR, "CREATE TABLE \"%s\"(...) failed: %s\n", zTable, - sqlite3_errmsg(p->db)); + *pzErr = sqlite3_mprintf("CREATE TABLE \"%s\"(...) failed: %s\n", + zTable, sqlite3_errmsg(p->db)); import_cleanup(&sCtx); return 1; } @@ -8175,7 +8194,7 @@ DISPATCHABLE_COMMAND( import ? 3 7 ){ sqlite3_free(zSql); if( rc ){ if (pStmt) sqlite3_finalize(pStmt); - utf8_printf(STD_ERR,"Error: %s\n", sqlite3_errmsg(p->db)); + *pzErr = sqlite3_mprintf("Error: %s\n", sqlite3_errmsg(p->db)); import_cleanup(&sCtx); return 1; } @@ -8202,7 +8221,7 @@ DISPATCHABLE_COMMAND( import ? 3 7 ){ rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); sqlite3_free(zSql); if( rc ){ - utf8_printf(STD_ERR, "Error: %s\n", sqlite3_errmsg(p->db)); + *pzErr = sqlite3_mprintf("Error: %s\n", sqlite3_errmsg(p->db)); if (pStmt) sqlite3_finalize(pStmt); import_cleanup(&sCtx); return 1; @@ -8293,8 +8312,8 @@ DISPATCHABLE_COMMAND( imposter ? 3 3 ){ int lenPK = 0; /* Length of the PRIMARY KEY string for isWO tables */ int i; if( !(nArg==3 || (nArg==2 && sqlite3_stricmp(azArg[1],"off")==0)) ){ - utf8_printf(STD_ERR, "Usage: .imposter INDEX IMPOSTER\n" - " .imposter off\n"); + *pzErr = sqlite3_mprintf("Usage: .imposter INDEX IMPOSTER\n" + " .imposter off\n"); /* Also allowed, but not documented: ** ** .imposter TABLE IMPOSTER @@ -8352,7 +8371,7 @@ DISPATCHABLE_COMMAND( imposter ? 3 3 ){ } sqlite3_finalize(pStmt); if( i==0 || tnum==0 ){ - utf8_printf(STD_ERR, "no such index: \"%s\"\n", azArg[1]); + *pzErr = sqlite3_mprintf("no such index: \"%s\"\n", azArg[1]); sqlite3_free(zCollist); return 1; } @@ -8366,7 +8385,8 @@ DISPATCHABLE_COMMAND( imposter ? 3 3 ){ rc = sqlite3_exec(p->db, zSql, 0, 0, 0); sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 0, 0); if( rc ){ - utf8_printf(STD_ERR, "Error in [%s]: %s\n", zSql, sqlite3_errmsg(p->db)); + *pzErr = sqlite3_mprintf("Error in [%s]: %s\n", + zSql, sqlite3_errmsg(p->db)); }else{ utf8_printf(STD_OUT, "%s;\n", zSql); raw_printf(STD_OUT, @@ -8375,7 +8395,7 @@ DISPATCHABLE_COMMAND( imposter ? 3 3 ){ ); } }else{ - raw_printf(STD_ERR, "SQLITE_TESTCTRL_IMPOSTER returns %d\n", rc); + *pzErr = sqlite3_mprintf("SQLITE_TESTCTRL_IMPOSTER returns %d\n", rc); } sqlite3_free(zSql); return rc != 0; @@ -8392,7 +8412,7 @@ DISPATCHABLE_COMMAND( iotrace ? 2 2 ){ }else{ iotrace = fopen(azArg[1], "w"); if( iotrace==0 ){ - utf8_printf(STD_ERR, "Error: cannot open \"%s\"\n", azArg[1]); + *pzErr = sqlite3_mprintf("Error: cannot open \"%s\"\n", azArg[1]); sqlite3IoTrace = 0; return 1; }else{ @@ -8427,8 +8447,7 @@ DISPATCHABLE_COMMAND( limits 5 1 3 ){ sqlite3_limit(p->db, aLimit[i].limitCode, -1)); } }else if( nArg>3 ){ - raw_printf(STD_ERR, "Usage: .limit NAME ?NEW-VALUE?\n"); - return 1; + return SHELL_INVALID_ARGS; }else{ int iLimit = -1; n2 = strlen30(azArg[1]); @@ -8437,15 +8456,16 @@ DISPATCHABLE_COMMAND( limits 5 1 3 ){ if( iLimit<0 ){ iLimit = i; }else{ - utf8_printf(STD_ERR, "ambiguous limit: \"%s\"\n", azArg[1]); + *pzErr = sqlite3_mprintf("ambiguous limit: \"%s\"\n", azArg[1]); return 1; } } } if( iLimit<0 ){ - utf8_printf(STD_ERR, "unknown limit: \"%s\"\n" - "enter \".limits\" with no arguments for a list.\n", - azArg[1]); + *pzErr = sqlite3_mprintf + ("unknown limit: \"%s\"\n" + "enter \".limits\" with no arguments for a list.\n", + azArg[1]); return 1; } if( nArg==3 ){ @@ -8464,23 +8484,21 @@ DISPATCHABLE_COMMAND( lint 3 1 0 ){ if( n>0 && !sqlite3_strnicmp(azArg[1], "fkey-indexes", n) ){ return lintFkeyIndexes(p, azArg, nArg); } - raw_printf(STD_ERR, - "Usage %s sub-command ?switches...?\n" - "Where sub-commands are:\n" - " fkey-indexes\n", azArg[0]); + *pzErr = sqlite3_mprintf + ("Usage %s sub-command ?switches...?\n" + "Where sub-commands are:\n" + " fkey-indexes\n", azArg[0]); return 1; } DISPATCHABLE_COMMAND( load ? 2 3 ){ const char *zFile, *zProc; char *zErrMsg = 0; - failIfSafeMode(p, "cannot run .load in safe mode"); + if( p->bSafeMode ) return SHELL_FORBIDDEN_OP; zFile = azArg[1]; zProc = nArg>=3 ? azArg[2] : 0; open_db(p, 0); - if( SQLITE_OK!=sqlite3_load_extension(p->db, zFile, zProc, &zErrMsg)){ - utf8_printf(STD_ERR, "Error: %s\n", zErrMsg); - sqlite3_free(zErrMsg); + if( SQLITE_OK!=sqlite3_load_extension(p->db, zFile, zProc, pzErr) ){ return 1; } return 0; @@ -8488,7 +8506,7 @@ DISPATCHABLE_COMMAND( load ? 2 3 ){ DISPATCHABLE_COMMAND( log ? 2 2 ){ const char *zFile = azArg[1]; - failIfSafeMode(p, "cannot run .log in safe mode"); + if( p->bSafeMode ) return SHELL_FORBIDDEN_OP; output_file_close(p->pLog); p->pLog = output_file_open(zFile, 0); return 0; @@ -8515,11 +8533,16 @@ COLLECT_HELP_TEXT[ " tabs Tab-separated values", " tcl TCL list elements", ]; -DISPATCHABLE_COMMAND( mode ? 2 3 ){ +DISPATCHABLE_COMMAND( mode ? 1 3 ){ const char *zMode = nArg>=2 ? azArg[1] : ""; int n2 = strlen30(zMode); int c2 = zMode[0]; - if( c2=='l' && n2>2 && strncmp(azArg[1],"lines",n2)==0 ){ + if( c2=='i' && strncmp(azArg[1],"insert",n2)==0 ){ + p->mode = MODE_Insert; + set_table_name(p, nArg>=3 ? azArg[2] : "table"); + }else if( nArg>2 ){ + return SHELL_INVALID_ARGS; + }else if( c2=='l' && n2>2 && strncmp(azArg[1],"lines",n2)==0 ){ p->mode = MODE_Line; sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row); }else if( c2=='c' && strncmp(azArg[1],"columns",n2)==0 ){ @@ -8545,9 +8568,6 @@ DISPATCHABLE_COMMAND( mode ? 2 3 ){ }else if( c2=='t' && strncmp(azArg[1],"tabs",n2)==0 ){ p->mode = MODE_List; sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Tab); - }else if( c2=='i' && strncmp(azArg[1],"insert",n2)==0 ){ - p->mode = MODE_Insert; - set_table_name(p, nArg>=3 ? azArg[2] : "table"); }else if( c2=='q' && strncmp(azArg[1],"quote",n2)==0 ){ p->mode = MODE_Quote; sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma); @@ -8567,9 +8587,9 @@ DISPATCHABLE_COMMAND( mode ? 2 3 ){ }else if( nArg==1 ){ raw_printf(p->out, "current output mode: %s\n", modeDescr[p->mode]); }else{ - raw_printf(STD_ERR, "Error: mode should be one of: " - "ascii box column csv html insert json line\n" - " list markdown quote table tabs tcl\n"); + *pzErr = sqlite3_mprintf + ("Error: mode should be one of: ascii box column csv html\n" + " insert json line list markdown quote table tabs tcl\n"); return 1; } p->cMode = p->mode; @@ -8632,6 +8652,7 @@ DISPATCHABLE_COMMAND( open 3 1 0 ){ int iName = 1; /* Index in azArg[] of the filename */ int newFlag = 0; /* True to delete file before opening */ int openMode = SHELL_OPEN_UNSPEC; + int rc = 0; /* Check for command-line arguments */ for(iName=1; iNameszMax = integerValue(azArg[++iName]); #endif /* SQLITE_OMIT_DESERIALIZE */ }else if( z[0]=='-' ){ - utf8_printf(STD_ERR, "unknown option: %s\n", z); - return 1; + *pzErr = sqlite3_mprintf("unknown option: %s\n", z); + return SHELL_INVALID_ARGS; }else if( zNewFilename ){ - utf8_printf(STD_ERR, "extra argument: \"%s\"\n", z); - return 1; + *pzErr = sqlite3_mprintf("extra argument: \"%s\"\n", z); + return SHELL_INVALID_ARGS; }else{ zNewFilename = sqlite3_mprintf("%s", z); } @@ -8685,13 +8706,15 @@ DISPATCHABLE_COMMAND( open 3 1 0 ){ && zNewFilename && strcmp(zNewFilename,":memory:")!=0 ){ - failIfSafeMode(p, "cannot open disk-based database files in safe mode"); + *pzErr = sqlite3_mprintf("open disk-based databases"); + return SHELL_FORBIDDEN_OP; } p->pAuxDb->zDbFilename = zNewFilename; open_db(p, OPEN_DB_KEEPALIVE); if( p->db==0 ){ - utf8_printf(STD_ERR, "Error: cannot open '%s'\n", zNewFilename); + *pzErr = sqlite3_mprintf("Error: cannot open '%s'\n", zNewFilename); sqlite3_free(zNewFilename); + rc = 1; }else{ p->pAuxDb->zFreeOnClose = zNewFilename; } @@ -8701,7 +8724,7 @@ DISPATCHABLE_COMMAND( open 3 1 0 ){ p->pAuxDb->zDbFilename = 0; open_db(p, 0); } - return 0; + return rc; } DISPATCHABLE_COMMAND( nonce ? 2 2 ){ @@ -8888,15 +8911,15 @@ DISPATCHABLE_COMMAND( progress 3 2 0 ){ } if( strcmp(z,"limit")==0 ){ if( i+1>=nArg ){ - utf8_printf(STD_ERR, "Error: missing argument on --limit\n"); - return 1; + *pzErr = sqlite3_mprintf("Error: missing argument on --limit\n"); + return SHELL_INVALID_ARGS; }else{ p->mxProgress = (int)integerValue(azArg[++i]); } continue; } - utf8_printf(STD_ERR, "Error: unknown option: \"%s\"\n", azArg[i]); - return 1; + *pzErr = sqlite3_mprintf("Error: unknown option: \"%s\"\n", azArg[i]); + return SHELL_INVALID_ARGS; }else{ nn = (int)integerValue(z); } @@ -8905,7 +8928,8 @@ DISPATCHABLE_COMMAND( progress 3 2 0 ){ sqlite3_progress_handler(p->db, nn, progress_handler, p); return 0; } -DISPATCHABLE_COMMAND( prompt ? 2 3 ){ +/* Allow too few arguments by tradition, (a form of no-op.) */ +DISPATCHABLE_COMMAND( prompt ? 1 3 ){ if( nArg >= 2) { strncpy(mainPrompt,azArg[1],(int)ArraySize(mainPrompt)-1); } @@ -8933,16 +8957,16 @@ DISPATCHABLE_COMMAND( read 3 2 2 ){ int rc = 0; FILE *inSaved = p->in; int savedLineno = p->lineno; - failIfSafeMode(p, "cannot run .read in safe mode"); + if( p->bSafeMode ) return SHELL_FORBIDDEN_OP; if( azArg[1][0]=='|' ){ #ifdef SQLITE_OMIT_POPEN - raw_printf(STD_ERR, "Error: pipes are not supported in this OS\n"); + *pzErr = sqlite3_mprintf("Error: pipes are not supported in this OS\n"); rc = 1; p->out = STD_OUT; #else p->in = popen(azArg[1]+1, "r"); if( p->in==0 ){ - utf8_printf(STD_ERR, "Error: cannot open \"%s\"\n", azArg[1]); + *pzErr = sqlite3_mprintf("Error: cannot open \"%s\"\n", azArg[1]); rc = 1; }else{ rc = process_input(p); @@ -8950,7 +8974,7 @@ DISPATCHABLE_COMMAND( read 3 2 2 ){ } #endif }else if( (p->in = openChrSource(azArg[1]))==0 ){ - utf8_printf(STD_ERR,"Error: cannot open \"%s\"\n", azArg[1]); + *pzErr = sqlite3_mprintf("Error: cannot open \"%s\"\n", azArg[1]); rc = 1; }else{ rc = process_input(p); @@ -9000,7 +9024,7 @@ DISPATCHABLE_COMMAND( recover ? 1 7 ){ bRowids = 0; } else{ - utf8_printf(STD_ERR, "unexpected option: %s\n", azArg[i]); + *pzErr = sqlite3_mprintf("unexpected option: %s\n", azArg[i]); showHelp(p->out, azArg[0]); return 1; } @@ -9289,7 +9313,7 @@ DISPATCHABLE_COMMAND( restore ? 2 3 ){ sqlite3_backup *pBackup; int nTimeout = 0; - failIfSafeMode(p, "cannot run .restore in safe mode"); + if( p->bSafeMode ) return SHELL_FORBIDDEN_OP; if( nArg==2 ){ zSrcFile = azArg[1]; zDb = "main"; @@ -9297,19 +9321,18 @@ DISPATCHABLE_COMMAND( restore ? 2 3 ){ zSrcFile = azArg[2]; zDb = azArg[1]; }else{ - raw_printf(STD_ERR, "Usage: .restore ?DB? FILE\n"); - return 1; + return SHELL_INVALID_ARGS; } rc = sqlite3_open(zSrcFile, &pSrc); if( rc!=SQLITE_OK ){ - utf8_printf(STD_ERR, "Error: cannot open \"%s\"\n", zSrcFile); + *pzErr = sqlite3_mprintf("Error: cannot open \"%s\"\n", zSrcFile); close_db(pSrc); return 1; } open_db(p, 0); pBackup = sqlite3_backup_init(p->db, zDb, pSrc, "main"); if( pBackup==0 ){ - utf8_printf(STD_ERR, "Error: %s\n", sqlite3_errmsg(p->db)); + *pzErr = sqlite3_mprintf("Error: %s\n", sqlite3_errmsg(p->db)); close_db(pSrc); return 1; } @@ -9324,10 +9347,10 @@ DISPATCHABLE_COMMAND( restore ? 2 3 ){ if( rc==SQLITE_DONE ){ rc = 0; }else if( rc==SQLITE_BUSY || rc==SQLITE_LOCKED ){ - raw_printf(STD_ERR, "Error: source database is busy\n"); + *pzErr = sqlite3_mprintf("Error: source database is busy\n"); rc = 1; }else{ - utf8_printf(STD_ERR, "Error: %s\n", sqlite3_errmsg(p->db)); + *pzErr = sqlite3_mprintf("Error: %s\n", sqlite3_errmsg(p->db)); rc = 1; } close_db(pSrc); @@ -9376,13 +9399,12 @@ DISPATCHABLE_COMMAND( schema ? 1 2 ){ }else if( optionMatch(azArg[ii],"nosys") ){ bNoSystemTabs = 1; }else if( azArg[ii][0]=='-' ){ - utf8_printf(STD_ERR, "Unknown option: \"%s\"\n", azArg[ii]); - return 1; + *pzErr = sqlite3_mprintf("Unknown option: \"%s\"\n", azArg[ii]); + return SHELL_INVALID_ARGS; }else if( zName==0 ){ zName = azArg[ii]; }else{ - raw_printf(STD_ERR, "Usage: .schema ?--indent? ?--nosys? ?LIKE-PATTERN?\n"); - return 1; + return SHELL_INVALID_ARGS; } } if( zName!=0 ){ @@ -9412,7 +9434,7 @@ DISPATCHABLE_COMMAND( schema ? 1 2 ){ rc = sqlite3_prepare_v2(p->db, "SELECT name FROM pragma_database_list", -1, &pStmt, 0); if( rc ){ - utf8_printf(STD_ERR, "Error: %s\n", sqlite3_errmsg(p->db)); + *pzErr = sqlite3_mprintf("Error: %s\n", sqlite3_errmsg(p->db)); sqlite3_finalize(pStmt); return 1; } @@ -9478,11 +9500,10 @@ DISPATCHABLE_COMMAND( schema ? 1 2 ){ freeText(&sSelect); } if( zErrMsg ){ - utf8_printf(STD_ERR,"Error: %s\n", zErrMsg); - sqlite3_free(zErrMsg); + *pzErr = zErrMsg; rc = 1; }else if( rc != SQLITE_OK ){ - raw_printf(STD_ERR,"Error: querying schema information\n"); + *pzErr = sqlite3_mprintf("Error: querying schema information\n"); rc = 1; }else{ rc = 0; @@ -9586,8 +9607,9 @@ DISPATCHABLE_COMMAND( session 3 2 0 ){ if( pSession->p==0 ) goto session_not_open; out = fopen(azCmd[1], "wb"); if( out==0 ){ - utf8_printf(STD_ERR, "ERROR: cannot open \"%s\" for writing\n", - azCmd[1]); + *pzErr = sqlite3_mprintf + ("ERROR: cannot open \"%s\" for writing\n", azCmd[1]); + rc = 1; }else{ int szChng; void *pChng; @@ -9600,8 +9622,7 @@ DISPATCHABLE_COMMAND( session 3 2 0 ){ fprintf(STD_OUT, "Error: error code %d\n", rc); rc = 0; } - if( pChng - && fwrite(pChng, szChng, 1, out)!=1 ){ + if( pChng && fwrite(pChng, szChng, 1, out)!=1 ){ raw_printf(STD_ERR, "ERROR: Failed to write entire %d-byte output\n", szChng); } @@ -9649,8 +9670,7 @@ DISPATCHABLE_COMMAND( session 3 2 0 ){ nByte = sizeof(pSession->azFilter[0])*(nCmd-1); pSession->azFilter = sqlite3_malloc( nByte ); if( pSession->azFilter==0 ){ - raw_printf(STD_ERR, "Error: out or memory\n"); - exit(1); + shell_out_of_memory(); } for(ii=1; iiazFilter[ii-1] = sqlite3_mprintf("%s", azCmd[ii]); @@ -9711,14 +9731,16 @@ DISPATCHABLE_COMMAND( session 3 2 0 ){ } } if( pAuxDb->nSession>=ArraySize(pAuxDb->aSession) ){ - raw_printf(STD_ERR, "Maximum of %d sessions\n", - ArraySize(pAuxDb->aSession)); + raw_printf + (STD_ERR, "Maximum of %d sessions\n", + ArraySize(pAuxDb->aSession)); return rc; } pSession = &pAuxDb->aSession[pAuxDb->nSession]; rc = sqlite3session_create(p->db, azCmd[1], &pSession->p); if( rc ){ - raw_printf(STD_ERR, "Cannot open session: error code=%d\n", rc); + *pzErr = sqlite3_mprintf + ("Cannot open session: error code=%d\n", rc); return rc; } pSession->nFilter = 0; @@ -9763,14 +9785,12 @@ DISPATCHABLE_COMMAND( sha3sum 4 1 1 ){ bDebug = 1; }else { - utf8_printf(STD_ERR, "Unknown option \"%s\" on \"%s\"\n", - azArg[i], azArg[0]); - showHelp(p->out, azArg[0]); - return 1; + *pzErr = sqlite3_mprintf + ("Unknown option \"%s\" on \"%s\"\n", azArg[i], azArg[0]); + return SHELL_INVALID_ARGS; } }else if( zLike ){ - raw_printf(STD_ERR, "Usage: .sha3sum ?OPTIONS? ?LIKE-PATTERN?\n"); - return 1; + return SHELL_INVALID_ARGS; }else{ zLike = z; bSeparate = 1; @@ -9887,9 +9907,9 @@ DISPATCHABLE_COMMAND( selftest 4 0 0 ){ bVerbose++; }else { - utf8_printf(STD_ERR, "Unknown option \"%s\" on \"%s\"\n", - azArg[i], azArg[0]); - raw_printf(STD_ERR, "Should be one of: --init -v\n"); + *pzErr = sqlite3_mprintf + ("Unknown option \"%s\" on \"%s\"\n" + "Should be one of: --init -v\n", azArg[i], azArg[0]); return 1; } } @@ -9917,7 +9937,7 @@ DISPATCHABLE_COMMAND( selftest 4 0 0 ){ -1, &pStmt, 0); } if( rc ){ - raw_printf(STD_ERR, "Error querying the selftest table\n"); + *pzErr = sqlite3_mprintf("Error querying the selftest table\n"); sqlite3_finalize(pStmt); return 1; } @@ -9958,8 +9978,8 @@ DISPATCHABLE_COMMAND( selftest 4 0 0 ){ } }else { - utf8_printf(STD_ERR, - "Unknown operation \"%s\" on selftest line %d\n", zOp, tno); + *pzErr = sqlite3_mprintf + ("Unknown operation \"%s\" on selftest line %d\n", zOp, tno); rc = 1; break; } @@ -9971,10 +9991,10 @@ DISPATCHABLE_COMMAND( selftest 4 0 0 ){ return rc > 0; } #ifndef SQLITE_NOHAVE_SYSTEM -static int shellOut(char *azArg[], int nArg, ShellState *p){ +static int shellOut(char *azArg[], int nArg, ShellState *p, char **pzErr){ char *zCmd; int i, x; - failIfSafeMode(p, "cannot run .%s in safe mode", azArg[0]); + if( p->bSafeMode ) return SHELL_FORBIDDEN_OP; zCmd = sqlite3_mprintf(strchr(azArg[1],' ')==0?"%s":"\"%s\"", azArg[1]); for(i=2; idb, p, 0); }else{ - raw_printf(STD_ERR, "Usage: .stats ?on|off|stmt|vmstep?\n"); + *pzErr = sqlite3_mprintf("Usage: .stats ?on|off|stmt|vmstep?\n"); return 1; } return 0; @@ -10057,7 +10077,8 @@ COLLECT_HELP_TEXT[ " If TABLE is specified, only show indexes for", " tables matching TABLE using the LIKE operator.", ]; -static int showTableLike(char *azArg[], int nArg, ShellState *p, char ot){ +static int showTableLike(char *azArg[], int nArg, ShellState *p, + char **pzErr, char ot){ int rc; sqlite3_stmt *pStmt; char **azResult; @@ -10076,7 +10097,7 @@ static int showTableLike(char *azArg[], int nArg, ShellState *p, char ot){ /* It is an historical accident that the .indexes command shows an error ** when called with the wrong number of arguments whereas the .tables ** command does not. */ - raw_printf(STD_ERR, "Usage: .indexes ?LIKE-PATTERN?\n"); + *pzErr = sqlite3_mprintf("Usage: .indexes ?LIKE-PATTERN?\n"); sqlite3_finalize(pStmt); return 1; } @@ -10205,17 +10226,17 @@ DISPATCHABLE_COMMAND( tables 2 1 3 ){ --nArg; break; default: - return INVALID_ARGS; + return SHELL_INVALID_ARGS; } } #endif - return showTableLike(azArg, nArg, p, objType); + return showTableLike(azArg, nArg, p, pzErr, objType); } DISPATCHABLE_COMMAND( indexes 3 1 2 ){ - return showTableLike(azArg, nArg, p, 'i'); + return showTableLike(azArg, nArg, p, pzErr, 'i'); } DISPATCHABLE_COMMAND( indices 3 1 2 ){ - return showTableLike(azArg, nArg, p, 'i'); + return showTableLike(azArg, nArg, p, pzErr, 'i'); } /***************** @@ -10350,8 +10371,9 @@ DISPATCHABLE_COMMAND( testctrl ? 0 0 ){ testctrl = aCtrl[i].ctrlCode; iCtrl = i; }else{ - utf8_printf(STD_ERR, "Error: ambiguous test-control: \"%s\"\n" - "Use \".testctrl --help\" for help\n", zCmd); + *pzErr = sqlite3_mprintf + ("Error: ambiguous test-control: \"%s\"\n" + "Use \".testctrl --help\" for help\n", zCmd); return 1; } } @@ -10508,7 +10530,7 @@ DISPATCHABLE_COMMAND( testctrl ? 0 0 ){ } return 0; } -DISPATCHABLE_COMMAND( timeout 4 2 2 ){ +DISPATCHABLE_COMMAND( timeout 4 1 2 ){ open_db(p, 0); sqlite3_busy_timeout(p->db, nArg>=2 ? (int)integerValue(azArg[1]) : 0); return 0; @@ -10552,7 +10574,7 @@ DISPATCHABLE_COMMAND( trace ? 0 0 ){ mType |= SQLITE_TRACE_CLOSE; } else { - raw_printf(STD_ERR, "Unknown option \"%s\" on \".trace\"\n", z); + *pzErr = sqlite3_mprintf("Unknown option \"%s\" on \".trace\"\n", z); return 1; } }else{ @@ -10586,19 +10608,18 @@ DISPATCHABLE_COMMAND( user ? 0 0 ){ ; if( nArg<2 ){ teach_fail: - raw_printf(STD_ERR, usage); + *pzErr = sqlite3_mprintf(usage); return 1; } open_db(p, 0); if( strcmp(azArg[1],"login")==0 ){ if( nArg!=4 ){ - raw_printf(STD_ERR, usage); - return 1; + goto teach_fail; } rc = sqlite3_user_authenticate(p->db, azArg[2], azArg[3], strlen30(azArg[3])); if( rc ){ - utf8_printf(STD_ERR, "Authentication failed for user %s\n", azArg[2]); + *pzErr = sqlite3_mprintf("Authentication failed for user %s\n", azArg[2]); return 1; } }else if( strcmp(azArg[1],"add")==0 ){ @@ -10608,7 +10629,7 @@ DISPATCHABLE_COMMAND( user ? 0 0 ){ rc = sqlite3_user_add(p->db, azArg[2], azArg[3], strlen30(azArg[3]), booleanValue(azArg[4])); if( rc ){ - raw_printf(STD_ERR, "User-Add failed: %d\n", rc); + *pzErr = sqlite3_mprintf("User-Add failed: %d\n", rc); return 1; } }else if( strcmp(azArg[1],"edit")==0 ){ @@ -10618,7 +10639,7 @@ DISPATCHABLE_COMMAND( user ? 0 0 ){ rc = sqlite3_user_change(p->db, azArg[2], azArg[3], strlen30(azArg[3]), booleanValue(azArg[4])); if( rc ){ - raw_printf(STD_ERR, "User-Edit failed: %d\n", rc); + *pzErr = sqlite3_mprintf("User-Edit failed: %d\n", rc); return 1; } }else if( strcmp(azArg[1],"delete")==0 ){ @@ -10627,7 +10648,7 @@ DISPATCHABLE_COMMAND( user ? 0 0 ){ } rc = sqlite3_user_delete(p->db, azArg[2]); if( rc ){ - raw_printf(STD_ERR, "User-Delete failed: %d\n", rc); + *pzErr = sqlite3_mprintf("User-Delete failed: %d\n", rc); return 1; } }else{ @@ -10743,15 +10764,12 @@ COMMENT section to define new or altered meta-commands and their help text. */ INCLUDE( COMMAND_CUSTOMIZE ); -#if OBJECTIFY_COMMANDS -INCLUDE shext_linkage.h -#endif typedef struct MetaCommand MetaCommand; /* Define and populate command dispatch table. */ static struct CommandInfo { const char * cmdName; - int (*cmdDoer)(char *azArg[], int nArg, ShellState *); + int (*cmdDoer)(char *azArg[], int nArg, ShellState *, char **pzErr); unsigned char minLen, minArgs, maxArgs; #if OBJECTIFY_COMMANDS const char *azHelp[2]; /* primary and secondary help text */ @@ -10791,12 +10809,23 @@ static const char *(azHelp[]) = { 0 /* Sentinel */ }; -/***************** - * Command dispatcher - */ -int dispatchCommand(char *azArg[], int nArg, ShellState *pSS) -{ +#define NO_SUCH_COMMAND SQLITE_NOTFOUND +/* SHELL_INVALID_ARGS defined as SQLITE_MISUSE in shext_linkage.h */ + +/***************** +** Command dispatcher +** For the non-extended or non-extensible shell, this function does +** a binary search of the fixed list of meta-command info structs. +** For an extended shell, it may (TBD) query the shell's DB. Either +** way, this function retains its interface. +** After successful command lookup and (simple) argument checking, +** it calls the found meta-command with the input arguments (except +** that azArg[0] is replaced with the properly spelled command name.) +** The return is either a dispatch error or whatever the dispatched +** meta-command returns. +*/ +int dispatchCommand(char *azArg[], int nArg, ShellState *pSS, char **pzErr){ const char *cmdName = azArg[0]; int cmdLen = strlen30(cmdName); struct CommandInfo *pci = 0; @@ -10819,10 +10848,12 @@ int dispatchCommand(char *azArg[], int nArg, ShellState *pSS) if( 0==pci ){ return NO_SUCH_COMMAND; } - if((pci->minArgs > 0 && pci->minArgs > nArg)||(pci->maxArgs > 0 && pci->maxArgs < nArg)){ - return INVALID_ARGS; + if( pci->minArgs > nArg||(pci->maxArgs > 0 && pci->maxArgs < nArg) ){ + return SHELL_INVALID_ARGS; } - return (pci->cmdDoer)(azArg, nArg, pSS); + /* Replace any user-shortened command name with its whole name. */ + azArg[0] = (char *)pci->cmdName; + return (pci->cmdDoer)(azArg, nArg, pSS, pzErr); } @@ -10892,7 +10923,7 @@ static int do_meta_command(char *zLine, ShellState *p){ #ifdef SQLITE_DEBUG /* Undocumented commands for internal testing. * Subject to change without notice. - * These are not dispatch via lookup because the command word varies. + * These are not dispatched via lookup because the command word varies. */ if( c=='s' && n>=10 && strncmp(azArg[0], "selftest-", 9)==0 ){ if( strncmp(azArg[0]+9, "boolean", n-9)==0 ){ @@ -10915,16 +10946,44 @@ static int do_meta_command(char *zLine, ShellState *p){ #endif /* The meta-command is not among the specially handled ones. Dispatch it. */ { - int dispatchResult = dispatchCommand(azArg, nArg, p); - if( NO_SUCH_COMMAND==dispatchResult ){ - utf8_printf(STD_ERR, "Error: unknown command: \"%s\"\n" - " Enter \".help\" for a list of commands.\n", azArg[0]); + char *zErr = 0; + int dispatchResult = dispatchCommand(azArg, nArg, p, &zErr); + switch( dispatchResult ){ + case NO_SUCH_COMMAND: + utf8_printf(STD_ERR, "Error: unknown command: \"%s\"\n", azArg[0]); + if( stdin_is_interactive ) + utf8_printf(STD_ERR, " Enter \".help\" for a list of commands.\n"); rc = 1; - } - if( INVALID_ARGS==dispatchResult ){ - utf8_printf(STD_ERR, "Error: invalid arguments for \".%s\"\n" - " Enter \".help %s\" for help on it.\n", azArg[0],azArg[0]); + break; + case SHELL_INVALID_ARGS: + utf8_printf(STD_ERR, "Error: invalid arguments for \".%s\"\n", azArg[0]); + if( stdin_is_interactive ){ + if( zErr!=0 ){ + utf8_printf(STD_ERR, " %s\n", zErr); + }else{ + utf8_printf(STD_ERR, "Usage: "); + showPrimaryHelp(STD_ERR, azArg[0]); + } + } rc = 1; + break; + case SHELL_FORBIDDEN_OP: + if( zErr!=0 ){ + utf8_printf + (STD_ERR, + "Error: \".%s\" may not %s in --safe mode\n", azArg[0], zErr); + sqlite3_free(zErr); + }else { + utf8_printf(STD_ERR, + "Error: \".%s\" forbidden in --safe mode\n", azArg[0]); + } + exit(1); + default: + if( 0!=dispatchResult ) rc = 1; + if( zErr!=0 ){ + utf8_printf(STD_ERR, "%s", zErr); + sqlite3_free(zErr); + } } } @@ -11430,6 +11489,7 @@ static void verify_uninitialized(void){ */ static void main_init(ShellState *data) { memset(data, 0, sizeof(*data)); + data->out = STD_OUT; data->normalMode = data->cMode = data->mode = MODE_List; data->autoExplain = 1; data->pAuxDb = &data->aAuxDb[0]; diff --git a/src/shext_linkage.h b/src/shext_linkage.h index df79943a78..4107cd412e 100644 --- a/src/shext_linkage.h +++ b/src/shext_linkage.h @@ -4,6 +4,10 @@ #include "obj_interfaces.h" +#ifdef __cplusplus +extern "C" { +#endif + /* Convey data to, from and/or between I/O handlers and meta-commands. */ typedef struct { /* A semi-transient holder of arbitrary data used during operations @@ -80,10 +84,11 @@ PURE_VMETHOD(int, execute, MetaCommand, 4,(ShellStateX *, char **pzErrMsg, int nArgs, char *azArgs[])); INTERFACE_END( MetaCommand ); -/* Define an error code to be returned either by a meta-command during its - * own argument checking or by the dispatcher for bad argument counts. +/* Define error codes to be returned either by a meta-command during + * its own checking or by the dispatcher for bad argument counts. */ #define SHELL_INVALID_ARGS SQLITE_MISUSE +#define SHELL_FORBIDDEN_OP 0x7ffe /* Action disallowed under --safe.*/ /* An object implementing below interface is registered with the * shell to make new or overriding output modes available to it. @@ -127,8 +132,9 @@ typedef struct { int helperCount; union ExtHelp { struct { + void (*failIfSafeMode)(ShellStateX *p, const char *zErrMsg, ...); } named ; - void (*nameless[1])(); /* Same as named but anonymous plus a sentinel. */ + void (*nameless[2])(); /* Same as named but anonymous plus a sentinel. */ } helpers; } ExtensionHelpers; diff --git a/test/shell1.test b/test/shell1.test index c4e2ceb88b..aaf03ce43e 100644 --- a/test/shell1.test +++ b/test/shell1.test @@ -182,21 +182,24 @@ do_test shell1-1.16.1 { # check first token handling do_test shell1-2.1.1 { catchcmd "test.db" ".foo" -} {1 {Error: unknown command or invalid arguments: "foo". Enter ".help" for help}} +} {1 {Error: unknown command: "foo"}} do_test shell1-2.1.2 { catchcmd "test.db" ".\"foo OFF\"" -} {1 {Error: unknown command or invalid arguments: "foo OFF". Enter ".help" for help}} +} {1 {Error: unknown command: "foo OFF"}} do_test shell1-2.1.3 { catchcmd "test.db" ".\'foo OFF\'" -} {1 {Error: unknown command or invalid arguments: "foo OFF". Enter ".help" for help}} +} {1 {Error: unknown command: "foo OFF"}} + +set modeShouldBe "Error: mode should be one of: ascii box column csv html + insert json line list markdown quote table tabs tcl" # unbalanced quotes do_test shell1-2.2.1 { catchcmd "test.db" ".\"foo OFF" -} {1 {Error: unknown command or invalid arguments: "foo OFF". Enter ".help" for help}} +} {1 {Error: unknown command: "foo OFF"}} do_test shell1-2.2.2 { catchcmd "test.db" ".\'foo OFF" -} {1 {Error: unknown command or invalid arguments: "foo OFF". Enter ".help" for help}} +} {1 {Error: unknown command: "foo OFF"}} do_test shell1-2.2.3 { catchcmd "test.db" ".explain \"OFF" } {0 {}} @@ -205,10 +208,10 @@ do_test shell1-2.2.4 { } {0 {}} do_test shell1-2.2.5 { catchcmd "test.db" ".mode \"insert FOO" -} {1 {Error: mode should be one of: ascii box column csv html insert json line list markdown quote table tabs tcl}} +} [list 1 $modeShouldBe] do_test shell1-2.2.6 { catchcmd "test.db" ".mode \'insert FOO" -} {1 {Error: mode should be one of: ascii box column csv html insert json line list markdown quote table tabs tcl}} +} [list 1 $modeShouldBe] # check multiple tokens, and quoted tokens do_test shell1-2.3.1 { @@ -236,7 +239,7 @@ do_test shell1-2.3.7 { # check quoted args are unquoted do_test shell1-2.4.1 { catchcmd "test.db" ".mode FOO" -} {1 {Error: mode should be one of: ascii box column csv html insert json line list markdown quote table tabs tcl}} +} [list 1 $modeShouldBe] do_test shell1-2.4.2 { catchcmd "test.db" ".mode csv" } {0 {}} @@ -252,7 +255,7 @@ do_test shell1-2.4.2 { # .backup ?DB? FILE Backup DB (default "main") to FILE do_test shell1-3.1.1 { catchcmd "test.db" ".backup" -} {1 {missing FILENAME argument on .backup}} +} {1 {Error: invalid arguments for ".backup"}} forcedelete FOO do_test shell1-3.1.2 { catchcmd "test.db" ".backup FOO" @@ -263,12 +266,12 @@ do_test shell1-3.1.3 { do_test shell1-3.1.4 { # too many arguments catchcmd "test.db" ".backup FOO BAR BAD" -} {1 {Usage: .backup ?DB? ?OPTIONS? FILENAME}} +} {1 {Error: invalid arguments for ".backup"}} # .bail ON|OFF Stop after hitting an error. Default OFF do_test shell1-3.2.1 { catchcmd "test.db" ".bail" -} {1 {Usage: .bail on|off}} +} {1 {Error: invalid arguments for ".bail"}} do_test shell1-3.2.2 { catchcmd "test.db" ".bail ON" } {0 {}} @@ -278,7 +281,7 @@ do_test shell1-3.2.3 { do_test shell1-3.2.4 { # too many arguments catchcmd "test.db" ".bail OFF BAD" -} {1 {Usage: .bail on|off}} +} {1 {Error: invalid arguments for ".bail"}} ifcapable vtab { # .databases List names and files of attached databases @@ -313,7 +316,7 @@ do_test shell1-3.4.2 { # .echo ON|OFF Turn command echo on or off do_test shell1-3.5.1 { catchcmd "test.db" ".echo" -} {1 {Usage: .echo on|off}} +} {1 {Error: invalid arguments for ".echo"}} do_test shell1-3.5.2 { catchcmd "test.db" ".echo ON" } {0 {}} @@ -323,7 +326,7 @@ do_test shell1-3.5.3 { do_test shell1-3.5.4 { # too many arguments catchcmd "test.db" ".echo OFF BAD" -} {1 {Usage: .echo on|off}} +} {1 {Error: invalid arguments for ".echo"}} # .exit Exit this program do_test shell1-3.6.1 { @@ -342,15 +345,14 @@ do_test shell1-3.7.3 { catchcmd "test.db" ".explain OFF" } {0 {}} do_test shell1-3.7.4 { - # extra arguments ignored + # extra arguments no longer ignored catchcmd "test.db" ".explain OFF BAD" -} {0 {}} - +} {1 {Error: invalid arguments for ".explain"}} # .header(s) ON|OFF Turn display of headers on or off do_test shell1-3.9.1 { catchcmd "test.db" ".header" -} {1 {Usage: .headers on|off}} +} {1 {Error: invalid arguments for ".header"}} do_test shell1-3.9.2 { catchcmd "test.db" ".header ON" } {0 {}} @@ -360,11 +362,11 @@ do_test shell1-3.9.3 { do_test shell1-3.9.4 { # too many arguments catchcmd "test.db" ".header OFF BAD" -} {1 {Usage: .headers on|off}} +} {1 {Error: invalid arguments for ".header"}} do_test shell1-3.9.5 { catchcmd "test.db" ".headers" -} {1 {Usage: .headers on|off}} +} {1 {Error: invalid arguments for ".headers"}} do_test shell1-3.9.6 { catchcmd "test.db" ".headers ON" } {0 {}} @@ -374,7 +376,7 @@ do_test shell1-3.9.7 { do_test shell1-3.9.8 { # too many arguments catchcmd "test.db" ".headers OFF BAD" -} {1 {Usage: .headers on|off}} +} {1 {Error: invalid arguments for ".headers"}} # .help Show this message do_test shell1-3.10.1 { @@ -396,14 +398,15 @@ do_test shell1-3.10.2 { # .import FILE TABLE Import data from FILE into TABLE do_test shell1-3.11.1 { catchcmd "test.db" ".import" -} {/1 .ERROR: missing FILE argument.*/} +} {1 {Error: invalid arguments for ".import"}} do_test shell1-3.11.2 { catchcmd "test.db" ".import FOO" -} {/1 .ERROR: missing TABLE argument.*/} +} {1 {Error: invalid arguments for ".import"}} do_test shell1-3.11.3 { # too many arguments catchcmd "test.db" ".import FOO BAR BAD" -} {/1 .ERROR: extra argument: "BAD".*./} +} {1 {Error: invalid arguments for ".import" + surplus argument: "BAD"}} # .indexes ?TABLE? Show names of all indexes # If TABLE specified, only show indexes for tables @@ -420,7 +423,7 @@ do_test shell1-3.12.2-legacy { do_test shell1-3.12.3 { # too many arguments catchcmd "test.db" ".indexes FOO BAD" -} {1 {Usage: .indexes ?LIKE-PATTERN?}} +} {1 {Error: invalid arguments for ".indexes"}} # .mode MODE ?TABLE? Set output mode where MODE is one of: # ascii Columns/rows delimited by 0x1F and 0x1E @@ -437,7 +440,7 @@ do_test shell1-3.13.1 { } {0 {current output mode: list}} do_test shell1-3.13.2 { catchcmd "test.db" ".mode FOO" -} {1 {Error: mode should be one of: ascii box column csv html insert json line list markdown quote table tabs tcl}} +} [list 1 $modeShouldBe] do_test shell1-3.13.3 { catchcmd "test.db" ".mode csv" } {0 {}} @@ -463,17 +466,17 @@ do_test shell1-3.13.10 { catchcmd "test.db" ".mode tcl" } {0 {}} do_test shell1-3.13.11 { - # extra arguments ignored + # extra arguments rejected catchcmd "test.db" ".mode tcl BAD" -} {0 {}} +} {1 {Error: invalid arguments for ".mode"}} -# don't allow partial mode type matches +# don't allow too-partial mode type matches do_test shell1-3.13.12 { catchcmd "test.db" ".mode l" -} {1 {Error: mode should be one of: ascii box column csv html insert json line list markdown quote table tabs tcl}} +} [list 1 $modeShouldBe] do_test shell1-3.13.13 { catchcmd "test.db" ".mode li" -} {1 {Error: mode should be one of: ascii box column csv html insert json line list markdown quote table tabs tcl}} +} [list 1 $modeShouldBe] do_test shell1-3.13.14 { catchcmd "test.db" ".mode lin" } {0 {}} @@ -481,14 +484,14 @@ do_test shell1-3.13.14 { # .nullvalue STRING Print STRING in place of NULL values do_test shell1-3.14.1 { catchcmd "test.db" ".nullvalue" -} {1 {Usage: .nullvalue STRING}} +} {1 {Error: invalid arguments for ".nullvalue"}} do_test shell1-3.14.2 { catchcmd "test.db" ".nullvalue FOO" } {0 {}} do_test shell1-3.14.3 { # too many arguments catchcmd "test.db" ".nullvalue FOO BAD" -} {1 {Usage: .nullvalue STRING}} +} {1 {Error: invalid arguments for ".nullvalue"}} # .output FILENAME Send output to FILENAME do_test shell1-3.15.1 { @@ -500,14 +503,8 @@ do_test shell1-3.15.2 { do_test shell1-3.15.3 { # too many arguments catchcmd "test.db" ".output FOO BAD" -} {1 {ERROR: extra parameter: "BAD". Usage: -.output ?FILE? Send output to FILE or stdout if FILE is omitted - If FILE begins with '|' then open it as a pipe. - Options: - --bom Prefix output with a UTF8 byte-order mark - -e Send output to the system text editor - -x Send output as CSV to a spreadsheet -child process exited abnormally}} +} {1 {Error: invalid arguments for ".output" + excess argument: "BAD"}} # .output stdout Send output to the screen do_test shell1-3.16.1 { @@ -516,14 +513,8 @@ do_test shell1-3.16.1 { do_test shell1-3.16.2 { # too many arguments catchcmd "test.db" ".output stdout BAD" -} {1 {ERROR: extra parameter: "BAD". Usage: -.output ?FILE? Send output to FILE or stdout if FILE is omitted - If FILE begins with '|' then open it as a pipe. - Options: - --bom Prefix output with a UTF8 byte-order mark - -e Send output to the system text editor - -x Send output as CSV to a spreadsheet -child process exited abnormally}} +} {1 {Error: invalid arguments for ".output" + excess argument: "BAD"}} # .prompt MAIN CONTINUE Replace the standard prompts do_test shell1-3.17.1 { @@ -538,7 +529,7 @@ do_test shell1-3.17.3 { do_test shell1-3.17.4 { # too many arguments catchcmd "test.db" ".prompt FOO BAR BAD" -} {0 {}} +} {1 {Error: invalid arguments for ".prompt"}} # .quit Exit this program do_test shell1-3.18.1 { @@ -552,7 +543,7 @@ do_test shell1-3.18.2 { # .read FILENAME Execute SQL in FILENAME do_test shell1-3.19.1 { catchcmd "test.db" ".read" -} {1 {Usage: .read FILE}} +} {1 {Error: invalid arguments for ".read"}} do_test shell1-3.19.2 { forcedelete FOO catchcmd "test.db" ".read FOO" @@ -560,12 +551,12 @@ do_test shell1-3.19.2 { do_test shell1-3.19.3 { # too many arguments catchcmd "test.db" ".read FOO BAD" -} {1 {Usage: .read FILE}} +} {1 {Error: invalid arguments for ".read"}} # .restore ?DB? FILE Restore content of DB (default "main") from FILE do_test shell1-3.20.1 { catchcmd "test.db" ".restore" -} {1 {Usage: .restore ?DB? FILE}} +} {1 {Error: invalid arguments for ".restore"}} do_test shell1-3.20.2 { catchcmd "test.db" ".restore FOO" } {0 {}} @@ -575,7 +566,7 @@ do_test shell1-3.20.3 { do_test shell1-3.20.4 { # too many arguments catchcmd "test.db" ".restore FOO BAR BAD" -} {1 {Usage: .restore ?DB? FILE}} +} {1 {Error: invalid arguments for ".restore"}} ifcapable vtab { # .schema ?TABLE? Show the CREATE statements @@ -590,7 +581,7 @@ do_test shell1-3.21.2 { do_test shell1-3.21.3 { # too many arguments catchcmd "test.db" ".schema FOO BAD" -} {1 {Usage: .schema ?--indent? ?--nosys? ?LIKE-PATTERN?}} +} {1 {Error: invalid arguments for ".schema"}} do_test shell1-3.21.4 { catchcmd "test.db" { @@ -610,7 +601,7 @@ db eval {DROP VIEW v1; DROP VIEW v2; DROP TABLE t1;} # .separator STRING Change column separator used by output and .import do_test shell1-3.22.1 { catchcmd "test.db" ".separator" -} {1 {Usage: .separator COL ?ROW?}} +} {1 {Error: invalid arguments for ".separator"}} do_test shell1-3.22.2 { catchcmd "test.db" ".separator FOO" } {0 {}} @@ -620,7 +611,7 @@ do_test shell1-3.22.3 { do_test shell1-3.22.4 { # too many arguments catchcmd "test.db" ".separator FOO BAD BAD2" -} {1 {Usage: .separator COL ?ROW?}} +} {1 {Error: invalid arguments for ".separator"}} # .show Show the current values for various settings do_test shell1-3.23.1 { @@ -639,7 +630,7 @@ do_test shell1-3.23.1 { do_test shell1-3.23.2 { # too many arguments catchcmd "test.db" ".show BAD" -} {1 {Usage: .show}} +} {1 {Error: invalid arguments for ".show"}} # .stats ON|OFF Turn stats on or off #do_test shell1-3.23b.1 { @@ -697,7 +688,7 @@ do_test shell1-3.25.3 { do_test shell1-3.25.4 { # too many arguments catchcmd "test.db" ".timeout 1 BAD" -} {0 {}} +} {1 {Error: invalid arguments for ".timeout"}} # .width NUM NUM ... Set column widths for "column" mode do_test shell1-3.26.1 { @@ -728,7 +719,7 @@ do_test shell1-3.26.6 { # .timer ON|OFF Turn the CPU timer measurement on or off do_test shell1-3.27.1 { catchcmd "test.db" ".timer" -} {1 {Usage: .timer on|off}} +} {1 {Error: invalid arguments for ".timer"}} do_test shell1-3.27.2 { catchcmd "test.db" ".timer ON" } {0 {}} @@ -738,7 +729,7 @@ do_test shell1-3.27.3 { do_test shell1-3.27.4 { # too many arguments catchcmd "test.db" ".timer OFF BAD" -} {1 {Usage: .timer on|off}} +} {1 {Error: invalid arguments for ".timer"}} do_test shell1-3-28.1 { catchcmd test.db \ diff --git a/test/shell2.test b/test/shell2.test index 6b4dff515e..8a6e5a217a 100644 --- a/test/shell2.test +++ b/test/shell2.test @@ -63,9 +63,7 @@ do_test shell2-1.3 { UPDATE OR REPLACE t5 SET a = 4 WHERE a = 1; } -} {1 {Error: near line 9: stepping, too many levels of trigger recursion (1)}} - - +} {1 {Error: near line 9: in stepping, too many levels of trigger recursion (1)}} # Shell not echoing all commands with echo on. # Ticket [eb620916be]. diff --git a/test/shell5.test b/test/shell5.test index dc99a7acea..f1384fbf78 100644 --- a/test/shell5.test +++ b/test/shell5.test @@ -32,19 +32,19 @@ forcedelete test.db test.db-journal test.db-wal # .import FILE TABLE Import data from FILE into TABLE do_test shell5-1.1.1 { catchcmd "test.db" ".import" -} {/1 .ERROR: missing FILE argument.*/} +} {1 {Error: invalid arguments for ".import"}} do_test shell5-1.1.2 { catchcmd "test.db" ".import FOO" -} {/1 .ERROR: missing TABLE argument.*/} +} {1 {Error: invalid arguments for ".import"}} do_test shell5-1.1.3 { # too many arguments catchcmd "test.db" ".import FOO BAR BAD" -} {/1 .ERROR: extra argument.*/} +} {1 {Error: invalid arguments for ".import"}} # .separator STRING Change separator used by output mode and .import do_test shell5-1.2.1 { catchcmd "test.db" ".separator" -} {1 {Usage: .separator COL ?ROW?}} +} {1 {Error: invalid arguments for ".separator"}} do_test shell5-1.2.2 { catchcmd "test.db" ".separator ONE" } {0 {}} @@ -54,7 +54,7 @@ do_test shell5-1.2.3 { do_test shell5-1.2.4 { # too many arguments catchcmd "test.db" ".separator ONE TWO THREE" -} {1 {Usage: .separator COL ?ROW?}} +} {1 {Error: invalid arguments for ".separator"}} # column separator should default to "|" do_test shell5-1.3.1.1 {