Compare commits
116 Commits
max-subquery
..
qrf
| Author | SHA1 | Date | |
|---|---|---|---|
| 07e071e500 | |||
| 53794ab541 | |||
| 234d2e51ac | |||
| 02268693c3 | |||
| 4d91527aa5 | |||
| 1db7790ecb | |||
| e20406040a | |||
| 4dc404cef4 | |||
| f4870a2b51 | |||
| 36a54c001e | |||
| 4e12c0b0e9 | |||
| 1d06c9f700 | |||
| 3b2754446a | |||
| dd3b30ec85 | |||
| 18c7b4d651 | |||
| 3338ca5f56 | |||
| 7a0d5bdd29 | |||
| 850da77de1 | |||
| c2b9896e50 | |||
| 9a3561e2d9 | |||
| c5d6fbdeea | |||
| 8254c1a4fa | |||
| 02751a7162 | |||
| a7b9a10707 | |||
| d5ee8aa625 | |||
| e85b670a55 | |||
| ce4a86e08f | |||
| 0412f3297a | |||
| c4f198bfc4 | |||
| c37fcdd5d1 | |||
| bf891f707b | |||
| 2a376849ca | |||
| b9a471a745 | |||
| a9136b45fa | |||
| ed72bb3fa3 | |||
| 3b847a4040 | |||
| b43e8920d8 | |||
| 7f947dbd6c | |||
| 3a5f3aa858 | |||
| babac214d6 | |||
| 71b65c5055 | |||
| 0c4c0dbc7d | |||
| dfeb788b0f | |||
| a04f5335f9 | |||
| 57781916ad | |||
| e029b4a44e | |||
| 09f16c5ab6 | |||
| f863c0187c | |||
| e2201e40ce | |||
| 7f28c6d64e | |||
| c1aac60386 | |||
| 639d8b407b | |||
| 3e98ff6b1d | |||
| edc34bf866 | |||
| bfa8c7d370 | |||
| 44aea46a07 | |||
| 96e47e16e7 | |||
| 22d6a48ba7 | |||
| ca111b06f3 | |||
| e8cd0ee61f | |||
| 6eb5f5d9a7 | |||
| ec27a2e7e5 | |||
| d2424338b0 | |||
| a6b4039050 | |||
| eedf226700 | |||
| 84c03d6c36 | |||
| b6dcd0ae00 | |||
| 10747754d4 | |||
| 78e831d31f | |||
| 04586681af | |||
| 099f7f052b | |||
| 1f3efba202 | |||
| cb69edd23d | |||
| bac6b5eaef | |||
| 2e660d30f5 | |||
| 1301bc1f6e | |||
| 33cc175e51 | |||
| b230147671 | |||
| a354a15717 | |||
| 0296bab9fd | |||
| 9ff8a73ba4 | |||
| 35cc5176e0 | |||
| 03e6242802 | |||
| 630b111cd3 | |||
| a73fb2b233 | |||
| ccae8e0c47 | |||
| 74e5918178 | |||
| c64739e017 | |||
| a75737f931 | |||
| c873460fd1 | |||
| 52d1e3aef3 | |||
| cc1a3d3d85 | |||
| 09efb92900 | |||
| b3a3a4c006 | |||
| fa56585242 | |||
| a678784c4c | |||
| e40b5d9867 | |||
| f32be465e8 | |||
| 3c11df7e92 | |||
| 21769e1d85 | |||
| 41b5ded8d0 | |||
| 22f8a84fda | |||
| ce3d809d62 | |||
| dcd722d204 | |||
| 15a064807f | |||
| 8e544ca512 | |||
| 8c8bd1969c | |||
| 861cb4c0b4 | |||
| 6e334ef616 | |||
| a1f32824e2 | |||
| 5b5b35f6d6 | |||
| a0b13abd34 | |||
| 377c4a8bfe | |||
| 7ebd8a8d85 | |||
| f39a16c595 | |||
| c02f8fdfe2 |
+22
-10
@@ -1459,7 +1459,7 @@ SRC01 = \
|
||||
$(TOP)\src\status.c \
|
||||
$(TOP)\src\table.c \
|
||||
$(TOP)\src\threads.c \
|
||||
$(TOP)\src\tclsqlite.c \
|
||||
tclsqlite-ex.c \
|
||||
$(TOP)\src\tokenize.c \
|
||||
$(TOP)\src\treeview.c \
|
||||
$(TOP)\src\trigger.c \
|
||||
@@ -2020,8 +2020,18 @@ sqlite3.c: .target_source sqlite3ext.h sqlite3session.h $(MKSQLITE3C_TOOL) src-v
|
||||
|
||||
sqlite3-all.c: sqlite3.c $(TOP)\tool\split-sqlite3c.tcl $(JIM_TCLSH)
|
||||
$(JIM_TCLSH) $(TOP)\tool\split-sqlite3c.tcl
|
||||
|
||||
TCLSQLITEEX = \
|
||||
$(TOP)\ext\qrf\qrf.h \
|
||||
$(TOP)\ext\qrf\qrf.c \
|
||||
$(TOP)\src\tclsqlite.c
|
||||
|
||||
tclsqlite-ex.c: $(TCLSQLITEEX) $(TOP)\tool\mkcombo.tcl $(JIM_TCLSH)
|
||||
$(JIM_TCLSH) $(TOP)\tool\mkcombo.tcl $(TCLSQLITEEX) -o $@
|
||||
# <</mark>>
|
||||
|
||||
tclsqlite-ex.c:
|
||||
|
||||
# Rule to build the amalgamation
|
||||
#
|
||||
sqlite3.lo: $(SQLITE3C)
|
||||
@@ -2321,11 +2331,11 @@ whereexpr.lo: $(TOP)\src\whereexpr.c $(HDR)
|
||||
window.lo: $(TOP)\src\window.c $(HDR)
|
||||
$(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\window.c
|
||||
|
||||
tclsqlite.lo: $(TOP)\src\tclsqlite.c $(HDR) $(SQLITE_TCL_DEP)
|
||||
$(LTCOMPILE) $(NO_WARN) -DUSE_TCL_STUBS=1 -DBUILD_sqlite -I$(TCLINCDIR) -c $(TOP)\src\tclsqlite.c
|
||||
tclsqlite.lo: tclsqlite-ex.c $(HDR) $(SQLITE_TCL_DEP)
|
||||
$(LTCOMPILE) $(NO_WARN) -DUSE_TCL_STUBS=1 -DBUILD_sqlite -I$(TCLINCDIR) -c tclsqlite-ex.c /OUT:tclsqlite.lo
|
||||
|
||||
tclsqlite-shell.lo: $(TOP)\src\tclsqlite.c $(HDR) $(SQLITE_TCL_DEP)
|
||||
$(LTCOMPILE) $(NO_WARN) -DTCLSH -DBUILD_sqlite -I$(TCLINCDIR) -c $(TOP)\src\tclsqlite.c
|
||||
tclsqlite-shell.lo: tclsqlite-ex.c $(HDR) $(SQLITE_TCL_DEP)
|
||||
$(LTCOMPILE) $(NO_WARN) -DTCLSH -DBUILD_sqlite -I$(TCLINCDIR) -c tclsqlite-ex.c
|
||||
|
||||
tclsqlite3.exe: tclsqlite-shell.lo $(SQLITE3C) $(SQLITE3H) $(LIBRESOBJS)
|
||||
$(LTLINK) $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) $(TCLLIBPATHS) $(LTLIBPATHS) /OUT:$@ tclsqlite-shell.lo $(LIBRESOBJS) $(TCLLIBS) $(LTLIBS) $(TLIBS)
|
||||
@@ -2378,6 +2388,8 @@ keywordhash.h: $(TOP)\tool\mkkeywordhash.c mkkeywordhash.exe
|
||||
# Source and header files that shell.c depends on
|
||||
SHELL_DEP = \
|
||||
$(TOP)\src\shell.c.in \
|
||||
$(TOP)\ext\qrf\qrf.c \
|
||||
$(TOP)\ext\qrf\qrf.h \
|
||||
$(TOP)\ext\expert\sqlite3expert.c \
|
||||
$(TOP)\ext\expert\sqlite3expert.h \
|
||||
$(TOP)\ext\intck\sqlite3intck.c \
|
||||
@@ -2541,9 +2553,9 @@ TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_STRICT_SUBTYPE=1
|
||||
TESTFIXTURE_SRC0 = $(TESTEXT) $(TESTSRC2)
|
||||
TESTFIXTURE_SRC1 = $(TESTEXT) $(SQLITE3C)
|
||||
!IF $(USE_AMALGAMATION)==0
|
||||
TESTFIXTURE_SRC = $(TESTSRC) $(TOP)\src\tclsqlite.c $(TESTFIXTURE_SRC0)
|
||||
TESTFIXTURE_SRC = $(TESTSRC) tclsqlite-ex.c $(TESTFIXTURE_SRC0)
|
||||
!ELSE
|
||||
TESTFIXTURE_SRC = $(TESTSRC) $(TOP)\src\tclsqlite.c $(TESTFIXTURE_SRC1)
|
||||
TESTFIXTURE_SRC = $(TESTSRC) tclsqlite-ex.c $(TESTFIXTURE_SRC1)
|
||||
!ENDIF
|
||||
|
||||
!IF $(USE_STDCALL)!=0 || $(FOR_WIN10)!=0
|
||||
@@ -2678,14 +2690,14 @@ smoketest: $(TESTPROGS)
|
||||
shelltest: $(TESTPROGS)
|
||||
.\testfixture.exe $(TOP)\test\permutations.test shell
|
||||
|
||||
sqlite3_analyzer.c: $(SQLITE3C) $(SQLITE3H) $(TOP)\src\tclsqlite.c $(TOP)\tool\spaceanal.tcl $(TOP)\tool\mkccode.tcl $(TOP)\tool\sqlite3_analyzer.c.in $(TOP)\ext\misc\sqlite3_stdio.h $(TOP)\ext\misc\sqlite3_stdio.c $(SQLITE_TCL_DEP)
|
||||
sqlite3_analyzer.c: $(SQLITE3C) $(SQLITE3H) tclsqlite-ex.c $(TOP)\tool\spaceanal.tcl $(TOP)\tool\mkccode.tcl $(TOP)\tool\sqlite3_analyzer.c.in $(TOP)\ext\misc\sqlite3_stdio.h $(TOP)\ext\misc\sqlite3_stdio.c $(SQLITE_TCL_DEP)
|
||||
$(TCLSH_CMD) $(TOP)\tool\mkccode.tcl -DINCLUDE_SQLITE3_C $(TOP)\tool\sqlite3_analyzer.c.in > $@
|
||||
|
||||
sqlite3_analyzer.exe: sqlite3_analyzer.c $(LIBRESOBJS)
|
||||
$(LTLINK) $(NO_WARN) -DBUILD_sqlite -I$(TCLINCDIR) sqlite3_analyzer.c \
|
||||
/link $(LDFLAGS) $(LTLINKOPTS) $(TCLLIBPATHS) $(LTLIBPATHS) $(LIBRESOBJS) $(TCLLIBS) $(LTLIBS) $(TLIBS)
|
||||
|
||||
sqltclsh.c: sqlite3.c $(TOP)\src\tclsqlite.c $(TOP)\tool\sqltclsh.tcl $(TOP)\ext\misc\appendvfs.c $(TOP)\tool\mkccode.tcl $(TOP)\tool\sqltclsh.c.in
|
||||
sqltclsh.c: sqlite3.c tclsqlite-ex.c $(TOP)\tool\sqltclsh.tcl $(TOP)\ext\misc\appendvfs.c $(TOP)\tool\mkccode.tcl $(TOP)\tool\sqltclsh.c.in
|
||||
$(TCLSH_CMD) $(TOP)\tool\mkccode.tcl $(TOP)\tool\sqltclsh.c.in >sqltclsh.c
|
||||
|
||||
sqltclsh.exe: sqltclsh.c $(SHELL_CORE_DEP) $(LIBRESOBJS)
|
||||
@@ -2698,7 +2710,7 @@ sqlite3_expert.exe: $(SQLITE3C) $(TOP)\ext\expert\sqlite3expert.h $(TOP)\ext\exp
|
||||
CHECKER_DEPS =\
|
||||
$(TOP)\tool\mkccode.tcl \
|
||||
sqlite3.c \
|
||||
$(TOP)\src\tclsqlite.c \
|
||||
tclsqlite-ex.c \
|
||||
$(TOP)\ext\repair\sqlite3_checker.tcl \
|
||||
$(TOP)\ext\repair\checkindex.c \
|
||||
$(TOP)\ext\repair\checkfreelist.c \
|
||||
|
||||
@@ -805,7 +805,8 @@ proc sqlite-handle-common-feature-flags {} {
|
||||
sqlite-add-feature-flag -DSQLITE_ENABLE_MEMSYS3
|
||||
}
|
||||
}
|
||||
scanstatus -DSQLITE_ENABLE_STMT_SCANSTATUS {}
|
||||
bytecode-vtab -DSQLITE_ENABLE_BYTECODE_VTAB {}
|
||||
scanstatus {-DSQLITE_ENABLE_STMT_SCANSTATUS -DSQLITE_ENABLE_BYTECODE_VTAB} {}
|
||||
column-metadata -DSQLITE_ENABLE_COLUMN_METADATA {}
|
||||
dbpage -DSQLITE_ENABLE_DBPAGE_VTAB {}
|
||||
dbstat -DSQLITE_ENABLE_DBSTAT_VTAB {}
|
||||
|
||||
@@ -90,7 +90,7 @@ foreach {tn setup} {
|
||||
proc do_rec_test {tn sql res} {
|
||||
set res [squish [string trim $res]]
|
||||
set tst [subst -nocommands {
|
||||
squish [string trim [exec $::CLI test.db ".expert" {$sql;}]]
|
||||
squish [string trim [exec $::CLI -noinit test.db ".expert" {$sql;}]]
|
||||
}]
|
||||
uplevel [list do_test $tn $tst $res]
|
||||
}
|
||||
|
||||
+51
-43
@@ -133,9 +133,11 @@
|
||||
** Which sqlite3.c we're using needs to be configurable to enable
|
||||
** building against a custom copy, e.g. the SEE variant. We have to
|
||||
** include sqlite3.c, as opposed to sqlite3.h, in order to get access
|
||||
** to some internal details like SQLITE_MAX_... and friends, and keep
|
||||
** those consistent with this build. This increases the rebuild time
|
||||
** considerably, however.
|
||||
** to some internal details like SQLITE_MAX_... and friends. This
|
||||
** increases the rebuild time considerably but we need this in order
|
||||
** to access some internal functionality and keep the to-Java-exported
|
||||
** values of SQLITE_MAX_... and SQLITE_LIMIT_... in sync with the C
|
||||
** build.
|
||||
*/
|
||||
#ifndef SQLITE_C
|
||||
# define SQLITE_C sqlite3.c
|
||||
@@ -333,7 +335,7 @@ struct S3JniNphOp {
|
||||
const char * const zMember /* Name of member property */;
|
||||
const char * const zTypeSig /* JNI type signature of zMember */;
|
||||
/*
|
||||
** klazz is a global ref to the class represented by zName.
|
||||
** klazz is a global ref to the class represented by pRef.
|
||||
**
|
||||
** According to:
|
||||
**
|
||||
@@ -997,20 +999,19 @@ static S3JniEnv * S3JniEnv__get(JNIEnv * const env){
|
||||
** JNI bindings such as sqlite3_prepare_v2/v3(), and definitely not
|
||||
** from client code.
|
||||
**
|
||||
** Returns err_code _unless_ err_code is 0 and sqlite3_set_errmsg()
|
||||
** fails with OOM, in which case it may return SQLITE_OOM or fail
|
||||
** fatally.
|
||||
**
|
||||
** This function predates sqlite3_set_errmsg(), which is why it has a
|
||||
** slightly different interface. Before that function was introduced,
|
||||
** this code used the SQLite-internal APIs to do this.
|
||||
** Returns err_code.
|
||||
*/
|
||||
static int s3jni_db_error(JNIEnv * env, sqlite3* const db,
|
||||
int err_code, const char * const zMsg){
|
||||
static int s3jni_db_error(sqlite3* const db, int err_code,
|
||||
const char * const zMsg){
|
||||
if( db!=0 ){
|
||||
int const rc = sqlite3_set_errmsg(db, err_code, zMsg);
|
||||
s3jni_oom_fatal(0==rc);
|
||||
if( rc && !err_code ) err_code=rc;
|
||||
if( 0==zMsg ){
|
||||
sqlite3Error(db, err_code);
|
||||
}else{
|
||||
const int nMsg = sqlite3Strlen30(zMsg);
|
||||
sqlite3_mutex_enter(sqlite3_db_mutex(db));
|
||||
sqlite3ErrorWithMsg(db, err_code, "%.*s", nMsg, zMsg);
|
||||
sqlite3_mutex_leave(sqlite3_db_mutex(db));
|
||||
}
|
||||
}
|
||||
return err_code;
|
||||
}
|
||||
@@ -1234,11 +1235,11 @@ static int s3jni__db_exception(JNIEnv * const env, sqlite3 * const pDb,
|
||||
char * zMsg;
|
||||
S3JniExceptionClear;
|
||||
zMsg = s3jni_exception_error_msg(env, ex);
|
||||
s3jni_db_error(env, pDb, errCode, zMsg ? zMsg : zDfltMsg);
|
||||
s3jni_db_error(pDb, errCode, zMsg ? zMsg : zDfltMsg);
|
||||
sqlite3_free(zMsg);
|
||||
S3JniUnrefLocal(ex);
|
||||
}else if( zDfltMsg ){
|
||||
s3jni_db_error(env, pDb, errCode, zDfltMsg);
|
||||
s3jni_db_error(pDb, errCode, zDfltMsg);
|
||||
}
|
||||
return errCode;
|
||||
}
|
||||
@@ -1955,6 +1956,15 @@ static void S3JniUdf_finalizer(void * s){
|
||||
S3JniUdf_free(s3jni_env(), (S3JniUdf*)s, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
** Helper for processing args to UDF handlers with signature
|
||||
** (sqlite3_context*,int,sqlite3_value**).
|
||||
*/
|
||||
typedef struct {
|
||||
jobject jcx /* sqlite3_context */;
|
||||
jobjectArray jargv /* sqlite3_value[] */;
|
||||
} udf_jargs;
|
||||
|
||||
/*
|
||||
** Converts the given (cx, argc, argv) into arguments for the given
|
||||
** UDF, writing the result (Java wrappers for cx and argv) in the
|
||||
@@ -1996,7 +2006,7 @@ error_oom:
|
||||
/*
|
||||
** Requires that jCx and jArgv are sqlite3_context
|
||||
** resp. array-of-sqlite3_value values initialized by udf_args(). The
|
||||
** (argc,argv) are (0,NULL) for UDF types with no arguments. This
|
||||
** latter will be 0-and-NULL for UDF types with no arguments. This
|
||||
** function zeroes out the nativePointer member of jCx and each entry
|
||||
** in jArgv. This is a safety-net precaution to avoid undefined
|
||||
** behavior if a Java-side UDF holds a reference to its context or one
|
||||
@@ -2089,19 +2099,19 @@ static int udf_xFSI(sqlite3_context* const pCx, int argc,
|
||||
sqlite3_value** const argv, S3JniUdf * const s,
|
||||
jmethodID xMethodID, const char * const zFuncType){
|
||||
S3JniDeclLocal_env;
|
||||
jobject jcx = 0 /* sqlite3_context */;
|
||||
jobjectArray jargv = 0 /* sqlite3_value[] */;
|
||||
int rc = udf_args(env, pCx, argc, argv, &jcx, &jargv);
|
||||
udf_jargs args = {0,0};
|
||||
int rc = udf_args(env, pCx, argc, argv, &args.jcx, &args.jargv);
|
||||
|
||||
if( 0 == rc ){
|
||||
(*env)->CallVoidMethod(env, s->jObj, xMethodID, jcx, jargv);
|
||||
(*env)->CallVoidMethod(env, s->jObj, xMethodID, args.jcx, args.jargv);
|
||||
S3JniIfThrew{
|
||||
rc = udf_report_exception(env, 'F'==zFuncType[1]/*xFunc*/, pCx,
|
||||
s->zFuncName, zFuncType);
|
||||
}
|
||||
udf_unargs(env, jcx, argc, jargv);
|
||||
udf_unargs(env, args.jcx, argc, args.jargv);
|
||||
}
|
||||
S3JniUnrefLocal(jcx);
|
||||
S3JniUnrefLocal(jargv);
|
||||
S3JniUnrefLocal(args.jcx);
|
||||
S3JniUnrefLocal(args.jargv);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -3290,7 +3300,7 @@ static jobject s3jni_commit_rollback_hook(int isCommit, JNIEnv * const env,
|
||||
S3JniDb_mutex_enter;
|
||||
ps = S3JniDb_from_jlong(jpDb);
|
||||
if( !ps ){
|
||||
s3jni_db_error(env, ps->pDb, SQLITE_MISUSE, 0);
|
||||
s3jni_db_error(ps->pDb, SQLITE_MISUSE, 0);
|
||||
S3JniDb_mutex_leave;
|
||||
return 0;
|
||||
}
|
||||
@@ -3310,14 +3320,13 @@ static jobject s3jni_commit_rollback_hook(int isCommit, JNIEnv * const env,
|
||||
else sqlite3_rollback_hook(ps->pDb, 0, 0);
|
||||
}else{
|
||||
jclass const klazz = (*env)->GetObjectClass(env, jHook);
|
||||
jmethodID const xCallback =
|
||||
(*env)->GetMethodID(env, klazz, "call",
|
||||
isCommit ? "()I" : "()V");
|
||||
jmethodID const xCallback = (*env)->GetMethodID(env, klazz, "call",
|
||||
isCommit ? "()I" : "()V");
|
||||
S3JniUnrefLocal(klazz);
|
||||
S3JniIfThrew {
|
||||
S3JniExceptionReport;
|
||||
S3JniExceptionClear;
|
||||
s3jni_db_error(env, ps->pDb, SQLITE_ERROR,
|
||||
s3jni_db_error(ps->pDb, SQLITE_ERROR,
|
||||
"Cannot not find matching call() method in"
|
||||
"hook object.");
|
||||
}else{
|
||||
@@ -3597,7 +3606,7 @@ S3JniApi(sqlite3_create_collation() sqlite3_create_collation_v2(),
|
||||
(*env)->GetMethodID(env, klazz, "call", "([B[B)I");
|
||||
S3JniUnrefLocal(klazz);
|
||||
S3JniIfThrew{
|
||||
rc = s3jni_db_error(env, ps->pDb, SQLITE_ERROR,
|
||||
rc = s3jni_db_error(ps->pDb, SQLITE_ERROR,
|
||||
"Could not get call() method from "
|
||||
"CollationCallback object.");
|
||||
}else{
|
||||
@@ -3636,15 +3645,15 @@ S3JniApi(sqlite3_create_function() sqlite3_create_function_v2()
|
||||
|
||||
if( !pDb || !jFuncName ){
|
||||
return SQLITE_MISUSE;
|
||||
}else if( !encodingTypeIsValid(eTextRep & 0x0f) ){
|
||||
return s3jni_db_error(env, pDb, SQLITE_FORMAT,
|
||||
}else if( !encodingTypeIsValid(eTextRep) ){
|
||||
return s3jni_db_error(pDb, SQLITE_FORMAT,
|
||||
"Invalid function encoding option.");
|
||||
}
|
||||
s = S3JniUdf_alloc(env, jFunctor);
|
||||
if( !s ) return SQLITE_NOMEM;
|
||||
|
||||
if( UDF_UNKNOWN_TYPE==s->type ){
|
||||
rc = s3jni_db_error(env, pDb, SQLITE_MISUSE,
|
||||
rc = s3jni_db_error(pDb, SQLITE_MISUSE,
|
||||
"Cannot unambiguously determine function type.");
|
||||
S3JniUdf_free(env, s, 1);
|
||||
goto error_cleanup;
|
||||
@@ -4003,7 +4012,7 @@ S3JniApi(sqlite3_jni_db_error(), jint, 1jni_1db_1error)(
|
||||
zStr = jStr
|
||||
? s3jni_jstring_to_utf8( jStr, 0)
|
||||
: NULL;
|
||||
rc = s3jni_db_error(env, ps->pDb, (int)jRc, zStr );
|
||||
rc = s3jni_db_error( ps->pDb, (int)jRc, zStr );
|
||||
sqlite3_free(zStr);
|
||||
}
|
||||
return rc;
|
||||
@@ -4312,7 +4321,7 @@ static void s3jni_updatepre_hook_impl(void * pState, sqlite3 *pDb, int opId,
|
||||
jTable = jDbName ? s3jni_utf8_to_jstring( zTable, -1) : 0;
|
||||
S3JniIfThrew {
|
||||
S3JniExceptionClear;
|
||||
s3jni_db_error(env, ps->pDb, SQLITE_NOMEM, 0);
|
||||
s3jni_db_error(ps->pDb, SQLITE_NOMEM, 0);
|
||||
}else{
|
||||
assert( hook.jObj );
|
||||
assert( hook.midCallback );
|
||||
@@ -4414,7 +4423,7 @@ static jobject s3jni_updatepre_hook(JNIEnv * env, int isPre, jlong jpDb, jobject
|
||||
S3JniUnrefLocal(klazz);
|
||||
S3JniIfThrew {
|
||||
S3JniExceptionClear;
|
||||
s3jni_db_error(env, ps->pDb, SQLITE_ERROR,
|
||||
s3jni_db_error(ps->pDb, SQLITE_ERROR,
|
||||
"Cannot not find matching callback on "
|
||||
"(pre)update hook object.");
|
||||
}else{
|
||||
@@ -4523,7 +4532,7 @@ S3JniApi(sqlite3_progress_handler(),void,1progress_1handler)(
|
||||
S3JniUnrefLocal(klazz);
|
||||
S3JniIfThrew {
|
||||
S3JniExceptionClear;
|
||||
s3jni_db_error(env, ps->pDb, SQLITE_ERROR,
|
||||
s3jni_db_error(ps->pDb, SQLITE_ERROR,
|
||||
"Cannot not find matching xCallback() on "
|
||||
"ProgressHandler object.");
|
||||
}else{
|
||||
@@ -4897,9 +4906,8 @@ S3JniApi(sqlite3_set_authorizer(),jint,1set_1authorizer)(
|
||||
")I");
|
||||
S3JniUnrefLocal(klazz);
|
||||
S3JniIfThrew {
|
||||
rc = s3jni_db_error(env, ps->pDb, SQLITE_ERROR,
|
||||
"Error setting up Java parts of "
|
||||
"authorizer hook.");
|
||||
rc = s3jni_db_error(ps->pDb, SQLITE_ERROR,
|
||||
"Error setting up Java parts of authorizer hook.");
|
||||
}else{
|
||||
rc = sqlite3_set_authorizer(ps->pDb, s3jni_xAuth, ps);
|
||||
}
|
||||
@@ -5183,7 +5191,7 @@ S3JniApi(sqlite3_trace_v2(),jint,1trace_1v2)(
|
||||
S3JniUnrefLocal(klazz);
|
||||
S3JniIfThrew {
|
||||
S3JniExceptionClear;
|
||||
rc = s3jni_db_error(env, ps->pDb, SQLITE_ERROR,
|
||||
rc = s3jni_db_error(ps->pDb, SQLITE_ERROR,
|
||||
"Cannot not find matching call() on "
|
||||
"TracerCallback object.");
|
||||
}else{
|
||||
|
||||
@@ -815,9 +815,7 @@ public class Tester1 implements Runnable {
|
||||
};
|
||||
|
||||
// Register and use the function...
|
||||
int rc = sqlite3_create_function(db, "myfunc", -1,
|
||||
SQLITE_UTF8 | SQLITE_INNOCUOUS,
|
||||
func);
|
||||
int rc = sqlite3_create_function(db, "myfunc", -1, SQLITE_UTF8, func);
|
||||
affirm(0 == rc);
|
||||
affirm(0 == xFuncAccum.value);
|
||||
final sqlite3_stmt stmt = prepare(db, "SELECT myfunc(1,2,3)");
|
||||
|
||||
@@ -258,7 +258,7 @@ int sqlite3_fputs(const char *z, FILE *out){
|
||||
|
||||
|
||||
/*
|
||||
** Work-alike for fprintf() from the standard C library.
|
||||
** Work-alikes for fprintf() and vfprintf() from the standard C library.
|
||||
*/
|
||||
int sqlite3_fprintf(FILE *out, const char *zFormat, ...){
|
||||
int rc;
|
||||
@@ -285,6 +285,24 @@ int sqlite3_fprintf(FILE *out, const char *zFormat, ...){
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
int sqlite3_vfprintf(FILE *out, const char *zFormat, va_list ap){
|
||||
int rc;
|
||||
if( UseWtextForOutput(out) ){
|
||||
/* When writing to the command-prompt in Windows, it is necessary
|
||||
** to use _O_WTEXT input mode and write UTF-16 characters.
|
||||
*/
|
||||
char *z;
|
||||
z = sqlite3_vmprintf(zFormat, ap);
|
||||
sqlite3_fputs(z, out);
|
||||
rc = (int)strlen(z);
|
||||
sqlite3_free(z);
|
||||
}else{
|
||||
/* Writing to a file or other destination, just write bytes without
|
||||
** any translation. */
|
||||
rc = vfprintf(out, zFormat, ap);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Set the mode for an output stream. mode argument is typically _O_BINARY or
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#ifdef _WIN32
|
||||
/**** Definitions For Windows ****/
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <windows.h>
|
||||
|
||||
FILE *sqlite3_fopen(const char *zFilename, const char *zMode);
|
||||
@@ -38,6 +39,7 @@ FILE *sqlite3_popen(const char *zCommand, const char *type);
|
||||
char *sqlite3_fgets(char *s, int size, FILE *stream);
|
||||
int sqlite3_fputs(const char *s, FILE *stream);
|
||||
int sqlite3_fprintf(FILE *stream, const char *format, ...);
|
||||
int sqlite3_vfprintf(FILE *stream, const char *format, va_list);
|
||||
void sqlite3_fsetmode(FILE *stream, int mode);
|
||||
|
||||
|
||||
@@ -49,6 +51,7 @@ void sqlite3_fsetmode(FILE *stream, int mode);
|
||||
#define sqlite3_fgets fgets
|
||||
#define sqlite3_fputs fputs
|
||||
#define sqlite3_fprintf fprintf
|
||||
#define sqlite3_vfprintf vfprintf
|
||||
#define sqlite3_fsetmode(F,X) /*no-op*/
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,674 @@
|
||||
# SQLite Query Result Formatting Subsystem
|
||||
|
||||
The "Query Result Formatter" or "QRF" subsystem is a C-language
|
||||
subroutine that formats the output from an SQLite query for display using
|
||||
a fix-width font, for example on a terminal window over an SSH connection.
|
||||
The output format is configurable. The application can request various
|
||||
table formats, with flexible column widths and alignments, row-oriented
|
||||
formats, such as CSV and similar, as well as various special purpose formats
|
||||
like JSON.
|
||||
|
||||
For the first 25 years of SQLite's existance, the
|
||||
[command-line interface](https://sqlite.org/cli.html) (CLI)
|
||||
formatted query results using a hodge-podge of routines
|
||||
that had grown slowly by accretion. The QRF was created
|
||||
in fall of 2025 to refactor and reorganize this code into
|
||||
a more usable form. The idea behind QRF is to implement all the
|
||||
query result formatting capabilities of the CLI in a subroutine
|
||||
that can be incorporated and reused by other applications.
|
||||
|
||||
## 1.0 Overview Of Operation
|
||||
|
||||
Suppose `pStmt` is a pointer to an SQLite prepared statement
|
||||
(a pointer to an `sqlite3_stmt` object) that has been reset and
|
||||
bound and is ready to run. Then to format the output from this
|
||||
prepared statement, use code similar to the following:
|
||||
|
||||
> ~~~
|
||||
sqlite3_qrf_spec spec; /* Format specification */
|
||||
char *zErrMsg; /* Text error message (optional) */
|
||||
char *zResult = 0; /* Formatted output written here */
|
||||
int rc; /* Result code */
|
||||
|
||||
memset(&spec, 0, sizeof(spec)); /* Initialize the spec */
|
||||
spec.iVersion = 1; /* Version number must be 1 */
|
||||
spec.pzOutput = &zResult; /* Write results in variable zResult */
|
||||
/* Optionally fill in other settings in spec here, as needed */
|
||||
zErrMsg = 0; /* Not required; just being pedantic */
|
||||
rc = sqlite3_format_query_result(pStmt, &spec, &zErrMsg); /* Format results */
|
||||
if( rc ){
|
||||
printf("Error (%d): %s\n", rc, zErrMsg); /* Report an error */
|
||||
sqlite3_free(zErrMsg); /* Free the error message text */
|
||||
}else{
|
||||
printf("%s", zResult); /* Report the results */
|
||||
sqlite3_free(zResult); /* Free memory used to hold results */
|
||||
}
|
||||
~~~
|
||||
|
||||
The `sqlite3_qrf_spec` object describes the desired output format
|
||||
and what to do with the generated output. Most of the work in using
|
||||
the QRF involves filling out the sqlite3_qrf_spec.
|
||||
|
||||
## 2.0 The `sqlite3_qrf_spec` object
|
||||
|
||||
The `sqlite3_qrf_spec` structure defines how the results of a query
|
||||
are to be formatted, and what to do with the formatted text. The
|
||||
most recent definition of `sqlite3_qrf_spec` is shown below.
|
||||
|
||||
Do not be alarmed by the complexity of this structure. You only have
|
||||
to understand the properties you want to modify. Zero is always a good
|
||||
default for all of the attributes (except iVersion and pzOutput/xWrite)
|
||||
and so simply zeroing out the bulk of this structure is a good start.
|
||||
You can then slowly make adjustments to individual fields to get the
|
||||
results you desire.
|
||||
|
||||
> ~~~
|
||||
typedef struct sqlite3_qrf_spec sqlite3_qrf_spec;
|
||||
struct sqlite3_qrf_spec {
|
||||
unsigned char iVersion; /* Version number of this structure */
|
||||
unsigned char eStyle; /* Formatting style. "box", "csv", etc... */
|
||||
unsigned char eEsc; /* How to escape control characters in text */
|
||||
unsigned char eText; /* Quoting style for text */
|
||||
unsigned char eTitle; /* Quating style for the text of column names */
|
||||
unsigned char eBlob; /* Quoting style for BLOBs */
|
||||
unsigned char bTitles; /* True to show column names */
|
||||
unsigned char bWordWrap; /* Try to wrap on word boundaries */
|
||||
unsigned char bTextJsonb; /* Render JSONB blobs as JSON text */
|
||||
unsigned char bTextNull; /* Apply eText encoding to zNull[] */
|
||||
unsigned char eDfltAlign; /* Default alignment, no covered by aAlignment */
|
||||
unsigned char eTitleAlign; /* Alignment for column headers */
|
||||
short int nWrap; /* Wrap columns wider than this */
|
||||
short int nScreenWidth; /* Maximum overall table width */
|
||||
short int nLineLimit; /* Maximum number of lines for any row */
|
||||
int nCharLimit; /* Maximum number of characters in a cell */
|
||||
int nWidth; /* Number of entries in aWidth[] */
|
||||
int nAlign; /* Number of entries in aAlignment[] */
|
||||
short int *aWidth; /* Column widths */
|
||||
unsigned char *aAlign; /* Column alignments */
|
||||
char *zColumnSep; /* Alternative column separator */
|
||||
char *zRowSep; /* Alternative row separator */
|
||||
char *zTableName; /* Output table name */
|
||||
char *zNull; /* Rendering of NULL */
|
||||
char *(*xRender)(void*,sqlite3_value*); /* Render a value */
|
||||
int (*xWrite)(void*,const char*,sqlite3_int64); /* Write output */
|
||||
void *pRenderArg; /* First argument to the xRender callback */
|
||||
void *pWriteArg; /* First argument to the xWrite callback */
|
||||
char **pzOutput; /* Storage location for output string */
|
||||
/* Additional fields may be added in the future */
|
||||
};
|
||||
~~~
|
||||
|
||||
Again, the only fields that must initialized are:
|
||||
|
||||
* `.iVersion`
|
||||
* One of `.pzOutput` or `.xWrite`.
|
||||
|
||||
All other fields can be zeroed. Or they can contain other values to
|
||||
alter the formatting of the query results.
|
||||
|
||||
Further detail on the meanings of each of the fields in the
|
||||
`sqlite3_qrf_spec` object are described below.
|
||||
|
||||
### 2.1 Structure Version Number
|
||||
|
||||
The sqlite3_qrf_spec.iVersion field must be 1. Future enhancements to
|
||||
the QRF might add new fields onto the bottom of the sqlite3_qrf_spec
|
||||
object. Those new fields will only be accessible if the iVersion is greater
|
||||
than 1. Thus the iVersion field is used to support upgradability.
|
||||
|
||||
### 2.2 Output Deposition (xWrite and pzOutput)
|
||||
|
||||
The formatted output can either be sent to a callback function
|
||||
or accumulated into an output buffer in memory obtained
|
||||
from sqlite3_malloc(). If the sqlite3_qrf_spec.xWrite column is not NULL,
|
||||
then that function is invoked (using sqlite3_qrf_spec.xWriteArg as its
|
||||
first argument) to transmit the formatted output. Or, if
|
||||
sqlite3_qrf_spec.pzOutput points to a pointer to a character, then that
|
||||
pointer is made to point to memory obtained from sqlite3_malloc() that
|
||||
contains the complete text of the formatted output. If spec.pzOutput\[0\]
|
||||
is initially non-NULL, then it is assumed to point to memory obtained
|
||||
from sqlite3_malloc(). In that case, the buffer is resized using
|
||||
sqlite3_realloc() and the new text is appended.
|
||||
|
||||
One of either sqlite3_qrf_spec.xWrite and sqlite3_qrf_spec.pzOutput must be
|
||||
non-NULL and the other must be NULL.
|
||||
|
||||
The return value from xWrite is an SQLITE result code. The usual return
|
||||
should be SQLITE_OK. But if for some reason the write fails, a different
|
||||
value might be returned.
|
||||
|
||||
### 2.3 Output Format
|
||||
|
||||
The sqlite3_qrf_spec.eStyle field is an integer code that defines the
|
||||
specific output format that will be generated. See section 4.0 below
|
||||
for details on the meaning of the various style options.
|
||||
|
||||
Other fields in sqlite3_qrf_spec might be used or might be
|
||||
ignored, depending on the value of eStyle.
|
||||
|
||||
### 2.4 Show Column Names (bTitles)
|
||||
|
||||
The sqlite3_qrf_spec.bTitles field can be either QRF_SW_Auto,
|
||||
QRF_SW_On, or QRF_SW_Off. Those three constants also have shorter
|
||||
alternative spellings: QRF_Auto, QRF_No, and
|
||||
QRF_Yes.
|
||||
|
||||
> ~~~
|
||||
#define QRF_SW_Auto 0 /* Let QRF choose the best value */
|
||||
#define QRF_SW_Off 1 /* This setting is forced off */
|
||||
#define QRF_SW_On 2 /* This setting is forced on */
|
||||
#define QRF_Auto 0 /* Alternate spelling for QRF_SW_Auto and others */
|
||||
#define QRF_No 1 /* Alternate spelling for QRF_SW_Off */
|
||||
#define QRF_Yes 2 /* Alternate spelling for QRF_SW_On */
|
||||
~~~
|
||||
|
||||
If the value is QRF_Yes, then column names appear in the output.
|
||||
If the value is QRF_No, column names are omitted. If the
|
||||
value is QRF_Auto, then an appropriate default is chosen.
|
||||
|
||||
### 2.5 Control Character Escapes (eEsc)
|
||||
|
||||
The sqlite3_qrf_spec.eEsc determines how ASCII control characters are
|
||||
formatted when displaying TEXT values in the result. These are the allowed
|
||||
values:
|
||||
|
||||
> ~~~
|
||||
#define QRF_ESC_Auto 0 /* Choose the ctrl-char escape automatically */
|
||||
#define QRF_ESC_Off 1 /* Do not escape control characters */
|
||||
#define QRF_ESC_Ascii 2 /* Unix-style escapes. Ex: U+0007 shows ^G */
|
||||
#define QRF_ESC_Symbol 3 /* Unicode escapes. Ex: U+0007 shows U+2407 */
|
||||
~~~
|
||||
|
||||
If the value of eEsc is QRF_ESC_Ascii, then the control character
|
||||
with value X is displayed as ^Y where Y is X+0x40. Hence, a
|
||||
backspace character (U+0008) is shown as "^H".
|
||||
|
||||
If eEsc is QRF_ESC_Symbol, then control characters in the range of U+0001
|
||||
through U+001f are mapped into U+2401 through U+241f, respectively.
|
||||
|
||||
If the value of eEsc is QRF_ESC_Off, then no translation occurs
|
||||
and control characters that appear in TEXT strings are transmitted
|
||||
to the formatted output as-is. This can be dangerous in applications,
|
||||
since an adversary who can control TEXT values might be able to
|
||||
inject ANSI cursor movement sequences to hide nefarious values.
|
||||
|
||||
The QRF_ESC_Auto value for eEsc means that the query result formatter
|
||||
gets to pick whichever control-character encoding it thinks is best for
|
||||
the situation. This will usually be QRF_ESC_Ascii.
|
||||
|
||||
The TAB (U+0009), LF (U+000a) and CR-LF (U+000d,U+000a) character
|
||||
sequence are always output literally and are not mapped to alternative
|
||||
display values, regardless of this setting.
|
||||
|
||||
### 2.6 Display of TEXT values (eText, eTitle)
|
||||
|
||||
The sqlite3_qrf_spec.eText controls how text values are rendered in the
|
||||
display. sqlite3_qrf_spec.eTitle controls how column names are rendered.
|
||||
Both fields can have one of the following values:
|
||||
|
||||
> ~~~
|
||||
#define QRF_TEXT_Auto 0 /* Choose text encoding automatically */
|
||||
#define QRF_TEXT_Plain 1 /* Literal text */
|
||||
#define QRF_TEXT_Sql 2 /* Quote as an SQL literal */
|
||||
#define QRF_TEXT_Csv 3 /* CSV-style quoting */
|
||||
#define QRF_TEXT_Html 4 /* HTML-style quoting */
|
||||
#define QRF_TEXT_Tcl 5 /* C/Tcl quoting */
|
||||
#define QRF_TEXT_Json 6 /* JSON quoting */
|
||||
~~~
|
||||
|
||||
A value of QRF_TEXT_Auto means that the query result formatter will choose
|
||||
what it thinks will be the best text encoding.
|
||||
|
||||
A value of QRF_TEXT_Plain means that text values appear in the output exactly
|
||||
as they are found in the database file, with no translation.
|
||||
|
||||
A value of QRF_TEXT_Sql means that text values are escaped so that they
|
||||
look like SQL literals. That means the value will be surrounded by
|
||||
single-quotes (U+0027) and any single-quotes contained within the text
|
||||
will be doubled.
|
||||
|
||||
A value of QRF_TEXT_Csv means that text values are escaped in accordance
|
||||
with RFC 4180, which defines Comma-Separated-Value or CSV files.
|
||||
Text strings that contain no special values appears as-is. Text strings
|
||||
that contain special values are contained in double-quotes (U+0022) and
|
||||
any double-quotes within the value are doubled.
|
||||
|
||||
A value of QRF_TEXT_Html means that text values are escaped for use in
|
||||
HTML. Special characters "<", "&", ">", """, and "'"
|
||||
are displayed as "&lt;", "&amp;", "&gt;", "&quot;",
|
||||
and "&#39;", respectively.
|
||||
|
||||
A value of QRF_TEXT_Tcl means that text values are displayed inside of
|
||||
double-quotes and special characters within the string are escaped using
|
||||
backslash escape, as in ANSI-C or TCL or Perl or other popular programming
|
||||
languages.
|
||||
|
||||
A value of QRF_TEXT_Json gives similar results as QRF_TEXT_Tcl except that the
|
||||
rules are adjusted so that the displayed string is strictly conforming
|
||||
the JSON specification.
|
||||
|
||||
### 2.7 How to display BLOB values (eBlob and bTextJsonb)
|
||||
|
||||
If the sqlite3_qrf_spec.bTextJsonb flag is QRF_SW_On and if the value to be
|
||||
displayed is JSONB, then the JSONB is translated into text JSON and the
|
||||
text is shown according to the sqlite3_qrf_spec.eText setting as
|
||||
described in the previous section.
|
||||
|
||||
If the bTextJsonb flag is QRF_SW_Off (the usual case) or if the BLOB value to
|
||||
be displayed is not JSONB, then the sqlite3_qrf_spec.eBlob field determines
|
||||
how the BLOB value is formatted. The following options are available;
|
||||
|
||||
> ~~~
|
||||
#define QRF_BLOB_Auto 0 /* Determine BLOB quoting using eText */
|
||||
#define QRF_BLOB_Text 1 /* Display content exactly as it is */
|
||||
#define QRF_BLOB_Sql 2 /* Quote as an SQL literal */
|
||||
#define QRF_BLOB_Hex 3 /* Hexadecimal representation */
|
||||
#define QRF_BLOB_Tcl 4 /* "\000" notation */
|
||||
#define QRF_BLOB_Json 5 /* A JSON string */
|
||||
~~~
|
||||
|
||||
A value of QRF_BLOB_Auto means that display format is selected automatically
|
||||
by sqlite3_format_query_result() based on eStyle and eText.
|
||||
|
||||
A value of QRF_BLOB_Text means that BLOB values are interpreted as UTF8
|
||||
text and are displayed using formatting results set by eEsc and
|
||||
eText.
|
||||
|
||||
A value of QRF_BLOB_Sql means that BLOB values are shown as SQL BLOB
|
||||
literals: a prefix "`x'`" following by hexadecimal and ending with a
|
||||
final "`'`".
|
||||
|
||||
A value of QRF_BLOB_Hex means that BLOB values are shown as
|
||||
hexadecimal text with no delimiters.
|
||||
|
||||
A value of QRF_BLOB_Tcl means that BLOB values are shown as a
|
||||
C/Tcl/Perl string literal where every byte is an octal backslash
|
||||
escape. So a BLOB of `x'052881f3'` would be displayed as
|
||||
`"\005\050\201\363"`.
|
||||
|
||||
A value of QRF_BLOB_Json is similar to QRF_BLOB_Tcl except that is
|
||||
uses unicode backslash escapes, since JSON does not understand
|
||||
the C/Tcl/Perl octal backslash escapes. So the string from the
|
||||
previous paragraph would be shown as
|
||||
`"\u0005\u0028\u0081\u00f3"`.
|
||||
|
||||
### 2.8 Maximum size of displayed content (nLineLimit, nCharLimit)
|
||||
|
||||
If the sqlite3_qrf_spec.nCharLimit setting is non-zero, then the formatter
|
||||
will display only the first nCharLimit characters of each value.
|
||||
Only characters that take up space are counted when enforcing this
|
||||
limit. Zero-width characters and VT100 escape sequences do not count
|
||||
toward this limit. The count is in characters, not bytes. When
|
||||
imposing this limit, the formatter adds the three characters "..."
|
||||
to the end of the value. Those added characters are not counted
|
||||
as part of the limit. Very small limits still result in truncation,
|
||||
but might render a few more characters than the limit.
|
||||
|
||||
If the sqlite3_qrf_spec.nLineLimit setting is non-zero, then the
|
||||
formatter will only display the first nLineLimit lines of each value.
|
||||
It does not matter if the value is split because it contains a newline
|
||||
character, or if it split by wrapping. This setting merely limits
|
||||
the number of displayed lines. This setting only works for
|
||||
**Box**, **Column**, **Line**, **Markdown**, and **Table** styles.
|
||||
|
||||
The idea behind both of these settings is to prevent large renderings
|
||||
when doing a query that (unexpectedly) contains very large text or
|
||||
blob values: perhaps megabyes of text.
|
||||
|
||||
### 2.9 Word Wrapping In Columnar Styles (nWrap, bWordWrap)
|
||||
|
||||
When using columnar formatting modes (QRF_STYLE_Box, QRF_STYLE_Column,
|
||||
QRF_STYLE_Markdown, or QRF_STYLE_Table), the formatter attempts to limit
|
||||
the width of any individual column to sqlite3_qrf_spec.nWrap characters
|
||||
if nWrap is non-zero. A zero value for nWrap means "unlimited".
|
||||
The nWrap limit might be exceeded if the limit is very small.
|
||||
|
||||
In order to keep individual columns within requested width limits,
|
||||
it is sometimes necessary to wrap the content for a single row of
|
||||
a single column across multiple lines. When this
|
||||
becomes necessary and if the bWordWrap setting is QRF_Yes, then the
|
||||
formatter attempts to split the content on whitespace or at a word boundary.
|
||||
If bWordWrap is QRF_No, then the formatter is free to split content
|
||||
anywhere, including in the middle of a word.
|
||||
|
||||
For narrow columns and wide words, it might sometimes be necessary to split
|
||||
a column in the middle of a word, even when bWordWrap is QRF_Yes.
|
||||
|
||||
### 2.10 Helping The Output To Fit On The Terminal (nScreenWidth)
|
||||
|
||||
The sqlite3_qrf_spec.nScreenWidth field can be set the number of
|
||||
characters that will fit on one line on the viewer output device.
|
||||
This is typically a number like 80 or 132. The formatter will attempt
|
||||
to reduce the length of output lines, depending on the style, so
|
||||
that all output fits on that screen.
|
||||
|
||||
A value of zero for nScreenWidth means "unknown" or "no width limit".
|
||||
When the value is zero, the formatter makes no attempt to keep the
|
||||
lines of output short.
|
||||
|
||||
The nScreenWidth is a hint to the formatter, not a requirement.
|
||||
The formatter trieds to keep lines below the nScreenWidth limit,
|
||||
but it does not guarantee that it will.
|
||||
|
||||
### 2.11 Individual Column Width (nWidth and aWidth)
|
||||
|
||||
The sqlite3_qrf_spec.aWidth field is a pointer to an array of
|
||||
signed 16-bit integers that control the width of individual columns
|
||||
in columnar output modes (QRF_STYLE_Box, QRF_STYLE_Column,
|
||||
QRF_STYLE_Markdown, or QRF_STYLE_Table). The sqlite3_qrf_spec.nWidth
|
||||
field is the number of integers in the aWidth array.
|
||||
|
||||
If aWidth is a NULL pointer or if nWidth is zero, then the array is
|
||||
assumed to be all zeros. If nWidth is less then the number of
|
||||
columns in the output, then zero is used for the width
|
||||
for all columns past then end of the aWidth array.
|
||||
|
||||
The aWidth array is deliberately an array of 16-bit signed integers.
|
||||
Only 16 bits are used because no good comes for having very large
|
||||
column widths. The range if further restricted as follows:
|
||||
|
||||
> ~~~
|
||||
#define QRF_MAX_WIDTH 10000 /* Maximum column width */
|
||||
#define QRF_MIN_WIDTH 0 /* Minimum column width */
|
||||
~~~
|
||||
|
||||
A width greater than then QRF_MAX_WIDTH is interpreted as QRF_MAX_WIDTH.
|
||||
|
||||
Any aWidth\[\] value of zero means the formatter should use a flexible
|
||||
width column (limited only by sqlite_qrf_spec.mxWidth) that is just
|
||||
big enough to hold the largest row.
|
||||
|
||||
For historical compatibility, aWidth\[\] can contain negative values,
|
||||
down to -QRF_MAX_WIDTH. The column width used is the absolute value
|
||||
of the number in aWidth\[\]. The only difference is that negative
|
||||
values cause the default horizontal alignment to be QRF_ALIGN_Right.
|
||||
The sign of the aWidth\[\] values only affects alignment if the
|
||||
alignment is not otherwise specified by aAlign\[\] or eDfltAlign.
|
||||
Again, negative values for aWidth\[\] entries are supported for
|
||||
backwards compatibility only, and are not recommended for new
|
||||
applications.
|
||||
|
||||
### 2.12 Alignment (nAlignment, aAlignment, eDfltAlign, eTitleAlign)
|
||||
|
||||
Some cells in a display table might contain a lot of text and thus
|
||||
be wide, or they might contain newline characters or be wrapped by
|
||||
width constraints so that they span many rows of text. Other cells
|
||||
might be narrower and shorter. In columnar formats, the display width
|
||||
of a cell is the maximum of the widest value in the same column, and the
|
||||
display height is the height of the tallest value in the same row.
|
||||
So some cells might be much taller and wider than necessary to hold
|
||||
their values.
|
||||
|
||||
Alignment determines where smaller values are placed within larger cells.
|
||||
|
||||
The sqlite3_qrf_spec.aAlign field points to an array of unsigned characters
|
||||
that specifies alignment (both vertical and horizontal) of individual
|
||||
columns within the table. The sqlite3_qrf_spec.nAlign fields holds
|
||||
the number of entries in the aAlign\[\] array.
|
||||
|
||||
If sqlite3_qrf_spec.aAlign is a NULL pointer or if sqlite3_qrf_spec.nAlign
|
||||
is zero, or for columns to the right of what are specified by
|
||||
sqlite3_qrf_spec.nAlign, the sqlite3_qrf_spec.eDfltAlign value is used
|
||||
for the alignment. Column names can be (and often are) aligned
|
||||
differently, as specified by sqlite3_qrf_spec.eTitleAlign.
|
||||
|
||||
Each alignment value specifies both vertical and horizontal alignment.
|
||||
Horizontal alignment can be left, center, right, or no preference.
|
||||
Vertical alignment can be top, middle, bottom, or no preference.
|
||||
Thus there are 16 possible alignment values, as follows:
|
||||
|
||||
> ~~~
|
||||
/*
|
||||
** Horizontal Vertial
|
||||
** ---------- -------- */
|
||||
#define QRF_ALIGN_Auto 0 /* auto auto */
|
||||
#define QRF_ALIGN_Left 1 /* left auto */
|
||||
#define QRF_ALIGN_Center 2 /* center auto */
|
||||
#define QRF_ALIGN_Right 3 /* right auto */
|
||||
#define QRF_ALIGN_Top 4 /* auto top */
|
||||
#define QRF_ALIGN_NW 5 /* left top */
|
||||
#define QRF_ALIGN_N 6 /* center top */
|
||||
#define QRF_ALIGN_NE 7 /* right top */
|
||||
#define QRF_ALIGN_Middle 8 /* auto middle */
|
||||
#define QRF_ALIGN_W 9 /* left middle */
|
||||
#define QRF_ALIGN_C 10 /* center middle */
|
||||
#define QRF_ALIGN_E 11 /* right middle */
|
||||
#define QRF_ALIGN_Bottom 12 /* auto bottom */
|
||||
#define QRF_ALIGN_SW 13 /* left bottom */
|
||||
#define QRF_ALIGN_S 14 /* center bottom */
|
||||
#define QRF_ALIGN_SE 15 /* right bottom */
|
||||
~~~
|
||||
|
||||
Notice how alignment values with an unspecified horizontal
|
||||
or vertical component can be added to another alignment value
|
||||
for which that component is specified, to get a fully
|
||||
specified alignment. For eample:
|
||||
|
||||
> QRF_ALIGN_Center + QRF_ALIGN_Bottom == QRF_ALIGN_S.
|
||||
|
||||
The alignment for column names is always determined by the
|
||||
eTitleAlign setting. If eTitleAlign is QRF_Auto, then column
|
||||
names use center-bottom alignment, QRF_ALIGN_W, value 14.
|
||||
The aAlign\[\] and eDfltAlign settings have no affect on
|
||||
column names.
|
||||
|
||||
For data in the first nAlign columns, the aAlign\[\] array
|
||||
entry for that column takes precedence. If either the horizontal
|
||||
or vertical alignment has an "auto" value for that column or if
|
||||
a column is beyond the first nAlign entries, then eDfltAlign
|
||||
is used as a backup. If neither aAlign\[\] nor eDfltAlign
|
||||
specify a horizontal alignment, then values are left-aligned
|
||||
(QRF_ALIGN_Left). If neither aAlign\[\] nor eDfltAlign
|
||||
specify a vertical alignment, then values are top-aligned
|
||||
(QRF_ALIGN_Top).
|
||||
|
||||
*As of 2025-11-08, only horizontal alignment is implemented.
|
||||
The vertical alignment settings are currently ignored and
|
||||
the vertical alignment is always QRF_ALIGN_Top.*
|
||||
|
||||
### 2.13 Row and Column Separator Strings
|
||||
|
||||
The sqlite3_qrf_spec.zColumnSep and sqlite3_qrf_spec.zRowSep strings
|
||||
are alternative column and row separator character sequences. If not
|
||||
specified (if these pointers are left as NULL) then appropriate defaults
|
||||
are used. Some output styles have hard-coded column and row separators
|
||||
and these settings are ignored for those styles.
|
||||
|
||||
### 2.14 The Output Table Name
|
||||
|
||||
The sqlite3_qrf_spec.zTableName value is the name of the output table
|
||||
when eStyle is QRF_STYLE_Insert.
|
||||
|
||||
### 2.15 The Rendering Of NULL (zNull, eTextNull)
|
||||
|
||||
If a value is NULL then show the NULL using the string
|
||||
found in sqlite3_qrf_spec.zNull. If zNull is itself a NULL pointer
|
||||
then NULL values are rendered as an empty string.
|
||||
|
||||
If the sqlite3_qrf_spec.bTextNull field is QRF_Yes, then the
|
||||
text encoding specified by eText is applied to the value in
|
||||
zNull. If bTextNull is QRF_No or QRF_Auto, then the value
|
||||
in zNull is shown verbatim.
|
||||
|
||||
### 2.16 Optional Value Rendering Callback
|
||||
|
||||
If the sqlite3_qrf_spec.xRender field is not NULL, then each
|
||||
sqlite3_value coming out of the query is first passed to the
|
||||
xRender function, giving that function an opportunity to render
|
||||
the results itself, using whatever custom format is desired.
|
||||
If xRender chooses to render, it should write the rendering
|
||||
into memory obtained from sqlite3_malloc() and return a pointer
|
||||
to that memory. The xRender function can decline
|
||||
to render (for example, based on the sqlite3_value_type() or other
|
||||
characteristics of the value) in which case it can simply return a
|
||||
NULL pointer and the usual default rendering will be used instead.
|
||||
|
||||
The sqlite3_format_query_result() function (which calls xRender)
|
||||
will take responsibility for freeing the string returned by xRender
|
||||
after it has finished using it.
|
||||
|
||||
The eText, eBlob, and eEsc settings above become no-ops if the xRender
|
||||
routine returns non-NULL. In other words, the application-supplied
|
||||
xRender routine is expected to do all of its own quoting and formatting.
|
||||
|
||||
## 3.0 The `sqlite3_format_query_result()` Interface
|
||||
|
||||
Invoke the `sqlite3_format_query_result(P,S,E)` interface to run
|
||||
the prepared statement P and format its results according to the
|
||||
specification found in S. The sqlite3_format_query_result() function
|
||||
will return an SQLite result code, usually SQLITE_OK, but perhaps
|
||||
SQLITE_NOMEM or SQLITE_ERROR or similar. If an error occurs and if
|
||||
the E parameter is not NULL, then error message text might be written
|
||||
into *E. Any error message text will be stored in memory obtained
|
||||
from sqlite3_malloc() and it is the responsibility of the caller to
|
||||
free that memory by a subsequent call to sqlite3_free().
|
||||
|
||||
## 4.0 Output Styles
|
||||
|
||||
The result formatter supports a variety of output styles. The
|
||||
output style used is determined by the eStyle setting of the
|
||||
sqlite3_qrf_spec object. The set of supported output modes
|
||||
might increase in future versions.
|
||||
The following output modes are currently defined:
|
||||
|
||||
> ~~~
|
||||
#define QRF_STYLE_Auto 0 /* Choose a style automatically */
|
||||
#define QRF_STYLE_Box 1 /* Unicode box-drawing characters */
|
||||
#define QRF_STYLE_Column 2 /* One record per line in neat columns */
|
||||
#define QRF_STYLE_Count 3 /* Output only a count of the rows of output */
|
||||
#define QRF_STYLE_Csv 4 /* Comma-separated-value */
|
||||
#define QRF_STYLE_Eqp 5 /* Format EXPLAIN QUERY PLAN output */
|
||||
#define QRF_STYLE_Explain 6 /* EXPLAIN output */
|
||||
#define QRF_STYLE_Html 7 /* Generate an XHTML table */
|
||||
#define QRF_STYLE_Insert 8 /* Generate SQL "insert" statements */
|
||||
#define QRF_STYLE_Json 9 /* Output is a list of JSON objects */
|
||||
#define QRF_STYLE_JObject 10 /* Independent JSON objects for each row */
|
||||
#define QRF_STYLE_Line 11 /* One column per line. */
|
||||
#define QRF_STYLE_List 12 /* One record per line with a separator */
|
||||
#define QRF_STYLE_Markdown 13 /* Markdown formatting */
|
||||
#define QRF_STYLE_Off 14 /* No query output shown */
|
||||
#define QRF_STYLE_Quote 15 /* SQL-quoted, comma-separated */
|
||||
#define QRF_STYLE_Stats 16 /* EQP-like output but with performance stats */
|
||||
#define QRF_STYLE_StatsEst 17 /* EQP-like output with planner estimates */
|
||||
#define QRF_STYLE_StatsVm 18 /* EXPLAIN-like output with performance stats */
|
||||
#define QRF_STYLE_Table 19 /* MySQL-style table formatting */
|
||||
~~~
|
||||
|
||||
In the following subsections, these styles will often be referred
|
||||
to without the "QRF_STYLE_" prefix.
|
||||
|
||||
### 4.1 Default Style (Auto)
|
||||
|
||||
The **Auto** style means QRF gets to choose an appropriate output
|
||||
style. It will usually choose **Box**, but might also pick one of
|
||||
**Explain** or **Eqp** if the `sqlite3_stmt_explain()` function
|
||||
returns 1 or 2, respectively.
|
||||
|
||||
### 4.2 Columnar Styles (Box, Column, Markdown, Table)
|
||||
|
||||
The **Box**, **Column**, **Markdown**, and **Table**
|
||||
modes are columnar. This means the output is arranged into neat,
|
||||
uniform-width columns. These styles can use more memory, especially when
|
||||
the query result has many rows, because they need to load the entire output
|
||||
into memory first in order to determine how wide to make each column.
|
||||
|
||||
The nWidth, aWidth, and mxWidth fields of the `sqlite3_qrf_spec` object
|
||||
are used by these styles only, and are ignored by all other styles.
|
||||
The zRowSep and zColumnSep settings are ignored by these styles. The
|
||||
bTitles setting is honored by these styles; it defaults to QRF_SW_On.
|
||||
|
||||
The **Box** style uses Unicode box-drawing character to draw a grid
|
||||
of columns and rows to show the result. The **Table** is the same,
|
||||
except that it uses ASCII-art rather than Unicode box-drawing characters
|
||||
to draw the grid. The **Column** arranges the results in neat columns
|
||||
but does not draw in column or row separator, except that it does draw
|
||||
lines horizontal lines using "`-`" characters to separate the column names
|
||||
from the data below. This is very similar to default output styling in
|
||||
psql. The **Markdown** renders its result in the
|
||||
Markdown table format.
|
||||
|
||||
### 4.3 Line-oriented Styles
|
||||
|
||||
The line-oriented styles output each row of result as it is received from
|
||||
the prepared statement.
|
||||
|
||||
The **List** style is the most familiar line-oriented output format.
|
||||
The **List** style shows output columns for each row on the
|
||||
same line, each separated by a single "`|`" character and with lines
|
||||
terminated by a single newline (\\u000a or \\n). These column
|
||||
and row separator choices can be overridden using the zColumnSep
|
||||
and zRowSep fields of the `sqlite3_qrf_spec` structure. The text
|
||||
formatting is QRF_TEXT_Plain, and BLOB encoding is QRF_BLOB_Text. So
|
||||
characters appear in the output exactly as they appear in the database.
|
||||
Except the eEsp mode defaults to `QRF_ESC_On`, so that control
|
||||
characters are escaped, for safety.
|
||||
|
||||
The **Csv** and **Quote** styles are simply variations on **List**
|
||||
with hard-coded values for some of the sqlite3_qrf_spec settings:
|
||||
|
||||
<table border=1 cellpadding=2 cellspacing=0>
|
||||
<tr><th> <th>Quote<th>Csv
|
||||
<tr><td>zColumnSep<td>","<td>","
|
||||
<tr><td>zRowSep<td>"\\n"<td>"\\r\\n"
|
||||
<tr><td>zNull<td>"NULL"<td>""
|
||||
<tr><td>eText<td>QRF_TEXT_Sql<td>QRF_TEXT_Csv
|
||||
<tr><td>eBlob<td>QRF_BLOB_Sql<td>QRF_BLOB_Text
|
||||
</table>
|
||||
|
||||
The **Html** style generates HTML table content, just without
|
||||
the `<TABLE>..</TABLE>` around the outside.
|
||||
|
||||
The **Insert** style generates a series of SQL "INSERT" statements
|
||||
that will inserts the data that is output into a table whose name is defined
|
||||
by the zTableName field of `sqlite3_qrf_spec`. If zTableName is NULL,
|
||||
then a substitute name is used.
|
||||
|
||||
The **Json** and **JObject** styles generates JSON text for the query result.
|
||||
The **Json** style produces a JSON array of structures with one
|
||||
structure per row. **JObject** outputs independent JSON objects, one per
|
||||
row, with each structure on a separate line all by itself, and not
|
||||
part of a larger array. In both cases, the labels on the elements of the
|
||||
JSON objects are taken from the column names of the SQL query. So if
|
||||
you have an SQL query that has two or more output columns with the same
|
||||
name, you will end up with JSON structures that have duplicate elements.
|
||||
|
||||
Finally, the **Line** style paints each column of a row on a
|
||||
separate line with the column name on the left and a "`=`" separating the
|
||||
column name from its value. A single blank line appears between rows.
|
||||
|
||||
### 4.4 EXPLAIN Styles (Eqp, Explain)
|
||||
|
||||
The **Eqp** and **Explain** styles format output for
|
||||
EXPLAIN QUERY PLAN and EXPLAIN statements, respectively. If the input
|
||||
statement is not already an EXPLAIN QUERY PLAN or EXPLAIN statement is
|
||||
is temporarily converted for the duration of the rendering, but
|
||||
is converted back before `sqlite3_format_query_result()` returns.
|
||||
|
||||
### 4.5 ScanStatus Styles (Stats, StatsEst, StatsVm)
|
||||
|
||||
The **Stats**, **StatsEst**, and **StatsVm** styles are similar to **Eqp**
|
||||
and **Explain** except that they include profiling information
|
||||
from prior executions of the input prepared statement.
|
||||
These modes only work if SQLite has been compiled with
|
||||
-DSQLITE_ENABLE_STMT_SCANSTATUS and if the SQLITE_DBCONFIG_STMT_SCANSTATUS
|
||||
is enabled for the database connection. The **StatsVm** style
|
||||
also requires the bytecode() virtual table which is enabled using
|
||||
the -DSQLITE_ENABLE_BYTECODE_VTAB compile-time option.
|
||||
|
||||
### 4.6 Other Styles (Count, Off)
|
||||
|
||||
The **Count** style discards all query results and returns
|
||||
a count of the number of rows of output at the end. The **Off**
|
||||
style is completely silent; it generates no output. These corner-case
|
||||
modes are sometimes useful for debugging.
|
||||
|
||||
### 5.0 Source Code Files
|
||||
|
||||
The SQLite Query Result Formatter is implemented in three source code files:
|
||||
|
||||
* `qrf.c` → The implementation, written in portable C99
|
||||
* `qrf.h` → A header file defining interfaces
|
||||
* `README.md` → This documentation, in Markdown
|
||||
|
||||
To use the SQLite result formatter, include the "`qrf.h`" header file
|
||||
and link the application against the "`qrf.c`" source file.
|
||||
+2496
File diff suppressed because it is too large
Load Diff
+184
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
** 2025-10-20
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
*************************************************************************
|
||||
** Header file for the Result-Format or "resfmt" utility library for SQLite.
|
||||
** See the resfmt.md documentation for additional information.
|
||||
*/
|
||||
#ifndef SQLITE_QRF_H
|
||||
#define SQLITE_QRF_H
|
||||
#include <stdlib.h>
|
||||
#include "sqlite3.h"
|
||||
|
||||
/*
|
||||
** Specification used by clients to define the output format they want
|
||||
*/
|
||||
typedef struct sqlite3_qrf_spec sqlite3_qrf_spec;
|
||||
struct sqlite3_qrf_spec {
|
||||
unsigned char iVersion; /* Version number of this structure */
|
||||
unsigned char eStyle; /* Formatting style. "box", "csv", etc... */
|
||||
unsigned char eEsc; /* How to escape control characters in text */
|
||||
unsigned char eText; /* Quoting style for text */
|
||||
unsigned char eTitle; /* Quating style for the text of column names */
|
||||
unsigned char eBlob; /* Quoting style for BLOBs */
|
||||
unsigned char bTitles; /* True to show column names */
|
||||
unsigned char bWordWrap; /* Try to wrap on word boundaries */
|
||||
unsigned char bTextJsonb; /* Render JSONB blobs as JSON text */
|
||||
unsigned char bTextNull; /* Apply eText encoding to zNull[] */
|
||||
unsigned char eDfltAlign; /* Default alignment, no covered by aAlignment */
|
||||
unsigned char eTitleAlign; /* Alignment for column headers */
|
||||
short int nWrap; /* Wrap columns wider than this */
|
||||
short int nScreenWidth; /* Maximum overall table width */
|
||||
short int nLineLimit; /* Maximum number of lines for any row */
|
||||
int nCharLimit; /* Maximum number of characters in a cell */
|
||||
int nWidth; /* Number of entries in aWidth[] */
|
||||
int nAlign; /* Number of entries in aAlignment[] */
|
||||
short int *aWidth; /* Column widths */
|
||||
unsigned char *aAlign; /* Column alignments */
|
||||
char *zColumnSep; /* Alternative column separator */
|
||||
char *zRowSep; /* Alternative row separator */
|
||||
char *zTableName; /* Output table name */
|
||||
char *zNull; /* Rendering of NULL */
|
||||
char *(*xRender)(void*,sqlite3_value*); /* Render a value */
|
||||
int (*xWrite)(void*,const char*,sqlite3_int64); /* Write output */
|
||||
void *pRenderArg; /* First argument to the xRender callback */
|
||||
void *pWriteArg; /* First argument to the xWrite callback */
|
||||
char **pzOutput; /* Storage location for output string */
|
||||
/* Additional fields may be added in the future */
|
||||
};
|
||||
|
||||
/*
|
||||
** Interfaces
|
||||
*/
|
||||
int sqlite3_format_query_result(
|
||||
sqlite3_stmt *pStmt, /* SQL statement to run */
|
||||
const sqlite3_qrf_spec *pSpec, /* Result format specification */
|
||||
char **pzErr /* OUT: Write error message here */
|
||||
);
|
||||
|
||||
/*
|
||||
** Range of values for sqlite3_qrf_spec.aWidth[] entries and for
|
||||
** sqlite3_qrf_spec.mxColWidth and .nScreenWidth
|
||||
*/
|
||||
#define QRF_MAX_WIDTH 10000
|
||||
#define QRF_MIN_WIDTH 0
|
||||
|
||||
/*
|
||||
** Output styles:
|
||||
*/
|
||||
#define QRF_STYLE_Auto 0 /* Choose a style automatically */
|
||||
#define QRF_STYLE_Box 1 /* Unicode box-drawing characters */
|
||||
#define QRF_STYLE_Column 2 /* One record per line in neat columns */
|
||||
#define QRF_STYLE_Count 3 /* Output only a count of the rows of output */
|
||||
#define QRF_STYLE_Csv 4 /* Comma-separated-value */
|
||||
#define QRF_STYLE_Eqp 5 /* Format EXPLAIN QUERY PLAN output */
|
||||
#define QRF_STYLE_Explain 6 /* EXPLAIN output */
|
||||
#define QRF_STYLE_Html 7 /* Generate an XHTML table */
|
||||
#define QRF_STYLE_Insert 8 /* Generate SQL "insert" statements */
|
||||
#define QRF_STYLE_Json 9 /* Output is a list of JSON objects */
|
||||
#define QRF_STYLE_JObject 10 /* Independent JSON objects for each row */
|
||||
#define QRF_STYLE_Line 11 /* One column per line. */
|
||||
#define QRF_STYLE_List 12 /* One record per line with a separator */
|
||||
#define QRF_STYLE_Markdown 13 /* Markdown formatting */
|
||||
#define QRF_STYLE_Off 14 /* No query output shown */
|
||||
#define QRF_STYLE_Quote 15 /* SQL-quoted, comma-separated */
|
||||
#define QRF_STYLE_Stats 16 /* EQP-like output but with performance stats */
|
||||
#define QRF_STYLE_StatsEst 17 /* EQP-like output with planner estimates */
|
||||
#define QRF_STYLE_StatsVm 18 /* EXPLAIN-like output with performance stats */
|
||||
#define QRF_STYLE_Table 19 /* MySQL-style table formatting */
|
||||
|
||||
/*
|
||||
** Quoting styles for text.
|
||||
** Allowed values for sqlite3_qrf_spec.eText
|
||||
*/
|
||||
#define QRF_TEXT_Auto 0 /* Choose text encoding automatically */
|
||||
#define QRF_TEXT_Plain 1 /* Literal text */
|
||||
#define QRF_TEXT_Sql 2 /* Quote as an SQL literal */
|
||||
#define QRF_TEXT_Csv 3 /* CSV-style quoting */
|
||||
#define QRF_TEXT_Html 4 /* HTML-style quoting */
|
||||
#define QRF_TEXT_Tcl 5 /* C/Tcl quoting */
|
||||
#define QRF_TEXT_Json 6 /* JSON quoting */
|
||||
|
||||
/*
|
||||
** Quoting styles for BLOBs
|
||||
** Allowed values for sqlite3_qrf_spec.eBlob
|
||||
*/
|
||||
#define QRF_BLOB_Auto 0 /* Determine BLOB quoting using eText */
|
||||
#define QRF_BLOB_Text 1 /* Display content exactly as it is */
|
||||
#define QRF_BLOB_Sql 2 /* Quote as an SQL literal */
|
||||
#define QRF_BLOB_Hex 3 /* Hexadecimal representation */
|
||||
#define QRF_BLOB_Tcl 4 /* "\000" notation */
|
||||
#define QRF_BLOB_Json 5 /* A JSON string */
|
||||
|
||||
/*
|
||||
** Control-character escape modes.
|
||||
** Allowed values for sqlite3_qrf_spec.eEsc
|
||||
*/
|
||||
#define QRF_ESC_Auto 0 /* Choose the ctrl-char escape automatically */
|
||||
#define QRF_ESC_Off 1 /* Do not escape control characters */
|
||||
#define QRF_ESC_Ascii 2 /* Unix-style escapes. Ex: U+0007 shows ^G */
|
||||
#define QRF_ESC_Symbol 3 /* Unicode escapes. Ex: U+0007 shows U+2407 */
|
||||
|
||||
/*
|
||||
** Allowed values for "boolean" fields, such as "bColumnNames", "bWordWrap",
|
||||
** and "bTextJsonb". There is an extra "auto" variants so these are actually
|
||||
** tri-state settings, not booleans.
|
||||
*/
|
||||
#define QRF_SW_Auto 0 /* Let QRF choose the best value */
|
||||
#define QRF_SW_Off 1 /* This setting is forced off */
|
||||
#define QRF_SW_On 2 /* This setting is forced on */
|
||||
#define QRF_Auto 0 /* Alternate spelling for QRF_*_Auto */
|
||||
#define QRF_No 1 /* Alternate spelling for QRF_SW_Off */
|
||||
#define QRF_Yes 2 /* Alternate spelling for QRF_SW_On */
|
||||
|
||||
/*
|
||||
** Possible alignment values alignment settings
|
||||
**
|
||||
** Horizontal Vertial
|
||||
** ---------- -------- */
|
||||
#define QRF_ALIGN_Auto 0 /* auto auto */
|
||||
#define QRF_ALIGN_Left 1 /* left auto */
|
||||
#define QRF_ALIGN_Center 2 /* center auto */
|
||||
#define QRF_ALIGN_Right 3 /* right auto */
|
||||
#define QRF_ALIGN_Top 4 /* auto top */
|
||||
#define QRF_ALIGN_NW 5 /* left top */
|
||||
#define QRF_ALIGN_N 6 /* center top */
|
||||
#define QRF_ALIGN_NE 7 /* right top */
|
||||
#define QRF_ALIGN_Middle 8 /* auto middle */
|
||||
#define QRF_ALIGN_W 9 /* left middle */
|
||||
#define QRF_ALIGN_C 10 /* center middle */
|
||||
#define QRF_ALIGN_E 11 /* right middle */
|
||||
#define QRF_ALIGN_Bottom 12 /* auto bottom */
|
||||
#define QRF_ALIGN_SW 13 /* left bottom */
|
||||
#define QRF_ALIGN_S 14 /* center bottom */
|
||||
#define QRF_ALIGN_SE 15 /* right bottom */
|
||||
#define QRF_ALIGN_HMASK 3 /* Horizontal alignment mask */
|
||||
#define QRF_ALIGN_VMASK 12 /* Vertical alignment mask */
|
||||
|
||||
/*
|
||||
** Auxiliary routines contined within this module that might be useful
|
||||
** in other contexts, and which are therefore exported.
|
||||
*/
|
||||
/*
|
||||
** Return an estimate of the width, in columns, for the single Unicode
|
||||
** character c. For normal characters, the answer is always 1. But the
|
||||
** estimate might be 0 or 2 for zero-width and double-width characters.
|
||||
**
|
||||
** Different display devices display unicode using different widths. So
|
||||
** it is impossible to know that true display width with 100% accuracy.
|
||||
** Inaccuracies in the width estimates might cause columns to be misaligned.
|
||||
** Unfortunately, there is nothing we can do about that.
|
||||
*/
|
||||
int sqlite3_qrf_wcwidth(int c);
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* !defined(SQLITE_QRF_H) */
|
||||
+25
-45
@@ -219,8 +219,9 @@ b.cp = $(call b.mkdir@); \
|
||||
# $4 = optional $(bin.c-pp) flags
|
||||
define b.c-pp.shcmd
|
||||
$(call b.mkdir@); \
|
||||
$(call b.echo,$(1),$(emo.disk)$(emo.lock)[$(3)] $(4)); \
|
||||
rm -f $(3); $(bin.c-pp) -o $(3) $(4) $(2) || exit; \
|
||||
$(call b.echo,$(1),$(emo.disk)$(emo.lock) $(bin.c-pp) $(4) $(if $(loud.if),$(2))); \
|
||||
rm -f $(3); \
|
||||
$(bin.c-pp) -o $(3) $(4) $(2) || exit; \
|
||||
chmod -w $(3)
|
||||
endef
|
||||
|
||||
@@ -232,8 +233,7 @@ endef
|
||||
# Args: as for $(b.c-pp.shcmd).
|
||||
define b.c-pp.target
|
||||
$(3): $$(MAKEFILE_LIST) $$(bin.c-pp) $(2)
|
||||
@$$(call b.mkdir@)
|
||||
@$$(call b.c-pp.shcmd,$(1),$(2),$(3),$(4) $$(b.c-pp.target.flags))
|
||||
@$$(call b.c-pp.shcmd,$(1),$(2),$(3),$(4) $(b.c-pp.target.flags))
|
||||
CLEAN_FILES += $(3)
|
||||
endef
|
||||
|
||||
@@ -260,7 +260,7 @@ endef
|
||||
#
|
||||
# To repeat: all node.js builds are 100% untested and unsupported.
|
||||
#
|
||||
# Most c-pp.D.X are set via $(bin.mkwb) and X is a build name.
|
||||
# Most c-pp.D.X are set via $(bin.mkwasmbuilds) and X is a build name.
|
||||
# Those make rules reference c-pp.D.64bit, so it should be defined in
|
||||
# advance.
|
||||
#
|
||||
@@ -282,20 +282,9 @@ c-pp.D.64bit = -Dbits64
|
||||
# This is intended to be used in makefile targets which generate an
|
||||
# Emscripten module and where $@ is the module's .js/.mjs file.
|
||||
#
|
||||
# This is inherently fragile and has been broken by Emscripten updates
|
||||
# before.
|
||||
#
|
||||
ifeq (1,1)
|
||||
define b.strip-js-emcc-bindings
|
||||
echo "$(1) $(emo.garbage) Stripping export wrappers."; \
|
||||
sed -i -e '/var _sqlite3.*makeInvalidEarly.*;/d' \
|
||||
-e '/assert.*sqlite3.*missing.*;/d' \
|
||||
-e '/_sqlite.*createExportWrapper.*;/d' $@
|
||||
endef
|
||||
else
|
||||
b.strip-js-emcc-bindings = \
|
||||
echo '$(1) $(emo.bug) (disabled because it breaks emsdk 4.0.16+)'
|
||||
endif
|
||||
|
||||
|
||||
#
|
||||
# Set up sqlite3.c and sqlite3.h...
|
||||
@@ -861,8 +850,9 @@ endef
|
||||
#
|
||||
sqlite3-license-version.js = $(dir.tmp)/sqlite3-license-version.js
|
||||
$(sqlite3-license-version.js): $(bin.version-info) \
|
||||
$(dir.api)/sqlite3-license-version-header.js $(MAKEFILE)
|
||||
@$(call b.mkdir@); echo '$(logtag.@) $(emo.disk)'; { \
|
||||
$(dir.api)/sqlite3-license-version-header.js
|
||||
@echo '$(logtag.@) $(emo.disk)'; \
|
||||
$(call b.mkdir@); { \
|
||||
cat $(dir.api)/sqlite3-license-version-header.js || exit $$?; \
|
||||
echo '/*'; \
|
||||
echo '** This code was built from sqlite3 version...'; \
|
||||
@@ -870,7 +860,7 @@ $(sqlite3-license-version.js): $(bin.version-info) \
|
||||
awk '/define SQLITE_VERSION/{$$1=""; print "**" $$0}' $(sqlite3.h); \
|
||||
awk '/define SQLITE_SOURCE_ID/{$$1=""; print "**" $$0}' $(sqlite3.h); \
|
||||
echo '**'; echo '** Emscripten SDK: $(emcc.version)'; \
|
||||
echo '**'; echo '** Preprocessed by:'; echo '** @c-pp::ARGV@'; \
|
||||
echo '**'; \
|
||||
echo '*/'; \
|
||||
} > $@
|
||||
|
||||
@@ -896,10 +886,10 @@ $(sqlite3-api-build-version.js): $(bin.version-info) $(MAKEFILE)
|
||||
# sqlite3-api.js, in the order they need to be assembled.
|
||||
sqlite3-api.jses = $(sqlite3-license-version.js)
|
||||
sqlite3-api.jses += $(dir.api)/sqlite3-api-prologue.js
|
||||
sqlite3-api.jses += $(sqlite3-api-build-version.js)
|
||||
sqlite3-api.jses += $(dir.common)/whwasmutil.js
|
||||
sqlite3-api.jses += $(dir.jacc)/jaccwabyt.js
|
||||
sqlite3-api.jses += $(dir.api)/sqlite3-api-glue.c-pp.js
|
||||
sqlite3-api.jses += $(sqlite3-api-build-version.js)
|
||||
sqlite3-api.jses += $(dir.api)/sqlite3-api-oo1.c-pp.js
|
||||
sqlite3-api.jses += $(dir.api)/sqlite3-api-worker1.c-pp.js
|
||||
sqlite3-api.jses += $(dir.api)/sqlite3-vfs-helper.c-pp.js
|
||||
@@ -908,13 +898,7 @@ ifeq (0,$(wasm-bare-bones))
|
||||
endif
|
||||
sqlite3-api.jses += $(dir.api)/sqlite3-vfs-opfs.c-pp.js
|
||||
sqlite3-api.jses += $(dir.api)/sqlite3-vfs-opfs-sahpool.c-pp.js
|
||||
|
||||
# Parallel builds can fail if $(sqlite3-license-version.js) is not
|
||||
# created early enough, so make all files in $(sqlite-api.jses) except
|
||||
# for $(sqlite3-license-version.js) depend on
|
||||
# $(sqlite3-license-version.js).
|
||||
deps.jses = $(filter-out $(sqlite3-license-version.js),$(sqlite3-api.jses))
|
||||
$(deps.jses): $(sqlite3-license-version.js)
|
||||
sqlite3-api.jses += $(dir.api)/sqlite3-api-cleanup.js
|
||||
|
||||
#
|
||||
# extern-post-js* and extern-pre-js* are files for use with
|
||||
@@ -953,7 +937,7 @@ $(post-js.in.js): $(MKDIR.bld) $(post-jses.js) $(MAKEFILE)
|
||||
done > $@
|
||||
|
||||
#
|
||||
# speedtest1 decls needed before the $(bin.mkwb)-generated makefile
|
||||
# speedtest1 decls needed before the $(bin.mkws)-generated makefile
|
||||
# is included.
|
||||
#
|
||||
bin.speedtest1 = ../../speedtest1
|
||||
@@ -994,7 +978,7 @@ endif
|
||||
|
||||
EXPORTED_FUNCTIONS.fiddle = $(dir.tmp)/EXPORTED_FUNCTIONS.fiddle
|
||||
$(EXPORTED_FUNCTIONS.fiddle): $(EXPORTED_FUNCTIONS.api.in) $(MAKEFILE_LIST)
|
||||
@$(call b.mkdir@)
|
||||
@$(b.mkdir@)
|
||||
@$(call b.c-pp.shcmd,filter,$(EXPORTED_FUNCTIONS.api.in),\
|
||||
$@,$(EXPORTED_FUNCTIONS.c-pp.flags) -Dfiddle)
|
||||
@echo $(logtag.@) $(emo.disk)
|
||||
@@ -1122,10 +1106,10 @@ sqlite3.ext.js =
|
||||
define gen-worker1
|
||||
# $1 = X.ext part of sqlite3-worker1X.ext
|
||||
# $2 = $(c-pp.D.NAME)
|
||||
$(call b.c-pp.target,filter,$$(dir.api)/sqlite3-worker1.c-pp.js,\
|
||||
$$(dir.dout)/sqlite3-worker1$(1),$(2))
|
||||
sqlite3.ext.js += $$(dir.dout)/sqlite3-worker1$(1)
|
||||
all: $$(dir.dout)/sqlite3-worker1$(1)
|
||||
$(call b.c-pp.target,filter,$(dir.api)/sqlite3-worker1.c-pp.js,\
|
||||
$(dir.dout)/sqlite3-worker1$(1),$(2))
|
||||
sqlite3.ext.js += $(dir.dout)/sqlite3-worker1$(1)
|
||||
all: $(dir.dout)/sqlite3-worker1$(1)
|
||||
endef
|
||||
|
||||
$(eval $(call gen-worker1,.js,$(c-pp.D.vanilla)))
|
||||
@@ -1139,10 +1123,10 @@ $(eval $(call gen-worker1,-bundler-friendly.mjs,$(c-pp.D.bundler)))
|
||||
define gen-promiser
|
||||
# $1 = X.ext part of sqlite3-worker1-promiserX.ext
|
||||
# $2 = $(c-pp.D.NAME)
|
||||
$(call b.c-pp.target,filter,$$(dir.api)/sqlite3-worker1-promiser.c-pp.js,\
|
||||
$$(dir.dout)/sqlite3-worker1-promiser$(1),$(2))
|
||||
sqlite3.ext.js += $$(dir.dout)/sqlite3-worker1-promiser$(1)
|
||||
all: $$(dir.dout)/sqlite3-worker1-promiser$(1)
|
||||
$(call b.c-pp.target,filter,$(dir.api)/sqlite3-worker1-promiser.c-pp.js,\
|
||||
$(dir.dout)/sqlite3-worker1-promiser$(1),$(2))
|
||||
sqlite3.ext.js += $(dir.dout)/sqlite3-worker1-promiser$(1)
|
||||
all: $(dir.dout)/sqlite3-worker1-promiser$(1)
|
||||
endef
|
||||
|
||||
$(eval $(call gen-promiser,.js,$(c-pp.D.vanilla)))
|
||||
@@ -1184,19 +1168,14 @@ $(dir.dout)/sqlite3-opfs-async-proxy.js: $(dir.api)/sqlite3-opfs-async-proxy.js
|
||||
# we don't otherwise have a great place to attach them such that
|
||||
# they're always copied when we need them.
|
||||
#
|
||||
# The var $(out.$(B).js) comes from $(bin.mkwb) and $(B) is the name
|
||||
# of a build set up by that tool, e.g. b-vanilla or b-esm64.
|
||||
# The var $(out.$(B).js) comes from $(bin.mkwasmbuilds).
|
||||
#
|
||||
$(foreach B,$(b.names),$(eval $(out.$(B).js): $(sqlite3.ext.js)))
|
||||
|
||||
#
|
||||
# b-all: builds all available js/wasm builds.
|
||||
#
|
||||
$(foreach B,$(b.names),$(eval b-all: $(out.$(B).js)))
|
||||
|
||||
#$(foreach B,$(b.names),$(eval pre: $(pre-js.$(B).js)))
|
||||
$(foreach B,$(b.names),$(eval post: $(post-js.$(B).js)))
|
||||
|
||||
#
|
||||
# speedtest1 is our primary benchmarking tool.
|
||||
#
|
||||
@@ -1246,7 +1225,8 @@ speedtest1.exit-runtime1 = -sEXIT_RUNTIME=1
|
||||
# which runs speedtest1 multiple times.
|
||||
|
||||
$(EXPORTED_FUNCTIONS.speedtest1): $(EXPORTED_FUNCTIONS.api)
|
||||
@$(call b.mkdir@); $(call b.echo,@,$(emo.disk)); \
|
||||
@$(call b.echo,@,$(emo.disk)); \
|
||||
$(call b.mkdir@); \
|
||||
{ echo _wasm_main; cat $(EXPORTED_FUNCTIONS.api); } > $@ || exit
|
||||
speedtest1: b-speedtest1
|
||||
|
||||
|
||||
+36
-39
@@ -60,14 +60,14 @@ maintenance point of view.
|
||||
At the center of the onion is `sqlite3-api.js`, which gets generated
|
||||
by concatenating the following files together in their listed order:
|
||||
|
||||
- **`sqlite3-api-prologue.js`**
|
||||
- **`sqlite3-api-prologue.js`**\
|
||||
Contains the initial bootstrap setup of the sqlite3 API
|
||||
objects. This is exposed as a function, rather than objects, so that
|
||||
the next step can pass in a config object which abstracts away parts
|
||||
of the WASM environment, to facilitate plugging it in to arbitrary
|
||||
WASM toolchains. The bootstrapping function gets removed from the
|
||||
global scope in a later stage of the bootstrapping process.
|
||||
- **`../common/whwasmutil.js`**
|
||||
- **`../common/whwasmutil.js`**\
|
||||
A semi-third-party collection of JS/WASM utility code intended to
|
||||
replace much of the Emscripten glue. The sqlite3 APIs internally use
|
||||
these APIs instead of their Emscripten counterparts, in order to be
|
||||
@@ -77,78 +77,79 @@ by concatenating the following files together in their listed order:
|
||||
toolchains. It is "semi-third-party" in that it was created in order
|
||||
to support this tree but is standalone and maintained together
|
||||
with...
|
||||
- **`../jaccwabyt/jaccwabyt.js`**
|
||||
- **`../jaccwabyt/jaccwabyt.js`**\
|
||||
Another semi-third-party API which creates bindings between JS
|
||||
and C structs, such that changes to the struct state from either JS
|
||||
or C are visible to the other end of the connection. This is also an
|
||||
independent spinoff project, conceived for the sqlite3 project but
|
||||
maintained separately.
|
||||
- **`sqlite3-api-glue.js`**
|
||||
- **`sqlite3-api-glue.js`**\
|
||||
Invokes functionality exposed by the previous two files to flesh out
|
||||
low-level parts of `sqlite3-api-prologue.js`. Most of these pieces
|
||||
involve populating the `sqlite3.capi.wasm` object and creating
|
||||
`sqlite3.capi.sqlite3_...()` bindings. This file also deletes most
|
||||
global-scope symbols the above files create, effectively moving them
|
||||
into the scope being used for initializing the API.
|
||||
- **`<build>/sqlite3-api-build-version.js`**
|
||||
- **`<build>/sqlite3-api-build-version.js`**\
|
||||
Gets created by the build process and populates the
|
||||
`sqlite3.version` object. This part is not critical, but records the
|
||||
version of the library against which this module was built.
|
||||
- **`sqlite3-api-oo1.js`**
|
||||
- **`sqlite3-api-oo1.js`**\
|
||||
Provides a high-level object-oriented wrapper to the lower-level C
|
||||
API, colloquially known as OO API #1. Its API is similar to other
|
||||
high-level sqlite3 JS wrappers and should feel relatively familiar
|
||||
to anyone familiar with such APIs. It is not a "required component"
|
||||
and can be elided from builds which do not want it.
|
||||
- **`sqlite3-api-worker1.js`**
|
||||
- **`sqlite3-api-worker1.js`**\
|
||||
A Worker-thread-based API which uses OO API #1 to provide an
|
||||
interface to a database which can be driven from the main Window
|
||||
thread via the Worker message-passing interface. Like OO API #1,
|
||||
this is an optional component, offering one of any number of
|
||||
potential implementations for such an API.
|
||||
- **`sqlite3-worker1.js`**
|
||||
- **`sqlite3-worker1.js`**\
|
||||
Is not part of the amalgamated sources and is intended to be
|
||||
loaded by a client Worker thread. It loads the sqlite3 module
|
||||
and runs the Worker #1 API which is implemented in
|
||||
`sqlite3-api-worker1.js`.
|
||||
- **`sqlite3-worker1-promiser.js`**
|
||||
- **`sqlite3-worker1-promiser.js`**\
|
||||
Is likewise not part of the amalgamated sources and provides
|
||||
a Promise-based interface into the Worker #1 API. This is
|
||||
a far user-friendlier way to interface with databases running
|
||||
in a Worker thread.
|
||||
- **`sqlite3-vfs-helper.js`**
|
||||
- **`sqlite3-vfs-helper.js`**\
|
||||
Installs the `sqlite3.vfs` namespace, which contain helpers for use
|
||||
by downstream code which creates `sqlite3_vfs` implementations.
|
||||
- **`sqlite3-vtab-helper.js`**
|
||||
- **`sqlite3-vtab-helper.js`**\
|
||||
Installs the `sqlite3.vtab` namespace, which contain helpers for use
|
||||
by downstream code which creates `sqlite3_module` implementations.
|
||||
- **`sqlite3-vfs-opfs.c-pp.js`**
|
||||
- **`sqlite3-vfs-opfs.c-pp.js`**\
|
||||
is an sqlite3 VFS implementation which supports the [Origin-Private
|
||||
FileSystem (OPFS)][OPFS] as a storage layer to provide persistent
|
||||
storage for database files in a browser. It requires...
|
||||
- **`sqlite3-opfs-async-proxy.js`**
|
||||
- **`sqlite3-opfs-async-proxy.js`**\
|
||||
is the asynchronous backend part of the [OPFS][] proxy. It
|
||||
speaks directly to the (async) OPFS API and channels those
|
||||
results back to its synchronous counterpart. This file, because
|
||||
it must be started in its own Worker, is not part of the
|
||||
amalgamation.
|
||||
- **`sqlite3-vfs-opfs-sahpool.c-pp.js`**
|
||||
- **`sqlite3-vfs-opfs-sahpool.c-pp.js`**\
|
||||
is another sqlite3 VFS supporting the [OPFS][], but uses a
|
||||
completely different approach than the above-listed one.
|
||||
- **`sqlite3-api-cleanup.js`**\
|
||||
The previous files do not immediately extend the library. Instead
|
||||
they add callback functions to be called during its
|
||||
bootstrapping. Some also temporarily create global objects in order
|
||||
to communicate their state to the files which follow them. This file
|
||||
cleans up any dangling globals and runs the API bootstrapping
|
||||
process, which is what finally executes the initialization code
|
||||
installed by the previous files. As of this writing, this code
|
||||
ensures that the previous files leave no more than a single global
|
||||
symbol installed - `sqlite3InitModule()`. When adapting the API for
|
||||
non-Emscripten toolchains, this "should" be the only file, of those
|
||||
in this list, where changes are needed. The Emscripten-specific
|
||||
pieces described below may also require counterparts in any as-yet
|
||||
hypothetical alternative build.
|
||||
|
||||
The previous files do not immediately extend the library. Instead they
|
||||
install a global function `sqlite3ApiBootstrap()`, which downstream
|
||||
code must call to configure the library for the current JS/WASM
|
||||
environment. Each file listed above pushes a callback into the
|
||||
bootstrapping queue, to be called as part of `sqlite3ApiBootstrap()`.
|
||||
Some files also temporarily create global objects in order to
|
||||
communicate their state to the files which follow them. Those
|
||||
get cleaned up vi `post-js-footer.js`, described below.
|
||||
|
||||
Adapting the build for non-Emscripten toolchains essentially requires packaging
|
||||
the above files, concatated together, into that toolchain's "JS glue"
|
||||
and, in the final stage of that glue, call `sqlite3ApiBootstrap()` and
|
||||
return its result to the end user.
|
||||
|
||||
**Files with the extension `.c-pp.js`** are intended [to be processed
|
||||
with `c-pp`](#c-pp), noting that such preprocessing may be applied
|
||||
@@ -170,27 +171,23 @@ from this file rather than `sqlite3.c`.
|
||||
The following Emscripten-specific files are injected into the
|
||||
build-generated `sqlite3.js` along with `sqlite3-api.js`.
|
||||
|
||||
- **`extern-pre-js.js`**
|
||||
- **`extern-pre-js.js`**\
|
||||
Emscripten-specific header for Emscripten's `--extern-pre-js`
|
||||
flag. As of this writing, that file is only used for experimentation
|
||||
purposes and holds no code relevant to the production deliverables.
|
||||
- **`pre-js.c-pp.js`**
|
||||
- **`pre-js.c-pp.js`**\
|
||||
Emscripten-specific header for Emscripten's `--pre-js` flag. This
|
||||
file overrides certain Emscripten behavior before Emscripten does
|
||||
most of its work.
|
||||
- **`post-js-header.js`**
|
||||
- **`post-js-header.js`**\
|
||||
Emscripten-specific header for the `--post-js` input. It opens up,
|
||||
but does not close, a function used for initializing the library.
|
||||
- **`sqlite3-api.js`** gets sandwiched between these ↑ two
|
||||
↓ files.
|
||||
- **`post-js-footer.js`**
|
||||
- (**`sqlite3-api.js`** gets sandwiched between these ↑ two
|
||||
↓ files.)
|
||||
- **`post-js-footer.js`**\
|
||||
Emscripten-specific footer for the `--post-js` input. This closes
|
||||
off the function opened by `post-js-header.js`. This file cleans up
|
||||
any dangling globals and runs `sqlite3ApiBootstrap()`. As of this
|
||||
writing, this code ensures that the previous files leave no more
|
||||
than a single global symbol installed - `sqlite3InitModule()`.
|
||||
|
||||
- **`extern-post-js.c-pp.js`**
|
||||
off the function opened by `post-js-header.js`.
|
||||
- **`extern-post-js.c-pp.js`**\
|
||||
Emscripten-specific header for Emscripten's `--extern-post-js`
|
||||
flag. This file is run in the global scope. It overwrites the
|
||||
Emscripten-installed `sqlite3InitModule()` function with one which
|
||||
|
||||
@@ -1,72 +1,3 @@
|
||||
/*
|
||||
2022-07-22
|
||||
|
||||
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.
|
||||
|
||||
***********************************************************************
|
||||
|
||||
This file is the tail end of the sqlite3-api.js constellation,
|
||||
closing the function scope opened by post-js-header.js.
|
||||
|
||||
In terms of amalgamation code placement, this file is appended
|
||||
immediately after the final sqlite3-api-*.js piece. Those files
|
||||
cooperate to prepare sqlite3ApiBootstrap() and this file calls it.
|
||||
It is run within a context which gives it access to Emscripten's
|
||||
Module object, after sqlite3.wasm is loaded but before
|
||||
sqlite3ApiBootstrap() has been called.
|
||||
|
||||
Because this code resides (after building) inside the function
|
||||
installed by post-js-header.js, it has access to state set up by
|
||||
pre-js.c-pp.js and friends.
|
||||
*/
|
||||
try{
|
||||
/* We are in the closing block of Module.runSQLite3PostLoadInit(), so
|
||||
its arguments are visible here. */
|
||||
|
||||
/* Config options for sqlite3ApiBootstrap(). */
|
||||
const bootstrapConfig = Object.assign(
|
||||
Object.create(null),
|
||||
/** The WASM-environment-dependent configuration for sqlite3ApiBootstrap() */
|
||||
{
|
||||
memory: ('undefined'!==typeof wasmMemory)
|
||||
? wasmMemory
|
||||
: EmscriptenModule['wasmMemory'],
|
||||
exports: ('undefined'!==typeof wasmExports)
|
||||
? wasmExports /* emscripten >=3.1.44 */
|
||||
: (Object.prototype.hasOwnProperty.call(EmscriptenModule,'wasmExports')
|
||||
? EmscriptenModule['wasmExports']
|
||||
: EmscriptenModule['asm']/* emscripten <=3.1.43 */)
|
||||
},
|
||||
globalThis.sqlite3ApiBootstrap.defaultConfig, // default options
|
||||
globalThis.sqlite3ApiConfig || {} // optional client-provided options
|
||||
);
|
||||
|
||||
sqlite3InitScriptInfo.debugModule("Bootstrapping lib config", bootstrapConfig);
|
||||
|
||||
/**
|
||||
For purposes of the Emscripten build, call sqlite3ApiBootstrap().
|
||||
Ideally clients should be able to inject their own config here,
|
||||
but that's not practical in this particular build constellation
|
||||
because of the order everything happens in. Clients may either
|
||||
define globalThis.sqlite3ApiConfig or modify
|
||||
globalThis.sqlite3ApiBootstrap.defaultConfig to tweak the default
|
||||
configuration used by a no-args call to sqlite3ApiBootstrap(),
|
||||
but must have first loaded their WASM module in order to be able
|
||||
to provide the necessary configuration state.
|
||||
*/
|
||||
const p = globalThis.sqlite3ApiBootstrap(bootstrapConfig);
|
||||
delete globalThis.sqlite3ApiBootstrap;
|
||||
return p /* the eventual result of globalThis.sqlite3InitModule() */;
|
||||
}catch(e){
|
||||
console.error("sqlite3ApiBootstrap() error:",e);
|
||||
throw e;
|
||||
}
|
||||
|
||||
//console.warn("This is the end of the Module.runSQLite3PostLoadInit handler.");
|
||||
}/*Module.runSQLite3PostLoadInit(...)*/;
|
||||
//console.warn("This is the end of the setup of the (pending) Module.runSQLite3PostLoadInit");
|
||||
|
||||
@@ -3,13 +3,14 @@
|
||||
post-js.js for use with Emscripten's --post-js flag, so it gets
|
||||
injected in the earliest stages of sqlite3InitModule().
|
||||
|
||||
This function wraps the whole SQLite3 library but does not
|
||||
bootstrap it.
|
||||
|
||||
Running this function will bootstrap the library and return
|
||||
a Promise to the sqlite3 namespace object.
|
||||
|
||||
In the canonical builds, this gets called by extern-post-js.c-pp.js
|
||||
*/
|
||||
Module.runSQLite3PostLoadInit = async function(
|
||||
sqlite3InitScriptInfo,
|
||||
Module.runSQLite3PostLoadInit = function(
|
||||
sqlite3InitScriptInfo /* populated by extern-post-js.c-pp.js */,
|
||||
EmscriptenModule/*the Emscripten-style module object*/,
|
||||
sqlite3IsUnderTest
|
||||
){
|
||||
@@ -34,6 +35,7 @@ Module.runSQLite3PostLoadInit = async function(
|
||||
- sqlite3-vtab-helper.c-pp.js => Utilities for virtual table impls
|
||||
- sqlite3-vfs-opfs.c-pp.js => OPFS VFS
|
||||
- sqlite3-vfs-opfs-sahpool.c-pp.js => OPFS SAHPool VFS
|
||||
- sqlite3-api-cleanup.js => final bootstrapping phase
|
||||
- post-js-footer.js => this file's epilogue
|
||||
|
||||
And all of that gets sandwiched between extern-pre-js.js and
|
||||
|
||||
@@ -35,12 +35,8 @@
|
||||
const sIMS =
|
||||
globalThis.sqlite3InitModuleState/*from extern-post-js.c-pp.js*/
|
||||
|| Object.assign(Object.create(null),{
|
||||
/* In WASMFS builds this file gets loaded once per thread,
|
||||
but sqlite3InitModuleState is not getting set for the
|
||||
worker threads? That those workers seem to function fine
|
||||
despite that is curious. */
|
||||
debugModule: function(){
|
||||
console.warn("globalThis.sqlite3InitModuleState is missing",arguments);
|
||||
debugModule: ()=>{
|
||||
console.warn("globalThis.sqlite3InitModuleState is missing");
|
||||
}
|
||||
});
|
||||
delete globalThis.sqlite3InitModuleState;
|
||||
@@ -93,7 +89,8 @@
|
||||
//#endif target:es6-module
|
||||
}.bind(sIMS);
|
||||
|
||||
//#if Module.instantiateWasm and not wasmfs
|
||||
//#if Module.instantiateWasm
|
||||
//#if not wasmfs
|
||||
/**
|
||||
Override Module.instantiateWasm().
|
||||
|
||||
@@ -129,6 +126,7 @@
|
||||
.then(finalThen)
|
||||
return loadWasm();
|
||||
}.bind(sIMS);
|
||||
//#endif Module.instantiateWasm and not wasmfs
|
||||
//#endif not wasmfs
|
||||
//#endif Module.instantiateWasm
|
||||
})(Module);
|
||||
/* END FILE: api/pre-js.js. */
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
2022-07-22
|
||||
|
||||
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.
|
||||
|
||||
***********************************************************************
|
||||
|
||||
This file is the tail end of the sqlite3-api.js constellation,
|
||||
intended to be appended after all other sqlite3-api-*.js files so
|
||||
that it can finalize any setup and clean up any global symbols
|
||||
temporarily used for setting up the API's various subsystems.
|
||||
|
||||
In Emscripten builds it's run in the context of what amounts to a
|
||||
Module.postRun handler, though it's no longer actually a postRun
|
||||
handler because Emscripten 4.0 changed postRun semantics in an
|
||||
incompatible way.
|
||||
|
||||
In terms of amalgamation code placement, this file is appended
|
||||
immediately after the final sqlite3-api-*.js piece. Those files
|
||||
cooperate to prepare sqlite3ApiBootstrap() and this file calls it.
|
||||
It is run within a context which gives it access to Emscripten's
|
||||
Module object, after sqlite3.wasm is loaded but before
|
||||
sqlite3ApiBootstrap() has been called.
|
||||
|
||||
Because this code resides (after building) inside the function
|
||||
installed by post-js-header.js, it has access to state set up by
|
||||
pre-js.c-pp.js and friends.
|
||||
*/
|
||||
'use strict';
|
||||
if( 'undefined' !== typeof EmscriptenModule/*from post-js-header.js*/ ){
|
||||
try{
|
||||
/* Config options for sqlite3ApiBootstrap(). */
|
||||
const bootstrapConfig = Object.assign(
|
||||
Object.create(null),
|
||||
globalThis.sqlite3ApiBootstrap.defaultConfig, // default options
|
||||
globalThis.sqlite3ApiConfig || {}, // optional client-provided options
|
||||
/** The WASM-environment-dependent configuration for sqlite3ApiBootstrap() */
|
||||
{
|
||||
memory: ('undefined'!==typeof wasmMemory)
|
||||
? wasmMemory
|
||||
: EmscriptenModule['wasmMemory'],
|
||||
exports: ('undefined'!==typeof wasmExports)
|
||||
? wasmExports /* emscripten >=3.1.44 */
|
||||
: (Object.prototype.hasOwnProperty.call(EmscriptenModule,'wasmExports')
|
||||
? EmscriptenModule['wasmExports']
|
||||
: EmscriptenModule['asm']/* emscripten <=3.1.43 */)
|
||||
}
|
||||
);
|
||||
|
||||
sqlite3InitScriptInfo.debugModule("Bootstrapping lib config", bootstrapConfig);
|
||||
|
||||
/**
|
||||
For purposes of the Emscripten build, call sqlite3ApiBootstrap().
|
||||
Ideally clients should be able to inject their own config here,
|
||||
but that's not practical in this particular build constellation
|
||||
because of the order everything happens in. Clients may either
|
||||
define globalThis.sqlite3ApiConfig or modify
|
||||
globalThis.sqlite3ApiBootstrap.defaultConfig to tweak the default
|
||||
configuration used by a no-args call to sqlite3ApiBootstrap(),
|
||||
but must have first loaded their WASM module in order to be able
|
||||
to provide the necessary configuration state.
|
||||
*/
|
||||
const p = globalThis.sqlite3ApiBootstrap(bootstrapConfig);
|
||||
delete globalThis.sqlite3ApiBootstrap;
|
||||
return p /* the eventual result of globalThis.sqlite3InitModule() */;
|
||||
}catch(e){
|
||||
console.error("sqlite3ApiBootstrap() error:",e);
|
||||
throw e;
|
||||
}
|
||||
}/*Emscripten post-load lib init*/
|
||||
@@ -27,14 +27,13 @@
|
||||
/**
|
||||
sqlite3ApiBootstrap() is the only global symbol persistently
|
||||
exposed by this API. It is intended to be called one time at the
|
||||
end of the API amalgamation process and passed configuration details
|
||||
for the current environment.
|
||||
end of the API amalgamation process, passed configuration details
|
||||
for the current environment, and then optionally be removed from
|
||||
the global object using `delete globalThis.sqlite3ApiBootstrap`.
|
||||
|
||||
This function is not intended for client-level use. It is intended
|
||||
for use in creating bundles configured for specific WASM
|
||||
environments. That said, the "sqlite3-api.js" intermediary build
|
||||
file aims to be suitable for dropping in to custom builds, and it
|
||||
exposes only this function.
|
||||
environments.
|
||||
|
||||
This function expects a configuration object, intended to abstract
|
||||
away details specific to any given WASM environment, primarily so
|
||||
@@ -94,10 +93,9 @@
|
||||
can be replaced with (e.g.) empty functions to squelch all such
|
||||
output.
|
||||
|
||||
- `wasmfsOpfsDir`[^1]: Specifies the "mount point" of the
|
||||
OPFS-backed filesystem in WASMFS-capable builds. This is only
|
||||
used in WASMFS-capable builds of the library (which the canonical
|
||||
builds do not include).
|
||||
- `wasmfsOpfsDir`[^1]: Specifies the "mount point" of the OPFS-backed
|
||||
filesystem in WASMFS-capable builds.
|
||||
|
||||
|
||||
[^1] = This property may optionally be a function, in which case
|
||||
this function calls that function to fetch the value,
|
||||
@@ -127,8 +125,7 @@
|
||||
Both sqlite3ApiBootstrap.defaultConfig and
|
||||
globalThis.sqlite3ApiConfig get deleted by sqlite3ApiBootstrap()
|
||||
because any changes to them made after that point would have no
|
||||
useful effect. This function also deletes itself from globalThis
|
||||
when it's called.
|
||||
useful effect.
|
||||
|
||||
This function returns a Promise to the sqlite3 namespace object,
|
||||
which resolves after the async pieces of the library init are
|
||||
@@ -180,6 +177,14 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
Eliminate any confusion about whether these config objects may
|
||||
be used after library initialization by eliminating the outward-facing
|
||||
objects...
|
||||
*/
|
||||
delete globalThis.sqlite3ApiConfig;
|
||||
delete sqlite3ApiBootstrap.defaultConfig;
|
||||
|
||||
/**
|
||||
The main sqlite3 binding API gets installed into this object,
|
||||
mimicking the C API as closely as we can. The numerous members
|
||||
@@ -791,8 +796,7 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(
|
||||
|
||||
/**
|
||||
wasm.X properties which are used for configuring the wasm
|
||||
environment via whwashutil.js. This object gets fleshed out with
|
||||
a number of WASM-specific utilities, in sqlite3-api-glue.c-pp.js.
|
||||
environment via whwashutil.js.
|
||||
*/
|
||||
Object.assign(wasm, {
|
||||
|
||||
@@ -805,9 +809,8 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(
|
||||
/**
|
||||
When Emscripten compiles with `-sIMPORTED_MEMORY`, it
|
||||
initializes the heap and imports it into wasm, as opposed to
|
||||
the other way around. In this case, the memory is not available
|
||||
via this.exports.memory so the client must pass it in via
|
||||
config.memory.
|
||||
the other way around. In this case, the memory is not
|
||||
available via this.exports.memory.
|
||||
*/
|
||||
memory: config.memory
|
||||
|| config.exports['memory']
|
||||
@@ -953,11 +956,7 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(
|
||||
};
|
||||
wasm.realloc.impl = wasm.exports[keyRealloc];
|
||||
wasm.dealloc = function f(m){
|
||||
f.impl(wasm.ptr.coerce(m)/*tag:64bit*/)
|
||||
/* This coerce() is the reason we have to set wasm.pointerSize before
|
||||
calling WhWasmUtilInstaller(). If we don't, that code will call
|
||||
into this very early in its init, before wasm.ptr has been set up,
|
||||
resulting in a null deref here. */;
|
||||
f.impl(wasm.ptr.coerce(m)/*tag:64bit*/);
|
||||
};
|
||||
wasm.dealloc.impl = wasm.exports[keyDealloc];
|
||||
}
|
||||
@@ -1028,18 +1027,18 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(
|
||||
}/*compileOptionUsed()*/;
|
||||
|
||||
/**
|
||||
sqlite3.wasm.pstack (pseudo-stack) holds a special-case allocator
|
||||
intended solely for short-lived, small data. In practice, it's
|
||||
primarily used to allocate output pointers. It must not be used
|
||||
for any memory which needs to outlive the scope in which it's
|
||||
obtained from pstack.
|
||||
sqlite3.wasm.pstack (pseudo-stack) holds a special-case intended
|
||||
solely for short-lived, small data. In practice, it's primarily
|
||||
used to allocate output pointers. It mus not be used for any
|
||||
memory which needs to outlive the scope in which it's obtained
|
||||
from pstack.
|
||||
|
||||
The library guarantees only that a minimum of 2kb are available
|
||||
in this allocator, and it may provide more (it's a build-time
|
||||
value). pstack.quota and pstack.remaining can be used to get the
|
||||
total resp. remaining amount of memory.
|
||||
|
||||
It has only a single intended usage pattern:
|
||||
It has only a single intended usage:
|
||||
|
||||
```
|
||||
const stackPos = pstack.pointer;
|
||||
@@ -1056,11 +1055,13 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(
|
||||
```
|
||||
|
||||
This allocator is much faster than a general-purpose one but is
|
||||
limited to usage patterns like the one shown above (which are
|
||||
pretty common when using sqlite3.capi).
|
||||
limited to usage patterns like the one shown above.
|
||||
|
||||
The memory lives in the WASM heap and can be used with routines
|
||||
such as wasm.poke() and wasm.heap8u().slice().
|
||||
It operates from a static range of memory which lives outside of
|
||||
space managed by Emscripten's stack-management, so does not
|
||||
collide with Emscripten-provided stack allocation APIs. The
|
||||
memory lives in the WASM heap and can be used with routines such
|
||||
as wasm.poke() and wasm.heap8u().slice().
|
||||
*/
|
||||
wasm.pstack = Object.assign(Object.create(null),{
|
||||
/**
|
||||
@@ -1134,7 +1135,7 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(
|
||||
argument: if it's 1, it returns a single pointer value. If it's
|
||||
more than 1, it returns the same as allocChunks().
|
||||
|
||||
When a returned pointer will refer to a 64-bit value, e.g. a
|
||||
When a returned pointers will refer to a 64-bit value, e.g. a
|
||||
double or int64, and that value must be written or fetched,
|
||||
e.g. using wasm.poke() or wasm.peek(), it is
|
||||
important that the pointer in question be aligned to an 8-byte
|
||||
@@ -1202,9 +1203,6 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(
|
||||
}
|
||||
})/*wasm.pstack properties*/;
|
||||
|
||||
/**
|
||||
Docs: https://sqlite.org/wasm/doc/trunk/api-c-style.md#sqlite3_randomness
|
||||
*/
|
||||
capi.sqlite3_randomness = (...args)=>{
|
||||
if(1===args.length
|
||||
&& util.isTypedArray(args[0])
|
||||
@@ -1239,6 +1237,8 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(
|
||||
wasm.exports.sqlite3_randomness(...args);
|
||||
};
|
||||
|
||||
/** State for sqlite3_wasmfs_opfs_dir(). */
|
||||
let __wasmfsOpfsDir = undefined;
|
||||
/**
|
||||
If the wasm environment has a WASMFS/OPFS-backed persistent
|
||||
storage directory, its path is returned by this function. If it
|
||||
@@ -1262,7 +1262,7 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(
|
||||
WASMFS capability requires a custom build.
|
||||
*/
|
||||
capi.sqlite3_wasmfs_opfs_dir = function(){
|
||||
if(undefined !== this.dir) return this.dir;
|
||||
if(undefined !== __wasmfsOpfsDir) return __wasmfsOpfsDir;
|
||||
// If we have no OPFS, there is no persistent dir
|
||||
const pdir = config.wasmfsOpfsDir;
|
||||
if(!pdir
|
||||
@@ -1270,21 +1270,21 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(
|
||||
|| !globalThis.FileSystemDirectoryHandle
|
||||
|| !globalThis.FileSystemFileHandle
|
||||
|| !wasm.exports.sqlite3__wasm_init_wasmfs){
|
||||
return this.dir = "";
|
||||
return __wasmfsOpfsDir = "";
|
||||
}
|
||||
try{
|
||||
if(pdir && 0===wasm.xCallWrapped(
|
||||
'sqlite3__wasm_init_wasmfs', 'i32', ['string'], pdir
|
||||
)){
|
||||
return this.dir = pdir;
|
||||
return __wasmfsOpfsDir = pdir;
|
||||
}else{
|
||||
return this.dir = "";
|
||||
return __wasmfsOpfsDir = "";
|
||||
}
|
||||
}catch(e){
|
||||
// sqlite3__wasm_init_wasmfs() is not available
|
||||
return this.dir = "";
|
||||
return __wasmfsOpfsDir = "";
|
||||
}
|
||||
}.bind(Object.create(null));
|
||||
};
|
||||
|
||||
/**
|
||||
Returns true if sqlite3.capi.sqlite3_wasmfs_opfs_dir() is a
|
||||
@@ -1340,7 +1340,7 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(
|
||||
*/
|
||||
capi.sqlite3_js_vfs_list = function(){
|
||||
const rc = [];
|
||||
let pVfs = capi.sqlite3_vfs_find(wasm.ptr.null);
|
||||
let pVfs = capi.sqlite3_vfs_find(wasm.ptr.coerce(0));
|
||||
while(pVfs){
|
||||
const oVfs = new capi.sqlite3_vfs(pVfs);
|
||||
rc.push(wasm.cstrToJs(oVfs.$zName));
|
||||
@@ -2068,8 +2068,8 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(
|
||||
*/
|
||||
asyncPostInit: async function ff(){
|
||||
if(ff.isReady instanceof Promise) return ff.isReady;
|
||||
let lia = this.initializersAsync;
|
||||
delete this.initializersAsync;
|
||||
let lia = sqlite3ApiBootstrap.initializersAsync;
|
||||
delete sqlite3ApiBootstrap.initializersAsync;
|
||||
const postInit = async ()=>{
|
||||
if(!sqlite3.__isUnderTest){
|
||||
/* Delete references to internal-only APIs which are used by
|
||||
@@ -2094,7 +2094,7 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(
|
||||
let p = Promise.resolve(sqlite3);
|
||||
while(lia.length) p = p.then(lia.shift());
|
||||
return ff.isReady = p.catch(catcher);
|
||||
}.bind(sqlite3ApiBootstrap),
|
||||
},
|
||||
/**
|
||||
scriptInfo ideally gets injected into this object by the
|
||||
infrastructure which assembles the JS/WASM module. It contains
|
||||
@@ -2121,37 +2121,16 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(
|
||||
}
|
||||
delete sqlite3ApiBootstrap.initializers;
|
||||
sqlite3ApiBootstrap.sqlite3 = sqlite3;
|
||||
if( 'undefined'!==typeof sqlite3InitScriptInfo/* from post-js-header.js */ ){
|
||||
sqlite3InitScriptInfo.debugModule(
|
||||
"sqlite3ApiBootstrap() complete", sqlite3
|
||||
);
|
||||
sqlite3.scriptInfo
|
||||
/* Used by some async init code. As of 2025-11-15 this is still
|
||||
in use by the OPFS VFS for locating its worker. In non-Emscripten
|
||||
builds, this would need to be injected in somewhere to get
|
||||
that VFS loading. */ = sqlite3InitScriptInfo;
|
||||
}
|
||||
sqlite3.__isUnderTest =
|
||||
('undefined'===typeof sqlite3IsUnderTest /* from post-js-header.js */)
|
||||
? false : !!sqlite3IsUnderTest;
|
||||
if( sqlite3.__isUnderTest ){
|
||||
if( 'undefined'!==typeof EmscriptenModule ){
|
||||
sqlite3.config.emscripten = EmscriptenModule;
|
||||
}
|
||||
/*
|
||||
The problem with exposing these pieces (in non-testing runs) via
|
||||
sqlite3.wasm is that it exposes non-SQLite pieces to the
|
||||
clients, who may come to expect it to remain. _We_ only have
|
||||
these data because we've overridden Emscripten's wasm file
|
||||
loader, and if we lose that capability for some reason then
|
||||
we'll lose access to this metadata.
|
||||
|
||||
These data are interesting for exploring how the wasm/JS
|
||||
pieces connect, e.g. for exploring exactly what Emscripten
|
||||
imports into WASM from its JS glue, but it's not
|
||||
SQLite-related.
|
||||
*/
|
||||
const iw = sqlite3.scriptInfo?.instantiateWasm;
|
||||
delete globalThis.sqlite3ApiBootstrap;
|
||||
delete globalThis.sqlite3ApiConfig;
|
||||
sqlite3InitScriptInfo.debugModule(
|
||||
"sqlite3ApiBootstrap() complete", sqlite3
|
||||
);
|
||||
sqlite3.scriptInfo /* used by some async init code */ =
|
||||
sqlite3InitScriptInfo /* from post-js-header.js */;
|
||||
if( (sqlite3.__isUnderTest = sqlite3IsUnderTest /* from post-js-header.js */) ){
|
||||
sqlite3.config.emscripten = EmscriptenModule;
|
||||
const iw = sqlite3InitScriptInfo.instantiateWasm;
|
||||
if( iw ){
|
||||
/* Metadata injected by the custom Module.instantiateWasm()
|
||||
in pre-js.c-pp.js. */
|
||||
@@ -2160,15 +2139,6 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(
|
||||
sqlite3.wasm.imports = iw.imports;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Eliminate any confusion about whether these config objects may
|
||||
be used after library initialization by eliminating the outward-facing
|
||||
objects...
|
||||
*/
|
||||
delete globalThis.sqlite3ApiConfig;
|
||||
delete globalThis.sqlite3ApiBootstrap;
|
||||
delete sqlite3ApiBootstrap.defaultConfig;
|
||||
return sqlite3.asyncPostInit().then((s)=>{
|
||||
sqlite3InitScriptInfo.debugModule(
|
||||
"sqlite3.asyncPostInit() complete", sqlite3
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
asynchronous Origin-Private FileSystem (OPFS) APIs using a second
|
||||
Worker, implemented in sqlite3-opfs-async-proxy.js. This file is
|
||||
intended to be appended to the main sqlite3 JS deliverable somewhere
|
||||
after sqlite3-api-oo1.js.
|
||||
after sqlite3-api-oo1.js and before sqlite3-api-cleanup.js.
|
||||
*/
|
||||
'use strict';
|
||||
globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
@@ -1441,7 +1441,7 @@ installOpfsVfs.defaultProxyUri =
|
||||
globalThis.sqlite3ApiBootstrap.initializersAsync.push(async (sqlite3)=>{
|
||||
try{
|
||||
let proxyJs = installOpfsVfs.defaultProxyUri;
|
||||
if( sqlite3?.scriptInfo?.sqlite3Dir ){
|
||||
if(sqlite3.scriptInfo.sqlite3Dir){
|
||||
installOpfsVfs.defaultProxyUri =
|
||||
sqlite3.scriptInfo.sqlite3Dir + proxyJs;
|
||||
//sqlite3.config.warn("installOpfsVfs.defaultProxyUri =",installOpfsVfs.defaultProxyUri);
|
||||
|
||||
@@ -136,8 +136,8 @@
|
||||
/*
|
||||
** If SQLITE_WASM_BARE_BONES is defined, undefine most of the ENABLE
|
||||
** macros. This will, when using the canonical makefile, also elide
|
||||
** any C functions from the WASM exports: see
|
||||
** ./EXPORTED_FUNCTIONS.c-pp.
|
||||
** any C functions from the WASM exports which are listed in
|
||||
** ./EXPORT_FUNCTIONS.sqlite3-extras.
|
||||
*/
|
||||
#ifdef SQLITE_WASM_BARE_BONES
|
||||
# undef SQLITE_ENABLE_COLUMN_METADATA
|
||||
|
||||
@@ -667,14 +667,12 @@ globalThis.WhWasmUtilInstaller = function(target){
|
||||
const ft = target.functionTable();
|
||||
const oldLen = __asPtrType(ft.length);
|
||||
let ptr;
|
||||
while( (ptr = cache.freeFuncIndexes.pop()) ){
|
||||
if(ft.get(ptr)){
|
||||
/* freeFuncIndexes's entry is stale. Table was modified via a
|
||||
different API */
|
||||
while(cache.freeFuncIndexes.length){
|
||||
ptr = cache.freeFuncIndexes.pop();
|
||||
if(ft.get(ptr)){ /* Table was modified via a different API */
|
||||
ptr = null;
|
||||
continue;
|
||||
}else{
|
||||
/* This index is free. We'll re-use it. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -765,9 +763,10 @@ globalThis.WhWasmUtilInstaller = function(target){
|
||||
has no side effects and returns undefined.
|
||||
*/
|
||||
target.uninstallFunction = function(ptr){
|
||||
if(!ptr && __NullPtr!==ptr) return undefined;
|
||||
if(!ptr && 0!==ptr) return undefined;
|
||||
const fi = cache.freeFuncIndexes;
|
||||
const ft = target.functionTable();
|
||||
cache.freeFuncIndexes.push(ptr);
|
||||
fi.push(ptr);
|
||||
const rc = ft.get(ptr);
|
||||
ft.set(ptr, null);
|
||||
return rc;
|
||||
|
||||
@@ -280,7 +280,7 @@ const BuildDefs oBuildDefs = {
|
||||
" -DSQLITE_SPEEDTEST1_WASM"
|
||||
" $(SQLITE_OPT)"
|
||||
" -USQLITE_WASM_BARE_BONES"
|
||||
" -USQLITE_C -DSQLITE_C=$(sqlite3.c)"
|
||||
" -USQLITE_C -DSQLITE_C=$(sqlite3.canonical.c)"
|
||||
" $(speedtest1.exit-runtime0)"
|
||||
" $(speedtest1.c.in)"
|
||||
" -lm",
|
||||
@@ -308,7 +308,7 @@ const BuildDefs oBuildDefs = {
|
||||
" -DSQLITE_SPEEDTEST1_WASM"
|
||||
" $(SQLITE_OPT)"
|
||||
" -USQLITE_WASM_BARE_BONES"
|
||||
" -USQLITE_C -DSQLITE_C=$(sqlite3.c)"
|
||||
" -USQLITE_C -DSQLITE_C=$(sqlite3.canonical.c)"
|
||||
" $(speedtest1.exit-runtime0)"
|
||||
" $(speedtest1.c.in)"
|
||||
" -lm",
|
||||
@@ -633,7 +633,7 @@ static void mk_pre_post(char const *zBuildName, BuildDef const * pB){
|
||||
pB->zDotWasm);
|
||||
}
|
||||
ps("");
|
||||
pf("\t@$(call b.mkdir@); $(call b.c-pp.shcmd,"
|
||||
pf("\t@$(call b.c-pp.shcmd,"
|
||||
"%s,"
|
||||
"$(pre-js.in.js),"
|
||||
"$(pre-js.%s.js),"
|
||||
|
||||
@@ -652,7 +652,7 @@ SRC = \
|
||||
$(TOP)/src/sqliteInt.h \
|
||||
$(TOP)/src/sqliteLimit.h \
|
||||
$(TOP)/src/table.c \
|
||||
$(TOP)/src/tclsqlite.c \
|
||||
tclsqlite-ex.c \
|
||||
$(TOP)/src/threads.c \
|
||||
$(TOP)/src/tokenize.c \
|
||||
$(TOP)/src/treeview.c \
|
||||
@@ -1409,15 +1409,15 @@ whereexpr.o: $(TOP)/src/whereexpr.c $(DEPS_OBJ_COMMON)
|
||||
window.o: $(TOP)/src/window.c $(DEPS_OBJ_COMMON)
|
||||
$(T.cc.sqlite) -c $(TOP)/src/window.c
|
||||
|
||||
tclsqlite.o: $(T.tcl.env.sh) $(TOP)/src/tclsqlite.c $(DEPS_OBJ_COMMON)
|
||||
tclsqlite.o: $(T.tcl.env.sh) tclsqlite-ex.c $(DEPS_OBJ_COMMON)
|
||||
$(T.compile.tcl) -DUSE_TCL_STUBS=1 $$TCL_INCLUDE_SPEC \
|
||||
-c $(TOP)/src/tclsqlite.c
|
||||
-c tclsqlite-ex.c -o tclsqlite.o
|
||||
|
||||
tclsqlite-shell.o: $(T.tcl.env.sh) $(TOP)/src/tclsqlite.c $(DEPS_OBJ_COMMON)
|
||||
$(T.compile.tcl) -DTCLSH -o $@ -c $(TOP)/src/tclsqlite.c $$TCL_INCLUDE_SPEC
|
||||
tclsqlite-shell.o: $(T.tcl.env.sh) tclsqlite-ex.c $(DEPS_OBJ_COMMON)
|
||||
$(T.compile.tcl) -DTCLSH -o $@ -c tclsqlite-ex.c $$TCL_INCLUDE_SPEC
|
||||
|
||||
tclsqlite-stubs.o: $(T.tcl.env.sh) $(TOP)/src/tclsqlite.c $(DEPS_OBJ_COMMON)
|
||||
$(T.compile.tcl) -DUSE_TCL_STUBS=1 -o $@ -c $(TOP)/src/tclsqlite.c $$TCL_INCLUDE_SPEC
|
||||
tclsqlite-stubs.o: $(T.tcl.env.sh) tclsqlite-ex.c $(DEPS_OBJ_COMMON)
|
||||
$(T.compile.tcl) -DUSE_TCL_STUBS=1 -o $@ -c tclsqlite-ex.c $$TCL_INCLUDE_SPEC
|
||||
|
||||
#
|
||||
# STATIC_TCLSQLITE3 = 1 to statically link tclsqlite3, else
|
||||
@@ -1661,11 +1661,19 @@ install-tcl-0 install-tcl-:
|
||||
install-tcl: install-tcl-$(HAVE_TCL)
|
||||
install: install-tcl
|
||||
|
||||
tclsqlite3.c: sqlite3.c
|
||||
TCLSQLITEEX = \
|
||||
$(TOP)/ext/qrf/qrf.h \
|
||||
$(TOP)/ext/qrf/qrf.c \
|
||||
$(TOP)/src/tclsqlite.c
|
||||
|
||||
tclsqlite-ex.c: $(TCLSQLITEEX) $(TOP)/tool/mkcombo.tcl $(B.tclsh)
|
||||
$(B.tclsh) $(TOP)/tool/mkcombo.tcl $(TCLSQLITEEX) -o $@
|
||||
|
||||
tclsqlite3.c: sqlite3.c tclsqlite-ex.c
|
||||
echo '#ifndef USE_SYSTEM_SQLITE' >tclsqlite3.c
|
||||
cat sqlite3.c >>tclsqlite3.c
|
||||
echo '#endif /* USE_SYSTEM_SQLITE */' >>tclsqlite3.c
|
||||
cat $(TOP)/src/tclsqlite.c >>tclsqlite3.c
|
||||
cat tclsqlite-ex.c >>tclsqlite3.c
|
||||
|
||||
#
|
||||
# $(CFLAGS.tclextension) = CFLAGS for the tclextension* targets.
|
||||
@@ -1782,7 +1790,7 @@ TESTFIXTURE_FLAGS += -DSQLITE_STRICT_SUBTYPE=1
|
||||
|
||||
TESTFIXTURE_SRC0 = $(TESTSRC2) $(libsqlite3.LIB)
|
||||
TESTFIXTURE_SRC1 = sqlite3.c
|
||||
TESTFIXTURE_SRC = $(TESTSRC) $(TOP)/src/tclsqlite.c
|
||||
TESTFIXTURE_SRC = $(TESTSRC) tclsqlite-ex.c
|
||||
TESTFIXTURE_SRC += $(TESTFIXTURE_SRC$(USE_AMALGAMATION))
|
||||
|
||||
testfixture$(T.exe): $(T.tcl.env.sh) has_tclsh85 $(TESTFIXTURE_SRC)
|
||||
@@ -1912,7 +1920,7 @@ shelltest:
|
||||
#
|
||||
sqlite3_analyzer.c.flags.0 = -DINCLUDE_SQLITE3_C=1
|
||||
sqlite3_analyzer.c.flags.1 =
|
||||
sqlite3_analyzer.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/spaceanal.tcl \
|
||||
sqlite3_analyzer.c: sqlite3.c tclsqlite-ex.c $(TOP)/tool/spaceanal.tcl \
|
||||
$(TOP)/tool/mkccode.tcl $(TOP)/tool/sqlite3_analyzer.c.in
|
||||
$(B.tclsh) $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqlite3_analyzer.c.in \
|
||||
$(sqlite3_analyzer.c.flags.$(LINK_TOOLS_DYNAMICALLY)) \
|
||||
@@ -1936,7 +1944,7 @@ sqlite3_analyzer$(T.exe): $(T.tcl.env.sh) sqlite3_analyzer.c \
|
||||
# can cause the $@ to link to an out-of-tree libsqlite3.so, which may
|
||||
# or may not fail or otherwise cause confusion.
|
||||
|
||||
sqltclsh.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/sqltclsh.tcl \
|
||||
sqltclsh.c: sqlite3.c tclsqlite-ex.c $(TOP)/tool/sqltclsh.tcl \
|
||||
$(TOP)/ext/misc/appendvfs.c $(TOP)/tool/mkccode.tcl \
|
||||
$(TOP)/tool/sqltclsh.c.in
|
||||
$(B.tclsh) $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqltclsh.c.in >sqltclsh.c
|
||||
@@ -1957,7 +1965,7 @@ xbin: sqlite3_expert$(T.exe)
|
||||
CHECKER_DEPS =\
|
||||
$(TOP)/tool/mkccode.tcl \
|
||||
sqlite3.c \
|
||||
$(TOP)/src/tclsqlite.c \
|
||||
tclsqlite-ex.c \
|
||||
$(TOP)/ext/repair/sqlite3_checker.tcl \
|
||||
$(TOP)/ext/repair/checkindex.c \
|
||||
$(TOP)/ext/repair/checkfreelist.c \
|
||||
@@ -2333,6 +2341,8 @@ mptest: mptester$(T.exe)
|
||||
# Source and header files that shell.c depends on
|
||||
SHELL_DEP = \
|
||||
$(TOP)/src/shell.c.in \
|
||||
$(TOP)/ext/qrf/qrf.c \
|
||||
$(TOP)/ext/qrf/qrf.h \
|
||||
$(TOP)/ext/expert/sqlite3expert.c \
|
||||
$(TOP)/ext/expert/sqlite3expert.h \
|
||||
$(TOP)/ext/intck/sqlite3intck.c \
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
C Experimental\sSQLITE_MAX_SUBQUERY\scompile-time\soption.
|
||||
D 2025-11-18T00:16:40.468
|
||||
C If\sSQL\sis\sentered\sas\sadditional\scommand-line\sarguments\sto\sCLI,\sthat\scounts\nthe\ssame\sas\sgetting\sinput\sfrom\sa\spipe\sor\sfile\sfor\sthe\spurpose\sof\sdetermining\nthe\sdefault\sformat\smode.
|
||||
D 2025-11-17T19:46:04.211
|
||||
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md 6bc480fc673fb4acbc4094e77edb326267dd460162d7723c7f30bee2d3d9e97d
|
||||
F Makefile.in 3ce07126d7e87c7464301482e161fdae6a51d0a2aa06b200b8f0000ef4d6163b
|
||||
F Makefile.linux-generic bd3e3cacd369821a6241d4ea1967395c962dfe3057e38cb0a435cee0e8b789d0
|
||||
F Makefile.msc 523bab2f6569e912a0aaf2d13e0b3f9bcb36d52310b236d950b354068c9de3f3
|
||||
F Makefile.msc 8c5ed7173ee4cc3c03ba8e21065128f7ca5292c83d68f3bf971786e21fc6e382
|
||||
F README.md dae499194b75deed76a13a4a83c82493f2530331882d7dfe5754d63287d3f8f7
|
||||
F VERSION 74672bfd4c7826c0fc6f84762488a707c52e7d2d94af42ccb0edcc6c74311c41
|
||||
F art/icon-243x273.gif 9750b734f82fdb3dc43127753d5e6fbf3b62c9f4e136c2fbf573b2f57ea87af5
|
||||
@@ -47,7 +47,7 @@ F autosetup/find_tclconfig.tcl e64886ffe3b982d4df42cd28ed91fe0b5940c2c5785e126c1
|
||||
F autosetup/jimsh0.c a57c16e65dcffc9c76e496757cb3f7fb47e01ecbd1631a0a5e01751fc856f049
|
||||
F autosetup/pkg-config.tcl 4e635bf39022ff65e0d5434339dd41503ea48fc53822c9c5bde88b02d3d952ba
|
||||
F autosetup/proj.tcl 6fc14ef82b19b77a95788ffbcfad7989b4e3cb4ce96a21dcb5cf7312f362fba9
|
||||
F autosetup/sqlite-config.tcl 1fd7c55394051fbfba2fb9fa9192c027ee7d74612dbf772b06e27feb9f1de5df
|
||||
F autosetup/sqlite-config.tcl 97dc76d332ae3344d02d15c99c57db0ac063537e9133cbee0520d48ba0eddc08
|
||||
F autosetup/system.tcl 51d4be76cd9a9074704b584e5c9cbba616202c8468cf9ba8a4f8294a7ab1dba9
|
||||
F autosetup/teaish/README.txt b40071e6f8506500a2f7f71d5fc69e0bf87b9d7678dd9da1e5b4d0acbf40b1ca
|
||||
F autosetup/teaish/core.tcl e014dd95900c7f9a34e8e0f460f47e94841059827bce8b4c49668b0c7ae3f1a0
|
||||
@@ -71,7 +71,7 @@ F doc/wal-lock.md 7db0cd61e2000b545b78ce89b0c2a9a8dd8d64c097839258ac10d7c5c4156e
|
||||
F ext/README.md 6eb1ac267d917767952ed0ef63f55de003b6a5da433ce1fa389e1a9532e73132
|
||||
F ext/expert/README.md b321c2762bb93c18ea102d5a5f7753a4b8bac646cb392b3b437f633caf2020c3
|
||||
F ext/expert/expert.c d548d603a4cc9e61f446cc179c120c6713511c413f82a4a32b1e1e69d3f086a4
|
||||
F ext/expert/expert1.test 1d2da6606623b57bb47064e02140823ce1daecd4cacbf402c73ad3473d7f000c
|
||||
F ext/expert/expert1.test d9dfbf7fb527cfd43049e30a6238ef02c94484041fa4461ed41acbc6435425d6
|
||||
F ext/expert/sqlite3expert.c 546010043fbec93544f762de5161b3d553165859e6bd853c4b85c05f93484260
|
||||
F ext/expert/sqlite3expert.h ca81efc2679a92373a13a3e76a6138d0310e32be53d6c3bfaedabd158ea8969b
|
||||
F ext/expert/test_expert.c c395134bd6d4efa594a7d26578a1cb624c4027b79b4b5fcd44736c5ef1f5f725
|
||||
@@ -290,7 +290,7 @@ F ext/intck/test_intck.c 4f9eaadaedccb9df1d26ba41116a0a8e5b0c5556dc3098c8ff68633
|
||||
F ext/jni/GNUmakefile 8a94e3a1953b88cf117fb2a5380480feada8b4f5316f02572cab425030a720b4
|
||||
F ext/jni/README.md 1479c83dbe26125264a060ee6873531795a7082dbc0d43c4067683371331559f
|
||||
F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa
|
||||
F ext/jni/src/c/sqlite3-jni.c 6ccc50b0e98b8ef8fd6a8b837223e1c8ebb92bfe6b976128cc757c26257d994a
|
||||
F ext/jni/src/c/sqlite3-jni.c 3d84a0176af779737ae977ba1c90d2ffe2537b8299c5d9f6552620493f12ac4b
|
||||
F ext/jni/src/c/sqlite3-jni.h df43024cced914c49485633d0f90168689e70577b3b17b0ecbdaf16e4a417bff
|
||||
F ext/jni/src/org/sqlite/jni/annotation/Experimental.java 8603498634e41d0f7c70f661f64e05df64376562ea8f126829fd1e0cdd47e82b
|
||||
F ext/jni/src/org/sqlite/jni/annotation/NotNull.java be6cc3e8e114485822331630097cc0f816377e8503af2fc02f9305ff2b353917
|
||||
@@ -319,7 +319,7 @@ F ext/jni/src/org/sqlite/jni/capi/SQLFunction.java 0d1e9afc9ff8a2adb94a155b72385
|
||||
F ext/jni/src/org/sqlite/jni/capi/SQLTester.java 3c0babc067d8560627a9ed1b07979f9d4393464e2282c2fca4832052e982c7bc
|
||||
F ext/jni/src/org/sqlite/jni/capi/ScalarFunction.java 93b9700fca4c68075ccab12fe0fbbc76c91cafc9f368e835b9bd7cd7732c8615
|
||||
F ext/jni/src/org/sqlite/jni/capi/TableColumnMetadata.java 9133bb7685901d2edf07801191284975e33b5583ce09dce1c05202ff91e7bb99
|
||||
F ext/jni/src/org/sqlite/jni/capi/Tester1.java 378d142435d220b20b7ce7343c62a03e853bb8c51e80447ee0f8ac5c37362d9a
|
||||
F ext/jni/src/org/sqlite/jni/capi/Tester1.java 4c3d16fdf6e979f839b2ecdb14d0a0c04bd3d0e41500fc9e8110b588883b140b
|
||||
F ext/jni/src/org/sqlite/jni/capi/TraceV2Callback.java 0a25e117a0daae3394a77f24713e36d7b44c67d6e6d30e9e1d56a63442eef723
|
||||
F ext/jni/src/org/sqlite/jni/capi/UpdateHookCallback.java c8bdf7848e6599115d601bcc9427ff902cb33129b9be32870ac6808e04b6ae56
|
||||
F ext/jni/src/org/sqlite/jni/capi/ValueHolder.java 2ce069f3e007fdbbe1f4e507a5a407fc9679da31a0aa40985e6317ed4d5ec7b5
|
||||
@@ -397,8 +397,8 @@ F ext/misc/shathree.c fd22d70620f86a0467acfdd3acd8435d5cb54eb1e2d9ff36ae44e38982
|
||||
F ext/misc/showauth.c 732578f0fe4ce42d577e1c86dc89dd14a006ab52
|
||||
F ext/misc/spellfix.c 693c8fd3293087fa821322967a97e59dfa24051e5d2ca7fa85790a4034db6fa4
|
||||
F ext/misc/sqlar.c a6175790482328171da47095f87608b48a476d4fac78d8a9ff18b03a2454f634
|
||||
F ext/misc/sqlite3_stdio.c 0fe5a45bd332b30aef2b68c64edbe69e31e9c42365b0fa79ce95a034bca6fbb0
|
||||
F ext/misc/sqlite3_stdio.h f05eaf5e0258f0573910324a789a9586fc360a57678c57a6d63cfaa2245b6176
|
||||
F ext/misc/sqlite3_stdio.c e49c07050bf7bdc87866da7583beda236f2f8c462018a34b61785d99cbddedfd
|
||||
F ext/misc/sqlite3_stdio.h 27a4ecea47e61bc9574ccdf2806f468afe23af2f95028c9b689bfa08ab1ce99f
|
||||
F ext/misc/stmt.c b090086cd6bd6281c21271d38d576eeffe662f0e6b67536352ce32bbaa438321
|
||||
F ext/misc/stmtrand.c 59cffa5d8e158943ff1ce078956d8e208e8c04e67307e8f249dece2436dcb7fc
|
||||
F ext/misc/templatevtab.c 10f15b165b95423ddef593bc5dcb915ec4eb5e0f1066d585e5435a368b8bc22b
|
||||
@@ -416,6 +416,9 @@ F ext/misc/wholenumber.c 0fa0c082676b7868bf2fa918e911133f2b349bcdceabd1198bba5f6
|
||||
F ext/misc/windirent.h 02211ce51f3034c675f2dbf4d228194d51b3ee05734678bad5106fff6292e60c
|
||||
F ext/misc/zipfile.c 09e6e3a3ff40a99677de3c0bc6569bd5f4709b1844ac3d1c1452a456c5a62f1c
|
||||
F ext/misc/zorder.c bddff2e1b9661a90c95c2a9a9c7ecd8908afab5763256294dd12d609d4664eee
|
||||
F ext/qrf/README.md dd565fd1ca0c46ea37dbf4d496e368b9ecade768c92669640bc106e039629016
|
||||
F ext/qrf/qrf.c ee3964addf075c87fc60e312a472eec35112ba34581edf655fcd5c34e2492602
|
||||
F ext/qrf/qrf.h b4b3489b3b3683523fd248d15cf5945830643b036943efacdb772a3e00367aa2
|
||||
F ext/rbu/rbu.c 801450b24eaf14440d8fd20385aacc751d5c9d6123398df41b1b5aa804bf4ce8
|
||||
F ext/rbu/rbu1.test 25870dd7db7eb5597e2b4d6e29e7a7e095abf332660f67d89959552ce8f8f255
|
||||
F ext/rbu/rbu10.test 7c22caa32c2ff26983ca8320779a31495a6555737684af7aba3daaf762ef3363
|
||||
@@ -575,7 +578,7 @@ F ext/session/sessionwor.test 6fd9a2256442cebde5b2284936ae9e0d54bde692d0f5fd009e
|
||||
F ext/session/sqlite3session.c b3de195ce668cace9b324599bf6255a70290cbfb5451e826e946f3aee6e64c54
|
||||
F ext/session/sqlite3session.h 7404723606074fcb2afdc6b72c206072cdb2b7d8ba097ca1559174a80bc26f7a
|
||||
F ext/session/test_session.c 8766b5973a6323934cb51248f621c3dc87ad2a98f023c3cc280d79e7d78d36fb
|
||||
F ext/wasm/GNUmakefile aef238930e96197fed6fa1b4d9e5443b519dd6c24e0139e124c26bc51270f39a
|
||||
F ext/wasm/GNUmakefile b669dac12f134b8ca7e0f2fc49784abe3ae0cf3e559b155d2651c0861ff021f3
|
||||
F ext/wasm/README-dist.txt f01081a850ce38a56706af6b481e3a7878e24e42b314cfcd4b129f0f8427066a
|
||||
F ext/wasm/README.md 2e87804e12c98f1d194b7a06162a88441d33bb443efcfe00dc6565a780d2f259
|
||||
F ext/wasm/SQLTester/GNUmakefile e0794f676d55819951bbfae45cc5e8d7818dc460492dc317ce7f0d2eca15caff
|
||||
@@ -584,30 +587,31 @@ F ext/wasm/SQLTester/SQLTester.run.mjs 57f2adb33f43f2784abbf8026c1bfd049d8013af1
|
||||
F ext/wasm/SQLTester/index.html 64f3435084c7d6139b08d1f2a713828a73f68de2ae6a3112cbb5980d991ba06f
|
||||
F ext/wasm/SQLTester/touint8array.c 2d5ece04ec1393a6a60c4bf96385bda5e1a10ad49f3038b96460fc5e5aa7e536
|
||||
F ext/wasm/api/EXPORTED_FUNCTIONS.c-pp d609c22bc05e25991bdd2eeed4497485a3756446158b2794471426e5e3517056
|
||||
F ext/wasm/api/README.md aae128e14711dafac29e7b645ff1b6be42305b73f74b1303d8401351f8448631
|
||||
F ext/wasm/api/README.md df476398c6d80affae807a8208c5a97d1615786e1d6767b5292bfe67edb59b18
|
||||
F ext/wasm/api/extern-post-js.c-pp.js 4b310c9891886e7c1ea4e2419966ff45dfeda825b897fdaa4119332509f7e3d1
|
||||
F ext/wasm/api/extern-pre-js.js cc61c09c7a24a07dbecb4c352453c3985170cec12b4e7e7e7a4d11d43c5c8f41
|
||||
F ext/wasm/api/post-js-footer.js a50c1a2c4d008aede7b2aa1f18891a7ee71437c2f415b8aeb3db237ddce2935b
|
||||
F ext/wasm/api/post-js-header.js d24bd0d065f3489c8b78ddf3ead6321e5d047187a162cd503c41700e03dd1f06
|
||||
F ext/wasm/api/pre-js.c-pp.js ad2546290e0c8ce5ca2081bff6e85cc25eeb904a3303921f1184290a7ff1b32f
|
||||
F ext/wasm/api/post-js-footer.js 5bd7170b5e8ce7b62102702bbcf47ef7b3b49cd56ed40c043fd990aa715b74ee
|
||||
F ext/wasm/api/post-js-header.js 79d078aec33d93b640a19c574b504d88bb2446432f38e2fbb3bb8e36da436e70
|
||||
F ext/wasm/api/pre-js.c-pp.js b1a7a09d14df1f36de11e801ba06cb92c0ddeb520e5b2f28836af0ec8146e288
|
||||
F ext/wasm/api/sqlite3-api-cleanup.js f0a408704e56d6e59d5c0a2f6d84651b71dc2af39a2a4017256213ee29c65cc4
|
||||
F ext/wasm/api/sqlite3-api-glue.c-pp.js 79a54b54ca6324d28e31e19b56bbaebb7d2cc4b3079066e7e901333fa5047c53
|
||||
F ext/wasm/api/sqlite3-api-oo1.c-pp.js 31dbfd470c91ffd96d77399b749bab6b69e3ba9074188833f97ac13f087cf07b
|
||||
F ext/wasm/api/sqlite3-api-prologue.js a7cab3e8f78d5a93d7173657677fef18265f48d4e0b1e1755740f734a69cae6d
|
||||
F ext/wasm/api/sqlite3-api-prologue.js 68cf99ffc9742462323da3f3b207027472214727a750a952c6c10d53b11a3fa6
|
||||
F ext/wasm/api/sqlite3-api-worker1.c-pp.js 1041dd645e8e821c082b628cd8d9acf70c667430f9d45167569633ffc7567938
|
||||
F ext/wasm/api/sqlite3-license-version-header.js 0c807a421f0187e778dc1078f10d2994b915123c1223fe752b60afdcd1263f89
|
||||
F ext/wasm/api/sqlite3-opfs-async-proxy.js 9654b565b346dc609b75d15337f20acfa7af7d9d558da1afeb9b6d8eaa404966
|
||||
F ext/wasm/api/sqlite3-vfs-helper.c-pp.js 3f828cc66758acb40e9c5b4dcfd87fd478a14c8fb7f0630264e6c7fa0e57515d
|
||||
F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 26cb41d5a62f46a106b6371eb00fef02de3cdbfaa51338ba087a45f53028e0d0
|
||||
F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js aa330fa0e8ef35cbd92eb0d52e05fbaa07e61540c5cb164e693c82428ce1d763
|
||||
F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 418c33fe284739564daab3c7a7a88882fdd3c99137497900f98eddec1e409af5
|
||||
F ext/wasm/api/sqlite3-vtab-helper.c-pp.js 9097074724172e31e56ce20ccd7482259cf72a76124213cbc9469d757676da86
|
||||
F ext/wasm/api/sqlite3-wasm.c 03451f8335f4ba8ea9a79dfc170560b1ee5376de64ff49c1a114274ccf50ab3d
|
||||
F ext/wasm/api/sqlite3-wasm.c 2d1cbe498f7b0fb64b11451eda481f458df74d6258baea635513e637fcbb8b1a
|
||||
F ext/wasm/api/sqlite3-worker1-promiser.c-pp.js bda1c75bd674a92a0e27cc2f3d46dbbf21e422413f8046814515a0bd7409328a
|
||||
F ext/wasm/api/sqlite3-worker1.c-pp.js 802d69ead8c38dc1be52c83afbfc77e757da8a91a2e159e7ed3ecda8b8dba2e7
|
||||
F ext/wasm/c-pp-lite.c 943be1a36774d58385dca32de36fc18d4f432fe79f7aa35e6c85dd6a6b825bd0
|
||||
F ext/wasm/common/SqliteTestUtil.js 7adaeffef757d8708418dc9190f72df22367b531831775804b31598b44f6aa51
|
||||
F ext/wasm/common/emscripten.css 11bd104b6c0d597c67d40cc8ecc0a60dae2b965151e3b6a37fa5708bac3acd15
|
||||
F ext/wasm/common/testing.css e97549bab24126c24e0daabfe2de9bb478fb0a69fdb2ddd0a73a992c091aad6f
|
||||
F ext/wasm/common/whwasmutil.js 804409dec98458f732b23e6e86788934ac6dec002107435cc4055355585d1c15
|
||||
F ext/wasm/common/whwasmutil.js b4fd73fac162406e67f276647ff8bae51881e15eebdf4b725aeb2b10ab1e056a
|
||||
F ext/wasm/config.make.in c424ae1cc3c89274520ad312509d36c4daa34a3fce5d0c688e5f8f4365e1049a
|
||||
F ext/wasm/demo-123-worker.html a0b58d9caef098a626a1a1db567076fca4245e8d60ba94557ede8684350a81ed
|
||||
F ext/wasm/demo-123.html 8c70a412ce386bd3796534257935eb1e3ea5c581e5d5aea0490b8232e570a508
|
||||
@@ -627,7 +631,7 @@ F ext/wasm/index.html 54e27db740695ab2cb296e02d42c4c66b3f11b65797340d19fa6590f5b
|
||||
F ext/wasm/jaccwabyt/jaccwabyt.js 1e734c624205cdf621f322972dfb0fc8013d573a5882f57492a6830e5ec23e17
|
||||
F ext/wasm/jaccwabyt/jaccwabyt.md 167fc0b624c9bc2c477846e336de9403842d81b1a24fc4d3b24317cb9eba734f
|
||||
F ext/wasm/mkdist.sh 64d53f469c823ed311f6696f69cec9093f745e467334b34f5ceabdf9de3c5b28 x
|
||||
F ext/wasm/mkwasmbuilds.c ef42e404236dd98cedb6ecea47b6d2474e3c593633ce6d992d316289dfc442b6
|
||||
F ext/wasm/mkwasmbuilds.c 9b02298593276962a6136575630498d452de5055f4a4737a3c254c1b04e7cc04
|
||||
F ext/wasm/module-symbols.html e54f42112e0aac2a31f850ab33e7f2630a2ea4f63496f484a12469a2501e07e2
|
||||
F ext/wasm/scratchpad-wasmfs.html a3d7388f3c4b263676b58b526846e9d02dfcb4014ff29d3a5040935286af5b96
|
||||
F ext/wasm/scratchpad-wasmfs.mjs 66034b9256b218de59248aad796760a1584c1dd842231505895eff00dbd57c63
|
||||
@@ -653,7 +657,7 @@ F ext/wasm/tests/opfs/sahpool/index.html be736567fd92d3ecb9754c145755037cbbd2bca
|
||||
F ext/wasm/tests/opfs/sahpool/sahpool-pausing.js f264925cfc82155de38cecb3d204c36e0f6991460fff0cb7c15079454679a4e2
|
||||
F ext/wasm/tests/opfs/sahpool/sahpool-worker.js bd25a43fc2ab2d1bafd8f2854ad3943ef673f7c3be03e95ecf1612ff6e8e2a61
|
||||
F magic.txt 5ade0bc977aa135e79e3faaea894d5671b26107cc91e70783aa7dc83f22f3ba0
|
||||
F main.mk 29078d11f7545a8fae4347305b164bb4e777b801da16baeb48214014a8d63a06
|
||||
F main.mk 27a0769b40a813343f19e8fca2e9d55405f0311cb3cc5327f5702640df0182a0
|
||||
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
|
||||
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
|
||||
F mptest/crash01.test 61e61469e257df0850df4293d7d4d6c2af301421
|
||||
@@ -673,7 +677,7 @@ F src/btmutex.c 30dada73a819a1ef5b7583786370dce1842e12e1ad941e4d05ac29695528daea
|
||||
F src/btree.c 8850125300b9780fa54bc45a41af88eb2796b90f2f97942279094beef9b0e971
|
||||
F src/btree.h e823c46d87f63d904d735a24b76146d19f51f04445ea561f71cc3382fd1307f0
|
||||
F src/btreeInt.h 9c0f9ea5c9b5f4dcaea18111d43efe95f2ac276cd86d770dce10fd99ccc93886
|
||||
F src/build.c 62cf7d885a93d87dcdb2a314408b760367cd9d9b54f8d4ea7d71d0cd36f0ab4c
|
||||
F src/build.c 611e07299d72ff04bbcb9e7109183467e30925d203c3e121ef9bb3cf6876289b
|
||||
F src/callback.c 3605bbf02bd7ed46c79cd48346db4a32fc51d67624400539c0532f4eead804ad
|
||||
F src/carray.c ff6081a31878fc34df8fa1052a9cbf17ddc22652544dcb3e2326886ed1053b55
|
||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||
@@ -726,20 +730,20 @@ F src/pcache.h 1497ce1b823cf00094bb0cf3bac37b345937e6f910890c626b16512316d3abf5
|
||||
F src/pcache1.c 131ca0daf4e66b4608d2945ae76d6ed90de3f60539afbd5ef9ec65667a5f2fcd
|
||||
F src/pragma.c ecec75795c1821520266e4f93fa8840cce48979af532db06f085e36a7813860f
|
||||
F src/prepare.c 2af0b5c1ec787c8eebd21baa9d79caf4a4dc3a18e76ce2edbf2027d706bca37a
|
||||
F src/printf.c b1b29b5e58e1530d5daeee5963d3c318d8ab2d7e38437580e28755753e0c1ded
|
||||
F src/printf.c 0f6c73d1427e397c631bfaf1e0117b12c9c0545e4c2e44987237ec7849c92044
|
||||
F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
|
||||
F src/resolve.c 5616fbcf3b833c7c705b24371828215ad0925d0c0073216c4f153348d5753f0a
|
||||
F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
|
||||
F src/select.c ba9cd07ffa3277883c1986085f6ddc4320f4d35d5f212ab58df79a7ecc1a576a
|
||||
F src/shell.c.in ceb0a9cc008ac82d8d2e6ef353db14a54bc40dfd60a8cfbb6bc98d071f538761
|
||||
F src/sqlite.h.in 667dff873941366da98da3200cf757ac05dfb62ea785e6642e33dd586ae5285c
|
||||
F src/shell.c.in ee5c0326a045f83f27705ef07746c84e532654bdadac3cc3824da6d7dab2ccf5
|
||||
F src/sqlite.h.in 795ce84cc136b4e74d882cf4fab56d2927c20b9af9fd2fcea27760a6fe50851b
|
||||
F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479
|
||||
F src/sqlite3ext.h 5d5330f5f8461f5ce74960436ddcfa53ecd09c2b8b23901e22ae38aec3243998
|
||||
F src/sqliteInt.h 775c133757bd5c7d0fce10407959ee45993678ae95088e4ebdb22ef24e9d78ff
|
||||
F src/sqliteInt.h 88f7fc9ce1630d9a5f7e0a8e1f3287cdc63882fba985c18e7eee1b9f457f59aa
|
||||
F src/sqliteLimit.h fe70bd8983e5d317a264f2ea97473b359faf3ebb0827877a76813f5cf0cdc364
|
||||
F src/status.c 7565d63a79aa2f326339a24a0461a60096d0bd2bce711fefb50b5c89335f3592
|
||||
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
|
||||
F src/tclsqlite.c 3c604c49e6cf4211960a9ddb9505280fd22cde32175f40884c641c0f5a286036
|
||||
F src/tclsqlite.c 381384fbe3cf342115f9ad01208fa81092e9a2156a4ea4d44de87852b8df3a8a
|
||||
F src/tclsqlite.h 614b3780a62522bc9f8f2b9fb22689e8009958e7aa77e572d0f3149050af348a
|
||||
F src/test1.c 5d061afe479c7364842e0170be7220dea13389575fa6030d30b3e20bec4e1f75
|
||||
F src/test2.c 62f0830958f9075692c29c6de51b495ae8969e1bef85f239ffcd9ba5fb44a5ff
|
||||
@@ -883,7 +887,7 @@ F test/autoindex5.test 3fb938cbf4e7f3896563ce04e2a24b0bc653fc6245b4bf3268cd7b20f
|
||||
F test/autovacuum.test 00671369bbf96c6a49989a9425f5b78b94075d6a4b031e5e00000c2c32f365df
|
||||
F test/autovacuum2.test 76f7eb4fe6a6bf6d33a196a7141dba98886d2fb53a268d7feca285d5da4759d7
|
||||
F test/autovacuum_ioerr2.test 8a367b224183ad801e0e24dcb7d1501f45f244b4
|
||||
F test/avfs.test 76f59743dc1f5fa533840d1818b420fe1ee45e21c0fd6bbac7942ba677903128
|
||||
F test/avfs.test 95bb8d04f8edad6dc9e600221d103f7e2cc3da398af84df215a3a819e560c45c
|
||||
F test/avtrans.test 7a6eae44763293024b137b53ff824d8500d754dbae060a8d940afbacfc1d4a15
|
||||
F test/backcompat.test f2431465ed668f09fc3f6998e56e893a1506ccea6e8b6f409f085f759f431b48
|
||||
F test/backup.test 3b08fd4af69f0fa786931103a31f4542b184aba16e239e5f22b18c3c2476697f
|
||||
@@ -1433,6 +1437,7 @@ F test/mmap4.test 2e2b4e32555b58da15176e6fe750f17c9dcf7f93
|
||||
F test/mmapcorrupt.test 470fb44fe92e99c1d23701d156f8c17865f5b027063c9119dcfdb842791f4465
|
||||
F test/mmapfault.test d4c9eff9cd8c2dc14bc43e71e042f175b0a26fe3
|
||||
F test/mmapwarm.test 2272005969cd17a910077bd5082f70bc1fefad9a875afec7fc9af483898ecaf3
|
||||
F test/modeA.clitest 73d091c785671f629af0900f0654a28468bbba5685a545c1513049c57f1b8cbc
|
||||
F test/multiplex.test d74c034e52805f6de8cc5432cef8c9eb774bb64ec29b83a22effc8ca4dac1f08
|
||||
F test/multiplex2.test 580ca5817c7edbe4cc68fa150609c9473393003a
|
||||
F test/multiplex3.test fac575e0b1b852025575a6a8357701d80933e98b5d2fe6d35ddaa68f92f6a1f7
|
||||
@@ -1502,6 +1507,9 @@ F test/printf2.test 3f55c1871a5a65507416076f6eb97e738d5210aeda7595a74ee895f2224c
|
||||
F test/progress.test ebab27f670bd0d4eb9d20d49cef96e68141d92fb
|
||||
F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc
|
||||
F test/pushdown.test 46a626ef1c0ca79b85296ff2e078b9da20a50e9b804b38f441590c3987580ddd
|
||||
F test/qrf01.test dfdbbd2b5f2808f5ff6598c8632ee002389b690eb5016450c2f847d8e51b9b92
|
||||
F test/qrf02.test 39b4afdc000bedccdafc0aecf17638df67a67aaa2d2942865ae6abcc48ba0e92
|
||||
F test/qrf03.test 9d88aeb5cdd53f050b7ab9bd203281f7c9d063c33f22f8808e441b7ac0874ccf
|
||||
F test/queryonly.test 5f653159e0f552f0552d43259890c1089391dcca
|
||||
F test/quick.test 1681febc928d686362d50057c642f77a02c62e57
|
||||
F test/quickcheck.test a4b7e878cd97e46108291c409b0bf8214f29e18fddd68a42bc5c1375ad1fb80a
|
||||
@@ -1514,7 +1522,7 @@ F test/randexpr1.test eda062a97e60f9c38ae8d806b03b0ddf23d796df
|
||||
F test/rbu.test 168573d353cd0fd10196b87b0caa322c144ef736
|
||||
F test/rdonly.test 64e2696c322e3538df0b1ed624e21f9a23ed9ff8
|
||||
F test/readonly.test 0d307c335b3421898cfe64a783a376138aa003849b6bff61ee2d21e805bc0051
|
||||
F test/recover.test c76d05f33f0271fba0f0752170e03b0ab5952dc61dcea7ab3ba40df03c4c42de
|
||||
F test/recover.test 643139b911ac880a1e881d7621f02cfb546b608b8f2494d7d26fd5ed103b1ceb
|
||||
F test/regexp1.test 8f2a8bc1569666e29a4cee6c1a666cd224eb6d50e2470d1dc1df995170f3e0f1
|
||||
F test/regexp2.test 64f9726b2ddc71aea06725fcad53231833d038d58b936d49083ace658b370a13
|
||||
F test/reindex.test cd9d6021729910ece82267b4f5e1b5ac2911a7566c43b43c176a6a4732e2118d
|
||||
@@ -1595,16 +1603,17 @@ F test/sharedA.test 64bdd21216dda2c6a3bd3475348ccdc108160f34682c97f2f51c19fc0e21
|
||||
F test/sharedB.test 1a84863d7a2204e0d42f2e1606577c5e92e4473fa37ea0f5bdf829e4bf8ee707
|
||||
F test/shared_err.test 32634e404a3317eeb94abc7a099c556a346fdb8fb3858dbe222a4cbb8926a939
|
||||
F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304
|
||||
F test/shell1.test ebe953d64c937ad42a0f33170ac0d2d2568faae26813fc7a95203756446d54aa
|
||||
F test/shell2.test ab23f01ea2347e4b72bb2399af7ee82aa00f9c059141749f7c4064abca5ad728
|
||||
F test/shell3.test 603b448e917537cf77be0f265c05c6f63bc677c63a533c8e96aae923b56f4a0e
|
||||
F test/shell4.test 03593fa7908a55f255916ffeda707cdf55680c777736e3da62b1d78cde0d684d
|
||||
F test/shell5.test d17e7927ab8b7f720efbdd9b5d05fceb6c3c56c25917901b315400214bf24ef4
|
||||
F test/shell1.test 8fbb73650b685766cdf4b5e8b5d12dee72664f44195eeb788d0f52fce08e04eb
|
||||
F test/shell2.test 103140814bdc7508aa41dd3462413cbc4aa84b4261112cb8d501d74275cb7d48
|
||||
F test/shell3.test 840192774cc4edf7653520c0434a311c7477b9bc324abbc7bd2887915792fa8c
|
||||
F test/shell4.test e25580a792b7b54560c3a76b6968bd8189261f38979fe28e6bc6312c5db280db
|
||||
F test/shell5.test 7a249400bb2af59ac8524f357f8cf2844a62b6ac5ff8ecd69b045ceb688700ae
|
||||
F test/shell6.test e3b883b61d4916b6906678a35f9d19054861123ad91b856461e0a456273bdbb8
|
||||
F test/shell7.test 43fd8e511c533bab5232e95c7b4be93b243451709e89582600d4b6e67693d5c3
|
||||
F test/shell8.test 641cf21a99c59404c24e3062923734951c4099a6b6b6520de00cf7a1249ee871
|
||||
F test/shell9.test 8742a5b390cdcef6369f5aa223e415aa4255a4129ef249b177887dc635a87209
|
||||
F test/shellA.test 4ecff8b7b2c0122ba8174abfbcc4b0f59e44d80f2a911068f8cd4cfc6661032d
|
||||
F test/shellA.test 4ece22f204532fb04ab702c5b9c70d8680ff610bff1e82c849c16a7b5cd57d83
|
||||
F test/shellB.test ca8a5ce5b9a59098732fa140c911162f0306f70239c6c2de6da9b718ca304cad
|
||||
F test/shmlock.test 9f1f729a7fe2c46c88b156af819ac9b72c0714ac6f7246638a73c5752b5fd13c
|
||||
F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3
|
||||
F test/show_speedtest1_rtree.tcl 32e6c5f073d7426148a6936a0408f4b5b169aba5
|
||||
@@ -1678,7 +1687,7 @@ F test/tabfunc01.test 56eeae736217204bb1d9f9ef38340d48058f809b64249217cf77ff4ba6
|
||||
F test/table.test e87294bf1c80bfd7792142b84ab32ea5beb4f3f71e535d7fb263a6b2068377bf
|
||||
F test/tableapi.test e37c33e6be2276e3a96bb54b00eea7f321277115d10e5b30fdb52a112b432750
|
||||
F test/tableopts.test dba698ba97251017b7c80d738c198d39ab747930
|
||||
F test/tclsqlite.test 3f697424cfc1cdc9c076ec0cadb0e700f059400a3e3ce134b7d856fc9f880e1c
|
||||
F test/tclsqlite.test 5d6c73bfe7006c85e2f7fb7db8638b521eb2043d5451aaacdac4851eab895443
|
||||
F test/tempdb.test 4cdaa23ddd8acb4d79cbb1b68ccdfd09b0537aaba909ca69a876157c2a2cbd08
|
||||
F test/tempdb2.test 353864e96fd3ae2f70773d0ffbf8b1fe48589b02c2ec05013b540879410c3440
|
||||
F test/tempfault.test 0c0d349c9a99bf5f374655742577f8712c647900
|
||||
@@ -1690,7 +1699,7 @@ F test/tester.tcl 463ae33b8bf75ac77451df19bd65e7c415c2e9891227c7c9e657d0a2d8e107
|
||||
F test/testloadext.c 862b848783eaed9985fbce46c65cd214664376b549fae252b364d5d1ef350a27
|
||||
F test/testrunner.tcl 86179a8e78997e9257cb8f738c5624cb23897da5297855578ba74715e64f1602 x
|
||||
F test/testrunner_data.tcl c507a9afa911c03446ed90442ffd4a98aca02882c3d51bd1177c24795674def8
|
||||
F test/testrunner_estwork.tcl 7927a84327259a32854926f68a75292e33a61e7e052fdbfcb01f18696c99c724
|
||||
F test/testrunner_estwork.tcl 81e2ae10238f50540f42fbf2d94913052a99bfb494b69e546506323f195dcff9
|
||||
F test/thread001.test a0985c117eab62c0c65526e9fa5d1360dd1cac5b03bde223902763274ce21899
|
||||
F test/thread002.test c24c83408e35ba5a952a3638b7ac03ccdf1ce4409289c54a050ac4c5f1de7502
|
||||
F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7
|
||||
@@ -2111,6 +2120,7 @@ F tool/merge-test.tcl de76b62f2de2a92d4c1ca4f976bce0aea6899e0229e250479b229b2a19
|
||||
F tool/mkamalzip.tcl 8aa5ebe7973c8b8774062d34e15fea9815c4cc2ceea3a9b184695f005910876a
|
||||
F tool/mkautoconfamal.sh 647dada5e34c466bef62a4408e1c99a7e5e1922805479dd57944f33f9803f2f8
|
||||
F tool/mkccode.tcl c42a8f8cf78f92e83795d5447460dbce7aaf78a3bbf9082f1507dc71a3665f3c x
|
||||
F tool/mkcombo.tcl 2a5189b219c4a495e1ff7fc980bd568d3cfb82ae9d50c84e77f7a161e96fc132
|
||||
F tool/mkctimec.tcl 3fb5cad05922f5da61262cb6bcd5868a34e94a49ca8833ae2d7796e7df075576 x
|
||||
F tool/mkkeywordhash.c 6b0be901c47f9ad42215fc995eb2f4384ac49213b1fba395102ec3e999acf559
|
||||
F tool/mkmsvcmin.tcl d76c45efda1cce2d4005bcea7b8a22bb752e3256009f331120fb4fecb14ebb7a
|
||||
@@ -2118,7 +2128,7 @@ F tool/mkopcodec.tcl 33d20791e191df43209b77d37f0ff0904620b28465cca6990cf8d60da61
|
||||
F tool/mkopcodeh.tcl 2b4e6967a670ef21bf53a164964c35c6163277d002a4c6f56fa231d68c88d023
|
||||
F tool/mkopts.tcl 680f785fdb09729fd9ac50632413da4eadbdf9071535e3f26d03795828ab07fa
|
||||
F tool/mkpragmatab.tcl 3801ce32f8c55fe63a3b279f231fb26c2c1a2ea9a09d2dd599239d87a609acec
|
||||
F tool/mkshellc.tcl bab0a72a68384181a5706712dfdf6815f6526446d4e8aacace2de5e80cda91b2
|
||||
F tool/mkshellc.tcl 1c9197524174237b580dc1a6d1552541c5f5b78162949b4b8e640a7aef688d40
|
||||
F tool/mksourceid.c 36aa8020014aed0836fd13c51d6dc9219b0df1761d6b5f58ff5b616211b079b9
|
||||
F tool/mksqlite3c-noext.tcl 351c55256213154cabb051a3c870ef9f4487de905015141ae50dc7578a901b84
|
||||
F tool/mksqlite3c.tcl 7a268139158e5deef27a370bc2f8db6ccf100c1ad7ac5e5b23743c0fd354f609
|
||||
@@ -2149,7 +2159,7 @@ F tool/split-sqlite3c.tcl 4969fd642dad0ea483e4e104163021d92baf98f6a8eac981fe4852
|
||||
F tool/sqldiff.c 134be7866be19f8beb32043d5aea5657f01aaeae2df8d33d758ff722c78666b9
|
||||
F tool/sqlite3_analyzer.c.in 14f02cb5ec3c264cd6107d1f1dad77092b1cf440fc196c30b69ae87b56a1a43b
|
||||
F tool/sqlite3_rsync.c d0e58a1e49fe2192c3ee0b697aed182d502bebfe5b4b406ba6b2baa52a04ecbe
|
||||
F tool/sqltclsh.c.in 1bcc2e9da58fadf17b0bf6a50e68c1159e602ce057210b655d50bad5aaaef898
|
||||
F tool/sqltclsh.c.in c103c6fc7d42bce611f9d4596774d60b7ef3d0b291a1f58c9e6184e458b89296
|
||||
F tool/sqltclsh.tcl 862f4cf1418df5e1315b5db3b5ebe88969e2a784525af5fbf9596592f14ed848
|
||||
F tool/src-verify.c 6c655d9a8d6b30f3648fc78a79bf3838ed68f8543869d380c43ea9f17b3b8501
|
||||
F tool/srcck1.c 559e703c6cca1d70398bdba1d7f91036c1a71adf718a1aaa6401a562ccaed154
|
||||
@@ -2166,11 +2176,8 @@ F tool/version-info.c 33d0390ef484b3b1cb685d59362be891ea162123cea181cb8e6d2cf6dd
|
||||
F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
|
||||
F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98
|
||||
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
||||
P 6621737cc05cbf8ff5f576775a8a3c64f666b56d42939968ebb55d72a835646b
|
||||
R d682117481a7b1cf594f7dd8ef6eff70
|
||||
T *branch * max-subquery
|
||||
T *sym-max-subquery *
|
||||
T -sym-trunk *
|
||||
P fd09f934d64ec07fd56f1b80ab05dafb28b605d5802ff5758eea17d8ad24e3cc
|
||||
R 6cfd84a13cbe695177bf002c2876e553
|
||||
U drh
|
||||
Z 62a7b6290233b3d348ba184dec1ce219
|
||||
Z ac921b72c830caadbe8526f354a297ee
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
||||
+2
-2
@@ -1,2 +1,2 @@
|
||||
branch max-subquery
|
||||
tag max-subquery
|
||||
branch qrf
|
||||
tag qrf
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
35ec117e5a20f30030a37d2fbd059654bb13d0ec64fcf8719d71d9a4318dc970
|
||||
3d55ec15a9e4dc8af4bf1e2884eaa2c809995fb1529633f73287dc7a54153629
|
||||
|
||||
@@ -5019,11 +5019,6 @@ int sqlite3SrcItemAttachSubquery(
|
||||
Subquery *p;
|
||||
assert( pSelect!=0 );
|
||||
assert( pItem->fg.isSubquery==0 );
|
||||
#if SQLITE_MAX_SUBQUERY+0 > 0
|
||||
if( pParse->nSubquery++ > SQLITE_MAX_SUBQUERY ){
|
||||
sqlite3ErrorMsg(pParse, "Too many subqueries");
|
||||
}
|
||||
#endif
|
||||
if( pItem->fg.fixedSchema ){
|
||||
pItem->u4.pSchema = 0;
|
||||
pItem->fg.fixedSchema = 0;
|
||||
|
||||
+1
-1
@@ -1230,7 +1230,7 @@ int sqlite3_str_length(sqlite3_str *p){
|
||||
|
||||
/* Truncate the text of the string to be no more than N bytes. */
|
||||
void sqlite3_str_truncate(sqlite3_str *p, int N){
|
||||
if( p!=0 && N>=0 && (u32)N<p->nChar ){
|
||||
if( p!=0 && N>=0 && N<p->nChar ){
|
||||
p->nChar = N;
|
||||
p->zText[p->nChar] = 0;
|
||||
}
|
||||
|
||||
+2671
-3535
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -8730,7 +8730,7 @@ sqlite3_str *sqlite3_str_new(sqlite3*);
|
||||
**
|
||||
** ^The [sqlite3_str_free(X)] interface destroys both the sqlite3_str object
|
||||
** X and the string content it contains. Calling sqlite3_str_free(X) is
|
||||
** the equivalent of calling [sqlite3_free](sqlite3_str_finish(X)).
|
||||
** the equivalent of calling [sqlite3_free](sqlite3_str_finalize(X)).
|
||||
*/
|
||||
char *sqlite3_str_finish(sqlite3_str*);
|
||||
void sqlite3_str_free(sqlite3_str*);
|
||||
|
||||
@@ -3942,9 +3942,6 @@ struct Parse {
|
||||
yDbMask cookieMask; /* Bitmask of schema verified databases */
|
||||
int nMaxArg; /* Max args to xUpdate and xFilter vtab methods */
|
||||
int nSelect; /* Number of SELECT stmts. Counter for Select.selId */
|
||||
#if SQLITE_MAX_SUBQUERY+0 > 0
|
||||
u32 nSubquery; /* Number of subqueries seen so far */
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
|
||||
u32 nProgressSteps; /* xProgress steps taken during sqlite3_prepare() */
|
||||
#endif
|
||||
|
||||
+382
-17
@@ -124,6 +124,15 @@
|
||||
/* Forward declaration */
|
||||
typedef struct SqliteDb SqliteDb;
|
||||
|
||||
/* Add -DSQLITE_ENABLE_QRF_IN_TCL to add the Query Result Formatter (QRF)
|
||||
** into the build of the TCL extension, when building using separate
|
||||
** source files. The QRF is included automatically when building from
|
||||
** the tclsqlite3.c amalgamation.
|
||||
*/
|
||||
#if defined(SQLITE_ENABLE_QRF_IN_TCL)
|
||||
#include "qrf.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
** New SQL functions can be created as TCL scripts. Each such function
|
||||
** is described by an instance of the following structure.
|
||||
@@ -2035,6 +2044,349 @@ static void DbHookCmd(
|
||||
sqlite3_wal_hook(db, (pDb->pWalHook?DbWalHandler:0), pDb);
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the "db format" command.
|
||||
**
|
||||
** Based on provided options, format the results of the SQL statement(s)
|
||||
** provided into human-readable form using the Query Result Formatter (QRF)
|
||||
** and return the resuling text.
|
||||
**
|
||||
** Syntax: db format OPTIONS SQL
|
||||
**
|
||||
** OPTIONS may be:
|
||||
**
|
||||
** -style ("auto"|"box"|"column"|...) Output style
|
||||
** -esc ("auto"|"off"|"ascii"|"symbol") How to deal with ctrl chars
|
||||
** -text ("auto"|"off"|"sql"|"csv"|...) How to escape TEXT values
|
||||
** -title ("auto"|"off"|"sql"|...|"off") How to escape column names
|
||||
** -blob ("auto"|"text"|"sql"|...) How to escape BLOB values
|
||||
** -wordwrap ("auto"|"off"|"on") Try to wrap at word boundry?
|
||||
** -textjsonb ("auto"|"off"|"on") Auto-convert JSONB to text?
|
||||
** -textnull ("auto"|"off"|"on") Use text encoding for -null.
|
||||
** -defaultalign ("auto"|"left"|...) Default alignment
|
||||
** -titalalign ("auto"|"left"|"right"|...) Default column name alignment
|
||||
** -wrap NUMBER Max width of any single column
|
||||
** -screenwidth NUMBER Width of the display TTY
|
||||
** -linelimit NUMBER Max lines for any cell
|
||||
** -charlimit NUMBER Content truncated to this size
|
||||
** -align LIST-OF-ALIGNMENT Alignment of columns
|
||||
** -widths LIST-OF-NUMBERS Widths for individual columns
|
||||
** -columnsep TEXT Column separator text
|
||||
** -rowsep TEXT Row separator text
|
||||
** -tablename TEXT Table name for style "insert"
|
||||
** -null TEXT Text for NULL values
|
||||
**
|
||||
** A mapping from TCL "format" command options to sqlite3_qrf_spec fields
|
||||
** is below. Use this to reference the QRF documentation:
|
||||
**
|
||||
** TCL Option spec field
|
||||
** ---------- ----------
|
||||
** -style eStyle
|
||||
** -esc eEsc
|
||||
** -text eText
|
||||
** -title eTitle, bTitle
|
||||
** -blob eBlob
|
||||
** -wordwrap bWordWrap
|
||||
** -textjsonb bTextJsonb
|
||||
** -textnull bTestNull
|
||||
** -defaultalign eDfltAlign
|
||||
** -titlealign eTitleAlign
|
||||
** -wrap nWrap
|
||||
** -screenwidth nScreenWidth
|
||||
** -linelimit nLineLimit
|
||||
** -charlimit nCharLimit
|
||||
** -align nAlign, aAlign
|
||||
** -widths nWidth, aWidth
|
||||
** -columnsep zColumnSep
|
||||
** -rowsep zRowSep
|
||||
** -tablename zTableName
|
||||
** -null zNull
|
||||
*/
|
||||
static int dbQrf(SqliteDb *pDb, int objc, Tcl_Obj *const*objv){
|
||||
#ifndef SQLITE_QRF_H
|
||||
Tcl_SetResult(pDb->interp, "QRF not available in this build", TCL_VOLATILE);
|
||||
return TCL_ERROR;
|
||||
#else
|
||||
char *zResult = 0; /* Result to be returned */
|
||||
const char *zSql = 0; /* SQL to run */
|
||||
int i; /* Loop counter */
|
||||
int rc; /* Result code */
|
||||
sqlite3_qrf_spec qrf; /* Formatting spec */
|
||||
static const char *azAlign[] = {
|
||||
"auto", "bottom", "c",
|
||||
"center", "e", "left",
|
||||
"middle", "n", "ne",
|
||||
"nw", "right", "s",
|
||||
"se", "sw", "top",
|
||||
"w", 0
|
||||
};
|
||||
static const unsigned char aAlignMap[] = {
|
||||
QRF_ALIGN_Auto, QRF_ALIGN_Bottom, QRF_ALIGN_C,
|
||||
QRF_ALIGN_Center, QRF_ALIGN_E, QRF_ALIGN_Left,
|
||||
QRF_ALIGN_Middle, QRF_ALIGN_N, QRF_ALIGN_NE,
|
||||
QRF_ALIGN_NW, QRF_ALIGN_Right, QRF_ALIGN_S,
|
||||
QRF_ALIGN_SE, QRF_ALIGN_SW, QRF_ALIGN_Top,
|
||||
QRF_ALIGN_W
|
||||
};
|
||||
|
||||
memset(&qrf, 0, sizeof(qrf));
|
||||
qrf.iVersion = 1;
|
||||
qrf.pzOutput = &zResult;
|
||||
for(i=2; i<objc; i++){
|
||||
const char *zArg = Tcl_GetString(objv[i]);
|
||||
const char *azBool[] = { "auto", "yes", "no", "on", "off", 0 };
|
||||
const unsigned char aBoolMap[] = { 0, 2, 1, 2, 1 };
|
||||
if( zArg[0]!='-' ){
|
||||
if( zSql ){
|
||||
Tcl_AppendResult(pDb->interp, "unknown argument: ", zArg, (char*)0);
|
||||
rc = TCL_ERROR;
|
||||
goto format_failed;
|
||||
}
|
||||
zSql = zArg;
|
||||
}else if( i==objc-1 ){
|
||||
Tcl_AppendResult(pDb->interp, "option has no argument: ", zArg, (char*)0);
|
||||
rc = TCL_ERROR;
|
||||
goto format_failed;
|
||||
}else if( strcmp(zArg,"-style")==0 ){
|
||||
static const char *azStyles[] = {
|
||||
"auto", "box", "column",
|
||||
"count", "csv", "eqp",
|
||||
"explain", "html", "insert",
|
||||
"jobject", "json", "line",
|
||||
"list", "markdown", "quote",
|
||||
"stats", "stats-est", "stats-vm",
|
||||
"table", 0
|
||||
};
|
||||
static unsigned char aStyleMap[] = {
|
||||
QRF_STYLE_Auto, QRF_STYLE_Box, QRF_STYLE_Column,
|
||||
QRF_STYLE_Count, QRF_STYLE_Csv, QRF_STYLE_Eqp,
|
||||
QRF_STYLE_Explain, QRF_STYLE_Html, QRF_STYLE_Insert,
|
||||
QRF_STYLE_JObject, QRF_STYLE_Json, QRF_STYLE_Line,
|
||||
QRF_STYLE_List, QRF_STYLE_Markdown, QRF_STYLE_Quote,
|
||||
QRF_STYLE_Stats, QRF_STYLE_StatsEst, QRF_STYLE_StatsVm,
|
||||
QRF_STYLE_Table
|
||||
};
|
||||
int style;
|
||||
rc = Tcl_GetIndexFromObj(pDb->interp, objv[i+1], azStyles,
|
||||
"format style (-style)", 0, &style);
|
||||
if( rc ) goto format_failed;
|
||||
qrf.eStyle = aStyleMap[style];
|
||||
i++;
|
||||
}else if( strcmp(zArg,"-esc")==0 ){
|
||||
static const char *azEsc[] = {
|
||||
"ascii", "auto", "off", "symbol", 0
|
||||
};
|
||||
static unsigned char aEscMap[] = {
|
||||
QRF_ESC_Ascii, QRF_ESC_Auto, QRF_ESC_Off, QRF_ESC_Symbol
|
||||
};
|
||||
int esc;
|
||||
rc = Tcl_GetIndexFromObj(pDb->interp, objv[i+1], azEsc,
|
||||
"control character escape (-esc)", 0, &esc);
|
||||
if( rc ) goto format_failed;
|
||||
qrf.eEsc = aEscMap[esc];
|
||||
i++;
|
||||
}else if( strcmp(zArg,"-text")==0 || strcmp(zArg, "-title")==0 ){
|
||||
/* NB: --title can be "off" or "on but --text may not be. Thus we put
|
||||
** the "off" and "on" choices first and start the search on the
|
||||
** thrid element of the array when processing --text */
|
||||
static const char *azText[] = { "off", "on",
|
||||
"auto", "csv", "html",
|
||||
"json", "plain", "sql",
|
||||
"tcl", 0
|
||||
};
|
||||
static unsigned char aTextMap[] = {
|
||||
QRF_TEXT_Auto, QRF_TEXT_Csv, QRF_TEXT_Html,
|
||||
QRF_TEXT_Json, QRF_TEXT_Plain, QRF_TEXT_Sql,
|
||||
QRF_TEXT_Tcl
|
||||
};
|
||||
int txt;
|
||||
int k = zArg[2]=='e';
|
||||
rc = Tcl_GetIndexFromObj(pDb->interp, objv[i+1], &azText[k*2], zArg,
|
||||
0, &txt);
|
||||
if( rc ) goto format_failed;
|
||||
if( k ){
|
||||
qrf.eText = aTextMap[txt];
|
||||
}else if( txt<=1 ){
|
||||
qrf.bTitles = txt ? QRF_Yes : QRF_No;
|
||||
qrf.eTitle = QRF_TEXT_Auto;
|
||||
}else{
|
||||
qrf.bTitles = QRF_Yes;
|
||||
qrf.eTitle = aTextMap[txt-2];
|
||||
}
|
||||
i++;
|
||||
}else if( strcmp(zArg,"-blob")==0 ){
|
||||
static const char *azBlob[] = {
|
||||
"auto", "hex", "json",
|
||||
"tcl", "text", "sql", 0
|
||||
};
|
||||
static unsigned char aBlobMap[] = {
|
||||
QRF_BLOB_Auto, QRF_BLOB_Hex, QRF_BLOB_Json,
|
||||
QRF_BLOB_Tcl, QRF_BLOB_Text, QRF_BLOB_Sql
|
||||
};
|
||||
int blob;
|
||||
rc = Tcl_GetIndexFromObj(pDb->interp, objv[i+1], azBlob,
|
||||
"BLOB encoding (-blob)", 0, &blob);
|
||||
if( rc ) goto format_failed;
|
||||
qrf.eBlob = aBlobMap[blob];
|
||||
i++;
|
||||
}else if( strcmp(zArg,"-wordwrap")==0 ){
|
||||
int v = 0;
|
||||
rc = Tcl_GetIndexFromObj(pDb->interp, objv[i+1], azBool,
|
||||
"-wordwrap", 0, &v);
|
||||
if( rc ) goto format_failed;
|
||||
qrf.bWordWrap = aBoolMap[v];
|
||||
i++;
|
||||
}else if( strcmp(zArg,"-textjsonb")==0 || strcmp(zArg,"-textnull")==0 ){
|
||||
int v = 0;
|
||||
rc = Tcl_GetIndexFromObj(pDb->interp, objv[i+1], azBool,
|
||||
zArg, 0, &v);
|
||||
if( rc ) goto format_failed;
|
||||
if( zArg[5]=='j' ){
|
||||
qrf.bTextJsonb = aBoolMap[v];
|
||||
}else{
|
||||
qrf.bTextNull = aBoolMap[v];
|
||||
}
|
||||
i++;
|
||||
}else if( strcmp(zArg,"-defaultalign")==0 || strcmp(zArg,"-titlealign")==0){
|
||||
int ax = 0;
|
||||
rc = Tcl_GetIndexFromObj(pDb->interp, objv[i+1], azAlign,
|
||||
zArg[1]=='d' ? "default alignment (-defaultalign)" :
|
||||
"title alignment (-titlealign)",
|
||||
0, &ax);
|
||||
if( rc ) goto format_failed;
|
||||
if( zArg[1]=='d' ){
|
||||
qrf.eDfltAlign = aAlignMap[ax];
|
||||
}else{
|
||||
qrf.eTitleAlign = aAlignMap[ax];
|
||||
}
|
||||
i++;
|
||||
}else if( strcmp(zArg,"-wrap")==0
|
||||
|| strcmp(zArg,"-screenwidth")==0
|
||||
|| strcmp(zArg,"-linelimit")==0
|
||||
){
|
||||
int v = 0;
|
||||
rc = Tcl_GetIntFromObj(pDb->interp, objv[i+1], &v);
|
||||
if( rc ) goto format_failed;
|
||||
if( v<QRF_MIN_WIDTH ){
|
||||
v = QRF_MIN_WIDTH;
|
||||
}else if( v>QRF_MAX_WIDTH ){
|
||||
v = QRF_MAX_WIDTH;
|
||||
}
|
||||
if( zArg[1]=='w' ){
|
||||
qrf.nWrap = v;
|
||||
}else if( zArg[1]=='s' ){
|
||||
qrf.nScreenWidth = v;
|
||||
}else{
|
||||
qrf.nLineLimit = v;
|
||||
}
|
||||
i++;
|
||||
}else if( strcmp(zArg,"-charlimit")==0 ){
|
||||
int v = 0;
|
||||
rc = Tcl_GetIntFromObj(pDb->interp, objv[i+1], &v);
|
||||
if( rc ) goto format_failed;
|
||||
if( v<0 ) v = 0;
|
||||
qrf.nCharLimit = v;
|
||||
i++;
|
||||
}else if( strcmp(zArg,"-align")==0 ){
|
||||
Tcl_Size n = 0;
|
||||
int jj;
|
||||
rc = Tcl_ListObjLength(pDb->interp, objv[i+1], &n);
|
||||
if( rc ) goto format_failed;
|
||||
sqlite3_free(qrf.aAlign);
|
||||
qrf.aAlign = sqlite3_malloc64( (n+1)*sizeof(qrf.aAlign[0]) );
|
||||
if( qrf.aAlign==0 ){
|
||||
Tcl_AppendResult(pDb->interp, "out of memory", (char*)0);
|
||||
rc = TCL_ERROR;
|
||||
goto format_failed;
|
||||
}
|
||||
memset(qrf.aAlign, 0, (n+1)*sizeof(qrf.aAlign[0]));
|
||||
qrf.nAlign = n;
|
||||
for(jj=0; jj<n; jj++){
|
||||
int x;
|
||||
Tcl_Obj *pTerm;
|
||||
rc = Tcl_ListObjIndex(pDb->interp, objv[i+1], jj, &pTerm);
|
||||
if( rc ) goto format_failed;
|
||||
rc = Tcl_GetIndexFromObj(pDb->interp, pTerm, azAlign,
|
||||
"column alignment (-align)", 0, &x);
|
||||
if( rc ) goto format_failed;
|
||||
qrf.aAlign[jj] = aAlignMap[x];
|
||||
}
|
||||
i++;
|
||||
}else if( strcmp(zArg,"-widths")==0 ){
|
||||
Tcl_Size n = 0;
|
||||
int jj;
|
||||
rc = Tcl_ListObjLength(pDb->interp, objv[i+1], &n);
|
||||
if( rc ) goto format_failed;
|
||||
sqlite3_free(qrf.aWidth);
|
||||
qrf.aWidth = sqlite3_malloc64( (n+1)*sizeof(qrf.aWidth[0]) );
|
||||
if( qrf.aWidth==0 ){
|
||||
Tcl_AppendResult(pDb->interp, "out of memory", (char*)0);
|
||||
rc = TCL_ERROR;
|
||||
goto format_failed;
|
||||
}
|
||||
memset(qrf.aWidth, 0, (n+1)*sizeof(qrf.aWidth[0]));
|
||||
qrf.nWidth = n;
|
||||
for(jj=0; jj<n; jj++){
|
||||
Tcl_Obj *pTerm;
|
||||
int v;
|
||||
rc = Tcl_ListObjIndex(pDb->interp, objv[i+1], jj, &pTerm);
|
||||
if( rc ) goto format_failed;
|
||||
rc = Tcl_GetIntFromObj(pDb->interp, pTerm, &v);
|
||||
if( v<(-QRF_MAX_WIDTH) ){
|
||||
v = -QRF_MAX_WIDTH;
|
||||
}else if( v>QRF_MAX_WIDTH ){
|
||||
v = QRF_MAX_WIDTH;
|
||||
}
|
||||
qrf.aWidth[jj] = (short int)v;
|
||||
}
|
||||
i++;
|
||||
}else if( strcmp(zArg,"-columnsep")==0 ){
|
||||
qrf.zColumnSep = Tcl_GetString(objv[i+1]);
|
||||
i++;
|
||||
}else if( strcmp(zArg,"-rowsep")==0 ){
|
||||
qrf.zRowSep = Tcl_GetString(objv[i+1]);
|
||||
i++;
|
||||
}else if( strcmp(zArg,"-tablename")==0 ){
|
||||
qrf.zTableName = Tcl_GetString(objv[i+1]);
|
||||
i++;
|
||||
}else if( strcmp(zArg,"-null")==0 ){
|
||||
qrf.zNull = Tcl_GetString(objv[i+1]);
|
||||
i++;
|
||||
}else{
|
||||
Tcl_AppendResult(pDb->interp, "unknown option: ", zArg, (char*)0);
|
||||
rc = TCL_ERROR;
|
||||
goto format_failed;
|
||||
}
|
||||
}
|
||||
while( zSql && zSql[0] ){
|
||||
SqlPreparedStmt *pStmt = 0; /* Next statement to run */
|
||||
char *zErr = 0; /* Error message from QRF */
|
||||
|
||||
rc = dbPrepareAndBind(pDb, zSql, &zSql, &pStmt);
|
||||
if( rc ) goto format_failed;
|
||||
if( pStmt==0 ) continue;
|
||||
rc = sqlite3_format_query_result(pStmt->pStmt, &qrf, &zErr);
|
||||
dbReleaseStmt(pDb, pStmt, 0);
|
||||
if( rc ){
|
||||
Tcl_SetResult(pDb->interp, zErr, TCL_VOLATILE);
|
||||
sqlite3_free(zErr);
|
||||
rc = TCL_ERROR;
|
||||
goto format_failed;
|
||||
}
|
||||
}
|
||||
Tcl_SetResult(pDb->interp, zResult, TCL_VOLATILE);
|
||||
rc = TCL_OK;
|
||||
/* Fall through...*/
|
||||
|
||||
format_failed:
|
||||
sqlite3_free(qrf.aWidth);
|
||||
sqlite3_free(qrf.aAlign);
|
||||
sqlite3_free(zResult);
|
||||
return rc;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** The "sqlite" command below creates a new Tcl command for each
|
||||
** connection it opens to an SQLite database. This routine is invoked
|
||||
@@ -2064,15 +2416,15 @@ static int SQLITE_TCLAPI DbObjCmd(
|
||||
"commit_hook", "complete", "config",
|
||||
"copy", "deserialize", "enable_load_extension",
|
||||
"errorcode", "erroroffset", "eval",
|
||||
"exists", "function", "incrblob",
|
||||
"interrupt", "last_insert_rowid", "nullvalue",
|
||||
"onecolumn", "preupdate", "profile",
|
||||
"progress", "rekey", "restore",
|
||||
"rollback_hook", "serialize", "status",
|
||||
"timeout", "total_changes", "trace",
|
||||
"trace_v2", "transaction", "unlock_notify",
|
||||
"update_hook", "version", "wal_hook",
|
||||
0
|
||||
"exists", "format", "function",
|
||||
"incrblob", "interrupt", "last_insert_rowid",
|
||||
"nullvalue", "onecolumn", "preupdate",
|
||||
"profile", "progress", "rekey",
|
||||
"restore", "rollback_hook", "serialize",
|
||||
"status", "timeout", "total_changes",
|
||||
"trace", "trace_v2", "transaction",
|
||||
"unlock_notify", "update_hook", "version",
|
||||
"wal_hook", 0
|
||||
};
|
||||
enum DB_enum {
|
||||
DB_AUTHORIZER, DB_BACKUP, DB_BIND_FALLBACK,
|
||||
@@ -2081,14 +2433,15 @@ static int SQLITE_TCLAPI DbObjCmd(
|
||||
DB_COMMIT_HOOK, DB_COMPLETE, DB_CONFIG,
|
||||
DB_COPY, DB_DESERIALIZE, DB_ENABLE_LOAD_EXTENSION,
|
||||
DB_ERRORCODE, DB_ERROROFFSET, DB_EVAL,
|
||||
DB_EXISTS, DB_FUNCTION, DB_INCRBLOB,
|
||||
DB_INTERRUPT, DB_LAST_INSERT_ROWID, DB_NULLVALUE,
|
||||
DB_ONECOLUMN, DB_PREUPDATE, DB_PROFILE,
|
||||
DB_PROGRESS, DB_REKEY, DB_RESTORE,
|
||||
DB_ROLLBACK_HOOK, DB_SERIALIZE, DB_STATUS,
|
||||
DB_TIMEOUT, DB_TOTAL_CHANGES, DB_TRACE,
|
||||
DB_TRACE_V2, DB_TRANSACTION, DB_UNLOCK_NOTIFY,
|
||||
DB_UPDATE_HOOK, DB_VERSION, DB_WAL_HOOK,
|
||||
DB_EXISTS, DB_FORMAT, DB_FUNCTION,
|
||||
DB_INCRBLOB, DB_INTERRUPT, DB_LAST_INSERT_ROWID,
|
||||
DB_NULLVALUE, DB_ONECOLUMN, DB_PREUPDATE,
|
||||
DB_PROFILE, DB_PROGRESS, DB_REKEY,
|
||||
DB_RESTORE, DB_ROLLBACK_HOOK, DB_SERIALIZE,
|
||||
DB_STATUS, DB_TIMEOUT, DB_TOTAL_CHANGES,
|
||||
DB_TRACE, DB_TRACE_V2, DB_TRANSACTION,
|
||||
DB_UNLOCK_NOTIFY, DB_UPDATE_HOOK, DB_VERSION,
|
||||
DB_WAL_HOOK
|
||||
};
|
||||
/* don't leave trailing commas on DB_enum, it confuses the AIX xlc compiler */
|
||||
|
||||
@@ -2978,6 +3331,18 @@ deserialize_error:
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
** $db format [OPTIONS] SQL
|
||||
**
|
||||
** Run the SQL statement(s) given as the final argument. Use the
|
||||
** Query Result Formatter extension of SQLite to format the output as
|
||||
** text and return that text.
|
||||
*/
|
||||
case DB_FORMAT: {
|
||||
rc = dbQrf(pDb, objc, objv);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
** $db function NAME [OPTIONS] SCRIPT
|
||||
**
|
||||
|
||||
@@ -332,9 +332,11 @@ do_test 4.3 {
|
||||
set ofd [open $shdo w]
|
||||
if {$::cliDoesAr} {
|
||||
puts $ofd ".ar -u $shdo"
|
||||
puts $ofd ".mode list"
|
||||
puts $ofd "select count(*) from sqlar where name = '$shdo';"
|
||||
} else {
|
||||
puts $ofd "insert into sqlar values (1);"
|
||||
puts $ofd ".mode list"
|
||||
puts $ofd "select count(*) from sqlar;"
|
||||
}
|
||||
puts $ofd ".q"
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
# 2025-11-12
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# Test cases for the ".mode" command of the CLI.
|
||||
# To run these tests:
|
||||
#
|
||||
# ./sqlite3 <test/modeA.clitest
|
||||
#
|
||||
#
|
||||
CREATE TABLE t1(a,b,c,d,e);
|
||||
INSERT INTO t1 VALUES(1,2.5,'three',x'4444',NULL);
|
||||
INSERT INTO t1 SELECT b,c,d,e,a FROM t1;
|
||||
INSERT INTO t1 SELECT d,e,a,b,c FROM t1;
|
||||
.mode box
|
||||
|
||||
.output memory
|
||||
SELECT * FROM t1;
|
||||
.output --verify END
|
||||
┌─────┬───────┬───────┬───────┬───────┐
|
||||
│ a │ b │ c │ d │ e │
|
||||
├─────┼───────┼───────┼───────┼───────┤
|
||||
│ 1 │ 2.5 │ three │ DD │ │
|
||||
│ 2.5 │ three │ DD │ │ 1 │
|
||||
│ DD │ │ 1 │ 2.5 │ three │
|
||||
│ │ 1 │ 2.5 │ three │ DD │
|
||||
└─────┴───────┴───────┴───────┴───────┘
|
||||
END
|
||||
|
||||
.output memory
|
||||
.mode --null xyz
|
||||
SELECT * FROM t1;
|
||||
.output --verify END
|
||||
┌─────┬───────┬───────┬───────┬───────┐
|
||||
│ a │ b │ c │ d │ e │
|
||||
├─────┼───────┼───────┼───────┼───────┤
|
||||
│ 1 │ 2.5 │ three │ DD │ xyz │
|
||||
│ 2.5 │ three │ DD │ xyz │ 1 │
|
||||
│ DD │ xyz │ 1 │ 2.5 │ three │
|
||||
│ xyz │ 1 │ 2.5 │ three │ DD │
|
||||
└─────┴───────┴───────┴───────┴───────┘
|
||||
END
|
||||
|
||||
.output memory --error-prefix "Error:"
|
||||
.mode foo
|
||||
.output --verify END
|
||||
Error: .mode foo
|
||||
Error: ^--- unknown mode
|
||||
Error: Use ".help .mode" for more info
|
||||
END
|
||||
|
||||
.output memory
|
||||
.mode --null xyzzy -v
|
||||
.output -glob ' --null "xyzzy"'
|
||||
.output memory
|
||||
.mode -null abcde -v
|
||||
.output -glob ' --null "abcde"'
|
||||
+893
@@ -0,0 +1,893 @@
|
||||
# 2025-11-05
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# Test cases for the Query Result Formatter (QRF)
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix qrf01
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(a, b, c);
|
||||
INSERT INTO t1 VALUES(1,2.5,'three'),(x'424c4f42',NULL,'Ἀμήν');
|
||||
}
|
||||
|
||||
do_test 1.10 {
|
||||
set result "\n[db format {SELECT * FROM t1}]"
|
||||
} {
|
||||
┌──────┬─────┬───────┐
|
||||
│ a │ b │ c │
|
||||
├──────┼─────┼───────┤
|
||||
│ 1 │ 2.5 │ three │
|
||||
│ BLOB │ │ Ἀμήν │
|
||||
└──────┴─────┴───────┘
|
||||
}
|
||||
do_test 1.11a {
|
||||
set result "\n[db format -title off {SELECT * FROM t1}]"
|
||||
} {
|
||||
┌──────┬─────┬───────┐
|
||||
│ 1 │ 2.5 │ three │
|
||||
│ BLOB │ │ Ἀμήν │
|
||||
└──────┴─────┴───────┘
|
||||
}
|
||||
do_test 1.11b {
|
||||
set result "\n[db format -text sql {SELECT * FROM t1}]"
|
||||
} {
|
||||
┌─────────────┬─────┬─────────┐
|
||||
│ a │ b │ c │
|
||||
├─────────────┼─────┼─────────┤
|
||||
│ 1 │ 2.5 │ 'three' │
|
||||
│ x'424c4f42' │ │ 'Ἀμήν' │
|
||||
└─────────────┴─────┴─────────┘
|
||||
}
|
||||
do_test 1.12 {
|
||||
set result "\n[db format -text csv {SELECT * FROM t1}]"
|
||||
} {
|
||||
┌────────────────────┬─────┬────────┐
|
||||
│ a │ b │ c │
|
||||
├────────────────────┼─────┼────────┤
|
||||
│ 1 │ 2.5 │ three │
|
||||
│ "\102\114\117\102" │ │ "Ἀμήν" │
|
||||
└────────────────────┴─────┴────────┘
|
||||
}
|
||||
do_test 1.13 {
|
||||
set result "\n[db format -text csv -blob hex {SELECT * FROM t1}]"
|
||||
} {
|
||||
┌──────────┬─────┬────────┐
|
||||
│ a │ b │ c │
|
||||
├──────────┼─────┼────────┤
|
||||
│ 1 │ 2.5 │ three │
|
||||
│ 424c4f42 │ │ "Ἀμήν" │
|
||||
└──────────┴─────┴────────┘
|
||||
}
|
||||
do_test 1.14 {
|
||||
catch {db format -text unk -blob hex {SELECT * FROM t1}} res
|
||||
set res
|
||||
} {bad -text "unk": must be auto, csv, html, json, plain, sql, or tcl}
|
||||
do_test 1.15 {
|
||||
catch {db format -text sql -blob unk {SELECT * FROM t1}} res
|
||||
set res
|
||||
} {bad BLOB encoding (-blob) "unk": must be auto, hex, json, tcl, text, or sql}
|
||||
do_test 1.16 {
|
||||
catch {db format -text sql -style unk {SELECT * FROM t1}} res
|
||||
set res
|
||||
} {bad format style (-style) "unk": must be auto, box, column, count, csv, eqp, explain, html, insert, jobject, json, line, list, markdown, quote, stats, stats-est, stats-vm, or table}
|
||||
|
||||
|
||||
do_test 1.20 {
|
||||
set result "\n[db format -style box {SELECT * FROM t1}]"
|
||||
} {
|
||||
┌──────┬─────┬───────┐
|
||||
│ a │ b │ c │
|
||||
├──────┼─────┼───────┤
|
||||
│ 1 │ 2.5 │ three │
|
||||
│ BLOB │ │ Ἀμήν │
|
||||
└──────┴─────┴───────┘
|
||||
}
|
||||
|
||||
do_test 1.30 {
|
||||
set result "\n[db format -style table {SELECT * FROM t1}]"
|
||||
} {
|
||||
+------+-----+-------+
|
||||
| a | b | c |
|
||||
+------+-----+-------+
|
||||
| 1 | 2.5 | three |
|
||||
| BLOB | | Ἀμήν |
|
||||
+------+-----+-------+
|
||||
}
|
||||
do_test 1.31 {
|
||||
set result "\n[db format -style table -title off {SELECT * FROM t1}]"
|
||||
} {
|
||||
+------+-----+-------+
|
||||
| 1 | 2.5 | three |
|
||||
| BLOB | | Ἀμήν |
|
||||
+------+-----+-------+
|
||||
}
|
||||
|
||||
do_test 1.40 {
|
||||
set result "\n[db format -style column {SELECT * FROM t1}]"
|
||||
} {
|
||||
a b c
|
||||
---- --- -----
|
||||
1 2.5 three
|
||||
BLOB Ἀμήν
|
||||
}
|
||||
do_test 1.41 {
|
||||
set result "\n[db format -style column -title off {SELECT * FROM t1}]"
|
||||
} {
|
||||
1 2.5 three
|
||||
BLOB Ἀμήν
|
||||
}
|
||||
|
||||
do_test 1.50 {
|
||||
db format -style count {SELECT * FROM t1}
|
||||
} 2
|
||||
|
||||
do_test 1.60a {
|
||||
db format -style list -columnsep , -rowsep \r\n -text csv -blob tcl {SELECT * FROM t1}
|
||||
} "1,2.5,three\r\n\"\\102\\114\\117\\102\",,\"Ἀμήν\"\r\n"
|
||||
do_test 1.60b {
|
||||
db format -style csv -columnsep xyz -rowsep pqr -text sql -blob sql {SELECT * FROM t1}
|
||||
} "1,2.5,three\r\nBLOB,,\"Ἀμήν\"\r\n"
|
||||
do_test 1.61a {
|
||||
db format -style list -columnsep , -rowsep \r\n -text csv -title auto -blob tcl {SELECT * FROM t1}
|
||||
} "a,b,c\r\n1,2.5,three\r\n\"\\102\\114\\117\\102\",,\"Ἀμήν\"\r\n"
|
||||
do_test 1.61b {
|
||||
db format -style csv -title auto -blob tcl {SELECT * FROM t1}
|
||||
} "a,b,c\r\n1,2.5,three\r\nBLOB,,\"Ἀμήν\"\r\n"
|
||||
do_test 1.62a {
|
||||
db format -style list -columnsep , -rowsep \r\n -text csv -title csv -blob tcl {SELECT a AS 'a x y', b, c FROM t1}
|
||||
} "\"a x y\",b,c\r\n1,2.5,three\r\n\"\\102\\114\\117\\102\",,\"Ἀμήν\"\r\n"
|
||||
do_test 1.62b {
|
||||
db format -style csv -title csv -blob tcl {SELECT a AS 'a x y', b, c FROM t1}
|
||||
} "\"a x y\",b,c\r\n1,2.5,three\r\nBLOB,,\"Ἀμήν\"\r\n"
|
||||
|
||||
do_test 1.70 {
|
||||
set result "\n[db format -style html {SELECT * FROM t1}]"
|
||||
} {
|
||||
<TR>
|
||||
<TD>1
|
||||
<TD>2.5
|
||||
<TD>three
|
||||
</TR>
|
||||
<TR>
|
||||
<TD>BLOB
|
||||
<TD>null
|
||||
<TD>Ἀμήν
|
||||
</TR>
|
||||
}
|
||||
do_test 1.71 {
|
||||
set result "\n[db format -style html -title auto {SELECT * FROM t1}]"
|
||||
} {
|
||||
<TR>
|
||||
<TH>a
|
||||
<TH>b
|
||||
<TH>c
|
||||
</TR>
|
||||
<TR>
|
||||
<TD>1
|
||||
<TD>2.5
|
||||
<TD>three
|
||||
</TR>
|
||||
<TR>
|
||||
<TD>BLOB
|
||||
<TD>null
|
||||
<TD>Ἀμήν
|
||||
</TR>
|
||||
}
|
||||
|
||||
do_test 1.80 {
|
||||
set result "\n[db format -style insert {SELECT * FROM t1}]"
|
||||
} {
|
||||
INSERT INTO tab VALUES(1,2.5,'three');
|
||||
INSERT INTO tab VALUES(x'424c4f42',NULL,'Ἀμήν');
|
||||
}
|
||||
do_test 1.81 {
|
||||
set result "\n[db format -style insert -tablename t1 {SELECT * FROM t1}]"
|
||||
} {
|
||||
INSERT INTO t1 VALUES(1,2.5,'three');
|
||||
INSERT INTO t1 VALUES(x'424c4f42',NULL,'Ἀμήν');
|
||||
}
|
||||
do_test 1.82 {
|
||||
set result "\n[db format -style insert -tablename t1 -title auto \
|
||||
{SELECT * FROM t1}]"
|
||||
} {
|
||||
INSERT INTO t1(a,b,c) VALUES(1,2.5,'three');
|
||||
INSERT INTO t1(a,b,c) VALUES(x'424c4f42',NULL,'Ἀμήν');
|
||||
}
|
||||
do_test 1.83 {
|
||||
set result "\n[db format -style insert -tablename drop -title on \
|
||||
{SELECT a AS "a-b", b, c AS "123" FROM t1}]"
|
||||
} {
|
||||
INSERT INTO "drop"("a-b",b,"123") VALUES(1,2.5,'three');
|
||||
INSERT INTO "drop"("a-b",b,"123") VALUES(x'424c4f42',NULL,'Ἀμήν');
|
||||
}
|
||||
|
||||
do_test 1.90 {
|
||||
set result "\n[db format -style json {SELECT * FROM t1}]"
|
||||
} {
|
||||
[{"a":1,"b":2.5,"c":"three"},
|
||||
{"a":"\u0042\u004c\u004f\u0042","b":null,"c":"Ἀμήν"}]
|
||||
}
|
||||
do_test 1.91 {
|
||||
set result "\n[db format -style jobject {SELECT * FROM t1}]"
|
||||
} {
|
||||
{"a":1,"b":2.5,"c":"three"}
|
||||
{"a":"\u0042\u004c\u004f\u0042","b":null,"c":"Ἀμήν"}
|
||||
}
|
||||
do_test 1.92 {
|
||||
set result "\n[db format -style jobject {SELECT *, unistr('abc\u000a123\u000d\u000axyz') AS xyz FROM t1}]"
|
||||
} {
|
||||
{"a":1,"b":2.5,"c":"three","xyz":"abc\n123\r\nxyz"}
|
||||
{"a":"\u0042\u004c\u004f\u0042","b":null,"c":"Ἀμήν","xyz":"abc\n123\r\nxyz"}
|
||||
}
|
||||
|
||||
do_test 1.100 {
|
||||
set result "\n[db format -style line {SELECT * FROM t1}]"
|
||||
} {
|
||||
a = 1
|
||||
b = 2.5
|
||||
c = three
|
||||
|
||||
a = BLOB
|
||||
b =
|
||||
c = Ἀμήν
|
||||
}
|
||||
do_test 1.101 {
|
||||
set result "\n[db format -style line -null (NULL) {SELECT * FROM t1}]"
|
||||
} {
|
||||
a = 1
|
||||
b = 2.5
|
||||
c = three
|
||||
|
||||
a = BLOB
|
||||
b = (NULL)
|
||||
c = Ἀμήν
|
||||
}
|
||||
do_test 1.102 {
|
||||
set result "\n[db format -style line -null (NULL) \
|
||||
-text sql {SELECT * FROM t1}]"
|
||||
} {
|
||||
a = 1
|
||||
b = 2.5
|
||||
c = 'three'
|
||||
|
||||
a = x'424c4f42'
|
||||
b = (NULL)
|
||||
c = 'Ἀμήν'
|
||||
}
|
||||
|
||||
do_test 1.110 {
|
||||
set result "\n[db format -style list {SELECT * FROM t1}]"
|
||||
} {
|
||||
1|2.5|three
|
||||
BLOB||Ἀμήν
|
||||
}
|
||||
do_test 1.111 {
|
||||
set result "\n[db format -style list -title on {SELECT * FROM t1}]"
|
||||
} {
|
||||
a|b|c
|
||||
1|2.5|three
|
||||
BLOB||Ἀμήν
|
||||
}
|
||||
do_test 1.112 {
|
||||
set result "\n[db format -style list -title on -text sql -null NULL \
|
||||
-title plain {SELECT * FROM t1}]"
|
||||
} {
|
||||
a|b|c
|
||||
1|2.5|'three'
|
||||
x'424c4f42'|NULL|'Ἀμήν'
|
||||
}
|
||||
do_test 1.118 {
|
||||
set rc [catch {db format -style list -title unk {SELECT * FROM t1}} res]
|
||||
lappend rc $res
|
||||
} {1 {bad -title "unk": must be off, on, auto, csv, html, json, plain, sql, or tcl}}
|
||||
|
||||
|
||||
do_test 1.120 {
|
||||
set result "\n[db format -style markdown {SELECT * FROM t1}]"
|
||||
} {
|
||||
| a | b | c |
|
||||
|------|-----|-------|
|
||||
| 1 | 2.5 | three |
|
||||
| BLOB | | Ἀμήν |
|
||||
}
|
||||
do_test 1.121 {
|
||||
set result "\n[db format -style markdown -title off {SELECT * FROM t1}]"
|
||||
} {
|
||||
| 1 | 2.5 | three |
|
||||
| BLOB | | Ἀμήν |
|
||||
}
|
||||
|
||||
do_test 1.130 {
|
||||
set result "\n[db format -style quote {SELECT * FROM t1}]"
|
||||
} {
|
||||
1,2.5,'three'
|
||||
x'424c4f42',NULL,'Ἀμήν'
|
||||
}
|
||||
do_test 1.131 {
|
||||
set result "\n[db format -style quote -title on {SELECT * FROM t1}]"
|
||||
} {
|
||||
'a','b','c'
|
||||
1,2.5,'three'
|
||||
x'424c4f42',NULL,'Ἀμήν'
|
||||
}
|
||||
|
||||
|
||||
do_execsql_test 2.0 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1 VALUES(1,2,'The quick fox jumps over the lazy brown dog.');
|
||||
}
|
||||
do_test 2.1 {
|
||||
set result "\n[db format -widths {5 -5 19} -wordwrap on \
|
||||
{SELECT * FROM t1}]"
|
||||
} {
|
||||
┌───────┬───────┬─────────────────────┐
|
||||
│ a │ b │ c │
|
||||
├───────┼───────┼─────────────────────┤
|
||||
│ 1 │ 2 │ The quick fox jumps │
|
||||
│ │ │ over the lazy brown │
|
||||
│ │ │ dog. │
|
||||
└───────┴───────┴─────────────────────┘
|
||||
}
|
||||
do_test 2.2 {
|
||||
set result "\n[db format -widths {5 -5 19} -wordwrap off \
|
||||
{SELECT * FROM t1}]"
|
||||
} {
|
||||
┌───────┬───────┬─────────────────────┐
|
||||
│ a │ b │ c │
|
||||
├───────┼───────┼─────────────────────┤
|
||||
│ 1 │ 2 │ The quick fox jumps │
|
||||
│ │ │ over the lazy brown │
|
||||
│ │ │ dog. │
|
||||
└───────┴───────┴─────────────────────┘
|
||||
}
|
||||
do_test 2.3 {
|
||||
set result "\n[db format -widths {5 -5 18} -wordwrap on \
|
||||
{SELECT * FROM t1}]"
|
||||
} {
|
||||
┌───────┬───────┬────────────────────┐
|
||||
│ a │ b │ c │
|
||||
├───────┼───────┼────────────────────┤
|
||||
│ 1 │ 2 │ The quick fox │
|
||||
│ │ │ jumps over the │
|
||||
│ │ │ lazy brown dog. │
|
||||
└───────┴───────┴────────────────────┘
|
||||
}
|
||||
do_test 2.4 {
|
||||
set result "\n[db format -widths {5 -5 -18} -wordwrap on \
|
||||
{SELECT * FROM t1}]"
|
||||
} {
|
||||
┌───────┬───────┬────────────────────┐
|
||||
│ a │ b │ c │
|
||||
├───────┼───────┼────────────────────┤
|
||||
│ 1 │ 2 │ The quick fox │
|
||||
│ │ │ jumps over the │
|
||||
│ │ │ lazy brown dog. │
|
||||
└───────┴───────┴────────────────────┘
|
||||
}
|
||||
do_test 2.5 {
|
||||
set result "\n[db format -widths {5 -5 19} -wordwrap off \
|
||||
{SELECT * FROM t1}]"
|
||||
} {
|
||||
┌───────┬───────┬─────────────────────┐
|
||||
│ a │ b │ c │
|
||||
├───────┼───────┼─────────────────────┤
|
||||
│ 1 │ 2 │ The quick fox jumps │
|
||||
│ │ │ over the lazy brown │
|
||||
│ │ │ dog. │
|
||||
└───────┴───────┴─────────────────────┘
|
||||
}
|
||||
do_test 2.6 {
|
||||
set result "\n[db format -widths {5 -5 18} -wordwrap off \
|
||||
{SELECT * FROM t1}]"
|
||||
} {
|
||||
┌───────┬───────┬────────────────────┐
|
||||
│ a │ b │ c │
|
||||
├───────┼───────┼────────────────────┤
|
||||
│ 1 │ 2 │ The quick fox jump │
|
||||
│ │ │ s over the lazy br │
|
||||
│ │ │ own dog. │
|
||||
└───────┴───────┴────────────────────┘
|
||||
}
|
||||
do_test 2.7 {
|
||||
set result "\n[db format -widths {5 5 18} -wordwrap yes \
|
||||
-align {left center right} -titlealign right \
|
||||
{SELECT * FROM t1}]"
|
||||
} {
|
||||
┌───────┬───────┬────────────────────┐
|
||||
│ a │ b │ c │
|
||||
├───────┼───────┼────────────────────┤
|
||||
│ 1 │ 2 │ The quick fox │
|
||||
│ │ │ jumps over the │
|
||||
│ │ │ lazy brown dog. │
|
||||
└───────┴───────┴────────────────────┘
|
||||
}
|
||||
do_test 2.8 {
|
||||
set result "\n[db format -widths {5 8 11} -wordwrap yes \
|
||||
-align {auto auto center} -titlealign left \
|
||||
-defaultalign right \
|
||||
{SELECT * FROM t1}]"
|
||||
} {
|
||||
┌───────┬──────────┬─────────────┐
|
||||
│ a │ b │ c │
|
||||
├───────┼──────────┼─────────────┤
|
||||
│ 1 │ 2 │ The quick │
|
||||
│ │ │ fox jumps │
|
||||
│ │ │ over the │
|
||||
│ │ │ lazy brown │
|
||||
│ │ │ dog. │
|
||||
└───────┴──────────┴─────────────┘
|
||||
}
|
||||
do_test 2.9 {
|
||||
catch {db format -align {auto xyz 123} {SELECT * FROM t1}} res
|
||||
set res
|
||||
} {bad column alignment (-align) "xyz": must be auto, bottom, c, center, e, left, middle, n, ne, nw, right, s, se, sw, top, or w}
|
||||
do_test 2.10 {
|
||||
catch {db format -defaultalign xyz {SELECT * FROM t1}} res
|
||||
set res
|
||||
} {bad default alignment (-defaultalign) "xyz": must be auto, bottom, c, center, e, left, middle, n, ne, nw, right, s, se, sw, top, or w}
|
||||
do_test 2.11 {
|
||||
catch {db format -titlealign xyz {SELECT * FROM t1}} res
|
||||
set res
|
||||
} {bad title alignment (-titlealign) "xyz": must be auto, bottom, c, center, e, left, middle, n, ne, nw, right, s, se, sw, top, or w}
|
||||
|
||||
|
||||
do_execsql_test 2.30 {
|
||||
UPDATE t1 SET c='Η γρήγορη αλεπού πηδάει πάνω από το τεμπέλικο καφέ σκυλί';
|
||||
SELECT hex(c) FROM t1;
|
||||
} {CE9720CEB3CF81CEAECEB3CEBFCF81CEB720CEB1CEBBCEB5CF80CEBFCF8D20CF80CEB7CEB4CEACCEB5CEB920CF80CEACCEBDCF8920CEB1CF80CF8C20CF84CEBF20CF84CEB5CEBCCF80CEADCEBBCEB9CEBACEBF20CEBACEB1CF86CEAD20CF83CEBACF85CEBBCEAF}
|
||||
do_test 2.31 {
|
||||
set result "\n[db format -widths {5 -5 18} -wordwrap on \
|
||||
{SELECT * FROM t1}]"
|
||||
} {
|
||||
┌───────┬───────┬────────────────────┐
|
||||
│ a │ b │ c │
|
||||
├───────┼───────┼────────────────────┤
|
||||
│ 1 │ 2 │ Η γρήγορη αλεπού │
|
||||
│ │ │ πηδάει πάνω από το │
|
||||
│ │ │ τεμπέλικο καφέ │
|
||||
│ │ │ σκυλί │
|
||||
└───────┴───────┴────────────────────┘
|
||||
}
|
||||
do_test 2.32 {
|
||||
set result "\n[db format -widths {5 5 18} -align {left center center} -wordwrap on \
|
||||
{SELECT * FROM t1}]"
|
||||
} {
|
||||
┌───────┬───────┬────────────────────┐
|
||||
│ a │ b │ c │
|
||||
├───────┼───────┼────────────────────┤
|
||||
│ 1 │ 2 │ Η γρήγορη αλεπού │
|
||||
│ │ │ πηδάει πάνω από το │
|
||||
│ │ │ τεμπέλικο καφέ │
|
||||
│ │ │ σκυλί │
|
||||
└───────┴───────┴────────────────────┘
|
||||
}
|
||||
|
||||
|
||||
do_execsql_test 3.0 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1 VALUES(1,2,unistr('abc\u001b[1;31m123\u001b[0mxyz'));
|
||||
}
|
||||
do_test 3.1 {
|
||||
set result "\n[db format {SELECT * FROM t1}]"
|
||||
} {
|
||||
┌───┬───┬────────────────────────┐
|
||||
│ a │ b │ c │
|
||||
├───┼───┼────────────────────────┤
|
||||
│ 1 │ 2 │ abc^[[1;31m123^[[0mxyz │
|
||||
└───┴───┴────────────────────────┘
|
||||
}
|
||||
do_test 3.2 {
|
||||
set result "\n[db format -esc off {SELECT * FROM t1}]"
|
||||
string map [list \033 X] $result
|
||||
} {
|
||||
┌───┬───┬───────────┐
|
||||
│ a │ b │ c │
|
||||
├───┼───┼───────────┤
|
||||
│ 1 │ 2 │ abcX[1;31m123X[0mxyz │
|
||||
└───┴───┴───────────┘
|
||||
}
|
||||
do_test 3.3 {
|
||||
set result "\n[db format -esc symbol {SELECT * FROM t1}]"
|
||||
} {
|
||||
┌───┬───┬──────────────────────┐
|
||||
│ a │ b │ c │
|
||||
├───┼───┼──────────────────────┤
|
||||
│ 1 │ 2 │ abc␛[1;31m123␛[0mxyz │
|
||||
└───┴───┴──────────────────────┘
|
||||
}
|
||||
do_test 3.4 {
|
||||
set result "\n[db format -esc ascii {SELECT * FROM t1}]"
|
||||
} {
|
||||
┌───┬───┬────────────────────────┐
|
||||
│ a │ b │ c │
|
||||
├───┼───┼────────────────────────┤
|
||||
│ 1 │ 2 │ abc^[[1;31m123^[[0mxyz │
|
||||
└───┴───┴────────────────────────┘
|
||||
}
|
||||
do_test 3.5 {
|
||||
catch {db format -esc unk {SELECT * FROM t1}} res
|
||||
set res
|
||||
} {bad control character escape (-esc) "unk": must be ascii, auto, off, or symbol}
|
||||
|
||||
do_execsql_test 4.0 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1 VALUES(json('{a:5,b:6}'), jsonb('{c:1,d:2}'), 99);
|
||||
}
|
||||
do_test 4.1 {
|
||||
set result "\n[db format -text sql {SELECT * FROM t1}]"
|
||||
} {
|
||||
┌─────────────────┬───────────────────────┬────┐
|
||||
│ a │ b │ c │
|
||||
├─────────────────┼───────────────────────┼────┤
|
||||
│ '{"a":5,"b":6}' │ x'8c1763133117641332' │ 99 │
|
||||
└─────────────────┴───────────────────────┴────┘
|
||||
}
|
||||
do_test 4.2 {
|
||||
set result "\n[db format -text sql -textjsonb on {SELECT * FROM t1}]"
|
||||
} {
|
||||
┌─────────────────┬────────────────────────┬────┐
|
||||
│ a │ b │ c │
|
||||
├─────────────────┼────────────────────────┼────┤
|
||||
│ '{"a":5,"b":6}' │ jsonb('{"c":1,"d":2}') │ 99 │
|
||||
└─────────────────┴────────────────────────┴────┘
|
||||
}
|
||||
do_test 4.3 {
|
||||
set result "\n[db format -text plain -textjsonb on -wrap 11 \
|
||||
{SELECT a AS json, b AS jsonb, c AS num FROM t1}]"
|
||||
} {
|
||||
┌─────────────┬─────────────┬─────┐
|
||||
│ json │ jsonb │ num │
|
||||
├─────────────┼─────────────┼─────┤
|
||||
│ {"a":5,"b": │ {"c":1,"d": │ 99 │
|
||||
│ 6} │ 2} │ │
|
||||
└─────────────┴─────────────┴─────┘
|
||||
}
|
||||
|
||||
do_execsql_test 5.0 {
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1(name, mtime, value);
|
||||
INSERT INTO t1 VALUES
|
||||
('entry-one',1708791504,zeroblob(300)),
|
||||
(unistr('one\u000atwo\u000athree'),1333206973,NULL),
|
||||
('sample-jsonb',1333101221,jsonb('{
|
||||
"alpha":53.11688723,
|
||||
"beta":"qrfWidthPrint(p, p->pOut, -p->u.sLine.mxColWth);",
|
||||
"zeta":[15,null,1333206973,"fd8ffe000104a46494600010101"]}'));
|
||||
}
|
||||
do_test 5.1 {
|
||||
set sql {SELECT name, mtime, datetime(mtime,'unixepoch') AS time,
|
||||
value FROM t1 ORDER BY mtime}
|
||||
set result "\n[db format -style line -screenwidth 60 -blob sql \
|
||||
-text sql -wordwrap off -linelimit 77 $sql]"
|
||||
} {
|
||||
name = 'sample-jsonb'
|
||||
mtime = 1333101221
|
||||
time = '2012-03-30 09:53:41'
|
||||
value = x'cc7c57616c706861b535332e31313638383732334762657461
|
||||
c73071726657696474685072696e7428702c20702d3e704f7574
|
||||
2c202d702d3e752e734c696e652e6d78436f6c577468293b477a
|
||||
657461cb2c23313500a331333333323036393733c71b66643866
|
||||
6665303030313034613436343934363030303130313031'
|
||||
|
||||
name = unistr('one\u000atwo\u000athree')
|
||||
mtime = 1333206973
|
||||
time = '2012-03-31 15:16:13'
|
||||
value =
|
||||
|
||||
name = 'entry-one'
|
||||
mtime = 1708791504
|
||||
time = '2024-02-24 16:18:24'
|
||||
value = x'00000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000
|
||||
000000000000000000000000000000'
|
||||
}
|
||||
do_test 5.2 {
|
||||
set sql {SELECT name, mtime, datetime(mtime,'unixepoch') AS time,
|
||||
value FROM t1 ORDER BY mtime}
|
||||
set result "\n[db format -style line -screenwidth 60 -blob sql \
|
||||
-text plain -esc off -textjsonb yes \
|
||||
-wordwrap yes -linelimit 3 $sql]"
|
||||
} {
|
||||
name = sample-jsonb
|
||||
mtime = 1333101221
|
||||
time = 2012-03-30 09:53:41
|
||||
value = {"alpha":53.11688723,"beta":"qrfWidthPrint(p,
|
||||
p->pOut, -p->u.sLine.mxColWth);","zeta":[15,null,
|
||||
1333206973,"fd8ffe000104a46494600010101"]}
|
||||
|
||||
name = one
|
||||
two
|
||||
three
|
||||
mtime = 1333206973
|
||||
time = 2012-03-31 15:16:13
|
||||
value =
|
||||
|
||||
name = entry-one
|
||||
mtime = 1708791504
|
||||
time = 2024-02-24 16:18:24
|
||||
value = x'00000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000
|
||||
...
|
||||
}
|
||||
do_test 5.3a {
|
||||
set result "\n[db format -style box -widths {0 10 10 14}\
|
||||
-align {left right right center} \
|
||||
-blob sql \
|
||||
-text plain -esc off -textjsonb no \
|
||||
-wordwrap yes -linelimit 2 $sql]"
|
||||
} {
|
||||
┌──────────────┬────────────┬────────────┬────────────────┐
|
||||
│ name │ mtime │ time │ value │
|
||||
├──────────────┼────────────┼────────────┼────────────────┤
|
||||
│ sample-jsonb │ 1333101221 │ 2012-03-30 │ x'cc7c57616c70 │
|
||||
│ │ │ 09:53:41 │ 6861b535332e31 │
|
||||
│ │ │ │ ... │
|
||||
├──────────────┼────────────┼────────────┼────────────────┤
|
||||
│ one │ 1333206973 │ 2012-03-31 │ │
|
||||
│ two │ │ 15:16:13 │ │
|
||||
│ ... │ │ │ │
|
||||
├──────────────┼────────────┼────────────┼────────────────┤
|
||||
│ entry-one │ 1708791504 │ 2024-02-24 │ x'000000000000 │
|
||||
│ │ │ 16:18:24 │ 00000000000000 │
|
||||
│ │ │ │ ... │
|
||||
└──────────────┴────────────┴────────────┴────────────────┘
|
||||
}
|
||||
do_test 5.3b {
|
||||
set result "\n[db format -style table -widths {0 10 10 14}\
|
||||
-align {center right right right} \
|
||||
-blob sql \
|
||||
-text plain -esc off -textjsonb no \
|
||||
-wordwrap yes -linelimit 2 $sql]"
|
||||
} {
|
||||
+--------------+------------+------------+----------------+
|
||||
| name | mtime | time | value |
|
||||
+--------------+------------+------------+----------------+
|
||||
| sample-jsonb | 1333101221 | 2012-03-30 | x'cc7c57616c70 |
|
||||
| | | 09:53:41 | 6861b535332e31 |
|
||||
| | | | ... |
|
||||
+--------------+------------+------------+----------------+
|
||||
| one | 1333206973 | 2012-03-31 | |
|
||||
| two | | 15:16:13 | |
|
||||
| ... | | | |
|
||||
+--------------+------------+------------+----------------+
|
||||
| entry-one | 1708791504 | 2024-02-24 | x'000000000000 |
|
||||
| | | 16:18:24 | 00000000000000 |
|
||||
| | | | ... |
|
||||
+--------------+------------+------------+----------------+
|
||||
}
|
||||
do_test 5.3c {
|
||||
set result "\n[db format -style column -widths {0 10 10 14}\
|
||||
-align {center right right right} \
|
||||
-blob sql \
|
||||
-text plain -esc off -textjsonb no \
|
||||
-wordwrap yes -linelimit 2 $sql]"
|
||||
} {
|
||||
name mtime time value
|
||||
------------ ---------- ---------- --------------
|
||||
sample-jsonb 1333101221 2012-03-30 x'cc7c57616c70
|
||||
09:53:41 6861b535332e31
|
||||
...
|
||||
|
||||
one 1333206973 2012-03-31
|
||||
two 15:16:13
|
||||
...
|
||||
|
||||
entry-one 1708791504 2024-02-24 x'000000000000
|
||||
16:18:24 00000000000000
|
||||
...
|
||||
}
|
||||
do_test 5.4 {
|
||||
db eval {
|
||||
CREATE TABLE t2(a,b,c,d,e);
|
||||
WITH v(x) AS (SELECT 'abcdefghijklmnopqrstuvwxyz')
|
||||
INSERT INTO t2 SELECT x,x,x,x,x FROM v;
|
||||
}
|
||||
set sql {SELECT char(0x61,0xa,0x62,0xa,0x63,0xa,0x64) a,
|
||||
mtime b, mtime c, mtime d, mtime e FROM t1}
|
||||
set result "\n[db format -style box -widths {1 2 3 4 5}\
|
||||
-linelimit 3 -wordwrap off {SELECT *, 'x' AS x FROM t2}]"
|
||||
} {
|
||||
┌────┬────┬─────┬──────┬───────┬───┐
|
||||
│ a │ b │ c │ d │ e │ x │
|
||||
├────┼────┼─────┼──────┼───────┼───┤
|
||||
│ ab │ ab │ abc │ abcd │ abcde │ x │
|
||||
│ cd │ cd │ def │ efgh │ fghij │ │
|
||||
│ ef │ ef │ ghi │ ijkl │ klmno │ │
|
||||
│ .. │ .. │ ... │ ... │ ... │ │
|
||||
└────┴────┴─────┴──────┴───────┴───┘
|
||||
}
|
||||
|
||||
do_execsql_test 6.0 {
|
||||
DELETE FROM t2;
|
||||
INSERT INTO t2 VALUES
|
||||
(1, 2.5, 'three', x'342028666f757229', null);
|
||||
}
|
||||
do_test 6.1a {
|
||||
set result "\n[db format -style list -null NULL \
|
||||
-text tcl -columnsep , \
|
||||
{SELECT * FROM t2}]"
|
||||
} {
|
||||
1,2.5,"three","\064\040\050\146\157\165\162\051",NULL
|
||||
}
|
||||
do_test 6.1b {
|
||||
set result "\n[db format -style list -null NULL \
|
||||
-text tcl -columnsep , -textnull off \
|
||||
{SELECT * FROM t2}]"
|
||||
} {
|
||||
1,2.5,"three","\064\040\050\146\157\165\162\051",NULL
|
||||
}
|
||||
do_test 6.1c {
|
||||
set result "\n[db format -style list -null NULL \
|
||||
-text tcl -columnsep , -textnull auto \
|
||||
{SELECT * FROM t2}]"
|
||||
} {
|
||||
1,2.5,"three","\064\040\050\146\157\165\162\051",NULL
|
||||
}
|
||||
do_test 6.2 {
|
||||
set result "\n[db format -style list -null NULL \
|
||||
-text tcl -columnsep , -textnull yes \
|
||||
{SELECT * FROM t2}]"
|
||||
} {
|
||||
1,2.5,"three","\064\040\050\146\157\165\162\051","NULL"
|
||||
}
|
||||
do_test 6.3 {
|
||||
catch {db format -textnull xyz {SELECT * FROM t2}} res
|
||||
set res
|
||||
} {bad -textnull "xyz": must be auto, yes, no, on, or off}
|
||||
|
||||
do_execsql_test 7.0 {
|
||||
CREATE TABLE t7(a,b);
|
||||
INSERT INTO t7 VALUES('abcdefghijklmnop',
|
||||
'abcぁdefかghiのjklはmnop');
|
||||
}
|
||||
do_test 7.1 {
|
||||
set result "\n[db format -style list -charlimit 13 \
|
||||
{SELECT * FROM t7}]"
|
||||
} {
|
||||
abcdefghijklm...|abcぁdefかghi...
|
||||
}
|
||||
do_test 7.2 {
|
||||
set result "\n[db format -style list -charlimit 14 \
|
||||
{SELECT * FROM t7}]"
|
||||
} {
|
||||
abcdefghijklmn...|abcぁdefかghi...
|
||||
}
|
||||
do_test 7.3 {
|
||||
set result "\n[db format -style list -charlimit 15 \
|
||||
{SELECT * FROM t7}]"
|
||||
} {
|
||||
abcdefghijklmno...|abcぁdefかghiの...
|
||||
}
|
||||
do_test 7.4 {
|
||||
set result "\n[db format -style list -charlimit 16 \
|
||||
{SELECT * FROM t7}]"
|
||||
} {
|
||||
abcdefghijklmnop|abcぁdefかghiのj...
|
||||
}
|
||||
|
||||
do_test 8.0 {
|
||||
set result "\n[db format -style table {
|
||||
WITH c(n) AS (VALUES(1) UNION ALL SELECT n+1 FROM c WHERE n<10)
|
||||
SELECT 'aaa' AS 'a', format('%.*c',n,'b')||char(9)||'xx' AS x FROM c}]"
|
||||
} {
|
||||
+-----+--------------------+
|
||||
| a | x |
|
||||
+-----+--------------------+
|
||||
| aaa | b xx |
|
||||
| aaa | bb xx |
|
||||
| aaa | bbb xx |
|
||||
| aaa | bbbb xx |
|
||||
| aaa | bbbbb xx |
|
||||
| aaa | bbbbbb xx |
|
||||
| aaa | bbbbbbb xx |
|
||||
| aaa | bbbbbbbb xx |
|
||||
| aaa | bbbbbbbbb xx |
|
||||
| aaa | bbbbbbbbbb xx |
|
||||
+-----+--------------------+
|
||||
}
|
||||
do_test 8.1 {
|
||||
set result "\n[db format -style table {
|
||||
WITH c(n) AS (VALUES(1) UNION ALL SELECT n+1 FROM c WHERE n<10)
|
||||
SELECT 'aaaa' AS 'a', format('%.*c',n,'b')||char(9)||'xx' AS x FROM c}]"
|
||||
} {
|
||||
+------+--------------------+
|
||||
| a | x |
|
||||
+------+--------------------+
|
||||
| aaaa | b xx |
|
||||
| aaaa | bb xx |
|
||||
| aaaa | bbb xx |
|
||||
| aaaa | bbbb xx |
|
||||
| aaaa | bbbbb xx |
|
||||
| aaaa | bbbbbb xx |
|
||||
| aaaa | bbbbbbb xx |
|
||||
| aaaa | bbbbbbbb xx |
|
||||
| aaaa | bbbbbbbbb xx |
|
||||
| aaaa | bbbbbbbbbb xx |
|
||||
+------+--------------------+
|
||||
}
|
||||
do_test 8.3 {
|
||||
set result "\n[db format -style table -esc off {
|
||||
WITH c(n) AS (VALUES(1) UNION ALL SELECT n+1 FROM c WHERE n<15)
|
||||
SELECT 'aaa' AS 'a',n, 'xx'||char(n)||'yy' AS xy FROM c
|
||||
WHERE n NOT IN (8,10,13,14)}]"
|
||||
} {
|
||||
+-----+----+------------+
|
||||
| a | n | xy |
|
||||
+-----+----+------------+
|
||||
| aaa | 1 | xx␁yy |
|
||||
| aaa | 2 | xx␂yy |
|
||||
| aaa | 3 | xx␃yy |
|
||||
| aaa | 4 | xx␄yy |
|
||||
| aaa | 5 | xx␅yy |
|
||||
| aaa | 6 | xx␆yy |
|
||||
| aaa | 7 | xx␇yy |
|
||||
| aaa | 9 | xx yy |
|
||||
| aaa | 11 | xx␋yy |
|
||||
| aaa | 12 | xx␌yy |
|
||||
| aaa | 15 | xx␏yy |
|
||||
+-----+----+------------+
|
||||
}
|
||||
do_test 8.4 {
|
||||
set result "\n[db format -style table -esc off {
|
||||
WITH c(n) AS (VALUES(1) UNION ALL SELECT n+1 FROM c WHERE n<15)
|
||||
SELECT 'aaa' AS 'a',n, 'xx'||char(n)||'yy'||char(9)||'zz' AS xyz FROM c
|
||||
WHERE n NOT IN (8,10,13,14)}]"
|
||||
} {
|
||||
+-----+----+--------------------+
|
||||
| a | n | xyz |
|
||||
+-----+----+--------------------+
|
||||
| aaa | 1 | xx␁yy zz |
|
||||
| aaa | 2 | xx␂yy zz |
|
||||
| aaa | 3 | xx␃yy zz |
|
||||
| aaa | 4 | xx␄yy zz |
|
||||
| aaa | 5 | xx␅yy zz |
|
||||
| aaa | 6 | xx␆yy zz |
|
||||
| aaa | 7 | xx␇yy zz |
|
||||
| aaa | 9 | xx yy zz |
|
||||
| aaa | 11 | xx␋yy zz |
|
||||
| aaa | 12 | xx␌yy zz |
|
||||
| aaa | 15 | xx␏yy zz |
|
||||
+-----+----+--------------------+
|
||||
}
|
||||
|
||||
do_test 9.1 {
|
||||
db eval {
|
||||
CREATE TABLE t9(x);
|
||||
INSERT INTO t9 VALUES
|
||||
(x'4331323334'),
|
||||
(x'c30431323334'),
|
||||
(x'd3000431323334'),
|
||||
(x'e30000000431323334'),
|
||||
(x'f3000000000000000431323334');
|
||||
}
|
||||
db format -style list -text plain -rowsep , -textjsonb on \
|
||||
{SELECT * FROM t9}
|
||||
} {1234,1234,1234,1234,1234,}
|
||||
do_test 9.2 {
|
||||
db format -style list -text sql -rowsep , -textjsonb on \
|
||||
{SELECT * FROM t9}
|
||||
} {jsonb('1234'),jsonb('1234'),jsonb('1234'),jsonb('1234'),jsonb('1234'),}
|
||||
db close
|
||||
|
||||
finish_test
|
||||
@@ -0,0 +1,47 @@
|
||||
# 2025-11-05
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# Test cases for the Query Result Formatter (QRF)
|
||||
#
|
||||
# These tests are for EXPLAIN and EXPLAIN QUERY PLAN formatting, the
|
||||
# output of which can change when enhancments are made to the query
|
||||
# planner. So expect to have to modify the expected results of these
|
||||
# test cases in the future.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix qrf02
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(a);
|
||||
INSERT INTO t1 VALUES(1);
|
||||
}
|
||||
|
||||
set result [db format {EXPLAIN SELECT * FROM t1}]
|
||||
do_test 1.10 {
|
||||
set result
|
||||
} {/*addr opcode p1 p2 p3 p4 p5 comment
|
||||
---- ------------- ---- ---- ---- ------------- -- -------------
|
||||
0 Init */}
|
||||
regsub -all {\d+} $result {N} result2
|
||||
do_test 1.11 {
|
||||
set result2
|
||||
} "/.*\nN Rewind .*\nN Column .*/"
|
||||
|
||||
do_test 1.20 {
|
||||
set result "\n[db format {EXPLAIN QUERY PLAN SELECT * FROM t1}]"
|
||||
} {
|
||||
QUERY PLAN
|
||||
`--SCAN t1
|
||||
}
|
||||
|
||||
finish_test
|
||||
+176
@@ -0,0 +1,176 @@
|
||||
# 2025-11-15
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# Test cases for the Query Result Formatter (QRF)
|
||||
#
|
||||
# Format narrowing due to nScreenWidth
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix qrf03
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE mlink(
|
||||
mid INTEGER,
|
||||
fid INTEGER,
|
||||
pmid INTEGER,
|
||||
pid INTEGER,
|
||||
fnid INTEGER REFERENCES filename,
|
||||
pfnid INTEGER,
|
||||
mperm INTEGER,
|
||||
isaux BOOLEAN DEFAULT 0
|
||||
);
|
||||
INSERT INTO mlink VALUES(28775,28774,28773,28706,1,0,0,0);
|
||||
INSERT INTO mlink VALUES(28773,28706,28770,28685,1,0,0,0);
|
||||
INSERT INTO mlink VALUES(28770,28736,28769,28695,2,0,0,0);
|
||||
INSERT INTO mlink VALUES(28770,28697,28769,28698,3,0,0,0);
|
||||
INSERT INTO mlink VALUES(28767,28768,28759,28746,4,0,0,0);
|
||||
CREATE TABLE event(
|
||||
type TEXT,
|
||||
mtime DATETIME,
|
||||
objid INTEGER PRIMARY KEY,
|
||||
tagid INTEGER,
|
||||
uid INTEGER REFERENCES user,
|
||||
bgcolor TEXT,
|
||||
euser TEXT,
|
||||
user TEXT,
|
||||
ecomment TEXT,
|
||||
comment TEXT,
|
||||
brief TEXT,
|
||||
omtime DATETIME
|
||||
);
|
||||
INSERT INTO event VALUES('ci',2460994.978048461023,126223,NULL,NULL,NULL,NULL,'drh',NULL,unistr('Data structure improvements on columnar layout. Prep work for getting\u000acolumnar layouts to respond to nScreenWidth.'),NULL,2460994.978048461023);
|
||||
INSERT INTO event VALUES('ci',2460994.836955601816,126218,NULL,NULL,NULL,NULL,'stephan',NULL,'API doc typo fix.',NULL,2460994.836955601816);
|
||||
INSERT INTO event VALUES('ci',2460994.88823369192,126212,NULL,NULL,NULL,NULL,'stephan',NULL,'Move sqlite3-api-cleanup.js into post-js-footer.js to remove the final direct Emscripten dependency from the intermediary build product sqlite3-api.js (the whole library, waiting to be bootstrapped). This is partly in response to [forum:4b7d45433731d2e0|forum post 4b7d45433731d2e0], which demonstrates a potential use case for a standalone sqlite3-api.js. This is a build/doc change, not a functional one.',NULL,2460994.88823369192);
|
||||
INSERT INTO event VALUES('ci',2460994.516081551089,126211,NULL,NULL,NULL,NULL,'drh',NULL,unistr('Improve columnar layout in QRF so that it correctly deals with control\u000acharacters, and especially tabs.'),NULL,2460994.516081551089);
|
||||
INSERT INTO event VALUES('ci',2460994.409343171865,126208,NULL,NULL,NULL,NULL,'drh',NULL,'Make use of the new sqlite3_str_free() interface in the CLI.',NULL,2460994.409343171865);
|
||||
}
|
||||
|
||||
do_test 1.10 {
|
||||
set x "\n[db format -style box -screenwidth 68 \
|
||||
{SELECT * FROM mlink ORDER BY rowid}]"
|
||||
|
||||
} {
|
||||
┌───────┬───────┬───────┬───────┬──────┬───────┬───────┬───────┐
|
||||
│ mid │ fid │ pmid │ pid │ fnid │ pfnid │ mperm │ isaux │
|
||||
├───────┼───────┼───────┼───────┼──────┼───────┼───────┼───────┤
|
||||
│ 28775 │ 28774 │ 28773 │ 28706 │ 1 │ 0 │ 0 │ 0 │
|
||||
│ 28773 │ 28706 │ 28770 │ 28685 │ 1 │ 0 │ 0 │ 0 │
|
||||
│ 28770 │ 28736 │ 28769 │ 28695 │ 2 │ 0 │ 0 │ 0 │
|
||||
│ 28770 │ 28697 │ 28769 │ 28698 │ 3 │ 0 │ 0 │ 0 │
|
||||
│ 28767 │ 28768 │ 28759 │ 28746 │ 4 │ 0 │ 0 │ 0 │
|
||||
└───────┴───────┴───────┴───────┴──────┴───────┴───────┴───────┘
|
||||
}
|
||||
do_test 1.11 {
|
||||
set x "\n[db format -style box -screenwidth 52 \
|
||||
{SELECT * FROM mlink ORDER BY rowid}]"
|
||||
|
||||
} {
|
||||
┌─────┬─────┬─────┬─────┬────┬─────┬─────┬─────┐
|
||||
│ mid │ fid │pmid │ pid │fnid│pfnid│mperm│isaux│
|
||||
├─────┼─────┼─────┼─────┼────┼─────┼─────┼─────┤
|
||||
│28775│28774│28773│28706│1 │0 │0 │0 │
|
||||
│28773│28706│28770│28685│1 │0 │0 │0 │
|
||||
│28770│28736│28769│28695│2 │0 │0 │0 │
|
||||
│28770│28697│28769│28698│3 │0 │0 │0 │
|
||||
│28767│28768│28759│28746│4 │0 │0 │0 │
|
||||
└─────┴─────┴─────┴─────┴────┴─────┴─────┴─────┘
|
||||
}
|
||||
|
||||
do_test 1.20 {
|
||||
set x "\n[db format -style table -screenwidth 68 \
|
||||
{SELECT * FROM mlink ORDER BY rowid}]"
|
||||
|
||||
} {
|
||||
+-------+-------+-------+-------+------+-------+-------+-------+
|
||||
| mid | fid | pmid | pid | fnid | pfnid | mperm | isaux |
|
||||
+-------+-------+-------+-------+------+-------+-------+-------+
|
||||
| 28775 | 28774 | 28773 | 28706 | 1 | 0 | 0 | 0 |
|
||||
| 28773 | 28706 | 28770 | 28685 | 1 | 0 | 0 | 0 |
|
||||
| 28770 | 28736 | 28769 | 28695 | 2 | 0 | 0 | 0 |
|
||||
| 28770 | 28697 | 28769 | 28698 | 3 | 0 | 0 | 0 |
|
||||
| 28767 | 28768 | 28759 | 28746 | 4 | 0 | 0 | 0 |
|
||||
+-------+-------+-------+-------+------+-------+-------+-------+
|
||||
}
|
||||
do_test 1.21 {
|
||||
set x "\n[db format -style table -screenwidth 52 \
|
||||
{SELECT * FROM mlink ORDER BY rowid}]"
|
||||
|
||||
} {
|
||||
+-----+-----+-----+-----+----+-----+-----+-----+
|
||||
| mid | fid |pmid | pid |fnid|pfnid|mperm|isaux|
|
||||
+-----+-----+-----+-----+----+-----+-----+-----+
|
||||
|28775|28774|28773|28706|1 |0 |0 |0 |
|
||||
|28773|28706|28770|28685|1 |0 |0 |0 |
|
||||
|28770|28736|28769|28695|2 |0 |0 |0 |
|
||||
|28770|28697|28769|28698|3 |0 |0 |0 |
|
||||
|28767|28768|28759|28746|4 |0 |0 |0 |
|
||||
+-----+-----+-----+-----+----+-----+-----+-----+
|
||||
}
|
||||
|
||||
do_test 1.30 {
|
||||
set x "\n[db format -style markdown -screenwidth 68 \
|
||||
{SELECT * FROM mlink ORDER BY rowid}]"
|
||||
|
||||
} {
|
||||
| mid | fid | pmid | pid | fnid | pfnid | mperm | isaux |
|
||||
|-------|-------|-------|-------|------|-------|-------|-------|
|
||||
| 28775 | 28774 | 28773 | 28706 | 1 | 0 | 0 | 0 |
|
||||
| 28773 | 28706 | 28770 | 28685 | 1 | 0 | 0 | 0 |
|
||||
| 28770 | 28736 | 28769 | 28695 | 2 | 0 | 0 | 0 |
|
||||
| 28770 | 28697 | 28769 | 28698 | 3 | 0 | 0 | 0 |
|
||||
| 28767 | 28768 | 28759 | 28746 | 4 | 0 | 0 | 0 |
|
||||
}
|
||||
do_test 1.31 {
|
||||
set x "\n[db format -style markdown -screenwidth 52 \
|
||||
{SELECT * FROM mlink ORDER BY rowid}]"
|
||||
|
||||
} {
|
||||
| mid | fid |pmid | pid |fnid|pfnid|mperm|isaux|
|
||||
|-----|-----|-----|-----|----|-----|-----|-----|
|
||||
|28775|28774|28773|28706|1 |0 |0 |0 |
|
||||
|28773|28706|28770|28685|1 |0 |0 |0 |
|
||||
|28770|28736|28769|28695|2 |0 |0 |0 |
|
||||
|28770|28697|28769|28698|3 |0 |0 |0 |
|
||||
|28767|28768|28759|28746|4 |0 |0 |0 |
|
||||
}
|
||||
|
||||
do_test 1.40 {
|
||||
set x "\n[db format -style column -screenwidth 68 \
|
||||
{SELECT * FROM mlink ORDER BY rowid}]"
|
||||
|
||||
} {
|
||||
mid fid pmid pid fnid pfnid mperm isaux
|
||||
----- ----- ----- ----- ---- ----- ----- -----
|
||||
28775 28774 28773 28706 1 0 0 0
|
||||
28773 28706 28770 28685 1 0 0 0
|
||||
28770 28736 28769 28695 2 0 0 0
|
||||
28770 28697 28769 28698 3 0 0 0
|
||||
28767 28768 28759 28746 4 0 0 0
|
||||
}
|
||||
do_test 1.41 {
|
||||
set x "\n[db format -style column -screenwidth 52 \
|
||||
{SELECT * FROM mlink ORDER BY rowid}]"
|
||||
|
||||
} {
|
||||
mid fid pmid pid fnid pfnid mperm isaux
|
||||
----- ----- ----- ----- ---- ----- ----- -----
|
||||
28775 28774 28773 28706 1 0 0 0
|
||||
28773 28706 28770 28685 1 0 0 0
|
||||
28770 28736 28769 28695 2 0 0 0
|
||||
28770 28697 28769 28698 3 0 0 0
|
||||
28767 28768 28759 28746 4 0 0 0
|
||||
}
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
+1
-1
@@ -42,7 +42,7 @@ proc compare_dbs {db1 db2} {
|
||||
|
||||
proc recover_with_opts {opts} {
|
||||
set cmd ".recover $opts"
|
||||
set fd [open [list |$::CLI test.db $cmd]]
|
||||
set fd [open [list |$::CLI -noinit test.db $cmd]]
|
||||
fconfigure $fd -translation binary
|
||||
set sql [read $fd]
|
||||
close $fd
|
||||
|
||||
+89
-72
@@ -48,7 +48,7 @@ do_test shell1-1.1.1b {
|
||||
} {1 1}
|
||||
# error on extra options
|
||||
do_test shell1-1.1.2 {
|
||||
catchcmd "test.db \"select+3\" \"select+4\"" ""
|
||||
catchcmd "-compat 20250101 test.db \"select+3\" \"select+4\"" ""
|
||||
} {0 {3
|
||||
4}}
|
||||
# error on extra options
|
||||
@@ -182,7 +182,7 @@ do_test shell1-1.17.1 {
|
||||
catchcmd {-- --db "CREATE TABLE T(c1);"}
|
||||
} {0 {}}
|
||||
do_test shell1-1.17.2 {
|
||||
catchcmd {-- --db "SELECT name from sqlite_schema;"}
|
||||
catchcmd {-compat 20250101 -- --db "SELECT name from sqlite_schema;"}
|
||||
} {0 T}
|
||||
forcedelete ./--db
|
||||
|
||||
@@ -216,10 +216,14 @@ 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 qbox quote table tabs tcl}}
|
||||
} {1 {line 1: .mode "insert FOO
|
||||
line 1: ^--- unknown mode
|
||||
line 1: Use ".help .mode" for more info}}
|
||||
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 qbox quote table tabs tcl}}
|
||||
} {1 {line 1: .mode 'insert FOO
|
||||
line 1: ^--- unknown mode
|
||||
line 1: Use ".help .mode" for more info}}
|
||||
|
||||
# check multiple tokens, and quoted tokens
|
||||
do_test shell1-2.3.1 {
|
||||
@@ -247,7 +251,9 @@ 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 qbox quote table tabs tcl}}
|
||||
} {1 {line 1: .mode FOO
|
||||
line 1: ^--- unknown mode
|
||||
line 1: Use ".help .mode" for more info}}
|
||||
do_test shell1-2.4.2 {
|
||||
catchcmd "test.db" ".mode csv"
|
||||
} {0 {}}
|
||||
@@ -364,7 +370,6 @@ do_test shell1-3.7.4 {
|
||||
catchcmd "test.db" ".explain OFF BAD"
|
||||
} {0 {}}
|
||||
|
||||
|
||||
# .header(s) ON|OFF Turn display of headers on or off
|
||||
do_test shell1-3.9.1 {
|
||||
catchcmd "test.db" ".header"
|
||||
@@ -400,7 +405,7 @@ do_test shell1-3.10.1 {
|
||||
# look for a few of the possible help commands
|
||||
list [regexp {.help} $res] \
|
||||
[regexp {.quit} $res] \
|
||||
[regexp {.show} $res]
|
||||
[regexp {.mode} $res]
|
||||
} {1 1 1}
|
||||
do_test shell1-3.10.2 {
|
||||
# we allow .help to take extra args (it is help after all)
|
||||
@@ -408,7 +413,7 @@ do_test shell1-3.10.2 {
|
||||
# look for a few of the possible help commands
|
||||
list [regexp {.help} $res] \
|
||||
[regexp {.quit} $res] \
|
||||
[regexp {.show} $res]
|
||||
[regexp {.mode} $res]
|
||||
} {1 1 1}
|
||||
|
||||
# .import FILE TABLE Import data from FILE into TABLE
|
||||
@@ -421,7 +426,8 @@ do_test shell1-3.11.2 {
|
||||
do_test shell1-3.11.3 {
|
||||
# too many arguments
|
||||
catchcmd "test.db" ".import FOO BAR BAD"
|
||||
} {/1 .ERROR: extra argument: "BAD".*./}
|
||||
} {1 {line 1: .import FOO BAR BAD
|
||||
line 1: ^--- unknown argument}}
|
||||
|
||||
# .indexes ?TABLE? Show names of all indexes
|
||||
# If TABLE specified, only show indexes for tables
|
||||
@@ -451,11 +457,13 @@ do_test shell1-3.12.3 {
|
||||
# tabs Tab-separated values
|
||||
# tcl TCL list elements
|
||||
do_test shell1-3.13.1 {
|
||||
catchcmd "test.db" ".mode"
|
||||
} {0 {current output mode: list --escape ascii}}
|
||||
catchcmd "test.db" ".mode batch\n.mode"
|
||||
} {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 qbox quote table tabs tcl}}
|
||||
} {1 {line 1: .mode FOO
|
||||
line 1: ^--- unknown mode
|
||||
line 1: Use ".help .mode" for more info}}
|
||||
do_test shell1-3.13.3 {
|
||||
catchcmd "test.db" ".mode csv"
|
||||
} {0 {}}
|
||||
@@ -503,7 +511,7 @@ do_test shell1-3.15.1 {
|
||||
.print x"
|
||||
} {0 x}
|
||||
do_test shell1-3.15.2 {
|
||||
catchcmd "test.db" ".output FOO
|
||||
catchcmd "test.db" ".mode batch\n.output FOO
|
||||
.print x
|
||||
.output
|
||||
SELECT readfile('FOO');"
|
||||
@@ -512,17 +520,8 @@ SELECT readfile('FOO');"
|
||||
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.
|
||||
If FILE is 'off' then output is disabled.
|
||||
Options:
|
||||
--bom Prefix output with a UTF8 byte-order mark
|
||||
-e Send output to the system text editor
|
||||
--plain Use text/plain for -w option
|
||||
-w Send output to a web browser
|
||||
-x Send output as CSV to a spreadsheet
|
||||
child process exited abnormally}}
|
||||
} {1 {line 1: .output FOO BAD
|
||||
line 1: ^--- surplus argument}}
|
||||
|
||||
# .output stdout Send output to the screen
|
||||
do_test shell1-3.16.1 {
|
||||
@@ -531,17 +530,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.
|
||||
If FILE is 'off' then output is disabled.
|
||||
Options:
|
||||
--bom Prefix output with a UTF8 byte-order mark
|
||||
-e Send output to the system text editor
|
||||
--plain Use text/plain for -w option
|
||||
-w Send output to a web browser
|
||||
-x Send output as CSV to a spreadsheet
|
||||
child process exited abnormally}}
|
||||
} {1 {line 1: .output stdout BAD
|
||||
line 1: ^--- surplus argument}}
|
||||
|
||||
# .prompt MAIN CONTINUE Replace the standard prompts
|
||||
do_test shell1-3.17.1 {
|
||||
@@ -643,7 +633,7 @@ do_test shell1-3.22.4 {
|
||||
|
||||
# .show Show the current values for various settings
|
||||
do_test shell1-3.23.1 {
|
||||
set res [catchcmd "test.db" ".show"]
|
||||
set res [catchcmd "test.db" ".mode batch\n.show"]
|
||||
list [regexp {echo:} $res] \
|
||||
[regexp {explain:} $res] \
|
||||
[regexp {headers:} $res] \
|
||||
@@ -679,7 +669,7 @@ do_test shell1-3.23b.4 {
|
||||
# Adverse interaction between .stats and .eqp
|
||||
#
|
||||
do_test shell1-3.23b.5 {
|
||||
catchcmd "test.db" [string map {"\n " "\n"} {
|
||||
catchcmd "test.db" [string map {"\n " "\n"} {.mode batch
|
||||
CREATE TEMP TABLE t1(x);
|
||||
INSERT INTO t1 VALUES(1),(2);
|
||||
.stats on
|
||||
@@ -762,9 +752,9 @@ do_test shell1-3.27.4 {
|
||||
catchcmd "test.db" ".timer OFF BAD"
|
||||
} {1 {Usage: .timer on|off}}
|
||||
|
||||
do_test shell1-3-28.1 {
|
||||
do_test shell1-3.28.1 {
|
||||
catchcmd test.db \
|
||||
".log stdout\nSELECT coalesce(sqlite_log(123,'hello'),'456');"
|
||||
".mode batch\n.log stdout\nSELECT coalesce(sqlite_log(123,'hello'),'456');"
|
||||
} "0 {(123) hello\n456}"
|
||||
|
||||
do_test shell1-3-29.1 {
|
||||
@@ -803,14 +793,14 @@ INSERT INTO t1 VALUES('');
|
||||
INSERT INTO t1 VALUES(1);
|
||||
INSERT INTO t1 VALUES(2.25);
|
||||
INSERT INTO t1 VALUES('hello');
|
||||
INSERT INTO t1 VALUES(X'807f');
|
||||
INSERT INTO t1 VALUES(x'807f');
|
||||
CREATE TABLE t3(x,y);
|
||||
INSERT INTO t3 VALUES(1,NULL);
|
||||
INSERT INTO t3 VALUES(2,'');
|
||||
INSERT INTO t3 VALUES(3,1);
|
||||
INSERT INTO t3 VALUES(4,2.25);
|
||||
INSERT INTO t3 VALUES(5,'hello');
|
||||
INSERT INTO t3 VALUES(6,X'807f');
|
||||
INSERT INTO t3 VALUES(6,x'807f');
|
||||
COMMIT;}}
|
||||
|
||||
|
||||
@@ -828,14 +818,14 @@ INSERT INTO t1(rowid,x) VALUES(2,'');
|
||||
INSERT INTO t1(rowid,x) VALUES(3,1);
|
||||
INSERT INTO t1(rowid,x) VALUES(4,2.25);
|
||||
INSERT INTO t1(rowid,x) VALUES(5,'hello');
|
||||
INSERT INTO t1(rowid,x) VALUES(6,X'807f');
|
||||
INSERT INTO t1(rowid,x) VALUES(6,x'807f');
|
||||
CREATE TABLE t3(x,y);
|
||||
INSERT INTO t3(rowid,x,y) VALUES(1,1,NULL);
|
||||
INSERT INTO t3(rowid,x,y) VALUES(2,2,'');
|
||||
INSERT INTO t3(rowid,x,y) VALUES(3,3,1);
|
||||
INSERT INTO t3(rowid,x,y) VALUES(4,4,2.25);
|
||||
INSERT INTO t3(rowid,x,y) VALUES(5,5,'hello');
|
||||
INSERT INTO t3(rowid,x,y) VALUES(6,6,X'807f');
|
||||
INSERT INTO t3(rowid,x,y) VALUES(6,6,x'807f');
|
||||
COMMIT;}}
|
||||
|
||||
# If the table contains an INTEGER PRIMARY KEY, do not record a separate
|
||||
@@ -854,12 +844,12 @@ do_test shell1-4.1.2 {
|
||||
} {0 {PRAGMA foreign_keys=OFF;
|
||||
BEGIN TRANSACTION;
|
||||
CREATE TABLE t1(x INTEGER PRIMARY KEY, y);
|
||||
INSERT INTO t1 VALUES(1,NULL);
|
||||
INSERT INTO t1 VALUES(2,'');
|
||||
INSERT INTO t1 VALUES(3,1);
|
||||
INSERT INTO t1 VALUES(4,2.25);
|
||||
INSERT INTO t1 VALUES(5,'hello');
|
||||
INSERT INTO t1 VALUES(6,X'807f');
|
||||
INSERT INTO t1(x,y) VALUES(1,NULL);
|
||||
INSERT INTO t1(x,y) VALUES(2,'');
|
||||
INSERT INTO t1(x,y) VALUES(3,1);
|
||||
INSERT INTO t1(x,y) VALUES(4,2.25);
|
||||
INSERT INTO t1(x,y) VALUES(5,'hello');
|
||||
INSERT INTO t1(x,y) VALUES(6,x'807f');
|
||||
COMMIT;}}
|
||||
|
||||
# Verify that the table named [table] is correctly quoted and that
|
||||
@@ -883,7 +873,7 @@ INSERT INTO "table"(rowid,x,y) VALUES(2,12,'');
|
||||
INSERT INTO "table"(rowid,x,y) VALUES(3,23,1);
|
||||
INSERT INTO "table"(rowid,x,y) VALUES(4,34,2.25);
|
||||
INSERT INTO "table"(rowid,x,y) VALUES(5,45,'hello');
|
||||
INSERT INTO "table"(rowid,x,y) VALUES(6,56,X'807f');
|
||||
INSERT INTO "table"(rowid,x,y) VALUES(6,56,x'807f');
|
||||
COMMIT;}}
|
||||
|
||||
# Do not record rowids for a WITHOUT ROWID table. Also check correct quoting
|
||||
@@ -902,12 +892,12 @@ do_test shell1-4.1.4 {
|
||||
} {0 {PRAGMA foreign_keys=OFF;
|
||||
BEGIN TRANSACTION;
|
||||
CREATE TABLE [ta<>ble](x INTEGER PRIMARY KEY, y) WITHOUT ROWID;
|
||||
INSERT INTO "ta<>ble" VALUES(1,NULL);
|
||||
INSERT INTO "ta<>ble" VALUES(12,'');
|
||||
INSERT INTO "ta<>ble" VALUES(23,1);
|
||||
INSERT INTO "ta<>ble" VALUES(34,2.25);
|
||||
INSERT INTO "ta<>ble" VALUES(45,'hello');
|
||||
INSERT INTO "ta<>ble" VALUES(56,X'807f');
|
||||
INSERT INTO "ta<>ble"(x,y) VALUES(1,NULL);
|
||||
INSERT INTO "ta<>ble"(x,y) VALUES(12,'');
|
||||
INSERT INTO "ta<>ble"(x,y) VALUES(23,1);
|
||||
INSERT INTO "ta<>ble"(x,y) VALUES(34,2.25);
|
||||
INSERT INTO "ta<>ble"(x,y) VALUES(45,'hello');
|
||||
INSERT INTO "ta<>ble"(x,y) VALUES(56,x'807f');
|
||||
COMMIT;}}
|
||||
|
||||
# Do not record rowids if the rowid is inaccessible
|
||||
@@ -924,9 +914,9 @@ do_test shell1-4.1.5 {
|
||||
} {0 {PRAGMA foreign_keys=OFF;
|
||||
BEGIN TRANSACTION;
|
||||
CREATE TABLE t1(_ROWID_,rowid,oid);
|
||||
INSERT INTO t1 VALUES(1,NULL,'alpha');
|
||||
INSERT INTO t1 VALUES(12,'',99);
|
||||
INSERT INTO t1 VALUES(23,1,X'b0b1b2');
|
||||
INSERT INTO t1(_ROWID_,rowid,oid) VALUES(1,NULL,'alpha');
|
||||
INSERT INTO t1(_ROWID_,rowid,oid) VALUES(12,'',99);
|
||||
INSERT INTO t1(_ROWID_,rowid,oid) VALUES(23,1,x'b0b1b2');
|
||||
COMMIT;}}
|
||||
|
||||
} else {
|
||||
@@ -1020,7 +1010,7 @@ INSERT INTO t1 VALUES('');
|
||||
INSERT INTO t1 VALUES(1);
|
||||
INSERT INTO t1 VALUES(2.25);
|
||||
INSERT INTO t1 VALUES('hello');
|
||||
INSERT INTO t1 VALUES(X'807f');}}
|
||||
INSERT INTO t1 VALUES(x'807f');}}
|
||||
|
||||
# Test the output of ".mode insert" with headers
|
||||
#
|
||||
@@ -1031,7 +1021,7 @@ INSERT INTO t1(x) VALUES('');
|
||||
INSERT INTO t1(x) VALUES(1);
|
||||
INSERT INTO t1(x) VALUES(2.25);
|
||||
INSERT INTO t1(x) VALUES('hello');
|
||||
INSERT INTO t1(x) VALUES(X'807f');}}
|
||||
INSERT INTO t1(x) VALUES(x'807f');}}
|
||||
|
||||
# Test the output of ".mode insert"
|
||||
#
|
||||
@@ -1042,7 +1032,7 @@ INSERT INTO t3 VALUES(2,'');
|
||||
INSERT INTO t3 VALUES(3,1);
|
||||
INSERT INTO t3 VALUES(4,2.25);
|
||||
INSERT INTO t3 VALUES(5,'hello');
|
||||
INSERT INTO t3 VALUES(6,X'807f');}}
|
||||
INSERT INTO t3 VALUES(6,x'807f');}}
|
||||
|
||||
# Test the output of ".mode insert" with headers
|
||||
#
|
||||
@@ -1053,7 +1043,7 @@ INSERT INTO t3(x,y) VALUES(2,'');
|
||||
INSERT INTO t3(x,y) VALUES(3,1);
|
||||
INSERT INTO t3(x,y) VALUES(4,2.25);
|
||||
INSERT INTO t3(x,y) VALUES(5,'hello');
|
||||
INSERT INTO t3(x,y) VALUES(6,X'807f');}}
|
||||
INSERT INTO t3(x,y) VALUES(6,x'807f');}}
|
||||
|
||||
# Test the output of ".mode tcl"
|
||||
#
|
||||
@@ -1069,8 +1059,8 @@ do_test shell1-4.3 {
|
||||
catchcmd test.db ".mode tcl\nselect * from t1;"
|
||||
} {0 {""
|
||||
""
|
||||
"1"
|
||||
"2.25"
|
||||
1
|
||||
2.25
|
||||
"hello"
|
||||
"\200\177"}}
|
||||
|
||||
@@ -1083,15 +1073,15 @@ do_test shell1-4.4 {
|
||||
}
|
||||
catchcmd test.db ".mode tcl\nselect * from t2;"
|
||||
} {0 {"" ""
|
||||
"1" "2.25"
|
||||
1 2.25
|
||||
"hello" "\200\177"}}
|
||||
|
||||
# Test the output of ".mode tcl" with ".nullvalue"
|
||||
#
|
||||
do_test shell1-4.5 {
|
||||
catchcmd test.db ".mode tcl\n.nullvalue NULL\nselect * from t2;"
|
||||
} {0 {"NULL" ""
|
||||
"1" "2.25"
|
||||
} {0 {NULL ""
|
||||
1 2.25
|
||||
"hello" "\200\177"}}
|
||||
|
||||
# Test the output of ".mode tcl" with Tcl reserved characters
|
||||
@@ -1115,7 +1105,7 @@ do_test shell1-4.6 {
|
||||
#
|
||||
do_test shell1-4.7 {
|
||||
catchcmd test.db ".mode quote\nselect x'0123456789ABCDEF';"
|
||||
} {0 X'0123456789abcdef'}
|
||||
} {0 x'0123456789abcdef'}
|
||||
|
||||
# Test using arbitrary byte data with the shell via standard input/output.
|
||||
#
|
||||
@@ -1274,7 +1264,7 @@ do_test shell1-7.1.7 {
|
||||
# information.
|
||||
#
|
||||
do_test shell1-8.1 {
|
||||
catchcmd ":memory:" {
|
||||
catchcmd ":memory:" {.mode batch
|
||||
-- The pow2 table will hold all the necessary powers of two.
|
||||
CREATE TABLE pow2(x INTEGER PRIMARY KEY, v TEXT);
|
||||
WITH RECURSIVE c(x,v) AS (
|
||||
@@ -1326,6 +1316,7 @@ do_test_with_ansi_output shell1-8.5 {
|
||||
create table t(a text, b int);
|
||||
insert into t values ('too long for one line', 1), ('shorter', NULL);
|
||||
.header on
|
||||
.mode box --wordwrap off
|
||||
.width 10 10
|
||||
.nullvalue NADA
|
||||
select * from t;}
|
||||
@@ -1344,12 +1335,12 @@ select * from t;}
|
||||
#
|
||||
do_test shell1-9.1 {
|
||||
catchcmd :memory: {
|
||||
.mode csv
|
||||
.mode csv --rowsep "\n"
|
||||
/*
|
||||
x */ select 1,2; --x
|
||||
-- .nada
|
||||
;
|
||||
.mode csv
|
||||
.mode csv --rowsep "\n"
|
||||
--x
|
||||
select 2,1; select 3,4;
|
||||
}
|
||||
@@ -1387,4 +1378,30 @@ select base85(zeroblob(2000000000));
|
||||
}
|
||||
} {/1.*too big.*/}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# As of 2025-11-17, the default mode is:
|
||||
#
|
||||
# qbox --screenwidth auto --linelimit 5 --charlimit 300 --textjsonb on
|
||||
#
|
||||
do_test shell1-12.1 {
|
||||
catchcmd :memory: {.mode tty
|
||||
.print
|
||||
SELECT jsonb(1234) AS x;}
|
||||
} {0 {
|
||||
┌───────────────┐
|
||||
│ x │
|
||||
├───────────────┤
|
||||
│ jsonb('1234') │
|
||||
└───────────────┘}}
|
||||
do_test shell1-12.2 {
|
||||
catchcmd :memory: {.mode box --textjsonb on
|
||||
.print
|
||||
SELECT jsonb(1234) AS x;}
|
||||
} {0 {
|
||||
┌──────┐
|
||||
│ x │
|
||||
├──────┤
|
||||
│ 1234 │
|
||||
└──────┘}}
|
||||
|
||||
finish_test
|
||||
|
||||
+79
-9
@@ -44,7 +44,7 @@ do_test shell2-1.1.1 {
|
||||
# Shell silently ignores extra parameters.
|
||||
# Ticket [f5cb008a65].
|
||||
do_test shell2-1.2.1 {
|
||||
catchcmdex {:memory: "select+3" "select+4"}
|
||||
catchcmdex {:memory: -list "select+3" "select+4"}
|
||||
} {0 {3
|
||||
4
|
||||
}}
|
||||
@@ -64,7 +64,7 @@ do_test shell2-1.3 {
|
||||
|
||||
UPDATE OR REPLACE t5 SET a = 4 WHERE a = 1;
|
||||
}
|
||||
} {1 {Runtime error near line 9: too many levels of trigger recursion}}
|
||||
} {1 {Error near line 9: too many levels of trigger recursion}}
|
||||
|
||||
|
||||
|
||||
@@ -75,7 +75,8 @@ do_test shell2-1.3 {
|
||||
# NB. whitespace is important
|
||||
do_test shell2-1.4.1 {
|
||||
forcedelete foo.db
|
||||
catchcmd "foo.db" {CREATE TABLE foo(a);
|
||||
catchcmd "foo.db" {.mode batch
|
||||
CREATE TABLE foo(a);
|
||||
INSERT INTO foo(a) VALUES(1);
|
||||
SELECT * FROM foo;}
|
||||
} {0 1}
|
||||
@@ -84,7 +85,7 @@ SELECT * FROM foo;}
|
||||
# NB. whitespace is important
|
||||
do_test shell2-1.4.2 {
|
||||
forcedelete foo.db
|
||||
catchcmd "-echo foo.db" {CREATE TABLE foo(a);
|
||||
catchcmd "-compat 20250101 -echo foo.db" {CREATE TABLE foo(a);
|
||||
INSERT INTO foo(a) VALUES(1);
|
||||
SELECT * FROM foo;}
|
||||
} {0 {CREATE TABLE foo(a);
|
||||
@@ -96,7 +97,9 @@ SELECT * FROM foo;
|
||||
# NB. whitespace is important
|
||||
do_test shell2-1.4.3 {
|
||||
forcedelete foo.db
|
||||
catchcmd "foo.db" {.echo ON
|
||||
catchcmd "foo.db" {
|
||||
.mode batch
|
||||
.echo ON
|
||||
CREATE TABLE foo(a);
|
||||
INSERT INTO foo(a) VALUES(1);
|
||||
SELECT * FROM foo;}
|
||||
@@ -110,7 +113,9 @@ SELECT * FROM foo;
|
||||
# NB. whitespace is important
|
||||
do_test shell2-1.4.4 {
|
||||
forcedelete foo.db
|
||||
catchcmd "foo.db" {.echo ON
|
||||
catchcmd "foo.db" {
|
||||
.mode batch
|
||||
.echo ON
|
||||
CREATE TABLE foo(a);
|
||||
.echo OFF
|
||||
INSERT INTO foo(a) VALUES(1);
|
||||
@@ -124,7 +129,9 @@ SELECT * FROM foo;}
|
||||
# NB. whitespace is important
|
||||
do_test shell2-1.4.5 {
|
||||
forcedelete foo.db
|
||||
catchcmdex "foo.db" {.echo ON
|
||||
catchcmdex "foo.db" {
|
||||
.mode batch
|
||||
.echo ON
|
||||
CREATE TABLE foo1(a);
|
||||
INSERT INTO foo1(a) VALUES(1);
|
||||
CREATE TABLE foo2(b);
|
||||
@@ -153,7 +160,9 @@ SELECT * FROM foo1; SELECT * FROM foo2;
|
||||
# NB. whitespace is important
|
||||
do_test shell2-1.4.6 {
|
||||
forcedelete foo.db
|
||||
catchcmdex "foo.db" {.echo ON
|
||||
catchcmdex "foo.db" {
|
||||
.mode batch
|
||||
.echo ON
|
||||
.headers ON
|
||||
CREATE TABLE foo1(a);
|
||||
INSERT INTO foo1(a) VALUES(1);
|
||||
@@ -208,6 +217,7 @@ do_test shell2-1.4.9 {
|
||||
do_test shell2-1.4.9 {
|
||||
forcedelete clone.db
|
||||
set res [catchcmd :memory: [string trim {
|
||||
.mode batch
|
||||
CREATE TABLE t(id INTEGER PRIMARY KEY AUTOINCREMENT);
|
||||
INSERT INTO t VALUES (1),(2);
|
||||
.clone clone.db
|
||||
@@ -222,6 +232,7 @@ ifcapable vtab {
|
||||
# See overflow report at https://sqlite.org/forum/forumpost/5d34ce5280
|
||||
do_test shell2-1.4.10 {
|
||||
set res [catchcmd :memory: [string trim {
|
||||
.mode batch
|
||||
SELECT * FROM generate_series(9223372036854775807,9223372036854775807,1);
|
||||
SELECT * FROM generate_series(9223372036854775807,9223372036854775807,-1);
|
||||
SELECT avg(value),min(value),max(value) FROM generate_series(
|
||||
@@ -248,6 +259,65 @@ do_test shell2-1.4.10 {
|
||||
0
|
||||
1
|
||||
2}}
|
||||
do_test shell2-1.4.10b {
|
||||
set res [catchcmd :memory: [string trim {
|
||||
.mode tty
|
||||
.print
|
||||
SELECT * FROM generate_series(9223372036854775807,9223372036854775807,1);
|
||||
SELECT * FROM generate_series(9223372036854775807,9223372036854775807,-1);
|
||||
SELECT avg(value),min(value),max(value) FROM generate_series(
|
||||
-9223372036854775808,9223372036854775807,1085102592571150095);
|
||||
SELECT * FROM generate_series(-9223372036854775808,9223372036854775807,
|
||||
9223372036854775807);
|
||||
SELECT value FROM generate_series(-4611686018427387904,
|
||||
4611686018427387904, 4611686018427387904) ORDER BY value DESC;
|
||||
SELECT * FROM generate_series(0,-2,-1);
|
||||
SELECT * FROM generate_series(0,-2);
|
||||
SELECT * FROM generate_series(0,2) LIMIT 3;}]]
|
||||
} {0 {
|
||||
┌─────────────────────┐
|
||||
│ value │
|
||||
├─────────────────────┤
|
||||
│ 9223372036854775807 │
|
||||
└─────────────────────┘
|
||||
┌─────────────────────┐
|
||||
│ value │
|
||||
├─────────────────────┤
|
||||
│ 9223372036854775807 │
|
||||
└─────────────────────┘
|
||||
┌────────────┬──────────────────────┬─────────────────────┐
|
||||
│ avg(value) │ min(value) │ max(value) │
|
||||
├────────────┼──────────────────────┼─────────────────────┤
|
||||
│ -0.5 │ -9223372036854775808 │ 9223372036854775807 │
|
||||
└────────────┴──────────────────────┴─────────────────────┘
|
||||
┌──────────────────────┐
|
||||
│ value │
|
||||
├──────────────────────┤
|
||||
│ -9223372036854775808 │
|
||||
│ -1 │
|
||||
│ 9223372036854775806 │
|
||||
└──────────────────────┘
|
||||
┌──────────────────────┐
|
||||
│ value │
|
||||
├──────────────────────┤
|
||||
│ 4611686018427387904 │
|
||||
│ 0 │
|
||||
│ -4611686018427387904 │
|
||||
└──────────────────────┘
|
||||
┌───────┐
|
||||
│ value │
|
||||
├───────┤
|
||||
│ 0 │
|
||||
│ -1 │
|
||||
│ -2 │
|
||||
└───────┘
|
||||
┌───────┐
|
||||
│ value │
|
||||
├───────┤
|
||||
│ 0 │
|
||||
│ 1 │
|
||||
│ 2 │
|
||||
└───────┘}}
|
||||
} ;# ifcapable vtab
|
||||
|
||||
ifcapable vtab {
|
||||
@@ -270,7 +340,7 @@ do_test shell2-1.4.11 {
|
||||
# Bug from forum post 7cbe081746dd3803
|
||||
# Keywords as column names were producing an error message.
|
||||
do_test shell2-1.4.12 {
|
||||
set res [catchcmd :memory: [string trim {
|
||||
set res [catchcmd :memory: [string trim {.mode batch
|
||||
CREATE TABLE "group"("order" text);
|
||||
INSERT INTO "group" VALUES ('ABC');
|
||||
.sha3sum}]]
|
||||
|
||||
+1
-1
@@ -109,7 +109,7 @@ do_test shell3-2.7 {
|
||||
# Run combinations of odd identifiers, comments, semicolon placement
|
||||
do_test shell3-3.1 {
|
||||
forcedelete foo.db
|
||||
set rc [ catchcmd "foo.db" {CREATE TABLE t1("
|
||||
set rc [ catchcmd "foo.db -compat 20250101" {CREATE TABLE t1("
|
||||
a--.
|
||||
" --x
|
||||
); CREATE TABLE t2("a[""b""]");
|
||||
|
||||
+4
-4
@@ -136,15 +136,15 @@ SELECT * FROM t1;}
|
||||
|
||||
do_test shell4-3.1 {
|
||||
set fd [open t1.txt wb]
|
||||
puts $fd "SELECT 'squirrel';"
|
||||
puts $fd ".mode list\nSELECT 'squirrel';"
|
||||
close $fd
|
||||
exec $::CLI_ONLY :memory: --interactive ".read t1.txt"
|
||||
exec $::CLI_ONLY --noinit :memory: --interactive ".read t1.txt"
|
||||
} {squirrel}
|
||||
do_test_with_ansi_output shell4-3.2 {
|
||||
set fd [open t1.txt wb]
|
||||
puts $fd "SELECT 'pound: \302\243';"
|
||||
puts $fd ".mode list\nSELECT 'pound: \302\243';"
|
||||
close $fd
|
||||
exec $::CLI_ONLY :memory: --interactive ".read t1.txt"
|
||||
exec $::CLI_ONLY --noinit :memory: --interactive ".read t1.txt"
|
||||
} {pound: £}
|
||||
|
||||
do_test shell4-4.1 {
|
||||
|
||||
+29
-21
@@ -40,7 +40,8 @@ do_test shell5-1.1.2 {
|
||||
do_test shell5-1.1.3 {
|
||||
# too many arguments
|
||||
catchcmd "test.db" ".import FOO BAR BAD"
|
||||
} {/1 .ERROR: extra argument.*/}
|
||||
} {1 {line 1: .import FOO BAR BAD
|
||||
line 1: ^--- unknown argument}}
|
||||
|
||||
# .separator STRING Change separator used by output mode and .import
|
||||
do_test shell5-1.2.1 {
|
||||
@@ -59,13 +60,13 @@ do_test shell5-1.2.4 {
|
||||
|
||||
# column separator should default to "|"
|
||||
do_test shell5-1.3.1.1 {
|
||||
set res [catchcmd "test.db" ".show"]
|
||||
set res [catchcmd "test.db" ".mode list\n.show"]
|
||||
list [regexp {colseparator: \"\|\"} $res]
|
||||
} {1}
|
||||
|
||||
# row separator should default to "\n"
|
||||
do_test shell5-1.3.1.2 {
|
||||
set res [catchcmd "test.db" ".show"]
|
||||
set res [catchcmd "test.db" ".mode list\n.show"]
|
||||
list [regexp {rowseparator: \"\\n\"} $res]
|
||||
} {1}
|
||||
|
||||
@@ -97,7 +98,9 @@ do_test shell5-1.4.2 {
|
||||
forcedelete shell5.csv
|
||||
set in [open shell5.csv w]
|
||||
close $in
|
||||
set res [catchcmd ":memory:" {ATTACH 'test.db' AS test;
|
||||
set res [catchcmd ":memory:" {
|
||||
.mode list
|
||||
ATTACH 'test.db' AS test;
|
||||
.import -schema test shell5.csv t1
|
||||
SELECT COUNT(*) FROM test.t1;}]
|
||||
} {0 0}
|
||||
@@ -116,7 +119,7 @@ do_test shell5-1.4.4 {
|
||||
set in [open shell5.csv w]
|
||||
puts $in "1|2|3"
|
||||
close $in
|
||||
set res [catchcmd ":memory:" {ATTACH 'test.db' AS test;
|
||||
set res [catchcmd ":memory: --list" {ATTACH 'test.db' AS test;
|
||||
.import --schema test shell5.csv t1}]
|
||||
} {1 {shell5.csv:1: expected 2 columns but found 3 - extras ignored}}
|
||||
|
||||
@@ -125,7 +128,7 @@ do_test shell5-1.4.5 {
|
||||
set in [open shell5.csv w]
|
||||
puts $in "1|2"
|
||||
close $in
|
||||
set res [catchcmd "test.db" {DELETE FROM t1;
|
||||
set res [catchcmd "test.db -list" {DELETE FROM t1;
|
||||
.import shell5.csv t1
|
||||
SELECT COUNT(*) FROM t1;}]
|
||||
} {0 1}
|
||||
@@ -138,7 +141,9 @@ do_test shell5-1.4.6 {
|
||||
puts $in "2|3"
|
||||
puts $in "3|4"
|
||||
close $in
|
||||
set res [catchcmd ":memory:" {ATTACH 'test.db' AS test;
|
||||
set res [catchcmd ":memory:" {
|
||||
.mode list
|
||||
ATTACH 'test.db' AS test;
|
||||
.import -schema test shell5.csv t1
|
||||
SELECT COUNT(*) FROM test.t1;}]
|
||||
} {0 3}
|
||||
@@ -148,7 +153,9 @@ do_test shell5-1.4.7 {
|
||||
set in [open shell5.csv w]
|
||||
puts $in "4,5"
|
||||
close $in
|
||||
set res [catchcmd ":memory:" {ATTACH 'test.db' AS test;
|
||||
set res [catchcmd ":memory:" {
|
||||
.mode list
|
||||
ATTACH 'test.db' AS test;
|
||||
.separator ,
|
||||
.import --schema test shell5.csv t1
|
||||
SELECT COUNT(*) FROM test.t1;}]
|
||||
@@ -159,12 +166,13 @@ do_test shell5-1.4.8.1 {
|
||||
set in [open shell5.csv w]
|
||||
puts $in "5|Now is the time for all good men to come to the aid of their country."
|
||||
close $in
|
||||
set res [catchcmd "test.db" {.import shell5.csv t1
|
||||
set res [catchcmd "test.db" {.mode list
|
||||
.import shell5.csv t1
|
||||
SELECT COUNT(*) FROM t1;}]
|
||||
} {0 5}
|
||||
|
||||
do_test shell5-1.4.8.2 {
|
||||
catchcmd "test.db" {SELECT b FROM t1 WHERE a='5';}
|
||||
catchcmd "test.db -list" {SELECT b FROM t1 WHERE a='5';}
|
||||
} {0 {Now is the time for all good men to come to the aid of their country.}}
|
||||
|
||||
# import file with 1 row, 2 columns, quoted text data
|
||||
@@ -174,12 +182,12 @@ do_test shell5-1.4.9.1 {
|
||||
set in [open shell5.csv w]
|
||||
puts $in "6|'Now is the time for all good men to come to the aid of their country.'"
|
||||
close $in
|
||||
set res [catchcmd "test.db" {.import shell5.csv t1
|
||||
set res [catchcmd "test.db -list" {.import shell5.csv t1
|
||||
SELECT COUNT(*) FROM t1;}]
|
||||
} {0 6}
|
||||
|
||||
do_test shell5-1.4.9.2 {
|
||||
catchcmd "test.db" {SELECT b FROM t1 WHERE a='6';}
|
||||
catchcmd "test.db -list" {SELECT b FROM t1 WHERE a='6';}
|
||||
} {0 {'Now is the time for all good men to come to the aid of their country.'}}
|
||||
|
||||
# import file with 1 row, 2 columns, quoted text data
|
||||
@@ -187,12 +195,12 @@ do_test shell5-1.4.10.1 {
|
||||
set in [open shell5.csv w]
|
||||
puts $in "7|\"Now is the time for all good men to come to the aid of their country.\""
|
||||
close $in
|
||||
set res [catchcmd "test.db" {.import shell5.csv t1
|
||||
set res [catchcmd "test.db -list" {.import shell5.csv t1
|
||||
SELECT COUNT(*) FROM t1;}]
|
||||
} {0 7}
|
||||
|
||||
do_test shell5-1.4.10.2 {
|
||||
catchcmd "test.db" {SELECT b FROM t1 WHERE a='7';}
|
||||
catchcmd "test.db -list" {SELECT b FROM t1 WHERE a='7';}
|
||||
} {0 {Now is the time for all good men to come to the aid of their country.}}
|
||||
|
||||
# import file with 2 rows, 2 columns and an initial BOM
|
||||
@@ -203,7 +211,7 @@ do_test shell5-1.4.11 {
|
||||
puts $in "2|3"
|
||||
puts $in "4|5"
|
||||
close $in
|
||||
set res [catchcmd "test.db" {CREATE TABLE t2(x INT, y INT);
|
||||
set res [catchcmd "test.db -list" {CREATE TABLE t2(x INT, y INT);
|
||||
.import shell5.csv t2
|
||||
.mode quote
|
||||
.header on
|
||||
@@ -218,7 +226,7 @@ do_test shell5-1.4.12 {
|
||||
puts $in "\xef\xbb\xbf\"two\"|3"
|
||||
puts $in "4|5"
|
||||
close $in
|
||||
set res [catchcmd "test.db" {DELETE FROM t2;
|
||||
set res [catchcmd "test.db -list" {DELETE FROM t2;
|
||||
.import shell5.csv t2
|
||||
.mode quote
|
||||
.header on
|
||||
@@ -232,7 +240,7 @@ do_test shell5-1.5.1 {
|
||||
set in [open shell5.csv w]
|
||||
puts $in "8|$str"
|
||||
close $in
|
||||
set res [catchcmd "test.db" {.import shell5.csv t1
|
||||
set res [catchcmd "test.db -list" {.import shell5.csv t1
|
||||
SELECT length(b) FROM t1 WHERE a='8';}]
|
||||
} {0 999}
|
||||
|
||||
@@ -252,7 +260,7 @@ do_test shell5-1.6.1 {
|
||||
set in [open shell5.csv w]
|
||||
puts $in $data
|
||||
close $in
|
||||
set res [catchcmd "test.db" {DROP TABLE IF EXISTS t2;
|
||||
set res [catchcmd "test.db -list" {DROP TABLE IF EXISTS t2;
|
||||
.import shell5.csv t2
|
||||
SELECT COUNT(*) FROM t2;}]
|
||||
} {0 1}
|
||||
@@ -576,8 +584,8 @@ do_test_with_ansi_output shell5-6.2 {
|
||||
catchcmd test.db {.import -csv shell5.csv t1
|
||||
.mode line
|
||||
SELECT * FROM t1;}
|
||||
} {0 { 1 = あい
|
||||
2 = うえお}}
|
||||
} {0 {1 = あい
|
||||
2 = うえお}}
|
||||
|
||||
# 2024-03-11 https://sqlite.org/forum/forumpost/ca014d7358
|
||||
# Import into a table that contains computed columns.
|
||||
@@ -588,7 +596,7 @@ do_test shell5-7.1 {
|
||||
puts $out {aaa|bbb}
|
||||
close $out
|
||||
forcedelete test.db
|
||||
catchcmd :memory: {CREATE TABLE t1(a TEXT, b TEXT, c AS (a||b));
|
||||
catchcmd ":memory: -list" {CREATE TABLE t1(a TEXT, b TEXT, c AS (a||b));
|
||||
.import shell5.csv t1
|
||||
SELECT * FROM t1;}
|
||||
} {0 aaa|bbb|aaabbb}
|
||||
|
||||
+27
-31
@@ -36,7 +36,7 @@ do_execsql_test shellA-1.0 {
|
||||
# and that our calls to the CLI are working.
|
||||
#
|
||||
do_test_with_ansi_output shellA-1.2 {
|
||||
exec {*}$CLI test.db {.mode box --escape symbol} {SELECT * FROM t1;}
|
||||
exec {*}$CLI -noinit test.db {.mode box -quote off --escape symbol} {SELECT * FROM t1;}
|
||||
} {
|
||||
┌───┬──────────────────────────┐
|
||||
│ a │ x │
|
||||
@@ -63,33 +63,33 @@ do_test_with_ansi_output shellA-1.2 {
|
||||
# ".mode list"
|
||||
#
|
||||
do_test shellA-1.3 {
|
||||
exec {*}$CLI test.db {SELECT x FROM t1 WHERE a=2;}
|
||||
exec {*}$CLI -noinit -list test.db {SELECT x FROM t1 WHERE a=2;}
|
||||
} {
|
||||
^[[31mVT-100 codes^[[0m
|
||||
}
|
||||
do_test_with_ansi_output shellA-1.4 {
|
||||
exec {*}$CLI test.db --escape symbol {SELECT x FROM t1 WHERE a=2;}
|
||||
exec {*}$CLI -noinit -list test.db --escape symbol {SELECT x FROM t1 WHERE a=2;}
|
||||
} {
|
||||
␛[31mVT-100 codes␛[0m
|
||||
}
|
||||
do_test shellA-1.5 {
|
||||
exec {*}$CLI test.db --escape ascii {SELECT x FROM t1 WHERE a=2;}
|
||||
exec {*}$CLI -noinit -list test.db --escape ascii {SELECT x FROM t1 WHERE a=2;}
|
||||
} {
|
||||
^[[31mVT-100 codes^[[0m
|
||||
}
|
||||
do_test_with_ansi_output shellA-1.6 {
|
||||
exec {*}$CLI test.db {.mode list --escape symbol} {SELECT x FROM t1 WHERE a=2;}
|
||||
exec {*}$CLI -noinit test.db {.mode list --escape symbol} {SELECT x FROM t1 WHERE a=2;}
|
||||
} {
|
||||
␛[31mVT-100 codes␛[0m
|
||||
}
|
||||
do_test shellA-1.7 {
|
||||
exec {*}$CLI test.db {.mode list --escape ascii} {SELECT x FROM t1 WHERE a=2;}
|
||||
exec {*}$CLI -noinit test.db {.mode list --escape ascii} {SELECT x FROM t1 WHERE a=2;}
|
||||
} {
|
||||
^[[31mVT-100 codes^[[0m
|
||||
}
|
||||
do_test shellA-1.8 {
|
||||
file delete -force out.txt
|
||||
exec {*}$CLI test.db {.mode list --escape off} {SELECT x FROM t1 WHERE a=7;} \
|
||||
exec {*}$CLI -noinit test.db {.mode list --escape off} {SELECT x FROM t1 WHERE a=7;} \
|
||||
>out.txt
|
||||
set fd [open out.txt rb]
|
||||
set res [read $fd]
|
||||
@@ -98,44 +98,45 @@ do_test shellA-1.8 {
|
||||
} "carriage\rreturn"
|
||||
do_test shellA-1.9 {
|
||||
set rc [catch {
|
||||
exec {*}$CLI test.db {.mode test --escape xyz}
|
||||
exec {*}$CLI -noinit test.db {.mode test --escape xyz}
|
||||
} msg]
|
||||
lappend rc $msg
|
||||
} {1 {unknown control character escape mode "xyz" - choices: ascii symbol off}}
|
||||
} {1 {argv[3]: .mode test --escape xyz
|
||||
argv[3]: ^--- unknown mode
|
||||
argv[3]: Use ".help .mode" for more info}}
|
||||
do_test shellA-1.10 {
|
||||
set rc [catch {
|
||||
exec {*}$CLI --escape abc test.db .q
|
||||
exec {*}$CLI --noinit --escape abc test.db .q
|
||||
} msg]
|
||||
lappend rc $msg
|
||||
} {1 {unknown control character escape mode "abc" - choices: ascii symbol off}}
|
||||
} {1 {unknown control character escape mode "abc" - choices: auto off ascii symbol}}
|
||||
|
||||
# ".mode quote"
|
||||
#
|
||||
do_test shellA-2.1 {
|
||||
exec {*}$CLI test.db --quote {SELECT a, x FROM t1 WHERE a IN (1,2,6,7,8)}
|
||||
exec {*}$CLI -noinit test.db --quote {SELECT a, x FROM t1 WHERE a IN (1,2,6,7,8)}
|
||||
} {
|
||||
1,'line with '' single quote'
|
||||
2,unistr('\u001b[31mVT-100 codes\u001b[0m')
|
||||
6,'new
|
||||
line'
|
||||
6,unistr('new\u000aline')
|
||||
7,unistr('carriage\u000dreturn')
|
||||
8,'last line'
|
||||
}
|
||||
do_test shellA-2.2 {
|
||||
exec {*}$CLI test.db --quote {.mode}
|
||||
} {current output mode: quote --escape ascii}
|
||||
exec {*}$CLI -noinit test.db --quote {.mode -v}
|
||||
} {/*current output mode: quote* --escape auto*/}
|
||||
do_test shellA-2.3 {
|
||||
exec {*}$CLI test.db --quote --escape SYMBOL {.mode}
|
||||
exec {*}$CLI -noinit -compat 20250101 test.db --quote --escape SYMBOL {.mode}
|
||||
} {current output mode: quote --escape symbol}
|
||||
do_test shellA-2.4 {
|
||||
exec {*}$CLI test.db --quote --escape OFF {.mode}
|
||||
exec {*}$CLI -noinit -compat 20250101 test.db --quote --escape OFF {.mode}
|
||||
} {current output mode: quote --escape off}
|
||||
|
||||
|
||||
# ".mode line"
|
||||
#
|
||||
do_test_with_ansi_output shellA-3.1 {
|
||||
exec {*}$CLI test.db --line --escape symbol \
|
||||
exec {*}$CLI -noinit test.db --line --escape symbol \
|
||||
{SELECT a, x FROM t1 WHERE a IN (1,2,6,7,8)}
|
||||
} {
|
||||
a = 1
|
||||
@@ -155,7 +156,7 @@ line
|
||||
x = last line
|
||||
}
|
||||
do_test shellA-3.2 {
|
||||
exec {*}$CLI test.db --line --escape ascii \
|
||||
exec {*}$CLI -noinit test.db --line --escape ascii \
|
||||
{SELECT a, x FROM t1 WHERE a IN (1,2,6,7,8)}
|
||||
} {
|
||||
a = 1
|
||||
@@ -178,7 +179,7 @@ line
|
||||
# ".mode box"
|
||||
#
|
||||
do_test_with_ansi_output shellA-4.1 {
|
||||
exec {*}$CLI test.db --box --escape ascii \
|
||||
exec {*}$CLI -noinit test.db --box --escape ascii \
|
||||
{SELECT a, x FROM t1 WHERE a IN (1,2,6,7,8)}
|
||||
} {
|
||||
┌───┬──────────────────────────┐
|
||||
@@ -197,20 +198,15 @@ do_test_with_ansi_output shellA-4.1 {
|
||||
└───┴──────────────────────────┘
|
||||
}
|
||||
do_test_with_ansi_output shellA-4.2 {
|
||||
exec {*}$CLI test.db {.mode qbox} {SELECT a, x FROM t1 WHERE a IN (1,2,6,7,8)}
|
||||
exec {*}$CLI -noinit test.db {.mode qbox} {SELECT a, x FROM t1 WHERE a IN (1,2,6,7,8)}
|
||||
} {
|
||||
┌───┬───────────────────────────────────────────┐
|
||||
│ a │ x │
|
||||
├───┼───────────────────────────────────────────┤
|
||||
│ 1 │ 'line with '' single quote' │
|
||||
├───┼───────────────────────────────────────────┤
|
||||
│ 2 │ unistr('\u001b[31mVT-100 codes\u001b[0m') │
|
||||
├───┼───────────────────────────────────────────┤
|
||||
│ 6 │ 'new │
|
||||
│ │ line' │
|
||||
├───┼───────────────────────────────────────────┤
|
||||
│ 6 │ unistr('new\u000aline') │
|
||||
│ 7 │ unistr('carriage\u000dreturn') │
|
||||
├───┼───────────────────────────────────────────┤
|
||||
│ 8 │ 'last line' │
|
||||
└───┴───────────────────────────────────────────┘
|
||||
}
|
||||
@@ -218,7 +214,7 @@ do_test_with_ansi_output shellA-4.2 {
|
||||
# ".mode insert"
|
||||
#
|
||||
do_test shellA-5.1 {
|
||||
exec {*}$CLI test.db {.mode insert t1 --escape ascii} \
|
||||
exec {*}$CLI -noinit test.db {.mode insert t1 --escape ascii} \
|
||||
{SELECT a, x FROM t1 WHERE a IN (1,2,6,7,8)}
|
||||
} {
|
||||
INSERT INTO t1 VALUES(1,'line with '' single quote');
|
||||
@@ -228,7 +224,7 @@ INSERT INTO t1 VALUES(7,unistr('carriage\u000dreturn'));
|
||||
INSERT INTO t1 VALUES(8,'last line');
|
||||
}
|
||||
do_test shellA-5.2 {
|
||||
exec {*}$CLI test.db {.mode insert t1 --escape symbol} \
|
||||
exec {*}$CLI -noinit test.db {.mode insert t1 --escape symbol} \
|
||||
{SELECT a, x FROM t1 WHERE a IN (1,2,6,7,8)}
|
||||
} {
|
||||
INSERT INTO t1 VALUES(1,'line with '' single quote');
|
||||
@@ -239,7 +235,7 @@ INSERT INTO t1 VALUES(8,'last line');
|
||||
}
|
||||
do_test shellA-5.3 {
|
||||
file delete -force out.txt
|
||||
exec {*}$CLI test.db {.mode insert t1 --escape off} \
|
||||
exec {*}$CLI -noinit test.db {.mode insert t1 --escape off} \
|
||||
{SELECT a, x FROM t1 WHERE a IN (1,2,6,7,8)} >out.txt
|
||||
set fd [open out.txt rb]
|
||||
set res [read $fd]
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
# 2025-11-12
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
# TESTRUNNER: shell
|
||||
#
|
||||
# Test cases for the command-line shell using the new ".output memory"
|
||||
# feature.
|
||||
#
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set CLI [test_cli_invocation]
|
||||
|
||||
# Run an instance of the CLI on the file $name.
|
||||
# Capture the number of test cases and the number of
|
||||
# errors and increment the counts.
|
||||
#
|
||||
proc do_clitest {name} {
|
||||
set mapping [list <NAME> $::testdir/$name <CLI> $::CLI]
|
||||
set script [string map $mapping {
|
||||
catch {exec <CLI> :memory: ".read <NAME>" 2>@stdout} res
|
||||
set ntest 0
|
||||
set nerr 999
|
||||
regexp {.*(\d+) tests? run with (\d+) errors?} $res all ntest nerr
|
||||
set_test_counter count [expr {[set_test_counter count]+$ntest-1}]
|
||||
set_test_counter errors [expr {[set_test_counter errors]+$nerr}]
|
||||
if {$nerr==0} {set res "error count: 0"}
|
||||
set res
|
||||
}]
|
||||
# puts $script
|
||||
do_test shellB-$name $script {error count: 0}
|
||||
}
|
||||
|
||||
do_clitest modeA.clitest
|
||||
|
||||
finish_test
|
||||
+1
-1
@@ -42,7 +42,7 @@ do_test tcl-1.1.1 {
|
||||
do_test tcl-1.2 {
|
||||
set v [catch {db bogus} msg]
|
||||
lappend v $msg
|
||||
} {1 {bad option "bogus": must be authorizer, backup, bind_fallback, busy, cache, changes, close, collate, collation_needed, commit_hook, complete, config, copy, deserialize, enable_load_extension, errorcode, erroroffset, eval, exists, function, incrblob, interrupt, last_insert_rowid, nullvalue, onecolumn, preupdate, profile, progress, rekey, restore, rollback_hook, serialize, status, timeout, total_changes, trace, trace_v2, transaction, unlock_notify, update_hook, version, or wal_hook}}
|
||||
} {1 {bad option "bogus": must be authorizer, backup, bind_fallback, busy, cache, changes, close, collate, collation_needed, commit_hook, complete, config, copy, deserialize, enable_load_extension, errorcode, erroroffset, eval, exists, format, function, incrblob, interrupt, last_insert_rowid, nullvalue, onecolumn, preupdate, profile, progress, rekey, restore, rollback_hook, serialize, status, timeout, total_changes, trace, trace_v2, transaction, unlock_notify, update_hook, version, or wal_hook}}
|
||||
do_test tcl-1.2.1 {
|
||||
set v [catch {db cache bogus} msg]
|
||||
lappend v $msg
|
||||
|
||||
@@ -364,6 +364,7 @@ set estwork(shell6.test) 3
|
||||
set estwork(shell8.test) 104
|
||||
set estwork(shell9.test) 3
|
||||
set estwork(shellA.test) 2
|
||||
set estwork(shellB.test) 2
|
||||
set estwork(shmlock.test) 27
|
||||
set estwork(sidedelete.test) 10
|
||||
set estwork(skipscan1.test) 7
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
#!/usr/bin/tclsh
|
||||
#
|
||||
# Use this script to combine multiple source code files into a single
|
||||
# file. Example:
|
||||
#
|
||||
# tclsh mkcombo.tcl file1.c file2.c file3.c -o file123.c
|
||||
#
|
||||
|
||||
set help {Usage: tclsh mkcombo.tcl [OPTIONS] [FILELIST]
|
||||
where OPTIONS is zero or more of the following with these effects:
|
||||
--linemacros=? => Emit #line directives into output or not. (? = 1 or 0)
|
||||
--o FILE => write to alternative output file named FILE
|
||||
--help => See this.
|
||||
}
|
||||
|
||||
set linemacros 0
|
||||
set fname {}
|
||||
set src [list]
|
||||
|
||||
|
||||
for {set i 0} {$i<[llength $argv]} {incr i} {
|
||||
set x [lindex $argv $i]
|
||||
if {[regexp {^-?-linemacros(?:=([01]))?$} $x ma ulm]} {
|
||||
if {$ulm == ""} {set ulm 1}
|
||||
set linemacros $ulm
|
||||
} elseif {[regexp {^-o$} $x]} {
|
||||
incr i
|
||||
if {$i==[llength $argv]} {
|
||||
error "No argument following $x"
|
||||
}
|
||||
set fname [lindex $argv $i]
|
||||
} elseif {[regexp {^-?-((help)|\?)$} $x]} {
|
||||
puts $help
|
||||
exit 0
|
||||
} elseif {[regexp {^-?-} $x]} {
|
||||
error "unknown command-line option: $x"
|
||||
} else {
|
||||
lappend src $x
|
||||
}
|
||||
}
|
||||
|
||||
# Open the output file and write a header comment at the beginning
|
||||
# of the file.
|
||||
#
|
||||
if {![info exists fname]} {
|
||||
set fname sqlite3.c
|
||||
if {$enable_recover} { set fname sqlite3r.c }
|
||||
}
|
||||
set out [open $fname wb]
|
||||
|
||||
# Return a string consisting of N "*" characters.
|
||||
#
|
||||
proc star N {
|
||||
set r {}
|
||||
for {set i 0} {$i<$N} {incr i} {append r *}
|
||||
return $r
|
||||
}
|
||||
|
||||
# Force the output to use unix line endings, even on Windows.
|
||||
fconfigure $out -translation binary
|
||||
puts $out "/[star 78]"
|
||||
puts $out {** The following is an amalgamation of these source code files:}
|
||||
puts $out {**}
|
||||
foreach s $src {
|
||||
regsub {^.*/(src|ext)/} $s {\1/} s2
|
||||
puts $out "** $s2"
|
||||
}
|
||||
puts $out {**}
|
||||
puts $out "[star 78]/"
|
||||
|
||||
# Insert a comment into the code
|
||||
#
|
||||
proc section_comment {text} {
|
||||
global out s78
|
||||
set n [string length $text]
|
||||
set nstar [expr {60 - $n}]
|
||||
puts $out "/************** $text [star $nstar]/"
|
||||
}
|
||||
|
||||
# Read the source file named $filename and write it into the
|
||||
# sqlite3.c output file. The only transformation is the trimming
|
||||
# of EOL whitespace.
|
||||
#
|
||||
proc copy_file_verbatim {filename} {
|
||||
global out
|
||||
set in [open $filename rb]
|
||||
set tail [file tail $filename]
|
||||
section_comment "Begin file $tail"
|
||||
while {![eof $in]} {
|
||||
set line [string trimright [gets $in]]
|
||||
puts $out $line
|
||||
}
|
||||
section_comment "End of $tail"
|
||||
}
|
||||
set taillist ""
|
||||
foreach file $src {
|
||||
copy_file_verbatim $file
|
||||
append taillist ", [file tail $file]"
|
||||
}
|
||||
|
||||
set taillist "End of the amalgamation of [string range $taillist 2 end]"
|
||||
set n [string length $taillist]
|
||||
set ns [expr {(75-$n)/2}]
|
||||
if {$ns<3} {set ns 3}
|
||||
puts $out "/[star $ns] $taillist [star $ns]/"
|
||||
close $out
|
||||
+104
-25
@@ -13,28 +13,90 @@ set topdir [file dir [file dir [file normal $argv0]]]
|
||||
set out stdout
|
||||
fconfigure stdout -translation binary
|
||||
if {[lindex $argv 0]!=""} {
|
||||
set out [open [lindex $argv 0] wb]
|
||||
set output_file [lindex $argv 0]
|
||||
file delete -force $output_file
|
||||
set out [open $output_file wb]
|
||||
} else {
|
||||
set output_file {}
|
||||
}
|
||||
puts $out {/* DO NOT EDIT!
|
||||
** This file is automatically generated by the script in the canonical
|
||||
** SQLite source tree at tool/mkshellc.tcl. That script combines source
|
||||
** code from various constituent source files of SQLite into this single
|
||||
** "shell.c" file used to implement the SQLite command-line shell.
|
||||
**
|
||||
** Most of the code found below comes from the "src/shell.c.in" file in
|
||||
** the canonical SQLite source tree. That main file contains "INCLUDE"
|
||||
** lines that specify other files in the canonical source tree that are
|
||||
** inserted to getnerate this complete program source file.
|
||||
**
|
||||
** The code from multiple files is combined into this single "shell.c"
|
||||
** source file to help make the command-line program easier to compile.
|
||||
**
|
||||
** To modify this program, get a copy of the canonical SQLite source tree,
|
||||
** edit the src/shell.c.in" and/or some of the other files that are included
|
||||
** by "src/shell.c.in", then rerun the tool/mkshellc.tcl script.
|
||||
*/}
|
||||
|
||||
############################## FIRST PASS ################################
|
||||
# Read through the shell.c.in source file to gather information. Do not
|
||||
# yet generate any code
|
||||
#
|
||||
set in [open $topdir/src/shell.c.in]
|
||||
fconfigure $in -translation binary
|
||||
set allSource(src/shell.c.in) 1
|
||||
set inUsage 0
|
||||
set dotcmd {}
|
||||
while {1} {
|
||||
set lx [gets $in]
|
||||
if {[eof $in]} break;
|
||||
if {[regexp {^INCLUDE } $lx]} {
|
||||
set cfile [lindex $lx 1]
|
||||
if {[string match ../* $cfile]} {
|
||||
set xfile [string range $cfile 3 end]
|
||||
} else {
|
||||
set xfile "src/$cfile"
|
||||
}
|
||||
set allSource($xfile) 1
|
||||
} elseif {[regexp {^\*\* USAGE:\s+([^\s]+)} $lx all dotcmd]} {
|
||||
set inUsage 1
|
||||
set details [string trim [string range $lx 2 end]]
|
||||
} elseif {$inUsage} {
|
||||
if {![regexp {^\*\*} $lx] || [regexp { DOT-COMMAND: } $lx]} {
|
||||
set inUsage 0
|
||||
set Usage($dotcmd) [string trim $details]
|
||||
} else {
|
||||
append details \n
|
||||
append details [string range [string trimright $lx] 3 end]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Generate dot-command usage text based on the data accumulated in
|
||||
# the Usage() array.
|
||||
#
|
||||
proc generate_usage {out} {
|
||||
global Usage
|
||||
puts $out "/**************************************************************"
|
||||
puts $out "** \"Usage\" help text automatically generated from comments */"
|
||||
puts $out "static const struct \173"
|
||||
puts $out " const char *zCmd; /* Name of the dot-command */"
|
||||
puts $out " const char *zUsage; /* Documentation */"
|
||||
puts $out "\175 aUsage\[\] = \173"
|
||||
foreach dotcmd [array names Usage] {
|
||||
puts $out " \173 \"$dotcmd\","
|
||||
foreach line [split $Usage($dotcmd) \n] {
|
||||
set x [string map [list \\ \\\\ \" \\\"] $line]
|
||||
puts $out "\"$x\\n\""
|
||||
}
|
||||
puts $out " \175,"
|
||||
}
|
||||
puts $out "\175;"
|
||||
}
|
||||
# generate_usage stderr
|
||||
|
||||
###### SECOND PASS #######
|
||||
# Make a second pass through shell.c.in to generate the the final
|
||||
# output, based on data gathered during the first pass.
|
||||
#
|
||||
|
||||
puts $out {/*
|
||||
** This is the amalgamated source code to the "sqlite3" or "sqlite3.exe"
|
||||
** command-line shell (CLI) for SQLite. This file is automatically
|
||||
** generated by the tool/mkshellc.tcl script from the following sources:
|
||||
**}
|
||||
foreach fn [lsort [array names allSource]] {
|
||||
puts $out "** $fn"
|
||||
}
|
||||
puts $out {**
|
||||
** To modify this program, get a copy of the canonical SQLite source tree,
|
||||
** edit the src/shell.c.in file and/or some of the other files that are
|
||||
** listed above, then rerun the rerun "make shell.c".
|
||||
*/}
|
||||
seek $in 0 start
|
||||
puts $out "/************************* Begin src/shell.c.in ******************/"
|
||||
proc omit_redundant_typedefs {line} {
|
||||
global typedef_seen
|
||||
if {[regexp {^typedef .* ([a-zA-Z0-9_]+);} $line all typename]} {
|
||||
@@ -53,9 +115,14 @@ while {1} {
|
||||
incr iLine
|
||||
if {[regexp {^INCLUDE } $lx]} {
|
||||
set cfile [lindex $lx 1]
|
||||
puts $out "/************************* Begin $cfile ******************/"
|
||||
# puts $out "#line 1 \"$cfile\""
|
||||
set in2 [open $topdir/src/$cfile]
|
||||
if {[string match ../* $cfile]} {
|
||||
set xfile [string range $cfile 3 end]
|
||||
} else {
|
||||
set xfile "src/$cfile"
|
||||
}
|
||||
puts $out "/************************* Begin $xfile ******************/"
|
||||
# puts $out "#line 1 \"$xfile\""
|
||||
set in2 [open $topdir/$xfile]
|
||||
fconfigure $in2 -translation binary
|
||||
while {![eof $in2]} {
|
||||
set lx [omit_redundant_typedefs [gets $in2]]
|
||||
@@ -69,11 +136,23 @@ while {1} {
|
||||
puts $out $lx
|
||||
}
|
||||
close $in2
|
||||
puts $out "/************************* End $cfile ********************/"
|
||||
puts $out "/************************* End $xfile ********************/"
|
||||
# puts $out "#line [expr $iLine+1] \"shell.c.in\""
|
||||
continue
|
||||
} elseif {[regexp {^INSERT-USAGE-TEXT-HERE} $lx]} {
|
||||
generate_usage $out
|
||||
} else {
|
||||
puts $out $lx
|
||||
}
|
||||
puts $out $lx
|
||||
}
|
||||
puts $out "/************************* End src/shell.c.in ******************/"
|
||||
close $in
|
||||
close $out
|
||||
|
||||
# Try to disable write permissions on the generate file, to prevent
|
||||
# accidentally editing the generated file rather than source files.
|
||||
#
|
||||
if {$output_file ne ""} {
|
||||
catch {file attributes $output_file -readonly 1}
|
||||
catch {file attributes $output_file -permissions -w}
|
||||
catch {exec chmod -w $output_file}
|
||||
}
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@ INCLUDE $ROOT/ext/misc/appendvfs.c
|
||||
INCLUDE $ROOT/ext/misc/zipfile.c
|
||||
INCLUDE $ROOT/ext/misc/sqlar.c
|
||||
#endif
|
||||
INCLUDE $ROOT/src/tclsqlite.c
|
||||
INCLUDE tclsqlite-ex.c
|
||||
|
||||
const char *sqlite3_tclapp_init_proc(Tcl_Interp *interp){
|
||||
(void)interp;
|
||||
|
||||
Reference in New Issue
Block a user