* to leave Tk objects and variables set so that when a GUI event
* loop is run, some useful GUI program runs and can terminate.
*
- * Before running the setup code, a variable, ::isHost, is set
+ * Before running the setup code, a variable, ::isHost, is set
* true to possibly inform the setup code that it should avoid
* exit and exec calls. Setup code which is designed for either
* hosted or standalone use, when run with $::isHost!=0, may opt
-C Get\ssqlite3x\sand\sextensions\stesting\sfrom\sMakefile\ssetup,\sand\ssome\sof\swapptest\schanges\sdone\sto\srun\ssame.\s(a\sWIP)
-D 2022-04-15T21:21:01.750
+C For\ssqlite3x,\srudimentary\stesting\sin\splace\sas\smake\starget\sshellxtest\s.\sMore\sto\scome.
+D 2022-04-17T00:48:49.519
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
F ext/misc/spellfix.c 94df9bbfa514a563c1484f684a2df3d128a2f7209a84ca3ca100c68a0163e29f
F ext/misc/sqlar.c 0ace5d3c10fe736dc584bf1159a36b8e2e60fab309d310cd8a0eecd9036621b6
F ext/misc/stmt.c 35063044a388ead95557e4b84b89c1b93accc2f1c6ddea3f9710e8486a7af94a
-F ext/misc/tclshext.c.in 93228dbc48e6b300aa3d8632d2a061edaafcab60a83664ae7549e5e682e3b48b
+F ext/misc/tclshext.c.in e0e4387b95410172385488feaea2f622ad1d398f1ac6a4275874791fbfd31d4e
F ext/misc/templatevtab.c 8a16a91a5ceaccfcbd6aaaa56d46828806e460dd194965b3f77bf38f14b942c4
F ext/misc/totype.c fa4aedeb07f66169005dffa8de3b0a2b621779fd44f85c103228a42afa71853b
F ext/misc/uint.c 053fed3bce2e89583afcd4bf804d75d659879bbcedac74d0fa9ed548839a030b
F src/resolve.c 18d99e7146852d6064559561769fcca0743eb32b14a97da6dbed373a30ee0e76
F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
F src/select.c 7c106b3f36d483242b0a9c696614cd53d6f29e1ac81da6a3f0e9ea92f4211cc3
-F src/shell.c.in da1afe360a268736d373218fabfce706558628ba49655855bdcb759be963880e
+F src/shell.c.in 47c84d1511e44ef28fb215c70a80065c6c103650579743ac60a129f541af17b2
F src/shext_linkage.h 41e7e665fffd125b38b8211dc650233d4fe54941acd8177f23d3deb9d6f70154
F src/sqlite.h.in 2a35f62185eb5e7ecc64a2f68442b538ce9be74f80f28a00abc24837edcf1c17
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/test_rtree.c 671f3fae50ff116ef2e32a3bf1fe21b5615b4b7b
F src/test_schema.c f5d6067dfc2f2845c4dd56df63e66ee826fb23877855c785f75cc2ca83fd0c1b
F src/test_server.c a2615049954cbb9cfb4a62e18e2f0616e4dc38fe
-F src/test_shellext_c.c e0cd6bf508d4d5c7147766d58b926bf36d49265654896ab91b1abad0aa8d7656 w src/test_shellext.c
-F src/test_shellext_cpp.cpp ae20a1d280311348910ac8c6b2dce7ddc36b38c82ff13929434eb98114696342 w src/test_shellext.cpp
+F src/test_shellext_c.c b611e468bb99ba27df9211f8b6f1179cbd77f29390a0c7b846eb0d00e14dd1dc
+F src/test_shellext_cpp.cpp d33cc8538ebe76f10114c8c9e5d65caa4e183fb461a4311145739f0affb15566
F src/test_sqllog.c 540feaea7280cd5f926168aee9deb1065ae136d0bbbe7361e2ef3541783e187a
F src/test_superlock.c 4839644b9201da822f181c5bc406c0b2385f672e
F src/test_syscall.c 1073306ba2e9bfc886771871a13d3de281ed3939
F test/shell6.test 1ceb51b2678c472ba6cf1e5da96679ce8347889fe2c3bf93a0e0fa73f00b00d3
F test/shell7.test 115132f66d0463417f408562cc2cf534f6bbc6d83a6d50f0072a9eb171bae97f
F test/shell8.test 388471d16e4de767333107e30653983f186232c0e863f4490bb230419e830aae
-F test/shell_x/shell9.test c3e5aefa4cc6088efe9034b22ed33157e18653d599cb109f254904a7344cd230 w test/shell9.test
+F test/shell_x/shell10.test 9b396b83c3b150ffb4c3bca62600f28ed91d0e31a4f82d4de482e20f3b84570a
+F test/shell_x/shell9.test 22f15500ccdec5561cbedb3a4c28f0f2175a2b8eff1b837cc127de59c3bc0f73
F test/shmlock.test 3dbf017d34ab0c60abe6a44e447d3552154bd0c87b41eaf5ceacd408dd13fda5
F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3
F test/show_speedtest1_rtree.tcl 32e6c5f073d7426148a6936a0408f4b5b169aba5
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P f78d7b8b89b667daba486fdb67de105bd8524203cc44bb02c3cb94acd85560e9
-R 1ba3c589060988b7f35661d48f220afd
+P d238fcf4beb0b121e4754e288df9906cb61d38a827f1fe38cf4aaa784520fc08
+Q +82366436ef74838dae1f379f3e5b8ad187225a30ec58fb49f047ab7c08a263cf
+R ef5b2dbf2d2afa126edf6b3816e08feb
U larrybr
-Z 85689539bcda51dbf9a7b11c35f28148
+Z a3ff9fe808da85c8206c0da625259951
# Remove this line to create a well-formed Fossil manifest.
-d238fcf4beb0b121e4754e288df9906cb61d38a827f1fe38cf4aaa784520fc08
\ No newline at end of file
+b73928befb013622a369bf8f9904b5aeca626a5598884b4030229a33f684960f
\ No newline at end of file
static const char * const zColDigits = "\
SELECT CAST(ceil(log(count(*)+0.5)) AS INT) FROM ColNames \
";
+#else
+ /* Counting on SQLITE_MAX_COLUMN < 100,000 here. (32767 is the hard limit.) */
+ static const char * const zColDigits = "\
+SELECT CASE WHEN (nc < 10) THEN 1 WHEN (nc < 100) THEN 2 \
+ WHEN (nc < 1000) THEN 3 WHEN (nc < 10000) THEN 4 \
+ ELSE 5 FROM (SELECT count(*) AS nc FROM ColNames) \
+";
#endif
static const char * const zRenameRank =
#ifdef SHELL_COLUMN_RENAME_CLEAN
/* Formulate the columns spec, close the DB, zero *pDb. */
char *zColsSpec = 0;
int hasDupes = db_int(*pDb, zHasDupes);
-#ifdef SQLITE_ENABLE_MATH_FUNCTIONS
int nDigits = (hasDupes)? db_int(*pDb, zColDigits) : 0;
-#else
-# define nDigits 2
-#endif
if( hasDupes ){
#ifdef SHELL_COLUMN_RENAME_CLEAN
rc = sqlite3_exec(*pDb, zDedoctor, 0, 0, 0);
* The function bodies are not so easily written, of course. */
DERIVED_METHOD(void, destruct, DotCommand,BatBeing, 0, ()){
- fprintf(stderr, "BatBeing unbecoming.\n");
+ fprintf(stdout, "BatBeing unbecoming.\n");
}
DERIVED_METHOD(const char *, name, DotCommand,BatBeing, 0,()){
}
DERIVED_METHOD(DotCmdRC, execute, DotCommand,BatBeing, 4,
- (ShellExState *psx, char **pzErrMsg, int nArgs, char *azArgs[])){
- FILE *out = pExtHelpers->currentOutputFile(psx);
- switch( nArgs ){
- default: fprintf(out, "The Penguin, Joker and Riddler have teamed up!\n");
- case 2: fprintf(out, "The Dynamic Duo arrives, and ... ");
- case 1: fprintf(out, "@#$ KaPow! $#@\n");
- }
- sayHowMany((BatBeing *)pThis, out, psx);
- return DCR_Ok;
-}
+ (ShellExState *psx, char **pzErrMsg, int nArgs, char *azArgs[]));
/* Define a DotCommand v-table initialized to reference above methods. */
DotCommand_IMPLEMENT_VTABLE(BatBeing, batty_methods);
INSTANCE_BEGIN(BatBeing);
int numCalls;
DotCommand * pPrint;
+ DotCommand * pPrior;
INSTANCE_END(BatBeing) batty = {
&batty_methods,
- 0, 0
+ 0, 0, 0
};
+DERIVED_METHOD(DotCmdRC, execute, DotCommand,BatBeing, 4,
+ (ShellExState *psx, char **pzErrMsg, int nArgs, char *azArgs[])){
+ FILE *out = pExtHelpers->currentOutputFile(psx);
+ BatBeing *pbb = (BatBeing*)pThis;
+ switch( nArgs ){
+ default:
+ {
+ if( pbb->pPrior ){
+ char *az1 = azArgs[1];
+ for( int i=2; i<nArgs; ++i ) azArgs[i-1] = azArgs[i];
+ azArgs[nArgs-1] = az1;
+ return pbb->pPrior->pMethods->execute(pbb->pPrior, psx,
+ pzErrMsg, nArgs, azArgs);
+ }else{
+ int cix;
+ SHX_HELPER(setColumnWidths)(psx, azArgs+1, nArgs-1);
+ fprintf(out, "Column widths:");
+ for( cix=0; cix<psx->numWidths; ++cix ){
+ fprintf(out, " %d", psx->pSpecWidths[cix]);
+ }
+ fprintf(out, "\n");
+ }
+ }
+ break;
+ case 3:
+ fprintf(out, "The Penguin, Joker and Riddler have teamed up!\n");
+ case 2: fprintf(out, "The Dynamic Duo arrives, and ... ");
+ case 1: fprintf(out, "@#$ KaPow! $#@\n");
+ }
+ sayHowMany((BatBeing *)pThis, out, psx);
+ return DCR_Ok;
+}
+
static void sayHowMany( BatBeing *pbb, FILE *out, ShellExState *psx ){
if( pbb->pPrint ){
char *az[] = { "print", 0 };
char *zErr = 0;
DotCommand * pdcPrint = pbb->pPrint;
DotCmdRC rc;
- az[1] = sqlite3_mprintf("This execute has been called %d times.\n",
+ az[1] = sqlite3_mprintf("This execute has been called %d times.",
++pbb->numCalls);
rc = pdcPrint->pMethods->execute(pdcPrint, psx, &zErr, 2, az);
sqlite3_free(az[1]);
fprintf(out, "BatBeing incommunicado.\n");
}else if( nk==NK_DbUserAppeared || nk==NK_DbUserVanishing ){
const char *zWhat = (nk==NK_DbUserAppeared)? "appeared" : "vanishing";
- fprintf(out, "dbUser(%p) %s\n", pvSubject, zWhat);
+ int isDbu = pvSubject==psx->dbUser;
+ fprintf(out, "db%s %s\n", isDbu? "User" : "?", zWhat);
if( psx->dbUser != pvSubject ) fprintf(out, "not dbx(%p)\n", psx->dbUser);
}else if( nk==NK_DbAboutToClose ){
- fprintf(out, "db(%p) closing\n", pvSubject);
+ const char *zdb = (pvSubject==psx->dbUser)? "User"
+ : (pvSubject==psx->dbShell)? "Shell" : "?";
+ fprintf(out, "db%s closing\n", zdb);
}
return 0;
}
#ifdef _WIN32
__declspec(dllexport)
#endif
-int sqlite3_testshellext_c_init(
+int sqlite3_testshellextc_init(
sqlite3 *db,
char **pzErrMsg,
const sqlite3_api_routines *pApi
ShellExState *psx = pShExtLink->pSXS;
DotCommand *pdc = (DotCommand *)&batty;
int rc;
+ char *zLoadArgs = sqlite3_mprintf("Load arguments:");
+ int ila;
- SHX_API(subscribeEvents)(psx, sqlite3_testshellext_c_init, &batty,
+ for( ila=0; ila<pShExtLink->nLoadArgs; ++ila ){
+ zLoadArgs = sqlite3_mprintf("%z %s", zLoadArgs,
+ pShExtLink->azLoadArgs[ila]);
+ }
+ if( ila ) fprintf(SHX_HELPER(currentOutputFile)(psx), "%s\n", zLoadArgs);
+ sqlite3_free(zLoadArgs);
+ SHX_API(subscribeEvents)(psx, sqlite3_testshellextc_init, &batty,
NK_CountOf, shellEventHandle);
batty.pPrint = SHX_HELPER(findDotCommand)("print", psx, &rc);
- rc = SHX_API(registerDotCommand)(psx, sqlite3_testshellext_c_init, pdc);
+ batty.pPrior = SHX_HELPER(findDotCommand)("bat_being", psx, &rc);
+ rc = SHX_API(registerDotCommand)(psx, sqlite3_testshellextc_init, pdc);
if( rc!=0 ) ++nErr;
- pShExtLink->eid = sqlite3_testshellext_c_init;
+ pShExtLink->eid = sqlite3_testshellextc_init;
}
return nErr ? SQLITE_ERROR : SQLITE_OK;
}
struct BatBeing : DotCommand {
- ~BatBeing() {}; // No held resources; copy/assign is fine and dying is easy.
+ ~BatBeing() {
+ fprintf(stdout, "BatBeing RIP.\n");
+ }; // No held resources; copy/assign is fine and dying is easy.
- void destruct() { this->~BatBeing(); }
+ void destruct() {
+ fprintf(stdout, "BatBeing unbecoming.\n");
+ }
const char *name() { return "bat_being"; };
BatBeing(DotCommand *pp = 0) {
numCalls = 0;
pPrint = pp;
+ pPrior = 0;
+ fprintf(stdout, "BatBeing lives.\n");
};
// Default copy/assign are fine; nothing held.
int numCalls;
DotCommand * pPrint;
+ DotCommand * pPrior;
};
static void sayHowMany( BatBeing *pbb, FILE *out, ShellExState *psx ){
char *az[] = { cmd, 0 };
char *zErr = 0;
DotCmdRC rc;
- az[1] = sqlite3_mprintf("This execute has been called %d times.\n",
+ az[1] = sqlite3_mprintf("This execute has been called %d times.",
++pbb->numCalls);
rc = pbb->pPrint->execute(psx, &zErr, 2, az);
sqlite3_free(az[1]);
int nArgs, char *azArgs[]) {
FILE *out = SHX_HELPER(currentOutputFile)(psx);
switch( nArgs ){
- default: fprintf(out, "The Penguin, Joker and Riddler have teamed up!\n");
+ default:
+ {
+ if( pPrior ){
+ char *az1 = azArgs[1];
+ for( int i=2; i<nArgs; ++i ) azArgs[i-1] = azArgs[i];
+ azArgs[nArgs-1] = az1;
+ return pPrior->execute(psx, pzErrMsg, nArgs, azArgs);
+ }else{
+ SHX_HELPER(setColumnWidths)(psx, azArgs+1, nArgs-1);
+ fprintf(out, "Column widths:");
+ for( int cix=0; cix<psx->numWidths; ++cix ){
+ fprintf(out, " %d", psx->pSpecWidths[cix]);
+ }
+ fprintf(out, "\n");
+ }
+ }
+ break;
+ case 3:
+ fprintf(out, "The Penguin, Joker and Riddler have teamed up!\n");
case 2: fprintf(out, "The Dynamic Duo arrives, and ... ");
case 1: fprintf(out, "@#$ KaPow! $#@\n");
}
return DCR_Ok;
}
-/* Define/initialize BatBeing as a DotCommand subclass using above v-table.
+/* Define/initialize BatBeing as a DotCommand subclass using above v-table.
* This compiles in a type-safe manner because the batty_methods v-table
* and methods it incorporates strictly match the DotCommand interface.
*/
fprintf(out, "BatBeing incommunicado.\n");
}else if( nk==NK_DbUserAppeared || nk==NK_DbUserVanishing ){
const char *zWhat = (nk==NK_DbUserAppeared)? "appeared" : "vanishing";
- fprintf(out, "dbUser(%p) %s\n", pvSubject, zWhat);
+ int isDbu = pvSubject==psx->dbUser;
+ fprintf(out, "db%s %s\n", isDbu? "User" : "?", zWhat);
if( psx->dbUser != pvSubject ) fprintf(out, "not dbx(%p)\n", psx->dbUser);
}else if( nk==NK_DbAboutToClose ){
- fprintf(out, "db(%p) closing\n", pvSubject);
+ const char *zdb = (pvSubject==psx->dbUser)? "User"
+ : (pvSubject==psx->dbShell)? "Shell" : "?";
+ fprintf(out, "db%s closing\n", zdb);
}
return 0;
}
#ifdef _WIN32
__declspec(dllexport)
#endif
-int sqlite3_testshellext_cpp_init(
+int sqlite3_testshellextcpp_init(
sqlite3 *db,
char **pzErrMsg,
const sqlite3_api_routines *pApi
}else{
ShellExState *psx = pShExtLink->pSXS;
int rc;
+ char *zLoadArgs = sqlite3_mprintf("Load arguments:");
+ int ila;
- SHX_API(subscribeEvents)(psx, sqlite3_testshellext_cpp_init, &batty,
+ for( ila=0; ila<pShExtLink->nLoadArgs; ++ila ){
+ zLoadArgs = sqlite3_mprintf("%z %s", zLoadArgs,
+ pShExtLink->azLoadArgs[ila]);
+ }
+ if( ila ) fprintf(SHX_HELPER(currentOutputFile)(psx), "%s\n", zLoadArgs);
+ sqlite3_free(zLoadArgs);
+ SHX_API(subscribeEvents)(psx, sqlite3_testshellextcpp_init, &batty,
NK_CountOf, shellEventHandle);
batty.pPrint = SHX_HELPER(findDotCommand)("print", psx, &rc);
+ batty.pPrior = SHX_HELPER(findDotCommand)(batty.name(), psx, &rc);
rc = SHX_API(registerDotCommand)(psx,
- sqlite3_testshellext_cpp_init, &batty);
+ sqlite3_testshellextcpp_init, &batty);
if( rc!=0 ) ++nErr;
- pShExtLink->eid = sqlite3_testshellext_cpp_init;
+ pShExtLink->eid = sqlite3_testshellextcpp_init;
}
return nErr ? SQLITE_ERROR : SQLITE_OK;
}
--- /dev/null
+# 2022 Apr 16
+#
+# The author disclaims copyright to this source code. In place of
+# a legal notice, here is a blessing:
+#
+# May you do good and not evil.
+# May you find forgiveness for yourself and forgive others.
+# May you share freely, never taking more than you give.
+#
+#***********************************************************************
+#
+# The focus of this file is testing the extensible CLI shell tool's
+# feature whereby shell extensions may be loaded and used, particularly
+# the Tcl extension.
+#
+
+# Test plan:
+#
+# shell10-1.*: loading/running the {C,C++}-written test extensions
+# shell10-2.*: Tcl extension load and execution environment switching
+# shell10-3.*: Tcl extension ad hoc command creation
+
+set testdir [file join [file dirname $argv0] ..]
+source [file join $testdir tester.tcl]
+set CLI [test_find_cli sqlite3x]
+set blddir [file normalize [file join $testdir ..]]
+
+db close
+forcedelete test.db test.db-journal test.db-wal
+forcedelete x.db xn.db
+
+sqlite3 db test.db
+set mdb ":memory:"
+
+proc catch_mdb_cmd {args} {
+ global CLI
+ set cmd [join $args "\n"]
+ set rc [catch { exec $CLI :memory: << $cmd } msg]
+ list $rc $msg
+}
+
+#----------------------------------------------------------------------------
+# Test cases shell10-1.*: loading/running the {C,C++}-written test extensions
+set cmds ".
+ .load $blddir/test_shellext_cpp -shext C++
+"
+do_test shell10-1.1 {
+ catch_mdb_cmd $cmds
+} {0 {BatBeing lives.
+Load arguments: C++
+dbUser closing
+dbShell closing
+BatBeing incommunicado.
+BatBeing unbecoming.
+BatBeing RIP.}}
+
+set cmds ".
+ .load $blddir/test_shellext_c -shext C
+ .bat 10 20 30
+ .load $blddir/test_shellext_cpp -shext C++
+ .bat 10 20 30
+"
+do_test shell10-1.2 {
+ catch_mdb_cmd $cmds
+} {0 {Load arguments: C
+Column widths: 10 20 30
+This execute has been called 1 times.
+BatBeing lives.
+Load arguments: C++
+Column widths: 20 30 10
+This execute has been called 2 times.
+dbUser closing
+dbUser closing
+dbShell closing
+dbShell closing
+BatBeing incommunicado.
+BatBeing incommunicado.
+BatBeing unbecoming.
+BatBeing unbecoming.
+BatBeing RIP.}}
+
+
+#----------------------------------------------------------------------------
+# Test cases shell10-2.*: Tcl extension load and execution environment switching
+
+set ldtce ".load $blddir/tclshext -shext"
+
+set cmds {
+ ..
+ puts Putsing
+ for {set i 0} {$i<2} {incr i} {.print $i}
+ puts [info commands ..]
+ .
+ .print Printing
+ .quit
+}
+do_test shell10-2.1 {
+ catch_mdb_cmd $ldtce $cmds
+} {0 {Putsing
+..
+0
+1
+Printing}}
+
+#----------------------------------------------------------------------------
+# Test cases shell10-3.*: Tcl extension ad hoc command creation
+
+set cmds {
+ ..
+ proc .sum {args} {
+ set sum 0
+ foreach addend $args {incr sum $addend}
+ .print $sum
+ }
+ register_adhoc_command sum ".sum Sums arguments and prints result.
+ Arguments must be integers."
+ .
+ .help sum
+ .sum 1 2 3 4 5
+ .quit
+}
+do_test shell10-3.1 {
+ catch_mdb_cmd $ldtce $cmds
+} {0 {.sum Sums arguments and prints result.
+ Arguments must be integers.
+15}}
#***********************************************************************
#
# The focus of this file is testing the CLI shell tool enhanced parsing,
-# new .parameter subcommands and uses, and the new .x meta-command.
+# .parameter and .vars subcommands and uses, and the .x command.
#
#