Compare commits
3 Commits
88d8e60511
...
537a8654fa
Author | SHA1 | Date | |
---|---|---|---|
537a8654fa | |||
9de33d06d2 | |||
0e5f320664 |
31
GNUmakefile
31
GNUmakefile
@ -7,6 +7,8 @@ VERSION_CODE := 17
|
|||||||
VERSION_NUMBER := 0.0.17-wip
|
VERSION_NUMBER := 0.0.17-wip
|
||||||
VERSION_NAME := Please enjoy responsibly.
|
VERSION_NAME := Please enjoy responsibly.
|
||||||
|
|
||||||
|
SQLITE_URL := https://www.sqlite.org/2024/sqlite-amalgamation-3450200.zip
|
||||||
|
|
||||||
PROJECT = tildefriends
|
PROJECT = tildefriends
|
||||||
BUILD_DIR ?= out
|
BUILD_DIR ?= out
|
||||||
UNAME_S := $(shell uname -s)
|
UNAME_S := $(shell uname -s)
|
||||||
@ -14,6 +16,18 @@ UNAME_M := $(shell uname -m)
|
|||||||
|
|
||||||
ANDROID_SDK ?= ~/Android/Sdk
|
ANDROID_SDK ?= ~/Android/Sdk
|
||||||
|
|
||||||
|
ifeq ($(UNAME_M),x86_64)
|
||||||
|
ifneq ($(UNAME_S),Haiku)
|
||||||
|
debug: CFLAGS += -fsanitize=address -fsanitize=undefined -fno-common
|
||||||
|
debug: LDFLAGS += -fsanitize=address -fsanitize=undefined
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(UNAME_M),aarch64)
|
||||||
|
debug: CFLAGS += -fsanitize=address -fsanitize=undefined -fno-common
|
||||||
|
debug: LDFLAGS += -fsanitize=address -fsanitize=undefined
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(UNAME_S),Darwin)
|
ifeq ($(UNAME_S),Darwin)
|
||||||
BUILD_TYPES := macosdebug macosrelease iosdebug iosrelease iossimdebug iossimrelease
|
BUILD_TYPES := macosdebug macosrelease iosdebug iosrelease iossimdebug iossimrelease
|
||||||
else ifeq ($(UNAME_S),Linux)
|
else ifeq ($(UNAME_S),Linux)
|
||||||
@ -207,18 +221,6 @@ $(IOS_TARGETS): LDFLAGS += -Ldeps/openssl/ios/ios64-xcrun/usr/local/lib
|
|||||||
$(IOSSIM_TARGETS): CFLAGS += -Ideps/openssl/ios/iossimulator-xcrun/usr/local/include
|
$(IOSSIM_TARGETS): CFLAGS += -Ideps/openssl/ios/iossimulator-xcrun/usr/local/include
|
||||||
$(IOSSIM_TARGETS): LDFLAGS += -Ldeps/openssl/ios/iossimulator-xcrun/usr/local/lib
|
$(IOSSIM_TARGETS): LDFLAGS += -Ldeps/openssl/ios/iossimulator-xcrun/usr/local/lib
|
||||||
|
|
||||||
ifeq ($(UNAME_M),x86_64)
|
|
||||||
ifneq ($(UNAME_S),Haiku)
|
|
||||||
debug: CFLAGS += -fsanitize=address -fsanitize=undefined -fno-common
|
|
||||||
debug: LDFLAGS += -fsanitize=address -fsanitize=undefined
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(UNAME_M),aarch64)
|
|
||||||
debug: CFLAGS += -fsanitize=address -fsanitize=undefined -fno-common
|
|
||||||
debug: LDFLAGS += -fsanitize=address -fsanitize=undefined
|
|
||||||
endif
|
|
||||||
|
|
||||||
get_objs = \
|
get_objs = \
|
||||||
$(foreach build_type,$(BUILD_TYPES),$(addprefix $(BUILD_DIR)/$(build_type)/,$(addsuffix .o,$(basename $(value $(1)))))) \
|
$(foreach build_type,$(BUILD_TYPES),$(addprefix $(BUILD_DIR)/$(build_type)/,$(addsuffix .o,$(basename $(value $(1)))))) \
|
||||||
$(foreach build_type,debug release,$(addprefix $(BUILD_DIR)/$(build_type)/,$(addsuffix .o,$(basename $(value $(1)_unix))))) \
|
$(foreach build_type,debug release,$(addprefix $(BUILD_DIR)/$(build_type)/,$(addsuffix .o,$(basename $(value $(1)_unix))))) \
|
||||||
@ -810,8 +812,9 @@ fetchdeps:
|
|||||||
@test -f out/deps/libuv.tar.gz || (mkdir -p out/deps/ && curl -q https://dist.libuv.org/dist/v1.48.0/libuv-v1.48.0.tar.gz -o out/deps/libuv.tar.gz)
|
@test -f out/deps/libuv.tar.gz || (mkdir -p out/deps/ && curl -q https://dist.libuv.org/dist/v1.48.0/libuv-v1.48.0.tar.gz -o out/deps/libuv.tar.gz)
|
||||||
@test -d deps/libuv/ || (mkdir -p deps/libuv/ && tar -C deps/libuv/ -m --strip=1 -xf out/deps/libuv.tar.gz)
|
@test -d deps/libuv/ || (mkdir -p deps/libuv/ && tar -C deps/libuv/ -m --strip=1 -xf out/deps/libuv.tar.gz)
|
||||||
@echo "[fetch] sqlite"
|
@echo "[fetch] sqlite"
|
||||||
@test -f out/deps/sqlite.zip || (mkdir -p out/deps/ && curl -q https://www.sqlite.org/2024/sqlite-amalgamation-3450100.zip -o out/deps/sqlite.zip)
|
@test -f out/deps/sqlite.zip && test $$(cat out/deps/sqlite.txt) = $(SQLITE_URL) || (mkdir -p out/deps/ && curl -q $(SQLITE_URL) -o out/deps/sqlite.zip) &&
|
||||||
@test -d deps/sqlite/ || (mkdir -p deps/sqlite/ && unzip -qDj -d deps/sqlite/ out/deps/sqlite.zip)
|
@test -d deps/sqlite/ && test $$(cat out/deps/sqlite.txt) = $(SQLITE_URL) || (mkdir -p deps/sqlite/ && unzip -qDjo -d deps/sqlite/ out/deps/sqlite.zip)
|
||||||
|
@echo -n $(SQLITE_URL) > out/deps/sqlite.txt
|
||||||
@echo "[fetch] prettier"
|
@echo "[fetch] prettier"
|
||||||
@test -f deps/prettier/standalone.mjs || curl -q --create-dirs -O --output-dir deps/prettier/ https://cdn.jsdelivr.net/npm/prettier@3.2.5/standalone.mjs
|
@test -f deps/prettier/standalone.mjs || curl -q --create-dirs -O --output-dir deps/prettier/ https://cdn.jsdelivr.net/npm/prettier@3.2.5/standalone.mjs
|
||||||
@test -f deps/prettier/html.mjs || curl -q --create-dirs -O --output-dir deps/prettier/ https://cdn.jsdelivr.net/npm/prettier@3.2.5/plugins/html.mjs
|
@test -f deps/prettier/html.mjs || curl -q --create-dirs -O --output-dir deps/prettier/ https://cdn.jsdelivr.net/npm/prettier@3.2.5/plugins/html.mjs
|
||||||
|
93
deps/sqlite/shell.c
vendored
93
deps/sqlite/shell.c
vendored
@ -580,6 +580,9 @@ zSkipValidUtf8(const char *z, int nAccept, long ccm);
|
|||||||
#ifndef HAVE_CONSOLE_IO_H
|
#ifndef HAVE_CONSOLE_IO_H
|
||||||
# include "console_io.h"
|
# include "console_io.h"
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
# pragma warning(disable : 4204)
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef SQLITE_CIO_NO_TRANSLATE
|
#ifndef SQLITE_CIO_NO_TRANSLATE
|
||||||
# if (defined(_WIN32) || defined(WIN32)) && !SQLITE_OS_WINRT
|
# if (defined(_WIN32) || defined(WIN32)) && !SQLITE_OS_WINRT
|
||||||
@ -678,6 +681,10 @@ static short streamOfConsole(FILE *pf, /* out */ PerStreamTags *ppst){
|
|||||||
# endif
|
# endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
|
||||||
|
# define ENABLE_VIRTUAL_TERMINAL_PROCESSING (0x4)
|
||||||
|
# endif
|
||||||
|
|
||||||
# if CIO_WIN_WC_XLATE
|
# if CIO_WIN_WC_XLATE
|
||||||
/* Define console modes for use with the Windows Console API. */
|
/* Define console modes for use with the Windows Console API. */
|
||||||
# define SHELL_CONI_MODE \
|
# define SHELL_CONI_MODE \
|
||||||
@ -1228,6 +1235,10 @@ SQLITE_INTERNAL_LINKAGE char* fGetsUtf8(char *cBuf, int ncMax, FILE *pfIn){
|
|||||||
}
|
}
|
||||||
#endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */
|
#endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
# pragma warning(default : 4204)
|
||||||
|
#endif
|
||||||
|
|
||||||
#undef SHELL_INVALID_FILE_PTR
|
#undef SHELL_INVALID_FILE_PTR
|
||||||
|
|
||||||
/************************* End ../ext/consio/console_io.c ********************/
|
/************************* End ../ext/consio/console_io.c ********************/
|
||||||
@ -20619,6 +20630,7 @@ static void exec_prepared_stmt_columnar(
|
|||||||
rc = sqlite3_step(pStmt);
|
rc = sqlite3_step(pStmt);
|
||||||
if( rc!=SQLITE_ROW ) return;
|
if( rc!=SQLITE_ROW ) return;
|
||||||
nColumn = sqlite3_column_count(pStmt);
|
nColumn = sqlite3_column_count(pStmt);
|
||||||
|
if( nColumn==0 ) goto columnar_end;
|
||||||
nAlloc = nColumn*4;
|
nAlloc = nColumn*4;
|
||||||
if( nAlloc<=0 ) nAlloc = 1;
|
if( nAlloc<=0 ) nAlloc = 1;
|
||||||
azData = sqlite3_malloc64( nAlloc*sizeof(char*) );
|
azData = sqlite3_malloc64( nAlloc*sizeof(char*) );
|
||||||
@ -20704,7 +20716,6 @@ static void exec_prepared_stmt_columnar(
|
|||||||
if( n>p->actualWidth[j] ) p->actualWidth[j] = n;
|
if( n>p->actualWidth[j] ) p->actualWidth[j] = n;
|
||||||
}
|
}
|
||||||
if( seenInterrupt ) goto columnar_end;
|
if( seenInterrupt ) goto columnar_end;
|
||||||
if( nColumn==0 ) goto columnar_end;
|
|
||||||
switch( p->cMode ){
|
switch( p->cMode ){
|
||||||
case MODE_Column: {
|
case MODE_Column: {
|
||||||
colSep = " ";
|
colSep = " ";
|
||||||
@ -25553,16 +25564,15 @@ static int do_meta_command(char *zLine, ShellState *p){
|
|||||||
#ifndef SQLITE_SHELL_FIDDLE
|
#ifndef SQLITE_SHELL_FIDDLE
|
||||||
if( c=='i' && cli_strncmp(azArg[0], "import", n)==0 ){
|
if( c=='i' && cli_strncmp(azArg[0], "import", n)==0 ){
|
||||||
char *zTable = 0; /* Insert data into this table */
|
char *zTable = 0; /* Insert data into this table */
|
||||||
char *zSchema = 0; /* within this schema (may default to "main") */
|
char *zSchema = 0; /* Schema of zTable */
|
||||||
char *zFile = 0; /* Name of file to extra content from */
|
char *zFile = 0; /* Name of file to extra content from */
|
||||||
sqlite3_stmt *pStmt = NULL; /* A statement */
|
sqlite3_stmt *pStmt = NULL; /* A statement */
|
||||||
int nCol; /* Number of columns in the table */
|
int nCol; /* Number of columns in the table */
|
||||||
int nByte; /* Number of bytes in an SQL string */
|
i64 nByte; /* Number of bytes in an SQL string */
|
||||||
int i, j; /* Loop counters */
|
int i, j; /* Loop counters */
|
||||||
int needCommit; /* True to COMMIT or ROLLBACK at end */
|
int needCommit; /* True to COMMIT or ROLLBACK at end */
|
||||||
int nSep; /* Number of bytes in p->colSeparator[] */
|
int nSep; /* Number of bytes in p->colSeparator[] */
|
||||||
char *zSql; /* An SQL statement */
|
char *zSql = 0; /* An SQL statement */
|
||||||
char *zFullTabName; /* Table name with schema if applicable */
|
|
||||||
ImportCtx sCtx; /* Reader context */
|
ImportCtx sCtx; /* Reader context */
|
||||||
char *(SQLITE_CDECL *xRead)(ImportCtx*); /* Func to read one value */
|
char *(SQLITE_CDECL *xRead)(ImportCtx*); /* Func to read one value */
|
||||||
int eVerbose = 0; /* Larger for more console output */
|
int eVerbose = 0; /* Larger for more console output */
|
||||||
@ -25696,24 +25706,14 @@ static int do_meta_command(char *zLine, ShellState *p){
|
|||||||
while( (nSkip--)>0 ){
|
while( (nSkip--)>0 ){
|
||||||
while( xRead(&sCtx) && sCtx.cTerm==sCtx.cColSep ){}
|
while( xRead(&sCtx) && sCtx.cTerm==sCtx.cColSep ){}
|
||||||
}
|
}
|
||||||
if( zSchema!=0 ){
|
|
||||||
zFullTabName = sqlite3_mprintf("\"%w\".\"%w\"", zSchema, zTable);
|
|
||||||
}else{
|
|
||||||
zFullTabName = sqlite3_mprintf("\"%w\"", zTable);
|
|
||||||
}
|
|
||||||
zSql = sqlite3_mprintf("SELECT * FROM %s", zFullTabName);
|
|
||||||
if( zSql==0 || zFullTabName==0 ){
|
|
||||||
import_cleanup(&sCtx);
|
|
||||||
shell_out_of_memory();
|
|
||||||
}
|
|
||||||
nByte = strlen30(zSql);
|
|
||||||
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
|
|
||||||
import_append_char(&sCtx, 0); /* To ensure sCtx.z is allocated */
|
import_append_char(&sCtx, 0); /* To ensure sCtx.z is allocated */
|
||||||
if( rc && sqlite3_strglob("no such table: *", sqlite3_errmsg(p->db))==0 ){
|
if( sqlite3_table_column_metadata(p->db, zSchema, zTable,0,0,0,0,0,0) ){
|
||||||
|
/* Table does not exist. Create it. */
|
||||||
sqlite3 *dbCols = 0;
|
sqlite3 *dbCols = 0;
|
||||||
char *zRenames = 0;
|
char *zRenames = 0;
|
||||||
char *zColDefs;
|
char *zColDefs;
|
||||||
zCreate = sqlite3_mprintf("CREATE TABLE %s", zFullTabName);
|
zCreate = sqlite3_mprintf("CREATE TABLE \"%w\".\"%w\"",
|
||||||
|
zSchema ? zSchema : "main", zTable);
|
||||||
while( xRead(&sCtx) ){
|
while( xRead(&sCtx) ){
|
||||||
zAutoColumn(sCtx.z, &dbCols, 0);
|
zAutoColumn(sCtx.z, &dbCols, 0);
|
||||||
if( sCtx.cTerm!=sCtx.cColSep ) break;
|
if( sCtx.cTerm!=sCtx.cColSep ) break;
|
||||||
@ -25728,34 +25728,50 @@ static int do_meta_command(char *zLine, ShellState *p){
|
|||||||
assert(dbCols==0);
|
assert(dbCols==0);
|
||||||
if( zColDefs==0 ){
|
if( zColDefs==0 ){
|
||||||
eputf("%s: empty file\n", sCtx.zFile);
|
eputf("%s: empty file\n", sCtx.zFile);
|
||||||
import_fail:
|
|
||||||
sqlite3_free(zCreate);
|
|
||||||
sqlite3_free(zSql);
|
|
||||||
sqlite3_free(zFullTabName);
|
|
||||||
import_cleanup(&sCtx);
|
import_cleanup(&sCtx);
|
||||||
rc = 1;
|
rc = 1;
|
||||||
goto meta_command_exit;
|
goto meta_command_exit;
|
||||||
}
|
}
|
||||||
zCreate = sqlite3_mprintf("%z%z\n", zCreate, zColDefs);
|
zCreate = sqlite3_mprintf("%z%z\n", zCreate, zColDefs);
|
||||||
|
if( zCreate==0 ){
|
||||||
|
import_cleanup(&sCtx);
|
||||||
|
shell_out_of_memory();
|
||||||
|
}
|
||||||
if( eVerbose>=1 ){
|
if( eVerbose>=1 ){
|
||||||
oputf("%s\n", zCreate);
|
oputf("%s\n", zCreate);
|
||||||
}
|
}
|
||||||
rc = sqlite3_exec(p->db, zCreate, 0, 0, 0);
|
rc = sqlite3_exec(p->db, zCreate, 0, 0, 0);
|
||||||
if( rc ){
|
|
||||||
eputf("%s failed:\n%s\n", zCreate, sqlite3_errmsg(p->db));
|
|
||||||
goto import_fail;
|
|
||||||
}
|
|
||||||
sqlite3_free(zCreate);
|
sqlite3_free(zCreate);
|
||||||
zCreate = 0;
|
zCreate = 0;
|
||||||
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
|
if( rc ){
|
||||||
|
eputf("%s failed:\n%s\n", zCreate, sqlite3_errmsg(p->db));
|
||||||
|
import_cleanup(&sCtx);
|
||||||
|
rc = 1;
|
||||||
|
goto meta_command_exit;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
zSql = sqlite3_mprintf("SELECT count(*) FROM pragma_table_info(%Q,%Q);",
|
||||||
|
zTable, zSchema);
|
||||||
|
if( zSql==0 ){
|
||||||
|
import_cleanup(&sCtx);
|
||||||
|
shell_out_of_memory();
|
||||||
|
}
|
||||||
|
nByte = strlen(zSql);
|
||||||
|
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
|
||||||
|
sqlite3_free(zSql);
|
||||||
|
zSql = 0;
|
||||||
if( rc ){
|
if( rc ){
|
||||||
if (pStmt) sqlite3_finalize(pStmt);
|
if (pStmt) sqlite3_finalize(pStmt);
|
||||||
eputf("Error: %s\n", sqlite3_errmsg(p->db));
|
eputf("Error: %s\n", sqlite3_errmsg(p->db));
|
||||||
goto import_fail;
|
import_cleanup(&sCtx);
|
||||||
|
rc = 1;
|
||||||
|
goto meta_command_exit;
|
||||||
|
}
|
||||||
|
if( sqlite3_step(pStmt)==SQLITE_ROW ){
|
||||||
|
nCol = sqlite3_column_int(pStmt, 0);
|
||||||
|
}else{
|
||||||
|
nCol = 0;
|
||||||
}
|
}
|
||||||
sqlite3_free(zSql);
|
|
||||||
nCol = sqlite3_column_count(pStmt);
|
|
||||||
sqlite3_finalize(pStmt);
|
sqlite3_finalize(pStmt);
|
||||||
pStmt = 0;
|
pStmt = 0;
|
||||||
if( nCol==0 ) return 0; /* no columns, no error */
|
if( nCol==0 ) return 0; /* no columns, no error */
|
||||||
@ -25764,7 +25780,12 @@ static int do_meta_command(char *zLine, ShellState *p){
|
|||||||
import_cleanup(&sCtx);
|
import_cleanup(&sCtx);
|
||||||
shell_out_of_memory();
|
shell_out_of_memory();
|
||||||
}
|
}
|
||||||
sqlite3_snprintf(nByte+20, zSql, "INSERT INTO %s VALUES(?", zFullTabName);
|
if( zSchema ){
|
||||||
|
sqlite3_snprintf(nByte+20, zSql, "INSERT INTO \"%w\".\"%w\" VALUES(?",
|
||||||
|
zSchema, zTable);
|
||||||
|
}else{
|
||||||
|
sqlite3_snprintf(nByte+20, zSql, "INSERT INTO \"%w\" VALUES(?", zTable);
|
||||||
|
}
|
||||||
j = strlen30(zSql);
|
j = strlen30(zSql);
|
||||||
for(i=1; i<nCol; i++){
|
for(i=1; i<nCol; i++){
|
||||||
zSql[j++] = ',';
|
zSql[j++] = ',';
|
||||||
@ -25776,13 +25797,15 @@ static int do_meta_command(char *zLine, ShellState *p){
|
|||||||
oputf("Insert using: %s\n", zSql);
|
oputf("Insert using: %s\n", zSql);
|
||||||
}
|
}
|
||||||
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
|
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
|
||||||
|
sqlite3_free(zSql);
|
||||||
|
zSql = 0;
|
||||||
if( rc ){
|
if( rc ){
|
||||||
eputf("Error: %s\n", sqlite3_errmsg(p->db));
|
eputf("Error: %s\n", sqlite3_errmsg(p->db));
|
||||||
if (pStmt) sqlite3_finalize(pStmt);
|
if (pStmt) sqlite3_finalize(pStmt);
|
||||||
goto import_fail;
|
import_cleanup(&sCtx);
|
||||||
|
rc = 1;
|
||||||
|
goto meta_command_exit;
|
||||||
}
|
}
|
||||||
sqlite3_free(zSql);
|
|
||||||
sqlite3_free(zFullTabName);
|
|
||||||
needCommit = sqlite3_get_autocommit(p->db);
|
needCommit = sqlite3_get_autocommit(p->db);
|
||||||
if( needCommit ) sqlite3_exec(p->db, "BEGIN", 0, 0, 0);
|
if( needCommit ) sqlite3_exec(p->db, "BEGIN", 0, 0, 0);
|
||||||
do{
|
do{
|
||||||
|
295
deps/sqlite/sqlite3.c
vendored
295
deps/sqlite/sqlite3.c
vendored
@ -1,6 +1,6 @@
|
|||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
** This file is an amalgamation of many separate C source files from SQLite
|
** This file is an amalgamation of many separate C source files from SQLite
|
||||||
** version 3.45.1. By combining all the individual C code files into this
|
** version 3.45.2. By combining all the individual C code files into this
|
||||||
** single large file, the entire code can be compiled as a single translation
|
** single large file, the entire code can be compiled as a single translation
|
||||||
** unit. This allows many compilers to do optimizations that would not be
|
** unit. This allows many compilers to do optimizations that would not be
|
||||||
** possible if the files were compiled separately. Performance improvements
|
** possible if the files were compiled separately. Performance improvements
|
||||||
@ -18,7 +18,7 @@
|
|||||||
** separate file. This file contains only code for the core SQLite library.
|
** separate file. This file contains only code for the core SQLite library.
|
||||||
**
|
**
|
||||||
** The content in this amalgamation comes from Fossil check-in
|
** The content in this amalgamation comes from Fossil check-in
|
||||||
** e876e51a0ed5c5b3126f52e532044363a014.
|
** d8cd6d49b46a395b13955387d05e9e1a2a47.
|
||||||
*/
|
*/
|
||||||
#define SQLITE_CORE 1
|
#define SQLITE_CORE 1
|
||||||
#define SQLITE_AMALGAMATION 1
|
#define SQLITE_AMALGAMATION 1
|
||||||
@ -459,9 +459,9 @@ extern "C" {
|
|||||||
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
|
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
|
||||||
** [sqlite_version()] and [sqlite_source_id()].
|
** [sqlite_version()] and [sqlite_source_id()].
|
||||||
*/
|
*/
|
||||||
#define SQLITE_VERSION "3.45.1"
|
#define SQLITE_VERSION "3.45.2"
|
||||||
#define SQLITE_VERSION_NUMBER 3045001
|
#define SQLITE_VERSION_NUMBER 3045002
|
||||||
#define SQLITE_SOURCE_ID "2024-01-30 16:01:20 e876e51a0ed5c5b3126f52e532044363a014bc594cfefa87ffb5b82257cc467a"
|
#define SQLITE_SOURCE_ID "2024-03-12 11:06:23 d8cd6d49b46a395b13955387d05e9e1a2a47e54fb99f3c9b59835bbefad6af77"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** CAPI3REF: Run-Time Library Version Numbers
|
** CAPI3REF: Run-Time Library Version Numbers
|
||||||
@ -733,6 +733,8 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
|
|||||||
** the 1st parameter to sqlite3_exec() while sqlite3_exec() is running.
|
** the 1st parameter to sqlite3_exec() while sqlite3_exec() is running.
|
||||||
** <li> The application must not modify the SQL statement text passed into
|
** <li> The application must not modify the SQL statement text passed into
|
||||||
** the 2nd parameter of sqlite3_exec() while sqlite3_exec() is running.
|
** the 2nd parameter of sqlite3_exec() while sqlite3_exec() is running.
|
||||||
|
** <li> The application must not dereference the arrays or string pointers
|
||||||
|
** passed as the 3rd and 4th callback parameters after it returns.
|
||||||
** </ul>
|
** </ul>
|
||||||
*/
|
*/
|
||||||
SQLITE_API int sqlite3_exec(
|
SQLITE_API int sqlite3_exec(
|
||||||
@ -15097,6 +15099,7 @@ SQLITE_PRIVATE u32 sqlite3TreeTrace;
|
|||||||
** 0x00010000 Beginning of DELETE/INSERT/UPDATE processing
|
** 0x00010000 Beginning of DELETE/INSERT/UPDATE processing
|
||||||
** 0x00020000 Transform DISTINCT into GROUP BY
|
** 0x00020000 Transform DISTINCT into GROUP BY
|
||||||
** 0x00040000 SELECT tree dump after all code has been generated
|
** 0x00040000 SELECT tree dump after all code has been generated
|
||||||
|
** 0x00080000 NOT NULL strength reduction
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -19346,6 +19349,7 @@ struct NameContext {
|
|||||||
#define NC_InAggFunc 0x020000 /* True if analyzing arguments to an agg func */
|
#define NC_InAggFunc 0x020000 /* True if analyzing arguments to an agg func */
|
||||||
#define NC_FromDDL 0x040000 /* SQL text comes from sqlite_schema */
|
#define NC_FromDDL 0x040000 /* SQL text comes from sqlite_schema */
|
||||||
#define NC_NoSelect 0x080000 /* Do not descend into sub-selects */
|
#define NC_NoSelect 0x080000 /* Do not descend into sub-selects */
|
||||||
|
#define NC_Where 0x100000 /* Processing WHERE clause of a SELECT */
|
||||||
#define NC_OrderAgg 0x8000000 /* Has an aggregate other than count/min/max */
|
#define NC_OrderAgg 0x8000000 /* Has an aggregate other than count/min/max */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -19369,6 +19373,7 @@ struct Upsert {
|
|||||||
Expr *pUpsertWhere; /* WHERE clause for the ON CONFLICT UPDATE */
|
Expr *pUpsertWhere; /* WHERE clause for the ON CONFLICT UPDATE */
|
||||||
Upsert *pNextUpsert; /* Next ON CONFLICT clause in the list */
|
Upsert *pNextUpsert; /* Next ON CONFLICT clause in the list */
|
||||||
u8 isDoUpdate; /* True for DO UPDATE. False for DO NOTHING */
|
u8 isDoUpdate; /* True for DO UPDATE. False for DO NOTHING */
|
||||||
|
u8 isDup; /* True if 2nd or later with same pUpsertIdx */
|
||||||
/* Above this point is the parse tree for the ON CONFLICT clauses.
|
/* Above this point is the parse tree for the ON CONFLICT clauses.
|
||||||
** The next group of fields stores intermediate data. */
|
** The next group of fields stores intermediate data. */
|
||||||
void *pToFree; /* Free memory when deleting the Upsert object */
|
void *pToFree; /* Free memory when deleting the Upsert object */
|
||||||
@ -21444,7 +21449,7 @@ SQLITE_PRIVATE With *sqlite3WithPush(Parse*, With*, u8);
|
|||||||
SQLITE_PRIVATE Upsert *sqlite3UpsertNew(sqlite3*,ExprList*,Expr*,ExprList*,Expr*,Upsert*);
|
SQLITE_PRIVATE Upsert *sqlite3UpsertNew(sqlite3*,ExprList*,Expr*,ExprList*,Expr*,Upsert*);
|
||||||
SQLITE_PRIVATE void sqlite3UpsertDelete(sqlite3*,Upsert*);
|
SQLITE_PRIVATE void sqlite3UpsertDelete(sqlite3*,Upsert*);
|
||||||
SQLITE_PRIVATE Upsert *sqlite3UpsertDup(sqlite3*,Upsert*);
|
SQLITE_PRIVATE Upsert *sqlite3UpsertDup(sqlite3*,Upsert*);
|
||||||
SQLITE_PRIVATE int sqlite3UpsertAnalyzeTarget(Parse*,SrcList*,Upsert*);
|
SQLITE_PRIVATE int sqlite3UpsertAnalyzeTarget(Parse*,SrcList*,Upsert*,Upsert*);
|
||||||
SQLITE_PRIVATE void sqlite3UpsertDoUpdate(Parse*,Upsert*,Table*,Index*,int);
|
SQLITE_PRIVATE void sqlite3UpsertDoUpdate(Parse*,Upsert*,Table*,Index*,int);
|
||||||
SQLITE_PRIVATE Upsert *sqlite3UpsertOfIndex(Upsert*,Index*);
|
SQLITE_PRIVATE Upsert *sqlite3UpsertOfIndex(Upsert*,Index*);
|
||||||
SQLITE_PRIVATE int sqlite3UpsertNextIsIPK(Upsert*);
|
SQLITE_PRIVATE int sqlite3UpsertNextIsIPK(Upsert*);
|
||||||
@ -31309,6 +31314,7 @@ SQLITE_API void sqlite3_str_vappendf(
|
|||||||
if( xtype==etFLOAT ){
|
if( xtype==etFLOAT ){
|
||||||
iRound = -precision;
|
iRound = -precision;
|
||||||
}else if( xtype==etGENERIC ){
|
}else if( xtype==etGENERIC ){
|
||||||
|
if( precision==0 ) precision = 1;
|
||||||
iRound = precision;
|
iRound = precision;
|
||||||
}else{
|
}else{
|
||||||
iRound = precision+1;
|
iRound = precision+1;
|
||||||
@ -35199,6 +35205,9 @@ do_atof_calc:
|
|||||||
u64 s2;
|
u64 s2;
|
||||||
rr[0] = (double)s;
|
rr[0] = (double)s;
|
||||||
s2 = (u64)rr[0];
|
s2 = (u64)rr[0];
|
||||||
|
#if defined(_MSC_VER) && _MSC_VER<1700
|
||||||
|
if( s2==0x8000000000000000LL ){ s2 = 2*(u64)(0.5*rr[0]); }
|
||||||
|
#endif
|
||||||
rr[1] = s>=s2 ? (double)(s - s2) : -(double)(s2 - s);
|
rr[1] = s>=s2 ? (double)(s - s2) : -(double)(s2 - s);
|
||||||
if( e>0 ){
|
if( e>0 ){
|
||||||
while( e>=100 ){
|
while( e>=100 ){
|
||||||
@ -35641,7 +35650,7 @@ SQLITE_PRIVATE void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRou
|
|||||||
assert( p->n>0 );
|
assert( p->n>0 );
|
||||||
assert( p->n<sizeof(p->zBuf) );
|
assert( p->n<sizeof(p->zBuf) );
|
||||||
p->iDP = p->n + exp;
|
p->iDP = p->n + exp;
|
||||||
if( iRound<0 ){
|
if( iRound<=0 ){
|
||||||
iRound = p->iDP - iRound;
|
iRound = p->iDP - iRound;
|
||||||
if( iRound==0 && p->zBuf[i+1]>='5' ){
|
if( iRound==0 && p->zBuf[i+1]>='5' ){
|
||||||
iRound = 1;
|
iRound = 1;
|
||||||
@ -53262,6 +53271,14 @@ SQLITE_API unsigned char *sqlite3_serialize(
|
|||||||
pOut = 0;
|
pOut = 0;
|
||||||
}else{
|
}else{
|
||||||
sz = sqlite3_column_int64(pStmt, 0)*szPage;
|
sz = sqlite3_column_int64(pStmt, 0)*szPage;
|
||||||
|
if( sz==0 ){
|
||||||
|
sqlite3_reset(pStmt);
|
||||||
|
sqlite3_exec(db, "BEGIN IMMEDIATE; COMMIT;", 0, 0, 0);
|
||||||
|
rc = sqlite3_step(pStmt);
|
||||||
|
if( rc==SQLITE_ROW ){
|
||||||
|
sz = sqlite3_column_int64(pStmt, 0)*szPage;
|
||||||
|
}
|
||||||
|
}
|
||||||
if( piSize ) *piSize = sz;
|
if( piSize ) *piSize = sz;
|
||||||
if( mFlags & SQLITE_SERIALIZE_NOCOPY ){
|
if( mFlags & SQLITE_SERIALIZE_NOCOPY ){
|
||||||
pOut = 0;
|
pOut = 0;
|
||||||
@ -77088,7 +77105,10 @@ static int fillInCell(
|
|||||||
n = nHeader + nPayload;
|
n = nHeader + nPayload;
|
||||||
testcase( n==3 );
|
testcase( n==3 );
|
||||||
testcase( n==4 );
|
testcase( n==4 );
|
||||||
if( n<4 ) n = 4;
|
if( n<4 ){
|
||||||
|
n = 4;
|
||||||
|
pPayload[nPayload] = 0;
|
||||||
|
}
|
||||||
*pnSize = n;
|
*pnSize = n;
|
||||||
assert( nSrc<=nPayload );
|
assert( nSrc<=nPayload );
|
||||||
testcase( nSrc<nPayload );
|
testcase( nSrc<nPayload );
|
||||||
@ -79534,7 +79554,10 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
|
|||||||
if( flags & BTREE_PREFORMAT ){
|
if( flags & BTREE_PREFORMAT ){
|
||||||
rc = SQLITE_OK;
|
rc = SQLITE_OK;
|
||||||
szNew = p->pBt->nPreformatSize;
|
szNew = p->pBt->nPreformatSize;
|
||||||
if( szNew<4 ) szNew = 4;
|
if( szNew<4 ){
|
||||||
|
szNew = 4;
|
||||||
|
newCell[3] = 0;
|
||||||
|
}
|
||||||
if( ISAUTOVACUUM(p->pBt) && szNew>pPage->maxLocal ){
|
if( ISAUTOVACUUM(p->pBt) && szNew>pPage->maxLocal ){
|
||||||
CellInfo info;
|
CellInfo info;
|
||||||
pPage->xParseCell(pPage, newCell, &info);
|
pPage->xParseCell(pPage, newCell, &info);
|
||||||
@ -88379,6 +88402,23 @@ static void serialGet(
|
|||||||
pMem->flags = IsNaN(x) ? MEM_Null : MEM_Real;
|
pMem->flags = IsNaN(x) ? MEM_Null : MEM_Real;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
static int serialGet7(
|
||||||
|
const unsigned char *buf, /* Buffer to deserialize from */
|
||||||
|
Mem *pMem /* Memory cell to write value into */
|
||||||
|
){
|
||||||
|
u64 x = FOUR_BYTE_UINT(buf);
|
||||||
|
u32 y = FOUR_BYTE_UINT(buf+4);
|
||||||
|
x = (x<<32) + y;
|
||||||
|
assert( sizeof(x)==8 && sizeof(pMem->u.r)==8 );
|
||||||
|
swapMixedEndianFloat(x);
|
||||||
|
memcpy(&pMem->u.r, &x, sizeof(x));
|
||||||
|
if( IsNaN(x) ){
|
||||||
|
pMem->flags = MEM_Null;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
pMem->flags = MEM_Real;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
SQLITE_PRIVATE void sqlite3VdbeSerialGet(
|
SQLITE_PRIVATE void sqlite3VdbeSerialGet(
|
||||||
const unsigned char *buf, /* Buffer to deserialize from */
|
const unsigned char *buf, /* Buffer to deserialize from */
|
||||||
u32 serial_type, /* Serial type to deserialize */
|
u32 serial_type, /* Serial type to deserialize */
|
||||||
@ -89058,7 +89098,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
|
|||||||
}else if( serial_type==0 ){
|
}else if( serial_type==0 ){
|
||||||
rc = -1;
|
rc = -1;
|
||||||
}else if( serial_type==7 ){
|
}else if( serial_type==7 ){
|
||||||
sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1);
|
serialGet7(&aKey1[d1], &mem1);
|
||||||
rc = -sqlite3IntFloatCompare(pRhs->u.i, mem1.u.r);
|
rc = -sqlite3IntFloatCompare(pRhs->u.i, mem1.u.r);
|
||||||
}else{
|
}else{
|
||||||
i64 lhs = vdbeRecordDecodeInt(serial_type, &aKey1[d1]);
|
i64 lhs = vdbeRecordDecodeInt(serial_type, &aKey1[d1]);
|
||||||
@ -89083,14 +89123,18 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
|
|||||||
}else if( serial_type==0 ){
|
}else if( serial_type==0 ){
|
||||||
rc = -1;
|
rc = -1;
|
||||||
}else{
|
}else{
|
||||||
sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1);
|
|
||||||
if( serial_type==7 ){
|
if( serial_type==7 ){
|
||||||
if( mem1.u.r<pRhs->u.r ){
|
if( serialGet7(&aKey1[d1], &mem1) ){
|
||||||
|
rc = -1; /* mem1 is a NaN */
|
||||||
|
}else if( mem1.u.r<pRhs->u.r ){
|
||||||
rc = -1;
|
rc = -1;
|
||||||
}else if( mem1.u.r>pRhs->u.r ){
|
}else if( mem1.u.r>pRhs->u.r ){
|
||||||
rc = +1;
|
rc = +1;
|
||||||
|
}else{
|
||||||
|
assert( rc==0 );
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
|
sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1);
|
||||||
rc = sqlite3IntFloatCompare(mem1.u.i, pRhs->u.r);
|
rc = sqlite3IntFloatCompare(mem1.u.i, pRhs->u.r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -89160,7 +89204,14 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
|
|||||||
/* RHS is null */
|
/* RHS is null */
|
||||||
else{
|
else{
|
||||||
serial_type = aKey1[idx1];
|
serial_type = aKey1[idx1];
|
||||||
rc = (serial_type!=0 && serial_type!=10);
|
if( serial_type==0
|
||||||
|
|| serial_type==10
|
||||||
|
|| (serial_type==7 && serialGet7(&aKey1[d1], &mem1)!=0)
|
||||||
|
){
|
||||||
|
assert( rc==0 );
|
||||||
|
}else{
|
||||||
|
rc = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( rc!=0 ){
|
if( rc!=0 ){
|
||||||
@ -94858,7 +94909,9 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}else if( affinity==SQLITE_AFF_TEXT && ((flags1 | flags3) & MEM_Str)!=0 ){
|
}else if( affinity==SQLITE_AFF_TEXT && ((flags1 | flags3) & MEM_Str)!=0 ){
|
||||||
if( (flags1 & MEM_Str)==0 && (flags1&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){
|
if( (flags1 & MEM_Str)!=0 ){
|
||||||
|
pIn1->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal);
|
||||||
|
}else if( (flags1&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){
|
||||||
testcase( pIn1->flags & MEM_Int );
|
testcase( pIn1->flags & MEM_Int );
|
||||||
testcase( pIn1->flags & MEM_Real );
|
testcase( pIn1->flags & MEM_Real );
|
||||||
testcase( pIn1->flags & MEM_IntReal );
|
testcase( pIn1->flags & MEM_IntReal );
|
||||||
@ -94867,7 +94920,9 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
|
|||||||
flags1 = (pIn1->flags & ~MEM_TypeMask) | (flags1 & MEM_TypeMask);
|
flags1 = (pIn1->flags & ~MEM_TypeMask) | (flags1 & MEM_TypeMask);
|
||||||
if( NEVER(pIn1==pIn3) ) flags3 = flags1 | MEM_Str;
|
if( NEVER(pIn1==pIn3) ) flags3 = flags1 | MEM_Str;
|
||||||
}
|
}
|
||||||
if( (flags3 & MEM_Str)==0 && (flags3&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){
|
if( (flags3 & MEM_Str)!=0 ){
|
||||||
|
pIn3->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal);
|
||||||
|
}else if( (flags3&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){
|
||||||
testcase( pIn3->flags & MEM_Int );
|
testcase( pIn3->flags & MEM_Int );
|
||||||
testcase( pIn3->flags & MEM_Real );
|
testcase( pIn3->flags & MEM_Real );
|
||||||
testcase( pIn3->flags & MEM_IntReal );
|
testcase( pIn3->flags & MEM_IntReal );
|
||||||
@ -106212,6 +106267,8 @@ static void resolveAlias(
|
|||||||
assert( iCol>=0 && iCol<pEList->nExpr );
|
assert( iCol>=0 && iCol<pEList->nExpr );
|
||||||
pOrig = pEList->a[iCol].pExpr;
|
pOrig = pEList->a[iCol].pExpr;
|
||||||
assert( pOrig!=0 );
|
assert( pOrig!=0 );
|
||||||
|
assert( !ExprHasProperty(pExpr, EP_Reduced|EP_TokenOnly) );
|
||||||
|
if( pExpr->pAggInfo ) return;
|
||||||
db = pParse->db;
|
db = pParse->db;
|
||||||
pDup = sqlite3ExprDup(db, pOrig, 0);
|
pDup = sqlite3ExprDup(db, pOrig, 0);
|
||||||
if( db->mallocFailed ){
|
if( db->mallocFailed ){
|
||||||
@ -107097,6 +107154,19 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
|||||||
** resolved. This prevents "column" from being counted as having been
|
** resolved. This prevents "column" from being counted as having been
|
||||||
** referenced, which might prevent a SELECT from being erroneously
|
** referenced, which might prevent a SELECT from being erroneously
|
||||||
** marked as correlated.
|
** marked as correlated.
|
||||||
|
**
|
||||||
|
** 2024-03-28: Beware of aggregates. A bare column of aggregated table
|
||||||
|
** can still evaluate to NULL even though it is marked as NOT NULL.
|
||||||
|
** Example:
|
||||||
|
**
|
||||||
|
** CREATE TABLE t1(a INT NOT NULL);
|
||||||
|
** SELECT a, a IS NULL, a IS NOT NULL, count(*) FROM t1;
|
||||||
|
**
|
||||||
|
** The "a IS NULL" and "a IS NOT NULL" expressions cannot be optimized
|
||||||
|
** here because at the time this case is hit, we do not yet know whether
|
||||||
|
** or not t1 is being aggregated. We have to assume the worst and omit
|
||||||
|
** the optimization. The only time it is safe to apply this optimization
|
||||||
|
** is within the WHERE clause.
|
||||||
*/
|
*/
|
||||||
case TK_NOTNULL:
|
case TK_NOTNULL:
|
||||||
case TK_ISNULL: {
|
case TK_ISNULL: {
|
||||||
@ -107107,19 +107177,36 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
|||||||
anRef[i] = p->nRef;
|
anRef[i] = p->nRef;
|
||||||
}
|
}
|
||||||
sqlite3WalkExpr(pWalker, pExpr->pLeft);
|
sqlite3WalkExpr(pWalker, pExpr->pLeft);
|
||||||
if( 0==sqlite3ExprCanBeNull(pExpr->pLeft) && !IN_RENAME_OBJECT ){
|
if( IN_RENAME_OBJECT ) return WRC_Prune;
|
||||||
testcase( ExprHasProperty(pExpr, EP_OuterON) );
|
if( sqlite3ExprCanBeNull(pExpr->pLeft) ){
|
||||||
assert( !ExprHasProperty(pExpr, EP_IntValue) );
|
/* The expression can be NULL. So the optimization does not apply */
|
||||||
pExpr->u.iValue = (pExpr->op==TK_NOTNULL);
|
return WRC_Prune;
|
||||||
pExpr->flags |= EP_IntValue;
|
|
||||||
pExpr->op = TK_INTEGER;
|
|
||||||
|
|
||||||
for(i=0, p=pNC; p && i<ArraySize(anRef); p=p->pNext, i++){
|
|
||||||
p->nRef = anRef[i];
|
|
||||||
}
|
|
||||||
sqlite3ExprDelete(pParse->db, pExpr->pLeft);
|
|
||||||
pExpr->pLeft = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for(i=0, p=pNC; p; p=p->pNext, i++){
|
||||||
|
if( (p->ncFlags & NC_Where)==0 ){
|
||||||
|
return WRC_Prune; /* Not in a WHERE clause. Unsafe to optimize. */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
testcase( ExprHasProperty(pExpr, EP_OuterON) );
|
||||||
|
assert( !ExprHasProperty(pExpr, EP_IntValue) );
|
||||||
|
#if TREETRACE_ENABLED
|
||||||
|
if( sqlite3TreeTrace & 0x80000 ){
|
||||||
|
sqlite3DebugPrintf(
|
||||||
|
"NOT NULL strength reduction converts the following to %d:\n",
|
||||||
|
pExpr->op==TK_NOTNULL
|
||||||
|
);
|
||||||
|
sqlite3ShowExpr(pExpr);
|
||||||
|
}
|
||||||
|
#endif /* TREETRACE_ENABLED */
|
||||||
|
pExpr->u.iValue = (pExpr->op==TK_NOTNULL);
|
||||||
|
pExpr->flags |= EP_IntValue;
|
||||||
|
pExpr->op = TK_INTEGER;
|
||||||
|
for(i=0, p=pNC; p && i<ArraySize(anRef); p=p->pNext, i++){
|
||||||
|
p->nRef = anRef[i];
|
||||||
|
}
|
||||||
|
sqlite3ExprDelete(pParse->db, pExpr->pLeft);
|
||||||
|
pExpr->pLeft = 0;
|
||||||
return WRC_Prune;
|
return WRC_Prune;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108019,7 +108106,9 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
|
|||||||
}
|
}
|
||||||
if( sqlite3ResolveExprNames(&sNC, p->pHaving) ) return WRC_Abort;
|
if( sqlite3ResolveExprNames(&sNC, p->pHaving) ) return WRC_Abort;
|
||||||
}
|
}
|
||||||
|
sNC.ncFlags |= NC_Where;
|
||||||
if( sqlite3ResolveExprNames(&sNC, p->pWhere) ) return WRC_Abort;
|
if( sqlite3ResolveExprNames(&sNC, p->pWhere) ) return WRC_Abort;
|
||||||
|
sNC.ncFlags &= ~NC_Where;
|
||||||
|
|
||||||
/* Resolve names in table-valued-function arguments */
|
/* Resolve names in table-valued-function arguments */
|
||||||
for(i=0; i<p->pSrc->nSrc; i++){
|
for(i=0; i<p->pSrc->nSrc; i++){
|
||||||
@ -128947,13 +129036,13 @@ SQLITE_PRIVATE void sqlite3QuoteValue(StrAccum *pStr, sqlite3_value *pValue){
|
|||||||
double r1, r2;
|
double r1, r2;
|
||||||
const char *zVal;
|
const char *zVal;
|
||||||
r1 = sqlite3_value_double(pValue);
|
r1 = sqlite3_value_double(pValue);
|
||||||
sqlite3_str_appendf(pStr, "%!.15g", r1);
|
sqlite3_str_appendf(pStr, "%!0.15g", r1);
|
||||||
zVal = sqlite3_str_value(pStr);
|
zVal = sqlite3_str_value(pStr);
|
||||||
if( zVal ){
|
if( zVal ){
|
||||||
sqlite3AtoF(zVal, &r2, pStr->nChar, SQLITE_UTF8);
|
sqlite3AtoF(zVal, &r2, pStr->nChar, SQLITE_UTF8);
|
||||||
if( r1!=r2 ){
|
if( r1!=r2 ){
|
||||||
sqlite3_str_reset(pStr);
|
sqlite3_str_reset(pStr);
|
||||||
sqlite3_str_appendf(pStr, "%!.20e", r1);
|
sqlite3_str_appendf(pStr, "%!0.20e", r1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -129255,7 +129344,7 @@ static void replaceFunc(
|
|||||||
}
|
}
|
||||||
if( zPattern[0]==0 ){
|
if( zPattern[0]==0 ){
|
||||||
assert( sqlite3_value_type(argv[1])!=SQLITE_NULL );
|
assert( sqlite3_value_type(argv[1])!=SQLITE_NULL );
|
||||||
sqlite3_result_value(context, argv[0]);
|
sqlite3_result_text(context, (const char*)zStr, nStr, SQLITE_TRANSIENT);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
nPattern = sqlite3_value_bytes(argv[1]);
|
nPattern = sqlite3_value_bytes(argv[1]);
|
||||||
@ -133175,7 +133264,7 @@ SQLITE_PRIVATE void sqlite3Insert(
|
|||||||
pNx->iDataCur = iDataCur;
|
pNx->iDataCur = iDataCur;
|
||||||
pNx->iIdxCur = iIdxCur;
|
pNx->iIdxCur = iIdxCur;
|
||||||
if( pNx->pUpsertTarget ){
|
if( pNx->pUpsertTarget ){
|
||||||
if( sqlite3UpsertAnalyzeTarget(pParse, pTabList, pNx) ){
|
if( sqlite3UpsertAnalyzeTarget(pParse, pTabList, pNx, pUpsert) ){
|
||||||
goto insert_cleanup;
|
goto insert_cleanup;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -139474,31 +139563,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|||||||
int mxCol; /* Maximum non-virtual column number */
|
int mxCol; /* Maximum non-virtual column number */
|
||||||
|
|
||||||
if( pObjTab && pObjTab!=pTab ) continue;
|
if( pObjTab && pObjTab!=pTab ) continue;
|
||||||
if( !IsOrdinaryTable(pTab) ){
|
if( !IsOrdinaryTable(pTab) ) continue;
|
||||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
|
||||||
sqlite3_vtab *pVTab;
|
|
||||||
int a1;
|
|
||||||
if( !IsVirtual(pTab) ) continue;
|
|
||||||
if( pTab->nCol<=0 ){
|
|
||||||
const char *zMod = pTab->u.vtab.azArg[0];
|
|
||||||
if( sqlite3HashFind(&db->aModule, zMod)==0 ) continue;
|
|
||||||
}
|
|
||||||
sqlite3ViewGetColumnNames(pParse, pTab);
|
|
||||||
if( pTab->u.vtab.p==0 ) continue;
|
|
||||||
pVTab = pTab->u.vtab.p->pVtab;
|
|
||||||
if( NEVER(pVTab==0) ) continue;
|
|
||||||
if( NEVER(pVTab->pModule==0) ) continue;
|
|
||||||
if( pVTab->pModule->iVersion<4 ) continue;
|
|
||||||
if( pVTab->pModule->xIntegrity==0 ) continue;
|
|
||||||
sqlite3VdbeAddOp3(v, OP_VCheck, i, 3, isQuick);
|
|
||||||
pTab->nTabRef++;
|
|
||||||
sqlite3VdbeAppendP4(v, pTab, P4_TABLEREF);
|
|
||||||
a1 = sqlite3VdbeAddOp1(v, OP_IsNull, 3); VdbeCoverage(v);
|
|
||||||
integrityCheckResultRow(v);
|
|
||||||
sqlite3VdbeJumpHere(v, a1);
|
|
||||||
#endif
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if( isQuick || HasRowid(pTab) ){
|
if( isQuick || HasRowid(pTab) ){
|
||||||
pPk = 0;
|
pPk = 0;
|
||||||
r2 = 0;
|
r2 = 0;
|
||||||
@ -139633,6 +139698,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|||||||
** is REAL, we have to load the actual data using OP_Column
|
** is REAL, we have to load the actual data using OP_Column
|
||||||
** to reliably determine if the value is a NULL. */
|
** to reliably determine if the value is a NULL. */
|
||||||
sqlite3VdbeAddOp3(v, OP_Column, p1, p3, 3);
|
sqlite3VdbeAddOp3(v, OP_Column, p1, p3, 3);
|
||||||
|
sqlite3ColumnDefault(v, pTab, j, 3);
|
||||||
jmp3 = sqlite3VdbeAddOp2(v, OP_NotNull, 3, labelOk);
|
jmp3 = sqlite3VdbeAddOp2(v, OP_NotNull, 3, labelOk);
|
||||||
VdbeCoverage(v);
|
VdbeCoverage(v);
|
||||||
}
|
}
|
||||||
@ -139823,6 +139889,38 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||||
|
/* Second pass to invoke the xIntegrity method on all virtual
|
||||||
|
** tables.
|
||||||
|
*/
|
||||||
|
for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
|
||||||
|
Table *pTab = sqliteHashData(x);
|
||||||
|
sqlite3_vtab *pVTab;
|
||||||
|
int a1;
|
||||||
|
if( pObjTab && pObjTab!=pTab ) continue;
|
||||||
|
if( IsOrdinaryTable(pTab) ) continue;
|
||||||
|
if( !IsVirtual(pTab) ) continue;
|
||||||
|
if( pTab->nCol<=0 ){
|
||||||
|
const char *zMod = pTab->u.vtab.azArg[0];
|
||||||
|
if( sqlite3HashFind(&db->aModule, zMod)==0 ) continue;
|
||||||
|
}
|
||||||
|
sqlite3ViewGetColumnNames(pParse, pTab);
|
||||||
|
if( pTab->u.vtab.p==0 ) continue;
|
||||||
|
pVTab = pTab->u.vtab.p->pVtab;
|
||||||
|
if( NEVER(pVTab==0) ) continue;
|
||||||
|
if( NEVER(pVTab->pModule==0) ) continue;
|
||||||
|
if( pVTab->pModule->iVersion<4 ) continue;
|
||||||
|
if( pVTab->pModule->xIntegrity==0 ) continue;
|
||||||
|
sqlite3VdbeAddOp3(v, OP_VCheck, i, 3, isQuick);
|
||||||
|
pTab->nTabRef++;
|
||||||
|
sqlite3VdbeAppendP4(v, pTab, P4_TABLEREF);
|
||||||
|
a1 = sqlite3VdbeAddOp1(v, OP_IsNull, 3); VdbeCoverage(v);
|
||||||
|
integrityCheckResultRow(v);
|
||||||
|
sqlite3VdbeJumpHere(v, a1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
static const int iLn = VDBE_OFFSET_LINENO(2);
|
static const int iLn = VDBE_OFFSET_LINENO(2);
|
||||||
@ -153460,7 +153558,8 @@ SQLITE_PRIVATE Upsert *sqlite3UpsertNew(
|
|||||||
SQLITE_PRIVATE int sqlite3UpsertAnalyzeTarget(
|
SQLITE_PRIVATE int sqlite3UpsertAnalyzeTarget(
|
||||||
Parse *pParse, /* The parsing context */
|
Parse *pParse, /* The parsing context */
|
||||||
SrcList *pTabList, /* Table into which we are inserting */
|
SrcList *pTabList, /* Table into which we are inserting */
|
||||||
Upsert *pUpsert /* The ON CONFLICT clauses */
|
Upsert *pUpsert, /* The ON CONFLICT clauses */
|
||||||
|
Upsert *pAll /* Complete list of all ON CONFLICT clauses */
|
||||||
){
|
){
|
||||||
Table *pTab; /* That table into which we are inserting */
|
Table *pTab; /* That table into which we are inserting */
|
||||||
int rc; /* Result code */
|
int rc; /* Result code */
|
||||||
@ -153563,6 +153662,14 @@ SQLITE_PRIVATE int sqlite3UpsertAnalyzeTarget(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
pUpsert->pUpsertIdx = pIdx;
|
pUpsert->pUpsertIdx = pIdx;
|
||||||
|
if( sqlite3UpsertOfIndex(pAll,pIdx)!=pUpsert ){
|
||||||
|
/* Really this should be an error. The isDup ON CONFLICT clause will
|
||||||
|
** never fire. But this problem was not discovered until three years
|
||||||
|
** after multi-CONFLICT upsert was added, and so we silently ignore
|
||||||
|
** the problem to prevent breaking applications that might actually
|
||||||
|
** have redundant ON CONFLICT clauses. */
|
||||||
|
pUpsert->isDup = 1;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if( pUpsert->pUpsertIdx==0 ){
|
if( pUpsert->pUpsertIdx==0 ){
|
||||||
@ -153589,9 +153696,13 @@ SQLITE_PRIVATE int sqlite3UpsertNextIsIPK(Upsert *pUpsert){
|
|||||||
Upsert *pNext;
|
Upsert *pNext;
|
||||||
if( NEVER(pUpsert==0) ) return 0;
|
if( NEVER(pUpsert==0) ) return 0;
|
||||||
pNext = pUpsert->pNextUpsert;
|
pNext = pUpsert->pNextUpsert;
|
||||||
if( pNext==0 ) return 1;
|
while( 1 /*exit-by-return*/ ){
|
||||||
if( pNext->pUpsertTarget==0 ) return 1;
|
if( pNext==0 ) return 1;
|
||||||
if( pNext->pUpsertIdx==0 ) return 1;
|
if( pNext->pUpsertTarget==0 ) return 1;
|
||||||
|
if( pNext->pUpsertIdx==0 ) return 1;
|
||||||
|
if( !pNext->isDup ) return 0;
|
||||||
|
pNext = pNext->pNextUpsert;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204785,6 +204896,7 @@ json_parse_restart:
|
|||||||
case '[': {
|
case '[': {
|
||||||
/* Parse array */
|
/* Parse array */
|
||||||
iThis = pParse->nBlob;
|
iThis = pParse->nBlob;
|
||||||
|
assert( i<=(u32)pParse->nJson );
|
||||||
jsonBlobAppendNode(pParse, JSONB_ARRAY, pParse->nJson - i, 0);
|
jsonBlobAppendNode(pParse, JSONB_ARRAY, pParse->nJson - i, 0);
|
||||||
iStart = pParse->nBlob;
|
iStart = pParse->nBlob;
|
||||||
if( pParse->oom ) return -1;
|
if( pParse->oom ) return -1;
|
||||||
@ -205183,6 +205295,10 @@ static void jsonReturnStringAsBlob(JsonString *pStr){
|
|||||||
JsonParse px;
|
JsonParse px;
|
||||||
memset(&px, 0, sizeof(px));
|
memset(&px, 0, sizeof(px));
|
||||||
jsonStringTerminate(pStr);
|
jsonStringTerminate(pStr);
|
||||||
|
if( pStr->eErr ){
|
||||||
|
sqlite3_result_error_nomem(pStr->pCtx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
px.zJson = pStr->zBuf;
|
px.zJson = pStr->zBuf;
|
||||||
px.nJson = pStr->nUsed;
|
px.nJson = pStr->nUsed;
|
||||||
px.db = sqlite3_context_db_handle(pStr->pCtx);
|
px.db = sqlite3_context_db_handle(pStr->pCtx);
|
||||||
@ -206508,8 +206624,9 @@ rebuild_from_cache:
|
|||||||
}
|
}
|
||||||
p->zJson = (char*)sqlite3_value_text(pArg);
|
p->zJson = (char*)sqlite3_value_text(pArg);
|
||||||
p->nJson = sqlite3_value_bytes(pArg);
|
p->nJson = sqlite3_value_bytes(pArg);
|
||||||
|
if( db->mallocFailed ) goto json_pfa_oom;
|
||||||
if( p->nJson==0 ) goto json_pfa_malformed;
|
if( p->nJson==0 ) goto json_pfa_malformed;
|
||||||
if( NEVER(p->zJson==0) ) goto json_pfa_oom;
|
assert( p->zJson!=0 );
|
||||||
if( jsonConvertTextToBlob(p, (flgs & JSON_KEEPERROR) ? 0 : ctx) ){
|
if( jsonConvertTextToBlob(p, (flgs & JSON_KEEPERROR) ? 0 : ctx) ){
|
||||||
if( flgs & JSON_KEEPERROR ){
|
if( flgs & JSON_KEEPERROR ){
|
||||||
p->nErr = 1;
|
p->nErr = 1;
|
||||||
@ -206675,10 +206792,10 @@ static void jsonDebugPrintBlob(
|
|||||||
if( sz==0 && x<=JSONB_FALSE ){
|
if( sz==0 && x<=JSONB_FALSE ){
|
||||||
sqlite3_str_append(pOut, "\n", 1);
|
sqlite3_str_append(pOut, "\n", 1);
|
||||||
}else{
|
}else{
|
||||||
u32 i;
|
u32 j;
|
||||||
sqlite3_str_appendall(pOut, ": \"");
|
sqlite3_str_appendall(pOut, ": \"");
|
||||||
for(i=iStart+n; i<iStart+n+sz; i++){
|
for(j=iStart+n; j<iStart+n+sz; j++){
|
||||||
u8 c = pParse->aBlob[i];
|
u8 c = pParse->aBlob[j];
|
||||||
if( c<0x20 || c>=0x7f ) c = '.';
|
if( c<0x20 || c>=0x7f ) c = '.';
|
||||||
sqlite3_str_append(pOut, (char*)&c, 1);
|
sqlite3_str_append(pOut, (char*)&c, 1);
|
||||||
}
|
}
|
||||||
@ -208086,6 +208203,9 @@ static int jsonEachColumn(
|
|||||||
case JEACH_VALUE: {
|
case JEACH_VALUE: {
|
||||||
u32 i = jsonSkipLabel(p);
|
u32 i = jsonSkipLabel(p);
|
||||||
jsonReturnFromBlob(&p->sParse, i, ctx, 1);
|
jsonReturnFromBlob(&p->sParse, i, ctx, 1);
|
||||||
|
if( (p->sParse.aBlob[i] & 0x0f)>=JSONB_ARRAY ){
|
||||||
|
sqlite3_result_subtype(ctx, JSON_SUBTYPE);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case JEACH_TYPE: {
|
case JEACH_TYPE: {
|
||||||
@ -208132,9 +208252,9 @@ static int jsonEachColumn(
|
|||||||
case JEACH_JSON: {
|
case JEACH_JSON: {
|
||||||
if( p->sParse.zJson==0 ){
|
if( p->sParse.zJson==0 ){
|
||||||
sqlite3_result_blob(ctx, p->sParse.aBlob, p->sParse.nBlob,
|
sqlite3_result_blob(ctx, p->sParse.aBlob, p->sParse.nBlob,
|
||||||
SQLITE_STATIC);
|
SQLITE_TRANSIENT);
|
||||||
}else{
|
}else{
|
||||||
sqlite3_result_text(ctx, p->sParse.zJson, -1, SQLITE_STATIC);
|
sqlite3_result_text(ctx, p->sParse.zJson, -1, SQLITE_TRANSIENT);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -209160,11 +209280,9 @@ static RtreeNode *nodeNew(Rtree *pRtree, RtreeNode *pParent){
|
|||||||
** Clear the Rtree.pNodeBlob object
|
** Clear the Rtree.pNodeBlob object
|
||||||
*/
|
*/
|
||||||
static void nodeBlobReset(Rtree *pRtree){
|
static void nodeBlobReset(Rtree *pRtree){
|
||||||
if( pRtree->pNodeBlob && pRtree->inWrTrans==0 && pRtree->nCursor==0 ){
|
sqlite3_blob *pBlob = pRtree->pNodeBlob;
|
||||||
sqlite3_blob *pBlob = pRtree->pNodeBlob;
|
pRtree->pNodeBlob = 0;
|
||||||
pRtree->pNodeBlob = 0;
|
sqlite3_blob_close(pBlob);
|
||||||
sqlite3_blob_close(pBlob);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -209208,7 +209326,6 @@ static int nodeAcquire(
|
|||||||
&pRtree->pNodeBlob);
|
&pRtree->pNodeBlob);
|
||||||
}
|
}
|
||||||
if( rc ){
|
if( rc ){
|
||||||
nodeBlobReset(pRtree);
|
|
||||||
*ppNode = 0;
|
*ppNode = 0;
|
||||||
/* If unable to open an sqlite3_blob on the desired row, that can only
|
/* If unable to open an sqlite3_blob on the desired row, that can only
|
||||||
** be because the shadow tables hold erroneous data. */
|
** be because the shadow tables hold erroneous data. */
|
||||||
@ -209268,6 +209385,7 @@ static int nodeAcquire(
|
|||||||
}
|
}
|
||||||
*ppNode = pNode;
|
*ppNode = pNode;
|
||||||
}else{
|
}else{
|
||||||
|
nodeBlobReset(pRtree);
|
||||||
if( pNode ){
|
if( pNode ){
|
||||||
pRtree->nNodeRef--;
|
pRtree->nNodeRef--;
|
||||||
sqlite3_free(pNode);
|
sqlite3_free(pNode);
|
||||||
@ -209412,6 +209530,7 @@ static void nodeGetCoord(
|
|||||||
int iCoord, /* Which coordinate to extract */
|
int iCoord, /* Which coordinate to extract */
|
||||||
RtreeCoord *pCoord /* OUT: Space to write result to */
|
RtreeCoord *pCoord /* OUT: Space to write result to */
|
||||||
){
|
){
|
||||||
|
assert( iCell<NCELL(pNode) );
|
||||||
readCoord(&pNode->zData[12 + pRtree->nBytesPerCell*iCell + 4*iCoord], pCoord);
|
readCoord(&pNode->zData[12 + pRtree->nBytesPerCell*iCell + 4*iCoord], pCoord);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209601,7 +209720,9 @@ static int rtreeClose(sqlite3_vtab_cursor *cur){
|
|||||||
sqlite3_finalize(pCsr->pReadAux);
|
sqlite3_finalize(pCsr->pReadAux);
|
||||||
sqlite3_free(pCsr);
|
sqlite3_free(pCsr);
|
||||||
pRtree->nCursor--;
|
pRtree->nCursor--;
|
||||||
nodeBlobReset(pRtree);
|
if( pRtree->nCursor==0 && pRtree->inWrTrans==0 ){
|
||||||
|
nodeBlobReset(pRtree);
|
||||||
|
}
|
||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -210186,7 +210307,11 @@ static int rtreeRowid(sqlite3_vtab_cursor *pVtabCursor, sqlite_int64 *pRowid){
|
|||||||
int rc = SQLITE_OK;
|
int rc = SQLITE_OK;
|
||||||
RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc);
|
RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc);
|
||||||
if( rc==SQLITE_OK && ALWAYS(p) ){
|
if( rc==SQLITE_OK && ALWAYS(p) ){
|
||||||
*pRowid = nodeGetRowid(RTREE_OF_CURSOR(pCsr), pNode, p->iCell);
|
if( p->iCell>=NCELL(pNode) ){
|
||||||
|
rc = SQLITE_ABORT;
|
||||||
|
}else{
|
||||||
|
*pRowid = nodeGetRowid(RTREE_OF_CURSOR(pCsr), pNode, p->iCell);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -210204,6 +210329,7 @@ static int rtreeColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
|
|||||||
|
|
||||||
if( rc ) return rc;
|
if( rc ) return rc;
|
||||||
if( NEVER(p==0) ) return SQLITE_OK;
|
if( NEVER(p==0) ) return SQLITE_OK;
|
||||||
|
if( p->iCell>=NCELL(pNode) ) return SQLITE_ABORT;
|
||||||
if( i==0 ){
|
if( i==0 ){
|
||||||
sqlite3_result_int64(ctx, nodeGetRowid(pRtree, pNode, p->iCell));
|
sqlite3_result_int64(ctx, nodeGetRowid(pRtree, pNode, p->iCell));
|
||||||
}else if( i<=pRtree->nDim2 ){
|
}else if( i<=pRtree->nDim2 ){
|
||||||
@ -211685,8 +211811,7 @@ constraint:
|
|||||||
*/
|
*/
|
||||||
static int rtreeBeginTransaction(sqlite3_vtab *pVtab){
|
static int rtreeBeginTransaction(sqlite3_vtab *pVtab){
|
||||||
Rtree *pRtree = (Rtree *)pVtab;
|
Rtree *pRtree = (Rtree *)pVtab;
|
||||||
assert( pRtree->inWrTrans==0 );
|
pRtree->inWrTrans = 1;
|
||||||
pRtree->inWrTrans++;
|
|
||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211700,6 +211825,9 @@ static int rtreeEndTransaction(sqlite3_vtab *pVtab){
|
|||||||
nodeBlobReset(pRtree);
|
nodeBlobReset(pRtree);
|
||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
|
static int rtreeRollback(sqlite3_vtab *pVtab){
|
||||||
|
return rtreeEndTransaction(pVtab);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** The xRename method for rtree module virtual tables.
|
** The xRename method for rtree module virtual tables.
|
||||||
@ -211818,7 +211946,7 @@ static sqlite3_module rtreeModule = {
|
|||||||
rtreeBeginTransaction, /* xBegin - begin transaction */
|
rtreeBeginTransaction, /* xBegin - begin transaction */
|
||||||
rtreeEndTransaction, /* xSync - sync transaction */
|
rtreeEndTransaction, /* xSync - sync transaction */
|
||||||
rtreeEndTransaction, /* xCommit - commit transaction */
|
rtreeEndTransaction, /* xCommit - commit transaction */
|
||||||
rtreeEndTransaction, /* xRollback - rollback transaction */
|
rtreeRollback, /* xRollback - rollback transaction */
|
||||||
0, /* xFindFunction - function overloading */
|
0, /* xFindFunction - function overloading */
|
||||||
rtreeRename, /* xRename - rename the table */
|
rtreeRename, /* xRename - rename the table */
|
||||||
rtreeSavepoint, /* xSavepoint */
|
rtreeSavepoint, /* xSavepoint */
|
||||||
@ -245377,23 +245505,26 @@ static void fts5IterSetOutputsTokendata(Fts5Iter *pIter){
|
|||||||
static void fts5TokendataIterNext(Fts5Iter *pIter, int bFrom, i64 iFrom){
|
static void fts5TokendataIterNext(Fts5Iter *pIter, int bFrom, i64 iFrom){
|
||||||
int ii;
|
int ii;
|
||||||
Fts5TokenDataIter *pT = pIter->pTokenDataIter;
|
Fts5TokenDataIter *pT = pIter->pTokenDataIter;
|
||||||
|
Fts5Index *pIndex = pIter->pIndex;
|
||||||
|
|
||||||
for(ii=0; ii<pT->nIter; ii++){
|
for(ii=0; ii<pT->nIter; ii++){
|
||||||
Fts5Iter *p = pT->apIter[ii];
|
Fts5Iter *p = pT->apIter[ii];
|
||||||
if( p->base.bEof==0
|
if( p->base.bEof==0
|
||||||
&& (p->base.iRowid==pIter->base.iRowid || (bFrom && p->base.iRowid<iFrom))
|
&& (p->base.iRowid==pIter->base.iRowid || (bFrom && p->base.iRowid<iFrom))
|
||||||
){
|
){
|
||||||
fts5MultiIterNext(p->pIndex, p, bFrom, iFrom);
|
fts5MultiIterNext(pIndex, p, bFrom, iFrom);
|
||||||
while( bFrom && p->base.bEof==0
|
while( bFrom && p->base.bEof==0
|
||||||
&& p->base.iRowid<iFrom
|
&& p->base.iRowid<iFrom
|
||||||
&& p->pIndex->rc==SQLITE_OK
|
&& pIndex->rc==SQLITE_OK
|
||||||
){
|
){
|
||||||
fts5MultiIterNext(p->pIndex, p, 0, 0);
|
fts5MultiIterNext(pIndex, p, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fts5IterSetOutputsTokendata(pIter);
|
if( pIndex->rc==SQLITE_OK ){
|
||||||
|
fts5IterSetOutputsTokendata(pIter);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -250547,7 +250678,7 @@ static void fts5SourceIdFunc(
|
|||||||
){
|
){
|
||||||
assert( nArg==0 );
|
assert( nArg==0 );
|
||||||
UNUSED_PARAM2(nArg, apUnused);
|
UNUSED_PARAM2(nArg, apUnused);
|
||||||
sqlite3_result_text(pCtx, "fts5: 2024-01-30 16:01:20 e876e51a0ed5c5b3126f52e532044363a014bc594cfefa87ffb5b82257cc467a", -1, SQLITE_TRANSIENT);
|
sqlite3_result_text(pCtx, "fts5: 2024-03-12 11:06:23 d8cd6d49b46a395b13955387d05e9e1a2a47e54fb99f3c9b59835bbefad6af77", -1, SQLITE_TRANSIENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
8
deps/sqlite/sqlite3.h
vendored
8
deps/sqlite/sqlite3.h
vendored
@ -146,9 +146,9 @@ extern "C" {
|
|||||||
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
|
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
|
||||||
** [sqlite_version()] and [sqlite_source_id()].
|
** [sqlite_version()] and [sqlite_source_id()].
|
||||||
*/
|
*/
|
||||||
#define SQLITE_VERSION "3.45.1"
|
#define SQLITE_VERSION "3.45.2"
|
||||||
#define SQLITE_VERSION_NUMBER 3045001
|
#define SQLITE_VERSION_NUMBER 3045002
|
||||||
#define SQLITE_SOURCE_ID "2024-01-30 16:01:20 e876e51a0ed5c5b3126f52e532044363a014bc594cfefa87ffb5b82257cc467a"
|
#define SQLITE_SOURCE_ID "2024-03-12 11:06:23 d8cd6d49b46a395b13955387d05e9e1a2a47e54fb99f3c9b59835bbefad6af77"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** CAPI3REF: Run-Time Library Version Numbers
|
** CAPI3REF: Run-Time Library Version Numbers
|
||||||
@ -420,6 +420,8 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
|
|||||||
** the 1st parameter to sqlite3_exec() while sqlite3_exec() is running.
|
** the 1st parameter to sqlite3_exec() while sqlite3_exec() is running.
|
||||||
** <li> The application must not modify the SQL statement text passed into
|
** <li> The application must not modify the SQL statement text passed into
|
||||||
** the 2nd parameter of sqlite3_exec() while sqlite3_exec() is running.
|
** the 2nd parameter of sqlite3_exec() while sqlite3_exec() is running.
|
||||||
|
** <li> The application must not dereference the arrays or string pointers
|
||||||
|
** passed as the 3rd and 4th callback parameters after it returns.
|
||||||
** </ul>
|
** </ul>
|
||||||
*/
|
*/
|
||||||
SQLITE_API int sqlite3_exec(
|
SQLITE_API int sqlite3_exec(
|
||||||
|
17
src/ssb.c
17
src/ssb.c
@ -1003,14 +1003,13 @@ static bool _tf_ssb_verify_and_strip_signature_internal(JSContext* context, JSVa
|
|||||||
return verified;
|
return verified;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tf_ssb_verify_and_strip_signature(
|
bool tf_ssb_verify_and_strip_signature(JSContext* context, JSValue val, char* out_id, size_t out_id_size, char* out_signature, size_t out_signature_size, int* out_flags)
|
||||||
JSContext* context, JSValue val, char* out_id, size_t out_id_size, char* out_signature, size_t out_signature_size, bool* out_sequence_before_author)
|
|
||||||
{
|
{
|
||||||
if (_tf_ssb_verify_and_strip_signature_internal(context, val, out_id, out_id_size, out_signature, out_signature_size))
|
if (_tf_ssb_verify_and_strip_signature_internal(context, val, out_id, out_id_size, out_signature, out_signature_size))
|
||||||
{
|
{
|
||||||
if (out_sequence_before_author)
|
if (out_flags)
|
||||||
{
|
{
|
||||||
*out_sequence_before_author = false;
|
*out_flags = 0;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1028,9 +1027,9 @@ bool tf_ssb_verify_and_strip_signature(
|
|||||||
JS_FreeValue(context, reordered);
|
JS_FreeValue(context, reordered);
|
||||||
if (result)
|
if (result)
|
||||||
{
|
{
|
||||||
if (out_sequence_before_author)
|
if (out_flags)
|
||||||
{
|
{
|
||||||
*out_sequence_before_author = true;
|
*out_flags = k_tf_ssb_message_flag_sequence_before_author;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -3562,11 +3561,11 @@ void tf_ssb_verify_strip_and_store_message(tf_ssb_t* ssb, JSValue value, tf_ssb_
|
|||||||
.user_data = user_data,
|
.user_data = user_data,
|
||||||
};
|
};
|
||||||
char signature[crypto_sign_BYTES + 128] = { 0 };
|
char signature[crypto_sign_BYTES + 128] = { 0 };
|
||||||
bool sequence_before_author = false;
|
int flags = 0;
|
||||||
if (tf_ssb_verify_and_strip_signature(context, value, async->id, sizeof(async->id), signature, sizeof(signature), &sequence_before_author))
|
if (tf_ssb_verify_and_strip_signature(context, value, async->id, sizeof(async->id), signature, sizeof(signature), &flags))
|
||||||
{
|
{
|
||||||
async->verified = true;
|
async->verified = true;
|
||||||
tf_ssb_db_store_message(ssb, context, async->id, value, signature, sequence_before_author, _tf_ssb_verify_strip_and_store_callback, async);
|
tf_ssb_db_store_message(ssb, context, async->id, value, signature, flags, _tf_ssb_verify_strip_and_store_callback, async);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
50
src/ssb.db.c
50
src/ssb.db.c
@ -103,7 +103,7 @@ void tf_ssb_db_init(tf_ssb_t* ssb)
|
|||||||
" hash TEXT,"
|
" hash TEXT,"
|
||||||
" content BLOB,"
|
" content BLOB,"
|
||||||
" signature TEXT,"
|
" signature TEXT,"
|
||||||
" sequence_before_author INTEGER,"
|
" flags INTEGER,"
|
||||||
" UNIQUE(author, sequence)"
|
" UNIQUE(author, sequence)"
|
||||||
")");
|
")");
|
||||||
|
|
||||||
@ -123,6 +123,12 @@ void tf_ssb_db_init(tf_ssb_t* ssb)
|
|||||||
_tf_ssb_db_exec(db, "COMMIT TRANSACTION");
|
_tf_ssb_db_exec(db, "COMMIT TRANSACTION");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_tf_ssb_db_has_rows(db, "SELECT name FROM pragma_table_info('messages') WHERE name = 'sequence_before_author'"))
|
||||||
|
{
|
||||||
|
tf_printf("Renaming sequence_before_author -> flags.\n");
|
||||||
|
_tf_ssb_db_exec(db, "ALTER TABLE messages RENAME COLUMN sequence_before_author TO flags");
|
||||||
|
}
|
||||||
|
|
||||||
_tf_ssb_db_exec(db, "CREATE INDEX IF NOT EXISTS messages_author_id_index ON messages (author, id)");
|
_tf_ssb_db_exec(db, "CREATE INDEX IF NOT EXISTS messages_author_id_index ON messages (author, id)");
|
||||||
_tf_ssb_db_exec(db, "CREATE INDEX IF NOT EXISTS messages_author_sequence_index ON messages (author, sequence)");
|
_tf_ssb_db_exec(db, "CREATE INDEX IF NOT EXISTS messages_author_sequence_index ON messages (author, sequence)");
|
||||||
_tf_ssb_db_exec(db, "CREATE INDEX IF NOT EXISTS messages_author_timestamp_index ON messages (author, timestamp)");
|
_tf_ssb_db_exec(db, "CREATE INDEX IF NOT EXISTS messages_author_timestamp_index ON messages (author, timestamp)");
|
||||||
@ -232,7 +238,7 @@ void tf_ssb_db_init(tf_ssb_t* ssb)
|
|||||||
" AND LENGTH(messages_refs.ref) = 52 "
|
" AND LENGTH(messages_refs.ref) = 52 "
|
||||||
" AND messages_refs.ref LIKE '&%.sha256'");
|
" AND messages_refs.ref LIKE '&%.sha256'");
|
||||||
|
|
||||||
bool need_add_sequence_before_author = true;
|
bool need_add_flags = true;
|
||||||
bool need_convert_timestamp_to_real = false;
|
bool need_convert_timestamp_to_real = false;
|
||||||
|
|
||||||
if (sqlite3_prepare(db, "PRAGMA table_info(messages)", -1, &statement, NULL) == SQLITE_OK)
|
if (sqlite3_prepare(db, "PRAGMA table_info(messages)", -1, &statement, NULL) == SQLITE_OK)
|
||||||
@ -246,9 +252,9 @@ void tf_ssb_db_init(tf_ssb_t* ssb)
|
|||||||
{
|
{
|
||||||
need_convert_timestamp_to_real = true;
|
need_convert_timestamp_to_real = true;
|
||||||
}
|
}
|
||||||
if (name && strcmp(name, "sequence_before_author") == 0)
|
if (name && strcmp(name, "flags") == 0)
|
||||||
{
|
{
|
||||||
need_add_sequence_before_author = false;
|
need_add_flags = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sqlite3_finalize(statement);
|
sqlite3_finalize(statement);
|
||||||
@ -266,10 +272,10 @@ void tf_ssb_db_init(tf_ssb_t* ssb)
|
|||||||
_tf_ssb_db_exec(db, "CREATE INDEX IF NOT EXISTS messages_author_timestamp_index ON messages (author, timestamp)");
|
_tf_ssb_db_exec(db, "CREATE INDEX IF NOT EXISTS messages_author_timestamp_index ON messages (author, timestamp)");
|
||||||
_tf_ssb_db_exec(db, "COMMIT TRANSACTION");
|
_tf_ssb_db_exec(db, "COMMIT TRANSACTION");
|
||||||
}
|
}
|
||||||
if (need_add_sequence_before_author)
|
if (need_add_flags)
|
||||||
{
|
{
|
||||||
tf_printf("Adding sequence_before_author column.\n");
|
tf_printf("Adding flags column.\n");
|
||||||
_tf_ssb_db_exec(db, "ALTER TABLE messages ADD COLUMN sequence_before_author INTEGER");
|
_tf_ssb_db_exec(db, "ALTER TABLE messages ADD COLUMN flags INTEGER");
|
||||||
}
|
}
|
||||||
tf_ssb_release_db_writer(ssb, db);
|
tf_ssb_release_db_writer(ssb, db);
|
||||||
}
|
}
|
||||||
@ -298,14 +304,14 @@ static bool _tf_ssb_db_previous_message_exists(sqlite3* db, const char* author,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int64_t _tf_ssb_db_store_message_raw(tf_ssb_t* ssb, const char* id, const char* previous, const char* author, int64_t sequence, double timestamp, const char* content,
|
static int64_t _tf_ssb_db_store_message_raw(tf_ssb_t* ssb, const char* id, const char* previous, const char* author, int64_t sequence, double timestamp, const char* content,
|
||||||
size_t content_len, const char* signature, bool sequence_before_author)
|
size_t content_len, const char* signature, int flags)
|
||||||
{
|
{
|
||||||
sqlite3* db = tf_ssb_acquire_db_writer(ssb);
|
sqlite3* db = tf_ssb_acquire_db_writer(ssb);
|
||||||
int64_t last_row_id = -1;
|
int64_t last_row_id = -1;
|
||||||
|
|
||||||
if (_tf_ssb_db_previous_message_exists(db, author, sequence, previous))
|
if (_tf_ssb_db_previous_message_exists(db, author, sequence, previous))
|
||||||
{
|
{
|
||||||
const char* query = "INSERT INTO messages (id, previous, author, sequence, timestamp, content, hash, signature, sequence_before_author) VALUES (?, ?, ?, ?, ?, jsonb(?), "
|
const char* query = "INSERT INTO messages (id, previous, author, sequence, timestamp, content, hash, signature, flags) VALUES (?, ?, ?, ?, ?, jsonb(?), "
|
||||||
"?, ?, ?) ON CONFLICT DO NOTHING";
|
"?, ?, ?) ON CONFLICT DO NOTHING";
|
||||||
sqlite3_stmt* statement;
|
sqlite3_stmt* statement;
|
||||||
if (sqlite3_prepare(db, query, -1, &statement, NULL) == SQLITE_OK)
|
if (sqlite3_prepare(db, query, -1, &statement, NULL) == SQLITE_OK)
|
||||||
@ -315,7 +321,7 @@ static int64_t _tf_ssb_db_store_message_raw(tf_ssb_t* ssb, const char* id, const
|
|||||||
sqlite3_bind_text(statement, 3, author, -1, NULL) == SQLITE_OK && sqlite3_bind_int64(statement, 4, sequence) == SQLITE_OK &&
|
sqlite3_bind_text(statement, 3, author, -1, NULL) == SQLITE_OK && sqlite3_bind_int64(statement, 4, sequence) == SQLITE_OK &&
|
||||||
sqlite3_bind_double(statement, 5, timestamp) == SQLITE_OK && sqlite3_bind_text(statement, 6, content, content_len, NULL) == SQLITE_OK &&
|
sqlite3_bind_double(statement, 5, timestamp) == SQLITE_OK && sqlite3_bind_text(statement, 6, content, content_len, NULL) == SQLITE_OK &&
|
||||||
sqlite3_bind_text(statement, 7, "sha256", 6, NULL) == SQLITE_OK && sqlite3_bind_text(statement, 8, signature, -1, NULL) == SQLITE_OK &&
|
sqlite3_bind_text(statement, 7, "sha256", 6, NULL) == SQLITE_OK && sqlite3_bind_text(statement, 8, signature, -1, NULL) == SQLITE_OK &&
|
||||||
sqlite3_bind_int(statement, 9, sequence_before_author) == SQLITE_OK)
|
sqlite3_bind_int(statement, 9, flags) == SQLITE_OK)
|
||||||
{
|
{
|
||||||
int r = sqlite3_step(statement);
|
int r = sqlite3_step(statement);
|
||||||
if (r != SQLITE_DONE)
|
if (r != SQLITE_DONE)
|
||||||
@ -397,7 +403,7 @@ typedef struct _message_store_t
|
|||||||
tf_ssb_t* ssb;
|
tf_ssb_t* ssb;
|
||||||
char id[k_id_base64_len];
|
char id[k_id_base64_len];
|
||||||
char signature[512];
|
char signature[512];
|
||||||
bool sequence_before_author;
|
int flags;
|
||||||
char previous[k_id_base64_len];
|
char previous[k_id_base64_len];
|
||||||
char author[k_id_base64_len];
|
char author[k_id_base64_len];
|
||||||
int64_t sequence;
|
int64_t sequence;
|
||||||
@ -421,7 +427,7 @@ static void _tf_ssb_db_store_message_work(uv_work_t* work)
|
|||||||
tf_trace_t* trace = tf_ssb_get_trace(store->ssb);
|
tf_trace_t* trace = tf_ssb_get_trace(store->ssb);
|
||||||
tf_trace_begin(trace, "message_store_work");
|
tf_trace_begin(trace, "message_store_work");
|
||||||
int64_t last_row_id = _tf_ssb_db_store_message_raw(store->ssb, store->id, *store->previous ? store->previous : NULL, store->author, store->sequence, store->timestamp,
|
int64_t last_row_id = _tf_ssb_db_store_message_raw(store->ssb, store->id, *store->previous ? store->previous : NULL, store->author, store->sequence, store->timestamp,
|
||||||
store->content, store->length, store->signature, store->sequence_before_author);
|
store->content, store->length, store->signature, store->flags);
|
||||||
if (last_row_id != -1)
|
if (last_row_id != -1)
|
||||||
{
|
{
|
||||||
store->out_stored = true;
|
store->out_stored = true;
|
||||||
@ -477,8 +483,8 @@ static void _tf_ssb_db_store_message_after_work(uv_work_t* work, int status)
|
|||||||
{
|
{
|
||||||
tf_trace_begin(trace, "notify_message_added");
|
tf_trace_begin(trace, "notify_message_added");
|
||||||
JSContext* context = tf_ssb_get_context(store->ssb);
|
JSContext* context = tf_ssb_get_context(store->ssb);
|
||||||
JSValue formatted = tf_ssb_format_message(
|
JSValue formatted =
|
||||||
context, store->previous, store->author, store->sequence, store->timestamp, "sha256", store->content, store->signature, store->sequence_before_author);
|
tf_ssb_format_message(context, store->previous, store->author, store->sequence, store->timestamp, "sha256", store->content, store->signature, store->flags);
|
||||||
JSValue message = JS_NewObject(context);
|
JSValue message = JS_NewObject(context);
|
||||||
JS_SetPropertyStr(context, message, "key", JS_NewString(context, store->id));
|
JS_SetPropertyStr(context, message, "key", JS_NewString(context, store->id));
|
||||||
JS_SetPropertyStr(context, message, "value", formatted);
|
JS_SetPropertyStr(context, message, "value", formatted);
|
||||||
@ -503,8 +509,8 @@ static void _tf_ssb_db_store_message_after_work(uv_work_t* work, int status)
|
|||||||
tf_trace_end(trace);
|
tf_trace_end(trace);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tf_ssb_db_store_message(tf_ssb_t* ssb, JSContext* context, const char* id, JSValue val, const char* signature, bool sequence_before_author,
|
void tf_ssb_db_store_message(
|
||||||
tf_ssb_db_store_message_callback_t* callback, void* user_data)
|
tf_ssb_t* ssb, JSContext* context, const char* id, JSValue val, const char* signature, int flags, tf_ssb_db_store_message_callback_t* callback, void* user_data)
|
||||||
{
|
{
|
||||||
JSValue previousval = JS_GetPropertyStr(context, val, "previous");
|
JSValue previousval = JS_GetPropertyStr(context, val, "previous");
|
||||||
const char* previous = JS_IsNull(previousval) ? NULL : JS_ToCString(context, previousval);
|
const char* previous = JS_IsNull(previousval) ? NULL : JS_ToCString(context, previousval);
|
||||||
@ -543,7 +549,7 @@ void tf_ssb_db_store_message(tf_ssb_t* ssb, JSContext* context, const char* id,
|
|||||||
.timestamp = timestamp,
|
.timestamp = timestamp,
|
||||||
.content = contentstr,
|
.content = contentstr,
|
||||||
.length = content_len,
|
.length = content_len,
|
||||||
.sequence_before_author = sequence_before_author,
|
.flags = flags,
|
||||||
|
|
||||||
.callback = callback,
|
.callback = callback,
|
||||||
.user_data = user_data,
|
.user_data = user_data,
|
||||||
@ -1002,12 +1008,12 @@ JSValue tf_ssb_db_visit_query(tf_ssb_t* ssb, const char* query, const JSValue bi
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSValue tf_ssb_format_message(JSContext* context, const char* previous, const char* author, int64_t sequence, double timestamp, const char* hash, const char* content,
|
JSValue tf_ssb_format_message(
|
||||||
const char* signature, bool sequence_before_author)
|
JSContext* context, const char* previous, const char* author, int64_t sequence, double timestamp, const char* hash, const char* content, const char* signature, int flags)
|
||||||
{
|
{
|
||||||
JSValue value = JS_NewObject(context);
|
JSValue value = JS_NewObject(context);
|
||||||
JS_SetPropertyStr(context, value, "previous", (previous && *previous) ? JS_NewString(context, previous) : JS_NULL);
|
JS_SetPropertyStr(context, value, "previous", (previous && *previous) ? JS_NewString(context, previous) : JS_NULL);
|
||||||
if (sequence_before_author)
|
if (flags & k_tf_ssb_message_flag_sequence_before_author)
|
||||||
{
|
{
|
||||||
JS_SetPropertyStr(context, value, "sequence", JS_NewInt64(context, sequence));
|
JS_SetPropertyStr(context, value, "sequence", JS_NewInt64(context, sequence));
|
||||||
JS_SetPropertyStr(context, value, "author", JS_NewString(context, author));
|
JS_SetPropertyStr(context, value, "author", JS_NewString(context, author));
|
||||||
@ -1499,8 +1505,8 @@ JSValue tf_ssb_db_get_message_by_id(tf_ssb_t* ssb, const char* id, bool is_keys)
|
|||||||
JSContext* context = tf_ssb_get_context(ssb);
|
JSContext* context = tf_ssb_get_context(ssb);
|
||||||
sqlite3* db = tf_ssb_acquire_db_reader(ssb);
|
sqlite3* db = tf_ssb_acquire_db_reader(ssb);
|
||||||
sqlite3_stmt* statement;
|
sqlite3_stmt* statement;
|
||||||
if (sqlite3_prepare(db, "SELECT previous, author, id, sequence, timestamp, hash, json(content), signature, sequence_before_author FROM messages WHERE id = ?", -1, &statement,
|
if (sqlite3_prepare(db, "SELECT previous, author, id, sequence, timestamp, hash, json(content), signature, flags FROM messages WHERE id = ?", -1, &statement, NULL) ==
|
||||||
NULL) == SQLITE_OK)
|
SQLITE_OK)
|
||||||
{
|
{
|
||||||
if (sqlite3_bind_text(statement, 1, id, -1, NULL) == SQLITE_OK)
|
if (sqlite3_bind_text(statement, 1, id, -1, NULL) == SQLITE_OK)
|
||||||
{
|
{
|
||||||
|
12
src/ssb.db.h
12
src/ssb.db.h
@ -70,12 +70,12 @@ typedef void(tf_ssb_db_store_message_callback_t)(const char* id, bool stored, vo
|
|||||||
** @param id The message identifier.
|
** @param id The message identifier.
|
||||||
** @param val The message object.
|
** @param val The message object.
|
||||||
** @param signature The signature of the message.
|
** @param signature The signature of the message.
|
||||||
** @param sequence_before_author The order of the message fields.
|
** @param flags tf_ssb_message_flags_t describing the message.
|
||||||
** @param callback A callback to call upon completion.
|
** @param callback A callback to call upon completion.
|
||||||
** @param user_data User data for the callback.
|
** @param user_data User data for the callback.
|
||||||
*/
|
*/
|
||||||
void tf_ssb_db_store_message(tf_ssb_t* ssb, JSContext* context, const char* id, JSValue val, const char* signature, bool sequence_before_author,
|
void tf_ssb_db_store_message(
|
||||||
tf_ssb_db_store_message_callback_t* callback, void* user_data);
|
tf_ssb_t* ssb, JSContext* context, const char* id, JSValue val, const char* signature, int flags, tf_ssb_db_store_message_callback_t* callback, void* user_data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** A function called when a block is stored in the database.
|
** A function called when a block is stored in the database.
|
||||||
@ -233,10 +233,10 @@ bool tf_ssb_db_identity_get_private_key(tf_ssb_t* ssb, const char* user, const c
|
|||||||
** @param hash The hash type (probably "sha256").
|
** @param hash The hash type (probably "sha256").
|
||||||
** @param content The message content.
|
** @param content The message content.
|
||||||
** @param signature The signature of the message.
|
** @param signature The signature of the message.
|
||||||
** @param sequence_before_author The order of the message fields (prefer false).
|
** @param flags tf_ssb_message_flags_t describing the message.
|
||||||
*/
|
*/
|
||||||
JSValue tf_ssb_format_message(JSContext* context, const char* previous, const char* author, int64_t sequence, double timestamp, const char* hash, const char* content,
|
JSValue tf_ssb_format_message(
|
||||||
const char* signature, bool sequence_before_author);
|
JSContext* context, const char* previous, const char* author, int64_t sequence, double timestamp, const char* hash, const char* content, const char* signature, int flags);
|
||||||
|
|
||||||
/** Information about a single followed account. */
|
/** Information about a single followed account. */
|
||||||
typedef struct _tf_ssb_following_t
|
typedef struct _tf_ssb_following_t
|
||||||
|
10
src/ssb.h
10
src/ssb.h
@ -40,6 +40,11 @@ typedef enum _tf_ssb_change_t
|
|||||||
k_tf_ssb_change_remove,
|
k_tf_ssb_change_remove,
|
||||||
} tf_ssb_change_t;
|
} tf_ssb_change_t;
|
||||||
|
|
||||||
|
typedef enum _tf_ssb_message_flags_t
|
||||||
|
{
|
||||||
|
k_tf_ssb_message_flag_sequence_before_author = 1,
|
||||||
|
} tf_ssb_message_flags_t;
|
||||||
|
|
||||||
/** An SSB instance. */
|
/** An SSB instance. */
|
||||||
typedef struct _tf_ssb_t tf_ssb_t;
|
typedef struct _tf_ssb_t tf_ssb_t;
|
||||||
/** An SSB connection. */
|
/** An SSB connection. */
|
||||||
@ -363,11 +368,10 @@ bool tf_ssb_id_bin_to_str(char* str, size_t str_size, const uint8_t* bin);
|
|||||||
** @param out_id_size The size of out_id.
|
** @param out_id_size The size of out_id.
|
||||||
** @param[out] out_signature A buffer to receive the message's signature.
|
** @param[out] out_signature A buffer to receive the message's signature.
|
||||||
** @param out_signature_size The size of out_signature.
|
** @param out_signature_size The size of out_signature.
|
||||||
** @param[out] out_sequence_before_author A flag describing the order of the sequence and author fields.
|
** @param[out] out_flags tf_ssb_message_flags_t describing the message.
|
||||||
** @return True if the signature is valid and was successfully extracted.
|
** @return True if the signature is valid and was successfully extracted.
|
||||||
*/
|
*/
|
||||||
bool tf_ssb_verify_and_strip_signature(
|
bool tf_ssb_verify_and_strip_signature(JSContext* context, JSValue val, char* out_id, size_t out_id_size, char* out_signature, size_t out_signature_size, int* out_flags);
|
||||||
JSContext* context, JSValue val, char* out_id, size_t out_id_size, char* out_signature, size_t out_signature_size, bool* out_sequence_before_author);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Determine the message identifier.
|
** Determine the message identifier.
|
||||||
|
@ -678,7 +678,7 @@ static void _tf_ssb_connection_send_history_stream_work(tf_ssb_connection_t* con
|
|||||||
sqlite3_stmt* statement;
|
sqlite3_stmt* statement;
|
||||||
const int k_max = 32;
|
const int k_max = 32;
|
||||||
if (sqlite3_prepare(db,
|
if (sqlite3_prepare(db,
|
||||||
"SELECT previous, author, id, sequence, timestamp, hash, json(content), signature, sequence_before_author FROM messages WHERE author = ?1 AND sequence > ?2 AND "
|
"SELECT previous, author, id, sequence, timestamp, hash, json(content), signature, flags FROM messages WHERE author = ?1 AND sequence > ?2 AND "
|
||||||
"sequence "
|
"sequence "
|
||||||
"< ?3 ORDER BY sequence",
|
"< ?3 ORDER BY sequence",
|
||||||
-1, &statement, NULL) == SQLITE_OK)
|
-1, &statement, NULL) == SQLITE_OK)
|
||||||
|
Loading…
Reference in New Issue
Block a user