mirror of
https://github.com/sqlite/sqlite.git
synced 2026-10-28 09:46:20 +08:00
Merge latest trunk changes into this branch.
FossilOrigin-Name: 230fd5533e07ec36f1938f34153c9ef97a7acd6604d023b56dfc5269ca6173c2
This commit is contained in:
commit
928276043b
61 files changed
+5379
-1344
No files matched your search
@@ -2664,6 +2664,17 @@ devtest: srctree-check sourcetest
|
||||
mdevtest:
|
||||
$(TCLSH_CMD) $(TOP)\test\testrunner.tcl mdevtest
|
||||
|
||||
# Show all errors from the most reason testrunner invocation
|
||||
#
|
||||
errors:
|
||||
$(TCLSH_CMD) $(TOP)\test\testrunner.tcl errors
|
||||
|
||||
# Show the status of the current testrunner invocation,
|
||||
# updated every couple of seconds
|
||||
#
|
||||
status:
|
||||
$(TCLSH_CMD) $(TOP)\test\testrunner.tcl status -d 2
|
||||
|
||||
# Validate that various generated files in the source tree
|
||||
# are up-to-date.
|
||||
#
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
<h1 align="center">SQLite Source Repository</h1>
|
||||
|
||||
This repository contains the complete source code for the
|
||||
[SQLite database engine](https://sqlite.org/), including
|
||||
many tests. Additional tests and most documentation
|
||||
[SQLite database engine](https://sqlite.org/) going back
|
||||
to 2000-05-29. The tree includes many tests and some
|
||||
documentation, though additional tests and most documentation
|
||||
are managed separately.
|
||||
|
||||
See the [on-line documentation](https://sqlite.org/) for more information
|
||||
@@ -99,16 +100,16 @@ script found at the root of the source tree. Then run "make".
|
||||
|
||||
For example:
|
||||
|
||||
apt install gcc make tcl-dev ;# Make sure you have all the necessary build tools
|
||||
apt install gcc make tcl-dev ;# Install the necessary build tools
|
||||
tar xzf sqlite.tar.gz ;# Unpack the source tree into "sqlite"
|
||||
mkdir bld ;# Build will occur in a sibling directory
|
||||
mkdir bld ;# Build happens in a sibling directory
|
||||
cd bld ;# Change to the build directory
|
||||
../sqlite/configure ;# Run the configure script
|
||||
make sqlite3 ;# Builds the "sqlite3" command-line tool
|
||||
make sqlite3.c ;# Build the "amalgamation" source file
|
||||
make sqldiff ;# Builds the "sqldiff" command-line tool
|
||||
# Makefile targets below this point require tcl-dev
|
||||
make tclextension-install ;# Build and install the SQLite TCL extension
|
||||
make sqlite3 ;# The "sqlite3" command-line tool
|
||||
make sqlite3.c ;# The "amalgamation" source file
|
||||
make sqldiff ;# The "sqldiff" command-line tool
|
||||
#### Targets below require tcl-dev ####
|
||||
make tclextension-install ;# Install the SQLite TCL extension
|
||||
make devtest ;# Run development tests
|
||||
make releasetest ;# Run full release tests
|
||||
make sqlite3_analyzer ;# Builds the "sqlite3_analyzer" tool
|
||||
@@ -116,14 +117,15 @@ For example:
|
||||
See the makefile for additional targets. For debugging builds, the
|
||||
core developers typically run "configure" with options like this:
|
||||
|
||||
../sqlite/configure --enable-all --enable-debug CFLAGS='-O0 -g'
|
||||
../sqlite/configure --all --debug CFLAGS='-O0 -g'
|
||||
|
||||
For release builds, the core developers usually do:
|
||||
|
||||
../sqlite/configure --enable-all
|
||||
../sqlite/configure --all
|
||||
|
||||
Almost all makefile targets require a "tclsh" TCL interpreter version 8.6 or
|
||||
later. The "tclextension-install" target and the test targets that follow
|
||||
Core deliverables (sqlite3.c, sqlite3) can be built without a TCL, but
|
||||
many makefile targets require a "tclsh" TCL interpreter version 8.6
|
||||
or later. The "tclextension-install" target and the test targets that follow
|
||||
all require TCL development libraries too. ("apt install tcl-dev"). It is
|
||||
helpful, but is not required, to install the SQLite TCL extension (the
|
||||
"tclextension-install" target) prior to running tests. The "releasetest"
|
||||
@@ -133,20 +135,20 @@ On "make" command-lines, one can add "OPTIONS=..." to specify additional
|
||||
compile-time options over and above those set by ./configure. For example,
|
||||
to compile with the SQLITE_OMIT_DEPRECATED compile-time option, one could say:
|
||||
|
||||
./configure --enable-all
|
||||
./configure --all
|
||||
make OPTIONS=-DSQLITE_OMIT_DEPRECATED sqlite3
|
||||
|
||||
The configure script uses autoconf 2.61 and libtool. If the configure
|
||||
script does not work out for you, there is a generic makefile named
|
||||
"Makefile.linux-gcc" in the top directory of the source tree that you
|
||||
can copy and edit to suit your needs. Comments on the generic makefile
|
||||
show what changes are needed.
|
||||
The configure script uses [autosetup](https://msteveb.github.io/autosetup/).
|
||||
If the configure script does not work out for you, there is a generic
|
||||
makefile named "Makefile.linux-gcc" in the top directory of the source tree
|
||||
that you can copy and edit to suit your needs. Comments on the generic
|
||||
makefile show what changes are needed.
|
||||
|
||||
## Compiling for Windows Using MSVC
|
||||
|
||||
On Windows, everything can be compiled with MSVC.
|
||||
You will also need a working installation of TCL if you want to run tests.
|
||||
TCL is not required if you just want to build SQLite itself.
|
||||
You will also need a working installation of TCL if you want to run tests,
|
||||
though TCL is not required if you just want to build SQLite itself.
|
||||
See the [compile-for-windows.md](doc/compile-for-windows.md) document for
|
||||
additional information about how to install MSVC and TCL and configure your
|
||||
build environment.
|
||||
@@ -156,24 +158,25 @@ TCL library, using a command like this:
|
||||
|
||||
set TCLDIR=c:\Tcl
|
||||
|
||||
SQLite uses "tclsh.exe" as part of the build process, and so that
|
||||
program will need to be somewhere on your %PATH%. SQLite itself
|
||||
does not contain any TCL code, but it does use TCL to run tests.
|
||||
You may need to install TCL development
|
||||
libraries in order to successfully complete some makefile targets.
|
||||
It is helpful, but is not required, to install the SQLite TCL extension
|
||||
(the "tclextension-install" target) prior to running tests.
|
||||
SQLite itself does not contain any TCL code, but it does use TCL to run
|
||||
tests. You may need to install TCL development libraries in order to
|
||||
successfully complete some makefile targets. It is helpful, but is not
|
||||
required, to install the SQLite TCL extension (the "tclextension-install"
|
||||
target) prior to running tests.
|
||||
|
||||
Build using Makefile.msc. Example:
|
||||
The source tree contains a "make.bat" file that allows the same "make"
|
||||
commands of Unix to work on Windows. In the following, you can substitute
|
||||
"nmake /f Makefile.msc" in place of "make", if you prefer to avoid this BAT
|
||||
file:
|
||||
|
||||
nmake /f Makefile.msc sqlite3.exe
|
||||
nmake /f Makefile.msc sqlite3.c
|
||||
nmake /f Makefile.msc sqldiff.exe
|
||||
# Makefile targets below this point require TCL development libraries
|
||||
nmake /f Makefile.msc tclextension-install
|
||||
nmake /f Makefile.msc devtest
|
||||
nmake /f Makefile.msc releasetest
|
||||
nmake /f Makefile.msc sqlite3_analyzer.exe
|
||||
make sqlite3.exe
|
||||
make sqlite3.c
|
||||
make sqldiff.exe
|
||||
#### Targets below require TCL development libraries ####
|
||||
make tclextension-install
|
||||
make devtest
|
||||
make releasetest
|
||||
make sqlite3_analyzer.exe
|
||||
|
||||
There are many other makefile targets. See comments in Makefile.msc for
|
||||
details.
|
||||
@@ -181,7 +184,7 @@ details.
|
||||
As with the unix Makefile, the OPTIONS=... argument can be passed on the nmake
|
||||
command-line to enable new compile-time options. For example:
|
||||
|
||||
nmake /f Makefile.msc OPTIONS=-DSQLITE_OMIT_DEPRECATED sqlite3.exe
|
||||
make OPTIONS=-DSQLITE_OMIT_DEPRECATED sqlite3.exe
|
||||
|
||||
## Source Tree Map
|
||||
|
||||
@@ -194,8 +197,7 @@ command-line to enable new compile-time options. For example:
|
||||
* **test/** - This directory and its subdirectories contains code used
|
||||
for testing. Files that end in "`.test`" are TCL scripts that run
|
||||
tests using an augmented TCL interpreter named "testfixture". Use
|
||||
a command like "`make testfixture`" (unix) or
|
||||
"`nmake /f Makefile.msc testfixture.exe`" (windows) to build that
|
||||
a command like "`make testfixture`" to build that
|
||||
augmented TCL interpreter, then run individual tests using commands like
|
||||
"`testfixture test/main.test`". This test/ subdirectory also contains
|
||||
additional C code modules and scripts for other kinds of testing.
|
||||
@@ -377,10 +379,11 @@ implementation. It will not be the easiest library in the world to hack.
|
||||
(and some other test programs too) is built and run when you type
|
||||
"make test".
|
||||
|
||||
* **VERSION**, **manifest**, and **manifest.uuid** - These files define
|
||||
the current SQLite version number. The "VERSION" file is human generated,
|
||||
but the "manifest" and "manifest.uuid" files are automatically generated
|
||||
by the [Fossil version control system](https://fossil-scm.org/).
|
||||
* **VERSION**, **manifest**, **manifest.tags**, and **manifest.uuid** -
|
||||
These files define the current SQLite version number. The "VERSION" file
|
||||
is human generated, but the "manifest", "manifest.tags", and
|
||||
"manifest.uuid" files are automatically generated by the
|
||||
[Fossil version control system](https://fossil-scm.org/).
|
||||
|
||||
There are many other source files. Each has a succinct header comment that
|
||||
describes its purpose and role within the larger system.
|
||||
@@ -406,10 +409,6 @@ makefile:
|
||||
|
||||
> make verify-source
|
||||
|
||||
Or on windows:
|
||||
|
||||
> nmake /f Makefile.msc verify-source
|
||||
|
||||
Using the makefile to verify source integrity is good for detecting
|
||||
accidental changes to the source tree, but malicious changes could be
|
||||
hidden by also modifying the makefiles.
|
||||
|
||||
@@ -1020,6 +1020,7 @@ SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_OFFSET_SQL_FUNC=1
|
||||
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_PERCENTILE=1
|
||||
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION=1
|
||||
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_STMT_SCANSTATUS=1
|
||||
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_BYTECODE_VTAB=1
|
||||
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_STRICT_SUBTYPE=1
|
||||
!ENDIF
|
||||
|
||||
@@ -1068,6 +1069,8 @@ $(SQLITE3EXE): shell.c $(SHELL_CORE_DEP) $(LIBRESOBJS) $(SHELL_CORE_SRC) $(SQLIT
|
||||
/link $(SQLITE3EXEPDB) $(LDFLAGS) $(LTLINKOPTS) $(SHELL_LINK_OPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LIBREADLINE) $(LTLIBS) $(TLIBS)
|
||||
|
||||
|
||||
tclsqlite-ex.c:
|
||||
|
||||
# Rule to build the amalgamation
|
||||
#
|
||||
sqlite3.lo: $(SQLITE3C)
|
||||
|
||||
@@ -375,6 +375,11 @@ configure process, and check it in.
|
||||
Patching Autosetup for Project-local Changes
|
||||
------------------------------------------------------------------------
|
||||
|
||||
The autosetup files require the following patches after updating
|
||||
from their upstream sources:
|
||||
|
||||
### `--debug` flag
|
||||
|
||||
Autosetup reserves the flag name **`--debug`** for its own purposes,
|
||||
and its own special handling of `--enable-...` flags makes `--debug`
|
||||
an alias for `--enable-debug`. As this project has a long history of
|
||||
@@ -388,6 +393,11 @@ If autosetup is upgraded and this patch is _not_ applied the invoking
|
||||
`./configure` will fail loudly because of the declaration of the
|
||||
`debug` flag in `auto.def` - duplicated flags are not permitted.
|
||||
|
||||
### Fail on `malloc()` error
|
||||
|
||||
See [check-in 72c8a5b94cdf5d](/info/72c8a5b94cdf5d).
|
||||
|
||||
|
||||
<a name="branch-customization"></a>
|
||||
Branch-specific Customization
|
||||
========================================================================
|
||||
|
||||
+6
-4
@@ -7409,11 +7409,13 @@ void *JimDefaultAllocator(void *ptr, size_t size)
|
||||
free(ptr);
|
||||
return NULL;
|
||||
}
|
||||
else if (ptr) {
|
||||
return realloc(ptr, size);
|
||||
}
|
||||
else {
|
||||
return malloc(size);
|
||||
void *p = realloc(ptr, size);
|
||||
if( p==0 ){
|
||||
fprintf(stderr,"Out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -98,9 +98,9 @@ typedef struct SegmentWriter SegmentWriter;
|
||||
** incrementally. See function fts3PendingListAppend() for details.
|
||||
*/
|
||||
struct PendingList {
|
||||
int nData;
|
||||
sqlite3_int64 nData;
|
||||
char *aData;
|
||||
int nSpace;
|
||||
sqlite3_int64 nSpace;
|
||||
sqlite3_int64 iLastDocid;
|
||||
sqlite3_int64 iLastCol;
|
||||
sqlite3_int64 iLastPos;
|
||||
@@ -760,7 +760,8 @@ static int fts3PendingTermsAddOne(
|
||||
|
||||
pList = (PendingList *)fts3HashFind(pHash, zToken, nToken);
|
||||
if( pList ){
|
||||
p->nPendingData -= (pList->nData + nToken + sizeof(Fts3HashElem));
|
||||
assert( pList->nData+nToken+sizeof(Fts3HashElem) <= (i64)p->nPendingData );
|
||||
p->nPendingData -= (int)(pList->nData + nToken + sizeof(Fts3HashElem));
|
||||
}
|
||||
if( fts3PendingListAppend(&pList, p->iPrevDocid, iCol, iPos, &rc) ){
|
||||
if( pList==fts3HashInsert(pHash, zToken, nToken, pList) ){
|
||||
@@ -773,7 +774,9 @@ static int fts3PendingTermsAddOne(
|
||||
}
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
p->nPendingData += (pList->nData + nToken + sizeof(Fts3HashElem));
|
||||
assert( (i64)p->nPendingData + pList->nData + nToken
|
||||
+ sizeof(Fts3HashElem) <= 0x3fffffff );
|
||||
p->nPendingData += (int)(pList->nData + nToken + sizeof(Fts3HashElem));
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@@ -5457,7 +5460,7 @@ static int fts3SpecialInsert(Fts3Table *p, sqlite3_value *pVal){
|
||||
v = atoi(&zVal[9]);
|
||||
if( v>=24 && v<=p->nPgsz-35 ) p->nNodeSize = v;
|
||||
rc = SQLITE_OK;
|
||||
}else if( nVal>11 && 0==sqlite3_strnicmp(zVal, "maxpending=", 9) ){
|
||||
}else if( nVal>11 && 0==sqlite3_strnicmp(zVal, "maxpending=", 11) ){
|
||||
v = atoi(&zVal[11]);
|
||||
if( v>=64 && v<=FTS3_MAX_PENDING_DATA ) p->nMaxPendingData = v;
|
||||
rc = SQLITE_OK;
|
||||
|
||||
@@ -2074,6 +2074,7 @@ static void fts5SegIterReverseInitPage(Fts5Index *p, Fts5SegIter *pIter){
|
||||
while( 1 ){
|
||||
u64 iDelta = 0;
|
||||
|
||||
if( i>=n ) break;
|
||||
if( eDetail==FTS5_DETAIL_NONE ){
|
||||
/* todo */
|
||||
if( i<n && a[i]==0 ){
|
||||
|
||||
@@ -396,7 +396,12 @@ static int fts5VocabOpenMethod(
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Restore cursor pCsr to the state it was in immediately after being
|
||||
** created by the xOpen() method.
|
||||
*/
|
||||
static void fts5VocabResetCursor(Fts5VocabCursor *pCsr){
|
||||
int nCol = pCsr->pFts5->pConfig->nCol;
|
||||
pCsr->rowid = 0;
|
||||
sqlite3Fts5IterClose(pCsr->pIter);
|
||||
sqlite3Fts5StructureRelease(pCsr->pStruct);
|
||||
@@ -406,6 +411,12 @@ static void fts5VocabResetCursor(Fts5VocabCursor *pCsr){
|
||||
pCsr->nLeTerm = -1;
|
||||
pCsr->zLeTerm = 0;
|
||||
pCsr->bEof = 0;
|
||||
pCsr->iCol = 0;
|
||||
pCsr->iInstPos = 0;
|
||||
pCsr->iInstOff = 0;
|
||||
pCsr->colUsed = 0;
|
||||
memset(pCsr->aCnt, 0, sizeof(i64)*nCol);
|
||||
memset(pCsr->aDoc, 0, sizeof(i64)*nCol);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -16124,5 +16124,367 @@ do_catchsql_test 83.1 {
|
||||
SELECT * FROM t1('R*R*R*R*R*R*R*R*') WHERE (a,b)<=(current_date,0 BETWEEN 'a'<>11 AND '') ORDER BY rowid DESC;
|
||||
} {/.*fts5: corruption found/}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_test 84.0 {
|
||||
sqlite3 db {}
|
||||
db deserialize [decode_hexdb {
|
||||
.open --hexdb
|
||||
| size 53248 pagesize 4096 filename c1a.txt.db
|
||||
| page 1 offset 0
|
||||
| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
|
||||
| 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 0d .....@ ........
|
||||
| 32: 00 00 00 02 00 00 00 01 00 00 00 09 00 00 00 04 ................
|
||||
| 48: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ................
|
||||
| 96: 00 00 00 00 0d 0f c7 00 07 0d 92 00 0f 8d 0f 36 ...............6
|
||||
| 112: 0e cb 0e 6b 0e 0e 0d b6 0d 92 0d 92 00 00 00 00 ...k............
|
||||
| 3472: 00 00 22 08 06 17 11 11 01 31 74 61 62 6c 65 74 .........1tablet
|
||||
| 3488: 32 74 32 0d 43 52 45 41 54 45 20 54 41 42 4c 45 2t2.CREATE TABLE
|
||||
| 3504: 20 74 32 28 78 29 56 07 06 17 1f 1f 01 7d 74 61 t2(x)V.......ta
|
||||
| 3520: 62 6c 65 74 31 5f 63 6f 6e 66 69 67 74 31 5f 63 blet1_configt1_c
|
||||
| 3536: 6f 6e 66 69 67 07 43 52 45 41 54 45 20 54 41 42 onfig.CREATE TAB
|
||||
| 3552: 4c 45 20 27 74 31 5f 63 6f 6e 66 69 67 27 28 6b LE 't1_config'(k
|
||||
| 3568: 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 76 29 PRIMARY KEY, v)
|
||||
| 3584: 20 57 49 54 48 4f 55 54 20 52 4f 57 49 44 5b 06 WITHOUT ROWID[.
|
||||
| 3600: 07 17 21 21 01 81 01 74 61 62 6c 65 74 31 5f 64 ..!!...tablet1_d
|
||||
| 3616: 6f 63 73 69 7a 65 74 31 5f 64 6f 63 73 69 7a 65 ocsizet1_docsize
|
||||
| 3632: 06 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 74 .CREATE TABLE 't
|
||||
| 3648: 31 5f 64 6f 63 73 69 7a 65 27 28 69 64 20 49 4e 1_docsize'(id IN
|
||||
| 3664: 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 TEGER PRIMARY KE
|
||||
| 3680: 59 2c 20 73 7a 20 42 4c 4f 42 29 5e 05 07 17 21 Y, sz BLOB)^...!
|
||||
| 3696: 21 01 81 07 74 61 62 6c 65 74 31 5f 63 6f 6e 74 !...tablet1_cont
|
||||
| 3712: 65 6e 74 74 31 5f 63 6f 6e 74 65 6e 74 05 43 52 entt1_content.CR
|
||||
| 3728: 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 63 EATE TABLE 't1_c
|
||||
| 3744: 6f 6e 74 65 6e 74 27 28 69 64 20 49 4e 54 45 47 ontent'(id INTEG
|
||||
| 3760: 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 ER PRIMARY KEY,
|
||||
| 3776: 63 30 2c 20 63 31 2c 20 63 32 29 69 04 07 17 19 c0, c1, c2)i....
|
||||
| 3792: 19 01 81 2d 74 61 62 6c 65 74 31 5f 69 64 78 74 ...-tablet1_idxt
|
||||
| 3808: 31 5f 69 64 78 04 43 52 45 41 54 45 20 54 41 42 1_idx.CREATE TAB
|
||||
| 3824: 4c 45 20 27 74 31 5f 69 64 78 27 28 73 65 67 69 LE 't1_idx'(segi
|
||||
| 3840: 64 2c 20 74 65 72 6d 2c 20 70 67 6e 6f 2c 20 50 d, term, pgno, P
|
||||
| 3856: 52 49 4d 41 52 59 20 4b 45 59 28 73 65 67 69 64 RIMARY KEY(segid
|
||||
| 3872: 2c 20 74 65 72 6d 29 29 20 57 49 54 48 4f 55 54 , term)) WITHOUT
|
||||
| 3888: 20 52 4f 57 49 44 55 03 07 17 1b 1b 01 81 01 74 ROWIDU........t
|
||||
| 3904: 61 62 6c 65 74 31 5f 64 61 74 61 74 31 5f 64 61 ablet1_datat1_da
|
||||
| 3920: 74 61 03 43 52 45 41 54 45 20 54 41 42 4c 45 20 ta.CREATE TABLE
|
||||
| 3936: 27 74 31 5f 64 61 74 61 27 28 69 64 20 49 4e 54 't1_data'(id INT
|
||||
| 3952: 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 EGER PRIMARY KEY
|
||||
| 3968: 2c 20 62 6c 6f 63 6b 20 42 4c 4f 42 29 38 02 06 , block BLOB)8..
|
||||
| 3984: 17 11 11 08 5f 74 61 62 6c 65 74 31 74 31 43 52 ...._tablet1t1CR
|
||||
| 4000: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 EATE VIRTUAL TAB
|
||||
| 4016: 4c 45 20 74 31 20 55 53 49 4e 47 20 66 74 73 35 LE t1 USING fts5
|
||||
| 4032: 28 61 2c 62 2c 63 29 00 00 00 39 00 00 00 00 00 (a,b,c)...9.....
|
||||
| page 3 offset 8192
|
||||
| 0: 05 00 00 00 02 0f f1 00 00 00 00 0c 0f fb 0f f1 ................
|
||||
| 4064: 00 00 0b 01 03 00 1c 81 3a 84 5e 81 3a 81 3a 0a ........:.^.:.:.
|
||||
| 4080: 0a 00 00 00 0b 84 80 80 80 80 01 00 00 00 0a 0a ................
|
||||
| page 4 offset 12288
|
||||
| 0: 0a 00 00 00 01 0f fa 00 0f fa 00 00 00 00 00 00 ................
|
||||
| 4080: 00 00 00 00 00 00 00 00 00 00 05 04 09 0c 01 02 ................
|
||||
| page 7 offset 24576
|
||||
| 0: 0a 00 00 00 01 0f f4 00 0f f4 00 00 00 00 00 00 ................
|
||||
| 4080: 00 00 00 00 0b 03 1b 01 76 65 72 73 69 6f 6e 04 ........version.
|
||||
| page 10 offset 36864
|
||||
| 0: 0d 00 00 00 02 0f e2 00 0f e2 0f ef 00 00 00 00 ................
|
||||
| 4064: 00 00 0b 01 03 00 1c 81 3a 84 5e 81 3a 81 3a 0f ........:.^.:.:.
|
||||
| 4080: 0a 03 00 24 00 00 00 00 01 01 02 00 01 01 01 09 ...$............
|
||||
| page 11 offset 40960
|
||||
| 0: 0d 00 00 00 01 00 22 00 00 22 00 00 00 00 00 00 ................
|
||||
| 32: 00 00 9f 56 84 80 80 80 80 01 04 00 bf 30 00 00 ...V.........0..
|
||||
| 48: 0f 58 02 30 30 19 02 05 01 02 05 01 02 05 16 02 .X.00...........
|
||||
| 64: 05 01 02 05 01 02 05 61 02 05 01 02 05 01 02 05 .......a........
|
||||
| 80: 13 02 05 01 02 05 01 02 05 0d 02 03 01 02 03 01 ................
|
||||
| 96: 02 03 02 09 78 66 66 66 66 66 66 66 65 81 17 02 ....xfffffffe...
|
||||
| 112: 05 01 02 05 01 02 05 01 01 31 04 02 04 01 02 04 .........1......
|
||||
| 128: 01 02 04 01 02 05 01 02 05 01 02 05 0d 02 06 01 ................
|
||||
| 144: 02 06 01 02 06 02 01 30 79 02 04 01 02 04 01 02 .......0y.......
|
||||
| 160: 04 03 02 30 30 2b 02 05 01 02 05 01 02 05 58 02 ...00+........X.
|
||||
| 176: 05 01 02 05 01 02 05 01 02 05 01 02 05 01 02 05 ................
|
||||
| 192: 16 02 05 01 02 05 01 02 05 05 06 30 30 30 30 30 ...........00000
|
||||
| 208: 30 81 0b 02 04 01 02 04 01 02 04 10 02 05 01 02 0...............
|
||||
| 224: 05 01 02 05 03 02 32 34 76 02 05 01 02 05 01 02 ......24v.......
|
||||
| 240: 05 02 01 38 07 02 04 01 02 04 01 02 04 01 01 32 ...8...........2
|
||||
| 256: 28 02 04 01 02 04 01 02 04 04 02 05 01 02 05 01 (...............
|
||||
| 272: 02 05 02 01 30 1f 02 05 01 02 05 01 02 05 03 02 ....0...........
|
||||
| 288: 30 30 10 02 05 01 02 05 01 02 05 6a 02 04 01 02 00.........j....
|
||||
| 304: 04 01 02 04 02 08 35 30 30 30 30 30 30 30 81 26 ......50000000.&
|
||||
| 320: 02 05 01 02 05 01 02 05 01 01 33 07 02 06 01 02 ..........3.....
|
||||
| 336: 06 01 02 06 81 2c 02 04 01 02 04 01 02 04 02 04 .....,..........
|
||||
| 352: 32 37 36 36 81 23 02 05 01 02 05 01 02 05 01 01 2766.#..........
|
||||
| 368: 34 13 02 05 01 02 05 01 02 05 02 03 30 39 36 1c 4...........096.
|
||||
| 384: 02 05 01 02 05 01 02 05 07 02 05 01 02 05 01 02 ................
|
||||
| 400: 05 01 03 35 30 30 7f 02 05 01 02 05 01 02 05 04 ...500..........
|
||||
| 416: 02 30 30 81 0e 02 06 01 02 06 01 02 06 06 03 30 .00............0
|
||||
| 432: 30 30 81 11 02 04 01 02 04 01 02 04 01 05 36 35 00............65
|
||||
| 448: 35 33 36 81 1a 02 05 01 02 05 01 02 05 01 04 38 536............8
|
||||
| 464: 31 39 32 81 02 02 06 01 02 06 01 02 06 01 05 61 192............a
|
||||
| 480: 6c 6c 6f 77 01 02 02 01 02 02 01 02 02 02 02 72 llow...........r
|
||||
| 496: 67 81 08 02 04 01 02 04 01 02 04 02 05 74 6f 6d g............tom
|
||||
| 512: 69 63 04 02 02 01 02 02 01 02 02 03 06 74 61 63 ic...........tac
|
||||
| 528: 68 65 64 79 02 03 01 02 03 01 02 03 02 0d 75 74 hedy..........ut
|
||||
| 544: 6f 63 68 65 63 6b 70 6f 69 6e 74 2b 02 04 01 02 ocheckpoint+....
|
||||
| 560: 04 01 02 04 05 06 76 61 63 75 75 6d 0d 02 03 01 ......vacuum....
|
||||
| 576: 02 03 01 02 03 01 06 62 69 6e 61 72 79 03 06 01 .......binary...
|
||||
| 592: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
|
||||
| 608: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................
|
||||
| 624: 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 ................
|
||||
| 640: 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 ................
|
||||
| 656: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
|
||||
| 672: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
|
||||
| 688: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................
|
||||
| 704: 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 ................
|
||||
| 720: 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 ................
|
||||
| 736: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
|
||||
| 752: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
|
||||
| 768: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................
|
||||
| 784: 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 ................
|
||||
| 800: 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 ................
|
||||
| 816: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
|
||||
| 832: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
|
||||
| 848: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................
|
||||
| 864: 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 ................
|
||||
| 880: 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 ................
|
||||
| 896: 01 02 02 02 07 79 74 65 63 6f 64 65 37 02 03 01 .....ytecode7...
|
||||
| 912: 02 03 01 02 03 01 05 63 61 63 68 65 10 02 03 01 .......cache....
|
||||
| 928: 02 03 01 01 03 02 04 6c 61 6e 67 07 02 03 01 02 .......lang.....
|
||||
| 944: 03 01 02 03 02 05 6f 6c 75 6d 6e 7c 02 03 01 02 ......olumn|....
|
||||
| 960: 03 01 02 03 03 06 6d 6d 65 6e 74 73 43 02 04 01 ......mmentsC...
|
||||
| 976: 02 04 01 02 04 04 05 70 69 6c 65 72 07 02 02 01 .......piler....
|
||||
| 992: 02 02 01 02 02 05 04 6f 75 6e 64 7f 02 03 01 02 .......ound.....
|
||||
| 1008: 03 01 02 03 03 03 75 6e 74 81 17 02 04 01 02 04 ......unt.......
|
||||
| 1024: 01 02 04 02 05 75 72 73 6f 72 3a 02 03 01 02 03 .....ursor:.....
|
||||
| 1040: 01 02 03 01 06 64 62 70 61 67 65 3d 02 03 01 02 .....dbpage=....
|
||||
| 1056: 03 01 02 03 03 04 73 74 61 74 40 02 03 01 02 03 ......stat@.....
|
||||
| 1072: 01 02 03 02 04 65 62 75 67 0a 02 02 01 02 02 01 .....ebug.......
|
||||
| 1088: 02 02 03 05 66 61 75 6c 74 0d 02 02 01 02 02 01 ....fault.......
|
||||
| 1104: 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 ................
|
||||
| 1120: 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 ................
|
||||
| 1136: 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 ................
|
||||
| 1152: 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 ................
|
||||
| 1168: 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 ................
|
||||
| 1184: 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 ................
|
||||
| 1200: 02 02 01 02 02 01 02 02 01 02 02 01 02 02 4f 02 ..............O.
|
||||
| 1216: 03 01 02 03 01 02 03 03 03 70 74 68 81 05 02 04 .........pth....
|
||||
| 1232: 01 02 04 01 02 04 19 02 04 01 02 04 01 02 04 02 ................
|
||||
| 1248: 05 69 72 65 63 74 34 02 02 01 02 02 01 02 02 01 .irect4.........
|
||||
| 1264: 06 65 6e 61 62 6c 65 37 02 02 01 02 02 01 02 02 .enable7........
|
||||
| 1280: 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 ................
|
||||
| 1296: 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 ................
|
||||
| 1312: 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 ................
|
||||
| 1328: 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 ................
|
||||
| 1344: 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 ................
|
||||
| 1360: 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 ................
|
||||
| 1376: 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 ................
|
||||
| 1392: 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 ................
|
||||
| 1408: 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 ................
|
||||
| 1424: 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 ................
|
||||
| 1440: 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 ................
|
||||
| 1456: 02 01 02 02 02 06 78 70 6c 61 69 6e 43 02 03 01 ......xplainC...
|
||||
| 1472: 02 03 01 02 03 04 01 72 81 05 02 03 01 02 03 01 .......r........
|
||||
| 1488: 02 03 03 07 74 65 6e 73 69 6f 6e 81 2f 02 04 01 ....tension./...
|
||||
| 1504: 02 04 01 02 04 01 04 66 69 6c 65 13 02 03 01 02 .......file.....
|
||||
| 1520: 03 01 02 03 02 05 6f 72 6d 61 74 13 02 04 01 02 ......ormat.....
|
||||
| 1536: 04 01 02 04 02 03 74 73 33 46 02 03 01 02 03 01 ......ts3F......
|
||||
| 1552: 02 03 01 02 03 01 02 03 01 02 03 04 01 34 4c 02 .............4L.
|
||||
| 1568: 03 01 02 03 01 02 03 04 01 35 4f 02 03 01 02 03 .........5O.....
|
||||
| 1584: 01 02 03 02 03 75 6e 63 5e 02 05 01 02 05 01 02 .....unc^.......
|
||||
| 1600: 05 05 04 74 69 6f 6e 73 02 05 01 02 05 01 02 05 ...tions........
|
||||
| 1616: 13 02 03 01 02 03 01 02 03 09 01 73 55 02 04 01 ...........sU...
|
||||
| 1632: 02 04 01 02 04 01 07 67 65 6f 70 6f 6c 79 52 02 .......geopolyR.
|
||||
| 1648: 03 01 02 03 01 02 03 01 05 68 69 6e 74 73 3a 02 .........hints:.
|
||||
| 1664: 04 01 02 04 01 02 04 02 03 6f 6f 6b 61 02 04 01 .........ooka...
|
||||
| 1680: 02 04 01 02 04 01 02 69 6e 01 02 04 01 02 04 01 .......in.......
|
||||
| 1696: 02 04 03 04 69 74 73 7a 1f 02 04 01 02 04 01 02 ....itsz........
|
||||
| 1712: 04 03 08 74 72 69 6e 73 69 63 73 04 02 03 01 02 ...trinsics.....
|
||||
| 1728: 03 01 02 03 01 07 6a 6f 75 72 6e 61 6c 16 02 03 ......journal...
|
||||
| 1744: 01 02 03 01 02 03 01 06 6c 65 6e 67 74 68 81 0b ........length..
|
||||
| 1760: 02 03 01 02 03 01 02 03 01 02 05 01 02 05 01 02 ................
|
||||
| 1776: 05 0d 02 04 01 02 04 01 02 04 02 03 69 6b 65 81 ............ike.
|
||||
| 1792: 0e 02 03 01 02 03 01 02 03 03 03 6d 69 74 16 02 ...........mit..
|
||||
| 1808: 05 01 02 05 01 02 05 5e 02 04 01 02 04 01 02 04 .......^........
|
||||
| 1824: 02 03 6f 61 64 81 2f 02 03 01 02 03 01 02 03 01 ..oad./.........
|
||||
| 1840: 06 6d 61 6c 6c 6f 63 76 02 02 01 02 02 01 02 02 .mallocv........
|
||||
| 1856: 3a 02 03 01 02 03 01 02 03 03 02 74 68 55 02 03 :..........thU..
|
||||
| 1872: 01 02 03 01 02 03 03 01 78 79 02 02 01 02 02 01 ........xy......
|
||||
| 1888: 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 ................
|
||||
| 1904: 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 ................
|
||||
| 1920: 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 ................
|
||||
| 1936: 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 ................
|
||||
| 1952: 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 ................
|
||||
| 1968: 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 ................
|
||||
| 1984: 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 ................
|
||||
| 2000: 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 ................
|
||||
| 2016: 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 ................
|
||||
| 2032: 02 02 02 05 65 6d 6f 72 79 81 11 02 03 01 02 03 ....emory.......
|
||||
| 2048: 01 02 03 04 04 73 79 73 35 58 02 03 01 02 03 01 .....sys5X......
|
||||
| 2064: 02 03 02 03 6d 61 70 19 02 03 01 02 03 01 02 03 ....map.........
|
||||
| 2080: 79 02 03 01 02 03 01 02 03 02 04 75 74 65 78 81 y..........utex.
|
||||
| 2096: 2c 02 02 01 02 02 01 02 02 01 06 6e 6f 63 61 73 ,..........nocas
|
||||
| 2112: 65 02 06 01 02 02 03 06 01 02 02 03 06 01 02 02 e...............
|
||||
| 2128: 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 ................
|
||||
| 2144: 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 ................
|
||||
| 2160: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
|
||||
| 2176: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
|
||||
| 2192: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................
|
||||
| 2208: 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 ................
|
||||
| 2224: 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 ................
|
||||
| 2240: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
|
||||
| 2256: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
|
||||
| 2272: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................
|
||||
| 2288: 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 ................
|
||||
| 2304: 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 ................
|
||||
| 2320: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
|
||||
| 2336: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
|
||||
| 2352: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................
|
||||
| 2368: 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 ................
|
||||
| 2384: 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 ................
|
||||
| 2400: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
|
||||
| 2416: 02 02 03 06 01 02 02 03 07 72 6d 61 6c 69 7a 65 .........rmalize
|
||||
| 2432: 5b 02 03 01 02 03 01 02 03 02 05 75 6d 62 65 72 [..........umber
|
||||
| 2448: 81 23 02 04 01 02 04 01 02 04 01 06 6f 66 66 73 .#..........offs
|
||||
| 2464: 65 74 5e 02 03 01 02 03 01 02 03 02 03 6d 69 74 et^..........mit
|
||||
| 2480: 81 2c 02 03 01 02 03 01 02 03 01 02 02 01 02 02 .,..............
|
||||
| 2496: 01 02 02 02 01 70 81 26 02 04 01 02 04 01 02 04 .....p.&........
|
||||
| 2512: 02 07 76 65 72 66 6c 6f 77 34 02 03 01 02 03 01 ..verflow4......
|
||||
| 2528: 02 03 01 04 70 61 67 65 1c 02 03 01 02 03 01 02 ....page........
|
||||
| 2544: 03 64 02 04 01 02 04 01 02 04 13 02 03 01 02 03 .d..............
|
||||
| 2560: 01 02 03 01 02 03 01 02 03 01 02 03 03 09 72 65 ..............re
|
||||
| 2576: 6e 74 68 65 73 69 73 49 02 04 01 02 04 01 02 04 nthesisI........
|
||||
| 2592: 03 05 74 74 65 72 6e 81 0e 02 04 01 02 04 01 02 ..ttern.........
|
||||
| 2608: 04 02 05 63 61 63 68 65 1f 02 03 01 02 03 01 02 ...cache........
|
||||
| 2624: 03 02 08 72 65 75 70 64 61 74 65 61 02 03 01 02 ...reupdatea....
|
||||
| 2640: 03 01 02 03 01 04 72 65 61 64 34 02 04 01 02 04 ......read4.....
|
||||
| 2656: 01 02 04 03 07 63 75 72 73 69 76 65 22 02 03 01 .....cursive....
|
||||
| 2672: 02 03 01 02 03 02 04 6f 77 69 64 01 02 03 01 02 .......owid.....
|
||||
| 2688: 03 01 02 03 02 04 74 72 65 65 64 02 03 01 02 03 ......treed.....
|
||||
| 2704: 01 02 03 04 02 69 6d 01 06 01 02 02 03 06 01 02 .....im.........
|
||||
| 2720: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................
|
||||
| 2736: 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 ................
|
||||
| 2752: 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 ................
|
||||
| 2768: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
|
||||
| 2784: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
|
||||
| 2800: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................
|
||||
| 2816: 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 ................
|
||||
| 2832: 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 ................
|
||||
| 2848: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
|
||||
| 2864: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
|
||||
| 2880: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................
|
||||
| 2896: 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 ................
|
||||
| 2912: 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 ................
|
||||
| 2928: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
|
||||
| 2944: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
|
||||
| 2960: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................
|
||||
| 2976: 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 ................
|
||||
| 2992: 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 ................
|
||||
| 3008: 01 02 02 03 06 01 02 02 03 06 01 02 02 01 0a 73 ...............s
|
||||
| 3024: 63 61 6e 73 74 61 74 75 73 70 02 04 01 02 04 01 canstatusp......
|
||||
| 3040: 02 04 02 05 65 63 74 6f 72 25 02 03 01 02 03 01 ....ector%......
|
||||
| 3056: 02 03 03 04 6c 65 63 74 7f 02 04 01 02 04 01 02 ....lect........
|
||||
| 3072: 04 03 05 73 73 69 6f 6e 67 02 03 01 02 03 01 02 ...ssiong.......
|
||||
| 3088: 03 02 03 69 7a 65 10 02 04 01 02 04 01 02 04 04 ...ize..........
|
||||
| 3104: 02 04 01 02 04 01 02 04 01 02 04 01 02 04 01 02 ................
|
||||
| 3120: 04 01 02 04 01 02 04 01 02 04 07 02 04 01 02 04 ................
|
||||
| 3136: 01 02 04 5b 02 05 01 02 05 01 02 05 10 02 04 01 ...[............
|
||||
| 3152: 02 04 01 02 04 04 02 04 01 02 04 01 02 04 02 03 ................
|
||||
| 3168: 6f 66 74 76 02 03 01 02 03 01 02 03 02 02 71 6c oftv..........ql
|
||||
| 3184: 5e 02 04 01 02 04 01 02 04 13 02 04 01 02 04 01 ^...............
|
||||
| 3200: 02 04 28 02 03 01 02 03 01 02 03 02 04 74 61 74 ..(..........tat
|
||||
| 3216: 34 6a 02 03 01 02 03 01 02 03 03 02 6d 74 70 02 4j..........mtp.
|
||||
| 3232: 03 01 02 03 01 02 03 05 04 76 74 61 62 6d 02 03 .........vtabm..
|
||||
| 3248: 01 02 03 01 02 03 03 03 6f 72 65 81 35 02 03 01 ........ore.5...
|
||||
| 3264: 02 03 01 02 03 02 0a 79 6e 63 68 72 6f 6e 6f 75 .......ynchronou
|
||||
| 3280: 73 28 02 03 01 02 03 01 02 03 04 02 04 01 02 04 s(..............
|
||||
| 3296: 01 02 04 03 04 73 74 65 6d 81 32 02 02 01 02 02 .....stem.2.....
|
||||
| 3312: 01 02 02 01 04 74 65 6d 70 81 35 02 02 01 02 02 .....temp.5.....
|
||||
| 3328: 01 02 02 02 06 68 72 65 61 64 73 31 02 04 01 02 .....hreads1....
|
||||
| 3344: 04 01 02 04 76 02 04 01 02 04 01 02 04 08 03 61 ....v..........a
|
||||
| 3360: 66 65 81 38 02 02 01 02 02 01 02 02 02 06 72 69 fe.8..........ri
|
||||
| 3376: 67 67 65 72 81 20 02 03 01 02 03 01 02 03 08 01 gger. ..........
|
||||
| 3392: 73 22 02 04 01 02 04 01 02 04 01 07 75 6e 6b 6e s...........unkn
|
||||
| 3408: 6f 77 6e 73 02 03 01 02 03 01 02 03 01 08 76 61 owns..........va
|
||||
| 3424: 72 69 61 62 6c 65 81 23 02 03 01 02 03 01 02 03 riable.#........
|
||||
| 3440: 02 03 64 62 65 81 26 02 03 01 02 03 01 02 03 02 ..dbe.&.........
|
||||
| 3456: 03 69 65 77 01 02 05 01 02 05 01 02 05 02 03 74 .iew...........t
|
||||
| 3472: 61 62 37 02 04 01 02 04 01 02 04 04 02 04 01 02 ab7.............
|
||||
| 3488: 04 01 02 04 01 02 04 01 02 04 01 02 04 01 03 77 ...............w
|
||||
| 3504: 61 6c 2b 02 03 01 02 03 01 02 03 01 02 03 01 02 al+.............
|
||||
| 3520: 03 01 02 03 02 05 6f 72 6b 65 72 31 02 03 01 02 ......orker1....
|
||||
| 3536: 03 01 02 03 76 02 03 01 02 03 01 02 03 01 01 78 ....v..........x
|
||||
| 3552: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
|
||||
| 3568: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................
|
||||
| 3584: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................
|
||||
| 3600: 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................
|
||||
| 3616: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 ................
|
||||
| 3632: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
|
||||
| 3648: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................
|
||||
| 3664: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................
|
||||
| 3680: 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................
|
||||
| 3696: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 ................
|
||||
| 3712: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
|
||||
| 3728: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................
|
||||
| 3744: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................
|
||||
| 3760: 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................
|
||||
| 3776: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 ................
|
||||
| 3792: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
|
||||
| 3808: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................
|
||||
| 3824: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................
|
||||
| 3840: 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................
|
||||
| 3856: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 ................
|
||||
| 3872: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
|
||||
| 3888: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................
|
||||
| 3904: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................
|
||||
| 3920: 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................
|
||||
| 3936: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 ................
|
||||
| 3952: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
|
||||
| 3968: 06 01 01 02 01 06 04 30 15 1e 0c 28 1b 0d 0c 15 .......0...(....
|
||||
| 3984: 0c 16 14 16 10 0c 17 0e 0e 0f 11 10 10 0e 10 11 ................
|
||||
| 4000: 18 11 82 3e 12 10 0f 10 11 10 0f 0f 10 11 0f 0f ...>............
|
||||
| 4016: 81 05 18 10 81 45 11 0d 13 0f 10 17 0c 0c 0e 18 .....E..........
|
||||
| 4032: 0c 12 10 0e 0d 0f 13 12 24 0f 17 0f 1a 0d 81 1c ........$.......
|
||||
| 4048: 11 0f 17 10 82 3e 12 11 11 18 0d 12 2a 14 11 10 .....>......*...
|
||||
| 4064: 13 0f 12 0f 0f 82 3a 15 10 0f 10 4d 0e 1f 0f 0d ......:....M....
|
||||
| 4080: 0f 0f 1e 10 10 1a 0f 12 0c 12 14 0f 0e 20 17 19 ............. ..
|
||||
| page 12 offset 45056
|
||||
| 0: 0d 00 00 00 01 0d f4 00 0d f4 00 00 00 00 00 00 ................
|
||||
| 3568: 00 00 00 00 84 04 84 80 80 80 80 02 04 00 88 0c ................
|
||||
| 3584: 00 07 02 00 01 01 02 56 06 01 01 02 01 06 01 01 .......V........
|
||||
| 3600: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 ................
|
||||
| 3616: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
|
||||
| 3632: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................
|
||||
| 3648: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................
|
||||
| 3664: 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................
|
||||
| 3680: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 ................
|
||||
| 3696: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
|
||||
| 3712: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................
|
||||
| 3728: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................
|
||||
| 3744: 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................
|
||||
| 3760: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 ................
|
||||
| 3776: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
|
||||
| 3792: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................
|
||||
| 3808: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................
|
||||
| 3824: 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................
|
||||
| 3840: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 ................
|
||||
| 3856: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
|
||||
| 3872: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................
|
||||
| 3888: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................
|
||||
| 3904: 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................
|
||||
| 3920: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 ................
|
||||
| 3936: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
|
||||
| 3952: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................
|
||||
| 3968: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................
|
||||
| 3984: 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................
|
||||
| 4000: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 ................
|
||||
| 4016: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
|
||||
| 4032: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................
|
||||
| 4048: 52 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 R...............
|
||||
| 4064: 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................
|
||||
| 4080: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 ................
|
||||
| end c1a.txt.db
|
||||
}]} {}
|
||||
|
||||
do_catchsql_test 84.1 {
|
||||
SELECT * FROM t1('R*R*x') ORDER BY rowid DESC;
|
||||
} {1 {fts5: corruption found reading blob 137438953475 from table "t1"}}
|
||||
|
||||
sqlite3_fts5_may_be_corrupt 0
|
||||
finish_test
|
||||
@@ -305,6 +305,28 @@ do_catchsql_test 6.2 {
|
||||
|
||||
sqlite3_fts5_may_be_corrupt 0
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 7.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(a, b);
|
||||
CREATE VIRTUAL TABLE v1 USING fts5vocab(t1, col);
|
||||
|
||||
INSERT INTO t1 VALUES('xx', 'xx');
|
||||
|
||||
CREATE TABLE x1(t);
|
||||
INSERT INTO x1 VALUES('xx');
|
||||
INSERT INTO x1 VALUES('xx');
|
||||
|
||||
SELECT term, col FROM v1;
|
||||
} {
|
||||
xx a xx b
|
||||
}
|
||||
|
||||
do_execsql_test 7.1 {
|
||||
SELECT * FROM x1 WHERE 'a'=(SELECT col FROM v1 WHERE term=t)
|
||||
} {xx xx}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
+10
-5
@@ -230,13 +230,16 @@ static void hash_finish(
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
** Implementation of the sha1(X) function.
|
||||
** Two SQL functions: sha1(X) and sha1b(X).
|
||||
**
|
||||
** Return a lower-case hexadecimal rendering of the SHA1 hash of the
|
||||
** argument X. If X is a BLOB, it is hashed as is. For all other
|
||||
** sha1(X) returns a lower-case hexadecimal rendering of the SHA1 hash
|
||||
** of the argument X. If X is a BLOB, it is hashed as is. For all other
|
||||
** types of input, X is converted into a UTF-8 string and the string
|
||||
** is hash without the trailing 0x00 terminator. The hash of a NULL
|
||||
** is hashed without the trailing 0x00 terminator. The hash of a NULL
|
||||
** value is NULL.
|
||||
**
|
||||
** sha1b(X) is the same except that it returns a 20-byte BLOB containing
|
||||
** the binary hash instead of a hexadecimal string.
|
||||
*/
|
||||
static void sha1Func(
|
||||
sqlite3_context *context,
|
||||
@@ -257,11 +260,13 @@ static void sha1Func(
|
||||
hash_step(&cx, sqlite3_value_text(argv[0]), nByte);
|
||||
}
|
||||
if( sqlite3_user_data(context)!=0 ){
|
||||
/* sha1b() - binary result */
|
||||
hash_finish(&cx, zOut, 1);
|
||||
sqlite3_result_blob(context, zOut, 20, SQLITE_TRANSIENT);
|
||||
}else{
|
||||
/* sha1() - hexadecimal text result */
|
||||
hash_finish(&cx, zOut, 0);
|
||||
sqlite3_result_blob(context, zOut, 40, SQLITE_TRANSIENT);
|
||||
sqlite3_result_text(context, zOut, 40, SQLITE_TRANSIENT);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+89
-29
@@ -19,10 +19,10 @@ 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:
|
||||
Suppose variable `sqlite3_stmt *pStmt` is a pointer to an SQLite
|
||||
prepared statement 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 */
|
||||
@@ -41,21 +41,60 @@ if( rc ){
|
||||
sqlite3_free(zErrMsg); /* Free the error message text */
|
||||
}else{
|
||||
printf("%s", zResult); /* Report the results */
|
||||
sqlite3_free(zResult); /* Free memory used to hold 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
|
||||
and where to send the generated output. Most of the work in using
|
||||
the QRF involves filling out the sqlite3_qrf_spec.
|
||||
|
||||
### 1.1 Using QRF with SQL text
|
||||
|
||||
If you start with SQL text instead of an sqlite3_stmt pointer, and
|
||||
especially if the SQL text might comprise two or more statements, then
|
||||
the SQL text needs to be converted into sqlite3_stmt objects separately.
|
||||
If the original SQL text is in a variable `const char *zSql` and the
|
||||
database connection is in variable `sqlite3 *db`, then code
|
||||
similar to the following should work:
|
||||
|
||||
> ~~~
|
||||
sqlite3_qrf_spec spec; /* Format specification */
|
||||
char *zErrMsg; /* Text error message (optional) */
|
||||
char *zResult = 0; /* Formatted output written here */
|
||||
sqlite3_stmt *pStmt; /* Next prepared statement */
|
||||
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 */
|
||||
while( zSql && zSql[0] ){
|
||||
pStmt = 0; /* Not required; just being pedantic */
|
||||
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zSql);
|
||||
if( rc!=SQLITE_OK ){
|
||||
printf("Error: %s\n", sqlite3_errmsg(db));
|
||||
}else{
|
||||
rc = sqlite3_format_query_result(pStmt, &spec, &zErrMsg); /* Get 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 */
|
||||
zResult = 0;
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
}
|
||||
~~~
|
||||
|
||||
## 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.
|
||||
The most recent definition of `sqlite3_qrf_spec` is shown below.
|
||||
|
||||
Do not be alarmed by the complexity of this structure. You only have
|
||||
Do not be alarmed by the complexity of this structure. You only need
|
||||
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.
|
||||
@@ -74,9 +113,10 @@ struct sqlite3_qrf_spec {
|
||||
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 */
|
||||
unsigned char bSplitColumn; /* Wrap single-column output into many columns */
|
||||
unsigned char bBorder; /* Show outer border in Box and Table styles */
|
||||
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 */
|
||||
@@ -112,7 +152,7 @@ Further detail on the meanings of each of the fields in the
|
||||
### 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
|
||||
the QRF might add new fields to 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.
|
||||
|
||||
@@ -126,7 +166,7 @@ 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
|
||||
is initially non-NULL, then it is assumed to already point to memory obtained
|
||||
from sqlite3_malloc(). In that case, the buffer is resized using
|
||||
sqlite3_realloc() and the new text is appended.
|
||||
|
||||
@@ -140,8 +180,8 @@ 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.
|
||||
specific output format that will be generated. See [section 4.0](#style)
|
||||
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.
|
||||
@@ -265,6 +305,7 @@ how the BLOB value is formatted. The following options are available;
|
||||
#define QRF_BLOB_Hex 3 /* Hexadecimal representation */
|
||||
#define QRF_BLOB_Tcl 4 /* "\000" notation */
|
||||
#define QRF_BLOB_Json 5 /* A JSON string */
|
||||
#define QRF_BLOB_Size 6 /* Display the blob size only */
|
||||
~~~
|
||||
|
||||
A value of QRF_BLOB_Auto means that display format is selected automatically
|
||||
@@ -292,6 +333,10 @@ the C/Tcl/Perl octal backslash escapes. So the string from the
|
||||
previous paragraph would be shown as
|
||||
`"\u0005\u0028\u0081\u00f3"`.
|
||||
|
||||
A value of QRF_BLOB_Size does not show any BLOB content at all.
|
||||
Instead, it substitutes a text string that says how many bytes
|
||||
the BLOB contains.
|
||||
|
||||
### 2.8 Maximum size of displayed content (nLineLimit, nCharLimit)
|
||||
|
||||
If the sqlite3_qrf_spec.nCharLimit setting is non-zero, then the formatter
|
||||
@@ -350,6 +395,10 @@ 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.
|
||||
|
||||
The nScreenWidth field currently only makes a difference in
|
||||
columnar styles (**Box**, **Column**, **Markdown**, and **Table**)
|
||||
and in the **Line** style.
|
||||
|
||||
### 2.11 Individual Column Width (nWidth and aWidth)
|
||||
|
||||
The sqlite3_qrf_spec.aWidth field is a pointer to an array of
|
||||
@@ -457,8 +506,9 @@ 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 horizontal alignment, then values are right-aligned
|
||||
(QRF_ALIGN_Right) if they are numeric and left-aligned
|
||||
(QRF_ALIGN_Left) otherwise. If neither aAlign\[\] nor eDfltAlign
|
||||
specify a vertical alignment, then values are top-aligned
|
||||
(QRF_ALIGN_Top).
|
||||
|
||||
@@ -479,17 +529,12 @@ and these settings are ignored for those styles.
|
||||
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)
|
||||
### 2.15 The Rendering Of NULL (zNull)
|
||||
|
||||
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
|
||||
@@ -523,12 +568,13 @@ 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().
|
||||
|
||||
<a id="style"></a>
|
||||
## 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.
|
||||
output style (sometimes called "output mode") is determined by
|
||||
the eStyle field of the sqlite3_qrf_spec object. The set of
|
||||
supported output modes might increase in future versions.
|
||||
The following output modes are currently defined:
|
||||
|
||||
> ~~~
|
||||
@@ -584,8 +630,22 @@ 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.
|
||||
psql. The **Markdown** renders its result in the Markdown table format.
|
||||
|
||||
The **Box** and **Table** styles normally have a border that surrounds
|
||||
the entire result. However, if sqlite3_qrf_spec.bBorder is QRF_No, then
|
||||
that border is omitted, saving a little space both horizontally and
|
||||
vertically.
|
||||
|
||||
#### 4.2.1 Split Column Mode
|
||||
|
||||
If the bSplitColumn field is QRF_Yes, and eStyle is QRF_STYLE_Column,
|
||||
and bTitles is QRF_No, and nScreenWidth is greater than zero, and if
|
||||
the query only returns a single column, then a special rendering known
|
||||
as "Split Column Mode" will be used. In split column mode, instead
|
||||
of showing all results in one tall column, the content wraps vertically
|
||||
so that it appears on the screen as multiple columns, as many as will
|
||||
fit in the available screen width.
|
||||
|
||||
### 4.3 Line-oriented Styles
|
||||
|
||||
@@ -668,7 +728,7 @@ 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
|
||||
* `README.md` → This documentation
|
||||
|
||||
To use the SQLite result formatter, include the "`qrf.h`" header file
|
||||
and link the application against the "`qrf.c`" source file.
|
||||
+315
-72
@@ -428,7 +428,7 @@ static const struct {
|
||||
{1, 0x00f7f}, {0, 0x00f80}, {1, 0x00f85}, {0, 0x00f86}, {1, 0x00f88},
|
||||
{0, 0x00f90}, {1, 0x00f98}, {0, 0x00f99}, {1, 0x00fbd}, {0, 0x00fc6},
|
||||
{1, 0x00fc7}, {0, 0x0102d}, {1, 0x01031}, {0, 0x01032}, {1, 0x01033},
|
||||
{0, 0x01036}, {1, 0x01038}, {0, 0x01039}, {1, 0x0103a}, {0, 0x01058},
|
||||
{0, 0x01036}, {1, 0x0103b}, {0, 0x01058},
|
||||
{1, 0x0105a}, {2, 0x01100}, {0, 0x01160}, {1, 0x01200}, {0, 0x0135f},
|
||||
{1, 0x01360}, {0, 0x01712}, {1, 0x01715}, {0, 0x01732}, {1, 0x01735},
|
||||
{0, 0x01752}, {1, 0x01754}, {0, 0x01772}, {1, 0x01774}, {0, 0x017b4},
|
||||
@@ -471,7 +471,7 @@ int sqlite3_qrf_wcwidth(int c){
|
||||
int iFirst, iLast;
|
||||
|
||||
/* Fast path for common characters */
|
||||
if( c<=0x300 ) return 1;
|
||||
if( c<0x300 ) return 1;
|
||||
|
||||
/* The general case */
|
||||
iFirst = 0;
|
||||
@@ -577,11 +577,14 @@ static int qrfDisplayLength(const char *zIn){
|
||||
** it will need to be split.
|
||||
*/
|
||||
static int qrfDisplayWidth(const char *zIn, sqlite3_int64 nByte, int *pnNL){
|
||||
const unsigned char *z = (const unsigned char*)zIn;
|
||||
const unsigned char *zEnd = &z[nByte];
|
||||
const unsigned char *z;
|
||||
const unsigned char *zEnd;
|
||||
int mx = 0;
|
||||
int n = 0;
|
||||
int nNL = 0;
|
||||
if( zIn==0 ) zIn = "";
|
||||
z = (const unsigned char*)zIn;
|
||||
zEnd = &z[nByte];
|
||||
while( z<zEnd ){
|
||||
if( z[0]<' ' ){
|
||||
int k;
|
||||
@@ -983,6 +986,11 @@ static void qrfRenderValue(Qrf *p, sqlite3_str *pOut, int iCol){
|
||||
}
|
||||
break;
|
||||
}
|
||||
case QRF_BLOB_Size: {
|
||||
int nBlob = sqlite3_column_bytes(p->pStmt,iCol);
|
||||
sqlite3_str_appendf(pOut, "(%d-byte blob)", nBlob);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
const char *zTxt = (const char*)sqlite3_column_text(p->pStmt,iCol);
|
||||
qrfEncodeText(p, pOut, zTxt);
|
||||
@@ -991,11 +999,7 @@ static void qrfRenderValue(Qrf *p, sqlite3_str *pOut, int iCol){
|
||||
break;
|
||||
}
|
||||
case SQLITE_NULL: {
|
||||
if( p->spec.bTextNull==QRF_Yes ){
|
||||
qrfEncodeText(p, pOut, p->spec.zNull);
|
||||
}else{
|
||||
sqlite3_str_appendall(pOut, p->spec.zNull);
|
||||
}
|
||||
sqlite3_str_appendall(pOut, p->spec.zNull);
|
||||
break;
|
||||
}
|
||||
case SQLITE_TEXT: {
|
||||
@@ -1042,6 +1046,17 @@ static void qrfRenderValue(Qrf *p, sqlite3_str *pOut, int iCol){
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Trim spaces of the end if pOut
|
||||
*/
|
||||
static void qrfRTrim(sqlite3_str *pOut){
|
||||
#if SQLITE_VERSION_NUMBER>=3052000
|
||||
int nByte = sqlite3_str_length(pOut);
|
||||
const char *zOut = sqlite3_str_value(pOut);
|
||||
while( nByte>0 && zOut[nByte-1]==' ' ){ nByte--; }
|
||||
sqlite3_str_truncate(pOut, nByte);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** Store string zUtf to pOut as w characters. If w is negative,
|
||||
** then right-justify the text. W is the width in display characters, not
|
||||
@@ -1119,15 +1134,15 @@ static void qrfWrapLine(
|
||||
const unsigned char *z = (const unsigned char*)zIn;
|
||||
unsigned char c = 0;
|
||||
|
||||
if( zIn[0]==0 ){
|
||||
if( z[0]==0 ){
|
||||
*pnThis = 0;
|
||||
*pnWide = 0;
|
||||
*piNext = 0;
|
||||
return;
|
||||
}
|
||||
n = 0;
|
||||
for(i=0; n<w; i++){
|
||||
c = zIn[i];
|
||||
for(i=0; n<=w; i++){
|
||||
c = z[i];
|
||||
if( c>=0xc0 ){
|
||||
int u;
|
||||
int len = sqlite3_qrf_decode_utf8(&z[i], &u);
|
||||
@@ -1138,11 +1153,12 @@ static void qrfWrapLine(
|
||||
continue;
|
||||
}
|
||||
if( c>=' ' ){
|
||||
if( n==w ) break;
|
||||
n++;
|
||||
continue;
|
||||
}
|
||||
if( c==0 || c=='\n' ) break;
|
||||
if( c=='\r' && zIn[i+1]=='\n' ){ c = zIn[++i]; break; }
|
||||
if( c=='\r' && z[i+1]=='\n' ){ c = z[++i]; break; }
|
||||
if( c=='\t' ){
|
||||
int wcw = 8 - (n&7);
|
||||
if( n+wcw>w ) break;
|
||||
@@ -1151,6 +1167,8 @@ static void qrfWrapLine(
|
||||
}
|
||||
if( c==0x1b && (k = qrfIsVt100(&z[i]))>0 ){
|
||||
i += k-1;
|
||||
}else if( n==w ){
|
||||
break;
|
||||
}else{
|
||||
n++;
|
||||
}
|
||||
@@ -1250,36 +1268,6 @@ static void qrfAppendWithTabs(
|
||||
sqlite3_str_append(pOut, (const char*)z, i);
|
||||
}
|
||||
|
||||
/*
|
||||
** Output horizontally justified text into pOut. The text is the
|
||||
** first nVal bytes of zVal. Include nWS bytes of whitespace, either
|
||||
** split between both sides, or on the left, or on the right, depending
|
||||
** on eAlign.
|
||||
*/
|
||||
static void qrfPrintAligned(
|
||||
sqlite3_str *pOut, /* Append text here */
|
||||
const char *zVal, /* Text to append */
|
||||
int nVal, /* Use only the first nVal bytes of zVal[] */
|
||||
int nWS, /* Whitespace for horizonal alignment */
|
||||
unsigned char eAlign /* Alignment type */
|
||||
){
|
||||
eAlign &= QRF_ALIGN_HMASK;
|
||||
if( eAlign==QRF_ALIGN_Center ){
|
||||
/* Center the text */
|
||||
sqlite3_str_appendchar(pOut, nWS/2, ' ');
|
||||
qrfAppendWithTabs(pOut, zVal, nVal);
|
||||
sqlite3_str_appendchar(pOut, nWS - nWS/2, ' ');
|
||||
}else if( eAlign==QRF_ALIGN_Right){
|
||||
/* Right justify the text */
|
||||
sqlite3_str_appendchar(pOut, nWS, ' ');
|
||||
qrfAppendWithTabs(pOut, zVal, nVal);
|
||||
}else{
|
||||
/* Left justify the next */
|
||||
qrfAppendWithTabs(pOut, zVal, nVal);
|
||||
sqlite3_str_appendchar(pOut, nWS, ' ');
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** GCC does not define the offsetof() macro so we'll have to do it
|
||||
** ourselves.
|
||||
@@ -1303,15 +1291,47 @@ struct qrfColData {
|
||||
sqlite3_int64 n; /* Number of cells. nCol*nRow */
|
||||
char **az; /* Content of all cells */
|
||||
int *aiWth; /* Width of each cell */
|
||||
unsigned char *abNum; /* True for each numeric cell */
|
||||
struct qrfPerCol { /* Per-column data */
|
||||
char *z; /* Cache of text for current row */
|
||||
int w; /* Computed width of this column */
|
||||
int mxW; /* Maximum natural (unwrapped) width */
|
||||
unsigned char e; /* Alignment */
|
||||
unsigned char fx; /* Width is fixed */
|
||||
unsigned char bNum; /* True if is numeric */
|
||||
} *a; /* One per column */
|
||||
};
|
||||
|
||||
/*
|
||||
** Output horizontally justified text into pOut. The text is the
|
||||
** first nVal bytes of zVal. Include nWS bytes of whitespace, either
|
||||
** split between both sides, or on the left, or on the right, depending
|
||||
** on eAlign.
|
||||
*/
|
||||
static void qrfPrintAligned(
|
||||
sqlite3_str *pOut, /* Append text here */
|
||||
struct qrfPerCol *pCol, /* Information about the text to print */
|
||||
int nVal, /* Use only the first nVal bytes of zVal[] */
|
||||
int nWS /* Whitespace for horizonal alignment */
|
||||
){
|
||||
unsigned char eAlign = pCol->e & QRF_ALIGN_HMASK;
|
||||
if( eAlign==QRF_Auto && pCol->bNum ) eAlign = QRF_ALIGN_Right;
|
||||
if( eAlign==QRF_ALIGN_Center ){
|
||||
/* Center the text */
|
||||
sqlite3_str_appendchar(pOut, nWS/2, ' ');
|
||||
qrfAppendWithTabs(pOut, pCol->z, nVal);
|
||||
sqlite3_str_appendchar(pOut, nWS - nWS/2, ' ');
|
||||
}else if( eAlign==QRF_ALIGN_Right ){
|
||||
/* Right justify the text */
|
||||
sqlite3_str_appendchar(pOut, nWS, ' ');
|
||||
qrfAppendWithTabs(pOut, pCol->z, nVal);
|
||||
}else{
|
||||
/* Left justify the text */
|
||||
qrfAppendWithTabs(pOut, pCol->z, nVal);
|
||||
sqlite3_str_appendchar(pOut, nWS, ' ');
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Free all the memory allocates in the qrfColData object
|
||||
*/
|
||||
@@ -1320,6 +1340,7 @@ static void qrfColDataFree(qrfColData *p){
|
||||
for(i=0; i<p->n; i++) sqlite3_free(p->az[i]);
|
||||
sqlite3_free(p->az);
|
||||
sqlite3_free(p->aiWth);
|
||||
sqlite3_free(p->abNum);
|
||||
sqlite3_free(p->a);
|
||||
memset(p, 0, sizeof(*p));
|
||||
}
|
||||
@@ -1331,6 +1352,7 @@ static void qrfColDataFree(qrfColData *p){
|
||||
static int qrfColDataEnlarge(qrfColData *p){
|
||||
char **azData;
|
||||
int *aiWth;
|
||||
unsigned char *abNum;
|
||||
p->nAlloc = 2*p->nAlloc + 10*p->nCol;
|
||||
azData = sqlite3_realloc64(p->az, p->nAlloc*sizeof(char*));
|
||||
if( azData==0 ){
|
||||
@@ -1346,6 +1368,13 @@ static int qrfColDataEnlarge(qrfColData *p){
|
||||
return 1;
|
||||
}
|
||||
p->aiWth = aiWth;
|
||||
abNum = sqlite3_realloc64(p->abNum, p->nAlloc);
|
||||
if( abNum==0 ){
|
||||
qrfOom(p->p);
|
||||
qrfColDataFree(p);
|
||||
return 1;
|
||||
}
|
||||
p->abNum = abNum;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1355,13 +1384,18 @@ static int qrfColDataEnlarge(qrfColData *p){
|
||||
static void qrfRowSeparator(sqlite3_str *pOut, qrfColData *p, char cSep){
|
||||
int i;
|
||||
if( p->nCol>0 ){
|
||||
sqlite3_str_append(pOut, &cSep, 1);
|
||||
int useBorder = p->p->spec.bBorder!=QRF_No;
|
||||
if( useBorder ){
|
||||
sqlite3_str_append(pOut, &cSep, 1);
|
||||
}
|
||||
sqlite3_str_appendchar(pOut, p->a[0].w+p->nMargin, '-');
|
||||
for(i=1; i<p->nCol; i++){
|
||||
sqlite3_str_append(pOut, &cSep, 1);
|
||||
sqlite3_str_appendchar(pOut, p->a[i].w+p->nMargin, '-');
|
||||
}
|
||||
sqlite3_str_append(pOut, &cSep, 1);
|
||||
if( useBorder ){
|
||||
sqlite3_str_append(pOut, &cSep, 1);
|
||||
}
|
||||
}
|
||||
sqlite3_str_append(pOut, "\n", 1);
|
||||
}
|
||||
@@ -1419,13 +1453,18 @@ static void qrfBoxSeparator(
|
||||
){
|
||||
int i;
|
||||
if( p->nCol>0 ){
|
||||
sqlite3_str_appendall(pOut, zSep1);
|
||||
int useBorder = p->p->spec.bBorder!=QRF_No;
|
||||
if( useBorder ){
|
||||
sqlite3_str_appendall(pOut, zSep1);
|
||||
}
|
||||
qrfBoxLine(pOut, p->a[0].w+p->nMargin);
|
||||
for(i=1; i<p->nCol; i++){
|
||||
sqlite3_str_appendall(pOut, zSep2);
|
||||
qrfBoxLine(pOut, p->a[i].w+p->nMargin);
|
||||
}
|
||||
sqlite3_str_appendall(pOut, zSep3);
|
||||
if( useBorder ){
|
||||
sqlite3_str_appendall(pOut, zSep3);
|
||||
}
|
||||
}
|
||||
sqlite3_str_append(pOut, "\n", 1);
|
||||
}
|
||||
@@ -1452,6 +1491,144 @@ static void qrfLoadAlignment(qrfColData *pData, Qrf *p){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** If the single column in pData->a[] with pData->n entries can be
|
||||
** laid out as nCol columns with a 2-space gap between each such
|
||||
** that all columns fit within nSW, then return a pointer to an array
|
||||
** of integers which is the width of each column from left to right.
|
||||
**
|
||||
** If the layout is not possible, return a NULL pointer.
|
||||
**
|
||||
** Space to hold the returned array is from sqlite_malloc64().
|
||||
*/
|
||||
static int *qrfValidLayout(
|
||||
qrfColData *pData, /* Collected query results */
|
||||
Qrf *p, /* On which to report an OOM */
|
||||
int nCol, /* Attempt this many columns */
|
||||
int nSW /* Screen width */
|
||||
){
|
||||
int i; /* Loop counter */
|
||||
int nr; /* Number of rows */
|
||||
int w = 0; /* Width of the current column */
|
||||
int t; /* Total width of all columns */
|
||||
int *aw; /* Array of individual column widths */
|
||||
|
||||
aw = sqlite3_malloc64( sizeof(int)*nCol );
|
||||
if( aw==0 ){
|
||||
qrfOom(p);
|
||||
return 0;
|
||||
}
|
||||
nr = (pData->n + nCol - 1)/nCol;
|
||||
for(i=0; i<pData->n; i++){
|
||||
if( (i%nr)==0 ){
|
||||
if( i>0 ) aw[i/nr-1] = w;
|
||||
w = pData->aiWth[i];
|
||||
}else if( pData->aiWth[i]>w ){
|
||||
w = pData->aiWth[i];
|
||||
}
|
||||
}
|
||||
aw[nCol-1] = w;
|
||||
for(t=i=0; i<nCol; i++) t += aw[i];
|
||||
t += 2*(nCol-1);
|
||||
if( t>nSW ){
|
||||
sqlite3_free(aw);
|
||||
return 0;
|
||||
}
|
||||
return aw;
|
||||
}
|
||||
|
||||
/*
|
||||
** The output is single-column and the bSplitColumn flag is set.
|
||||
** Check to see if the single-column output can be split into multiple
|
||||
** columns that appear side-by-side. Adjust pData appropriately.
|
||||
*/
|
||||
static void qrfSplitColumn(qrfColData *pData, Qrf *p){
|
||||
int nCol = 1;
|
||||
int *aw = 0;
|
||||
char **az = 0;
|
||||
int *aiWth = 0;
|
||||
unsigned char *abNum = 0;
|
||||
int nColNext = 2;
|
||||
int w;
|
||||
struct qrfPerCol *a = 0;
|
||||
sqlite3_int64 nRow = 1;
|
||||
sqlite3_int64 i;
|
||||
while( 1/*exit-by-break*/ ){
|
||||
int *awNew = qrfValidLayout(pData, p, nColNext, p->spec.nScreenWidth);
|
||||
if( awNew==0 ) break;
|
||||
sqlite3_free(aw);
|
||||
aw = awNew;
|
||||
nCol = nColNext;
|
||||
nRow = (pData->n + nCol - 1)/nCol;
|
||||
if( nRow==1 ) break;
|
||||
nColNext++;
|
||||
while( (pData->n + nColNext - 1)/nColNext == nRow ) nColNext++;
|
||||
}
|
||||
if( nCol==1 ){
|
||||
sqlite3_free(aw);
|
||||
return; /* Cannot do better than 1 column */
|
||||
}
|
||||
az = sqlite3_malloc64( nRow*nCol*sizeof(char*) );
|
||||
if( az==0 ){
|
||||
qrfOom(p);
|
||||
return;
|
||||
}
|
||||
aiWth = sqlite3_malloc64( nRow*nCol*sizeof(int) );
|
||||
if( aiWth==0 ){
|
||||
sqlite3_free(az);
|
||||
qrfOom(p);
|
||||
return;
|
||||
}
|
||||
a = sqlite3_malloc64( nCol*sizeof(struct qrfPerCol) );
|
||||
if( a==0 ){
|
||||
sqlite3_free(az);
|
||||
sqlite3_free(aiWth);
|
||||
qrfOom(p);
|
||||
return;
|
||||
}
|
||||
abNum = sqlite3_malloc64( nRow*nCol );
|
||||
if( abNum==0 ){
|
||||
sqlite3_free(az);
|
||||
sqlite3_free(aiWth);
|
||||
sqlite3_free(a);
|
||||
qrfOom(p);
|
||||
return;
|
||||
}
|
||||
for(i=0; i<pData->n; i++){
|
||||
sqlite3_int64 j = (i%nRow)*nCol + (i/nRow);
|
||||
az[j] = pData->az[i];
|
||||
abNum[j]= pData->abNum[i];
|
||||
pData->az[i] = 0;
|
||||
aiWth[j] = pData->aiWth[i];
|
||||
}
|
||||
while( i<nRow*nCol ){
|
||||
sqlite3_int64 j = (i%nRow)*nCol + (i/nRow);
|
||||
az[j] = sqlite3_mprintf("");
|
||||
if( az[j]==0 ) qrfOom(p);
|
||||
aiWth[j] = 0;
|
||||
abNum[j] = 0;
|
||||
i++;
|
||||
}
|
||||
for(i=0; i<nCol; i++){
|
||||
a[i].fx = a[i].mxW = a[i].w = aw[i];
|
||||
a[i].e = pData->a[0].e;
|
||||
}
|
||||
sqlite3_free(pData->az);
|
||||
sqlite3_free(pData->aiWth);
|
||||
sqlite3_free(pData->a);
|
||||
sqlite3_free(pData->abNum);
|
||||
sqlite3_free(aw);
|
||||
pData->az = az;
|
||||
pData->aiWth = aiWth;
|
||||
pData->a = a;
|
||||
pData->abNum = abNum;
|
||||
pData->nCol = nCol;
|
||||
pData->n = pData->nAlloc = nRow*nCol;
|
||||
for(i=w=0; i<nCol; i++) w += a[i].w;
|
||||
pData->nMargin = (p->spec.nScreenWidth - w)/(nCol - 1);
|
||||
if( pData->nMargin>5 ) pData->nMargin = 5;
|
||||
}
|
||||
|
||||
/*
|
||||
** Adjust the layout for the screen width restriction
|
||||
*/
|
||||
@@ -1468,6 +1645,7 @@ static void qrfRestrictScreenWidth(qrfColData *pData, Qrf *p){
|
||||
sepW = pData->nCol*2 - 2;
|
||||
}else{
|
||||
sepW = pData->nCol*3 + 1;
|
||||
if( p->spec.bBorder==QRF_No ) sepW -= 2;
|
||||
}
|
||||
nCol = pData->nCol;
|
||||
for(i=sumW=0; i<nCol; i++) sumW += pData->a[i].w;
|
||||
@@ -1479,6 +1657,7 @@ static void qrfRestrictScreenWidth(qrfColData *pData, Qrf *p){
|
||||
sepW = pData->nCol - 1;
|
||||
}else{
|
||||
sepW = pData->nCol + 1;
|
||||
if( p->spec.bBorder==QRF_No ) sepW -= 2;
|
||||
}
|
||||
targetW = p->spec.nScreenWidth - sepW;
|
||||
|
||||
@@ -1541,6 +1720,7 @@ static void qrfColumnar(Qrf *p){
|
||||
int bWW; /* True to do word-wrap */
|
||||
sqlite3_str *pStr; /* Temporary rendering */
|
||||
qrfColData data; /* Columnar layout data */
|
||||
int bRTrim; /* Trim trailing space */
|
||||
|
||||
rc = sqlite3_step(p->pStmt);
|
||||
if( rc!=SQLITE_ROW || nColumn==0 ){
|
||||
@@ -1550,6 +1730,7 @@ static void qrfColumnar(Qrf *p){
|
||||
/* Initialize the data container */
|
||||
memset(&data, 0, sizeof(data));
|
||||
data.nCol = p->nCol;
|
||||
data.p = p;
|
||||
data.a = sqlite3_malloc64( nColumn*sizeof(struct qrfPerCol) );
|
||||
if( data.a==0 ){
|
||||
qrfOom(p);
|
||||
@@ -1563,6 +1744,7 @@ static void qrfColumnar(Qrf *p){
|
||||
if( p->spec.bTitles==QRF_Yes ){
|
||||
unsigned char saved_eText = p->spec.eText;
|
||||
p->spec.eText = p->spec.eTitle;
|
||||
memset(data.abNum, 0, nColumn);
|
||||
for(i=0; i<nColumn; i++){
|
||||
const char *z = (const char*)sqlite3_column_name(p->pStmt,i);
|
||||
int nNL = 0;
|
||||
@@ -1587,10 +1769,12 @@ static void qrfColumnar(Qrf *p){
|
||||
char *z;
|
||||
int nNL = 0;
|
||||
int n, w;
|
||||
int eType = sqlite3_column_type(p->pStmt,i);
|
||||
pStr = sqlite3_str_new(p->db);
|
||||
qrfRenderValue(p, pStr, i);
|
||||
n = sqlite3_str_length(pStr);
|
||||
z = data.az[data.n] = sqlite3_str_finish(pStr);
|
||||
data.abNum[data.n] = eType==SQLITE_INTEGER || eType==SQLITE_FLOAT;
|
||||
data.aiWth[data.n] = w = qrfDisplayWidth(z, n, &nNL);
|
||||
data.n++;
|
||||
if( w>data.a[i].mxW ) data.a[i].mxW = w;
|
||||
@@ -1650,8 +1834,22 @@ static void qrfColumnar(Qrf *p){
|
||||
data.a[i].w = w;
|
||||
}
|
||||
|
||||
/* Adjust the column widths due to screen width restrictions */
|
||||
qrfRestrictScreenWidth(&data, p);
|
||||
if( nColumn==1
|
||||
&& data.n>1
|
||||
&& p->spec.bSplitColumn==QRF_Yes
|
||||
&& p->spec.eStyle==QRF_STYLE_Column
|
||||
&& p->spec.bTitles==QRF_No
|
||||
&& p->spec.nScreenWidth>data.a[0].w+3
|
||||
){
|
||||
/* Attempt to convert single-column tables into multi-column by
|
||||
** verticle wrapping, if the screen is wide enough and if the
|
||||
** bSplitColumn flag is set. */
|
||||
qrfSplitColumn(&data, p);
|
||||
nColumn = data.nCol;
|
||||
}else{
|
||||
/* Adjust the column widths due to screen width restrictions */
|
||||
qrfRestrictScreenWidth(&data, p);
|
||||
}
|
||||
|
||||
/* Draw the line across the top of the table. Also initialize
|
||||
** the row boundary and column separator texts. */
|
||||
@@ -1666,7 +1864,12 @@ static void qrfColumnar(Qrf *p){
|
||||
colSep = BOX_13;
|
||||
rowSep = BOX_13 "\n";
|
||||
}
|
||||
qrfBoxSeparator(p->pOut, &data, BOX_23, BOX_234, BOX_34);
|
||||
if( p->spec.bBorder==QRF_No){
|
||||
rowStart += 3;
|
||||
rowSep = "\n";
|
||||
}else{
|
||||
qrfBoxSeparator(p->pOut, &data, BOX_23, BOX_234, BOX_34);
|
||||
}
|
||||
break;
|
||||
case QRF_STYLE_Table:
|
||||
if( data.nMargin ){
|
||||
@@ -1678,13 +1881,26 @@ static void qrfColumnar(Qrf *p){
|
||||
colSep = "|";
|
||||
rowSep = "|\n";
|
||||
}
|
||||
qrfRowSeparator(p->pOut, &data, '+');
|
||||
if( p->spec.bBorder==QRF_No ){
|
||||
rowStart += 1;
|
||||
rowSep = "\n";
|
||||
}else{
|
||||
qrfRowSeparator(p->pOut, &data, '+');
|
||||
}
|
||||
break;
|
||||
case QRF_STYLE_Column:
|
||||
case QRF_STYLE_Column: {
|
||||
static const char zSpace[] = " ";
|
||||
rowStart = "";
|
||||
colSep = data.nMargin ? " " : " ";
|
||||
if( data.nMargin<2 ){
|
||||
colSep = " ";
|
||||
}else if( data.nMargin<=5 ){
|
||||
colSep = &zSpace[5-data.nMargin];
|
||||
}else{
|
||||
colSep = zSpace;
|
||||
}
|
||||
rowSep = "\n";
|
||||
break;
|
||||
}
|
||||
default: /*case QRF_STYLE_Markdown:*/
|
||||
if( data.nMargin ){
|
||||
rowStart = "| ";
|
||||
@@ -1702,6 +1918,15 @@ static void qrfColumnar(Qrf *p){
|
||||
szColSep = (int)strlen(colSep);
|
||||
|
||||
bWW = (p->spec.bWordWrap==QRF_Yes && data.bMultiRow);
|
||||
if( p->spec.eStyle==QRF_STYLE_Column
|
||||
|| (p->spec.bBorder==QRF_No
|
||||
&& (p->spec.eStyle==QRF_STYLE_Box || p->spec.eStyle==QRF_STYLE_Table)
|
||||
)
|
||||
){
|
||||
bRTrim = 1;
|
||||
}else{
|
||||
bRTrim = 0;
|
||||
}
|
||||
for(i=0; i<data.n; i+=nColumn){
|
||||
int bMore;
|
||||
int nRow = 0;
|
||||
@@ -1710,7 +1935,11 @@ static void qrfColumnar(Qrf *p){
|
||||
** (if there is a title line) or a row in the body of the table.
|
||||
** The column number will be j. The row number is i/nColumn.
|
||||
*/
|
||||
for(j=0; j<nColumn; j++){ data.a[j].z = data.az[i+j]; }
|
||||
for(j=0; j<nColumn; j++){
|
||||
data.a[j].z = data.az[i+j];
|
||||
if( data.a[j].z==0 ) data.a[j].z = "";
|
||||
data.a[j].bNum = data.abNum[i+j];
|
||||
}
|
||||
do{
|
||||
sqlite3_str_append(p->pOut, rowStart, szRowStart);
|
||||
bMore = 0;
|
||||
@@ -1721,12 +1950,15 @@ static void qrfColumnar(Qrf *p){
|
||||
int nWS;
|
||||
qrfWrapLine(data.a[j].z, data.a[j].w, bWW, &nThis, &nWide, &iNext);
|
||||
nWS = data.a[j].w - nWide;
|
||||
qrfPrintAligned(p->pOut, data.a[j].z, nThis, nWS, data.a[j].e);
|
||||
qrfPrintAligned(p->pOut, &data.a[j], nThis, nWS);
|
||||
data.a[j].z += iNext;
|
||||
if( data.a[j].z[0]!=0 ) bMore = 1;
|
||||
if( data.a[j].z[0]!=0 ){
|
||||
bMore = 1;
|
||||
}
|
||||
if( j<nColumn-1 ){
|
||||
sqlite3_str_append(p->pOut, colSep, szColSep);
|
||||
}else{
|
||||
if( bRTrim ) qrfRTrim(p->pOut);
|
||||
sqlite3_str_append(p->pOut, rowSep, szRowSep);
|
||||
}
|
||||
}
|
||||
@@ -1740,11 +1972,13 @@ static void qrfColumnar(Qrf *p){
|
||||
}else{
|
||||
int nE = 3;
|
||||
if( nE>data.a[j].w ) nE = data.a[j].w;
|
||||
qrfPrintAligned(p->pOut, "...", nE, data.a[j].w-nE, data.a[j].e);
|
||||
data.a[j].z = "...";
|
||||
qrfPrintAligned(p->pOut, &data.a[j], nE, data.a[j].w-nE);
|
||||
}
|
||||
if( j<nColumn-1 ){
|
||||
sqlite3_str_append(p->pOut, colSep, szColSep);
|
||||
}else{
|
||||
if( bRTrim ) qrfRTrim(p->pOut);
|
||||
sqlite3_str_append(p->pOut, rowSep, szRowSep);
|
||||
}
|
||||
}
|
||||
@@ -1785,10 +2019,12 @@ static void qrfColumnar(Qrf *p){
|
||||
if( j<nColumn-1 ){
|
||||
sqlite3_str_append(p->pOut, colSep, szColSep);
|
||||
}else{
|
||||
qrfRTrim(p->pOut);
|
||||
sqlite3_str_append(p->pOut, rowSep, szRowSep);
|
||||
}
|
||||
}
|
||||
}else if( data.bMultiRow ){
|
||||
qrfRTrim(p->pOut);
|
||||
sqlite3_str_append(p->pOut, "\n", 1);
|
||||
}
|
||||
break;
|
||||
@@ -1798,13 +2034,15 @@ static void qrfColumnar(Qrf *p){
|
||||
}
|
||||
|
||||
/* Draw the line across the bottom of the table */
|
||||
switch( p->spec.eStyle ){
|
||||
case QRF_STYLE_Box:
|
||||
qrfBoxSeparator(p->pOut, &data, BOX_12, BOX_124, BOX_14);
|
||||
break;
|
||||
case QRF_STYLE_Table:
|
||||
qrfRowSeparator(p->pOut, &data, '+');
|
||||
break;
|
||||
if( p->spec.bBorder!=QRF_No ){
|
||||
switch( p->spec.eStyle ){
|
||||
case QRF_STYLE_Box:
|
||||
qrfBoxSeparator(p->pOut, &data, BOX_12, BOX_124, BOX_14);
|
||||
break;
|
||||
case QRF_STYLE_Table:
|
||||
qrfRowSeparator(p->pOut, &data, '+');
|
||||
break;
|
||||
}
|
||||
}
|
||||
qrfWrite(p);
|
||||
|
||||
@@ -2254,6 +2492,11 @@ static void qrfInitialize(
|
||||
if( p->mxWidth<=0 ) p->mxWidth = QRF_MAX_WIDTH;
|
||||
p->mxHeight = p->spec.nLineLimit;
|
||||
if( p->mxHeight<=0 ) p->mxHeight = 2147483647;
|
||||
if( p->spec.eStyle>QRF_STYLE_Table ) p->spec.eStyle = QRF_Auto;
|
||||
if( p->spec.eEsc>QRF_ESC_Symbol ) p->spec.eEsc = QRF_Auto;
|
||||
if( p->spec.eText>QRF_TEXT_Json ) p->spec.eText = QRF_Auto;
|
||||
if( p->spec.eTitle>QRF_TEXT_Json ) p->spec.eTitle = QRF_Auto;
|
||||
if( p->spec.eBlob>QRF_BLOB_Size ) p->spec.eBlob = QRF_Auto;
|
||||
qrf_reinit:
|
||||
switch( p->spec.eStyle ){
|
||||
case QRF_Auto: {
|
||||
@@ -2272,7 +2515,6 @@ qrf_reinit:
|
||||
case QRF_STYLE_JObject:
|
||||
case QRF_STYLE_Json: {
|
||||
p->spec.eText = QRF_TEXT_Json;
|
||||
p->spec.eBlob = QRF_BLOB_Json;
|
||||
p->spec.zNull = "null";
|
||||
break;
|
||||
}
|
||||
@@ -2283,7 +2525,6 @@ qrf_reinit:
|
||||
}
|
||||
case QRF_STYLE_Insert: {
|
||||
p->spec.eText = QRF_TEXT_Sql;
|
||||
p->spec.eBlob = QRF_BLOB_Sql;
|
||||
p->spec.zNull = "NULL";
|
||||
if( p->spec.zTableName==0 || p->spec.zTableName[0]==0 ){
|
||||
p->spec.zTableName = "tab";
|
||||
@@ -2293,7 +2534,6 @@ qrf_reinit:
|
||||
case QRF_STYLE_Csv: {
|
||||
p->spec.eStyle = QRF_STYLE_List;
|
||||
p->spec.eText = QRF_TEXT_Csv;
|
||||
p->spec.eBlob = QRF_BLOB_Text;
|
||||
p->spec.zColumnSep = ",";
|
||||
p->spec.zRowSep = "\r\n";
|
||||
p->spec.zNull = "";
|
||||
@@ -2301,7 +2541,6 @@ qrf_reinit:
|
||||
}
|
||||
case QRF_STYLE_Quote: {
|
||||
p->spec.eText = QRF_TEXT_Sql;
|
||||
p->spec.eBlob = QRF_BLOB_Sql;
|
||||
p->spec.zNull = "NULL";
|
||||
p->spec.zColumnSep = ",";
|
||||
p->spec.zRowSep = "\n";
|
||||
@@ -2386,13 +2625,17 @@ static void qrfFinalize(Qrf *p){
|
||||
break;
|
||||
}
|
||||
case QRF_STYLE_Json: {
|
||||
sqlite3_str_append(p->pOut, "}]\n", 3);
|
||||
qrfWrite(p);
|
||||
if( p->nRow>0 ){
|
||||
sqlite3_str_append(p->pOut, "}]\n", 3);
|
||||
qrfWrite(p);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case QRF_STYLE_JObject: {
|
||||
sqlite3_str_append(p->pOut, "}\n", 2);
|
||||
qrfWrite(p);
|
||||
if( p->nRow>0 ){
|
||||
sqlite3_str_append(p->pOut, "}\n", 2);
|
||||
qrfWrite(p);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case QRF_STYLE_Line: {
|
||||
|
||||
+9
-3
@@ -14,6 +14,9 @@
|
||||
*/
|
||||
#ifndef SQLITE_QRF_H
|
||||
#define SQLITE_QRF_H
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include "sqlite3.h"
|
||||
|
||||
@@ -31,9 +34,10 @@ struct sqlite3_qrf_spec {
|
||||
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 */
|
||||
unsigned char bSplitColumn; /* Wrap single-column output into many columns */
|
||||
unsigned char bBorder; /* Show outer border in Box and Table styles */
|
||||
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 */
|
||||
@@ -116,6 +120,7 @@ int sqlite3_format_query_result(
|
||||
#define QRF_BLOB_Hex 3 /* Hexadecimal representation */
|
||||
#define QRF_BLOB_Tcl 4 /* "\000" notation */
|
||||
#define QRF_BLOB_Json 5 /* A JSON string */
|
||||
#define QRF_BLOB_Size 6 /* Display the blob size only */
|
||||
|
||||
/*
|
||||
** Control-character escape modes.
|
||||
@@ -179,6 +184,7 @@ int sqlite3_format_query_result(
|
||||
int sqlite3_qrf_wcwidth(int c);
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* !defined(SQLITE_QRF_H) */
|
||||
+71
-13
@@ -874,7 +874,6 @@ $(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 '*/'; \
|
||||
} > $@
|
||||
|
||||
@@ -910,6 +909,7 @@ sqlite3-api.jses += $(dir.api)/sqlite3-vfs-helper.c-pp.js
|
||||
ifeq (0,$(wasm-bare-bones))
|
||||
sqlite3-api.jses += $(dir.api)/sqlite3-vtab-helper.c-pp.js
|
||||
endif
|
||||
sqlite3-api.jses += $(dir.api)/sqlite3-vfs-kvvfs.c-pp.js
|
||||
sqlite3-api.jses += $(dir.api)/sqlite3-vfs-opfs.c-pp.js
|
||||
sqlite3-api.jses += $(dir.api)/sqlite3-vfs-opfs-sahpool.c-pp.js
|
||||
|
||||
@@ -996,13 +996,21 @@ endif
|
||||
# /shell.c
|
||||
########################################################################
|
||||
|
||||
#
|
||||
# Fiddle-related decls we need before .wasmbuilds is included
|
||||
#
|
||||
|
||||
fiddle.c.in = $(dir.top)/shell.c $(sqlite3-wasm.c)
|
||||
|
||||
EXPORTED_FUNCTIONS.fiddle = $(dir.tmp)/EXPORTED_FUNCTIONS.fiddle
|
||||
$(EXPORTED_FUNCTIONS.fiddle): $(EXPORTED_FUNCTIONS.api.in) $(MAKEFILE_LIST)
|
||||
$(EXPORTED_FUNCTIONS.fiddle): $(EXPORTED_FUNCTIONS.api.in) \
|
||||
$(MAKEFILE_LIST) $(bin.c-pp)
|
||||
@$(call b.mkdir@)
|
||||
@$(call b.c-pp.shcmd,filter,$(EXPORTED_FUNCTIONS.api.in),\
|
||||
@$(call b.c-pp.shcmd,fiddle,$(EXPORTED_FUNCTIONS.api.in),\
|
||||
$@,$(EXPORTED_FUNCTIONS.c-pp.flags) -Dfiddle)
|
||||
@echo $(logtag.@) $(emo.disk)
|
||||
|
||||
|
||||
emcc.flags.fiddle = \
|
||||
$(emcc.cflags) $(emcc_opt_full) \
|
||||
--minify 0 \
|
||||
@@ -1027,21 +1035,23 @@ emcc.flags.fiddle = \
|
||||
-USQLITE_WASM_BARE_BONES \
|
||||
-DSQLITE_SHELL_FIDDLE
|
||||
|
||||
clean: clean-fiddle
|
||||
clean-fiddle:
|
||||
rm -f $(dir.fiddle)/fiddle-module.js \
|
||||
$(dir.fiddle)/*.wasm \
|
||||
$(dir.fiddle)/sqlite3-opfs-*.js \
|
||||
$(dir.fiddle)/*.gz \
|
||||
$(EXPORTED_FUNCTIONS.fiddle)
|
||||
rm -fr $(dir.fiddle-debug)
|
||||
|
||||
emcc.flags.fiddle.debug = $(emcc.flags.fiddle) \
|
||||
-DSQLITE_DEBUG \
|
||||
-DSQLITE_ENABLE_SELECTTRACE \
|
||||
-DSQLITE_ENABLE_WHERETRACE
|
||||
|
||||
fiddle.c.in = $(dir.top)/shell.c $(sqlite3-wasm.c)
|
||||
clean: clean-fiddle
|
||||
clean-fiddle:
|
||||
rm -f $(dir.fiddle)/fiddle-module.js \
|
||||
$(dir.fiddle)/*.wasm \
|
||||
$(dir.fiddle)/sqlite3-opfs-*.js \
|
||||
$(dir.fiddle)/*.gz \
|
||||
$(dir.fiddle)/index.html \
|
||||
$(EXPORTED_FUNCTIONS.fiddle)
|
||||
rm -fr $(dir.fiddle-debug)
|
||||
distclean: distclean-fiddle
|
||||
distclean-fiddle:
|
||||
rm -fr $(dir.fiddle)/jqterm
|
||||
|
||||
#
|
||||
# WASMFS build - unsupported and untested. We used WASMFS
|
||||
@@ -1370,6 +1380,54 @@ all: tester1
|
||||
# end tester1
|
||||
#
|
||||
|
||||
#
|
||||
# jquery.terminal support for fiddle:
|
||||
#
|
||||
# If a clone of https://github.com/jcubic/jquery.terminal
|
||||
# is found in $(JQTERM), defaulting to $(HOME)/src/jquery.terminal
|
||||
# then add jquery.terminal support to fiddle.
|
||||
#
|
||||
# To build that package, from its checkout dir:
|
||||
#
|
||||
# npm install
|
||||
# make
|
||||
#
|
||||
c-pp.D.fiddle ?=
|
||||
JQTERM ?= $(HOME)/src/jquery.terminal
|
||||
dir.jqtermExt = $(firstword $(wildcard $(JQTERM)))
|
||||
#$(info dir.jqtermExt=$(dir.jqtermExt))
|
||||
ifeq (0,$(MAKING_CLEAN))
|
||||
ifeq (,$(wildcard $(dir.jqtermExt)/js/jquery.terminal.min.js))
|
||||
$(info $(emo.magic) To add jquery.terminal support to fiddle, set JQTERM=/path/to/its/built/checkout)
|
||||
else
|
||||
$(info $(emo.magic) jquery.terminal found in $(dir.jqtermExt) - adding it to fiddle. Make sure it is built!)
|
||||
|
||||
dir.jqterm = $(dir.fiddle)/jqterm
|
||||
$(dir.fiddle)/jqterm/jquery.terminal.bundle.min.js:
|
||||
@$(call b.mkdir@)
|
||||
cat $(dir.jqtermExt)/js/jquery-1*.min.js \
|
||||
$(dir.jqtermExt)/js/jquery.terminal.min.js > $@
|
||||
|
||||
$(dir.fiddle)/jqterm/jquery.terminal.min.css: $(dir.jqtermExt)/css/jquery.terminal.min.css
|
||||
@$(call b.mkdir@)
|
||||
@$(call b.cp,fiddle,$<,$(dir $@))
|
||||
|
||||
$(dir.fiddle)/index.html: $(dir.fiddle)/jqterm/jquery.terminal.bundle.min.js \
|
||||
$(dir.fiddle)/jqterm/jquery.terminal.min.css
|
||||
c-pp.D.fiddle += -Djqterm
|
||||
endif
|
||||
endif
|
||||
# ^^^ JQTERM/MAKING_CLEAN
|
||||
|
||||
#
|
||||
# Generate fiddle/index.html. Must come after JQTERM is handled.
|
||||
#
|
||||
$(dir.fiddle)/index.html: $(dir.fiddle)/index.c-pp.html
|
||||
$(eval $(call b.c-pp.target,fiddle,\
|
||||
$(dir.fiddle)/index.c-pp.html,$(dir.fiddle)/index.html,$(c-pp.D.fiddle)))
|
||||
$(out.fiddle.wasm): $(dir.fiddle)/index.html
|
||||
|
||||
|
||||
#
|
||||
# Convenience rules to rebuild with various -Ox levels. Much
|
||||
# experimentation shows -O2 to be the clear winner in terms of speed.
|
||||
|
||||
@@ -75,6 +75,7 @@ _sqlite3_limit
|
||||
_sqlite3_malloc
|
||||
_sqlite3_malloc64
|
||||
_sqlite3_msize
|
||||
_sqlite3_next_stmt
|
||||
_sqlite3_open
|
||||
_sqlite3_open_v2
|
||||
_sqlite3_overload_function
|
||||
|
||||
@@ -62,7 +62,7 @@ by concatenating the following files together in their listed order:
|
||||
|
||||
- **`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
|
||||
objects. This is exposed as a bootstrapping function 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
|
||||
@@ -116,10 +116,10 @@ by concatenating the following files together in their listed order:
|
||||
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.c-pp.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.c-pp.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`**
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
This file was preprocessed using:
|
||||
|
||||
//#@policy error
|
||||
@c-pp::ARGV@
|
||||
@c-pp::argv@
|
||||
//#@policy off
|
||||
*/
|
||||
//#if unsupported-build
|
||||
|
||||
@@ -200,6 +200,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
["sqlite3_libversion_number", "int"],
|
||||
["sqlite3_limit", "int", ["sqlite3*", "int", "int"]],
|
||||
["sqlite3_malloc", "*","int"],
|
||||
["sqlite3_next_stmt", "sqlite3_stmt*", ["sqlite3*","sqlite3_stmt*"]],
|
||||
["sqlite3_open", "int", "string", "*"],
|
||||
["sqlite3_open_v2", "int", "string", "*", "int", "string"],
|
||||
/* sqlite3_prepare_v2() and sqlite3_prepare_v3() are handled
|
||||
@@ -975,10 +976,8 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
"entry SQLITE_WASM_DEALLOC (=="+capi.SQLITE_WASM_DEALLOC+").");
|
||||
}
|
||||
const __rcMap = Object.create(null);
|
||||
for(const t of ['resultCodes']){
|
||||
for(const e of Object.entries(wasm.ctype[t])){
|
||||
__rcMap[e[1]] = e[0];
|
||||
}
|
||||
for(const e of Object.entries(wasm.ctype['resultCodes'])){
|
||||
__rcMap[e[1]] = e[0];
|
||||
}
|
||||
/**
|
||||
For the given integer, returns the SQLITE_xxx result code as a
|
||||
@@ -990,8 +989,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
const notThese = Object.assign(Object.create(null),{
|
||||
// For each struct to NOT register, map its name to true:
|
||||
WasmTestStruct: true,
|
||||
/* We unregister the kvvfs VFS from Worker threads below. */
|
||||
sqlite3_kvvfs_methods: !util.isUIThread(),
|
||||
/* sqlite3_index_info and friends require int64: */
|
||||
sqlite3_index_info: !wasm.bigIntEnabled,
|
||||
sqlite3_index_constraint: !wasm.bigIntEnabled,
|
||||
@@ -1785,106 +1782,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
};
|
||||
}/* auto-extension */
|
||||
|
||||
const pKvvfs = capi.sqlite3_vfs_find("kvvfs");
|
||||
if( pKvvfs ){/* kvvfs-specific glue */
|
||||
if(util.isUIThread()){
|
||||
const kvvfsMethods = new capi.sqlite3_kvvfs_methods(
|
||||
wasm.exports.sqlite3__wasm_kvvfs_methods()
|
||||
);
|
||||
delete capi.sqlite3_kvvfs_methods;
|
||||
|
||||
const kvvfsMakeKey = wasm.exports.sqlite3__wasm_kvvfsMakeKeyOnPstack,
|
||||
pstack = wasm.pstack;
|
||||
|
||||
const kvvfsStorage = (zClass)=>
|
||||
((115/*=='s'*/===wasm.peek(zClass))
|
||||
? sessionStorage : localStorage);
|
||||
|
||||
/**
|
||||
Implementations for members of the object referred to by
|
||||
sqlite3__wasm_kvvfs_methods(). We swap out the native
|
||||
implementations with these, which use localStorage or
|
||||
sessionStorage for their backing store.
|
||||
*/
|
||||
const kvvfsImpls = {
|
||||
xRead: (zClass, zKey, zBuf, nBuf)=>{
|
||||
const stack = pstack.pointer,
|
||||
astack = wasm.scopedAllocPush();
|
||||
try {
|
||||
const zXKey = kvvfsMakeKey(zClass,zKey);
|
||||
if(!zXKey) return -3/*OOM*/;
|
||||
const jKey = wasm.cstrToJs(zXKey);
|
||||
const jV = kvvfsStorage(zClass).getItem(jKey);
|
||||
if(!jV) return -1;
|
||||
const nV = jV.length /* We are relying 100% on v being
|
||||
ASCII so that jV.length is equal
|
||||
to the C-string's byte length. */;
|
||||
if(nBuf<=0) return nV;
|
||||
else if(1===nBuf){
|
||||
wasm.poke(zBuf, 0);
|
||||
return nV;
|
||||
}
|
||||
const zV = wasm.scopedAllocCString(jV);
|
||||
if(nBuf > nV + 1) nBuf = nV + 1;
|
||||
wasm.heap8u().copyWithin(
|
||||
Number(zBuf), Number(zV), wasm.ptr.addn(zV, nBuf,- 1)
|
||||
);
|
||||
wasm.poke(wasm.ptr.add(zBuf, nBuf, -1), 0);
|
||||
return nBuf - 1;
|
||||
}catch(e){
|
||||
sqlite3.config.error("kvstorageRead()",e);
|
||||
return -2;
|
||||
}finally{
|
||||
pstack.restore(stack);
|
||||
wasm.scopedAllocPop(astack);
|
||||
}
|
||||
},
|
||||
xWrite: (zClass, zKey, zData)=>{
|
||||
const stack = pstack.pointer;
|
||||
try {
|
||||
const zXKey = kvvfsMakeKey(zClass,zKey);
|
||||
if(!zXKey) return 1/*OOM*/;
|
||||
const jKey = wasm.cstrToJs(zXKey);
|
||||
kvvfsStorage(zClass).setItem(jKey, wasm.cstrToJs(zData));
|
||||
return 0;
|
||||
}catch(e){
|
||||
sqlite3.config.error("kvstorageWrite()",e);
|
||||
return capi.SQLITE_IOERR;
|
||||
}finally{
|
||||
pstack.restore(stack);
|
||||
}
|
||||
},
|
||||
xDelete: (zClass, zKey)=>{
|
||||
const stack = pstack.pointer;
|
||||
try {
|
||||
const zXKey = kvvfsMakeKey(zClass,zKey);
|
||||
if(!zXKey) return 1/*OOM*/;
|
||||
kvvfsStorage(zClass).removeItem(wasm.cstrToJs(zXKey));
|
||||
return 0;
|
||||
}catch(e){
|
||||
sqlite3.config.error("kvstorageDelete()",e);
|
||||
return capi.SQLITE_IOERR;
|
||||
}finally{
|
||||
pstack.restore(stack);
|
||||
}
|
||||
}
|
||||
}/*kvvfsImpls*/;
|
||||
for(const k of Object.keys(kvvfsImpls)){
|
||||
kvvfsMethods[kvvfsMethods.memberKey(k)] =
|
||||
wasm.installFunction(
|
||||
kvvfsMethods.memberSignature(k),
|
||||
kvvfsImpls[k]
|
||||
);
|
||||
}
|
||||
}else{
|
||||
/* Worker thread: unregister kvvfs to avoid it being used
|
||||
for anything other than local/sessionStorage. It "can"
|
||||
be used that way but it's not really intended to be. */
|
||||
capi.sqlite3_vfs_unregister(pKvvfs);
|
||||
delete capi.sqlite3_kvvfs_methods;
|
||||
}
|
||||
}/*pKvvfs*/
|
||||
|
||||
/* Warn if client-level code makes use of FuncPtrAdapter. */
|
||||
wasm.xWrap.FuncPtrAdapter.warnOnUse = true;
|
||||
|
||||
|
||||
@@ -88,7 +88,8 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
wasm.installFunction('i(ippp)', function(t,c,p,x){
|
||||
if(capi.SQLITE_TRACE_STMT===t){
|
||||
// x == SQL, p == sqlite3_stmt*
|
||||
console.log("SQL TRACE #"+(++this.counter)+' via sqlite3@'+c+':',
|
||||
console.log("SQL TRACE #"+(++this.counter),
|
||||
'via sqlite3@'+c+'['+capi.sqlite3_db_filename(c,null)+']',
|
||||
wasm.cstrToJs(x));
|
||||
}
|
||||
}.bind({counter: 0}));
|
||||
@@ -222,32 +223,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
It also accepts those as the first 3 arguments.
|
||||
*/
|
||||
const dbCtorHelper = function ctor(...args){
|
||||
if(!ctor._name2vfs){
|
||||
/**
|
||||
Map special filenames which we handle here (instead of in C)
|
||||
to some helpful metadata...
|
||||
|
||||
As of 2022-09-20, the C API supports the names :localStorage:
|
||||
and :sessionStorage: for kvvfs. However, C code cannot
|
||||
determine (without embedded JS code, e.g. via Emscripten's
|
||||
EM_JS()) whether the kvvfs is legal in the current browser
|
||||
context (namely the main UI thread). In order to help client
|
||||
code fail early on, instead of it being delayed until they
|
||||
try to read or write a kvvfs-backed db, we'll check for those
|
||||
names here and throw if they're not legal in the current
|
||||
context.
|
||||
*/
|
||||
ctor._name2vfs = Object.create(null);
|
||||
const isWorkerThread = ('function'===typeof importScripts/*===running in worker thread*/)
|
||||
? (n)=>toss3("The VFS for",n,"is only available in the main window thread.")
|
||||
: false;
|
||||
ctor._name2vfs[':localStorage:'] = {
|
||||
vfs: 'kvvfs', filename: isWorkerThread || (()=>'local')
|
||||
};
|
||||
ctor._name2vfs[':sessionStorage:'] = {
|
||||
vfs: 'kvvfs', filename: isWorkerThread || (()=>'session')
|
||||
};
|
||||
}
|
||||
const opt = ctor.normalizeArgs(...args);
|
||||
//sqlite3.config.debug("DB ctor",opt);
|
||||
let pDb;
|
||||
@@ -269,12 +244,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
sqlite3.config.error("Invalid DB ctor args",opt,arguments);
|
||||
toss3("Invalid arguments for DB constructor:", arguments, "opts:", opt);
|
||||
}
|
||||
let fnJs = wasm.isPtr(fn) ? wasm.cstrToJs(fn) : fn;
|
||||
const vfsCheck = ctor._name2vfs[fnJs];
|
||||
if(vfsCheck){
|
||||
vfsName = vfsCheck.vfs;
|
||||
fn = fnJs = vfsCheck.filename(fnJs);
|
||||
}
|
||||
let oflags = 0;
|
||||
if( flagsStr.indexOf('c')>=0 ){
|
||||
oflags |= capi.SQLITE_OPEN_CREATE | capi.SQLITE_OPEN_READWRITE;
|
||||
@@ -299,7 +268,15 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
}finally{
|
||||
wasm.pstack.restore(stack);
|
||||
}
|
||||
this.filename = fnJs;
|
||||
this.filename =
|
||||
/* A poor design choice we have to keep: this.filename may be
|
||||
in the form "file:....?....". It really should have been
|
||||
sqlite3_db_filename(pDb) but that discrepancy went too long
|
||||
unnoticed to be able to change without risk of
|
||||
breakage. DB.dbFilename() can be used to fetch _just_ the
|
||||
name part.
|
||||
*/ wasm.isPtr(fn) ? wasm.cstrToJs(fn) : fn;
|
||||
|
||||
}
|
||||
__ptrMap.set(this, pDb);
|
||||
__stmtMap.set(this, Object.create(null));
|
||||
@@ -390,12 +367,12 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
|
||||
The given db filename must be resolvable using whatever
|
||||
filesystem layer (virtual or otherwise) is set up for the default
|
||||
sqlite3 VFS.
|
||||
sqlite3 VFS or a VFS which can resolve it must be specified.
|
||||
|
||||
Note that the special sqlite3 db names ":memory:" and ""
|
||||
(temporary db) have their normal special meanings here and need
|
||||
not resolve to real filenames, but "" uses an on-storage
|
||||
temporary database and requires that the VFS support that.
|
||||
The special sqlite3 db names ":memory:" and "" (temporary db)
|
||||
have their normal special meanings here and need not resolve to
|
||||
real filenames, but "" uses an on-storage temporary database and
|
||||
requires that the VFS support that.
|
||||
|
||||
The second argument specifies the open/create mode for the
|
||||
database. It must be string containing a sequence of letters (in
|
||||
@@ -2295,55 +2272,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
Stmt
|
||||
}/*oo1 object*/;
|
||||
|
||||
if(util.isUIThread()){
|
||||
/**
|
||||
Functionally equivalent to DB(storageName,'c','kvvfs') except
|
||||
that it throws if the given storage name is not one of 'local'
|
||||
or 'session'.
|
||||
|
||||
As of version 3.46, the argument may optionally be an options
|
||||
object in the form:
|
||||
|
||||
{
|
||||
filename: 'session'|'local',
|
||||
... etc. (all options supported by the DB ctor)
|
||||
}
|
||||
|
||||
noting that the 'vfs' option supported by main DB
|
||||
constructor is ignored here: the vfs is always 'kvvfs'.
|
||||
*/
|
||||
sqlite3.oo1.JsStorageDb = function(storageName='session'){
|
||||
const opt = dbCtorHelper.normalizeArgs(...arguments);
|
||||
storageName = opt.filename;
|
||||
if('session'!==storageName && 'local'!==storageName){
|
||||
toss3("JsStorageDb db name must be one of 'session' or 'local'.");
|
||||
}
|
||||
opt.vfs = 'kvvfs';
|
||||
dbCtorHelper.call(this, opt);
|
||||
};
|
||||
const jdb = sqlite3.oo1.JsStorageDb;
|
||||
jdb.prototype = Object.create(DB.prototype);
|
||||
/** Equivalent to sqlite3_js_kvvfs_clear(). */
|
||||
jdb.clearStorage = capi.sqlite3_js_kvvfs_clear;
|
||||
/**
|
||||
Clears this database instance's storage or throws if this
|
||||
instance has been closed. Returns the number of
|
||||
database blocks which were cleaned up.
|
||||
*/
|
||||
jdb.prototype.clearStorage = function(){
|
||||
return jdb.clearStorage(affirmDbOpen(this).filename);
|
||||
};
|
||||
/** Equivalent to sqlite3_js_kvvfs_size(). */
|
||||
jdb.storageSize = capi.sqlite3_js_kvvfs_size;
|
||||
/**
|
||||
Returns the _approximate_ number of bytes this database takes
|
||||
up in its storage or throws if this instance has been closed.
|
||||
*/
|
||||
jdb.prototype.storageSize = function(){
|
||||
return jdb.storageSize(affirmDbOpen(this).filename);
|
||||
};
|
||||
}/*main-window-only bits*/
|
||||
|
||||
});
|
||||
//#else
|
||||
/* Built with the omit-oo1 flag. */
|
||||
|
||||
@@ -1604,86 +1604,6 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(
|
||||
return x===v ? undefined : x;
|
||||
}
|
||||
|
||||
if( util.isUIThread() ){
|
||||
/* Features specific to the main window thread... */
|
||||
|
||||
/**
|
||||
Internal helper for sqlite3_js_kvvfs_clear() and friends.
|
||||
Its argument should be one of ('local','session',"").
|
||||
*/
|
||||
const __kvvfsInfo = function(which){
|
||||
const rc = Object.create(null);
|
||||
rc.prefix = 'kvvfs-'+which;
|
||||
rc.stores = [];
|
||||
if('session'===which || ""===which) rc.stores.push(globalThis.sessionStorage);
|
||||
if('local'===which || ""===which) rc.stores.push(globalThis.localStorage);
|
||||
return rc;
|
||||
};
|
||||
|
||||
/**
|
||||
Clears all storage used by the kvvfs DB backend, deleting any
|
||||
DB(s) stored there. Its argument must be either 'session',
|
||||
'local', or "". In the first two cases, only sessionStorage
|
||||
resp. localStorage is cleared. If it's an empty string (the
|
||||
default) then both are cleared. Only storage keys which match
|
||||
the pattern used by kvvfs are cleared: any other client-side
|
||||
data are retained.
|
||||
|
||||
This function is only available in the main window thread.
|
||||
|
||||
Returns the number of entries cleared.
|
||||
*/
|
||||
capi.sqlite3_js_kvvfs_clear = function(which=""){
|
||||
let rc = 0;
|
||||
const kvinfo = __kvvfsInfo(which);
|
||||
kvinfo.stores.forEach((s)=>{
|
||||
const toRm = [] /* keys to remove */;
|
||||
let i;
|
||||
for( i = 0; i < s.length; ++i ){
|
||||
const k = s.key(i);
|
||||
if(k.startsWith(kvinfo.prefix)) toRm.push(k);
|
||||
}
|
||||
toRm.forEach((kk)=>s.removeItem(kk));
|
||||
rc += toRm.length;
|
||||
});
|
||||
return rc;
|
||||
};
|
||||
|
||||
/**
|
||||
This routine guesses the approximate amount of
|
||||
window.localStorage and/or window.sessionStorage in use by the
|
||||
kvvfs database backend. Its argument must be one of
|
||||
('session', 'local', ""). In the first two cases, only
|
||||
sessionStorage resp. localStorage is counted. If it's an empty
|
||||
string (the default) then both are counted. Only storage keys
|
||||
which match the pattern used by kvvfs are counted. The returned
|
||||
value is the "length" value of every matching key and value,
|
||||
noting that JavaScript stores each character in 2 bytes.
|
||||
|
||||
Note that the returned size is not authoritative from the
|
||||
perspective of how much data can fit into localStorage and
|
||||
sessionStorage, as the precise algorithms for determining
|
||||
those limits are unspecified and may include per-entry
|
||||
overhead invisible to clients.
|
||||
*/
|
||||
capi.sqlite3_js_kvvfs_size = function(which=""){
|
||||
let sz = 0;
|
||||
const kvinfo = __kvvfsInfo(which);
|
||||
kvinfo.stores.forEach((s)=>{
|
||||
let i;
|
||||
for(i = 0; i < s.length; ++i){
|
||||
const k = s.key(i);
|
||||
if(k.startsWith(kvinfo.prefix)){
|
||||
sz += k.length;
|
||||
sz += s.getItem(k).length;
|
||||
}
|
||||
}
|
||||
});
|
||||
return sz * 2 /* because JS uses 2-byte char encoding */;
|
||||
};
|
||||
|
||||
}/* main-window-only bits */
|
||||
|
||||
/**
|
||||
Wraps all known variants of the C-side variadic
|
||||
sqlite3_db_config().
|
||||
@@ -2170,9 +2090,11 @@ globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(
|
||||
delete globalThis.sqlite3ApiBootstrap;
|
||||
delete sqlite3ApiBootstrap.defaultConfig;
|
||||
return sqlite3.asyncPostInit().then((s)=>{
|
||||
sqlite3InitScriptInfo.debugModule(
|
||||
"sqlite3.asyncPostInit() complete", sqlite3
|
||||
);
|
||||
if( 'undefined'!==typeof sqlite3InitScriptInfo/* from post-js-header.js */ ){
|
||||
sqlite3InitScriptInfo.debugModule(
|
||||
"sqlite3.asyncPostInit() complete", s
|
||||
);
|
||||
}
|
||||
delete s.asyncPostInit;
|
||||
delete s.scriptInfo;
|
||||
delete s.emscripten;
|
||||
|
||||
@@ -0,0 +1,333 @@
|
||||
//#if not omit-kvvfs
|
||||
/*
|
||||
2025-11-21
|
||||
|
||||
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 houses the "kvvfs" pieces of the JS API.
|
||||
|
||||
Main project home page: https://sqlite.org
|
||||
|
||||
Documentation home page: https://sqlite.org/wasm
|
||||
*/
|
||||
globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
'use strict';
|
||||
/* We unregister the kvvfs VFS from Worker threads later on. */
|
||||
const util = sqlite3.util,
|
||||
capi = sqlite3.capi,
|
||||
wasm = sqlite3.wasm,
|
||||
sqlite3_kvvfs_methods = capi.sqlite3_kvvfs_methods,
|
||||
pKvvfs = sqlite3.capi.sqlite3_vfs_find("kvvfs");
|
||||
delete capi.sqlite3_kvvfs_methods /* this is JS plumbing, not part
|
||||
of the public API */;
|
||||
if( !pKvvfs ) return /* built without kvvfs */;
|
||||
|
||||
if( !util.isUIThread() ){
|
||||
/* One test currently relies on this VFS not being visible
|
||||
in Workers. If we add generic object storage, we can
|
||||
retain this VFS in Workers. */
|
||||
capi.sqlite3_vfs_unregister(pKvvfs);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
Internal helper for sqlite3_js_kvvfs_clear() and friends.
|
||||
Its argument should be one of ('local','session',"").
|
||||
*/
|
||||
const __kvfsWhich = function(which){
|
||||
const rc = Object.create(null);
|
||||
rc.prefix = 'kvvfs-'+which;
|
||||
rc.stores = [];
|
||||
if('session'===which || ""===which) rc.stores.push(globalThis.sessionStorage);
|
||||
if('local'===which || ""===which) rc.stores.push(globalThis.localStorage);
|
||||
return rc;
|
||||
};
|
||||
|
||||
/**
|
||||
Clears all storage used by the kvvfs DB backend, deleting any
|
||||
DB(s) stored there. Its argument must be either 'session',
|
||||
'local', or "". In the first two cases, only sessionStorage
|
||||
resp. localStorage is cleared. If it's an empty string (the
|
||||
default) then both are cleared. Only storage keys which match
|
||||
the pattern used by kvvfs are cleared: any other client-side
|
||||
data are retained.
|
||||
|
||||
This function is only available in the main window thread.
|
||||
|
||||
Returns the number of entries cleared.
|
||||
*/
|
||||
capi.sqlite3_js_kvvfs_clear = function(which=""){
|
||||
let rc = 0;
|
||||
const kvWhich = __kvfsWhich(which);
|
||||
kvWhich.stores.forEach((s)=>{
|
||||
const toRm = [] /* keys to remove */;
|
||||
let i;
|
||||
for( i = 0; i < s.length; ++i ){
|
||||
const k = s.key(i);
|
||||
if(k.startsWith(kvWhich.prefix)) toRm.push(k);
|
||||
}
|
||||
toRm.forEach((kk)=>s.removeItem(kk));
|
||||
rc += toRm.length;
|
||||
});
|
||||
return rc;
|
||||
};
|
||||
|
||||
/**
|
||||
This routine guesses the approximate amount of
|
||||
window.localStorage and/or window.sessionStorage in use by the
|
||||
kvvfs database backend. Its argument must be one of ('session',
|
||||
'local', ""). In the first two cases, only sessionStorage
|
||||
resp. localStorage is counted. If it's an empty string (the
|
||||
default) then both are counted. Only storage keys which match
|
||||
the pattern used by kvvfs are counted. The returned value is
|
||||
twice the "length" value of every matching key and value,
|
||||
noting that JavaScript stores each character in 2 bytes.
|
||||
|
||||
The returned size is not authoritative from the perspective of
|
||||
how much data can fit into localStorage and sessionStorage, as
|
||||
the precise algorithms for determining those limits are
|
||||
unspecified and may include per-entry overhead invisible to
|
||||
clients.
|
||||
*/
|
||||
capi.sqlite3_js_kvvfs_size = function(which=""){
|
||||
let sz = 0;
|
||||
const kvWhich = __kvfsWhich(which);
|
||||
kvWhich.stores.forEach((s)=>{
|
||||
let i;
|
||||
for(i = 0; i < s.length; ++i){
|
||||
const k = s.key(i);
|
||||
if(k.startsWith(kvWhich.prefix)){
|
||||
sz += k.length;
|
||||
sz += s.getItem(k).length;
|
||||
}
|
||||
}
|
||||
});
|
||||
return sz * 2 /* because JS uses 2-byte char encoding */;
|
||||
};
|
||||
|
||||
const kvvfsMakeKey = wasm.exports.sqlite3__wasm_kvvfsMakeKeyOnPstack;
|
||||
const pstack = wasm.pstack;
|
||||
const kvvfsStorage = (zClass)=>((115/*=='s'*/===wasm.peek(zClass))
|
||||
? sessionStorage : localStorage);
|
||||
|
||||
{ /* Override native sqlite3_kvvfs_methods */
|
||||
const kvvfsMethods = new sqlite3_kvvfs_methods(
|
||||
/* Wraps the static sqlite3_api_methods singleton */
|
||||
wasm.exports.sqlite3__wasm_kvvfs_methods()
|
||||
);
|
||||
try{
|
||||
/**
|
||||
Implementations for members of the object referred to by
|
||||
sqlite3__wasm_kvvfs_methods(). We swap out the native
|
||||
implementations with these, which use JS Storage for their
|
||||
backing store.
|
||||
|
||||
The interface docs for these methods are in
|
||||
src/os_kv.c:kvstorageRead(), kvstorageWrite(), and
|
||||
kvstorageDelete().
|
||||
*/
|
||||
for(const e of Object.entries({
|
||||
xRead: (zClass, zKey, zBuf, nBuf)=>{
|
||||
const stack = pstack.pointer,
|
||||
astack = wasm.scopedAllocPush();
|
||||
try {
|
||||
const zXKey = kvvfsMakeKey(zClass,zKey);
|
||||
if(!zXKey) return -3/*OOM*/;
|
||||
const jKey = wasm.cstrToJs(zXKey);
|
||||
const jV = kvvfsStorage(zClass).getItem(jKey);
|
||||
if(!jV) return -1;
|
||||
const nV = jV.length /* We are relying 100% on v being
|
||||
ASCII so that jV.length is equal
|
||||
to the C-string's byte length. */;
|
||||
if(nBuf<=0) return nV;
|
||||
else if(1===nBuf){
|
||||
wasm.poke(zBuf, 0);
|
||||
return nV;
|
||||
}
|
||||
const zV = wasm.scopedAllocCString(jV);
|
||||
if(nBuf > nV + 1) nBuf = nV + 1;
|
||||
wasm.heap8u().copyWithin(
|
||||
Number(zBuf), Number(zV), wasm.ptr.addn(zV, nBuf,- 1)
|
||||
);
|
||||
wasm.poke(wasm.ptr.add(zBuf, nBuf, -1), 0);
|
||||
return nBuf - 1;
|
||||
}catch(e){
|
||||
sqlite3.config.error("kvstorageRead()",e);
|
||||
return -2;
|
||||
}finally{
|
||||
pstack.restore(stack);
|
||||
wasm.scopedAllocPop(astack);
|
||||
}
|
||||
},
|
||||
xWrite: (zClass, zKey, zData)=>{
|
||||
const stack = pstack.pointer;
|
||||
try {
|
||||
const zXKey = kvvfsMakeKey(zClass,zKey);
|
||||
if(!zXKey) return 1/*OOM*/;
|
||||
const jKey = wasm.cstrToJs(zXKey);
|
||||
kvvfsStorage(zClass).setItem(jKey, wasm.cstrToJs(zData));
|
||||
return 0;
|
||||
}catch(e){
|
||||
sqlite3.config.error("kvstorageWrite()",e);
|
||||
return capi.SQLITE_IOERR;
|
||||
}finally{
|
||||
pstack.restore(stack);
|
||||
}
|
||||
},
|
||||
xDelete: (zClass, zKey)=>{
|
||||
const stack = pstack.pointer;
|
||||
try {
|
||||
const zXKey = kvvfsMakeKey(zClass,zKey);
|
||||
if(!zXKey) return 1/*OOM*/;
|
||||
kvvfsStorage(zClass).removeItem(wasm.cstrToJs(zXKey));
|
||||
return 0;
|
||||
}catch(e){
|
||||
sqlite3.config.error("kvstorageDelete()",e);
|
||||
return capi.SQLITE_IOERR;
|
||||
}finally{
|
||||
pstack.restore(stack);
|
||||
}
|
||||
}
|
||||
})){
|
||||
kvvfsMethods[kvvfsMethods.memberKey(e[0])] =
|
||||
wasm.installFunction(kvvfsMethods.memberSignature(e[0]), e[1]);
|
||||
}
|
||||
}finally{
|
||||
kvvfsMethods.dispose();
|
||||
}
|
||||
}/* Override native sqlite3_api_methods */
|
||||
|
||||
/**
|
||||
After initial refactoring to support the use of arbitrary Storage
|
||||
objects (the interface from which localStorage and sessionStorage
|
||||
dervie), we will apparently need to override some of the
|
||||
associated sqlite3_vfs and sqlite3_io_methods members.
|
||||
|
||||
We can call back into the native impls when needed, but we need
|
||||
to override certain operations here to bypass its strict
|
||||
db-naming rules (which, funnily enough, are in place because
|
||||
they're relevant (only) for this browser-side
|
||||
implementation). Apropos: the port to generic objects would also
|
||||
make non-persistent kvvfs available in Worker threads and
|
||||
non-browser builds.
|
||||
*/
|
||||
const eventualTodo = 1 || {
|
||||
vfsMethods:{
|
||||
/**
|
||||
*/
|
||||
xOpen: function(pProtoVfs,zName,pProtoFile,flags,pOutFlags){},
|
||||
xDelete: function(pVfs, zName, iSyncFlag){},
|
||||
xAccess:function(pProtoVfs, zPath, flags, pResOut){},
|
||||
xFullPathname: function(pVfs, zPath, nOut, zOut){},
|
||||
xDlOpen: function(pVfs, zFilename){},
|
||||
xSleep: function(pVfs,usec){},
|
||||
xCurrentTime: function(pVfs,pOutDbl){},
|
||||
xCurrentTimeInt64: function(pVfs,pOutI64){},
|
||||
xRandomness: function(pVfs, nOut, pOut){
|
||||
const heap = wasm.heap8u();
|
||||
let i = 0;
|
||||
const npOut = Number(pOut);
|
||||
for(; i < nOut; ++i) heap[npOut + i] = (Math.random()*255000) & 0xFF;
|
||||
return i;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
kvvfs has separate impls for some of the I/O methods,
|
||||
depending on whether it's a db or journal file.
|
||||
*/
|
||||
ioMethods:{
|
||||
db:{
|
||||
xClose: function(pFile){},
|
||||
xRead: function(pFile,pTgt,n,iOff64){},
|
||||
xWrite: function(pFile,pSrc,n,iOff64){},
|
||||
xTruncate: function(pFile,i64){},
|
||||
xSync: function(pFile,flags){},
|
||||
xFileControl: function(pFile, opId, pArg){},
|
||||
xFileSize: function(pFile,pi64Out){},
|
||||
xLock: function(pFile,iLock){},
|
||||
xUnlock: function(pFile,iLock){},
|
||||
xCheckReservedLock: function(pFile,piOut){},
|
||||
xFileControl: function(pFile,iOp,pArg){},
|
||||
xSectorSize: function(pFile){},
|
||||
xDeviceCharacteristics: function(pFile){}
|
||||
},
|
||||
jrnl:{
|
||||
xClose: todoIOMethodsDb.xClose,
|
||||
xRead: function(pFile,pTgt,n,iOff64){},
|
||||
xWrite: function(pFile,pSrc,n,iOff64){},
|
||||
xTruncate: function(pFile,i64){},
|
||||
xSync: function(pFile,flags){},
|
||||
xFileControl: function(pFile, opId, pArg){},
|
||||
xFileSize: function(pFile,pi64Out){},
|
||||
xLock: todoIOMethodsDb.xLock,
|
||||
xUnlock: todoIOMethodsDb.xUnlock,
|
||||
xCheckReservedLock: todoIOMethodsDb.xCheckReservedLock,
|
||||
xFileControl: function(pFile,iOp,pArg){},
|
||||
xSectorSize: todoIOMethodsDb.xSectorSize,
|
||||
xDeviceCharacteristics: todoIOMethodsDb.xDeviceCharacteristics
|
||||
}
|
||||
}
|
||||
}/*eventualTodo*/;
|
||||
|
||||
if(sqlite3?.oo1?.DB){
|
||||
/**
|
||||
Functionally equivalent to DB(storageName,'c','kvvfs') except
|
||||
that it throws if the given storage name is not one of 'local'
|
||||
or 'session'.
|
||||
|
||||
As of version 3.46, the argument may optionally be an options
|
||||
object in the form:
|
||||
|
||||
{
|
||||
filename: 'session'|'local',
|
||||
... etc. (all options supported by the DB ctor)
|
||||
}
|
||||
|
||||
noting that the 'vfs' option supported by main DB
|
||||
constructor is ignored here: the vfs is always 'kvvfs'.
|
||||
*/
|
||||
sqlite3.oo1.JsStorageDb = function(
|
||||
storageName = sqlite3.oo1.JsStorageDb.defaultStorageName
|
||||
){
|
||||
const opt = sqlite3.oo1.DB.dbCtorHelper.normalizeArgs(...arguments);
|
||||
storageName = opt.filename;
|
||||
if('session'!==storageName && 'local'!==storageName){
|
||||
toss3("JsStorageDb db name must be one of 'session' or 'local'.");
|
||||
}
|
||||
opt.vfs = 'kvvfs';
|
||||
sqlite3.oo1.DB.dbCtorHelper.call(this, opt);
|
||||
};
|
||||
sqlite3.oo1.JsStorageDb.defaultStorageName = 'session';
|
||||
const jdb = sqlite3.oo1.JsStorageDb;
|
||||
jdb.prototype = Object.create(sqlite3.oo1.DB.prototype);
|
||||
/** Equivalent to sqlite3_js_kvvfs_clear(). */
|
||||
jdb.clearStorage = capi.sqlite3_js_kvvfs_clear;
|
||||
/**
|
||||
Clears this database instance's storage or throws if this
|
||||
instance has been closed. Returns the number of
|
||||
database blocks which were cleaned up.
|
||||
*/
|
||||
jdb.prototype.clearStorage = function(){
|
||||
return jdb.clearStorage(this.affirmDbOpen().filename);
|
||||
};
|
||||
/** Equivalent to sqlite3_js_kvvfs_size(). */
|
||||
jdb.storageSize = capi.sqlite3_js_kvvfs_size;
|
||||
/**
|
||||
Returns the _approximate_ number of bytes this database takes
|
||||
up in its storage or throws if this instance has been closed.
|
||||
*/
|
||||
jdb.prototype.storageSize = function(){
|
||||
return jdb.storageSize(this.affirmDbOpen().filename);
|
||||
};
|
||||
}/*sqlite3.oo1.JsStorageDb*/
|
||||
|
||||
})/*globalThis.sqlite3ApiBootstrap.initializers*/;
|
||||
//#endif not omit-kvvfs
|
||||
@@ -358,7 +358,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
try{
|
||||
const [cMsg, n] = wasm.scopedAllocCString(e.message, true);
|
||||
wasm.cstrncpy(pOut, cMsg, nOut);
|
||||
if(n > nOut) wasm.poke8(pOut + nOut - 1, 0);
|
||||
if(n > nOut) wasm.poke8(wasm.ptr.add(pOut,nOut,-1), 0);
|
||||
}catch(e){
|
||||
return capi.SQLITE_NOMEM;
|
||||
}finally{
|
||||
|
||||
@@ -589,7 +589,7 @@ const installOpfsVfs = function callee(options){
|
||||
|
||||
/**
|
||||
Returns an array of the deserialized state stored by the most
|
||||
recent serialize() operation (from from this thread or the
|
||||
recent serialize() operation (from this thread or the
|
||||
counterpart thread), or null if the serialization buffer is
|
||||
empty. If passed a truthy argument, the serialization buffer
|
||||
is cleared after deserialization.
|
||||
@@ -924,7 +924,7 @@ const installOpfsVfs = function callee(options){
|
||||
fh.filename = zName;
|
||||
fh.sab = new SharedArrayBuffer(state.fileBufferSize);
|
||||
fh.flags = flags;
|
||||
fh.readOnly = !(sqlite3.SQLITE_OPEN_CREATE & flags)
|
||||
fh.readOnly = !(capi.SQLITE_OPEN_CREATE & flags)
|
||||
&& !!(flags & capi.SQLITE_OPEN_READONLY);
|
||||
const rc = opRun('xOpen', pFile, zName, flags, opfsFlags);
|
||||
if(!rc){
|
||||
|
||||
@@ -93,6 +93,18 @@
|
||||
#undef SQLITE_ENABLE_API_ARMOR
|
||||
#define SQLITE_ENABLE_API_ARMOR 1
|
||||
|
||||
/**********************************************************************/
|
||||
/* SQLITE_EXPERIMENTAL_PRAGMA_20251114 */
|
||||
/*
|
||||
** See:
|
||||
** https://sqlite.org/src/info/e2b3f1a9480a9be3
|
||||
** https://github.com/rhashimoto/wa-sqlite/discussions/301
|
||||
**
|
||||
** It is enabled here for the sake of VFS experimentors.
|
||||
*/
|
||||
#undef SQLITE_EXPERIMENTAL_PRAGMA_20251114
|
||||
#define SQLITE_EXPERIMENTAL_PRAGMA_20251114
|
||||
|
||||
/**********************************************************************/
|
||||
/* SQLITE_O... */
|
||||
#undef SQLITE_OMIT_DEPRECATED
|
||||
|
||||
@@ -2603,7 +2603,7 @@ static int arg_is_flag( char const *zFlag, char const *zArg,
|
||||
|
||||
static void define_argv(int argc, char const * const * argv){
|
||||
sqlite3_str * const s = sqlite3_str_new(g.db);
|
||||
sqlite3_str_append(s, "c-pp::ARGV=", 11);
|
||||
sqlite3_str_append(s, "c-pp::argv=", 11);
|
||||
for( int i = 0; i < argc; ++i ){
|
||||
if( i ) sqlite3_str_appendchar(s, 1, ' ');
|
||||
sqlite3_str_appendf(s, "%s", argv[i]);
|
||||
|
||||
@@ -16,27 +16,35 @@
|
||||
|
||||
More specifically:
|
||||
|
||||
https://fossil.wanderinghorse.net/r/jaccwabyt/file/common/whwasmutil.js
|
||||
https://fossil.wanderinghorse.net/r/jaccwabyt/dir/wasmutil
|
||||
|
||||
and SQLite:
|
||||
|
||||
https://sqlite.org
|
||||
|
||||
This file is kept in sync between both of those trees.
|
||||
|
||||
This build was generated using:
|
||||
|
||||
./c-pp -o js/whwasmutil.js -@policy=error wasmutil/whwasmutil.c-pp.js
|
||||
|
||||
by libcmpp 2.x 2fc4afc31f6505c27b9c34988973a2bd9b157d559247cdd26868ae75632c3a5e @ 2025-11-16 23:03:27.352 UTC
|
||||
*/
|
||||
/**
|
||||
The primary goal of this function is to replace, where possible,
|
||||
Emscripten-generated glue code with equivalent utility code which
|
||||
can be used in arbitrary WASM environments built with toolchains
|
||||
other than Emscripten. To that end, it populates the given object
|
||||
with various WASM-specific APIs. These APIs work with both 32- and
|
||||
64-bit WASM builds.
|
||||
The primary goal of this function is to provide JS/WASM utility
|
||||
code similar to some of that provided by Emscripten-generated
|
||||
builds, the difference being that this one can be used in arbitrary
|
||||
WASM environments built with toolchains other than Emscripten. To
|
||||
that end, it populates the given object with various WASM-specific
|
||||
APIs. These APIs work with both 32- and 64-bit WASM builds.
|
||||
|
||||
Forewarning: this API explicitly targets only browser environments.
|
||||
If a given non-browser environment has the capabilities needed for
|
||||
a given feature (e.g. TextEncoder), great, but it does not go out
|
||||
of its way to account for them and does not provide compatibility
|
||||
crutches for them.
|
||||
crutches for them. That said: no specific incompatibilities with,
|
||||
e.g., node.js are known (whereas it is known that some folks
|
||||
use this with node.js).
|
||||
|
||||
Intended usage:
|
||||
|
||||
@@ -217,7 +225,9 @@
|
||||
newly-created (or config-provided) target. The current approach
|
||||
seemed better at the time.
|
||||
*/
|
||||
globalThis.WhWasmUtilInstaller = function(target){
|
||||
'use strict';
|
||||
globalThis.WhWasmUtilInstaller =
|
||||
function WhWasmUtilInstaller(target){
|
||||
'use strict';
|
||||
if(undefined===target.bigIntEnabled){
|
||||
target.bigIntEnabled = !!globalThis['BigInt64Array'];
|
||||
@@ -766,6 +776,7 @@ globalThis.WhWasmUtilInstaller = function(target){
|
||||
*/
|
||||
target.uninstallFunction = function(ptr){
|
||||
if(!ptr && __NullPtr!==ptr) return undefined;
|
||||
|
||||
const ft = target.functionTable();
|
||||
cache.freeFuncIndexes.push(ptr);
|
||||
const rc = ft.get(ptr);
|
||||
@@ -2461,7 +2472,8 @@ globalThis.WhWasmUtilInstaller = function(target){
|
||||
- If `wasmUtilTarget.alloc` is not set and
|
||||
`instance.exports.malloc` is, it installs
|
||||
`wasmUtilTarget.alloc()` and `wasmUtilTarget.dealloc()`
|
||||
wrappers for the exports `malloc` and `free` functions.
|
||||
wrappers for the exports' `malloc` and `free` functions
|
||||
if exports.malloc exists.
|
||||
|
||||
It returns a function which, when called, initiates loading of the
|
||||
module and returns a Promise. When that Promise resolves, it calls
|
||||
@@ -2484,7 +2496,9 @@ globalThis.WhWasmUtilInstaller = function(target){
|
||||
Error handling is up to the caller, who may attach a `catch()` call
|
||||
to the promise.
|
||||
*/
|
||||
globalThis.WhWasmUtilInstaller.yawl = function(config){
|
||||
globalThis.WhWasmUtilInstaller
|
||||
.yawl = function yawl(config){
|
||||
'use strict';
|
||||
const wfetch = ()=>fetch(config.uri, {credentials: 'same-origin'});
|
||||
const wui = this;
|
||||
const finalThen = function(arg){
|
||||
@@ -2509,7 +2523,7 @@ globalThis.WhWasmUtilInstaller.yawl = function(config){
|
||||
tgt.alloc = function(n){
|
||||
return exports.malloc(n) || toss("Allocation of",n,"bytes failed.");
|
||||
};
|
||||
tgt.dealloc = function(m){exports.free(m)};
|
||||
tgt.dealloc = function(m){m && exports.free(m)};
|
||||
}
|
||||
wui(tgt);
|
||||
}
|
||||
@@ -2528,4 +2542,6 @@ globalThis.WhWasmUtilInstaller.yawl = function(config){
|
||||
.then(finalThen)
|
||||
;
|
||||
return loadWasm;
|
||||
}.bind(globalThis.WhWasmUtilInstaller)/*yawl()*/;
|
||||
}.bind(
|
||||
globalThis.WhWasmUtilInstaller
|
||||
)/*yawl()*/;
|
||||
@@ -5,20 +5,29 @@
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<title>SQLite3 Fiddle</title>
|
||||
<link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon">
|
||||
//#if jqterm
|
||||
<!--
|
||||
To add a terminal-style view using jquery.terminal[^1],
|
||||
uncomment the following two HTML lines and ensure that these
|
||||
files are on the web server.
|
||||
|
||||
jquery-bundle.min.js is a concatenation of jquery.min.js from
|
||||
jquery.terminal.bundle.min.js is a concatenation of jquery.min.js from
|
||||
[^2] and jquery.terminal.min.js from [^1].
|
||||
jquery.terminal.min.css is from [^1].
|
||||
jquery.terminal.min.css is from [^1]. Alterntely, jquery-VERSION.min.js
|
||||
can be found in jquery.terminal's source tree.
|
||||
|
||||
Fiddle automatically enables support for this if it's installed.
|
||||
|
||||
In the canonical build process, if the JQTERM env var is set
|
||||
to a dir containing a clone of [^1] then this block gets
|
||||
enabled and a copy of [^1] is integrated automatically.
|
||||
|
||||
[^1]: https://github.com/jcubic/jquery.terminal
|
||||
[^2]: https://jquery.com
|
||||
-->
|
||||
<!--script src="jqterm/jqterm-bundle.min.js"></script>
|
||||
<link rel="stylesheet" href="jqterm/jquery.terminal.min.css"-->
|
||||
<script src="jqterm/jquery.terminal.bundle.min.js"></script>
|
||||
<link rel="stylesheet" href="jqterm/jquery.terminal.min.css">
|
||||
//#endif
|
||||
<style>
|
||||
/* The following styles are for app-level use. */
|
||||
:root {
|
||||
+346
-154
@@ -16,9 +16,17 @@
|
||||
Project homes:
|
||||
- https://fossil.wanderinghorse.net/r/jaccwabyt
|
||||
- https://sqlite.org/src/dir/ext/wasm/jaccwabyt
|
||||
|
||||
This build was generated using:
|
||||
|
||||
./c-pp -o js/jaccwabyt.js -@policy=error jaccwabyt/jaccwabyt.c-pp.js
|
||||
|
||||
by libcmpp 2.x 2fc4afc31f6505c27b9c34988973a2bd9b157d559247cdd26868ae75632c3a5e @ 2025-11-16 23:03:27.352 UTC
|
||||
*/
|
||||
'use strict';
|
||||
globalThis.Jaccwabyt = function StructBinderFactory(config){
|
||||
globalThis.Jaccwabyt =
|
||||
function StructBinderFactory(config){
|
||||
'use strict';
|
||||
/* ^^^^ it is recommended that clients move that object into wherever
|
||||
they'd like to have it and delete the globalThis-held copy. This
|
||||
API does not require the global reference - it is simply installed
|
||||
@@ -30,19 +38,32 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
||||
all args with a space between each. */
|
||||
const toss = (...args)=>{throw new Error(args.join(' '))};
|
||||
|
||||
if(!(config.heap instanceof WebAssembly.Memory)
|
||||
&& !(config.heap instanceof Function)){
|
||||
toss("config.heap must be WebAssembly.Memory instance or a function which returns one.");
|
||||
{
|
||||
let h = config.heap;
|
||||
if( h instanceof WebAssembly.Memory ){
|
||||
h = function(){return new Uint8Array(this.buffer)}.bind(h);
|
||||
}else if( !(h instanceof Function) ){
|
||||
//console.warn("The bothersome StructBinderFactory config:",config);
|
||||
toss("config.heap must be WebAssembly.Memory instance or",
|
||||
"a function which returns one.");
|
||||
}
|
||||
config.heap = h;
|
||||
}
|
||||
['alloc','dealloc'].forEach(function(k){
|
||||
(config[k] instanceof Function) ||
|
||||
toss("Config option '"+k+"' must be a function.");
|
||||
});
|
||||
const __heap = config.heap;
|
||||
const SBF = StructBinderFactory;
|
||||
const heap = __heap ? __heap : ()=>new Uint8Array(__heap.buffer),
|
||||
const heap = config.heap,
|
||||
alloc = config.alloc,
|
||||
dealloc = config.dealloc,
|
||||
realloc = (config.realloc || function(){
|
||||
toss("This StructBinderFactory was configured without realloc()");
|
||||
/* We can't know the original memory's size from here unless
|
||||
we internally proxy alloc()/dealloc() to track all
|
||||
pointers (not going to happen), so we can't fall back to
|
||||
doing alloc()/copy/dealloc(). */
|
||||
}),
|
||||
log = config.log || console.debug.bind(console),
|
||||
memberPrefix = (config.memberPrefix || ""),
|
||||
memberSuffix = (config.memberSuffix || ""),
|
||||
@@ -51,19 +72,21 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
||||
bigIntEnabled = config.bigIntEnabled ?? !!BigInt64Array;
|
||||
|
||||
//console.warn("config",config);
|
||||
let ptr = alloc(1);
|
||||
const ptrIR = config.pointerIR
|
||||
|| config.ptrIR/*deprecated*/
|
||||
|| ('bigint'===typeof ptr ? 'i64' : 'i32');
|
||||
/* Undocumented (on purpose) config options: */
|
||||
const ptrSize = config.ptrSize/*deprecated*/
|
||||
|| ('i32'===ptrIR ? 4 : 8);
|
||||
dealloc(ptr);
|
||||
ptr = undefined;
|
||||
let ptr;
|
||||
const ptrSize = config.pointerSize
|
||||
|| config.ptrSize/*deprecated*/
|
||||
|| ('bigint'===typeof (ptr = alloc(1)) ? 8 : 4);
|
||||
const ptrIR = config.pointerIR/*deprecated*/
|
||||
|| config.ptrIR/*deprecated*/
|
||||
|| (4===ptrSize ? 'i32' : 'i64');
|
||||
if( ptr ){
|
||||
dealloc(ptr);
|
||||
ptr = undefined;
|
||||
}
|
||||
//console.warn("ptrIR =",ptrIR,"ptrSize =",ptrSize);
|
||||
|
||||
if(ptrIR!=='i32' && ptrIR!=='i64') toss("Invalid pointer representation:",ptrIR);
|
||||
if(ptrSize!==4 && ptrSize!==8) toss("Invalid pointer size:",ptrSize);
|
||||
if(ptrIR!=='i32' && ptrIR!=='i64') toss("Invalid pointer representation:",ptrIR);
|
||||
|
||||
/** Either BigInt or, if !bigIntEnabled, a function which
|
||||
throws complaining that BigInt is not enabled. */
|
||||
@@ -91,6 +114,10 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
||||
return rc;
|
||||
};
|
||||
|
||||
const __ptrAddSelf = function(...args){
|
||||
return __ptrAdd(this.pointer,...args);
|
||||
};
|
||||
|
||||
if(!SBF.debugFlags){
|
||||
SBF.__makeDebugFlags = function(deriveFrom=null){
|
||||
/* This is disgustingly overengineered. :/ */
|
||||
@@ -120,12 +147,12 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
||||
SBF.debugFlags = SBF.__makeDebugFlags();
|
||||
}/*static init*/
|
||||
|
||||
const isLittleEndian = (function() {
|
||||
const isLittleEndian = true || (function() {
|
||||
const buffer = new ArrayBuffer(2);
|
||||
new DataView(buffer).setInt16(0, 256, true /* littleEndian */);
|
||||
// Int16Array uses the platform's endianness.
|
||||
return new Int16Array(buffer)[0] === 256;
|
||||
})();
|
||||
})() /* WASM is, by definition, Little Endian */;
|
||||
|
||||
/**
|
||||
Some terms used in the internal docs:
|
||||
@@ -146,8 +173,9 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
||||
const isAutoPtrSig = (s)=>'P'===s /*EXPERIMENTAL*/;
|
||||
/** Returns p if SIG s is a function SIG, else returns s[0]. */
|
||||
const sigLetter = (s)=>s ? (isFuncSig(s) ? 'p' : s[0]) : undefined;
|
||||
/** Returns the WASM IR form of the Emscripten-conventional letter
|
||||
at SIG s[0]. Throws for an unknown SIG. */
|
||||
|
||||
/** Returns the WASM IR form of the letter at SIG s[0]. Throws for
|
||||
an unknown SIG. */
|
||||
const sigIR = function(s){
|
||||
switch(sigLetter(s)){
|
||||
case 'c': case 'C': return 'i8';
|
||||
@@ -159,8 +187,9 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
||||
}
|
||||
toss("Unhandled signature IR:",s);
|
||||
};
|
||||
/** Returns the WASM sizeof of the Emscripten-conventional letter
|
||||
at SIG s[0]. Throws for an unknown SIG. */
|
||||
|
||||
/** Returns the WASM sizeof of the letter at SIG s[0]. Throws for an
|
||||
unknown SIG. */
|
||||
const sigSize = function(s){
|
||||
switch(sigLetter(s)){
|
||||
case 'c': case 'C': return 1;
|
||||
@@ -175,6 +204,7 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
||||
|
||||
const affirmBigIntArray = BigInt64Array
|
||||
? ()=>true : ()=>toss('BigInt64Array is not available.');
|
||||
|
||||
/** Returns the name of a DataView getter method corresponding
|
||||
to the given SIG. */
|
||||
const sigDVGetter = function(s){
|
||||
@@ -195,6 +225,7 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
||||
}
|
||||
toss("Unhandled DataView getter for signature:",s);
|
||||
};
|
||||
|
||||
/** Returns the name of a DataView setter method corresponding
|
||||
to the given SIG. */
|
||||
const sigDVSetter = function(s){
|
||||
@@ -246,26 +277,44 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
||||
/**
|
||||
In order to completely hide StructBinder-bound struct pointers
|
||||
from JS code, we store them in a scope-local WeakMap which maps
|
||||
the struct-bound objects to their WASM pointers. The pointers are
|
||||
accessible via boundObject.pointer, which is gated behind a
|
||||
property interceptor, but are not exposed anywhere else in the
|
||||
object.
|
||||
the struct-bound objects to an object with their metadata:
|
||||
|
||||
This approach means we cannot proxy arrays, or any type which
|
||||
might be realloced, as that pointer could change out from under
|
||||
us. That's not an issue for nested structs, but it might be for a
|
||||
struct they're embedded in. In the case of nested structs we
|
||||
"could" record their top-most parent object and their offset into
|
||||
that object, instead of storing the pointer itself. We could that
|
||||
by allowing a function instead of a pointer in this map, that
|
||||
function returning the (lazily-calculated) address. Hmm.
|
||||
{
|
||||
.p = the native pointer,
|
||||
.o = self (for an eventual reverse-mapping),
|
||||
.xb = extra bytes allocated for p,
|
||||
.zod = zeroOnDispose,
|
||||
.ownsPointer = true if this object owns p
|
||||
}
|
||||
|
||||
The .p data are accessible via obj.pointer, which is gated behind
|
||||
a property interceptor, but are not exposed anywhere else in the
|
||||
public API.
|
||||
*/
|
||||
const __instancePointerMap = new WeakMap();
|
||||
const getInstanceHandle = function f(obj, create=true){
|
||||
let ii = f.map.get(obj);
|
||||
if( !ii && create ){
|
||||
f.map.set(obj, (ii=f.create(obj)));
|
||||
}
|
||||
return ii;
|
||||
};
|
||||
getInstanceHandle.map = new WeakMap;
|
||||
getInstanceHandle.create = (forObj)=>{
|
||||
return Object.assign(Object.create(null),{
|
||||
o: forObj,
|
||||
p: undefined/*native ptr*/,
|
||||
ownsPointer: false,
|
||||
zod: false/*zeroOnDispose*/,
|
||||
xb: 0/*extraBytes*/
|
||||
});
|
||||
};
|
||||
|
||||
const getInstancePtr = (obj)=>__instancePointerMap.get(obj);
|
||||
|
||||
/** Property name for the pointer-is-external marker. */
|
||||
const xPtrPropName = Symbol('(pointer-is-external)');
|
||||
/**
|
||||
Remove the getInstanceHandle() mapping for obj.
|
||||
*/
|
||||
const rmInstanceHandle = (obj)=>getInstanceHandle.map.delete(obj)
|
||||
/* If/when we have a reverse map of ptr-to-objects, we need to
|
||||
clean that here. */;
|
||||
|
||||
const __isPtr32 = (ptr)=>('number'===typeof ptr && (ptr===(ptr|0)) && ptr>=0);
|
||||
const __isPtr64 = (ptr)=>(
|
||||
@@ -278,85 +327,127 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
||||
*/
|
||||
const __isPtr = (4===ptrSize) ? __isPtr32 : __isPtr64;
|
||||
|
||||
/** Frees the obj.pointer memory and clears the pointer
|
||||
property. */
|
||||
const __isNonNullPtr = (v)=>__isPtr(v) && (v>0);
|
||||
|
||||
/** Frees the obj.pointer memory (a.k.a. m), handles obj.ondispose,
|
||||
and unmaps obj from its native resources. */
|
||||
const __freeStruct = function(ctor, obj, m){
|
||||
if(!m) m = getInstancePtr(obj);
|
||||
if(m) {
|
||||
__instancePointerMap.delete(obj);
|
||||
if(Array.isArray(obj.ondispose)){
|
||||
let x;
|
||||
while((x = obj.ondispose.shift())){
|
||||
try{
|
||||
if(x instanceof Function) x.call(obj);
|
||||
else if(x instanceof StructType) x.dispose();
|
||||
else if(__isPtr(x)) dealloc(x);
|
||||
// else ignore. Strings are permitted to annotate entries
|
||||
// to assist in debugging.
|
||||
}catch(e){
|
||||
console.warn("ondispose() for",ctor.structName,'@',
|
||||
m,'threw. NOT propagating it.',e);
|
||||
}
|
||||
}
|
||||
}else if(obj.ondispose instanceof Function){
|
||||
try{obj.ondispose()}
|
||||
catch(e){
|
||||
/*do not rethrow: destructors must not throw*/
|
||||
const ii = getInstanceHandle(obj, false);
|
||||
if( !ii ) return;
|
||||
rmInstanceHandle(obj);
|
||||
if( !m && !(m = ii.p) ){
|
||||
console.warn("Cannot(?) happen: __freeStruct() found no instanceInfo");
|
||||
return;
|
||||
}
|
||||
if(Array.isArray(obj.ondispose)){
|
||||
let x;
|
||||
while((x = obj.ondispose.pop())){
|
||||
try{
|
||||
if(x instanceof Function) x.call(obj);
|
||||
else if(x instanceof StructType) x.dispose();
|
||||
else if(__isPtr(x)) dealloc(x);
|
||||
// else ignore. Strings are permitted to annotate entries
|
||||
// to assist in debugging.
|
||||
}catch(e){
|
||||
console.warn("ondispose() for",ctor.structName,'@',
|
||||
m,'threw. NOT propagating it.',e);
|
||||
}
|
||||
}
|
||||
delete obj.ondispose;
|
||||
if(ctor.debugFlags.__flags.dealloc){
|
||||
log("debug.dealloc:",(obj[xPtrPropName]?"EXTERNAL":""),
|
||||
ctor.structName,"instance:",
|
||||
ctor.structInfo.sizeof,"bytes @"+m);
|
||||
}
|
||||
if(!obj[xPtrPropName]){
|
||||
if( ctor.structInfo.zeroOnFree ){
|
||||
heap().fill(0, Number(m), Number(m)+ctor.structInfo.sizeof);
|
||||
}
|
||||
dealloc(m);
|
||||
}else if(obj.ondispose instanceof Function){
|
||||
try{obj.ondispose()}
|
||||
catch(e){
|
||||
/*do not rethrow: destructors must not throw*/
|
||||
console.warn("ondispose() for",ctor.structName,'@',
|
||||
m,'threw. NOT propagating it.',e);
|
||||
}
|
||||
}
|
||||
delete obj.ondispose;
|
||||
if(ctor.debugFlags.__flags.dealloc){
|
||||
log("debug.dealloc:",(ii.ownsPointer?"":"EXTERNAL"),
|
||||
ctor.structName,"instance:",
|
||||
ctor.structInfo.sizeof,"bytes @"+m);
|
||||
}
|
||||
if(ii.ownsPointer){
|
||||
if( ii.zod || ctor.structInfo.zeroOnDispose ){
|
||||
heap().fill(0, Number(m),
|
||||
Number(m) + ctor.structInfo.sizeof + ii.xb);
|
||||
}
|
||||
dealloc(m);
|
||||
}
|
||||
};
|
||||
|
||||
/** Returns a skeleton for a read-only, non-iterable property
|
||||
* descriptor. */
|
||||
const rop0 = ()=>{return {configurable: false, writable: false,
|
||||
iterable: false}};
|
||||
|
||||
/** Returns a skeleton for a read-only property accessor wrapping
|
||||
value v. */
|
||||
const rop = (v)=>{return {configurable: false, writable: false,
|
||||
iterable: false, value: v}};
|
||||
const rop = (v)=>{return {...rop0(), value: v}};
|
||||
|
||||
/** Allocates obj's memory buffer based on the size defined in
|
||||
ctor.structInfo.sizeof. */
|
||||
const __allocStruct = function(ctor, obj, m){
|
||||
let fill = !m;
|
||||
if(m) Object.defineProperty(obj, xPtrPropName, rop(m));
|
||||
else{
|
||||
m = alloc(ctor.structInfo.sizeof);
|
||||
if(!m) toss("Allocation of",ctor.structName,"structure failed.");
|
||||
const __allocStruct = function f(ctor, obj, xm){
|
||||
let opt;
|
||||
const checkPtr = (ptr)=>{
|
||||
__isNonNullPtr(ptr) ||
|
||||
toss("Invalid pointer value",arguments[0],"for",ctor.structName,"constructor.");
|
||||
};
|
||||
if( arguments.length>=3 ){
|
||||
if( xm && ('object'===typeof xm) ){
|
||||
opt = xm;
|
||||
xm = opt?.wrap;
|
||||
}else{
|
||||
checkPtr(xm);
|
||||
opt = {wrap: xm};
|
||||
}
|
||||
}else{
|
||||
opt = {}
|
||||
}
|
||||
|
||||
const fill = !xm /* true if we need to zero the memory */;
|
||||
let nAlloc = 0;
|
||||
let ownsPointer = false;
|
||||
if(xm){
|
||||
/* Externally-allocated memory. */
|
||||
checkPtr(xm);
|
||||
ownsPointer = !!opt?.takeOwnership;
|
||||
}else{
|
||||
const nX = opt?.extraBytes ?? 0;
|
||||
if( nX<0 || (nX!==(nX|0)) ){
|
||||
toss("Invalid extraBytes value:",opt?.extraBytes);
|
||||
}
|
||||
nAlloc = ctor.structInfo.sizeof + nX;
|
||||
xm = alloc(nAlloc)
|
||||
|| toss("Allocation of",ctor.structName,"structure failed.");
|
||||
ownsPointer = true;
|
||||
}
|
||||
try {
|
||||
if(ctor.debugFlags.__flags.alloc){
|
||||
if( opt?.debugFlags ){
|
||||
/* specifically undocumented */
|
||||
obj.debugFlags(opt.debugFlags);
|
||||
}
|
||||
if(ctor./*prototype.???*/debugFlags.__flags.alloc){
|
||||
log("debug.alloc:",(fill?"":"EXTERNAL"),
|
||||
ctor.structName,"instance:",
|
||||
ctor.structInfo.sizeof,"bytes @"+m);
|
||||
ctor.structInfo.sizeof,"bytes @"+xm);
|
||||
}
|
||||
if(fill){
|
||||
heap().fill(0, Number(m), Number(m) + ctor.structInfo.sizeof);
|
||||
heap().fill(0, Number(xm), Number(xm) + nAlloc);
|
||||
}
|
||||
const ii = getInstanceHandle(obj);
|
||||
ii.p = xm;
|
||||
ii.ownsPointer = ownsPointer;
|
||||
ii.xb = nAlloc ? (nAlloc-ctor.structInfo.sizeof) : 0;
|
||||
ii.zod = !!opt?.zeroOnDispose;
|
||||
if( opt?.ondispose && opt.ondispose!==xm ){
|
||||
obj.addOnDispose( opt.ondispose );
|
||||
}
|
||||
__instancePointerMap.set(obj, m);
|
||||
}catch(e){
|
||||
__freeStruct(ctor, obj, m);
|
||||
__freeStruct(ctor, obj, xm);
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
/** Gets installed as the memoryDump() method of all structs. */
|
||||
const __memoryDump = function(){
|
||||
const p = this.pointer;
|
||||
return p
|
||||
? new Uint8Array(heap().slice(Number(p), Number(p) + this.structInfo.sizeof))
|
||||
: null;
|
||||
};
|
||||
|
||||
/** True if sig looks like an emscripten/jaccwabyt
|
||||
type signature, else false. */
|
||||
@@ -390,25 +481,33 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
||||
|
||||
// StructBinder::adaptGet()
|
||||
const __adaptGet = function(key, ...args){
|
||||
/*if( looksLikeASig(key) ){
|
||||
toss("Getter adaptor's name (",key,") collides with a data type signature.");
|
||||
}*/
|
||||
return __adaptor(this, 0, key, ...args);
|
||||
};
|
||||
|
||||
const __affirmNotASig = function(ctx,key){
|
||||
looksLikeASig(key) &&
|
||||
toss(ctx,"(",key,") collides with a data type signature.");
|
||||
};
|
||||
|
||||
// StructBinder::adaptSet()
|
||||
const __adaptSet = function(key, ...args){
|
||||
if( looksLikeASig(key) ){
|
||||
toss("Setter adaptor's name (",key,") collides with a data type signature.");
|
||||
}
|
||||
__affirmNotASig('Setter adaptor',key);
|
||||
return __adaptor(this, 1, key, ...args);
|
||||
};
|
||||
|
||||
// StructBinder::adaptStruct()
|
||||
const __adaptStruct = function(key, ...args){
|
||||
__affirmNotASig('Struct adaptor',key);
|
||||
return __adaptor(this, 2, key, ...args);
|
||||
};
|
||||
|
||||
/**
|
||||
An internal counterpart of __adaptStruct(). If key is-a string,
|
||||
uses __adaptor(who) to fetch the struct-adaptor entry for key,
|
||||
else key is assumed to be a struct description object. If it
|
||||
resolves to an object, that's returned, else an exception is
|
||||
thrown.
|
||||
*/
|
||||
const __adaptStruct2 = function(who,key){
|
||||
const si = ('string'===typeof key)
|
||||
? __adaptor(who, 2, key) : key;
|
||||
@@ -455,15 +554,6 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
||||
return emscriptenFormat ? f._(m.signature) : m.signature;
|
||||
};
|
||||
|
||||
const __ptrPropDescriptor = {
|
||||
configurable: false, enumerable: false,
|
||||
get: function(){return getInstancePtr(this)},
|
||||
set: ()=>toss("Cannot assign the 'pointer' property of a struct.")
|
||||
// Reminder: leaving `set` undefined makes assignments
|
||||
// to the property _silently_ do nothing. Current unit tests
|
||||
// rely on it throwing, though.
|
||||
};
|
||||
|
||||
/** Impl of X.memberKeys() for StructType and struct ctors. */
|
||||
const __structMemberKeys = rop(function(){
|
||||
const a = [];
|
||||
@@ -597,13 +687,13 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
||||
Prototype for all StructFactory instances (the constructors
|
||||
returned from StructBinder).
|
||||
*/
|
||||
const StructType = function ctor(structName, structInfo){
|
||||
if(arguments[2]!==rop){
|
||||
const StructType = function StructType(structName, structInfo){
|
||||
if(arguments[2]!==rop/*internal sentinel value*/){
|
||||
toss("Do not call the StructType constructor",
|
||||
"from client-level code.");
|
||||
}
|
||||
Object.defineProperties(this,{
|
||||
//isA: rop((v)=>v instanceof ctor),
|
||||
//isA: rop((v)=>v instanceof StructType),
|
||||
structName: rop(structName),
|
||||
structInfo: rop(structInfo)
|
||||
});
|
||||
@@ -629,8 +719,31 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
||||
memberSignature: rop(function(memberName, emscriptenFormat=false){
|
||||
return __memberSignature(this, memberName, emscriptenFormat);
|
||||
}),
|
||||
memoryDump: rop(__memoryDump),
|
||||
pointer: __ptrPropDescriptor,
|
||||
memoryDump: rop(function(){
|
||||
const p = this.pointer;
|
||||
return p
|
||||
? new Uint8Array(heap().slice(Number(p), Number(p) + this.structInfo.sizeof))
|
||||
: null;
|
||||
}),
|
||||
extraBytes: {
|
||||
configurable: false, enumerable: false,
|
||||
get: function(){return getInstanceHandle(this, false)?.xb ?? 0;}
|
||||
},
|
||||
zeroOnDispose: {
|
||||
configurable: false, enumerable: false,
|
||||
get: function(){
|
||||
return getInstanceHandle(this, false)?.zod
|
||||
?? !!this.structInfo.zeroOnDispose;
|
||||
}
|
||||
},
|
||||
pointer: {
|
||||
configurable: false, enumerable: false,
|
||||
get: function(){return getInstanceHandle(this, false)?.p},
|
||||
set: ()=>toss("Cannot assign the 'pointer' property of a struct.")
|
||||
// Reminder: leaving `set` undefined makes assignments
|
||||
// to the property _silently_ do nothing. Current unit tests
|
||||
// rely on it throwing, though.
|
||||
},
|
||||
setMemberCString: rop(function(memberName, str){
|
||||
return __setMemberCString(this, memberName, str);
|
||||
})
|
||||
@@ -649,8 +762,12 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
||||
Object.defineProperties(StructType, {
|
||||
allocCString: rop(__allocCString),
|
||||
isA: rop((v)=>v instanceof StructType),
|
||||
hasExternalPointer: rop((v)=>(v instanceof StructType) && !!v[xPtrPropName]),
|
||||
hasExternalPointer: rop((v)=>{
|
||||
const ii = getInstanceHandle(v, false);
|
||||
return !!(ii?.p && !ii?.ownsPointer);
|
||||
}),
|
||||
memberKey: __memberKeyProp
|
||||
//ptrAdd = rop(__ptrAdd) no b/c one might think that it adds based on this.pointer.
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -693,7 +810,7 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
||||
do any permanent harm, as the wrapper object will be recreated
|
||||
when accessing f.bar, pointing to the same memory in f.
|
||||
|
||||
The si.zeroOnFree flag has no effect on embedded structs because
|
||||
The si.zeroOnDispose flag has no effect on embedded structs because
|
||||
they wrap "external" memory, so do not own it, and are thus never
|
||||
freed, as such.
|
||||
*/
|
||||
@@ -725,7 +842,7 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
||||
enumerable: false,
|
||||
set: __propThrowOnSet(ctor/*not si.constructor*/.structName, key),
|
||||
get: function(){
|
||||
const dbg = si.constructor.prototype.debugFlags.__flags;
|
||||
const dbg = this.debugFlags.__flags;
|
||||
const p = this.pointer;
|
||||
const k = p+'.'+key;
|
||||
let s = __innerStructs.get(k);
|
||||
@@ -746,6 +863,8 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
||||
}/*makeMemberStructWrapper()*/;
|
||||
|
||||
/**
|
||||
This is where most of the magic happens.
|
||||
|
||||
Pass this a StructBinderImpl-generated constructor, a member
|
||||
property name, and the struct member description object. It will
|
||||
define property accessors for proto[memberKey] which read
|
||||
@@ -758,16 +877,16 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
||||
return makeMemberStructWrapper.call(this, ctor, name, si);
|
||||
}
|
||||
|
||||
if(!f._){
|
||||
if(!f.cache){
|
||||
/* Cache all available getters/setters/set-wrappers for
|
||||
direct reuse in each accessor function. */
|
||||
f._ = {getters: {}, setters: {}, sw:{}};
|
||||
f.cache = {getters: {}, setters: {}, sw:{}};
|
||||
const a = ['i','c','C','p','P','s','f','d','v()'];
|
||||
if(bigIntEnabled) a.push('j');
|
||||
a.forEach(function(v){
|
||||
f._.getters[v] = sigDVGetter(v) /* DataView[MethodName] values for GETTERS */;
|
||||
f._.setters[v] = sigDVSetter(v) /* DataView[MethodName] values for SETTERS */;
|
||||
f._.sw[v] = sigDVSetWrapper(v) /* BigInt or Number ctor to wrap around values
|
||||
f.cache.getters[v] = sigDVGetter(v) /* DataView[MethodName] values for GETTERS */;
|
||||
f.cache.setters[v] = sigDVSetter(v) /* DataView[MethodName] values for SETTERS */;
|
||||
f.cache.sw[v] = sigDVSetWrapper(v) /* BigInt or Number ctor to wrap around values
|
||||
for conversion */;
|
||||
});
|
||||
f.sigCheck = function(obj, name, key,sig){
|
||||
@@ -784,8 +903,8 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
||||
si.key = key;
|
||||
si.name = name;
|
||||
const sigGlyph = sigLetter(si.signature);
|
||||
const xPropName = sPropName(ctor.prototype.structName,key);
|
||||
const dbg = ctor.prototype.debugFlags.__flags;
|
||||
const xPropName = sPropName(ctor.structName,key);
|
||||
const dbg = ctor.debugFlags.__flags;
|
||||
/*
|
||||
TODO?: set prototype of si to an object which can set/fetch
|
||||
its preferred representation, e.g. conversion to string or mapped
|
||||
@@ -797,14 +916,20 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
||||
prop.configurable = false;
|
||||
prop.enumerable = false;
|
||||
prop.get = function(){
|
||||
/**
|
||||
This getter proxy reads its value from the appropriate pointer
|
||||
address in the heap. It knows where and how much to read based on
|
||||
this.pointer, si.offset, and si.sizeof.
|
||||
*/
|
||||
if(dbg.getter){
|
||||
log("debug.getter:",f._.getters[sigGlyph],"for", sigIR(sigGlyph),
|
||||
log("debug.getter:",f.cache.getters[sigGlyph],"for", sigIR(sigGlyph),
|
||||
xPropName,'@', this.pointer,'+',si.offset,'sz',si.sizeof);
|
||||
}
|
||||
let rc = (
|
||||
new DataView(heap().buffer, Number(this.pointer) + si.offset, si.sizeof)
|
||||
)[f._.getters[sigGlyph]](0, isLittleEndian);
|
||||
if(getterProxy) rc = getterProxy.apply(this,[rc,key]);
|
||||
)[f.cache.getters[sigGlyph]](0, isLittleEndian);
|
||||
|
||||
if(getterProxy) rc = getterProxy.apply(this,[key,rc]);
|
||||
if(dbg.getter) log("debug.getter:",xPropName,"result =",rc);
|
||||
return rc;
|
||||
};
|
||||
@@ -813,28 +938,33 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
||||
}else{
|
||||
const setterProxy = memberSetterProxy(si);
|
||||
prop.set = function(v){
|
||||
/**
|
||||
The converse of prop.get(), this encodes v into the appropriate
|
||||
spot in the WASM heap.
|
||||
*/
|
||||
if(dbg.setter){
|
||||
log("debug.setter:",f._.setters[sigGlyph],"for", sigIR(sigGlyph),
|
||||
log("debug.setter:",f.cache.setters[sigGlyph],"for", sigIR(sigGlyph),
|
||||
xPropName,'@', this.pointer,'+',si.offset,'sz',si.sizeof, v);
|
||||
}
|
||||
if(!this.pointer){
|
||||
toss("Cannot set native property on a disposed struct instance.");
|
||||
toss("Cannot set native property on a disposed",
|
||||
this.structName,"instance.");
|
||||
}
|
||||
if( setterProxy ) v = setterProxy.apply(this,[v]);
|
||||
if( setterProxy ) v = setterProxy.apply(this,[key,v]);
|
||||
if( null===v || undefined===v ) v = __NullPtr;
|
||||
else while( isPtrSig(si.signature) && !__isPtr(v) ){
|
||||
else if( isPtrSig(si.signature) && !__isPtr(v) ){
|
||||
if(isAutoPtrSig(si.signature) && (v instanceof StructType)){
|
||||
// It's a struct instance: let's store its pointer value!
|
||||
// It's a struct instance: store its pointer value
|
||||
v = v.pointer || __NullPtr;
|
||||
if(dbg.setter) log("debug.setter:",xPropName,"resolved to",v);
|
||||
break;
|
||||
}else{
|
||||
toss("Invalid value for pointer-type",xPropName+'.');
|
||||
}
|
||||
toss("Invalid value for pointer-type",xPropName+'.');
|
||||
}
|
||||
(
|
||||
new DataView(heap().buffer, Number(this.pointer) + si.offset,
|
||||
si.sizeof)
|
||||
)[f._.setters[sigGlyph]](0, f._.sw[sigGlyph](v), isLittleEndian);
|
||||
)[f.cache.setters[sigGlyph]](0, f.cache.sw[sigGlyph](v), isLittleEndian);
|
||||
};
|
||||
}
|
||||
Object.defineProperty(ctor.prototype, key, prop);
|
||||
@@ -863,25 +993,59 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
||||
StructCtor is the eventual return value of this function. We
|
||||
need to populate this early on so that we can do some trickery
|
||||
in feeding it through recursion.
|
||||
|
||||
Uses:
|
||||
|
||||
// heap-allocated:
|
||||
const x = new StructCtor;
|
||||
// externally-managed memory:
|
||||
const y = new StructCtor( aPtrToACompatibleCStruct );
|
||||
|
||||
or, more recently:
|
||||
|
||||
const z = new StructCtor({
|
||||
extraBytes: [int=0] extra bytes to allocate after the struct
|
||||
|
||||
wrap: [aPtrToACompatibleCStruct=undefined]. If provided, this
|
||||
instance waps, but does not (by default) own the memory, else
|
||||
a new instance is allocated from the WASM heap.
|
||||
|
||||
ownsPointer: true if this object takes over ownership of
|
||||
wrap.
|
||||
|
||||
zeroOnDispose: [bool=StructCtor.structInfo.zeroOnDispose]
|
||||
|
||||
autoCalcSizeOffset: [bool=false] Automatically calculate
|
||||
sizeof an offset. This is fine for pure-JS structs (which
|
||||
probably aren't useful beyond testing of Jaccwabyt) but it's
|
||||
dangerous to use with actual WASM objects because we cannot
|
||||
be guaranteed to have the same memory layout as an ostensibly
|
||||
matching C struct. This applies recursively to all children
|
||||
of the struct description.
|
||||
|
||||
// TODO? Per-instance overrides of the struct-level flags?
|
||||
|
||||
get: (k,v)=>v,
|
||||
set: (k,v)=>v,
|
||||
adaptGet: string,
|
||||
adaptSet: string
|
||||
|
||||
// That wouldn't fit really well right now, apparently.
|
||||
});
|
||||
|
||||
*/
|
||||
const StructCtor = function StructCtor(externalMemory){
|
||||
externalMemory = __asPtrType(externalMemory);
|
||||
//console.warn("externalMemory",externalMemory,arguments[0]);
|
||||
const StructCtor = function StructCtor(arg){
|
||||
//console.warn("opt",opt,arguments[0]);
|
||||
if(!(this instanceof StructCtor)){
|
||||
toss("The",structName,"constructor may only be called via 'new'.");
|
||||
}else if(arguments.length){
|
||||
if( !__isPtr(externalMemory) ){
|
||||
toss("Invalid pointer value",arguments[0],"for",structName,"constructor.");
|
||||
}
|
||||
__allocStruct(StructCtor, this, externalMemory);
|
||||
}else{
|
||||
__allocStruct(StructCtor, this);
|
||||
}
|
||||
__allocStruct(StructCtor, this, ...arguments);
|
||||
};
|
||||
const self = this;
|
||||
/**
|
||||
"Convert" struct description x to a struct description, if
|
||||
needed.
|
||||
needed. This expands adaptStruct() mappings and transforms
|
||||
{memberName:signatureString} signature syntax to object form.
|
||||
*/
|
||||
const ads = (x)=>{
|
||||
//console.warn("looksLikeASig(",x,") =",looksLikeASig(x));
|
||||
@@ -902,6 +1066,7 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
||||
structName ??= opt.structName;
|
||||
if( !structName ) toss("One of 'name' or 'structName' are required.");
|
||||
if( si.adapt ){
|
||||
/* Install adaptGet(), adaptSet(), and adaptStruct() proxies. */
|
||||
Object.keys(si.adapt.struct||{}).forEach((k)=>{
|
||||
__adaptStruct.call(StructBinderImpl, k, si.adapt.struct[k]);
|
||||
});
|
||||
@@ -924,21 +1089,32 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
||||
memberKeys: __structMemberKeys,
|
||||
//methodInfoForKey: rop(function(mKey){/*???*/}),
|
||||
structInfo: rop(si),
|
||||
structName: rop(structName)
|
||||
structName: rop(structName),
|
||||
ptrAdd: rop(__ptrAdd)
|
||||
});
|
||||
StructCtor.prototype = new StructType(structName, si, rop);
|
||||
Object.defineProperties(StructCtor.prototype,{
|
||||
debugFlags: debugFlags,
|
||||
constructor: rop(StructCtor)
|
||||
/*if we assign StructCtor.prototype and don't do
|
||||
this then StructCtor!==instance.constructor*/
|
||||
this then StructCtor!==instance.constructor*/,
|
||||
ptrAdd: rop(__ptrAddSelf)
|
||||
});
|
||||
|
||||
|
||||
let lastMember = false;
|
||||
let offset = 0;
|
||||
const autoCalc = !!si.autoCalcSizeOffset;
|
||||
//console.warn(structName,"si =",si);
|
||||
si.offset ??= 0;
|
||||
if( !autoCalc ){
|
||||
if( !si.sizeof ){
|
||||
toss(structName,"description is missing its sizeof property.");
|
||||
}
|
||||
/*if( undefined===si.offset ){
|
||||
toss(structName,"description is missing its offset property.");
|
||||
}*/
|
||||
si.offset ??= 0;
|
||||
}else{
|
||||
si.offset ??= 0;
|
||||
}
|
||||
Object.keys(si.members || {}).forEach((k)=>{
|
||||
// Sanity checks of sizeof/offset info...
|
||||
let m = ads(si.members[k]);
|
||||
@@ -951,11 +1127,23 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
||||
}
|
||||
}
|
||||
if( undefined===m.offset ){
|
||||
m.offset = offset;
|
||||
if( autoCalc ) m.offset = offset;
|
||||
else{
|
||||
toss(sPropName(structName,k),"is missing its offset.",
|
||||
JSON.stringify(m));
|
||||
}
|
||||
/* A missing offset on the initial child is okay (it's always
|
||||
zero), but we don't know for sure that the members are
|
||||
their natural order, so we don't know, at this point, which
|
||||
one is "first". */
|
||||
}
|
||||
si.members[k] = m;
|
||||
si.members[k] = m /* in case ads() resolved it to something else */;
|
||||
if(!lastMember || lastMember.offset < m.offset) lastMember = m;
|
||||
makeMemberWrapper.call(self, StructCtor, k, m)
|
||||
const oldAutoCalc = !!m.autoCalc;
|
||||
if( autoCalc ) m.autoCalcSizeOffset = true;
|
||||
makeMemberWrapper.call(self, StructCtor, k, m);
|
||||
if( oldAutoCalc ) m.autoCalcSizeOffset = true;
|
||||
else delete m.autoCalcSizeOffset;
|
||||
offset += m.sizeof;
|
||||
//console.warn("offset",sPropName(structName,k),offset);
|
||||
});
|
||||
@@ -979,12 +1167,15 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
||||
toss(structName,"offset is not aligned. offset="+si.offset);
|
||||
}
|
||||
}
|
||||
|
||||
if( si.sizeof < offset ){
|
||||
console.warn("Suspect struct description:",si,"offset =",offset);
|
||||
toss("Mismatch in the calculated vs. the provided sizeof/offset info.",
|
||||
"Expected sizeof",offset,"but got",si.sizeof,"for",si);
|
||||
/* It is legal for the native struct to be larger, so long as
|
||||
we're pointing to all the right offsets for the members
|
||||
exposed here. */
|
||||
}
|
||||
delete si.autoCalcSizeOffset;
|
||||
return StructCtor;
|
||||
}/*StructBinderImpl*/;
|
||||
|
||||
@@ -999,6 +1190,7 @@ globalThis.Jaccwabyt = function StructBinderFactory(config){
|
||||
StructBinder.adaptGet = __adaptGet;
|
||||
StructBinder.adaptSet = __adaptSet;
|
||||
StructBinder.adaptStruct = __adaptStruct;
|
||||
StructBinder.ptrAdd = __ptrAdd;
|
||||
if(!StructBinder.debugFlags){
|
||||
StructBinder.debugFlags = SBF.__makeDebugFlags(SBF.debugFlags);
|
||||
}
|
||||
|
||||
+578
-344
File diff suppressed because it is too large.
Load diff
@@ -1027,7 +1027,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
let ptr = k1.pointer;
|
||||
k1.dispose();
|
||||
T.assert(undefined === k1.pointer).
|
||||
mustThrowMatching(()=>{k1.$pP=1}, /disposed struct instance/);
|
||||
mustThrowMatching(()=>{k1.$pP=1}, /disposed/);
|
||||
}finally{
|
||||
k1.dispose();
|
||||
k2.dispose();
|
||||
@@ -2907,11 +2907,12 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
]);
|
||||
T.assert(3 === db.selectValue('select count(*) from kvvfs'));
|
||||
db.close();
|
||||
db = undefined;
|
||||
db = new JDb(filename);
|
||||
db.exec('insert into kvvfs(a) values(4),(5),(6)');
|
||||
T.assert(6 === db.selectValue('select count(*) from kvvfs'));
|
||||
}finally{
|
||||
db.close();
|
||||
if( db ) db.close();
|
||||
}
|
||||
}
|
||||
}/*kvvfs sanity checks*/)
|
||||
|
||||
@@ -1863,6 +1863,12 @@ mdevtest: srctree-check has_tclsh85
|
||||
sdevtest: has_tclsh85
|
||||
$(TCLSH_CMD) $(TOP)/test/testrunner.tcl sdevtest $(TSTRNNR_OPTS)
|
||||
|
||||
errors:
|
||||
$(TCLSH_CMD) $(TOP)/test/testrunner.tcl errors
|
||||
|
||||
status:
|
||||
$(TCLSH_CMD) $(TOP)/test/testrunner.tcl status -d 2
|
||||
|
||||
# Like releasetest, except it omits srctree-check and verify-source so
|
||||
# that it can be used on a modified source tree.
|
||||
#
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
C Fix\sa\scrash\sthat\scould\soccur\sfollowing\sa\sparse\serror\son\sthis\sbranch.
|
||||
D 2025-12-01T17:22:15.541
|
||||
C Merge\slatest\strunk\schanges\sinto\sthis\sbranch.
|
||||
D 2025-12-01T17:22:35.232
|
||||
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 8c5ed7173ee4cc3c03ba8e21065128f7ca5292c83d68f3bf971786e21fc6e382
|
||||
F README.md dae499194b75deed76a13a4a83c82493f2530331882d7dfe5754d63287d3f8f7
|
||||
F Makefile.msc 295bc62fdd8663a6581cc43252403fac3cb784002164ff53fac8d15fc72fdfaa
|
||||
F README.md 3fa51fc7ababc32edd175ae8b2986c86d5ea120c1cb1e57c7f7849492d1405ec
|
||||
F VERSION 74672bfd4c7826c0fc6f84762488a707c52e7d2d94af42ccb0edcc6c74311c41
|
||||
F art/icon-243x273.gif 9750b734f82fdb3dc43127753d5e6fbf3b62c9f4e136c2fbf573b2f57ea87af5
|
||||
F art/icon-80x90.gif 65509ce3e5f86a9cd64fe7fca2d23954199f31fe44c1e09e208c80fb83d87031
|
||||
@@ -18,7 +18,7 @@ F art/sqlite370.svg 40b7e2fe8aac3add5d56dd86ab8d427a4eca5bcb3fe4f8946cb3794e1821
|
||||
F auto.def 44a0d1bf09d78355fc88251ccbf8e64e6341fd89c11de68a01c3645e53a2bade
|
||||
F autoconf/Makefile.fallback 22fe523eb36dfce31e0f6349f782eb084e86a5620b2b0b4f84a2d6133f53f5ac
|
||||
F autoconf/Makefile.in 306f500fce8cae9e1af9459f1ac7fe89ce46999594ef3fdc62dc9d7d651fb091
|
||||
F autoconf/Makefile.msc 803aa9e23b6a764751f6a91d0673620eefa46729fb80faf51391120e1d752966
|
||||
F autoconf/Makefile.msc 7952ed1fbb824f9421688e6b46d09fc4d5a13decec791a6264be4f65e64dfc08
|
||||
F autoconf/README.first f1d3876e9a7852c22f275a6f06814e64934cecbc0b5b9617d64849094c1fd136
|
||||
F autoconf/README.txt b749816b8452b3af994dc6d607394bef3df1736d7e09359f1087de8439a52807
|
||||
F autoconf/auto.def 3d994f3a9cc9b712dbce92a5708570ddcf3b988141b6eb738f2ed16127a9f0ac
|
||||
@@ -33,7 +33,7 @@ F autoconf/tea/teaish.tcl 81feb417e718ed75cdd7e2fdf6771f3da80dae97377a90c4d5b62b
|
||||
F autoconf/tea/teaish.test.tcl cfe94e1fb79dd078f650295be59843d470125e0cc3a17a1414c1fb8d77f4aea6
|
||||
F autosetup/LICENSE 41a26aebdd2cd185d1e2b210f71b7ce234496979f6b35aef2cbf6b80cbed4ce4
|
||||
F autosetup/README.autosetup a78ff8c4a3d2636a4268736672a74bf14a82f42687fcf0631a70c516075c031e
|
||||
F autosetup/README.md ce0f95980a687bb861bd830b76bc4b48513567be5cf5ee7004f4f3439ffe3841
|
||||
F autosetup/README.md e8503618f6cb31b692383ca662f6eb9ef4345463f5e3c1fc84a5d6863c7058be
|
||||
F autosetup/autosetup b16e44924c197783df67366762dda985b45d49ebc4af15f4054e3ee0e3b65169 x
|
||||
F autosetup/autosetup-config.guess dfa101c5e8220e864d5e9c72a85e87110df60260d36cb951ad0a85d6d9eaa463 x
|
||||
F autosetup/autosetup-config.sub a38fb074d0dece01cf919e9fb534a26011608aa8fa606490864295328526cd73 x
|
||||
@@ -44,7 +44,7 @@ F autosetup/cc-lib.tcl 493c5935b5dd3bf9bd4eca89b07c8b1b1a9356d61783035144e21795f
|
||||
F autosetup/cc-shared.tcl 163eda58c14cd662fd8a504bd2ad8a716ef4db7015dc1de0095d5de8dd601a4b
|
||||
F autosetup/cc.tcl c0fcc50ca91deff8741e449ddad05bcd08268bc31177e613a6343bbd1fd3e45f
|
||||
F autosetup/find_tclconfig.tcl e64886ffe3b982d4df42cd28ed91fe0b5940c2c5785e126c1821baf61bc86a7e
|
||||
F autosetup/jimsh0.c a57c16e65dcffc9c76e496757cb3f7fb47e01ecbd1631a0a5e01751fc856f049
|
||||
F autosetup/jimsh0.c 916bbdf8023fbda9937afae57d81a853d8c2ea00f2320aa27becbc33574f963d
|
||||
F autosetup/pkg-config.tcl 4e635bf39022ff65e0d5434339dd41503ea48fc53822c9c5bde88b02d3d952ba
|
||||
F autosetup/proj.tcl 6fc14ef82b19b77a95788ffbcfad7989b4e3cb4ce96a21dcb5cf7312f362fba9
|
||||
F autosetup/sqlite-config.tcl 97dc76d332ae3344d02d15c99c57db0ac063537e9133cbee0520d48ba0eddc08
|
||||
@@ -97,7 +97,7 @@ F ext/fts3/fts3_tokenizer.h 64c6ef6c5272c51ebe60fc607a896e84288fcbc3
|
||||
F ext/fts3/fts3_tokenizer1.c c1de4ae28356ad98ccb8b2e3388a7fdcce7607b5523738c9afb6275dab765154
|
||||
F ext/fts3/fts3_unicode.c de426ff05c1c2e7bce161cf6b706638419c3a1d9c2667de9cb9dc0458c18e226
|
||||
F ext/fts3/fts3_unicode2.c 416eb7e1e81142703520d284b768ca2751d40e31fa912cae24ba74860532bf0f
|
||||
F ext/fts3/fts3_write.c 2bee1c5828f6401adffd07ca64260aeb79d64138958273a56de8fa5e8759a0c1
|
||||
F ext/fts3/fts3_write.c 66abcd0a35c722ad13ea73d4c31fc7773b9a01b35d434ad945cbf17b4f2563bd
|
||||
F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9
|
||||
F ext/fts3/tool/fts3cov.sh c331d006359456cf6f8f953e37f2b9c7d568f3863f00bb5f7eb87fea4ac01b73
|
||||
F ext/fts3/tool/fts3view.c 413c346399159df81f86c4928b7c4a455caab73bfbc8cd68f950f632e5751674
|
||||
@@ -113,7 +113,7 @@ F ext/fts5/fts5_buffer.c f1e6d0324d7c55329d340673befc26681a372a4d36086caa8d1ec7d
|
||||
F ext/fts5/fts5_config.c e7d8dd062b44a66cd77e5a0f74f23a2354cd1f3f8575afb967b2773c3384f7f8
|
||||
F ext/fts5/fts5_expr.c b8c32da1127bafaf10d6b4768b0dcb92285798524bed2d87a8686f99a8e8d259
|
||||
F ext/fts5/fts5_hash.c a6266cedd801ab7964fa9e74ebcdda6d30ec6a96107fa24148ec6b7b5b80f6e0
|
||||
F ext/fts5/fts5_index.c 8dbda33a9830764167d7697f1c9980c8a6ee74f5decb28206b963222583b8cdd
|
||||
F ext/fts5/fts5_index.c 5e82963a6691ae519df1e018cc7971272a3da1fd47daca5029af0e9ce24f1a8b
|
||||
F ext/fts5/fts5_main.c 42025174a556257287071e90516d3ab8115daf1dd525a301883544469a260014
|
||||
F ext/fts5/fts5_storage.c 19bc7c4cbe1e6a2dd9849ef7d84b5ca1fcbf194cefc3e386b901e00e08bf05c2
|
||||
F ext/fts5/fts5_tcl.c 7fb5a3d3404099075aaa2457307cb459bbc257c0de3dbd52b1e80a5b503e0329
|
||||
@@ -122,7 +122,7 @@ F ext/fts5/fts5_test_tok.c 3cb0a9b508b30d17ef025ccddd26ae3dc8ddffbe76c057616e59a
|
||||
F ext/fts5/fts5_tokenize.c 49aea8cc400a690a6c4f83c4cedc67f4f8830c6789c4ee343404f62bcaebca7b
|
||||
F ext/fts5/fts5_unicode2.c 536a6dae41d16edadd6a6b58c56e2ebbb133f0dfe757562a2edbcdc9b8362e50
|
||||
F ext/fts5/fts5_varint.c e64d2113f6e1bfee0032972cffc1207b77af63319746951bf1d09885d1dadf80
|
||||
F ext/fts5/fts5_vocab.c ff0441c4ea165081e8152dec6d29056faa0cdc281a9f218a00e3d7aacc1958bc
|
||||
F ext/fts5/fts5_vocab.c 23e263ad94ac357cfffd19bd7e001c3f15c4420fb10fa35b5993142127e780e6
|
||||
F ext/fts5/fts5parse.y eb526940f892ade5693f22ffd6c4f2702543a9059942772526eac1fde256bb05
|
||||
F ext/fts5/mkportersteps.tcl 5acf962d2e0074f701620bb5308155fa1e4a63ba
|
||||
F ext/fts5/test/fts5_common.tcl c5aa7cf7148b6dcffb5b61520ae18212baf169936af734ab265143f59db328fe
|
||||
@@ -162,7 +162,7 @@ F ext/fts5/test/fts5contentless4.test ec34dc69ef474ca9997dae6d91e072906e0e9a5a4b
|
||||
F ext/fts5/test/fts5contentless5.test 38cd0392c730dc7090c550321ce3c24ba4c392bc97308b51a4180e9959dca7b5
|
||||
F ext/fts5/test/fts5corrupt.test 237fce1c3261bb3a5bec333b0f0dbf5b105ec32627ef14cccbda3cfe13833193
|
||||
F ext/fts5/test/fts5corrupt2.test 4a03a158c2cb617c9f76d26b35c1ef2534124bc0bbddcea38dfd5b170ebea27b
|
||||
F ext/fts5/test/fts5corrupt3.test 43d6a836892d79ab738ab89b3b6f4ae46c07ee966193e4b357bbb14e7f81d5da
|
||||
F ext/fts5/test/fts5corrupt3.test e489b51b6c4ded2a808e0f78bdbe126f6d369de41a59ac2717878e37fc3db0e8
|
||||
F ext/fts5/test/fts5corrupt4.test dc08d19f5b8943e95a7778a7d8da592042504faf18dd93f68f7d7a0d7d7dd733
|
||||
F ext/fts5/test/fts5corrupt5.test 73985d4fe6d8f0d5d5c7bcf79ae7c6522c376cd6ad710a0ff2f26e0c2e222abe
|
||||
F ext/fts5/test/fts5corrupt6.test 2d72db743db7b5d9c9a6d0cfef24d799ed1aa5e8192b66c40e871a37ed9eed06
|
||||
@@ -269,7 +269,7 @@ F ext/fts5/test/fts5update.test b8affd796e45c94a4d19ad5c26606ea06065a0f162a9562d
|
||||
F ext/fts5/test/fts5update2.test c5baa76799ac605ebb8e5e21035db2014b396cef25c903eb96ba39b1d6f9f046
|
||||
F ext/fts5/test/fts5version.test 44ab35566267b7618c090443de2d9ad84f633df5d20bf72e9bad199ae5fced84
|
||||
F ext/fts5/test/fts5vocab.test 2a2bdb60d0998fa3124d541b6d30b019504918dc43a6584645b63a24be72f992
|
||||
F ext/fts5/test/fts5vocab2.test bbba149c254375d00055930c1a501c9a51e80b0d20bf7b98f3e9fa3b03786373
|
||||
F ext/fts5/test/fts5vocab2.test 4265137a3747b27deb1e2e2bde5654120c6de72bfed3238e67806d85af60fc4c
|
||||
F ext/fts5/tool/fts5speed.tcl b0056f91a55b2d1a3684ec05729de92b042e2f85
|
||||
F ext/fts5/tool/fts5txt2db.tcl c0d43c8590656f8240e622b00957b3a0facc49482411a9fdc2870b45c0c82f9f
|
||||
F ext/fts5/tool/loadfts5.tcl 95b03429ee6b138645703c6ca192c3ac96eaf093
|
||||
@@ -392,7 +392,7 @@ F ext/misc/remember.c add730f0f7e7436cd15ea3fd6a90fd83c3f706ab44169f7f048438b7d6
|
||||
F ext/misc/rot13.c 51ac5f51e9d5fd811db58a9c23c628ad5f333c173f1fc53c8491a3603d38556c
|
||||
F ext/misc/scrub.c 2a44b0d44c69584c0580ad2553f6290a307a49df4668941d2812135bfb96a946
|
||||
F ext/misc/series.c 22c6d8f00cc1b5089b1b37392e9097e9df9a5db53be86daf9a7669d95bb179f4
|
||||
F ext/misc/sha1.c cb5002148c2661b5946f34561701e9105e9d339b713ec8ac057fd888b196dcb9
|
||||
F ext/misc/sha1.c 3030b5926b34bb09459200e100fae34e48c04077cf175381a7560f72bbf3d9cf
|
||||
F ext/misc/shathree.c fd22d70620f86a0467acfdd3acd8435d5cb54eb1e2d9ff36ae44e389826993df
|
||||
F ext/misc/showauth.c 732578f0fe4ce42d577e1c86dc89dd14a006ab52
|
||||
F ext/misc/spellfix.c 693c8fd3293087fa821322967a97e59dfa24051e5d2ca7fa85790a4034db6fa4
|
||||
@@ -416,9 +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/qrf/README.md 86fc5c3c5e3eddbe54fc1235cbdc52b8c2c0732791d224345c3014cd45c4c0e7
|
||||
F ext/qrf/qrf.c 425d02cffcc5b5fe9ff5817794bf751b1fdd6912f570c354272429ce1262b866
|
||||
F ext/qrf/qrf.h 322d48537a5aa39c206c2ec0764a7938ea7662a8c25be1c4e9d742789609ba1e
|
||||
F ext/rbu/rbu.c 801450b24eaf14440d8fd20385aacc751d5c9d6123398df41b1b5aa804bf4ce8
|
||||
F ext/rbu/rbu1.test 25870dd7db7eb5597e2b4d6e29e7a7e095abf332660f67d89959552ce8f8f255
|
||||
F ext/rbu/rbu10.test 7c22caa32c2ff26983ca8320779a31495a6555737684af7aba3daaf762ef3363
|
||||
@@ -578,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 01f5e1bc688911b0c0accb0b152dccb19818cb301a90ba9772e3b329a7f625b0
|
||||
F ext/wasm/GNUmakefile 2fe52720144ab481755c6df45f46dcf6c540f8622a5387ed280f1d0b26a6d28f
|
||||
F ext/wasm/README-dist.txt f01081a850ce38a56706af6b481e3a7878e24e42b314cfcd4b129f0f8427066a
|
||||
F ext/wasm/README.md 2e87804e12c98f1d194b7a06162a88441d33bb443efcfe00dc6565a780d2f259
|
||||
F ext/wasm/SQLTester/GNUmakefile e0794f676d55819951bbfae45cc5e8d7818dc460492dc317ce7f0d2eca15caff
|
||||
@@ -586,31 +586,32 @@ F ext/wasm/SQLTester/SQLTester.mjs 6b3c52ed36a5573ca4883176f326332a8d4c0cecf5efd
|
||||
F ext/wasm/SQLTester/SQLTester.run.mjs 57f2adb33f43f2784abbf8026c1bfd049d8013af1998e7dcb8b50c89ffc332e0
|
||||
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/EXPORTED_FUNCTIONS.c-pp 7ba933e8f1290cc65459dd371c0c9a031d96bdf14d7a2244fa761d9775117b90
|
||||
F ext/wasm/api/README.md a905d5c6bfc3e2df875bd391d6d6b7b48d41b43bdee02ad115b47244781a7e81
|
||||
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/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/pre-js.c-pp.js d73088472f91856a27837c0588ac355516cea441ff67d2990effc2ca0627bf21
|
||||
F ext/wasm/api/sqlite3-api-glue.c-pp.js 9b33e3ee467791dec4fd1b444b12a8545dfbb6c8b28ac651c7bdc7661a3b5a5c
|
||||
F ext/wasm/api/sqlite3-api-oo1.c-pp.js 7a6c85b260082d72a5c355caf37876763d8770a29d9e0587751e584c31bf2777
|
||||
F ext/wasm/api/sqlite3-api-prologue.js fd836265adefbe4ed8a978326e0273bafcfb7d42f754b69a5d131a9031428c9f
|
||||
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-kvvfs.c-pp.js f44a4396b2305b27dc81c00a1629fe4f615520f7fb11ed4e606255e365956ba2
|
||||
F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js a2eea6442556867b589e04107796c6e1d04a472219529eeb45b7cd221d7d048b
|
||||
F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 88ce2078267a2d1af57525a32d896295f4a8db7664de0e17e82dc9ff006ed8d3
|
||||
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 7778527bdbb241b8e742a5fc50e470e8b8d0529c41fab9ac127c2c63f3c90d47
|
||||
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/c-pp-lite.c f38254fba42561728c2e4764a7ba8d68700091e7c2f4418112868c0daba16783
|
||||
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 831f07a0d9bb61713164871370811432e96d0f813806a4d2c783d3c77c2373a0
|
||||
F ext/wasm/config.make.in c424ae1cc3c89274520ad312509d36c4daa34a3fce5d0c688e5f8f4365e1049a
|
||||
F ext/wasm/demo-123-worker.html a0b58d9caef098a626a1a1db567076fca4245e8d60ba94557ede8684350a81ed
|
||||
F ext/wasm/demo-123.html 8c70a412ce386bd3796534257935eb1e3ea5c581e5d5aea0490b8232e570a508
|
||||
@@ -624,11 +625,11 @@ F ext/wasm/demo-worker1.js 08720227e98fa5b44761cf6e219269cee3e9dd0421d8d91459535
|
||||
F ext/wasm/example_extra_init.c 2347cd69d19d839ef4e5e77b7855103a7fe3ef2af86f2e8c95839afd8b05862f
|
||||
F ext/wasm/fiddle/fiddle-worker.js 7798af02e672e088ff192716f80626c8895e19301a65b8af6d5d12b2d13d2451
|
||||
F ext/wasm/fiddle/fiddle.js 84fd75967e0af8b69d3dd849818342227d0f81d13db92e0dcbc63649b31a4893
|
||||
F ext/wasm/fiddle/index.html a27b8127ef9ecf19612da93b2a6a73bdb3777b5c56b5450bb7200a94bc108ff9
|
||||
F ext/wasm/fiddle/index.c-pp.html 72c7e5517217960b3809648429ea396a7cbad0ffb2c92f6a2f5703abecb27317 w ext/wasm/fiddle/index.html
|
||||
F ext/wasm/index-dist.html db23748044e286773f2768eec287669501703b5d5f72755e8db73607dc54d290
|
||||
F ext/wasm/index.html 54e27db740695ab2cb296e02d42c4c66b3f11b65797340d19fa6590f5b287da1
|
||||
F ext/wasm/jaccwabyt/jaccwabyt.js 1e734c624205cdf621f322972dfb0fc8013d573a5882f57492a6830e5ec23e17
|
||||
F ext/wasm/jaccwabyt/jaccwabyt.md 167fc0b624c9bc2c477846e336de9403842d81b1a24fc4d3b24317cb9eba734f
|
||||
F ext/wasm/jaccwabyt/jaccwabyt.js 4e2b797dc170851c9c530c3567679f4aa509eec0fab73b466d945b00b356574b
|
||||
F ext/wasm/jaccwabyt/jaccwabyt.md 6aa90fa1a973d0ad10d077088bea163b241d8470c75eafdef87620a1de1dea41
|
||||
F ext/wasm/mkdist.sh 64d53f469c823ed311f6696f69cec9093f745e467334b34f5ceabdf9de3c5b28 x
|
||||
F ext/wasm/mkwasmbuilds.c ef42e404236dd98cedb6ecea47b6d2474e3c593633ce6d992d316289dfc442b6
|
||||
F ext/wasm/module-symbols.html e54f42112e0aac2a31f850ab33e7f2630a2ea4f63496f484a12469a2501e07e2
|
||||
@@ -646,7 +647,7 @@ F ext/wasm/test-opfs-vfs.html 1f2d672f3f3fce810dfd48a8d56914aba22e45c6834e262555
|
||||
F ext/wasm/test-opfs-vfs.js 1618670e466f424aa289859fe0ec8ded223e42e9e69b5c851f809baaaca1a00c
|
||||
F ext/wasm/tester1-worker.c-pp.html 0e432ec2c0d99cd470484337066e8d27e7aee4641d97115338f7d962bf7b081a
|
||||
F ext/wasm/tester1.c-pp.html 52d88fe2c6f21a046030a36410b4839b632f4424028197a45a3d5669ea724ddb
|
||||
F ext/wasm/tester1.c-pp.js 2c255093205a0dac9dae7475030665c2c9d6dccc857de68ee7daf49aa82e6de8
|
||||
F ext/wasm/tester1.c-pp.js 015b4133cc3a5fb41d6236a6b39d23d996cc2d61a4877acde31a1f69574d4ce3
|
||||
F ext/wasm/tests/opfs/concurrency/index.html 657578a6e9ce1e9b8be951549ed93a6a471f4520a99e5b545928668f4285fb5e
|
||||
F ext/wasm/tests/opfs/concurrency/test.js d08889a5bb6e61937d0b8cbb78c9efbefbf65ad09f510589c779b7cc6a803a88
|
||||
F ext/wasm/tests/opfs/concurrency/worker.js 0a8c1a3e6ebb38aabbee24f122693f1fb29d599948915c76906681bb7da1d3d2
|
||||
@@ -656,7 +657,8 @@ 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 27a0769b40a813343f19e8fca2e9d55405f0311cb3cc5327f5702640df0182a0
|
||||
F main.mk 822f9eda3e689748341597f4327a071c2b0ce41cc3ed477d72f2560b956eb5c0
|
||||
F make.bat a136fd0b1c93e89854a86d5f4edcf0386d211e5d5ec2434480f6eea436c7420c
|
||||
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
|
||||
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
|
||||
F mptest/crash01.test 61e61469e257df0850df4293d7d4d6c2af301421
|
||||
@@ -666,7 +668,7 @@ F mptest/multiwrite01.test dab5c5f8f9534971efce679152c5146da265222d
|
||||
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||
F sqlite3.1 1b9c24374a85dfc7eb8fa7c4266ee0db4f9609cceecfc5481cd8307e5af04366
|
||||
F sqlite3.pc.in e6dee284fba59ef500092fdc1843df3be8433323a3733c91da96690a50a5b398
|
||||
F src/alter.c a02edd673c242698f42eecf150a0c6eef11d1cc8ebf555d5c0e9f2847c0e9e9d
|
||||
F src/alter.c 06a27ab1cc064f5c6647e7fadfb12c8d7cafd35de1751f12419e1f2b28037540
|
||||
F src/analyze.c 03bcfc083fc0cccaa9ded93604e1d4244ea245c17285d463ef6a60425fcb247d
|
||||
F src/attach.c 7cf07d4fa42b9fc8662237c60c40b730326c30aa90ae5fffc0b18b2d726ebf61
|
||||
F src/auth.c 54ab9c6c5803b47c0d45b76ce27eff22a03b4b1f767c5945a3a4eb13aa4c78dc
|
||||
@@ -676,7 +678,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 611e07299d72ff04bbcb9e7109183467e30925d203c3e121ef9bb3cf6876289b
|
||||
F src/build.c 4e1afafc56504ed6253e1b115c1502de4243c2287a0c799f4967fcd2d7716ad9
|
||||
F src/callback.c 3605bbf02bd7ed46c79cd48346db4a32fc51d67624400539c0532f4eead804ad
|
||||
F src/carray.c ff6081a31878fc34df8fa1052a9cbf17ddc22652544dcb3e2326886ed1053b55
|
||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||
@@ -691,7 +693,7 @@ F src/func.c 0b802107498048d3dcac0b757720bcb8506507ce02159e213ab8161458eb293b
|
||||
F src/global.c a19e4b1ca1335f560e9560e590fc13081e21f670643367f99cb9e8f9dc7d615b
|
||||
F src/hash.c 03c8c0f4be9e8bcb6de65aa26d34a61d48a9430747084a69f9469fbb00ea52ca
|
||||
F src/hash.h 46b92795a95bfefb210f52f0c316e9d7cdbcdd7e7fcfb0d8be796d3a5767cddf
|
||||
F src/hwtime.h d4d1b98c1afdc56986a5c0eba882786ef017e2180a320da25b4231b8e7e463e8
|
||||
F src/hwtime.h 21c2cf1f736e7b97502c3674d0c386db3f06870d6f10d0cf8174e2a4b8cb726e
|
||||
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
||||
F src/insert.c dfd311b0ac2d4f6359e62013db67799757f4d2cc56cca5c10f4888acfbbfa3fd
|
||||
F src/json.c fb031340edee159c07ad37dbe668ffe945ed86f525b0eb3822e4a67cbc498a72
|
||||
@@ -723,26 +725,26 @@ F src/os_win.c a89b501fc195085c7d6c9eec7f5bd782625e94bb2a96b000f4d009703df1083f
|
||||
F src/os_win.h 4c247cdb6d407c75186c94a1e84d5a22cbae4adcec93fcae8d2bc1f956fd1f19
|
||||
F src/pager.c a81461de271ac4886ad75b7ca2cca8157a48635820c4646cd2714acdc2c17e5f
|
||||
F src/pager.h 6137149346e6c8a3ddc1eeb40aee46381e9bc8b0fcc6dda8a1efde993c2275b8
|
||||
F src/parse.y 19ad77af6cd14c3b58d2979415c30de94172aa73c4cb1fd33f38407cfb2c311d
|
||||
F src/parse.y e31046636c50ba4a1cf4d12c7a6112a31b11975b1ade84a45f2109a30e8f358d
|
||||
F src/pcache.c 588cc3c5ccaaadde689ed35ce5c5c891a1f7b1f4d1f56f6cf0143b74d8ee6484
|
||||
F src/pcache.h 1497ce1b823cf00094bb0cf3bac37b345937e6f910890c626b16512316d3abf5
|
||||
F src/pcache1.c 131ca0daf4e66b4608d2945ae76d6ed90de3f60539afbd5ef9ec65667a5f2fcd
|
||||
F src/pragma.c ecec75795c1821520266e4f93fa8840cce48979af532db06f085e36a7813860f
|
||||
F src/prepare.c 2af0b5c1ec787c8eebd21baa9d79caf4a4dc3a18e76ce2edbf2027d706bca37a
|
||||
F src/prepare.c f6a6e28a281bd1d1da12f47d370a81af46159b40f73bf7fa0b276b664f9c8b7d
|
||||
F src/printf.c b1b29b5e58e1530d5daeee5963d3c318d8ab2d7e38437580e28755753e0c1ded
|
||||
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 4fdceb103ba8761bf3d68108c3a6e6499be913a2490a7c384ee79ee547a9517c
|
||||
F src/sqlite.h.in f1363321ca55cc2feaa289e9fe6dfb08102a28c54edf005564711a2348b06eef
|
||||
F src/select.c 6a509cddd815d64f6141e539fff633a518a393772a44dffb4490f7fc3f0d83a9
|
||||
F src/shell.c.in 8ec8bf61a3322c5e29c286d4aecbc82e25157df9244cb1a1a1c4e2c49de8b64d
|
||||
F src/sqlite.h.in 706cacea5308b0244fb6cec92e08310fb427a125375c64137cc1f878ae4cf5c0
|
||||
F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479
|
||||
F src/sqlite3ext.h 5d5330f5f8461f5ce74960436ddcfa53ecd09c2b8b23901e22ae38aec3243998
|
||||
F src/sqliteInt.h 993fed08967a58d906093bae969e4831e051afcf36f15c90e16f14fa7d772eaf
|
||||
F src/sqliteInt.h f8b6a6bdb92aaeeedd768d27650a39f543c4b7cc66534c564e2ec249ed80e210
|
||||
F src/sqliteLimit.h 0a5516b4ec192a205c541e05f67009028a9451dc6678aae4cf8e68596903c246
|
||||
F src/status.c 7565d63a79aa2f326339a24a0461a60096d0bd2bce711fefb50b5c89335f3592
|
||||
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
|
||||
F src/tclsqlite.c 381384fbe3cf342115f9ad01208fa81092e9a2156a4ea4d44de87852b8df3a8a
|
||||
F src/tclsqlite.c ec2ad3fbf5390c3d4307bc9d1f2a37a9c5d726b5309769dc770ab37f6812152d
|
||||
F src/tclsqlite.h 614b3780a62522bc9f8f2b9fb22689e8009958e7aa77e572d0f3149050af348a
|
||||
F src/test1.c 0e71fbcb484a271564e98e0158192c28c24f5521594218c3ba48bcb4cf634f91
|
||||
F src/test2.c 62f0830958f9075692c29c6de51b495ae8969e1bef85f239ffcd9ba5fb44a5ff
|
||||
@@ -792,7 +794,7 @@ F src/test_vfs.c b4135c1308516adf0dfd494e6d6c33114e03732be899eace0502919b674586b
|
||||
F src/test_window.c 6d80e11fba89a1796525e6f0048ff0c7789aa2c6b0b11c80827dc1437bd8ea72
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
|
||||
F src/tokenize.c cb3294cf23c11106b50d9af6998a6c1bf389b52e15b17698c9fab97bbaa9b37f
|
||||
F src/tokenize.c ca1382f02a3990d1a770acd5c55731dee10cd644465b2855eca33e4d2ea299ed
|
||||
F src/treeview.c 3ce7ac9835d2d70cc1c868b01b747ae8a062322e155701e58e3d62ca79aada7a
|
||||
F src/trigger.c 4983328a32feff8774503da634688aad96c7febf1e838ce9df92c3672f1fa64f
|
||||
F src/update.c 3e5e7ff66fa19ebe4d1b113d480639a24cc1175adbefabbd1a948a07f28e37cf
|
||||
@@ -834,12 +836,14 @@ F test/alter2.test 7e3d26ab409df52df887b366a63902c3429b935c41cb962fd58ffc25784f2
|
||||
F test/alter3.test dcdd5f850f30656a45a0f05e41abfb52b74bbf6ccba165d0f7adf6b0116e4fd6
|
||||
F test/alter4.test 37cafe164067a6590a0ee4cec780bddbbaa33dc50b11542dcfbe0e65626494fd
|
||||
F test/alterauth.test 63442ba61ceb0c1eeb63aac1f4f5cebfa509d352276059d27106ae256bafc959
|
||||
F test/alterauth2.test 48967abae0494d9a300d1c92473d99fcb66edfcc23579c89322f033f49410adc
|
||||
F test/altercol.test b43fb5725332f4cf8cff0280605202c1672e808281accea60a066d2ccc5129e5
|
||||
F test/alterauth2.test 4b74fa8f184f4736497317feb587b65759eb87d87acfe3a8ef433d4d18bb002b
|
||||
F test/altercol.test 3661c432aacb42bc2198dd4611bbb9c3b09fc73251b59edda046109103b8ac00
|
||||
F test/altercons.test ea18def4a0f26b9066da56095c9c480df705df4d02e4ae151708fae76f7e3884
|
||||
F test/altercons2.test 3c1f58312817df43aeada3b1827fdc3ce3fc50c6f49a95ef62cf4cbbae8583a0
|
||||
F test/altercorrupt.test 2e1d705342cf9d7de884518ddbb053fd52d7e60d2b8869b7b63b2fda68435c12
|
||||
F test/alterdropcol.test a653a3945f964d26845ec0cd0a8e74189f46de3119a984c5bc45457da392612e
|
||||
F test/alterdropcol2.test 527fce683b200d620f560f666c44ae33e22728e990a10a48a543280dfd4b4d41
|
||||
F test/alterfault.test 6bf0a5ff9eaa1ba1f654e5263c1ea6f2d2e1216c8cd046476fed571abd579cdf
|
||||
F test/alterfault.test 2bb3103954ea60f2e2777b1ae12e79ec3e1fd278f2b1398ad316c68835a62898
|
||||
F test/alterlegacy.test f38c6d06cda39e1f7b955bbce57f2e3ef5b7cb566d3d1234502093e228c15811
|
||||
F test/altermalloc.test 167a47de41b5c638f5f5c6efb59784002b196fff70f98d9b4ed3cd74a3fb80c9
|
||||
F test/altermalloc2.test 17fb3724c4b004c469c27dc4ef181608aa644555fbd3f3236767584f73747c81
|
||||
@@ -1209,7 +1213,7 @@ F test/fts4merge.test 57d093660a5093ae6e9fbd2d17592a88b45bbd66db2703c4b640b28828
|
||||
F test/fts4merge2.test 5faa558d1b672f82b847d2a337465fa745e46891
|
||||
F test/fts4merge3.test 8d9ccb4a3d41c4c617a149d6c4b13ad02de797d0
|
||||
F test/fts4merge4.test 66fce89934cd9508cbdc67de486558c34912ffb2e8ffe5c9a1bbb9b8a4408ba7
|
||||
F test/fts4merge5.test 69932d85cda8a1c4dcfb742865900ed8fbda51724b8cf9a45bbe226dfd06c596
|
||||
F test/fts4merge5.test 987af90c930e8555f74ab994f597431caec7f8defc52de7718655c32da07af9e
|
||||
F test/fts4min.test 1c11e4bde16674a0c795953509cbc3731a7d9cbd1ddc7f35467bf39d632d749f
|
||||
F test/fts4noti.test d5d933705b1b1516b67a5e3f8e514ecb19c6522fb3357bb744776d48427c2292
|
||||
F test/fts4onepass.test d69ddc4ee3415e40b0c5d1d0408488a87614d4f63ba9c44f3e52db541d6b7cc7
|
||||
@@ -1436,7 +1440,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/modeA.clitest e0c63c28e2651dd322e21de683fec7d247028b80f7a753663244ba0087215dc8
|
||||
F test/multiplex.test d74c034e52805f6de8cc5432cef8c9eb774bb64ec29b83a22effc8ca4dac1f08
|
||||
F test/multiplex2.test 580ca5817c7edbe4cc68fa150609c9473393003a
|
||||
F test/multiplex3.test fac575e0b1b852025575a6a8357701d80933e98b5d2fe6d35ddaa68f92f6a1f7
|
||||
@@ -1506,9 +1510,10 @@ 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/qrf01.test 48c86e90f606739e67b73937babb662ef0edf1ede06954489c588815fa17b560
|
||||
F test/qrf02.test 39b4afdc000bedccdafc0aecf17638df67a67aaa2d2942865ae6abcc48ba0e92
|
||||
F test/qrf03.test 9d88aeb5cdd53f050b7ab9bd203281f7c9d063c33f22f8808e441b7ac0874ccf
|
||||
F test/qrf03.test ad7fa339fb46b26b08625f3a77a4827bdee9f0dad402d8ddc1fcb8f05aa64a54
|
||||
F test/qrf04.test 0894692c998d2401dcc33449c02051b503ecce0c94217be54fb007c82d2d1379
|
||||
F test/queryonly.test 5f653159e0f552f0552d43259890c1089391dcca
|
||||
F test/quick.test 1681febc928d686362d50057c642f77a02c62e57
|
||||
F test/quickcheck.test a4b7e878cd97e46108291c409b0bf8214f29e18fddd68a42bc5c1375ad1fb80a
|
||||
@@ -1602,7 +1607,7 @@ 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 8fbb73650b685766cdf4b5e8b5d12dee72664f44195eeb788d0f52fce08e04eb
|
||||
F test/shell1.test f377091779c4099619e78e1f55a0a12513eaac55d5073a14ca6545c6742c746c
|
||||
F test/shell2.test 103140814bdc7508aa41dd3462413cbc4aa84b4261112cb8d501d74275cb7d48
|
||||
F test/shell3.test 840192774cc4edf7653520c0434a311c7477b9bc324abbc7bd2887915792fa8c
|
||||
F test/shell4.test e25580a792b7b54560c3a76b6968bd8189261f38979fe28e6bc6312c5db280db
|
||||
@@ -1611,8 +1616,8 @@ F test/shell6.test e3b883b61d4916b6906678a35f9d19054861123ad91b856461e0a456273bd
|
||||
F test/shell7.test 43fd8e511c533bab5232e95c7b4be93b243451709e89582600d4b6e67693d5c3
|
||||
F test/shell8.test 641cf21a99c59404c24e3062923734951c4099a6b6b6520de00cf7a1249ee871
|
||||
F test/shell9.test 8742a5b390cdcef6369f5aa223e415aa4255a4129ef249b177887dc635a87209
|
||||
F test/shellA.test 4ece22f204532fb04ab702c5b9c70d8680ff610bff1e82c849c16a7b5cd57d83
|
||||
F test/shellB.test ca8a5ce5b9a59098732fa140c911162f0306f70239c6c2de6da9b718ca304cad
|
||||
F test/shellA.test 4f57da76ed1f6d4a4eba0b2a27cdef4c756f1da2c813dc7034079e4df493110f
|
||||
F test/shellB.test de879b1ea7c25daf1a06b2c882b45a5d002e6580c81c57169ce47084cc6afb6b
|
||||
F test/shmlock.test 9f1f729a7fe2c46c88b156af819ac9b72c0714ac6f7246638a73c5752b5fd13c
|
||||
F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3
|
||||
F test/show_speedtest1_rtree.tcl 32e6c5f073d7426148a6936a0408f4b5b169aba5
|
||||
@@ -1697,7 +1702,7 @@ F test/temptrigfault.tes fc5918e64f3867156fefe7cfca9d8e1f495134a5229b2b511b0dc11
|
||||
F test/temptrigger.test a00f258ed8d21a0e8fd4f322f15e8cfb5cef2e43655670e07a753e3fb4769d61
|
||||
F test/tester.tcl 463ae33b8bf75ac77451df19bd65e7c415c2e9891227c7c9e657d0a2d8e1074a
|
||||
F test/testloadext.c 862b848783eaed9985fbce46c65cd214664376b549fae252b364d5d1ef350a27
|
||||
F test/testrunner.tcl 86179a8e78997e9257cb8f738c5624cb23897da5297855578ba74715e64f1602 x
|
||||
F test/testrunner.tcl 6cbda5d6ff9b26b11993f1e1ddd57d9521cec7c31676ad323a40a6821ce43ad6 x
|
||||
F test/testrunner_data.tcl c507a9afa911c03446ed90442ffd4a98aca02882c3d51bd1177c24795674def8
|
||||
F test/testrunner_estwork.tcl 81e2ae10238f50540f42fbf2d94913052a99bfb494b69e546506323f195dcff9
|
||||
F test/thread001.test a0985c117eab62c0c65526e9fa5d1360dd1cac5b03bde223902763274ce21899
|
||||
@@ -2122,7 +2127,7 @@ F tool/mkautoconfamal.sh 647dada5e34c466bef62a4408e1c99a7e5e1922805479dd57944f33
|
||||
F tool/mkccode.tcl c42a8f8cf78f92e83795d5447460dbce7aaf78a3bbf9082f1507dc71a3665f3c x
|
||||
F tool/mkcombo.tcl 2a5189b219c4a495e1ff7fc980bd568d3cfb82ae9d50c84e77f7a161e96fc132
|
||||
F tool/mkctimec.tcl 3fb5cad05922f5da61262cb6bcd5868a34e94a49ca8833ae2d7796e7df075576 x
|
||||
F tool/mkkeywordhash.c 6b0be901c47f9ad42215fc995eb2f4384ac49213b1fba395102ec3e999acf559
|
||||
F tool/mkkeywordhash.c 82d5af1d0e677900739fba59155cddac172d8c712c2d91ab73d6e6bcb30060f0
|
||||
F tool/mkmsvcmin.tcl d76c45efda1cce2d4005bcea7b8a22bb752e3256009f331120fb4fecb14ebb7a
|
||||
F tool/mkopcodec.tcl 33d20791e191df43209b77d37f0ff0904620b28465cca6990cf8d60da61a07ef
|
||||
F tool/mkopcodeh.tcl 2b4e6967a670ef21bf53a164964c35c6163277d002a4c6f56fa231d68c88d023
|
||||
@@ -2176,8 +2181,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 c4cc80eb281f7c8da3d62fec03b2258ce8d0063fc9cfff61f2cbcdd01e13c391
|
||||
R 2c80bedbc8d39f5ed20d2f9111a22a22
|
||||
P 951b4533509fae971e252be3ecd3623ac2bdce16220e0ce372e600f728f80f69 65202440874a7fea5aba262e8e78b97c833147d47837a99f301eca968f9a78b1
|
||||
R 83ef1a079a33c33622b152a79e70f1ed
|
||||
U dan
|
||||
Z 4cc55d003d3e663865fa89fedb536d6f
|
||||
Z 628c58958f6e69e505f16b7101c16084
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
+1
-1
@@ -1 +1 @@
|
||||
951b4533509fae971e252be3ecd3623ac2bdce16220e0ce372e600f728f80f69
|
||||
230fd5533e07ec36f1938f34153c9ef97a7acd6604d023b56dfc5269ca6173c2
|
||||
+725
-4
@@ -491,7 +491,7 @@ void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
|
||||
/* Look up the table being altered. */
|
||||
assert( pParse->pNewTable==0 );
|
||||
assert( sqlite3BtreeHoldsAllMutexes(db) );
|
||||
if( db->mallocFailed ) goto exit_begin_add_column;
|
||||
if( NEVER(db->mallocFailed) ) goto exit_begin_add_column;
|
||||
pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]);
|
||||
if( !pTab ) goto exit_begin_add_column;
|
||||
|
||||
@@ -563,7 +563,7 @@ exit_begin_add_column:
|
||||
** Or, if pTab is not a view or virtual table, zero is returned.
|
||||
*/
|
||||
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)
|
||||
static int isRealTable(Parse *pParse, Table *pTab, int bDrop){
|
||||
static int isRealTable(Parse *pParse, Table *pTab, int iOp){
|
||||
const char *zType = 0;
|
||||
#ifndef SQLITE_OMIT_VIEW
|
||||
if( IsView(pTab) ){
|
||||
@@ -576,9 +576,12 @@ static int isRealTable(Parse *pParse, Table *pTab, int bDrop){
|
||||
}
|
||||
#endif
|
||||
if( zType ){
|
||||
const char *azMsg[] = {
|
||||
"rename columns of", "drop column from", "edit constraints of"
|
||||
};
|
||||
assert( iOp>=0 && iOp<ArraySize(azMsg) );
|
||||
sqlite3ErrorMsg(pParse, "cannot %s %s \"%s\"",
|
||||
(bDrop ? "drop column from" : "rename columns of"),
|
||||
zType, pTab->zName
|
||||
azMsg[iOp], zType, pTab->zName
|
||||
);
|
||||
return 1;
|
||||
}
|
||||
@@ -1049,6 +1052,25 @@ static RenameToken *renameColumnTokenNext(RenameCtx *pCtx){
|
||||
return pBest;
|
||||
}
|
||||
|
||||
/*
|
||||
** Set the error message of the context passed as the first argument to
|
||||
** the result of formatting zFmt using printf() style formatting.
|
||||
*/
|
||||
static void errorMPrintf(sqlite3_context *pCtx, const char *zFmt, ...){
|
||||
sqlite3 *db = sqlite3_context_db_handle(pCtx);
|
||||
char *zErr = 0;
|
||||
va_list ap;
|
||||
va_start(ap, zFmt);
|
||||
zErr = sqlite3VMPrintf(db, zFmt, ap);
|
||||
va_end(ap);
|
||||
if( zErr ){
|
||||
sqlite3_result_error(pCtx, zErr, -1);
|
||||
sqlite3DbFree(db, zErr);
|
||||
}else{
|
||||
sqlite3_result_error_nomem(pCtx);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** An error occurred while parsing or otherwise processing a database
|
||||
** object (either pParse->pNewTable, pNewIndex or pNewTrigger) as part of an
|
||||
@@ -2309,6 +2331,701 @@ exit_drop_column:
|
||||
sqlite3SrcListDelete(db, pSrc);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the number of bytes of leading whitespace/comments in string z[].
|
||||
*/
|
||||
static int getWhitespace(const u8 *z){
|
||||
int nRet = 0;
|
||||
while( 1 ){
|
||||
int t = 0;
|
||||
int n = sqlite3GetToken(&z[nRet], &t);
|
||||
if( t!=TK_SPACE && t!=TK_COMMENT ) break;
|
||||
nRet += n;
|
||||
}
|
||||
return nRet;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Return the number of bytes until the end of the next non-whitespace and
|
||||
** non-comment token. For the purpose of this function, a "(" token includes
|
||||
** all of the bytes through and including the matching ")", or until the
|
||||
** first illegal token, whichever comes first.
|
||||
**
|
||||
** Write the token type into *piToken.
|
||||
**
|
||||
** The value returned is the number of bytes in the token itself plus
|
||||
** the number of bytes of leading whitespace and comments skipped plus
|
||||
** all bytes through the next matching ")" if the token is TK_LP.
|
||||
**
|
||||
** Example: (Note: '.' used in place of '*' in the example z[] text)
|
||||
**
|
||||
** ,--------- *piToken := TK_RP
|
||||
** v
|
||||
** z[] = " /.comment./ --comment\n (two three four) five"
|
||||
** | |
|
||||
** |<-------------------------------------->|
|
||||
** |
|
||||
** `--- return value
|
||||
*/
|
||||
static int getConstraintToken(const u8 *z, int *piToken){
|
||||
int iOff = 0;
|
||||
int t = 0;
|
||||
do {
|
||||
iOff += sqlite3GetToken(&z[iOff], &t);
|
||||
}while( t==TK_SPACE || t==TK_COMMENT );
|
||||
|
||||
*piToken = t;
|
||||
|
||||
if( t==TK_LP ){
|
||||
int nNest = 1;
|
||||
while( nNest>0 ){
|
||||
iOff += sqlite3GetToken(&z[iOff], &t);
|
||||
if( t==TK_LP ){
|
||||
nNest++;
|
||||
}else if( t==TK_RP ){
|
||||
t = TK_LP;
|
||||
nNest--;
|
||||
}else if( t==TK_ILLEGAL ){
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*piToken = t;
|
||||
return iOff;
|
||||
}
|
||||
|
||||
/*
|
||||
** Argument z points into the body of a constraint - specifically the
|
||||
** second token of the constraint definition. For a named constraint,
|
||||
** z points to the first token past the CONSTRAINT keyword. For an
|
||||
** unnamed NOT NULL constraint, z points to the first byte past the NOT
|
||||
** keyword.
|
||||
**
|
||||
** Return the number of bytes until the end of the constraint.
|
||||
*/
|
||||
static int getConstraint(const u8 *z){
|
||||
int iOff = 0;
|
||||
int t = 0;
|
||||
|
||||
/* Now, the current constraint proceeds until the next occurence of one
|
||||
** of the following tokens:
|
||||
**
|
||||
** CONSTRAINT, PRIMARY, NOT, UNIQUE, CHECK, DEFAULT,
|
||||
** COLLATE, REFERENCES, FOREIGN, GENERATED, AS, RP, or COMMA
|
||||
**
|
||||
** Also exit the loop if ILLEGAL turns up.
|
||||
*/
|
||||
while( 1 ){
|
||||
int n = getConstraintToken(&z[iOff], &t);
|
||||
if( t==TK_CONSTRAINT || t==TK_PRIMARY || t==TK_NOT || t==TK_UNIQUE
|
||||
|| t==TK_CHECK || t==TK_DEFAULT || t==TK_COLLATE || t==TK_REFERENCES
|
||||
|| t==TK_FOREIGN || t==TK_RP || t==TK_COMMA || t==TK_ILLEGAL
|
||||
|| t==TK_AS || t==TK_GENERATED
|
||||
){
|
||||
break;
|
||||
}
|
||||
iOff += n;
|
||||
}
|
||||
|
||||
return iOff;
|
||||
}
|
||||
|
||||
/*
|
||||
** Compare two constraint names.
|
||||
**
|
||||
** Summary: *pRes := zQuote != zCmp
|
||||
**
|
||||
** Details:
|
||||
** Compare the (possibly quoted) constraint name zQuote[0..nQuote-1]
|
||||
** against zCmp[]. Write zero into *pRes if they are the same and
|
||||
** non-zero if they differ. Normally return SQLITE_OK, except if there
|
||||
** is an OOM, set the OOM error condition on ctx and return SQLITE_NOMEM.
|
||||
*/
|
||||
static int quotedCompare(
|
||||
sqlite3_context *ctx, /* Function context on which to report errors */
|
||||
int t, /* Token type */
|
||||
const u8 *zQuote, /* Possibly quoted text. Not zero-terminated. */
|
||||
int nQuote, /* Length of zQuote in bytes */
|
||||
const u8 *zCmp, /* Zero-terminated, unquoted name to compare against */
|
||||
int *pRes /* OUT: Set to 0 if equal, non-zero if unequal */
|
||||
){
|
||||
char *zCopy = 0; /* De-quoted, zero-terminated copy of zQuote[] */
|
||||
|
||||
if( t==TK_ILLEGAL ){
|
||||
*pRes = 1;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
zCopy = sqlite3MallocZero(nQuote+1);
|
||||
if( zCopy==0 ){
|
||||
sqlite3_result_error_nomem(ctx);
|
||||
return SQLITE_NOMEM_BKPT;
|
||||
}
|
||||
memcpy(zCopy, zQuote, nQuote);
|
||||
sqlite3Dequote(zCopy);
|
||||
*pRes = sqlite3_stricmp((const char*)zCopy, (const char*)zCmp);
|
||||
sqlite3_free(zCopy);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** zSql[] is a CREATE TABLE statement, supposedly. Find the offset
|
||||
** into zSql[] of the first character past the first "(" and write
|
||||
** that offset into *piOff and return SQLITE_OK. Or, if not found,
|
||||
** set the SQLITE_CORRUPT error code and return SQLITE_ERROR.
|
||||
*/
|
||||
static int skipCreateTable(sqlite3_context *ctx, const u8 *zSql, int *piOff){
|
||||
int iOff = 0;
|
||||
|
||||
if( zSql==0 ) return SQLITE_ERROR;
|
||||
|
||||
/* Jump past the "CREATE TABLE" bit. */
|
||||
while( 1 ){
|
||||
int t = 0;
|
||||
iOff += sqlite3GetToken(&zSql[iOff], &t);
|
||||
if( t==TK_LP ) break;
|
||||
if( t==TK_ILLEGAL ){
|
||||
sqlite3_result_error_code(ctx, SQLITE_CORRUPT_BKPT);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
*piOff = iOff;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Internal SQL function sqlite3_drop_constraint(): Given an input
|
||||
** CREATE TABLE statement, return a revised CREATE TABLE statement
|
||||
** with a constraint removed. Two forms, depending on the datatype
|
||||
** of argv[2]:
|
||||
**
|
||||
** sqlite_drop_constraint(SQL, INT) -- Omit NOT NULL from the INT-th column
|
||||
** sqlite_drop_constraint(SQL, TEXT) -- OMIT constraint with name TEXT
|
||||
**
|
||||
** In the first case, the left-most column is 0.
|
||||
*/
|
||||
static void dropConstraintFunc(
|
||||
sqlite3_context *ctx,
|
||||
int NotUsed,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
const u8 *zSql = sqlite3_value_text(argv[0]);
|
||||
const u8 *zCons = 0;
|
||||
int iNotNull = -1;
|
||||
int ii;
|
||||
int iOff = 0;
|
||||
int iStart = 0;
|
||||
int iEnd = 0;
|
||||
char *zNew = 0;
|
||||
int t = 0;
|
||||
sqlite3 *db;
|
||||
UNUSED_PARAMETER(NotUsed);
|
||||
|
||||
if( zSql==0 ) return;
|
||||
|
||||
/* Jump past the "CREATE TABLE" bit. */
|
||||
if( skipCreateTable(ctx, zSql, &iOff) ) return;
|
||||
|
||||
if( sqlite3_value_type(argv[1])==SQLITE_INTEGER ){
|
||||
iNotNull = sqlite3_value_int(argv[1]);
|
||||
}else{
|
||||
zCons = sqlite3_value_text(argv[1]);
|
||||
}
|
||||
|
||||
/* Search for the named constraint within column definitions. */
|
||||
for(ii=0; iEnd==0; ii++){
|
||||
|
||||
/* Now parse the column or table constraint definition. Search
|
||||
** for the token CONSTRAINT if this is a DROP CONSTRAINT command, or
|
||||
** NOT in the right column if this is a DROP NOT NULL. */
|
||||
while( 1 ){
|
||||
iStart = iOff;
|
||||
iOff += getConstraintToken(&zSql[iOff], &t);
|
||||
if( t==TK_CONSTRAINT && (zCons || iNotNull==ii) ){
|
||||
/* Check if this is the constraint we are searching for. */
|
||||
int nTok = 0;
|
||||
int cmp = 1;
|
||||
|
||||
/* Skip past any whitespace. */
|
||||
iOff += getWhitespace(&zSql[iOff]);
|
||||
|
||||
/* Compare the next token - which may be quoted - with the name of
|
||||
** the constraint being dropped. */
|
||||
nTok = getConstraintToken(&zSql[iOff], &t);
|
||||
if( zCons ){
|
||||
if( quotedCompare(ctx, t, &zSql[iOff], nTok, zCons, &cmp) ) return;
|
||||
}
|
||||
iOff += nTok;
|
||||
|
||||
/* The next token is usually the first token of the constraint
|
||||
** definition. This is enough to tell the type of the constraint -
|
||||
** TK_NOT means it is a NOT NULL, TK_CHECK a CHECK constraint etc.
|
||||
**
|
||||
** There is also the chance that the next token is TK_CONSTRAINT
|
||||
** (or TK_DEFAULT or TK_COLLATE), for example if a table has been
|
||||
** created as follows:
|
||||
**
|
||||
** CREATE TABLE t1(cols, CONSTRAINT one CONSTRAINT two NOT NULL);
|
||||
**
|
||||
** In this case, allow the "CONSTRAINT one" bit to be dropped by
|
||||
** this command if that is what is requested, or to advance to
|
||||
** the next iteration of the loop with &zSql[iOff] still pointing
|
||||
** to the CONSTRAINT keyword. */
|
||||
nTok = getConstraintToken(&zSql[iOff], &t);
|
||||
if( t==TK_CONSTRAINT || t==TK_DEFAULT || t==TK_COLLATE
|
||||
|| t==TK_COMMA || t==TK_RP || t==TK_GENERATED || t==TK_AS
|
||||
){
|
||||
t = TK_CHECK;
|
||||
}else{
|
||||
iOff += nTok;
|
||||
iOff += getConstraint(&zSql[iOff]);
|
||||
}
|
||||
|
||||
if( cmp==0 || (iNotNull>=0 && t==TK_NOT) ){
|
||||
if( t!=TK_NOT && t!=TK_CHECK ){
|
||||
errorMPrintf(ctx, "constraint may not be dropped: %s", zCons);
|
||||
return;
|
||||
}
|
||||
iEnd = iOff;
|
||||
break;
|
||||
}
|
||||
|
||||
}else if( t==TK_NOT && iNotNull==ii ){
|
||||
iEnd = iOff + getConstraint(&zSql[iOff]);
|
||||
break;
|
||||
}else if( t==TK_RP || t==TK_ILLEGAL ){
|
||||
iEnd = -1;
|
||||
break;
|
||||
}else if( t==TK_COMMA ){
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If the constraint has not been found it is an error. */
|
||||
if( iEnd<=0 ){
|
||||
if( zCons ){
|
||||
errorMPrintf(ctx, "no such constraint: %s", zCons);
|
||||
}else{
|
||||
/* SQLite follows postgres in that a DROP NOT NULL on a column that is
|
||||
** not NOT NULL is not an error. So just return the original SQL here. */
|
||||
sqlite3_result_text(ctx, (const char*)zSql, -1, SQLITE_TRANSIENT);
|
||||
}
|
||||
}else{
|
||||
|
||||
/* Figure out if an extra space should be inserted after the constraint
|
||||
** is removed. And if an additional comma preceding the constraint
|
||||
** should be removed. */
|
||||
const char *zSpace = " ";
|
||||
iEnd += getWhitespace(&zSql[iEnd]);
|
||||
sqlite3GetToken(&zSql[iEnd], &t);
|
||||
if( t==TK_RP || t==TK_COMMA ){
|
||||
zSpace = "";
|
||||
if( zSql[iStart-1]==',' ) iStart--;
|
||||
}
|
||||
|
||||
db = sqlite3_context_db_handle(ctx);
|
||||
zNew = sqlite3MPrintf(db, "%.*s%s%s", iStart, zSql, zSpace, &zSql[iEnd]);
|
||||
sqlite3_result_text(ctx, zNew, -1, SQLITE_DYNAMIC);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Internal SQL function:
|
||||
**
|
||||
** sqlite_add_constraint(SQL, CONSTRAINT-TEXT, ICOL)
|
||||
**
|
||||
** SQL is a CREATE TABLE statement. Return a modified version of
|
||||
** SQL that adds CONSTRAINT-TEXT at the end of the ICOL-th column
|
||||
** definition. (The left-most column defintion is 0.)
|
||||
*/
|
||||
static void addConstraintFunc(
|
||||
sqlite3_context *ctx,
|
||||
int NotUsed,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
const u8 *zSql = sqlite3_value_text(argv[0]);
|
||||
const char *zCons = (const char*)sqlite3_value_text(argv[1]);
|
||||
int iCol = sqlite3_value_int(argv[2]);
|
||||
int iOff = 0;
|
||||
int ii;
|
||||
char *zNew = 0;
|
||||
int t = 0;
|
||||
sqlite3 *db;
|
||||
UNUSED_PARAMETER(NotUsed);
|
||||
|
||||
if( skipCreateTable(ctx, zSql, &iOff) ) return;
|
||||
|
||||
for(ii=0; ii<=iCol || (iCol<0 && t!=TK_RP); ii++){
|
||||
iOff += getConstraintToken(&zSql[iOff], &t);
|
||||
while( 1 ){
|
||||
int nTok = getConstraintToken(&zSql[iOff], &t);
|
||||
if( t==TK_COMMA || t==TK_RP ) break;
|
||||
if( t==TK_ILLEGAL ){
|
||||
sqlite3_result_error_code(ctx, SQLITE_CORRUPT_BKPT);
|
||||
return;
|
||||
}
|
||||
iOff += nTok;
|
||||
}
|
||||
}
|
||||
|
||||
iOff += getWhitespace(&zSql[iOff]);
|
||||
|
||||
db = sqlite3_context_db_handle(ctx);
|
||||
if( iCol<0 ){
|
||||
zNew = sqlite3MPrintf(db, "%.*s, %s%s", iOff, zSql, zCons, &zSql[iOff]);
|
||||
}else{
|
||||
zNew = sqlite3MPrintf(db, "%.*s %s%s", iOff, zSql, zCons, &zSql[iOff]);
|
||||
}
|
||||
sqlite3_result_text(ctx, zNew, -1, SQLITE_DYNAMIC);
|
||||
}
|
||||
|
||||
/*
|
||||
** Find a column named pCol in table pTab. If successful, set output
|
||||
** parameter *piCol to the index of the column in the table and return
|
||||
** SQLITE_OK. Otherwise, set *piCol to -1 and return an SQLite error
|
||||
** code.
|
||||
*/
|
||||
static int alterFindCol(Parse *pParse, Table *pTab, Token *pCol, int *piCol){
|
||||
sqlite3 *db = pParse->db;
|
||||
char *zName = sqlite3NameFromToken(db, pCol);
|
||||
int rc = SQLITE_NOMEM;
|
||||
int iCol = -1;
|
||||
|
||||
if( zName ){
|
||||
iCol = sqlite3ColumnIndex(pTab, zName);
|
||||
if( iCol<0 ){
|
||||
sqlite3ErrorMsg(pParse, "no such column: %s", zName);
|
||||
rc = SQLITE_ERROR;
|
||||
}else{
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
if( rc==SQLITE_OK ){
|
||||
const char *zDb = db->aDb[sqlite3SchemaToIndex(db, pTab->pSchema)].zDbSName;
|
||||
const char *zCol = pTab->aCol[iCol].zCnName;
|
||||
if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, zDb, pTab->zName, zCol) ){
|
||||
pTab = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
sqlite3DbFree(db, zName);
|
||||
*piCol = iCol;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Find the table named by the first entry in source list pSrc. If successful,
|
||||
** return a pointer to the Table structure and set output variable (*pzDb)
|
||||
** to point to the name of the database containin the table (i.e. "main",
|
||||
** "temp" or the name of an attached database).
|
||||
**
|
||||
** If the table cannot be located, return NULL. The value of the two output
|
||||
** parameters is undefined in this case.
|
||||
*/
|
||||
static Table *alterFindTable(
|
||||
Parse *pParse, /* Parsing context */
|
||||
SrcList *pSrc, /* Name of the table to look for */
|
||||
int *piDb, /* OUT: write the iDb here */
|
||||
const char **pzDb, /* OUT: write name of schema here */
|
||||
int bAuth /* Do ALTER TABLE authorization checks if true */
|
||||
){
|
||||
sqlite3 *db = pParse->db;
|
||||
Table *pTab = 0;
|
||||
assert( sqlite3BtreeHoldsAllMutexes(db) );
|
||||
pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]);
|
||||
if( pTab ){
|
||||
int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
*pzDb = db->aDb[iDb].zDbSName;
|
||||
*piDb = iDb;
|
||||
|
||||
if( SQLITE_OK!=isRealTable(pParse, pTab, 2)
|
||||
|| SQLITE_OK!=isAlterableTable(pParse, pTab)
|
||||
){
|
||||
pTab = 0;
|
||||
}
|
||||
}
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
if( pTab && bAuth ){
|
||||
if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, *pzDb, pTab->zName, 0) ){
|
||||
pTab = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
sqlite3SrcListDelete(db, pSrc);
|
||||
return pTab;
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate bytecode for one of:
|
||||
**
|
||||
** (1) ALTER TABLE pSrc DROP CONSTRAINT pCons
|
||||
** (2) ALTER TABLE pSrc ALTER pCol DROP NOT NULL
|
||||
**
|
||||
** One of pCons and pCol must be NULL and the other non-null.
|
||||
*/
|
||||
void sqlite3AlterDropConstraint(
|
||||
Parse *pParse, /* Parsing context */
|
||||
SrcList *pSrc, /* The table being altered */
|
||||
Token *pCons, /* Name of the constraint to drop */
|
||||
Token *pCol /* Name of the column from which to remove the NOT NULL */
|
||||
){
|
||||
sqlite3 *db = pParse->db;
|
||||
Table *pTab = 0;
|
||||
int iDb = 0;
|
||||
const char *zDb = 0;
|
||||
char *zArg = 0;
|
||||
|
||||
assert( (pCol==0)!=(pCons==0) );
|
||||
assert( pSrc->nSrc==1 );
|
||||
pTab = alterFindTable(pParse, pSrc, &iDb, &zDb, pCons!=0);
|
||||
if( !pTab ) return;
|
||||
|
||||
if( pCons ){
|
||||
zArg = sqlite3MPrintf(db, "%.*Q", pCons->n, pCons->z);
|
||||
}else{
|
||||
int iCol;
|
||||
if( alterFindCol(pParse, pTab, pCol, &iCol) ) return;
|
||||
zArg = sqlite3MPrintf(db, "%d", iCol);
|
||||
}
|
||||
|
||||
/* Edit the SQL for the named table. */
|
||||
sqlite3NestedParse(pParse,
|
||||
"UPDATE \"%w\"." LEGACY_SCHEMA_TABLE " SET "
|
||||
"sql = sqlite_drop_constraint(sql, %s) "
|
||||
"WHERE type='table' AND tbl_name=%Q COLLATE nocase"
|
||||
, zDb, zArg, pTab->zName
|
||||
);
|
||||
sqlite3DbFree(db, zArg);
|
||||
|
||||
/* Finally, reload the database schema. */
|
||||
renameReloadSchema(pParse, iDb, INITFLAG_AlterDropCons);
|
||||
}
|
||||
|
||||
/*
|
||||
** The implementation of SQL function sqlite_fail(MSG). This takes a single
|
||||
** argument, and returns it as an error message with the error code set to
|
||||
** SQLITE_CONSTRAINT.
|
||||
*/
|
||||
static void failConstraintFunc(
|
||||
sqlite3_context *ctx,
|
||||
int NotUsed,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
const char *zText = (const char*)sqlite3_value_text(argv[0]);
|
||||
int err = sqlite3_value_int(argv[1]);
|
||||
(void)NotUsed;
|
||||
sqlite3_result_error(ctx, zText, -1);
|
||||
sqlite3_result_error_code(ctx, err);
|
||||
}
|
||||
|
||||
/*
|
||||
** Buffer pCons, which is nCons bytes in size, contains the text of a
|
||||
** NOT NULL or CHECK constraint that will be inserted into a CREATE TABLE
|
||||
** statement. If successful, this function returns the size of the buffer in
|
||||
** bytes not including any trailing whitespace or "--" style comments. Or,
|
||||
** if an OOM occurs, it returns 0 and sets db->mallocFailed to true.
|
||||
**
|
||||
** C-style comments at the end are preserved. "--" style comments are
|
||||
** removed because the comment terminator might be \000, and we are about
|
||||
** to insert the pCons[] text into the middle of a larger string, and that
|
||||
** will have the effect of removing the comment terminator and messing up
|
||||
** the syntax.
|
||||
*/
|
||||
static int alterRtrimConstraint(
|
||||
sqlite3 *db, /* used to record OOM error */
|
||||
const char *pCons, /* Buffer containing constraint */
|
||||
int nCons /* Size of pCons in bytes */
|
||||
){
|
||||
u8 *zTmp = (u8*)sqlite3MPrintf(db, "%.*s", nCons, pCons);
|
||||
int iOff = 0;
|
||||
int iEnd = 0;
|
||||
|
||||
if( zTmp==0 ) return 0;
|
||||
|
||||
while( 1 ){
|
||||
int t = 0;
|
||||
int nToken = sqlite3GetToken(&zTmp[iOff], &t);
|
||||
if( t==TK_ILLEGAL ) break;
|
||||
if( t!=TK_SPACE && (t!=TK_COMMENT || zTmp[iOff]!='-') ){
|
||||
iEnd = iOff+nToken;
|
||||
}
|
||||
iOff += nToken;
|
||||
}
|
||||
|
||||
sqlite3DbFree(db, zTmp);
|
||||
return iEnd;
|
||||
}
|
||||
|
||||
/*
|
||||
** Prepare a statement of the form:
|
||||
**
|
||||
** ALTER TABLE pSrc ALTER pCol SET NOT NULL
|
||||
*/
|
||||
void sqlite3AlterSetNotNull(
|
||||
Parse *pParse, /* Parsing context */
|
||||
SrcList *pSrc, /* Name of the table being altered */
|
||||
Token *pCol, /* Name of the column to add a NOT NULL constraint to */
|
||||
Token *pFirst /* The NOT token of the NOT NULL constraint text */
|
||||
){
|
||||
Table *pTab = 0;
|
||||
int iCol = 0;
|
||||
int iDb = 0;
|
||||
const char *zDb = 0;
|
||||
const char *pCons = 0;
|
||||
int nCons = 0;
|
||||
|
||||
/* Look up the table being altered. */
|
||||
assert( pSrc->nSrc==1 );
|
||||
pTab = alterFindTable(pParse, pSrc, &iDb, &zDb, 0);
|
||||
if( !pTab ) return;
|
||||
|
||||
/* Find the column being altered. */
|
||||
if( alterFindCol(pParse, pTab, pCol, &iCol) ){
|
||||
return;
|
||||
}
|
||||
|
||||
/* Find the length in bytes of the constraint definition */
|
||||
pCons = pFirst->z;
|
||||
nCons = alterRtrimConstraint(pParse->db, pCons, pParse->sLastToken.z - pCons);
|
||||
|
||||
/* Search for a constraint violation. Throw an exception if one is found. */
|
||||
sqlite3NestedParse(pParse,
|
||||
"SELECT sqlite_fail('constraint failed', %d) "
|
||||
"FROM %Q.%Q AS x WHERE x.%.*s IS NULL",
|
||||
SQLITE_CONSTRAINT, zDb, pTab->zName, (int)pCol->n, pCol->z
|
||||
);
|
||||
|
||||
/* Edit the SQL for the named table. */
|
||||
sqlite3NestedParse(pParse,
|
||||
"UPDATE \"%w\"." LEGACY_SCHEMA_TABLE " SET "
|
||||
"sql = sqlite_add_constraint(sqlite_drop_constraint(sql, %d), %.*Q, %d) "
|
||||
"WHERE type='table' AND tbl_name=%Q COLLATE nocase"
|
||||
, zDb, iCol, nCons, pCons, iCol, pTab->zName
|
||||
);
|
||||
|
||||
/* Finally, reload the database schema. */
|
||||
renameReloadSchema(pParse, iDb, INITFLAG_AlterDropCons);
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of internal SQL function:
|
||||
**
|
||||
** sqlite_find_constraint(SQL, CONSTRAINT-NAME)
|
||||
**
|
||||
** This function returns true if the SQL passed as the first argument is a
|
||||
** CREATE TABLE that contains a constraint with the name CONSTRAINT-NAME,
|
||||
** or false otherwise.
|
||||
*/
|
||||
static void findConstraintFunc(
|
||||
sqlite3_context *ctx,
|
||||
int NotUsed,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
const u8 *zSql = 0;
|
||||
const u8 *zCons = 0;
|
||||
int iOff = 0;
|
||||
int t = 0;
|
||||
|
||||
(void)NotUsed;
|
||||
zSql = sqlite3_value_text(argv[0]);
|
||||
zCons = sqlite3_value_text(argv[1]);
|
||||
|
||||
if( zSql==0 || zCons==0 ) return;
|
||||
while( t!=TK_LP && t!=TK_ILLEGAL ){
|
||||
iOff += sqlite3GetToken(&zSql[iOff], &t);
|
||||
}
|
||||
|
||||
while( 1 ){
|
||||
iOff += getConstraintToken(&zSql[iOff], &t);
|
||||
if( t==TK_CONSTRAINT ){
|
||||
int nTok = 0;
|
||||
int cmp = 0;
|
||||
iOff += getWhitespace(&zSql[iOff]);
|
||||
nTok = getConstraintToken(&zSql[iOff], &t);
|
||||
if( quotedCompare(ctx, t, &zSql[iOff], nTok, zCons, &cmp) ) return;
|
||||
if( cmp==0 ){
|
||||
sqlite3_result_int(ctx, 1);
|
||||
return;
|
||||
}
|
||||
}else if( t==TK_ILLEGAL ){
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sqlite3_result_int(ctx, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate bytecode to implement:
|
||||
**
|
||||
** ALTER TABLE pSrc ADD [CONSTRAINT pName] CHECK(pExpr)
|
||||
**
|
||||
** Any "ON CONFLICT" text that occurs after the "CHECK(...)", up
|
||||
** until pParse->sLastToken, is included as part of the new constraint.
|
||||
*/
|
||||
void sqlite3AlterAddConstraint(
|
||||
Parse *pParse, /* Parse context */
|
||||
SrcList *pSrc, /* Table to add constraint to */
|
||||
Token *pFirst, /* First token of new constraint */
|
||||
Token *pName, /* Name of new constraint. NULL if name omitted. */
|
||||
const char *pExpr, /* Text of CHECK expression */
|
||||
int nExpr /* Size of pExpr in bytes */
|
||||
){
|
||||
Table *pTab = 0; /* Table identified by pSrc */
|
||||
int iDb = 0; /* Which schema does pTab live in */
|
||||
const char *zDb = 0; /* Name of the schema in which pTab lives */
|
||||
const char *pCons = 0; /* Text of the constraint */
|
||||
int nCons; /* Bytes of text to use from pCons[] */
|
||||
|
||||
/* Look up the table being altered. */
|
||||
assert( pSrc->nSrc==1 );
|
||||
pTab = alterFindTable(pParse, pSrc, &iDb, &zDb, 1);
|
||||
if( !pTab ) return;
|
||||
|
||||
/* If this new constraint has a name, check that it is not a duplicate of
|
||||
** an existing constraint. It is an error if it is. */
|
||||
if( pName ){
|
||||
char *zName = sqlite3NameFromToken(pParse->db, pName);
|
||||
|
||||
sqlite3NestedParse(pParse,
|
||||
"SELECT sqlite_fail('constraint %q already exists', %d) "
|
||||
"FROM \"%w\"." LEGACY_SCHEMA_TABLE " "
|
||||
"WHERE type='table' AND tbl_name=%Q COLLATE nocase "
|
||||
"AND sqlite_find_constraint(sql, %Q)",
|
||||
zName, SQLITE_ERROR, zDb, pTab->zName, zName
|
||||
);
|
||||
sqlite3DbFree(pParse->db, zName);
|
||||
}
|
||||
|
||||
/* Search for a constraint violation. Throw an exception if one is found. */
|
||||
sqlite3NestedParse(pParse,
|
||||
"SELECT sqlite_fail('constraint failed', %d) "
|
||||
"FROM %Q.%Q WHERE (%.*s) IS NOT TRUE",
|
||||
SQLITE_CONSTRAINT, zDb, pTab->zName, nExpr, pExpr
|
||||
);
|
||||
|
||||
/* Edit the SQL for the named table. */
|
||||
pCons = pFirst->z;
|
||||
nCons = alterRtrimConstraint(pParse->db, pCons, pParse->sLastToken.z - pCons);
|
||||
|
||||
sqlite3NestedParse(pParse,
|
||||
"UPDATE \"%w\"." LEGACY_SCHEMA_TABLE " SET "
|
||||
"sql = sqlite_add_constraint(sql, %.*Q, -1) "
|
||||
"WHERE type='table' AND tbl_name=%Q COLLATE nocase"
|
||||
, zDb, nCons, pCons, pTab->zName
|
||||
);
|
||||
|
||||
/* Finally, reload the database schema. */
|
||||
renameReloadSchema(pParse, iDb, INITFLAG_AlterDropCons);
|
||||
}
|
||||
|
||||
/*
|
||||
** Register built-in functions used to help implement ALTER TABLE
|
||||
*/
|
||||
@@ -2319,6 +3036,10 @@ void sqlite3AlterFunctions(void){
|
||||
INTERNAL_FUNCTION(sqlite_rename_test, 7, renameTableTest),
|
||||
INTERNAL_FUNCTION(sqlite_drop_column, 3, dropColumnFunc),
|
||||
INTERNAL_FUNCTION(sqlite_rename_quotefix,2, renameQuotefixFunc),
|
||||
INTERNAL_FUNCTION(sqlite_drop_constraint,2, dropConstraintFunc),
|
||||
INTERNAL_FUNCTION(sqlite_fail, 2, failConstraintFunc),
|
||||
INTERNAL_FUNCTION(sqlite_add_constraint, 3, addConstraintFunc),
|
||||
INTERNAL_FUNCTION(sqlite_find_constraint,2, findConstraintFunc),
|
||||
};
|
||||
sqlite3InsertBuiltinFuncs(aAlterTableFuncs, ArraySize(aAlterTableFuncs));
|
||||
}
|
||||
|
||||
+2
-2
@@ -2059,8 +2059,8 @@ void sqlite3ChangeCookie(Parse *pParse, int iDb){
|
||||
** The estimate is conservative. It might be larger that what is
|
||||
** really needed.
|
||||
*/
|
||||
static int identLength(const char *z){
|
||||
int n;
|
||||
static i64 identLength(const char *z){
|
||||
i64 n;
|
||||
for(n=0; *z; n++, z++){
|
||||
if( *z=='"' ){ n++; }
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#if defined(_MSC_VER) && defined(_WIN32)
|
||||
|
||||
#include "windows.h"
|
||||
#include <profileapi.h>
|
||||
|
||||
__inline sqlite3_uint64 sqlite3Hwtime(void){
|
||||
|
||||
+27
-7
@@ -1826,22 +1826,42 @@ cmd ::= ANALYZE nm(X) dbnm(Y). {sqlite3Analyze(pParse, &X, &Y);}
|
||||
cmd ::= ALTER TABLE fullname(X) RENAME TO nm(Z). {
|
||||
sqlite3AlterRenameTable(pParse,X,&Z);
|
||||
}
|
||||
cmd ::= ALTER TABLE add_column_fullname
|
||||
ADD kwcolumn_opt columnname(Y) carglist. {
|
||||
|
||||
// The ALTER TABLE ADD COLUMN command. This is broken into two sections so
|
||||
// that sqlite3AlterBeginAddColumn() is called before parsing the various
|
||||
// constraints and so on (carglist) attached to the new column definition.
|
||||
cmd ::= alter_add(Y) carglist. {
|
||||
Y.n = (int)(pParse->sLastToken.z-Y.z) + pParse->sLastToken.n;
|
||||
sqlite3AlterFinishAddColumn(pParse, &Y);
|
||||
}
|
||||
alter_add(A) ::= ALTER TABLE fullname(X) ADD kwcolumn_opt nm(Y) typetoken(Z). {
|
||||
disableLookaside(pParse);
|
||||
sqlite3AlterBeginAddColumn(pParse, X);
|
||||
sqlite3AddColumn(pParse, Y, Z);
|
||||
A = Y;
|
||||
}
|
||||
|
||||
cmd ::= ALTER TABLE fullname(X) DROP kwcolumn_opt nm(Y). {
|
||||
sqlite3AlterDropColumn(pParse, X, &Y);
|
||||
}
|
||||
|
||||
add_column_fullname ::= fullname(X). {
|
||||
disableLookaside(pParse);
|
||||
sqlite3AlterBeginAddColumn(pParse, X);
|
||||
}
|
||||
cmd ::= ALTER TABLE fullname(X) RENAME kwcolumn_opt nm(Y) TO nm(Z). {
|
||||
sqlite3AlterRenameColumn(pParse, X, &Y, &Z);
|
||||
}
|
||||
cmd ::= ALTER TABLE fullname(X) DROP CONSTRAINT nm(Y). {
|
||||
sqlite3AlterDropConstraint(pParse, X, &Y, 0);
|
||||
}
|
||||
cmd ::= ALTER TABLE fullname(X) ALTER kwcolumn_opt nm(Y) DROP NOT NULL. {
|
||||
sqlite3AlterDropConstraint(pParse, X, 0, &Y);
|
||||
}
|
||||
cmd ::= ALTER TABLE fullname(X) ALTER kwcolumn_opt nm(Y) SET NOT(Z) NULL onconf. {
|
||||
sqlite3AlterSetNotNull(pParse, X, &Y, &Z);
|
||||
}
|
||||
cmd ::= ALTER TABLE fullname(X) ADD CONSTRAINT(Y) nm(Z) CHECK LP(A) expr RP(B) onconf. {
|
||||
sqlite3AlterAddConstraint(pParse, X, &Y, &Z, A.z+1, (B.z-A.z-1));
|
||||
}
|
||||
cmd ::= ALTER TABLE fullname(X) ADD CHECK(Y) LP(A) expr RP(B) onconf. {
|
||||
sqlite3AlterAddConstraint(pParse, X, &Y, 0, A.z+1, (B.z-A.z-1));
|
||||
}
|
||||
|
||||
kwcolumn_opt ::= .
|
||||
kwcolumn_opt ::= COLUMNKW.
|
||||
|
||||
+2
-1
@@ -33,7 +33,8 @@ static void corruptSchema(
|
||||
static const char *azAlterType[] = {
|
||||
"rename",
|
||||
"drop column",
|
||||
"add column"
|
||||
"add column",
|
||||
"drop constraint"
|
||||
};
|
||||
*pData->pzErrMsg = sqlite3MPrintf(db,
|
||||
"error in %s %s after %s: %s", azObj[0], azObj[1],
|
||||
|
||||
+2
-2
@@ -2430,8 +2430,8 @@ void sqlite3SubqueryColumnTypes(
|
||||
}
|
||||
}
|
||||
if( zType ){
|
||||
const i64 k = sqlite3Strlen30(zType);
|
||||
n = sqlite3Strlen30(pCol->zCnName);
|
||||
const i64 k = strlen(zType);
|
||||
n = strlen(pCol->zCnName);
|
||||
pCol->zCnName = sqlite3DbReallocOrFree(db, pCol->zCnName, n+k+2);
|
||||
pCol->colFlags &= ~(COLFLAG_HASTYPE|COLFLAG_HASCOLL);
|
||||
if( pCol->zCnName ){
|
||||
|
||||
+280
-183
@@ -1428,14 +1428,16 @@ static const char *qrfQuoteNames[] =
|
||||
#define MODE_List 12 /* One record per line with a separator */
|
||||
#define MODE_Markdown 13 /* Markdown formatting */
|
||||
#define MODE_Off 14 /* No query output shown */
|
||||
#define MODE_QBox 15 /* BOX with SQL-quoted content */
|
||||
#define MODE_Quote 16 /* Quote values as for SQL */
|
||||
#define MODE_Table 17 /* MySQL-style table formatting */
|
||||
#define MODE_Tabs 18 /* Tab-separated values */
|
||||
#define MODE_Tcl 19 /* Space-separated list of TCL strings */
|
||||
#define MODE_Www 20 /* Full web-page output */
|
||||
#define MODE_Psql 15 /* Similar to psql */
|
||||
#define MODE_QBox 16 /* BOX with SQL-quoted content */
|
||||
#define MODE_Quote 17 /* Quote values as for SQL */
|
||||
#define MODE_Split 18 /* Split-column mode */
|
||||
#define MODE_Table 19 /* MySQL-style table formatting */
|
||||
#define MODE_Tabs 20 /* Tab-separated values */
|
||||
#define MODE_Tcl 21 /* Space-separated list of TCL strings */
|
||||
#define MODE_Www 22 /* Full web-page output */
|
||||
|
||||
#define MODE_BUILTIN 20 /* Maximum built-in mode */
|
||||
#define MODE_BUILTIN 22 /* Maximum built-in mode */
|
||||
#define MODE_BATCH 50 /* Default mode for batch processing */
|
||||
#define MODE_TTY 51 /* Default mode for interactive processing */
|
||||
#define MODE_USER 75 /* First user-defined mode */
|
||||
@@ -1456,6 +1458,7 @@ struct ModeInfo {
|
||||
unsigned char bHdr; /* Show headers by default. 0: n/a, 1: no 2: yes */
|
||||
unsigned char eStyle; /* Underlying QRF style */
|
||||
unsigned char eCx; /* 0: other, 1: line, 2: columnar */
|
||||
unsigned char mFlg; /* Flags. 1=border-off 2=split-column */
|
||||
};
|
||||
|
||||
/* String constants used by built-in modes */
|
||||
@@ -1466,28 +1469,30 @@ static const char *aModeStr[] =
|
||||
/* 9 10 11 12 */
|
||||
|
||||
static const ModeInfo aModeInfo[] = {
|
||||
/* zName eCSep eRSep eNull eText eHdr eBlob bHdr eStyle eCx */
|
||||
{ "ascii", 7, 6, 9, 1, 1, 1, 1, 12, 0 },
|
||||
{ "box", 0, 0, 9, 1, 1, 1, 2, 1, 2 },
|
||||
{ "c", 4, 1, 10, 5, 5, 4, 1, 12, 0 },
|
||||
{ "column", 0, 0, 9, 1, 1, 1, 2, 2, 2 },
|
||||
{ "count", 0, 0, 0, 0, 0, 0, 0, 3, 0 },
|
||||
{ "csv", 4, 5, 9, 3, 3, 3, 1, 12, 0 },
|
||||
{ "html", 0, 0, 9, 4, 4, 1, 2, 7, 0 },
|
||||
{ "insert", 0, 0, 10, 2, 2, 2, 1, 8, 0 },
|
||||
{ "jatom", 4, 1, 11, 6, 6, 5, 1, 12, 0 },
|
||||
{ "jobject", 0, 1, 11, 6, 6, 5, 0, 10, 0 },
|
||||
{ "json", 0, 0, 11, 6, 6, 0, 0, 9, 0 },
|
||||
{ "line", 0, 1, 9, 1, 1, 0, 0, 11, 1 },
|
||||
{ "list", 2, 1, 9, 1, 1, 1, 1, 12, 0 },
|
||||
{ "markdown", 0, 0, 9, 1, 1, 1, 2, 13, 2 },
|
||||
{ "off", 0, 0, 0, 0, 0, 0, 0, 14, 0 },
|
||||
{ "qbox", 0, 0, 9, 2, 1, 2, 2, 1, 2 },
|
||||
{ "quote", 4, 1, 10, 2, 2, 2, 1, 12, 0 },
|
||||
{ "table", 0, 0, 9, 1, 1, 1, 2, 19, 2 },
|
||||
{ "tabs", 8, 1, 9, 3, 3, 1, 1, 12, 0 },
|
||||
{ "tcl", 3, 1, 12, 5, 5, 4, 1, 12, 0 },
|
||||
{ "www", 0, 0, 9, 4, 4, 1, 2, 7, 0 }
|
||||
/* zName eCSep eRSep eNull eText eHdr eBlob bHdr eStyle eCx mFlg */
|
||||
{ "ascii", 7, 6, 9, 1, 1, 0, 1, 12, 0, 0 },
|
||||
{ "box", 0, 0, 9, 1, 1, 0, 2, 1, 2, 0 },
|
||||
{ "c", 4, 1, 10, 5, 5, 4, 1, 12, 0, 0 },
|
||||
{ "column", 0, 0, 9, 1, 1, 0, 2, 2, 2, 0 },
|
||||
{ "count", 0, 0, 0, 0, 0, 0, 0, 3, 0, 0 },
|
||||
{ "csv", 4, 5, 9, 3, 3, 0, 1, 12, 0, 0 },
|
||||
{ "html", 0, 0, 9, 4, 4, 0, 2, 7, 0, 0 },
|
||||
{ "insert", 0, 0, 10, 2, 2, 0, 1, 8, 0, 0 },
|
||||
{ "jatom", 4, 1, 11, 6, 6, 0, 1, 12, 0, 0 },
|
||||
{ "jobject", 0, 1, 11, 6, 6, 0, 0, 10, 0, 0 },
|
||||
{ "json", 0, 0, 11, 6, 6, 0, 0, 9, 0, 0 },
|
||||
{ "line", 0, 1, 9, 1, 1, 0, 0, 11, 1, 0 },
|
||||
{ "list", 2, 1, 9, 1, 1, 0, 1, 12, 0, 0 },
|
||||
{ "markdown", 0, 0, 9, 1, 1, 0, 2, 13, 2, 0 },
|
||||
{ "off", 0, 0, 0, 0, 0, 0, 0, 14, 0, 0 },
|
||||
{ "psql", 0, 0, 9, 1, 1, 0, 2, 19, 2, 1 },
|
||||
{ "qbox", 0, 0, 10, 2, 1, 0, 2, 1, 2, 0 },
|
||||
{ "quote", 4, 1, 10, 2, 2, 0, 1, 12, 0, 0 },
|
||||
{ "split", 0, 0, 9, 1, 1, 0, 1, 2, 2, 2 },
|
||||
{ "table", 0, 0, 9, 1, 1, 0, 2, 19, 2, 0 },
|
||||
{ "tabs", 8, 1, 9, 3, 3, 0, 1, 12, 0, 0 },
|
||||
{ "tcl", 3, 1, 12, 5, 5, 4, 1, 12, 0, 0 },
|
||||
{ "www", 0, 0, 9, 4, 4, 0, 2, 7, 0, 0 }
|
||||
}; /* | / / | / / | | \
|
||||
** | / / | / / | | \_ 2: columnar
|
||||
** Index into aModeStr[] | / / | | 1: line
|
||||
@@ -1497,12 +1502,13 @@ static const ModeInfo aModeInfo[] = {
|
||||
** v-------------------' | hdrs? | The QRF style
|
||||
** 0: n/a blob | v-----'
|
||||
** 1: plain v_---------' 0: n/a
|
||||
** 2: sql 0: n/a 1: no
|
||||
** 2: sql 0: auto 1: no
|
||||
** 3: csv 1: as-text 2: yes
|
||||
** 4: html 2: sql
|
||||
** 5: c 3: hex
|
||||
** 6: json 4: c
|
||||
** 5: json
|
||||
** 6: size
|
||||
******************************************************************/
|
||||
/*
|
||||
** These are the column/row/line separators used by the various
|
||||
@@ -1529,6 +1535,7 @@ static const ModeInfo aModeInfo[] = {
|
||||
** contains.
|
||||
*/
|
||||
static void modeFree(Mode *p){
|
||||
u8 autoExplain = p->autoExplain;
|
||||
free(p->spec.aWidth);
|
||||
free(p->spec.aAlign);
|
||||
free(p->spec.zColumnSep);
|
||||
@@ -1537,6 +1544,7 @@ static void modeFree(Mode *p){
|
||||
free(p->spec.zNull);
|
||||
memset(p, 0, sizeof(*p));
|
||||
p->spec.iVersion = 1;
|
||||
p->autoExplain = autoExplain;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1600,8 +1608,8 @@ static void modeSetStr(char **az, const char *zNew){
|
||||
static void modeChange(ShellState *p, unsigned char eMode){
|
||||
const ModeInfo *pI;
|
||||
if( eMode<ArraySize(aModeInfo) ){
|
||||
pI = &aModeInfo[eMode];
|
||||
Mode *pM = &p->mode;
|
||||
pI = &aModeInfo[eMode];
|
||||
pM->eMode = eMode;
|
||||
if( pI->eCSep ) modeSetStr(&pM->spec.zColumnSep, aModeStr[pI->eCSep]);
|
||||
if( pI->eRSep ) modeSetStr(&pM->spec.zRowSep, aModeStr[pI->eRSep]);
|
||||
@@ -1610,6 +1618,17 @@ static void modeChange(ShellState *p, unsigned char eMode){
|
||||
pM->spec.eBlob = pI->eBlob;
|
||||
pM->spec.bTitles = pI->bHdr;
|
||||
pM->spec.eTitle = pI->eHdr;
|
||||
if( pI->mFlg & 0x01 ){
|
||||
pM->spec.bBorder = QRF_No;
|
||||
}else{
|
||||
pM->spec.bBorder = QRF_Auto;
|
||||
}
|
||||
if( pI->mFlg & 0x02 ){
|
||||
pM->spec.bSplitColumn = QRF_Yes;
|
||||
pM->bAutoScreenWidth = 1;
|
||||
}else{
|
||||
pM->spec.bSplitColumn = QRF_No;
|
||||
}
|
||||
}else if( eMode>=MODE_USER && eMode-MODE_USER<p->nSavedModes ){
|
||||
modeFree(&p->mode);
|
||||
modeDup(&p->mode, &p->aSavedModes[eMode-MODE_USER].mode);
|
||||
@@ -2101,34 +2120,37 @@ static void interrupt_handler(int NotUsed){
|
||||
/* Try to determine the screen width. Use the default if unable.
|
||||
*/
|
||||
int shellScreenWidth(void){
|
||||
if( stdout_tty_width>0 ) return stdout_tty_width;
|
||||
if( stdout_tty_width>0 ){
|
||||
return stdout_tty_width;
|
||||
}else{
|
||||
#if defined(TIOCGSIZE)
|
||||
struct ttysize ts;
|
||||
if( ioctl(STDIN_FILENO, TIOCGSIZE, &ts)>=0
|
||||
|| ioctl(STDOUT_FILENO, TIOCGSIZE, &ts)>=0
|
||||
|| ioctl(STDERR_FILENO, TIOCGSIZE, &ts)>=0
|
||||
){
|
||||
return ts.ts_cols;
|
||||
}
|
||||
struct ttysize ts;
|
||||
if( ioctl(STDIN_FILENO, TIOCGSIZE, &ts)>=0
|
||||
|| ioctl(STDOUT_FILENO, TIOCGSIZE, &ts)>=0
|
||||
|| ioctl(STDERR_FILENO, TIOCGSIZE, &ts)>=0
|
||||
){
|
||||
return ts.ts_cols;
|
||||
}
|
||||
#elif defined(TIOCGWINSZ)
|
||||
struct winsize ws;
|
||||
if( ioctl(STDIN_FILENO, TIOCGWINSZ, &ws)>=0
|
||||
|| ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws)>=0
|
||||
|| ioctl(STDERR_FILENO, TIOCGWINSZ, &ws)>=0
|
||||
){
|
||||
return ws.ws_col;
|
||||
}
|
||||
struct winsize ws;
|
||||
if( ioctl(STDIN_FILENO, TIOCGWINSZ, &ws)>=0
|
||||
|| ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws)>=0
|
||||
|| ioctl(STDERR_FILENO, TIOCGWINSZ, &ws)>=0
|
||||
){
|
||||
return ws.ws_col;
|
||||
}
|
||||
#elif defined(_WIN32)
|
||||
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||||
if( GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)
|
||||
|| GetConsoleScreenBufferInfo(GetStdHandle(STD_ERROR_HANDLE), &csbi)
|
||||
|| GetConsoleScreenBufferInfo(GetStdHandle(STD_INPUT_HANDLE), &csbi)
|
||||
){
|
||||
return csbi.srWindow.Right - csbi.srWindow.Left + 1;
|
||||
}
|
||||
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||||
if( GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)
|
||||
|| GetConsoleScreenBufferInfo(GetStdHandle(STD_ERROR_HANDLE), &csbi)
|
||||
|| GetConsoleScreenBufferInfo(GetStdHandle(STD_INPUT_HANDLE), &csbi)
|
||||
){
|
||||
return csbi.srWindow.Right - csbi.srWindow.Left + 1;
|
||||
}
|
||||
#endif
|
||||
#define DEFAULT_SCREEN_WIDTH 80
|
||||
return DEFAULT_SCREEN_WIDTH;
|
||||
return DEFAULT_SCREEN_WIDTH;
|
||||
}
|
||||
}
|
||||
|
||||
#if (defined(_WIN32) || defined(WIN32)) && !defined(_WIN32_WCE)
|
||||
@@ -3181,6 +3203,13 @@ static int shell_exec(
|
||||
if( pArg->mode.bAutoScreenWidth ){
|
||||
spec.nScreenWidth = shellScreenWidth();
|
||||
}
|
||||
if( spec.eBlob==QRF_BLOB_Auto ){
|
||||
switch( spec.eText ){
|
||||
case QRF_TEXT_Sql: spec.eBlob = QRF_BLOB_Sql; break;
|
||||
case QRF_TEXT_Json: spec.eBlob = QRF_BLOB_Json; break;
|
||||
default: spec.eBlob = QRF_BLOB_Text; break;
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_AUTHORIZATION)
|
||||
if( pArg->expert.pExpert ){
|
||||
@@ -3548,6 +3577,8 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azNotUsed){
|
||||
savedMode = p->mode;
|
||||
p->mode.spec.zTableName = (char*)zTable;
|
||||
p->mode.eMode = MODE_Insert;
|
||||
p->mode.spec.eText = QRF_TEXT_Sql;
|
||||
p->mode.spec.eBlob = QRF_BLOB_Sql;
|
||||
p->mode.spec.bTitles = QRF_No;
|
||||
rc = shell_exec(p, sSelect.zTxt, 0);
|
||||
if( (rc&0xff)==SQLITE_CORRUPT ){
|
||||
@@ -6865,7 +6896,9 @@ static int recoverDatabaseCmd(ShellState *pState, int nArg, char **azArg){
|
||||
pState->db, "main", recoverSqlCb, (void*)pState
|
||||
);
|
||||
|
||||
sqlite3_recover_config(p, 789, (void*)zRecoveryDb); /* Debug use only */
|
||||
if( !pState->bSafeMode ){
|
||||
sqlite3_recover_config(p, 789, (void*)zRecoveryDb); /* Debug use only */
|
||||
}
|
||||
sqlite3_recover_config(p, SQLITE_RECOVER_LOST_AND_FOUND, (void*)zLAF);
|
||||
sqlite3_recover_config(p, SQLITE_RECOVER_ROWIDS, (void*)&bRowids);
|
||||
sqlite3_recover_config(p, SQLITE_RECOVER_FREELIST_CORRUPT,(void*)&bFreelist);
|
||||
@@ -7640,9 +7673,9 @@ static int modeTitleDsply(ShellState *p, int bAll){
|
||||
**
|
||||
** USAGE: .mode [MODE] [OPTIONS]
|
||||
**
|
||||
** Change the output mode to MODE and/or apply OPTIONS to the
|
||||
** output mode. If no arguments, show the current output mode
|
||||
** and relevant options.
|
||||
** Change the output mode to MODE and/or apply OPTIONS to the output mode.
|
||||
** Arguments are processed from left to right. If no arguments, show the
|
||||
** current output mode and relevant options.
|
||||
**
|
||||
** Options:
|
||||
** --align STRING Set the alignment of text in columnar modes
|
||||
@@ -7650,17 +7683,22 @@ static int modeTitleDsply(ShellState *p, int bAll){
|
||||
** meaning "left", "centered", and "right", with
|
||||
** one letter per column starting from the left.
|
||||
** Unspecified alignment defaults to 'L'.
|
||||
** --blob-quote ARG ARG can be "auto", "text", "sql", "hex", "tcl",
|
||||
** "json", or "size". Default is "auto".
|
||||
** --border on|off Show outer border on "box" and "table" modes.
|
||||
** --charlimit N Set the maximum number of output characters to
|
||||
** show for any single SQL value to N. Longer values
|
||||
** truncated. Zero means "no limit".
|
||||
** --colsep STRING Use STRING as the column separator
|
||||
** --escape ESC Enable/disable escaping of control characters
|
||||
** in output. ESC can be "off", "ascii", or
|
||||
** "symbol".
|
||||
** found in the output. ESC can be "off", "ascii",
|
||||
** or "symbol".
|
||||
** --linelimit N Set the maximum number of output lines to show for
|
||||
** any single SQL value to N. Longer values are
|
||||
** truncated. Zero means "no limit". Only works
|
||||
** in "line" mode and in columnar modes.
|
||||
** --limits L,C Shorthand for "--linelimit L --charlimit C".
|
||||
** Or "off" to mean "0,0". Or "on" for "5,300".
|
||||
** --list List available modes
|
||||
** --null STRING Render SQL NULL values as the given string
|
||||
** --once Setting changes to the right are reverted after
|
||||
@@ -7668,10 +7706,10 @@ static int modeTitleDsply(ShellState *p, int bAll){
|
||||
** --quote ARG Enable/disable quoting of text. ARG can be
|
||||
** "off", "on", "sql", "csv", "html", "tcl",
|
||||
** or "json". "off" means show the text as-is.
|
||||
** "on and "sql" are synonyms.
|
||||
** "on" is an alias for "sql".
|
||||
** --reset Changes all mode settings back to their default.
|
||||
** --rowsep STRING Use STRING as the row separator
|
||||
** --screenwidth N Declare the screen width of the output device
|
||||
** --sw|--screenwidth N Declare the screen width of the output device
|
||||
** to be N characters. An attempt may be made to
|
||||
** wrap output text to fit within this limit. Zero
|
||||
** means "no limit". Or N can be "auto" to set the
|
||||
@@ -7679,7 +7717,7 @@ static int modeTitleDsply(ShellState *p, int bAll){
|
||||
** --tablename NAME Set the name of the table for "insert" mode.
|
||||
** --tag NAME Save mode to the left as NAME.
|
||||
** --textjsonb BOOLEAN If enabled, JSONB text is displayed as text JSON.
|
||||
** --title ARG Whether or not to show column headers, and if so
|
||||
** --title ARG Whether or not to show column headers, and if so
|
||||
** how to encode them. ARG can be "off", "on",
|
||||
** "sql", "csv", "html", "tcl", or "json".
|
||||
** -v|--verbose Verbose output
|
||||
@@ -7753,6 +7791,29 @@ static int dotCmdMode(ShellState *p){
|
||||
"Should contain only characters L, C, and R.");
|
||||
return 1;
|
||||
}
|
||||
}else if( pickStr(z,0,"-blob","-blob-quote","")>=0 ){
|
||||
if( (++i)>=nArg ){
|
||||
dotCmdError(p, i-1, "missing argument", 0);
|
||||
return 1;
|
||||
}
|
||||
k = pickStr(azArg[i], 0,
|
||||
"auto", "text", "sql", "hex", "tcl", "json", "size", "");
|
||||
/* 0 1 2 3 4 5 6
|
||||
** Must match QRF_BLOB_xxxx values. See also tag-20251124a */
|
||||
if( k>=0 ){
|
||||
p->mode.spec.eBlob = k & 0xff;
|
||||
}
|
||||
chng = 1;
|
||||
}else if( optionMatch(z,"border") ){
|
||||
if( (++i)>=nArg ){
|
||||
dotCmdError(p, i-1, "missing argument", 0);
|
||||
return 1;
|
||||
}
|
||||
k = pickStr(azArg[i], 0, "auto", "off", "on", "");
|
||||
if( k>=0 ){
|
||||
p->mode.spec.bBorder = k & 0x3;
|
||||
}
|
||||
chng = 1;
|
||||
}else if( 0<=(k=pickStr(z,0,"-charlimit","-linelimit","")) ){
|
||||
int w; /* 0 1 */
|
||||
if( i+1>=nArg ){
|
||||
@@ -7783,11 +7844,10 @@ static int dotCmdMode(ShellState *p){
|
||||
}else if( optionMatch(z,"escape") ){
|
||||
/* See similar code at tag-20250224-1 */
|
||||
char *zErr = 0;
|
||||
if( i+1>=nArg ){
|
||||
dotCmdError(p, i, "missing argument", 0);
|
||||
if( (++i)>=nArg ){
|
||||
dotCmdError(p, i-1, "missing argument", 0);
|
||||
return 1;
|
||||
}
|
||||
i++; /* 0 1 2 <-- One less than QRF_ESC_ */
|
||||
} /* 0 1 2 <-- One less than QRF_ESC_ */
|
||||
k = pickStr(azArg[i],&zErr,"off","ascii","symbol","");
|
||||
if( k<0 ){
|
||||
dotCmdError(p, i, "unknown escape type", "%s", zErr);
|
||||
@@ -7796,6 +7856,30 @@ static int dotCmdMode(ShellState *p){
|
||||
}
|
||||
p->mode.spec.eEsc = k+1;
|
||||
chng = 1;
|
||||
}else if( optionMatch(z,"limits") ){
|
||||
if( (++i)>=nArg ){
|
||||
dotCmdError(p, i-1, "missing argument", 0);
|
||||
return 1;
|
||||
}
|
||||
k = pickStr(azArg[i],0,"on","off","");
|
||||
if( k==0 ){
|
||||
p->mode.spec.nLineLimit = 5;
|
||||
p->mode.spec.nCharLimit = 300;
|
||||
}else if( k==1 ){
|
||||
p->mode.spec.nLineLimit = 0;
|
||||
p->mode.spec.nCharLimit = 0;
|
||||
}else{
|
||||
int L, C;
|
||||
int nNum = sscanf(azArg[i], "%d,%d", &L, &C);
|
||||
if( nNum!=2 || L<0 || C<0 ){
|
||||
dotCmdError(p, i, "bad argument", "Should be \"L,C\" where L and C"
|
||||
" are unsigned integers");
|
||||
return 1;
|
||||
}
|
||||
p->mode.spec.nLineLimit = L;
|
||||
p->mode.spec.nCharLimit = C;
|
||||
}
|
||||
chng = 1;
|
||||
}else if( optionMatch(z,"list") ){
|
||||
int ii;
|
||||
cli_puts("available modes:", p->out);
|
||||
@@ -7807,6 +7891,17 @@ static int dotCmdMode(ShellState *p){
|
||||
cli_printf(p->out, " %s", p->aSavedModes[ii].zTag);
|
||||
}
|
||||
cli_puts(" batch tty\n", p->out);
|
||||
chng = 1; /* Not really a change, but we still want to suppress the
|
||||
** "current mode" output */
|
||||
}else if( optionMatch(z,"once") ){
|
||||
p->nPopMode = 0;
|
||||
modePush(p);
|
||||
p->nPopMode = 1;
|
||||
}else if( optionMatch(z,"noquote") ){
|
||||
/* (undocumented legacy) --noquote always turns quoting off */
|
||||
p->mode.spec.eText = QRF_TEXT_Plain;
|
||||
p->mode.spec.eBlob = QRF_BLOB_Auto;
|
||||
chng = 1;
|
||||
}else if( optionMatch(z,"quote") ){
|
||||
if( i+1<nArg
|
||||
&& azArg[i+1][0]!='-'
|
||||
@@ -7833,64 +7928,50 @@ static int dotCmdMode(ShellState *p){
|
||||
}
|
||||
switch( k ){
|
||||
case 1: /* on */
|
||||
modeSetStr(&p->mode.spec.zNull, "NULL");
|
||||
/* Fall through */
|
||||
case 2: /* sql */
|
||||
p->mode.spec.eText = QRF_TEXT_Sql;
|
||||
p->mode.spec.eBlob = QRF_BLOB_Sql;
|
||||
break;
|
||||
case 3: /* csv */
|
||||
p->mode.spec.eText = QRF_TEXT_Csv;
|
||||
p->mode.spec.eBlob = QRF_BLOB_Text;
|
||||
break;
|
||||
case 4: /* html */
|
||||
p->mode.spec.eText = QRF_TEXT_Html;
|
||||
p->mode.spec.eBlob = QRF_BLOB_Text;
|
||||
break;
|
||||
case 5: /* tcl */
|
||||
p->mode.spec.eText = QRF_TEXT_Tcl;
|
||||
p->mode.spec.eBlob = QRF_BLOB_Text;
|
||||
break;
|
||||
case 6: /* json */
|
||||
p->mode.spec.eText = QRF_TEXT_Json;
|
||||
p->mode.spec.eBlob = QRF_BLOB_Json;
|
||||
break;
|
||||
default: /* off */
|
||||
default: /* off */
|
||||
p->mode.spec.eText = QRF_TEXT_Plain;
|
||||
p->mode.spec.eBlob = QRF_BLOB_Text;
|
||||
break;
|
||||
}
|
||||
chng = 1;
|
||||
}else if( optionMatch(z,"once") ){
|
||||
p->nPopMode = 0;
|
||||
modePush(p);
|
||||
p->nPopMode = 1;
|
||||
}else if( optionMatch(z,"noquote") ){
|
||||
/* (undocumented legacy) --noquote always turns quoting off */
|
||||
p->mode.spec.eText = QRF_TEXT_Plain;
|
||||
p->mode.spec.eBlob = QRF_BLOB_Text;
|
||||
chng = 1;
|
||||
}else if( optionMatch(z,"reset") ){
|
||||
int saved_eMode = p->mode.eMode;
|
||||
modeFree(&p->mode);
|
||||
modeChange(p, saved_eMode);
|
||||
}else if( optionMatch(z,"screenwidth") ){
|
||||
if( i+1>=nArg ){
|
||||
dotCmdError(p, i, "missing argument", 0);
|
||||
}else if( optionMatch(z,"screenwidth") || optionMatch(z,"sw") ){
|
||||
if( (++i)>=nArg ){
|
||||
dotCmdError(p, i-1, "missing argument", 0);
|
||||
return 1;
|
||||
}
|
||||
k = pickStr(azArg[i+1],0,"off","auto","");
|
||||
k = pickStr(azArg[i],0,"off","auto","");
|
||||
if( k==0 ){
|
||||
p->mode.bAutoScreenWidth = 0;
|
||||
p->mode.spec.nScreenWidth = 0;
|
||||
}else if( k==1 ){
|
||||
p->mode.bAutoScreenWidth = 1;
|
||||
}else{
|
||||
i64 w = integerValue(azArg[i+1]);
|
||||
i64 w = integerValue(azArg[i]);
|
||||
p->mode.bAutoScreenWidth = 0;
|
||||
if( w<0 ) w = 0;
|
||||
if( w>QRF_MAX_WIDTH ) w = QRF_MAX_WIDTH;
|
||||
p->mode.spec.nScreenWidth = w;
|
||||
}
|
||||
i++;
|
||||
chng = 1;
|
||||
}else if( optionMatch(z,"tag") ){
|
||||
size_t nByte;
|
||||
@@ -7954,12 +8035,12 @@ static int dotCmdMode(ShellState *p){
|
||||
** specify, so strlen(zW) bytes should be plenty of space to hold the
|
||||
** result. */
|
||||
aWidth = malloc( strlen(zW) );
|
||||
while( isspace(zW[0]) ) zW++;
|
||||
while( IsSpace(zW[0]) ) zW++;
|
||||
while( zW[0] ){
|
||||
int w = 0;
|
||||
int nDigit = 0;
|
||||
k = zW[0]=='-' && isdigit(zW[1]);
|
||||
while( isdigit(zW[k]) ){
|
||||
k = zW[0]=='-' && IsDigit(zW[1]);
|
||||
while( IsDigit(zW[k]) ){
|
||||
w = w*10 + zW[k] - '0';
|
||||
if( w>QRF_MAX_WIDTH ){
|
||||
dotCmdError(p,i+1,"width too big",
|
||||
@@ -7980,7 +8061,7 @@ static int dotCmdMode(ShellState *p){
|
||||
aWidth[nWidth++] = w;
|
||||
zW += k;
|
||||
if( zW[0]==',' ) zW++;
|
||||
while( isspace(zW[0]) ) zW++;
|
||||
while( IsSpace(zW[0]) ) zW++;
|
||||
}
|
||||
free(p->mode.spec.aWidth);
|
||||
p->mode.spec.aWidth = aWidth;
|
||||
@@ -8035,7 +8116,21 @@ static int dotCmdMode(ShellState *p){
|
||||
}
|
||||
sqlite3_str_append(pDesc, "\"", 1);
|
||||
}
|
||||
if( bAll || p->mode.spec.nCharLimit>0 ){
|
||||
if( bAll
|
||||
|| (p->mode.spec.bBorder==QRF_No) != ((pI->mFlg&1)!=0)
|
||||
){
|
||||
sqlite3_str_appendf(pDesc," --border %s",
|
||||
p->mode.spec.bBorder==QRF_No ? "off" : "on");
|
||||
}
|
||||
if( bAll || p->mode.spec.eBlob!=QRF_BLOB_Auto ){
|
||||
const char *azBQuote[] =
|
||||
{ "auto", "text", "sql", "hex", "tcl", "json", "size" };
|
||||
/* 0 1 2 3 4 5 6
|
||||
** Must match QRF_BLOB_xxxx values. See all instances of tag-20251124a */
|
||||
u8 e = p->mode.spec.eBlob;
|
||||
sqlite3_str_appendf(pDesc, " --blob-quote %s", azBQuote[e]);
|
||||
}
|
||||
if( !bAll && p->mode.spec.nLineLimit==0 && p->mode.spec.nCharLimit>0 ){
|
||||
sqlite3_str_appendf(pDesc, " --charlimit %d",p->mode.spec.nCharLimit);
|
||||
}
|
||||
zSetting = aModeStr[pI->eCSep];
|
||||
@@ -8046,7 +8141,15 @@ static int dotCmdMode(ShellState *p){
|
||||
if( bAll || p->mode.spec.eEsc!=QRF_Auto ){
|
||||
sqlite3_str_appendf(pDesc, " --escape %s",qrfEscNames[p->mode.spec.eEsc]);
|
||||
}
|
||||
if( bAll || (p->mode.spec.nLineLimit>0 && pI->eCx>0) ){
|
||||
if( bAll || (p->mode.spec.nLineLimit>0 && p->mode.spec.nCharLimit>0) ){
|
||||
if( p->mode.spec.nLineLimit==0 && p->mode.spec.nCharLimit==0 ){
|
||||
sqlite3_str_appendf(pDesc, " --limits off");
|
||||
}else{
|
||||
sqlite3_str_appendf(pDesc, " --limits %d,%d",
|
||||
p->mode.spec.nLineLimit, p->mode.spec.nCharLimit);
|
||||
}
|
||||
}else
|
||||
if( p->mode.spec.nCharLimit==0 && p->mode.spec.nLineLimit>0 && pI->eCx>0 ){
|
||||
sqlite3_str_appendf(pDesc, " --linelimit %d",p->mode.spec.nLineLimit);
|
||||
}
|
||||
zSetting = aModeStr[pI->eNull];
|
||||
@@ -8419,9 +8522,10 @@ dotCmdOutput_error:
|
||||
sqlite3_free(zFile);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Parse input line zLine up into individual arguments. Retain the
|
||||
** parse in the p->dot substructure.
|
||||
** Enlarge the space allocated in p->dot so that it can hold more
|
||||
** than nArg parsed command-line arguments.
|
||||
*/
|
||||
static void parseDotRealloc(ShellState *p, int nArg){
|
||||
p->dot.nAlloc = nArg+22;
|
||||
@@ -8432,15 +8536,29 @@ static void parseDotRealloc(ShellState *p, int nArg){
|
||||
p->dot.abQuot = realloc(p->dot.abQuot,p->dot.nAlloc);
|
||||
shell_check_oom(p->dot.abQuot);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Parse input line zLine up into individual arguments. Retain the
|
||||
** parse in the p->dot substructure.
|
||||
*/
|
||||
static void parseDotCmdArgs(const char *zLine, ShellState *p){
|
||||
char *z;
|
||||
int h = 1;
|
||||
int nArg = 0;
|
||||
size_t szLine;
|
||||
|
||||
p->dot.zOrig = zLine;
|
||||
free(p->dot.zCopy);
|
||||
z = p->dot.zCopy = strdup(zLine);
|
||||
shell_check_oom(z);
|
||||
szLine = strlen(z);
|
||||
while( szLine>0 && IsSpace(z[szLine-1]) ) szLine--;
|
||||
if( szLine>0 && z[szLine-1]==';' && p->iCompat>=20251115 ){
|
||||
szLine--;
|
||||
while( szLine>0 && IsSpace(z[szLine-1]) ) szLine--;
|
||||
}
|
||||
z[szLine] = 0;
|
||||
parseDotRealloc(p, 2);
|
||||
while( z[h] ){
|
||||
while( IsSpace(z[h]) ){ h++; }
|
||||
@@ -9227,8 +9345,8 @@ static int do_meta_command(const char *zLine, ShellState *p){
|
||||
rc = shell_exec(&data,zSql,0);
|
||||
sqlite3_free(zSql);
|
||||
if( rc==SQLITE_OK ){
|
||||
memset(hasStat, 0, sizeof(hasStat));
|
||||
sqlite3_stmt *pStmt;
|
||||
memset(hasStat, 0, sizeof(hasStat));
|
||||
rc = sqlite3_prepare_v2(p->db,
|
||||
"SELECT substr(name,12,1) FROM sqlite_schema"
|
||||
" WHERE name GLOB 'sqlite_stat[134]'",
|
||||
@@ -9569,6 +9687,8 @@ static int do_meta_command(const char *zLine, ShellState *p){
|
||||
int openMode = SHELL_OPEN_UNSPEC;
|
||||
int openFlags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE;
|
||||
|
||||
if( p->bSafeMode ) openFlags = SQLITE_OPEN_READONLY;
|
||||
|
||||
/* Check for command-line arguments */
|
||||
for(iName=1; iName<nArg; iName++){
|
||||
const char *z = azArg[iName];
|
||||
@@ -9576,10 +9696,10 @@ static int do_meta_command(const char *zLine, ShellState *p){
|
||||
if( optionMatch(z,"new") ){
|
||||
newFlag = 1;
|
||||
#ifdef SQLITE_HAVE_ZLIB
|
||||
}else if( optionMatch(z, "zip") ){
|
||||
}else if( optionMatch(z, "zip") && !p->bSafeMode ){
|
||||
openMode = SHELL_OPEN_ZIPFILE;
|
||||
#endif
|
||||
}else if( optionMatch(z, "append") ){
|
||||
}else if( optionMatch(z, "append") && !p->bSafeMode ){
|
||||
openMode = SHELL_OPEN_APPENDVFS;
|
||||
}else if( optionMatch(z, "readonly") ){
|
||||
openFlags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE);
|
||||
@@ -10059,7 +10179,7 @@ static int do_meta_command(const char *zLine, ShellState *p){
|
||||
bIndent);
|
||||
}else{
|
||||
sqlite3_str_appendf(pSql,
|
||||
"SELECT shell_format_schema(shell_add_schema(sql,%Q,name),%d))",
|
||||
"SELECT shell_format_schema(shell_add_schema(sql,%Q,name),%d)",
|
||||
zDb, bIndent);
|
||||
}
|
||||
sqlite3_str_appendf(pSql,
|
||||
@@ -10749,11 +10869,9 @@ static int do_meta_command(const char *zLine, ShellState *p){
|
||||
|| cli_strncmp(azArg[0], "indexes", n)==0) )
|
||||
){
|
||||
sqlite3_stmt *pStmt;
|
||||
char **azResult;
|
||||
int nRow, nAlloc;
|
||||
int ii;
|
||||
ShellText s;
|
||||
initText(&s);
|
||||
sqlite3_str *pSql;
|
||||
const char *zPattern = nArg>1 ? azArg[1] : 0;
|
||||
|
||||
open_db(p, 0);
|
||||
rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0);
|
||||
if( rc ){
|
||||
@@ -10770,86 +10888,46 @@ static int do_meta_command(const char *zLine, ShellState *p){
|
||||
sqlite3_finalize(pStmt);
|
||||
goto meta_command_exit;
|
||||
}
|
||||
for(ii=0; sqlite3_step(pStmt)==SQLITE_ROW; ii++){
|
||||
pSql = sqlite3_str_new(p->db);
|
||||
while( sqlite3_step(pStmt)==SQLITE_ROW ){
|
||||
const char *zDbName = (const char*)sqlite3_column_text(pStmt, 1);
|
||||
if( zDbName==0 ) continue;
|
||||
if( s.zTxt && s.zTxt[0] ) appendText(&s, " UNION ALL ", 0);
|
||||
if( sqlite3_stricmp(zDbName, "main")==0 ){
|
||||
appendText(&s, "SELECT name FROM ", 0);
|
||||
}else{
|
||||
appendText(&s, "SELECT ", 0);
|
||||
appendText(&s, zDbName, '\'');
|
||||
appendText(&s, "||'.'||name FROM ", 0);
|
||||
if( sqlite3_str_length(pSql) ){
|
||||
sqlite3_str_appendall(pSql, " UNION ALL ");
|
||||
}
|
||||
appendText(&s, zDbName, '"');
|
||||
appendText(&s, ".sqlite_schema ", 0);
|
||||
if( c=='t' ){
|
||||
appendText(&s," WHERE type IN ('table','view')"
|
||||
" AND name NOT LIKE 'sqlite__%' ESCAPE '_'"
|
||||
" AND name LIKE ?1", 0);
|
||||
if( sqlite3_stricmp(zDbName, "main")==0 ){
|
||||
sqlite3_str_appendall(pSql, "SELECT name FROM ");
|
||||
}else{
|
||||
appendText(&s," WHERE type='index'"
|
||||
" AND tbl_name LIKE ?1", 0);
|
||||
sqlite3_str_appendf(pSql, "SELECT %Q||'.'||name FROM ", zDbName);
|
||||
}
|
||||
sqlite3_str_appendf(pSql, "\"%w\".sqlite_schema", zDbName);
|
||||
if( c=='t' ){
|
||||
sqlite3_str_appendf(pSql,
|
||||
" WHERE type IN ('table','view')"
|
||||
" AND name NOT LIKE 'sqlite__%%' ESCAPE '_'"
|
||||
);
|
||||
if( zPattern ){
|
||||
sqlite3_str_appendf(pSql," AND name LIKE %Q", zPattern);
|
||||
}
|
||||
}else{
|
||||
sqlite3_str_appendf(pSql, " WHERE type='index'");
|
||||
if( zPattern ){
|
||||
sqlite3_str_appendf(pSql," AND tbl_name LIKE %Q", zPattern);
|
||||
}
|
||||
}
|
||||
}
|
||||
rc = sqlite3_finalize(pStmt);
|
||||
if( rc==SQLITE_OK ){
|
||||
appendText(&s, " ORDER BY 1", 0);
|
||||
rc = sqlite3_prepare_v2(p->db, s.zTxt, -1, &pStmt, 0);
|
||||
sqlite3_str_appendall(pSql, " ORDER BY 1");
|
||||
}
|
||||
freeText(&s);
|
||||
|
||||
/* Run the SQL statement in "split" mode. */
|
||||
modePush(p);
|
||||
modeChange(p, MODE_Split);
|
||||
shell_exec(p, sqlite3_str_value(pSql), 0);
|
||||
sqlite3_str_free(pSql);
|
||||
modePop(p);
|
||||
if( rc ) return shellDatabaseError(p->db);
|
||||
|
||||
/* Run the SQL statement prepared by the above block. Store the results
|
||||
** as an array of nul-terminated strings in azResult[]. */
|
||||
nRow = nAlloc = 0;
|
||||
azResult = 0;
|
||||
if( nArg>1 ){
|
||||
sqlite3_bind_text(pStmt, 1, azArg[1], -1, SQLITE_TRANSIENT);
|
||||
}else{
|
||||
sqlite3_bind_text(pStmt, 1, "%", -1, SQLITE_STATIC);
|
||||
}
|
||||
while( sqlite3_step(pStmt)==SQLITE_ROW ){
|
||||
if( nRow>=nAlloc ){
|
||||
char **azNew;
|
||||
sqlite3_int64 n2 = 2*(sqlite3_int64)nAlloc + 10;
|
||||
azNew = sqlite3_realloc64(azResult, sizeof(azResult[0])*n2);
|
||||
shell_check_oom(azNew);
|
||||
nAlloc = (int)n2;
|
||||
azResult = azNew;
|
||||
}
|
||||
azResult[nRow] = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 0));
|
||||
shell_check_oom(azResult[nRow]);
|
||||
nRow++;
|
||||
}
|
||||
if( sqlite3_finalize(pStmt)!=SQLITE_OK ){
|
||||
rc = shellDatabaseError(p->db);
|
||||
}
|
||||
|
||||
/* Pretty-print the contents of array azResult[] to the output */
|
||||
if( rc==0 && nRow>0 ){
|
||||
int len, maxlen = 0;
|
||||
int i, j;
|
||||
int nPrintCol, nPrintRow;
|
||||
for(i=0; i<nRow; i++){
|
||||
len = strlen30(azResult[i]);
|
||||
if( len>maxlen ) maxlen = len;
|
||||
}
|
||||
nPrintCol = shellScreenWidth()/(maxlen+2);
|
||||
if( nPrintCol<1 ) nPrintCol = 1;
|
||||
nPrintRow = (nRow + nPrintCol - 1)/nPrintCol;
|
||||
for(i=0; i<nPrintRow; i++){
|
||||
for(j=i; j<nRow; j+=nPrintRow){
|
||||
char *zSp = j<nPrintRow ? "" : " ";
|
||||
cli_printf(p->out,
|
||||
"%s%-*s", zSp, maxlen, azResult[j] ? azResult[j]:"");
|
||||
}
|
||||
cli_puts("\n", p->out);
|
||||
}
|
||||
}
|
||||
|
||||
for(ii=0; ii<nRow; ii++) sqlite3_free(azResult[ii]);
|
||||
sqlite3_free(azResult);
|
||||
}else
|
||||
|
||||
#ifndef SQLITE_SHELL_FIDDLE
|
||||
@@ -12704,7 +12782,8 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
|
||||
#else
|
||||
cli_printf(stderr,
|
||||
"%s: Error: no database filename specified\n", Argv0);
|
||||
return 1;
|
||||
rc = 1;
|
||||
goto shell_main_exit;
|
||||
#endif
|
||||
}
|
||||
data.out = stdout;
|
||||
@@ -12758,6 +12837,8 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
|
||||
modeChange(&data, MODE_Markdown);
|
||||
}else if( cli_strcmp(z,"-table")==0 ){
|
||||
modeChange(&data, MODE_Table);
|
||||
}else if( cli_strcmp(z,"-psql")==0 ){
|
||||
modeChange(&data, MODE_Psql);
|
||||
}else if( cli_strcmp(z,"-box")==0 ){
|
||||
modeChange(&data, MODE_Box);
|
||||
}else if( cli_strcmp(z,"-csv")==0 ){
|
||||
@@ -12844,7 +12925,8 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
|
||||
}else if( cli_strcmp(z,"-version")==0 ){
|
||||
cli_printf(stdout, "%s %s (%d-bit)\n",
|
||||
sqlite3_libversion(), sqlite3_sourceid(), 8*(int)sizeof(char*));
|
||||
return 0;
|
||||
rc = 0;
|
||||
goto shell_main_exit;
|
||||
}else if( cli_strcmp(z,"-interactive")==0 ){
|
||||
/* Need to check for interactive override here to so that it can
|
||||
** affect console setup (for Windows only) and testing thereof.
|
||||
@@ -12901,25 +12983,29 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
|
||||
z = cmdline_option_value(argc,argv,++i);
|
||||
if( z[0]=='.' ){
|
||||
rc = do_meta_command(z, &data);
|
||||
if( rc && bail_on_error ) return rc==2 ? 0 : rc;
|
||||
if( rc && bail_on_error ){
|
||||
if( rc==2 ) rc = 0;
|
||||
goto shell_main_exit;
|
||||
}
|
||||
}else{
|
||||
open_db(&data, 0);
|
||||
rc = shell_exec(&data, z, &zErrMsg);
|
||||
if( zErrMsg!=0 ){
|
||||
shellEmitError(zErrMsg);
|
||||
sqlite3_free(zErrMsg);
|
||||
if( bail_on_error ) return rc!=0 ? rc : 1;
|
||||
if( !rc ) rc = 1;
|
||||
}else if( rc!=0 ){
|
||||
cli_printf(stderr,"Error: unable to process SQL \"%s\"\n", z);
|
||||
if( bail_on_error ) return rc;
|
||||
}
|
||||
if( bail_on_error ) goto shell_main_exit;
|
||||
}
|
||||
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB)
|
||||
}else if( cli_strncmp(z, "-A", 2)==0 ){
|
||||
if( nCmd>0 ){
|
||||
cli_printf(stderr,"Error: cannot mix regular SQL or dot-commands"
|
||||
" with \"%s\"\n", z);
|
||||
return 1;
|
||||
rc = 1;
|
||||
goto shell_main_exit;
|
||||
}
|
||||
open_db(&data, OPEN_DB_ZIPFILE);
|
||||
if( z[2] ){
|
||||
@@ -12939,7 +13025,8 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
|
||||
}else{
|
||||
cli_printf(stderr,"%s: Error: unknown option: %s\n", Argv0, z);
|
||||
eputz("Use -help for a list of options.\n");
|
||||
return 1;
|
||||
rc = 1;
|
||||
goto shell_main_exit;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12977,6 +13064,16 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
|
||||
if( rc==0 ) rc = 1;
|
||||
goto shell_main_exit;
|
||||
}
|
||||
if( data.nPopMode ){
|
||||
modePop(&data);
|
||||
data.nPopMode = 0;
|
||||
}
|
||||
}
|
||||
if( data.nPopOutput ){
|
||||
output_reset(&data);
|
||||
data.nPopOutput = 0;
|
||||
}else{
|
||||
clearTempFile(&data);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
|
||||
+3
-2
@@ -1490,7 +1490,7 @@ typedef const char *sqlite3_filename;
|
||||
** greater and the function pointer is not NULL) and will fall back
|
||||
** to xCurrentTime() if xCurrentTimeInt64() is unavailable.
|
||||
**
|
||||
** ^The xSetSystemCall(), xGetSystemCall(), and xNestSystemCall() interfaces
|
||||
** ^The xSetSystemCall(), xGetSystemCall(), and xNextSystemCall() interfaces
|
||||
** are not used by the SQLite core. These optional interfaces are provided
|
||||
** by some VFSes to facilitate testing of the VFS code. By overriding
|
||||
** system calls with functions under its control, a test program can
|
||||
@@ -4174,6 +4174,7 @@ void sqlite3_free_filename(sqlite3_filename);
|
||||
** <li> sqlite3_errmsg()
|
||||
** <li> sqlite3_errmsg16()
|
||||
** <li> sqlite3_error_offset()
|
||||
** <li> sqlite3_db_handle()
|
||||
** </ul>
|
||||
**
|
||||
** ^The sqlite3_errmsg() and sqlite3_errmsg16() return English-language
|
||||
@@ -8730,7 +8731,7 @@ sqlite3_str *sqlite3_str_new(sqlite3*);
|
||||
** pass the returned value to [sqlite3_free()] to avoid a memory leak.
|
||||
** ^The [sqlite3_str_finish(X)] interface may return a NULL pointer if any
|
||||
** errors were encountered during construction of the string. ^The
|
||||
** [sqlite3_str_finish(X)] interface will also return a NULL pointer if the
|
||||
** [sqlite3_str_finish(X)] interface might also return a NULL pointer if the
|
||||
** string in [sqlite3_str] object X is zero bytes long.
|
||||
**
|
||||
** ^The [sqlite3_str_free(X)] interface destroys both the sqlite3_str object
|
||||
|
||||
+5
-1
@@ -4267,10 +4267,11 @@ typedef struct {
|
||||
/*
|
||||
** Allowed values for mInitFlags
|
||||
*/
|
||||
#define INITFLAG_AlterMask 0x0003 /* Types of ALTER */
|
||||
#define INITFLAG_AlterMask 0x0007 /* Types of ALTER */
|
||||
#define INITFLAG_AlterRename 0x0001 /* Reparse after a RENAME */
|
||||
#define INITFLAG_AlterDrop 0x0002 /* Reparse after a DROP COLUMN */
|
||||
#define INITFLAG_AlterAdd 0x0003 /* Reparse after an ADD COLUMN */
|
||||
#define INITFLAG_AlterDropCons 0x0004 /* Reparse after an ADD COLUMN */
|
||||
|
||||
/* Tuning parameters are set using SQLITE_TESTCTRL_TUNE and are controlled
|
||||
** on debug-builds of the CLI using ".testctrl tune ID VALUE". Tuning
|
||||
@@ -5449,6 +5450,9 @@ void sqlite3Reindex(Parse*, Token*, Token*);
|
||||
void sqlite3AlterFunctions(void);
|
||||
void sqlite3AlterRenameTable(Parse*, SrcList*, Token*);
|
||||
void sqlite3AlterRenameColumn(Parse*, SrcList*, Token*, Token*);
|
||||
void sqlite3AlterDropConstraint(Parse*,SrcList*,Token*,Token*);
|
||||
void sqlite3AlterAddConstraint(Parse*,SrcList*,Token*,Token*,const char*,int);
|
||||
void sqlite3AlterSetNotNull(Parse*, SrcList*, Token*, Token*);
|
||||
i64 sqlite3GetToken(const unsigned char *, int *);
|
||||
void sqlite3NestedParse(Parse*, const char*, ...);
|
||||
void sqlite3ExpirePreparedStatements(sqlite3*, int);
|
||||
|
||||
+16
-7
@@ -2062,9 +2062,10 @@ static void DbHookCmd(
|
||||
** -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.
|
||||
** -splitcolumn ("auto"|"off"|"on") Enable split-column mode
|
||||
** -defaultalign ("auto"|"left"|...) Default alignment
|
||||
** -titalalign ("auto"|"left"|"right"|...) Default column name alignment
|
||||
** -border ("auto"|"off"|"on") Border for box and table styles
|
||||
** -wrap NUMBER Max width of any single column
|
||||
** -screenwidth NUMBER Width of the display TTY
|
||||
** -linelimit NUMBER Max lines for any cell
|
||||
@@ -2088,9 +2089,10 @@ static void DbHookCmd(
|
||||
** -blob eBlob
|
||||
** -wordwrap bWordWrap
|
||||
** -textjsonb bTextJsonb
|
||||
** -textnull bTestNull
|
||||
** -splitcolumn bSplitColumn
|
||||
** -defaultalign eDfltAlign
|
||||
** -titlealign eTitleAlign
|
||||
** -border bBorder
|
||||
** -wrap nWrap
|
||||
** -screenwidth nScreenWidth
|
||||
** -linelimit nLineLimit
|
||||
@@ -2217,11 +2219,13 @@ static int dbQrf(SqliteDb *pDb, int objc, Tcl_Obj *const*objv){
|
||||
}else if( strcmp(zArg,"-blob")==0 ){
|
||||
static const char *azBlob[] = {
|
||||
"auto", "hex", "json",
|
||||
"tcl", "text", "sql", 0
|
||||
"tcl", "text", "sql",
|
||||
"size", 0
|
||||
};
|
||||
static unsigned char aBlobMap[] = {
|
||||
QRF_BLOB_Auto, QRF_BLOB_Hex, QRF_BLOB_Json,
|
||||
QRF_BLOB_Tcl, QRF_BLOB_Text, QRF_BLOB_Sql
|
||||
QRF_BLOB_Tcl, QRF_BLOB_Text, QRF_BLOB_Sql,
|
||||
QRF_BLOB_Size
|
||||
};
|
||||
int blob;
|
||||
rc = Tcl_GetIndexFromObj(pDb->interp, objv[i+1], azBlob,
|
||||
@@ -2236,15 +2240,20 @@ static int dbQrf(SqliteDb *pDb, int objc, Tcl_Obj *const*objv){
|
||||
if( rc ) goto format_failed;
|
||||
qrf.bWordWrap = aBoolMap[v];
|
||||
i++;
|
||||
}else if( strcmp(zArg,"-textjsonb")==0 || strcmp(zArg,"-textnull")==0 ){
|
||||
}else if( strcmp(zArg,"-textjsonb")==0
|
||||
|| strcmp(zArg,"-splitcolumn")==0
|
||||
|| strcmp(zArg,"-border")==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' ){
|
||||
if( zArg[1]=='t' ){
|
||||
qrf.bTextJsonb = aBoolMap[v];
|
||||
}else if( zArg[1]=='b' ){
|
||||
qrf.bBorder = aBoolMap[v];
|
||||
}else{
|
||||
qrf.bTextNull = aBoolMap[v];
|
||||
qrf.bSplitColumn = aBoolMap[v];
|
||||
}
|
||||
i++;
|
||||
}else if( strcmp(zArg,"-defaultalign")==0 || strcmp(zArg,"-titlealign")==0){
|
||||
|
||||
+1
-1
@@ -604,7 +604,7 @@ int sqlite3RunParser(Parse *pParse, const char *zSql){
|
||||
int tokenType; /* type of the next token */
|
||||
int lastTokenParsed = -1; /* type of the previous token */
|
||||
sqlite3 *db = pParse->db; /* The database connection */
|
||||
int mxSqlLen; /* Max length of an SQL string */
|
||||
i64 mxSqlLen; /* Max length of an SQL string */
|
||||
Parse *pParentParse = 0; /* Outer parse context, if any */
|
||||
#ifdef sqlite3Parser_ENGINEALWAYSONSTACK
|
||||
yyParser sEngine; /* Space to hold the Lemon-generated Parser object */
|
||||
|
||||
@@ -116,4 +116,55 @@ do_auth_test 1.3 {
|
||||
{SQLITE_UPDATE sqlite_temp_master sql temp {}}
|
||||
}
|
||||
|
||||
do_auth_test 1.4 {
|
||||
ALTER TABLE t2 ALTER COLUMN b SET NOT NULL;
|
||||
} {
|
||||
{SQLITE_ALTER_TABLE main t2 b {}}
|
||||
{SQLITE_FUNCTION {} sqlite_add_constraint {} {}}
|
||||
{SQLITE_FUNCTION {} sqlite_drop_constraint {} {}}
|
||||
{SQLITE_FUNCTION {} sqlite_fail {} {}}
|
||||
{SQLITE_READ sqlite_master sql main {}}
|
||||
{SQLITE_READ sqlite_master tbl_name main {}}
|
||||
{SQLITE_READ sqlite_master type main {}}
|
||||
{SQLITE_READ t2 b main {}}
|
||||
{SQLITE_SELECT {} {} {} {}}
|
||||
{SQLITE_UPDATE sqlite_master sql main {}}
|
||||
}
|
||||
do_auth_test 1.5 {
|
||||
ALTER TABLE t2 ALTER COLUMN 'b' DROP NOT NULL;
|
||||
} {
|
||||
{SQLITE_ALTER_TABLE main t2 b {}}
|
||||
{SQLITE_FUNCTION {} sqlite_drop_constraint {} {}}
|
||||
{SQLITE_READ sqlite_master sql main {}}
|
||||
{SQLITE_READ sqlite_master tbl_name main {}}
|
||||
{SQLITE_READ sqlite_master type main {}}
|
||||
{SQLITE_UPDATE sqlite_master sql main {}}
|
||||
}
|
||||
|
||||
do_auth_test 1.6 {
|
||||
ALTER TABLE t2 ADD CONSTRAINT abc CHECK (aaa>b)
|
||||
} {
|
||||
{SQLITE_ALTER_TABLE main t2 {} {}}
|
||||
{SQLITE_FUNCTION {} sqlite_add_constraint {} {}}
|
||||
{SQLITE_FUNCTION {} sqlite_fail {} {}}
|
||||
{SQLITE_FUNCTION {} sqlite_find_constraint {} {}}
|
||||
{SQLITE_READ sqlite_master sql main {}}
|
||||
{SQLITE_READ sqlite_master tbl_name main {}}
|
||||
{SQLITE_READ sqlite_master type main {}}
|
||||
{SQLITE_READ t2 aaa main {}}
|
||||
{SQLITE_READ t2 b main {}}
|
||||
{SQLITE_SELECT {} {} {} {}}
|
||||
{SQLITE_UPDATE sqlite_master sql main {}}
|
||||
}
|
||||
do_auth_test 1.7 {
|
||||
ALTER TABLE t2 DROP CONSTRAINT abc;
|
||||
} {
|
||||
{SQLITE_ALTER_TABLE main t2 {} {}}
|
||||
{SQLITE_FUNCTION {} sqlite_drop_constraint {} {}}
|
||||
{SQLITE_READ sqlite_master sql main {}}
|
||||
{SQLITE_READ sqlite_master tbl_name main {}}
|
||||
{SQLITE_READ sqlite_master type main {}}
|
||||
{SQLITE_UPDATE sqlite_master sql main {}}
|
||||
}
|
||||
|
||||
finish_test
|
||||
@@ -946,4 +946,17 @@ do_execsql_test 23.20 {
|
||||
ROLLBACK;
|
||||
} {t4new}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 24.0 {
|
||||
CREATE TABLE t1(a PRIMARY KEY, b);
|
||||
CREATE TABLE t2(a, b, c);
|
||||
INSERT INTO t2 VALUES(1, 1, 1);
|
||||
}
|
||||
|
||||
do_catchsql_test 24.1 {
|
||||
PRAGMA foreign_keys = 1;
|
||||
ALTER TABLE t2 ADD COLUMN d REFERENCES t1 DEFAULT 123;
|
||||
} {1 {Cannot add a REFERENCES column with non-NULL default value}}
|
||||
|
||||
finish_test
|
||||
@@ -0,0 +1,442 @@
|
||||
# 2025 September 18
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#*************************************************************************
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix altercons
|
||||
|
||||
# If SQLITE_OMIT_ALTERTABLE is defined, omit this file.
|
||||
ifcapable !altertable {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
foreach {tn before after} {
|
||||
1 { CREATE TABLE t1(a, b CONSTRAINT abc CHECK(t1.a != t1.b)) }
|
||||
{ CREATE TABLE t1(a, b) }
|
||||
|
||||
2 { CREATE TABLE t1(a, b CONSTRAINT abc CHECK(t1.a != t1.b) NOT NULL) }
|
||||
{ CREATE TABLE t1(a, b NOT NULL) }
|
||||
|
||||
3 { CREATE TABLE t1(a, b CONSTRAINT abc CHECK(t1.a != t1.b)NOT NULL) }
|
||||
{ CREATE TABLE t1(a, b NOT NULL) }
|
||||
|
||||
3 { CREATE TABLE t1(a, b NOT NULL CONSTRAINT abc CHECK(t1.a != t1.b)); }
|
||||
{ CREATE TABLE t1(a, b NOT NULL) }
|
||||
|
||||
4 { CREATE TABLE t1(a, b, CONSTRAINT abc CHECK(t1.a != t1.b)) }
|
||||
{ CREATE TABLE t1(a, b) }
|
||||
|
||||
5 { CREATE TABLE t1(a, b, CONSTRAINT abc CHECK(t1.a != t1.b), PRIMARY KEY(a))}
|
||||
{ CREATE TABLE t1(a, b, PRIMARY KEY(a)) }
|
||||
|
||||
6 { CREATE TABLE t1(a, b,CONSTRAINT abc CHECK(t1.a != t1.b),PRIMARY KEY(a))}
|
||||
{ CREATE TABLE t1(a, b,PRIMARY KEY(a)) }
|
||||
|
||||
7 { CREATE TABLE t1(a, b CONSTRAINT abc CHECK(t1.a != t1.b) CONSTRAINT def UNIQUE) }
|
||||
{ CREATE TABLE t1(a, b CONSTRAINT def UNIQUE) }
|
||||
|
||||
8 { CREATE TABLE t1(a, b CONSTRAINT abc CHECK(t1.a != t1.b) CHECK (123)) }
|
||||
{ CREATE TABLE t1(a, b CHECK (123)) }
|
||||
|
||||
9 { CREATE TABLE t1(a, b CONSTRAINT abc CHECK(t1.a != t1.b) DEFAULT NULL) }
|
||||
{ CREATE TABLE t1(a, b DEFAULT NULL) }
|
||||
|
||||
10 { CREATE TABLE t1(a, b CONSTRAINT abc CHECK(t1.a != t1.b) COLLATE nocase) }
|
||||
{ CREATE TABLE t1(a, b COLLATE nocase) }
|
||||
|
||||
11 { CREATE TABLE t1(a, b CONSTRAINT abc CHECK(t1.a != t1.b) REFERENCES t2) }
|
||||
{ CREATE TABLE t1(a, b REFERENCES t2) }
|
||||
|
||||
12 { CREATE TABLE t1(a, b, c, CONSTRAINT one CONSTRAINT abc CHECK(a!=b) CONSTRAINT three) }
|
||||
{ CREATE TABLE t1(a, b, c, CONSTRAINT one CONSTRAINT three) }
|
||||
|
||||
13 { CREATE TABLE t1(a, b, c, CONSTRAINT abc CONSTRAINT one CHECK(a!=b) CONSTRAINT three) }
|
||||
{ CREATE TABLE t1(a, b, c, CONSTRAINT one CHECK(a!=b) CONSTRAINT three) }
|
||||
|
||||
14 { CREATE TABLE t1(a, b, c, CONSTRAINT abc) }
|
||||
{ CREATE TABLE t1(a, b, c) }
|
||||
|
||||
15 { CREATE TABLE t1(a, b, c,
|
||||
CONSTRAINT abc, CHECK( a!=b )) }
|
||||
{ CREATE TABLE t1(a, b, c, CHECK( a!=b )) }
|
||||
|
||||
16 { CREATE TABLE t1(a, b, c, CONSTRAINT abc /* hello */ CHECK( a!=b )) }
|
||||
{ CREATE TABLE t1(a, b, c) }
|
||||
|
||||
17 { CREATE TABLE t1(a, b, c, /* world */ CONSTRAINT abc CHECK( a!=b )) }
|
||||
{ CREATE TABLE t1(a, b, c) }
|
||||
|
||||
18 { CREATE TABLE t1(a, b, c -- comment
|
||||
CONSTRAINT abc NOT NULL
|
||||
) }
|
||||
{ CREATE TABLE t1(a, b, c) }
|
||||
|
||||
19 { CREATE TABLE t1(a, b, c, -- comment
|
||||
CONSTRAINT abc CHECK (a>b) CONSTRAINT two
|
||||
) }
|
||||
{ CREATE TABLE t1(a, b, c, CONSTRAINT two
|
||||
) }
|
||||
|
||||
20 { CREATE TABLE t1(a, b, c, CONSTRAINT one CONSTRAINT abc CHECK (a>b)CONSTRAINT two) }
|
||||
{ CREATE TABLE t1(a, b, c, CONSTRAINT one CONSTRAINT two) }
|
||||
|
||||
21 { CREATE TABLE t1(a, b, c CONSTRAINT abc AS (b+1)) }
|
||||
{ CREATE TABLE t1(a, b, c AS (b+1)) }
|
||||
|
||||
22 { CREATE TABLE t1(a, b, c CONSTRAINT abc GENERATED ALWAYS AS (b+1) STORED) }
|
||||
{ CREATE TABLE t1(a, b, c GENERATED ALWAYS AS (b+1) STORED) }
|
||||
} {
|
||||
reset_db
|
||||
|
||||
do_execsql_test 1.$tn.0 $before
|
||||
|
||||
do_execsql_test 1.$tn.1 {
|
||||
ALTER TABLE t1 DROP CONSTRAINT abc;
|
||||
} {}
|
||||
|
||||
do_execsql_test 1.$tn.2 {
|
||||
SELECT sql FROM sqlite_schema WHERE name='t1'
|
||||
} [list [string trim $after]]
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
do_execsql_test 2.0 {
|
||||
CREATE TABLE t2(x, y CONSTRAINT ccc UNIQUE);
|
||||
}
|
||||
do_catchsql_test 2.1 {
|
||||
ALTER TABLE t2 DROP CONSTRAINT ccc
|
||||
} {1 {constraint may not be dropped: ccc}}
|
||||
do_catchsql_test 2.2 {
|
||||
ALTER TABLE t2 DROP CONSTRAINT ddd
|
||||
} {1 {no such constraint: ddd}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
foreach {tn col before after} {
|
||||
1 a { CREATE TABLE t1(a NOT NULL, b) }
|
||||
{ CREATE TABLE t1(a, b) }
|
||||
|
||||
2 a { CREATE TABLE t1(a NOT NULL ON CONFLICT FAIL, b) }
|
||||
{ CREATE TABLE t1(a, b) }
|
||||
|
||||
3 a { CREATE TABLE t1(a NOT NULL ON CONFLICT FAIL UNIQUE, b) }
|
||||
{ CREATE TABLE t1(a UNIQUE, b) }
|
||||
|
||||
4 b { CREATE TABLE t1(a NOT NULL ON CONFLICT FAIL UNIQUE, b) }
|
||||
{ CREATE TABLE t1(a NOT NULL ON CONFLICT FAIL UNIQUE, b) }
|
||||
|
||||
5 a { CREATE TABLE t1(a CHECK(a<b) NOT NULL, b) }
|
||||
{ CREATE TABLE t1(a CHECK(a<b), b) }
|
||||
|
||||
6 a { CREATE TABLE t1(a CHECK(a<b) CONSTRAINT nn NOT NULL, b) }
|
||||
{ CREATE TABLE t1(a CHECK(a<b), b) }
|
||||
|
||||
7 b { CREATE TABLE t1(a, b NOT NULL PRIMARY KEY) }
|
||||
{ CREATE TABLE t1(a, b PRIMARY KEY) }
|
||||
|
||||
8 b { CREATE TABLE t1(a, b CHECK ((b+a) IS NOT NULL) NOT NULL PRIMARY KEY) }
|
||||
{ CREATE TABLE t1(a, b CHECK ((b+a) IS NOT NULL) PRIMARY KEY) }
|
||||
|
||||
9 b { CREATE TABLE t1(a, b CONSTRAINT nn CHECK (b IS NOT NULL) NOT NULL) }
|
||||
{ CREATE TABLE t1(a, b CONSTRAINT nn CHECK (b IS NOT NULL)) }
|
||||
|
||||
10 b { CREATE TABLE t1(a, b NOT NULL AS (a+1)) }
|
||||
{ CREATE TABLE t1(a, b AS (a+1)) }
|
||||
|
||||
11 b { CREATE TABLE t1(a, b NOT NULL GENERATED ALWAYS AS (a+1)) }
|
||||
{ CREATE TABLE t1(a, b GENERATED ALWAYS AS (a+1)) }
|
||||
} {
|
||||
reset_db
|
||||
|
||||
do_execsql_test 3.$tn.0 $before
|
||||
|
||||
do_execsql_test 3.$tn.1 "
|
||||
ALTER TABLE t1 ALTER COLUMN $col DROP NOT NULL
|
||||
"
|
||||
|
||||
do_execsql_test 3.$tn.2 {
|
||||
SELECT sql FROM sqlite_schema WHERE name='t1'
|
||||
} [list [string trim $after]]
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 4.0 {
|
||||
CREATE TABLE t2(x, y CONSTRAINT ccc UNIQUE);
|
||||
}
|
||||
do_execsql_test 4.1 {
|
||||
ALTER TABLE t2 ALTER x DROP NOT NULL;
|
||||
ALTER TABLE t2 ALTER x DROP NOT NULL;
|
||||
ALTER TABLE t2 ALTER x DROP NOT NULL;
|
||||
} {}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
|
||||
do_execsql_test 5.1 {
|
||||
CREATE TABLE t3(a INTEGER PRIMARY KEY, b);
|
||||
INSERT INTO t3 VALUES(1000, NULL);
|
||||
}
|
||||
|
||||
do_catchsql_test 5.2.1 {
|
||||
ALTER TABLE t3 ALTER b SET NOT NULL
|
||||
} {1 {constraint failed}}
|
||||
|
||||
do_test 5.2.2 {
|
||||
sqlite3_errcode db
|
||||
} {SQLITE_CONSTRAINT}
|
||||
|
||||
foreach {tn before alter after} {
|
||||
1 { CREATE TABLE t1(a, b) }
|
||||
{ ALTER TABLE t1 ALTER a SET NOT NULL }
|
||||
{ CREATE TABLE t1(a NOT NULL, b) }
|
||||
|
||||
2 { CREATE TABLE t1(a, b) }
|
||||
{ ALTER TABLE t1 ALTER a SET NOT NULL ON CONFLICT FAIL }
|
||||
{ CREATE TABLE t1(a NOT NULL ON CONFLICT FAIL, b) }
|
||||
|
||||
3 { CREATE TABLE t1(a, b) }
|
||||
{ ALTER TABLE t1 ALTER a SET NOT NULL ON CONFLICT fail; }
|
||||
{ CREATE TABLE t1(a NOT NULL ON CONFLICT fail, b) }
|
||||
|
||||
4 { CREATE TABLE t1(a, b) }
|
||||
{ ALTER TABLE t1 ALTER b SET NOT NULL ON CONFLICT IGNORE ; }
|
||||
{ CREATE TABLE t1(a, b NOT NULL ON CONFLICT IGNORE) }
|
||||
|
||||
5 { CREATE TABLE t1(a, 'a b c' VARCHAR(10), UNIQUE(a)) }
|
||||
{ ALTER TABLE t1 ALTER 'a b c' SET NOT NULL }
|
||||
{ CREATE TABLE t1(a, 'a b c' VARCHAR(10) NOT NULL, UNIQUE(a)) }
|
||||
} {
|
||||
reset_db
|
||||
do_execsql_test 5.3.$tn.1 $before
|
||||
do_execsql_test 5.3.$tn.2 $alter
|
||||
do_execsql_test 5.3.$tn.3 {
|
||||
SELECT sql FROM sqlite_schema WHERE name='t1';
|
||||
} [list [string trim $after]]
|
||||
}
|
||||
|
||||
do_execsql_test 5.4.1 {
|
||||
CREATE TABLE x1(a, b, c);
|
||||
}
|
||||
do_catchsql_test 5.4.2 {
|
||||
ALTER TABLE x1 ALTER d SET NOT NULL;
|
||||
} {1 {no such column: d}}
|
||||
do_catchsql_test 5.4.3 {
|
||||
ALTER TABLE x2 ALTER c SET NOT NULL;
|
||||
} {1 {no such table: x2}}
|
||||
do_catchsql_test 5.4.4 {
|
||||
ALTER TABLE temp.x1 ALTER c SET NOT NULL;
|
||||
} {1 {no such table: temp.x1}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
|
||||
do_execsql_test 6.1 {
|
||||
CREATE TABLE t1(a, b, c);
|
||||
INSERT INTO t1 VALUES(1, 2, 3);
|
||||
INSERT INTO t1 VALUES(4, 5, 6);
|
||||
}
|
||||
|
||||
do_catchsql_test 6.2.1 {
|
||||
ALTER TABLE t1 ADD CONSTRAINT nn CHECK (c!=6);
|
||||
} {1 {constraint failed}}
|
||||
do_execsql_test 6.2.2 {
|
||||
DELETE FROM t1 WHERE c=6;
|
||||
ALTER TABLE t1 ADD CONSTRAINT nn CHECK (c!=6);
|
||||
} {}
|
||||
do_catchsql_test 6.2.3 {
|
||||
INSERT INTO t1 VALUES(4, 5, 6);
|
||||
} {1 {CHECK constraint failed: nn}}
|
||||
|
||||
foreach {tn before alter after} {
|
||||
1 { CREATE TABLE t1(a, b) }
|
||||
{ ALTER TABLE t1 ADD CONSTRAINT nn CHECK (a>=0) }
|
||||
{ CREATE TABLE t1(a, b, CONSTRAINT nn CHECK (a>=0)) }
|
||||
|
||||
2 { CREATE TABLE t1(a, b ) }
|
||||
{ ALTER TABLE t1 ADD CONSTRAINT nn CHECK (a>=0) }
|
||||
{ CREATE TABLE t1(a, b , CONSTRAINT nn CHECK (a>=0)) }
|
||||
|
||||
3 { CREATE TABLE t1(a, b ) }
|
||||
{ ALTER TABLE t1 ADD CHECK (a>=0) }
|
||||
{ CREATE TABLE t1(a, b , CHECK (a>=0)) }
|
||||
} {
|
||||
reset_db
|
||||
do_execsql_test 6.3.$tn.1 $before
|
||||
do_execsql_test 6.3.$tn.2 $alter
|
||||
do_execsql_test 6.3.$tn.3 {
|
||||
SELECT sql FROM sqlite_schema WHERE type='table';
|
||||
} [list [string trim $after]]
|
||||
}
|
||||
|
||||
do_execsql_test 6.4.1 {
|
||||
CREATE TABLE b1(a, b, CONSTRAINT abc CHECK (a!=2));
|
||||
}
|
||||
do_catchsql_test 6.4.2 {
|
||||
ALTER TABLE b1 ADD CONSTRAINT abc CHECK (a!=3);
|
||||
} {1 {constraint abc already exists}}
|
||||
do_execsql_test 6.4.1 {
|
||||
SELECT sql FROM sqlite_schema WHERE tbl_name='b1'
|
||||
} {{CREATE TABLE b1(a, b, CONSTRAINT abc CHECK (a!=2))}}
|
||||
|
||||
do_execsql_test 6.5 {
|
||||
CREATE TABLE abc(x,y);
|
||||
}
|
||||
|
||||
do_catchsql_test 6.6 {
|
||||
ALTER TABLE abc ADD CHECK (z>=0);
|
||||
} {1 {no such column: z}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Try attaching a NOT NULL to a generated column.
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 7.0 {
|
||||
CREATE TABLE x1(a, b AS (a+1));
|
||||
INSERT INTO x1 VALUES(1), (2), (3), (NULL);
|
||||
}
|
||||
|
||||
do_catchsql_test 7.1 {
|
||||
ALTER TABLE x1 ALTER b SET NOT NULL;
|
||||
} {1 {constraint failed}}
|
||||
|
||||
do_catchsql_test 7.2 {
|
||||
DELETE FROM x1 WHERE b IS NULL;
|
||||
ALTER TABLE x1 ALTER b SET NOT NULL;
|
||||
} {0 {}}
|
||||
|
||||
do_execsql_test 7.3 {
|
||||
SELECT b FROM x1
|
||||
} {2 3 4}
|
||||
|
||||
do_catchsql_test 7.4 {
|
||||
ALTER TABLE x1 ALTER rowid SET NOT NULL;
|
||||
} {1 {no such column: rowid}}
|
||||
|
||||
do_execsql_test 7.5 {
|
||||
CREATE VIEW v1 AS SELECT a, b FROM x1;
|
||||
}
|
||||
do_catchsql_test 7.6 {
|
||||
ALTER TABLE v1 RENAME a TO c;
|
||||
} {1 {cannot rename columns of view "v1"}}
|
||||
do_catchsql_test 7.7 {
|
||||
ALTER TABLE v1 ALTER a SET NOT NULL;
|
||||
} {1 {cannot edit constraints of view "v1"}}
|
||||
do_catchsql_test 7.8 {
|
||||
ALTER TABLE sqlite_schema ALTER sql SET NOT NULL;
|
||||
} {1 {table sqlite_master may not be altered}}
|
||||
do_catchsql_test 7.9 {
|
||||
ALTER TABLE v1 ALTER a DROP NOT NULL
|
||||
} {1 {cannot edit constraints of view "v1"}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 8.0 {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b NOT NULL, c CHECK (c!=555), d);
|
||||
INSERT INTO t1 VALUES(1, 1, 1, 1);
|
||||
INSERT INTO t1 VALUES(2, 2, 2, 2);
|
||||
INSERT INTO t1 VALUES(3, 3, 3, 3);
|
||||
}
|
||||
|
||||
do_execsql_test 8.1.1 {
|
||||
ALTER TABLE t1 ALTER a SET NOT NULL;
|
||||
ALTER TABLE t1 ALTER b SET NOT NULL;
|
||||
ALTER TABLE t1 ALTER c SET NOT NULL;
|
||||
ALTER TABLE t1 ALTER d SET NOT NULL;
|
||||
}
|
||||
|
||||
do_execsql_test 8.1.2 {
|
||||
SELECT sql FROM sqlite_schema WHERE tbl_name = 't1'
|
||||
} {{CREATE TABLE t1(a INTEGER PRIMARY KEY NOT NULL, b NOT NULL, c CHECK (c!=555) NOT NULL, d NOT NULL)}}
|
||||
|
||||
do_execsql_test 8.1.3 {
|
||||
SELECT * FROM t1 WHERE a=2;
|
||||
} {2 2 2 2}
|
||||
|
||||
do_execsql_test 8.2.1 {
|
||||
ALTER TABLE t1 ALTER a DROP NOT NULL;
|
||||
ALTER TABLE t1 ALTER b DROP NOT NULL;
|
||||
ALTER TABLE t1 ALTER c DROP NOT NULL;
|
||||
ALTER TABLE t1 ALTER d DROP NOT NULL;
|
||||
}
|
||||
|
||||
do_execsql_test 8.2.2 {
|
||||
SELECT sql FROM sqlite_schema WHERE tbl_name = 't1'
|
||||
} {{CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c CHECK (c!=555), d)}}
|
||||
|
||||
do_execsql_test 8.2.3 {
|
||||
SELECT * FROM t1 WHERE a=3;
|
||||
} {3 3 3 3}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
forcedelete test.db2
|
||||
do_execsql_test 9.0 {
|
||||
CREATE TABLE t1(x, y, z);
|
||||
ATTACH 'test.db2' AS aux;
|
||||
CREATE TABLE aux.t1(x, y, z);
|
||||
INSERT INTO aux.t1 VALUES(1, 1, 1);
|
||||
INSERT INTO aux.t1 VALUES(2, 2, 2);
|
||||
INSERT INTO aux.t1 VALUES(3, 3, NULL);
|
||||
|
||||
CREATE TABLE aux.t2(x, y, z);
|
||||
}
|
||||
|
||||
do_catchsql_test 9.1.1 {
|
||||
ALTER TABLE aux.t1 ALTER COLUMN z SET NOT NULL
|
||||
} {1 {constraint failed}}
|
||||
do_execsql_test 9.1.2 {
|
||||
UPDATE aux.t1 SET z=x;
|
||||
ALTER TABLE aux.t1 ALTER COLUMN z SET NOT NULL;
|
||||
SELECT sql FROM aux.sqlite_schema WHERE name='t1';
|
||||
} {{CREATE TABLE t1(x, y, z NOT NULL)}}
|
||||
do_execsql_test 9.1.3 {
|
||||
ALTER TABLE aux.t1 ALTER z DROP NOT NULL;
|
||||
SELECT sql FROM aux.sqlite_schema WHERE name='t1';
|
||||
} {{CREATE TABLE t1(x, y, z)}}
|
||||
do_execsql_test 9.1.4 {
|
||||
ALTER TABLE t2 ALTER x SET NOT NULL;
|
||||
SELECT sql FROM aux.sqlite_schema WHERE name='t2';
|
||||
} {{CREATE TABLE t2(x NOT NULL, y, z)}}
|
||||
do_execsql_test 9.1.5 {
|
||||
ALTER TABLE t2 ALTER x DROP NOT NULL;
|
||||
SELECT sql FROM aux.sqlite_schema WHERE name='t2';
|
||||
} {{CREATE TABLE t2(x, y, z)}}
|
||||
|
||||
do_catchsql_test 9.2.1 {
|
||||
ALTER TABLE aux.t1 ADD CONSTRAINT bill CHECK (y!=2);
|
||||
} {1 {constraint failed}}
|
||||
do_execsql_test 9.2.2 {
|
||||
UPDATE aux.t1 SET y=4 WHERE y=2;
|
||||
ALTER TABLE aux.t1 ADD CONSTRAINT bill CHECK (y!=2);
|
||||
SELECT sql FROM aux.sqlite_schema WHERE name='t1';
|
||||
} {{CREATE TABLE t1(x, y, z, CONSTRAINT bill CHECK (y!=2))}}
|
||||
do_execsql_test 9.2.3 {
|
||||
ALTER TABLE aux.t1 DROP CONSTRAINT bill;
|
||||
SELECT sql FROM aux.sqlite_schema WHERE name='t1';
|
||||
} {{CREATE TABLE t1(x, y, z)}}
|
||||
do_execsql_test 9.2.4 {
|
||||
ALTER TABLE t2 ADD CONSTRAINT william CHECK (z!='');
|
||||
SELECT sql FROM aux.sqlite_schema WHERE name='t2';
|
||||
} {{CREATE TABLE t2(x, y, z, CONSTRAINT william CHECK (z!=''))}}
|
||||
do_execsql_test 9.2.5 {
|
||||
ALTER TABLE t2 DROP CONSTRAINT william;
|
||||
SELECT sql FROM aux.sqlite_schema WHERE name='t2';
|
||||
} {{CREATE TABLE t2(x, y, z)}}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,247 @@
|
||||
# 2025 September 18
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#*************************************************************************
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix altercons2
|
||||
|
||||
# If SQLITE_OMIT_ALTERTABLE is defined, omit this file.
|
||||
ifcapable !altertable {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
foreach {tn newsql alter res final} {
|
||||
1 "CREATE TABLE t1(a, b"
|
||||
"ALTER TABLE t1 ALTER c SET NOT NULL"
|
||||
{1 {database disk image is malformed}}
|
||||
"CREATE TABLE t1(a, b"
|
||||
|
||||
2 "CREATE TABLE t1(a, b, "
|
||||
"ALTER TABLE t1 ALTER c DROP NOT NULL"
|
||||
{0 {}}
|
||||
"CREATE TABLE t1(a, b, "
|
||||
|
||||
3 "CREATE TABLE t1(a, b, CHECK( ..."
|
||||
"ALTER TABLE t1 ALTER c DROP NOT NULL"
|
||||
{0 {}}
|
||||
"CREATE TABLE t1(a, b, CHECK( ..."
|
||||
|
||||
4 "CREATE TABLE t1(a, b, c NOT NULL"
|
||||
"ALTER TABLE t1 ALTER c DROP NOT NULL"
|
||||
{0 {}}
|
||||
"CREATE TABLE t1(a, b, c "
|
||||
|
||||
5 "CREATE TABLE"
|
||||
"ALTER TABLE t1 ALTER c DROP NOT NULL"
|
||||
{1 {database disk image is malformed}}
|
||||
"CREATE TABLE"
|
||||
|
||||
6 "CREATE TABLE"
|
||||
"ALTER TABLE t1 ADD CONSTRAINT nn CHECK (a!=0)"
|
||||
{1 {database disk image is malformed}}
|
||||
"CREATE TABLE"
|
||||
|
||||
} {
|
||||
reset_db
|
||||
do_execsql_test 1.$tn.0 {
|
||||
CREATE TABLE t1(a, b, c NOT NULL, CONSTRAINT xyz CHECK( a!=0 ));
|
||||
}
|
||||
do_execsql_test 1.$tn.1 {
|
||||
PRAGMA writable_schema = 1;
|
||||
UPDATE sqlite_schema SET sql = $::newsql
|
||||
}
|
||||
do_catchsql_test 1.$tn.2 $alter $res
|
||||
|
||||
do_execsql_test 1.$tn.3 {
|
||||
SELECT sql FROM sqlite_schema WHERE name='t1'
|
||||
} [list $final]
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
reset_db
|
||||
proc xAuth {t args} {
|
||||
if {$t=="SQLITE_ALTER_TABLE"} {
|
||||
return "SQLITE_DENY"
|
||||
}
|
||||
return "SQLITE_OK"
|
||||
}
|
||||
sqlite3 db test.db
|
||||
db auth xAuth
|
||||
|
||||
do_execsql_test 2.0 {
|
||||
CREATE TABLE x1(a PRIMARY KEY, b CHECK(a!=b) NOT NULL, c);
|
||||
}
|
||||
|
||||
do_catchsql_test 2.1.1 {
|
||||
ALTER TABLE x1 ADD CONSTRAINT ccc CHECK (a!='a')
|
||||
} {1 {not authorized}}
|
||||
do_execsql_test 2.1.2 {
|
||||
SELECT sql FROM sqlite_schema WHERE name='x1'
|
||||
} {{CREATE TABLE x1(a PRIMARY KEY, b CHECK(a!=b) NOT NULL, c)}}
|
||||
|
||||
do_catchsql_test 2.2.1 {
|
||||
ALTER TABLE x1 ALTER c SET NOT NULL
|
||||
} {1 {not authorized}}
|
||||
do_execsql_test 2.2.2 {
|
||||
SELECT sql FROM sqlite_schema WHERE name='x1'
|
||||
} {{CREATE TABLE x1(a PRIMARY KEY, b CHECK(a!=b) NOT NULL, c)}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 3.0 {
|
||||
CREATE TABLE t1(x);
|
||||
}
|
||||
do_execsql_test 3.1 {
|
||||
ALTER TABLE t1 ALTER x SET NOT NULL;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 4.0 {
|
||||
CREATE TABLE abc(a, b, c, CONSTRAINT one CONSTRAINT two CHECK (b!=c));
|
||||
}
|
||||
do_execsql_test 4.1 {
|
||||
ALTER TABLE abc DROP CONSTRAINT one
|
||||
}
|
||||
do_execsql_test 4.2 {
|
||||
SELECT sql FROM sqlite_schema
|
||||
} {
|
||||
{CREATE TABLE abc(a, b, c, CONSTRAINT two CHECK (b!=c))}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
|
||||
# The columns must come before the table constraints in a CREATE TABLE
|
||||
# statement. This is useful, as it means the DROP CONSTRAINT code does
|
||||
# not have to handle the constraint immediately following the '(' at
|
||||
# the start of the column-list.
|
||||
do_catchsql_test 5.0 {
|
||||
CREATE TABLE abc(a, b, c, CONSTRAINT two CHECK (b!=c), d)
|
||||
} {1 {near "d": syntax error}}
|
||||
do_catchsql_test 5.1 {
|
||||
CREATE TABLE def(CONSTRAINT abc CHECK( b!=c ), a, b, c);
|
||||
} {1 {near "CONSTRAINT": syntax error}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 6.0 {
|
||||
CREATE TABLE abc(a, b CONSTRAINT two COLLATE nocase CHECK (a!=b), c CONSTRAINT one DEFAULT 'abc');
|
||||
}
|
||||
|
||||
do_execsql_test 6.1 {
|
||||
ALTER TABLE abc DROP CONSTRAINT one;
|
||||
ALTER TABLE abc DROP CONSTRAINT two;
|
||||
}
|
||||
|
||||
do_execsql_test 6.2 {
|
||||
SELECT sql FROM sqlite_schema
|
||||
} {
|
||||
{CREATE TABLE abc(a, b COLLATE nocase CHECK (a!=b), c DEFAULT 'abc')}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 7.0 {
|
||||
CREATE TABLE abc(a, b, c, CONSTRAINT one CHECK (a>b) FOREIGN KEY(a) REFERENCES abc);
|
||||
}
|
||||
do_execsql_test 7.1 {
|
||||
ALTER TABLE abc DROP CONSTRAINT one
|
||||
}
|
||||
do_execsql_test 7.2 {
|
||||
SELECT sql FROM sqlite_schema
|
||||
} {
|
||||
{CREATE TABLE abc(a, b, c, FOREIGN KEY(a) REFERENCES abc)}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 8.0 {
|
||||
CREATE TABLE abc(a, b, c, CONSTRAINT one FOREIGN KEY(a) REFERENCES abc);
|
||||
}
|
||||
do_catchsql_test 8.1 {
|
||||
ALTER TABLE abc DROP CONSTRAINT one
|
||||
} {1 {constraint may not be dropped: one}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 9.0 {
|
||||
CREATE TABLE abc(a, b NOT NULL AS (a+1))
|
||||
}
|
||||
do_execsql_test 9.1 {
|
||||
ALTER TABLE abc ALTER b DROP NOT NULL;
|
||||
SELECT sql FROM sqlite_schema;
|
||||
} {{CREATE TABLE abc(a, b AS (a+1))}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 10.0 {
|
||||
CREATE TABLE abc(a, b GENERATED ALWAYS AS (a+1));
|
||||
INSERT INTO abc VALUES(1), (2);
|
||||
SELECT * FROM abc;
|
||||
} {1 2 2 3}
|
||||
|
||||
do_execsql_test 10.1 {
|
||||
ALTER TABLE abc ALTER b SET NOT NULL;
|
||||
}
|
||||
do_catchsql_test 10.2 {
|
||||
INSERT INTO abc VALUES(NULL);
|
||||
} {1 {NOT NULL constraint failed: abc.b}}
|
||||
do_execsql_test 10.3 {
|
||||
INSERT INTO abc VALUES(3);
|
||||
ALTER TABLE abc ALTER COLUMN b DROP NOT NULL;
|
||||
}
|
||||
do_execsql_test 10.4 {
|
||||
INSERT INTO abc VALUES(NULL);
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 11.0 {
|
||||
CREATE TABLE t1(a, b, c);
|
||||
}
|
||||
|
||||
do_execsql_test 11.1.1 {
|
||||
ALTER TABLE t1 ADD CONSTRAINT c1 CHECK(a=b) --comment
|
||||
;
|
||||
}
|
||||
|
||||
do_execsql_test 11.1.2 {ALTER TABLE t1 ADD CONSTRAINT c2 CHECK(a=b) --comment}
|
||||
|
||||
do_execsql_test 11.1.3 {
|
||||
SELECT sql FROM sqlite_schema;
|
||||
} {
|
||||
{CREATE TABLE t1(a, b, c, CONSTRAINT c1 CHECK(a=b), CONSTRAINT c2 CHECK(a=b))}
|
||||
}
|
||||
|
||||
do_execsql_test 11.2.1 {
|
||||
CREATE TABLE t2(a, b);
|
||||
}
|
||||
do_execsql_test 11.2.2 {ALTER TABLE t2 ALTER b SET NOT NULL --new cons}
|
||||
do_execsql_test 11.2.3 {
|
||||
SELECT sql FROM sqlite_schema WHERE name='t2';
|
||||
} {
|
||||
{CREATE TABLE t2(a, b NOT NULL)}
|
||||
}
|
||||
do_execsql_test 11.2.3 {
|
||||
ALTER TABLE t2 ALTER b DROP NOT NULL;
|
||||
SELECT sql FROM sqlite_schema WHERE name='t2';
|
||||
} {
|
||||
{CREATE TABLE t2(a, b)}
|
||||
}
|
||||
do_execsql_test 11.2.2 {ALTER TABLE t2 ALTER b SET NOT NULL --new cons
|
||||
;
|
||||
}
|
||||
finish_test
|
||||
|
||||
@@ -39,6 +39,40 @@ do_faultsim_test 1.1 -faults oom* -prep {
|
||||
faultsim_test_result {0 {}}
|
||||
}
|
||||
|
||||
reset_db
|
||||
do_execsql_test 2.0 {
|
||||
CREATE TABLE x1(d, e CONSTRAINT abc NOT NULL, f);
|
||||
}
|
||||
faultsim_save_and_close
|
||||
|
||||
foreach {tn sql} {
|
||||
1 { ALTER TABLE x1 ADD CHECK (d!=1) }
|
||||
2 { ALTER TABLE x1 ADD CONSTRAINT xyz CHECK (f>d+e); }
|
||||
3 { ALTER TABLE x1 DROP CONSTRAINT abc }
|
||||
4 { ALTER TABLE x1 ALTER f SET NOT NULL }
|
||||
5 { ALTER TABLE x1 ALTER e DROP NOT NULL }
|
||||
} {
|
||||
do_faultsim_test 2.$tn -faults oom* -prep {
|
||||
faultsim_restore_and_reopen
|
||||
} -body {
|
||||
execsql $::sql
|
||||
} -test {
|
||||
faultsim_test_result {0 {}}
|
||||
}
|
||||
}
|
||||
|
||||
# Test an OOM when returning an error.
|
||||
#
|
||||
do_faultsim_test 2.e -faults oom* -prep {
|
||||
faultsim_restore_and_reopen
|
||||
} -body {
|
||||
execsql {
|
||||
ALTER TABLE x1 DROP CONSTRAINT nosuchconstraint
|
||||
}
|
||||
} -test {
|
||||
faultsim_test_result \
|
||||
{1 {no such constraint: nosuchconstraint}} \
|
||||
{1 {SQL logic error}}
|
||||
}
|
||||
|
||||
finish_test
|
||||
@@ -53,6 +53,9 @@ for {set tn 1} {1} {incr tn} {
|
||||
}
|
||||
}
|
||||
|
||||
do_catchsql_test 1.5 {
|
||||
INSERT INTO x1(x1) VALUES('maxpendinAB64');
|
||||
} {1 {SQL logic error}}
|
||||
|
||||
|
||||
finish_test
|
||||
+27
-8
@@ -27,10 +27,10 @@ SELECT * FROM t1;
|
||||
┌─────┬───────┬───────┬───────┬───────┐
|
||||
│ 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 │
|
||||
│ 1 │ 2.5 │ three │ DD │ │
|
||||
│ 2.5 │ three │ DD │ │ 1 │
|
||||
│ DD │ │ 1 │ 2.5 │ three │
|
||||
│ │ 1 │ 2.5 │ three │ DD │
|
||||
└─────┴───────┴───────┴───────┴───────┘
|
||||
END
|
||||
|
||||
@@ -41,10 +41,10 @@ SELECT * FROM t1;
|
||||
┌─────┬───────┬───────┬───────┬───────┐
|
||||
│ 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 │
|
||||
│ 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
|
||||
|
||||
@@ -62,3 +62,22 @@ END
|
||||
.output memory
|
||||
.mode -null abcde -v
|
||||
.output -glob ' --null "abcde"'
|
||||
|
||||
# Test cases for the ".explain off" command
|
||||
.mode box -reset
|
||||
.output memory
|
||||
EXPLAIN SELECT * FROM t1;
|
||||
.output --notglob *────* --keep
|
||||
.output --notglob "* id │ parent │ notused │ detail *" --keep
|
||||
.output --glob "* Init *"
|
||||
.output memory
|
||||
EXPLAIN QUERY PLAN SELECT * FROM t1;
|
||||
.output --glob "*`--SCAN *"
|
||||
.explain off
|
||||
.output memory
|
||||
EXPLAIN SELECT * FROM t1;
|
||||
.output --glob *────*
|
||||
.output memory
|
||||
EXPLAIN QUERY PLAN SELECT * FROM t1;
|
||||
.output --glob "* id │ parent │ notused │ detail *"
|
||||
.explain auto
|
||||
+179
-36
@@ -49,6 +49,14 @@ do_test 1.11b {
|
||||
│ x'424c4f42' │ │ 'Ἀμήν' │
|
||||
└─────────────┴─────┴─────────┘
|
||||
}
|
||||
do_test 1.11c {
|
||||
set result "\n[db format -text sql -border off {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}]"
|
||||
} {
|
||||
@@ -76,7 +84,7 @@ do_test 1.14 {
|
||||
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}
|
||||
} {bad BLOB encoding (-blob) "unk": must be auto, hex, json, tcl, text, sql, or size}
|
||||
do_test 1.16 {
|
||||
catch {db format -text sql -style unk {SELECT * FROM t1}} res
|
||||
set res
|
||||
@@ -112,20 +120,58 @@ do_test 1.31 {
|
||||
| BLOB | | Ἀμήν |
|
||||
+------+-----+-------+
|
||||
}
|
||||
do_test 1.32 {
|
||||
set result "\n[db format -style table -border off {SELECT * FROM t1}]"
|
||||
} {
|
||||
a | b | c
|
||||
------+-----+-------
|
||||
1 | 2.5 | three
|
||||
BLOB | | Ἀμήν
|
||||
}
|
||||
do_test 1.33 {
|
||||
set result "\n[db format -style table -border off \
|
||||
-screenwidth 15 \
|
||||
{SELECT * FROM t1}]"
|
||||
} {
|
||||
a | b | c
|
||||
----+---+-----
|
||||
1|2.5|three
|
||||
BLOB| |Ἀμήν
|
||||
}
|
||||
do_test 1.34 {
|
||||
set result "\n[db format -style box -border off \
|
||||
-screenwidth 30 \
|
||||
{SELECT * FROM t1}]"
|
||||
} {
|
||||
a │ b │ c
|
||||
──────┼─────┼───────
|
||||
1 │ 2.5 │ three
|
||||
BLOB │ │ Ἀμήν
|
||||
}
|
||||
do_test 1.35 {
|
||||
set result "\n[db format -style box -border off \
|
||||
-screenwidth 15 \
|
||||
{SELECT * FROM t1}]"
|
||||
} {
|
||||
a │ b │ c
|
||||
────┼───┼─────
|
||||
1│2.5│three
|
||||
BLOB│ │Ἀμήν
|
||||
}
|
||||
|
||||
do_test 1.40 {
|
||||
set result "\n[db format -style column {SELECT * FROM t1}]"
|
||||
} {
|
||||
a b c
|
||||
a b c
|
||||
---- --- -----
|
||||
1 2.5 three
|
||||
BLOB Ἀμήν
|
||||
BLOB Ἀμήν
|
||||
}
|
||||
do_test 1.41 {
|
||||
set result "\n[db format -style column -title off {SELECT * FROM t1}]"
|
||||
} {
|
||||
1 2.5 three
|
||||
BLOB Ἀμήν
|
||||
BLOB Ἀμήν
|
||||
}
|
||||
|
||||
do_test 1.50 {
|
||||
@@ -137,19 +183,19 @@ do_test 1.60a {
|
||||
} "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"
|
||||
} "1,2.5,three\r\nx'424c4f42',,\"Ἀμήν\"\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"
|
||||
} "a,b,c\r\n1,2.5,three\r\n\"\\102\\114\\117\\102\",,\"Ἀμήν\"\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"
|
||||
} "\"a x y\",b,c\r\n1,2.5,three\r\n\"\\102\\114\\117\\102\",,\"Ἀμήν\"\r\n"
|
||||
|
||||
do_test 1.70 {
|
||||
set result "\n[db format -style html {SELECT * FROM t1}]"
|
||||
@@ -683,15 +729,15 @@ do_test 5.3c {
|
||||
-text plain -esc off -textjsonb no \
|
||||
-wordwrap yes -linelimit 2 $sql]"
|
||||
} {
|
||||
name mtime time value
|
||||
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
|
||||
...
|
||||
one 1333206973 2012-03-31
|
||||
two 15:16:13
|
||||
...
|
||||
|
||||
entry-one 1708791504 2024-02-24 x'000000000000
|
||||
16:18:24 00000000000000
|
||||
@@ -730,31 +776,6 @@ do_test 6.1a {
|
||||
} {
|
||||
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);
|
||||
@@ -888,6 +909,128 @@ 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'),}
|
||||
do_test 9.3 {
|
||||
db format -style json {SELECT * FROM t9 WHERE rowid<0}
|
||||
} {}
|
||||
do_test 9.4 {
|
||||
db format -style jobject {SELECT * FROM t9 WHERE rowid<0}
|
||||
} {}
|
||||
|
||||
do_test 10.1 {
|
||||
db eval {
|
||||
DROP TABLE IF EXISTS t1;
|
||||
CREATE TABLE t1(x);
|
||||
INSERT INTO t1(x) VALUES
|
||||
('alice'),
|
||||
('bob'),
|
||||
('cinderella-cinderella'),
|
||||
('daniel'),
|
||||
('emma'),
|
||||
('fred'),
|
||||
('gertrude'),
|
||||
('harold'),
|
||||
('ingrid'),
|
||||
('jake'),
|
||||
('lisa'),
|
||||
('mike'),
|
||||
('nina'),
|
||||
('octavian'),
|
||||
('paula'),
|
||||
('quintus'),
|
||||
('rita'),
|
||||
('sam'),
|
||||
('tammy'),
|
||||
('ulysses'),
|
||||
('violet'),
|
||||
('william'),
|
||||
('xanthippe'),
|
||||
('yates'),
|
||||
('zoe');
|
||||
}
|
||||
set result "\n[db format -style column -title off -screenwidth 41 -splitcolumn on \
|
||||
{SELECT x FROM t1}]"
|
||||
} {
|
||||
alice octavian
|
||||
bob paula
|
||||
cinderella-cinderella quintus
|
||||
daniel rita
|
||||
emma sam
|
||||
fred tammy
|
||||
gertrude ulysses
|
||||
harold violet
|
||||
ingrid william
|
||||
jake xanthippe
|
||||
lisa yates
|
||||
mike zoe
|
||||
nina
|
||||
}
|
||||
do_test 10.2 {
|
||||
set result "\n[db format -style column -title off -screenwidth 42 -splitcolumn on \
|
||||
{SELECT x FROM t1}]"
|
||||
} {
|
||||
alice jake tammy
|
||||
bob lisa ulysses
|
||||
cinderella-cinderella mike violet
|
||||
daniel nina william
|
||||
emma octavian xanthippe
|
||||
fred paula yates
|
||||
gertrude quintus zoe
|
||||
harold rita
|
||||
ingrid sam
|
||||
}
|
||||
do_test 10.3 {
|
||||
set result "\n[db format -style column -title off -screenwidth 51 -splitcolumn on \
|
||||
{SELECT x FROM t1}]"
|
||||
} {
|
||||
alice harold paula william
|
||||
bob ingrid quintus xanthippe
|
||||
cinderella-cinderella jake rita yates
|
||||
daniel lisa sam zoe
|
||||
emma mike tammy
|
||||
fred nina ulysses
|
||||
gertrude octavian violet
|
||||
}
|
||||
do_test 10.4 {
|
||||
set result "\n[db format -style column -title off -screenwidth 61 -splitcolumn on \
|
||||
{SELECT x FROM t1}]"
|
||||
} {
|
||||
alice fred lisa quintus violet
|
||||
bob gertrude mike rita william
|
||||
cinderella-cinderella harold nina sam xanthippe
|
||||
daniel ingrid octavian tammy yates
|
||||
emma jake paula ulysses zoe
|
||||
}
|
||||
do_test 10.5 {
|
||||
set result "\n[db format -style column -title off -screenwidth 74 -splitcolumn on \
|
||||
{SELECT x FROM t1}]"
|
||||
} {
|
||||
alice emma ingrid nina rita violet zoe
|
||||
bob fred jake octavian sam william
|
||||
cinderella-cinderella gertrude lisa paula tammy xanthippe
|
||||
daniel harold mike quintus ulysses yates
|
||||
}
|
||||
|
||||
do_test 11.1 {
|
||||
set result "\n[db format -style table -blob size {SELECT randomblob(1234)}]"
|
||||
} {
|
||||
+------------------+
|
||||
| randomblob(1234) |
|
||||
+------------------+
|
||||
| (1234-byte blob) |
|
||||
+------------------+
|
||||
}
|
||||
|
||||
do_test 12.1 {
|
||||
set result "\n[db format -style box -text html \
|
||||
{SELECT 'abc','','xyz'}]"
|
||||
} {
|
||||
┌───────┬────┬───────┐
|
||||
│ 'abc' │ '' │ 'xyz' │
|
||||
├───────┼────┼───────┤
|
||||
│ abc │ │ xyz │
|
||||
└───────┴────┴───────┘
|
||||
}
|
||||
|
||||
db close
|
||||
|
||||
finish_test
|
||||
+40
-40
@@ -63,11 +63,11 @@ do_test 1.10 {
|
||||
┌───────┬───────┬───────┬───────┬──────┬───────┬───────┬───────┐
|
||||
│ 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 │
|
||||
│ 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 {
|
||||
@@ -78,11 +78,11 @@ do_test 1.11 {
|
||||
┌─────┬─────┬─────┬─────┬────┬─────┬─────┬─────┐
|
||||
│ 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 │
|
||||
│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│
|
||||
└─────┴─────┴─────┴─────┴────┴─────┴─────┴─────┘
|
||||
}
|
||||
|
||||
@@ -94,11 +94,11 @@ do_test 1.20 {
|
||||
+-------+-------+-------+-------+------+-------+-------+-------+
|
||||
| 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 |
|
||||
| 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 {
|
||||
@@ -109,11 +109,11 @@ do_test 1.21 {
|
||||
+-----+-----+-----+-----+----+-----+-----+-----+
|
||||
| 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 |
|
||||
|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|
|
||||
+-----+-----+-----+-----+----+-----+-----+-----+
|
||||
}
|
||||
|
||||
@@ -124,11 +124,11 @@ do_test 1.30 {
|
||||
} {
|
||||
| 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 |
|
||||
| 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 \
|
||||
@@ -137,11 +137,11 @@ do_test 1.31 {
|
||||
} {
|
||||
| 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 |
|
||||
|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 {
|
||||
@@ -151,11 +151,11 @@ do_test 1.40 {
|
||||
} {
|
||||
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
|
||||
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 \
|
||||
@@ -164,11 +164,11 @@ do_test 1.41 {
|
||||
} {
|
||||
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
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
|
||||
+750
@@ -0,0 +1,750 @@
|
||||
# 2025-11-23
|
||||
#
|
||||
# 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), and especially
|
||||
# the bSplitColumn feature.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix qrf01
|
||||
|
||||
# The expected output from test 1.1. The "do_test" procedure normally
|
||||
# ignores differences in whitespace, but whitespace is important for
|
||||
# this test, so we have to do the comparison ourselves.
|
||||
#
|
||||
set expected {
|
||||
<---- 22 ---->
|
||||
alice
|
||||
bob
|
||||
cinderella-cinderella
|
||||
daniel
|
||||
emma
|
||||
fred
|
||||
gertrude
|
||||
harold
|
||||
ingrid
|
||||
jake
|
||||
lisa
|
||||
mike
|
||||
nina
|
||||
octavian
|
||||
paula
|
||||
quintus
|
||||
rita
|
||||
sam
|
||||
tammy
|
||||
ulysses
|
||||
violet
|
||||
william
|
||||
xanthippe
|
||||
yates
|
||||
zoe
|
||||
<---- 23 ---->
|
||||
alice
|
||||
bob
|
||||
cinderella-cinderella
|
||||
daniel
|
||||
emma
|
||||
fred
|
||||
gertrude
|
||||
harold
|
||||
ingrid
|
||||
jake
|
||||
lisa
|
||||
mike
|
||||
nina
|
||||
octavian
|
||||
paula
|
||||
quintus
|
||||
rita
|
||||
sam
|
||||
tammy
|
||||
ulysses
|
||||
violet
|
||||
william
|
||||
xanthippe
|
||||
yates
|
||||
zoe
|
||||
<---- 24 ---->
|
||||
alice
|
||||
bob
|
||||
cinderella-cinderella
|
||||
daniel
|
||||
emma
|
||||
fred
|
||||
gertrude
|
||||
harold
|
||||
ingrid
|
||||
jake
|
||||
lisa
|
||||
mike
|
||||
nina
|
||||
octavian
|
||||
paula
|
||||
quintus
|
||||
rita
|
||||
sam
|
||||
tammy
|
||||
ulysses
|
||||
violet
|
||||
william
|
||||
xanthippe
|
||||
yates
|
||||
zoe
|
||||
<---- 25 ---->
|
||||
alice
|
||||
bob
|
||||
cinderella-cinderella
|
||||
daniel
|
||||
emma
|
||||
fred
|
||||
gertrude
|
||||
harold
|
||||
ingrid
|
||||
jake
|
||||
lisa
|
||||
mike
|
||||
nina
|
||||
octavian
|
||||
paula
|
||||
quintus
|
||||
rita
|
||||
sam
|
||||
tammy
|
||||
ulysses
|
||||
violet
|
||||
william
|
||||
xanthippe
|
||||
yates
|
||||
zoe
|
||||
<---- 26 ---->
|
||||
alice
|
||||
bob
|
||||
cinderella-cinderella
|
||||
daniel
|
||||
emma
|
||||
fred
|
||||
gertrude
|
||||
harold
|
||||
ingrid
|
||||
jake
|
||||
lisa
|
||||
mike
|
||||
nina
|
||||
octavian
|
||||
paula
|
||||
quintus
|
||||
rita
|
||||
sam
|
||||
tammy
|
||||
ulysses
|
||||
violet
|
||||
william
|
||||
xanthippe
|
||||
yates
|
||||
zoe
|
||||
<---- 27 ---->
|
||||
alice
|
||||
bob
|
||||
cinderella-cinderella
|
||||
daniel
|
||||
emma
|
||||
fred
|
||||
gertrude
|
||||
harold
|
||||
ingrid
|
||||
jake
|
||||
lisa
|
||||
mike
|
||||
nina
|
||||
octavian
|
||||
paula
|
||||
quintus
|
||||
rita
|
||||
sam
|
||||
tammy
|
||||
ulysses
|
||||
violet
|
||||
william
|
||||
xanthippe
|
||||
yates
|
||||
zoe
|
||||
<---- 28 ---->
|
||||
alice
|
||||
bob
|
||||
cinderella-cinderella
|
||||
daniel
|
||||
emma
|
||||
fred
|
||||
gertrude
|
||||
harold
|
||||
ingrid
|
||||
jake
|
||||
lisa
|
||||
mike
|
||||
nina
|
||||
octavian
|
||||
paula
|
||||
quintus
|
||||
rita
|
||||
sam
|
||||
tammy
|
||||
ulysses
|
||||
violet
|
||||
william
|
||||
xanthippe
|
||||
yates
|
||||
zoe
|
||||
<---- 29 ---->
|
||||
alice
|
||||
bob
|
||||
cinderella-cinderella
|
||||
daniel
|
||||
emma
|
||||
fred
|
||||
gertrude
|
||||
harold
|
||||
ingrid
|
||||
jake
|
||||
lisa
|
||||
mike
|
||||
nina
|
||||
octavian
|
||||
paula
|
||||
quintus
|
||||
rita
|
||||
sam
|
||||
tammy
|
||||
ulysses
|
||||
violet
|
||||
william
|
||||
xanthippe
|
||||
yates
|
||||
zoe
|
||||
<---- 30 ---->
|
||||
alice
|
||||
bob
|
||||
cinderella-cinderella
|
||||
daniel
|
||||
emma
|
||||
fred
|
||||
gertrude
|
||||
harold
|
||||
ingrid
|
||||
jake
|
||||
lisa
|
||||
mike
|
||||
nina
|
||||
octavian
|
||||
paula
|
||||
quintus
|
||||
rita
|
||||
sam
|
||||
tammy
|
||||
ulysses
|
||||
violet
|
||||
william
|
||||
xanthippe
|
||||
yates
|
||||
zoe
|
||||
<---- 31 ---->
|
||||
alice
|
||||
bob
|
||||
cinderella-cinderella
|
||||
daniel
|
||||
emma
|
||||
fred
|
||||
gertrude
|
||||
harold
|
||||
ingrid
|
||||
jake
|
||||
lisa
|
||||
mike
|
||||
nina
|
||||
octavian
|
||||
paula
|
||||
quintus
|
||||
rita
|
||||
sam
|
||||
tammy
|
||||
ulysses
|
||||
violet
|
||||
william
|
||||
xanthippe
|
||||
yates
|
||||
zoe
|
||||
<---- 32 ---->
|
||||
alice octavian
|
||||
bob paula
|
||||
cinderella-cinderella quintus
|
||||
daniel rita
|
||||
emma sam
|
||||
fred tammy
|
||||
gertrude ulysses
|
||||
harold violet
|
||||
ingrid william
|
||||
jake xanthippe
|
||||
lisa yates
|
||||
mike zoe
|
||||
nina
|
||||
<---- 33 ---->
|
||||
alice octavian
|
||||
bob paula
|
||||
cinderella-cinderella quintus
|
||||
daniel rita
|
||||
emma sam
|
||||
fred tammy
|
||||
gertrude ulysses
|
||||
harold violet
|
||||
ingrid william
|
||||
jake xanthippe
|
||||
lisa yates
|
||||
mike zoe
|
||||
nina
|
||||
<---- 34 ---->
|
||||
alice octavian
|
||||
bob paula
|
||||
cinderella-cinderella quintus
|
||||
daniel rita
|
||||
emma sam
|
||||
fred tammy
|
||||
gertrude ulysses
|
||||
harold violet
|
||||
ingrid william
|
||||
jake xanthippe
|
||||
lisa yates
|
||||
mike zoe
|
||||
nina
|
||||
<---- 35 ---->
|
||||
alice octavian
|
||||
bob paula
|
||||
cinderella-cinderella quintus
|
||||
daniel rita
|
||||
emma sam
|
||||
fred tammy
|
||||
gertrude ulysses
|
||||
harold violet
|
||||
ingrid william
|
||||
jake xanthippe
|
||||
lisa yates
|
||||
mike zoe
|
||||
nina
|
||||
<---- 36 ---->
|
||||
alice octavian
|
||||
bob paula
|
||||
cinderella-cinderella quintus
|
||||
daniel rita
|
||||
emma sam
|
||||
fred tammy
|
||||
gertrude ulysses
|
||||
harold violet
|
||||
ingrid william
|
||||
jake xanthippe
|
||||
lisa yates
|
||||
mike zoe
|
||||
nina
|
||||
<---- 37 ---->
|
||||
alice octavian
|
||||
bob paula
|
||||
cinderella-cinderella quintus
|
||||
daniel rita
|
||||
emma sam
|
||||
fred tammy
|
||||
gertrude ulysses
|
||||
harold violet
|
||||
ingrid william
|
||||
jake xanthippe
|
||||
lisa yates
|
||||
mike zoe
|
||||
nina
|
||||
<---- 38 ---->
|
||||
alice octavian
|
||||
bob paula
|
||||
cinderella-cinderella quintus
|
||||
daniel rita
|
||||
emma sam
|
||||
fred tammy
|
||||
gertrude ulysses
|
||||
harold violet
|
||||
ingrid william
|
||||
jake xanthippe
|
||||
lisa yates
|
||||
mike zoe
|
||||
nina
|
||||
<---- 39 ---->
|
||||
alice octavian
|
||||
bob paula
|
||||
cinderella-cinderella quintus
|
||||
daniel rita
|
||||
emma sam
|
||||
fred tammy
|
||||
gertrude ulysses
|
||||
harold violet
|
||||
ingrid william
|
||||
jake xanthippe
|
||||
lisa yates
|
||||
mike zoe
|
||||
nina
|
||||
<---- 40 ---->
|
||||
alice octavian
|
||||
bob paula
|
||||
cinderella-cinderella quintus
|
||||
daniel rita
|
||||
emma sam
|
||||
fred tammy
|
||||
gertrude ulysses
|
||||
harold violet
|
||||
ingrid william
|
||||
jake xanthippe
|
||||
lisa yates
|
||||
mike zoe
|
||||
nina
|
||||
<---- 41 ---->
|
||||
alice octavian
|
||||
bob paula
|
||||
cinderella-cinderella quintus
|
||||
daniel rita
|
||||
emma sam
|
||||
fred tammy
|
||||
gertrude ulysses
|
||||
harold violet
|
||||
ingrid william
|
||||
jake xanthippe
|
||||
lisa yates
|
||||
mike zoe
|
||||
nina
|
||||
<---- 42 ---->
|
||||
alice jake tammy
|
||||
bob lisa ulysses
|
||||
cinderella-cinderella mike violet
|
||||
daniel nina william
|
||||
emma octavian xanthippe
|
||||
fred paula yates
|
||||
gertrude quintus zoe
|
||||
harold rita
|
||||
ingrid sam
|
||||
<---- 43 ---->
|
||||
alice jake tammy
|
||||
bob lisa ulysses
|
||||
cinderella-cinderella mike violet
|
||||
daniel nina william
|
||||
emma octavian xanthippe
|
||||
fred paula yates
|
||||
gertrude quintus zoe
|
||||
harold rita
|
||||
ingrid sam
|
||||
<---- 44 ---->
|
||||
alice jake tammy
|
||||
bob lisa ulysses
|
||||
cinderella-cinderella mike violet
|
||||
daniel nina william
|
||||
emma octavian xanthippe
|
||||
fred paula yates
|
||||
gertrude quintus zoe
|
||||
harold rita
|
||||
ingrid sam
|
||||
<---- 45 ---->
|
||||
alice jake tammy
|
||||
bob lisa ulysses
|
||||
cinderella-cinderella mike violet
|
||||
daniel nina william
|
||||
emma octavian xanthippe
|
||||
fred paula yates
|
||||
gertrude quintus zoe
|
||||
harold rita
|
||||
ingrid sam
|
||||
<---- 46 ---->
|
||||
alice jake tammy
|
||||
bob lisa ulysses
|
||||
cinderella-cinderella mike violet
|
||||
daniel nina william
|
||||
emma octavian xanthippe
|
||||
fred paula yates
|
||||
gertrude quintus zoe
|
||||
harold rita
|
||||
ingrid sam
|
||||
<---- 47 ---->
|
||||
alice jake tammy
|
||||
bob lisa ulysses
|
||||
cinderella-cinderella mike violet
|
||||
daniel nina william
|
||||
emma octavian xanthippe
|
||||
fred paula yates
|
||||
gertrude quintus zoe
|
||||
harold rita
|
||||
ingrid sam
|
||||
<---- 48 ---->
|
||||
alice jake tammy
|
||||
bob lisa ulysses
|
||||
cinderella-cinderella mike violet
|
||||
daniel nina william
|
||||
emma octavian xanthippe
|
||||
fred paula yates
|
||||
gertrude quintus zoe
|
||||
harold rita
|
||||
ingrid sam
|
||||
<---- 49 ---->
|
||||
alice jake tammy
|
||||
bob lisa ulysses
|
||||
cinderella-cinderella mike violet
|
||||
daniel nina william
|
||||
emma octavian xanthippe
|
||||
fred paula yates
|
||||
gertrude quintus zoe
|
||||
harold rita
|
||||
ingrid sam
|
||||
<---- 50 ---->
|
||||
alice jake tammy
|
||||
bob lisa ulysses
|
||||
cinderella-cinderella mike violet
|
||||
daniel nina william
|
||||
emma octavian xanthippe
|
||||
fred paula yates
|
||||
gertrude quintus zoe
|
||||
harold rita
|
||||
ingrid sam
|
||||
<---- 51 ---->
|
||||
alice harold paula william
|
||||
bob ingrid quintus xanthippe
|
||||
cinderella-cinderella jake rita yates
|
||||
daniel lisa sam zoe
|
||||
emma mike tammy
|
||||
fred nina ulysses
|
||||
gertrude octavian violet
|
||||
<---- 52 ---->
|
||||
alice harold paula william
|
||||
bob ingrid quintus xanthippe
|
||||
cinderella-cinderella jake rita yates
|
||||
daniel lisa sam zoe
|
||||
emma mike tammy
|
||||
fred nina ulysses
|
||||
gertrude octavian violet
|
||||
<---- 53 ---->
|
||||
alice harold paula william
|
||||
bob ingrid quintus xanthippe
|
||||
cinderella-cinderella jake rita yates
|
||||
daniel lisa sam zoe
|
||||
emma mike tammy
|
||||
fred nina ulysses
|
||||
gertrude octavian violet
|
||||
<---- 54 ---->
|
||||
alice harold paula william
|
||||
bob ingrid quintus xanthippe
|
||||
cinderella-cinderella jake rita yates
|
||||
daniel lisa sam zoe
|
||||
emma mike tammy
|
||||
fred nina ulysses
|
||||
gertrude octavian violet
|
||||
<---- 55 ---->
|
||||
alice harold paula william
|
||||
bob ingrid quintus xanthippe
|
||||
cinderella-cinderella jake rita yates
|
||||
daniel lisa sam zoe
|
||||
emma mike tammy
|
||||
fred nina ulysses
|
||||
gertrude octavian violet
|
||||
<---- 56 ---->
|
||||
alice harold paula william
|
||||
bob ingrid quintus xanthippe
|
||||
cinderella-cinderella jake rita yates
|
||||
daniel lisa sam zoe
|
||||
emma mike tammy
|
||||
fred nina ulysses
|
||||
gertrude octavian violet
|
||||
<---- 57 ---->
|
||||
alice harold paula william
|
||||
bob ingrid quintus xanthippe
|
||||
cinderella-cinderella jake rita yates
|
||||
daniel lisa sam zoe
|
||||
emma mike tammy
|
||||
fred nina ulysses
|
||||
gertrude octavian violet
|
||||
<---- 58 ---->
|
||||
alice harold paula william
|
||||
bob ingrid quintus xanthippe
|
||||
cinderella-cinderella jake rita yates
|
||||
daniel lisa sam zoe
|
||||
emma mike tammy
|
||||
fred nina ulysses
|
||||
gertrude octavian violet
|
||||
<---- 59 ---->
|
||||
alice harold paula william
|
||||
bob ingrid quintus xanthippe
|
||||
cinderella-cinderella jake rita yates
|
||||
daniel lisa sam zoe
|
||||
emma mike tammy
|
||||
fred nina ulysses
|
||||
gertrude octavian violet
|
||||
<---- 60 ---->
|
||||
alice harold paula william
|
||||
bob ingrid quintus xanthippe
|
||||
cinderella-cinderella jake rita yates
|
||||
daniel lisa sam zoe
|
||||
emma mike tammy
|
||||
fred nina ulysses
|
||||
gertrude octavian violet
|
||||
<---- 61 ---->
|
||||
alice fred lisa quintus violet
|
||||
bob gertrude mike rita william
|
||||
cinderella-cinderella harold nina sam xanthippe
|
||||
daniel ingrid octavian tammy yates
|
||||
emma jake paula ulysses zoe
|
||||
<---- 62 ---->
|
||||
alice fred lisa quintus violet
|
||||
bob gertrude mike rita william
|
||||
cinderella-cinderella harold nina sam xanthippe
|
||||
daniel ingrid octavian tammy yates
|
||||
emma jake paula ulysses zoe
|
||||
<---- 63 ---->
|
||||
alice fred lisa quintus violet
|
||||
bob gertrude mike rita william
|
||||
cinderella-cinderella harold nina sam xanthippe
|
||||
daniel ingrid octavian tammy yates
|
||||
emma jake paula ulysses zoe
|
||||
<---- 64 ---->
|
||||
alice fred lisa quintus violet
|
||||
bob gertrude mike rita william
|
||||
cinderella-cinderella harold nina sam xanthippe
|
||||
daniel ingrid octavian tammy yates
|
||||
emma jake paula ulysses zoe
|
||||
<---- 65 ---->
|
||||
alice fred lisa quintus violet
|
||||
bob gertrude mike rita william
|
||||
cinderella-cinderella harold nina sam xanthippe
|
||||
daniel ingrid octavian tammy yates
|
||||
emma jake paula ulysses zoe
|
||||
<---- 66 ---->
|
||||
alice fred lisa quintus violet
|
||||
bob gertrude mike rita william
|
||||
cinderella-cinderella harold nina sam xanthippe
|
||||
daniel ingrid octavian tammy yates
|
||||
emma jake paula ulysses zoe
|
||||
<---- 67 ---->
|
||||
alice fred lisa quintus violet
|
||||
bob gertrude mike rita william
|
||||
cinderella-cinderella harold nina sam xanthippe
|
||||
daniel ingrid octavian tammy yates
|
||||
emma jake paula ulysses zoe
|
||||
<---- 68 ---->
|
||||
alice fred lisa quintus violet
|
||||
bob gertrude mike rita william
|
||||
cinderella-cinderella harold nina sam xanthippe
|
||||
daniel ingrid octavian tammy yates
|
||||
emma jake paula ulysses zoe
|
||||
<---- 69 ---->
|
||||
alice fred lisa quintus violet
|
||||
bob gertrude mike rita william
|
||||
cinderella-cinderella harold nina sam xanthippe
|
||||
daniel ingrid octavian tammy yates
|
||||
emma jake paula ulysses zoe
|
||||
<---- 70 ---->
|
||||
alice fred lisa quintus violet
|
||||
bob gertrude mike rita william
|
||||
cinderella-cinderella harold nina sam xanthippe
|
||||
daniel ingrid octavian tammy yates
|
||||
emma jake paula ulysses zoe
|
||||
<---- 71 ---->
|
||||
alice fred lisa quintus violet
|
||||
bob gertrude mike rita william
|
||||
cinderella-cinderella harold nina sam xanthippe
|
||||
daniel ingrid octavian tammy yates
|
||||
emma jake paula ulysses zoe
|
||||
<---- 72 ---->
|
||||
alice fred lisa quintus violet
|
||||
bob gertrude mike rita william
|
||||
cinderella-cinderella harold nina sam xanthippe
|
||||
daniel ingrid octavian tammy yates
|
||||
emma jake paula ulysses zoe
|
||||
<---- 73 ---->
|
||||
alice fred lisa quintus violet
|
||||
bob gertrude mike rita william
|
||||
cinderella-cinderella harold nina sam xanthippe
|
||||
daniel ingrid octavian tammy yates
|
||||
emma jake paula ulysses zoe
|
||||
<---- 74 ---->
|
||||
alice emma ingrid nina rita violet zoe
|
||||
bob fred jake octavian sam william
|
||||
cinderella-cinderella gertrude lisa paula tammy xanthippe
|
||||
daniel harold mike quintus ulysses yates
|
||||
<---- 75 ---->
|
||||
alice emma ingrid nina rita violet zoe
|
||||
bob fred jake octavian sam william
|
||||
cinderella-cinderella gertrude lisa paula tammy xanthippe
|
||||
daniel harold mike quintus ulysses yates
|
||||
<---- 76 ---->
|
||||
alice emma ingrid nina rita violet zoe
|
||||
bob fred jake octavian sam william
|
||||
cinderella-cinderella gertrude lisa paula tammy xanthippe
|
||||
daniel harold mike quintus ulysses yates
|
||||
<---- 77 ---->
|
||||
alice emma ingrid nina rita violet zoe
|
||||
bob fred jake octavian sam william
|
||||
cinderella-cinderella gertrude lisa paula tammy xanthippe
|
||||
daniel harold mike quintus ulysses yates
|
||||
<---- 78 ---->
|
||||
alice emma ingrid nina rita violet zoe
|
||||
bob fred jake octavian sam william
|
||||
cinderella-cinderella gertrude lisa paula tammy xanthippe
|
||||
daniel harold mike quintus ulysses yates
|
||||
<---- 79 ---->
|
||||
alice emma ingrid nina rita violet zoe
|
||||
bob fred jake octavian sam william
|
||||
cinderella-cinderella gertrude lisa paula tammy xanthippe
|
||||
daniel harold mike quintus ulysses yates
|
||||
<---- 80 ---->
|
||||
alice emma ingrid nina rita violet zoe
|
||||
bob fred jake octavian sam william
|
||||
cinderella-cinderella gertrude lisa paula tammy xanthippe
|
||||
daniel harold mike quintus ulysses yates
|
||||
}
|
||||
|
||||
do_test 1.0 {
|
||||
db eval {
|
||||
CREATE TABLE t1(x);
|
||||
INSERT INTO t1(x) VALUES
|
||||
('alice'),
|
||||
('bob'),
|
||||
('cinderella-cinderella'),
|
||||
('daniel'),
|
||||
('emma'),
|
||||
('fred'),
|
||||
('gertrude'),
|
||||
('harold'),
|
||||
('ingrid'),
|
||||
('jake'),
|
||||
('lisa'),
|
||||
('mike'),
|
||||
('nina'),
|
||||
('octavian'),
|
||||
('paula'),
|
||||
('quintus'),
|
||||
('rita'),
|
||||
('sam'),
|
||||
('tammy'),
|
||||
('ulysses'),
|
||||
('violet'),
|
||||
('william'),
|
||||
('xanthippe'),
|
||||
('yates'),
|
||||
('zoe');
|
||||
}
|
||||
set res \n
|
||||
for {set i 22} {$i<=80} {incr i} {
|
||||
set sp [expr {$i-13}]
|
||||
append res [format "<----%*s%3d%*s---->\n" \
|
||||
[expr {$sp/2}] {} $i [expr {$sp-$sp/2}] {}]
|
||||
append res [db format -style column -title off \
|
||||
-screenwidth $i -splitcolumn on \
|
||||
{SELECT x FROM t1 ORDER BY x ASC}]
|
||||
}
|
||||
expr {$res eq $::expected}
|
||||
} {1}
|
||||
+8
-2
@@ -731,7 +731,7 @@ do_test shell1-3.26.5 {
|
||||
do_test shell1-3.26.6 {
|
||||
catchcmd "test.db" ".mode column\n.header off\n.width -10 10\nSELECT 'abcdefg', 123456;"
|
||||
# this should be treated the same as a '1' width for col 1 and 2
|
||||
} {0 { abcdefg 123456 }}
|
||||
} {0 { abcdefg 123456}}
|
||||
|
||||
|
||||
# .timer ON|OFF Turn the CPU timer measurement on or off
|
||||
@@ -931,7 +931,7 @@ do_test shell1-4.1.6 {
|
||||
(4,2.25), (5,'hello'), (6,x'807f');
|
||||
}
|
||||
catchcmd test2.db {.dump --preserve-rowids}
|
||||
} {1 {The --preserve-rowids option is not compatible with SQLITE_OMIT_VIRTUALTABLE}}
|
||||
} {/.* --preserve-rowids option is not compatible with SQLITE_OMIT_VIRTUALTABLE/}
|
||||
|
||||
}
|
||||
|
||||
@@ -1311,6 +1311,12 @@ do_test shell1-8.4 {
|
||||
+------------------+-----+
|
||||
| 6683623321994527 | -47 |
|
||||
+------------------+-----+}}
|
||||
do_test shell1-8.4b {
|
||||
catchcmd ":memory: --psql" \
|
||||
{SELECT ieee754_mantissa(47.49) AS M, ieee754_exponent(47.49) AS E;}
|
||||
} {0 { M | E
|
||||
------------------+-----
|
||||
6683623321994527 | -47}}
|
||||
do_test_with_ansi_output shell1-8.5 {
|
||||
catchcmd ":memory: --box" {
|
||||
create table t(a text, b int);
|
||||
|
||||
@@ -197,6 +197,24 @@ do_test_with_ansi_output shellA-4.1 {
|
||||
│ 8 │ last line │
|
||||
└───┴──────────────────────────┘
|
||||
}
|
||||
do_test_with_ansi_output shellA-4.1b {
|
||||
exec {*}$CLI -noinit test.db --box --escape ascii \
|
||||
{.mode -border off} \
|
||||
{SELECT a, x FROM t1 WHERE a IN (1,2,6,7,8)}
|
||||
} {
|
||||
a │ x
|
||||
───┼──────────────────────────
|
||||
1 │ line with ' single quote
|
||||
───┼──────────────────────────
|
||||
2 │ ^[[31mVT-100 codes^[[0m
|
||||
───┼──────────────────────────
|
||||
6 │ new
|
||||
│ line
|
||||
───┼──────────────────────────
|
||||
7 │ carriage^Mreturn
|
||||
───┼──────────────────────────
|
||||
8 │ last line
|
||||
}
|
||||
do_test_with_ansi_output shellA-4.2 {
|
||||
exec {*}$CLI -noinit test.db {.mode qbox} {SELECT a, x FROM t1 WHERE a IN (1,2,6,7,8)}
|
||||
} {
|
||||
@@ -210,6 +228,18 @@ do_test_with_ansi_output shellA-4.2 {
|
||||
│ 8 │ 'last line' │
|
||||
└───┴───────────────────────────────────────────┘
|
||||
}
|
||||
do_test_with_ansi_output shellA-4.2b {
|
||||
exec {*}$CLI -noinit test.db {.mode qbox -border off} \
|
||||
{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 │ unistr('new\u000aline')
|
||||
7 │ unistr('carriage\u000dreturn')
|
||||
8 │ 'last line'
|
||||
}
|
||||
|
||||
# ".mode insert"
|
||||
#
|
||||
@@ -250,4 +280,83 @@ INSERT INTO t1 VALUES(7,'carriage\rreturn');
|
||||
INSERT INTO t1 VALUES(8,'last line');
|
||||
"
|
||||
|
||||
# ".mode split"
|
||||
#
|
||||
do_test shellA-6.1 {
|
||||
db eval {
|
||||
CREATE TABLE t2(x);
|
||||
INSERT INTO t2(x) VALUES
|
||||
('one'), ('two'), ('three'), ('four'), ('five'),
|
||||
('six'), ('seven'), ('eight'), ('nine'), ('ten'),
|
||||
('eleven'), ('twelve'), ('thirteen'), ('fourteen');
|
||||
}
|
||||
exec {*}$CLI -noinit test.db \
|
||||
{.print} \
|
||||
{.mode split -screenwidth 30} \
|
||||
{SELECT x FROM t2}
|
||||
} {
|
||||
one five nine thirteen
|
||||
two six ten fourteen
|
||||
three seven eleven
|
||||
four eight twelve}
|
||||
# 3456789 123456789 123456789
|
||||
|
||||
do_test shellA-6.2 {
|
||||
exec {*}$CLI -noinit test.db \
|
||||
{.print} \
|
||||
{.mode split -screenwidth 30} \
|
||||
{SELECT x FROM t2} \
|
||||
{.mode column -titles off} \
|
||||
{SELECT x FROM t2}
|
||||
} {
|
||||
one five nine thirteen
|
||||
two six ten fourteen
|
||||
three seven eleven
|
||||
four eight twelve
|
||||
one
|
||||
two
|
||||
three
|
||||
four
|
||||
five
|
||||
six
|
||||
seven
|
||||
eight
|
||||
nine
|
||||
ten
|
||||
eleven
|
||||
twelve
|
||||
thirteen
|
||||
fourteen}
|
||||
|
||||
do_test shellA-6.3 {
|
||||
exec {*}$CLI -noinit test.db \
|
||||
{.print} \
|
||||
{.mode table} \
|
||||
{.mode --once split -screenwidth 30} \
|
||||
{SELECT x FROM t2} \
|
||||
{SELECT x FROM t2}
|
||||
} {
|
||||
one five nine thirteen
|
||||
two six ten fourteen
|
||||
three seven eleven
|
||||
four eight twelve
|
||||
+----------+
|
||||
| x |
|
||||
+----------+
|
||||
| one |
|
||||
| two |
|
||||
| three |
|
||||
| four |
|
||||
| five |
|
||||
| six |
|
||||
| seven |
|
||||
| eight |
|
||||
| nine |
|
||||
| ten |
|
||||
| eleven |
|
||||
| twelve |
|
||||
| thirteen |
|
||||
| fourteen |
|
||||
+----------+}
|
||||
|
||||
finish_test
|
||||
+1
-1
@@ -29,7 +29,7 @@ proc do_clitest {name} {
|
||||
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
|
||||
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"}
|
||||
|
||||
+14
-4
@@ -212,7 +212,8 @@ proc default_njob {} {
|
||||
if {$nCore<=2} {
|
||||
set nHelper 1
|
||||
} else {
|
||||
set nHelper [expr int($nCore*0.5)]
|
||||
set nHelper [expr int($nCore*0.8)]
|
||||
if {$nHelper>20} {set nHelper 20}
|
||||
}
|
||||
return $nHelper
|
||||
}
|
||||
@@ -706,9 +707,18 @@ if {[llength $argv]>=1
|
||||
}
|
||||
}
|
||||
|
||||
if {![file readable $TRG(dbname)]} {
|
||||
puts "Database missing: $TRG(dbname)"
|
||||
exit
|
||||
set once 1
|
||||
while {![file readable $TRG(dbname)]} {
|
||||
if {$delay==0} {
|
||||
puts "Database missing: $TRG(dbname)"
|
||||
exit
|
||||
}
|
||||
if {$once} {
|
||||
set once 0
|
||||
puts "Waiting for testing to start...."
|
||||
flush stdout
|
||||
}
|
||||
after [expr {$delay*1000}]
|
||||
}
|
||||
sqlite3 mydb $TRG(dbname)
|
||||
mydb timeout 2000
|
||||
|
||||
@@ -668,8 +668,8 @@ int main(int argc, char **argv){
|
||||
printf("/* Check to see if z[0..n-1] is a keyword. If it is, write the\n");
|
||||
printf("** parser symbol code for that keyword into *pType. Always\n");
|
||||
printf("** return the integer n (the length of the token). */\n");
|
||||
printf("static int keywordCode(const char *z, int n, int *pType){\n");
|
||||
printf(" int i, j;\n");
|
||||
printf("static i64 keywordCode(const char *z, i64 n, int *pType){\n");
|
||||
printf(" i64 i, j;\n");
|
||||
printf(" const char *zKW;\n");
|
||||
printf(" assert( n>=2 );\n");
|
||||
printf(" i = ((charMap(z[0])*%d) %c", HASH_C0, HASH_CC);
|
||||
|
||||
Reference in new issue
Block a user