fix: harden UCE runtime and starter
This commit is contained in:
Vendored
+257679
File diff suppressed because it is too large
Load Diff
Vendored
+13425
File diff suppressed because it is too large
Load Diff
Vendored
+719
@@ -0,0 +1,719 @@
|
||||
/*
|
||||
** 2006 June 7
|
||||
**
|
||||
** 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 header file defines the SQLite interface for use by
|
||||
** shared libraries that want to be imported as extensions into
|
||||
** an SQLite instance. Shared libraries that intend to be loaded
|
||||
** as extensions by SQLite should #include this file instead of
|
||||
** sqlite3.h.
|
||||
*/
|
||||
#ifndef SQLITE3EXT_H
|
||||
#define SQLITE3EXT_H
|
||||
#include "sqlite3.h"
|
||||
|
||||
/*
|
||||
** The following structure holds pointers to all of the SQLite API
|
||||
** routines.
|
||||
**
|
||||
** WARNING: In order to maintain backwards compatibility, add new
|
||||
** interfaces to the end of this structure only. If you insert new
|
||||
** interfaces in the middle of this structure, then older different
|
||||
** versions of SQLite will not be able to load each other's shared
|
||||
** libraries!
|
||||
*/
|
||||
struct sqlite3_api_routines {
|
||||
void * (*aggregate_context)(sqlite3_context*,int nBytes);
|
||||
int (*aggregate_count)(sqlite3_context*);
|
||||
int (*bind_blob)(sqlite3_stmt*,int,const void*,int n,void(*)(void*));
|
||||
int (*bind_double)(sqlite3_stmt*,int,double);
|
||||
int (*bind_int)(sqlite3_stmt*,int,int);
|
||||
int (*bind_int64)(sqlite3_stmt*,int,sqlite_int64);
|
||||
int (*bind_null)(sqlite3_stmt*,int);
|
||||
int (*bind_parameter_count)(sqlite3_stmt*);
|
||||
int (*bind_parameter_index)(sqlite3_stmt*,const char*zName);
|
||||
const char * (*bind_parameter_name)(sqlite3_stmt*,int);
|
||||
int (*bind_text)(sqlite3_stmt*,int,const char*,int n,void(*)(void*));
|
||||
int (*bind_text16)(sqlite3_stmt*,int,const void*,int,void(*)(void*));
|
||||
int (*bind_value)(sqlite3_stmt*,int,const sqlite3_value*);
|
||||
int (*busy_handler)(sqlite3*,int(*)(void*,int),void*);
|
||||
int (*busy_timeout)(sqlite3*,int ms);
|
||||
int (*changes)(sqlite3*);
|
||||
int (*close)(sqlite3*);
|
||||
int (*collation_needed)(sqlite3*,void*,void(*)(void*,sqlite3*,
|
||||
int eTextRep,const char*));
|
||||
int (*collation_needed16)(sqlite3*,void*,void(*)(void*,sqlite3*,
|
||||
int eTextRep,const void*));
|
||||
const void * (*column_blob)(sqlite3_stmt*,int iCol);
|
||||
int (*column_bytes)(sqlite3_stmt*,int iCol);
|
||||
int (*column_bytes16)(sqlite3_stmt*,int iCol);
|
||||
int (*column_count)(sqlite3_stmt*pStmt);
|
||||
const char * (*column_database_name)(sqlite3_stmt*,int);
|
||||
const void * (*column_database_name16)(sqlite3_stmt*,int);
|
||||
const char * (*column_decltype)(sqlite3_stmt*,int i);
|
||||
const void * (*column_decltype16)(sqlite3_stmt*,int);
|
||||
double (*column_double)(sqlite3_stmt*,int iCol);
|
||||
int (*column_int)(sqlite3_stmt*,int iCol);
|
||||
sqlite_int64 (*column_int64)(sqlite3_stmt*,int iCol);
|
||||
const char * (*column_name)(sqlite3_stmt*,int);
|
||||
const void * (*column_name16)(sqlite3_stmt*,int);
|
||||
const char * (*column_origin_name)(sqlite3_stmt*,int);
|
||||
const void * (*column_origin_name16)(sqlite3_stmt*,int);
|
||||
const char * (*column_table_name)(sqlite3_stmt*,int);
|
||||
const void * (*column_table_name16)(sqlite3_stmt*,int);
|
||||
const unsigned char * (*column_text)(sqlite3_stmt*,int iCol);
|
||||
const void * (*column_text16)(sqlite3_stmt*,int iCol);
|
||||
int (*column_type)(sqlite3_stmt*,int iCol);
|
||||
sqlite3_value* (*column_value)(sqlite3_stmt*,int iCol);
|
||||
void * (*commit_hook)(sqlite3*,int(*)(void*),void*);
|
||||
int (*complete)(const char*sql);
|
||||
int (*complete16)(const void*sql);
|
||||
int (*create_collation)(sqlite3*,const char*,int,void*,
|
||||
int(*)(void*,int,const void*,int,const void*));
|
||||
int (*create_collation16)(sqlite3*,const void*,int,void*,
|
||||
int(*)(void*,int,const void*,int,const void*));
|
||||
int (*create_function)(sqlite3*,const char*,int,int,void*,
|
||||
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xFinal)(sqlite3_context*));
|
||||
int (*create_function16)(sqlite3*,const void*,int,int,void*,
|
||||
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xFinal)(sqlite3_context*));
|
||||
int (*create_module)(sqlite3*,const char*,const sqlite3_module*,void*);
|
||||
int (*data_count)(sqlite3_stmt*pStmt);
|
||||
sqlite3 * (*db_handle)(sqlite3_stmt*);
|
||||
int (*declare_vtab)(sqlite3*,const char*);
|
||||
int (*enable_shared_cache)(int);
|
||||
int (*errcode)(sqlite3*db);
|
||||
const char * (*errmsg)(sqlite3*);
|
||||
const void * (*errmsg16)(sqlite3*);
|
||||
int (*exec)(sqlite3*,const char*,sqlite3_callback,void*,char**);
|
||||
int (*expired)(sqlite3_stmt*);
|
||||
int (*finalize)(sqlite3_stmt*pStmt);
|
||||
void (*free)(void*);
|
||||
void (*free_table)(char**result);
|
||||
int (*get_autocommit)(sqlite3*);
|
||||
void * (*get_auxdata)(sqlite3_context*,int);
|
||||
int (*get_table)(sqlite3*,const char*,char***,int*,int*,char**);
|
||||
int (*global_recover)(void);
|
||||
void (*interruptx)(sqlite3*);
|
||||
sqlite_int64 (*last_insert_rowid)(sqlite3*);
|
||||
const char * (*libversion)(void);
|
||||
int (*libversion_number)(void);
|
||||
void *(*malloc)(int);
|
||||
char * (*mprintf)(const char*,...);
|
||||
int (*open)(const char*,sqlite3**);
|
||||
int (*open16)(const void*,sqlite3**);
|
||||
int (*prepare)(sqlite3*,const char*,int,sqlite3_stmt**,const char**);
|
||||
int (*prepare16)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);
|
||||
void * (*profile)(sqlite3*,void(*)(void*,const char*,sqlite_uint64),void*);
|
||||
void (*progress_handler)(sqlite3*,int,int(*)(void*),void*);
|
||||
void *(*realloc)(void*,int);
|
||||
int (*reset)(sqlite3_stmt*pStmt);
|
||||
void (*result_blob)(sqlite3_context*,const void*,int,void(*)(void*));
|
||||
void (*result_double)(sqlite3_context*,double);
|
||||
void (*result_error)(sqlite3_context*,const char*,int);
|
||||
void (*result_error16)(sqlite3_context*,const void*,int);
|
||||
void (*result_int)(sqlite3_context*,int);
|
||||
void (*result_int64)(sqlite3_context*,sqlite_int64);
|
||||
void (*result_null)(sqlite3_context*);
|
||||
void (*result_text)(sqlite3_context*,const char*,int,void(*)(void*));
|
||||
void (*result_text16)(sqlite3_context*,const void*,int,void(*)(void*));
|
||||
void (*result_text16be)(sqlite3_context*,const void*,int,void(*)(void*));
|
||||
void (*result_text16le)(sqlite3_context*,const void*,int,void(*)(void*));
|
||||
void (*result_value)(sqlite3_context*,sqlite3_value*);
|
||||
void * (*rollback_hook)(sqlite3*,void(*)(void*),void*);
|
||||
int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*,
|
||||
const char*,const char*),void*);
|
||||
void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*));
|
||||
char * (*xsnprintf)(int,char*,const char*,...);
|
||||
int (*step)(sqlite3_stmt*);
|
||||
int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*,
|
||||
char const**,char const**,int*,int*,int*);
|
||||
void (*thread_cleanup)(void);
|
||||
int (*total_changes)(sqlite3*);
|
||||
void * (*trace)(sqlite3*,void(*xTrace)(void*,const char*),void*);
|
||||
int (*transfer_bindings)(sqlite3_stmt*,sqlite3_stmt*);
|
||||
void * (*update_hook)(sqlite3*,void(*)(void*,int ,char const*,char const*,
|
||||
sqlite_int64),void*);
|
||||
void * (*user_data)(sqlite3_context*);
|
||||
const void * (*value_blob)(sqlite3_value*);
|
||||
int (*value_bytes)(sqlite3_value*);
|
||||
int (*value_bytes16)(sqlite3_value*);
|
||||
double (*value_double)(sqlite3_value*);
|
||||
int (*value_int)(sqlite3_value*);
|
||||
sqlite_int64 (*value_int64)(sqlite3_value*);
|
||||
int (*value_numeric_type)(sqlite3_value*);
|
||||
const unsigned char * (*value_text)(sqlite3_value*);
|
||||
const void * (*value_text16)(sqlite3_value*);
|
||||
const void * (*value_text16be)(sqlite3_value*);
|
||||
const void * (*value_text16le)(sqlite3_value*);
|
||||
int (*value_type)(sqlite3_value*);
|
||||
char *(*vmprintf)(const char*,va_list);
|
||||
/* Added ??? */
|
||||
int (*overload_function)(sqlite3*, const char *zFuncName, int nArg);
|
||||
/* Added by 3.3.13 */
|
||||
int (*prepare_v2)(sqlite3*,const char*,int,sqlite3_stmt**,const char**);
|
||||
int (*prepare16_v2)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);
|
||||
int (*clear_bindings)(sqlite3_stmt*);
|
||||
/* Added by 3.4.1 */
|
||||
int (*create_module_v2)(sqlite3*,const char*,const sqlite3_module*,void*,
|
||||
void (*xDestroy)(void *));
|
||||
/* Added by 3.5.0 */
|
||||
int (*bind_zeroblob)(sqlite3_stmt*,int,int);
|
||||
int (*blob_bytes)(sqlite3_blob*);
|
||||
int (*blob_close)(sqlite3_blob*);
|
||||
int (*blob_open)(sqlite3*,const char*,const char*,const char*,sqlite3_int64,
|
||||
int,sqlite3_blob**);
|
||||
int (*blob_read)(sqlite3_blob*,void*,int,int);
|
||||
int (*blob_write)(sqlite3_blob*,const void*,int,int);
|
||||
int (*create_collation_v2)(sqlite3*,const char*,int,void*,
|
||||
int(*)(void*,int,const void*,int,const void*),
|
||||
void(*)(void*));
|
||||
int (*file_control)(sqlite3*,const char*,int,void*);
|
||||
sqlite3_int64 (*memory_highwater)(int);
|
||||
sqlite3_int64 (*memory_used)(void);
|
||||
sqlite3_mutex *(*mutex_alloc)(int);
|
||||
void (*mutex_enter)(sqlite3_mutex*);
|
||||
void (*mutex_free)(sqlite3_mutex*);
|
||||
void (*mutex_leave)(sqlite3_mutex*);
|
||||
int (*mutex_try)(sqlite3_mutex*);
|
||||
int (*open_v2)(const char*,sqlite3**,int,const char*);
|
||||
int (*release_memory)(int);
|
||||
void (*result_error_nomem)(sqlite3_context*);
|
||||
void (*result_error_toobig)(sqlite3_context*);
|
||||
int (*sleep)(int);
|
||||
void (*soft_heap_limit)(int);
|
||||
sqlite3_vfs *(*vfs_find)(const char*);
|
||||
int (*vfs_register)(sqlite3_vfs*,int);
|
||||
int (*vfs_unregister)(sqlite3_vfs*);
|
||||
int (*xthreadsafe)(void);
|
||||
void (*result_zeroblob)(sqlite3_context*,int);
|
||||
void (*result_error_code)(sqlite3_context*,int);
|
||||
int (*test_control)(int, ...);
|
||||
void (*randomness)(int,void*);
|
||||
sqlite3 *(*context_db_handle)(sqlite3_context*);
|
||||
int (*extended_result_codes)(sqlite3*,int);
|
||||
int (*limit)(sqlite3*,int,int);
|
||||
sqlite3_stmt *(*next_stmt)(sqlite3*,sqlite3_stmt*);
|
||||
const char *(*sql)(sqlite3_stmt*);
|
||||
int (*status)(int,int*,int*,int);
|
||||
int (*backup_finish)(sqlite3_backup*);
|
||||
sqlite3_backup *(*backup_init)(sqlite3*,const char*,sqlite3*,const char*);
|
||||
int (*backup_pagecount)(sqlite3_backup*);
|
||||
int (*backup_remaining)(sqlite3_backup*);
|
||||
int (*backup_step)(sqlite3_backup*,int);
|
||||
const char *(*compileoption_get)(int);
|
||||
int (*compileoption_used)(const char*);
|
||||
int (*create_function_v2)(sqlite3*,const char*,int,int,void*,
|
||||
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xFinal)(sqlite3_context*),
|
||||
void(*xDestroy)(void*));
|
||||
int (*db_config)(sqlite3*,int,...);
|
||||
sqlite3_mutex *(*db_mutex)(sqlite3*);
|
||||
int (*db_status)(sqlite3*,int,int*,int*,int);
|
||||
int (*extended_errcode)(sqlite3*);
|
||||
void (*log)(int,const char*,...);
|
||||
sqlite3_int64 (*soft_heap_limit64)(sqlite3_int64);
|
||||
const char *(*sourceid)(void);
|
||||
int (*stmt_status)(sqlite3_stmt*,int,int);
|
||||
int (*strnicmp)(const char*,const char*,int);
|
||||
int (*unlock_notify)(sqlite3*,void(*)(void**,int),void*);
|
||||
int (*wal_autocheckpoint)(sqlite3*,int);
|
||||
int (*wal_checkpoint)(sqlite3*,const char*);
|
||||
void *(*wal_hook)(sqlite3*,int(*)(void*,sqlite3*,const char*,int),void*);
|
||||
int (*blob_reopen)(sqlite3_blob*,sqlite3_int64);
|
||||
int (*vtab_config)(sqlite3*,int op,...);
|
||||
int (*vtab_on_conflict)(sqlite3*);
|
||||
/* Version 3.7.16 and later */
|
||||
int (*close_v2)(sqlite3*);
|
||||
const char *(*db_filename)(sqlite3*,const char*);
|
||||
int (*db_readonly)(sqlite3*,const char*);
|
||||
int (*db_release_memory)(sqlite3*);
|
||||
const char *(*errstr)(int);
|
||||
int (*stmt_busy)(sqlite3_stmt*);
|
||||
int (*stmt_readonly)(sqlite3_stmt*);
|
||||
int (*stricmp)(const char*,const char*);
|
||||
int (*uri_boolean)(const char*,const char*,int);
|
||||
sqlite3_int64 (*uri_int64)(const char*,const char*,sqlite3_int64);
|
||||
const char *(*uri_parameter)(const char*,const char*);
|
||||
char *(*xvsnprintf)(int,char*,const char*,va_list);
|
||||
int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*);
|
||||
/* Version 3.8.7 and later */
|
||||
int (*auto_extension)(void(*)(void));
|
||||
int (*bind_blob64)(sqlite3_stmt*,int,const void*,sqlite3_uint64,
|
||||
void(*)(void*));
|
||||
int (*bind_text64)(sqlite3_stmt*,int,const char*,sqlite3_uint64,
|
||||
void(*)(void*),unsigned char);
|
||||
int (*cancel_auto_extension)(void(*)(void));
|
||||
int (*load_extension)(sqlite3*,const char*,const char*,char**);
|
||||
void *(*malloc64)(sqlite3_uint64);
|
||||
sqlite3_uint64 (*msize)(void*);
|
||||
void *(*realloc64)(void*,sqlite3_uint64);
|
||||
void (*reset_auto_extension)(void);
|
||||
void (*result_blob64)(sqlite3_context*,const void*,sqlite3_uint64,
|
||||
void(*)(void*));
|
||||
void (*result_text64)(sqlite3_context*,const char*,sqlite3_uint64,
|
||||
void(*)(void*), unsigned char);
|
||||
int (*strglob)(const char*,const char*);
|
||||
/* Version 3.8.11 and later */
|
||||
sqlite3_value *(*value_dup)(const sqlite3_value*);
|
||||
void (*value_free)(sqlite3_value*);
|
||||
int (*result_zeroblob64)(sqlite3_context*,sqlite3_uint64);
|
||||
int (*bind_zeroblob64)(sqlite3_stmt*, int, sqlite3_uint64);
|
||||
/* Version 3.9.0 and later */
|
||||
unsigned int (*value_subtype)(sqlite3_value*);
|
||||
void (*result_subtype)(sqlite3_context*,unsigned int);
|
||||
/* Version 3.10.0 and later */
|
||||
int (*status64)(int,sqlite3_int64*,sqlite3_int64*,int);
|
||||
int (*strlike)(const char*,const char*,unsigned int);
|
||||
int (*db_cacheflush)(sqlite3*);
|
||||
/* Version 3.12.0 and later */
|
||||
int (*system_errno)(sqlite3*);
|
||||
/* Version 3.14.0 and later */
|
||||
int (*trace_v2)(sqlite3*,unsigned,int(*)(unsigned,void*,void*,void*),void*);
|
||||
char *(*expanded_sql)(sqlite3_stmt*);
|
||||
/* Version 3.18.0 and later */
|
||||
void (*set_last_insert_rowid)(sqlite3*,sqlite3_int64);
|
||||
/* Version 3.20.0 and later */
|
||||
int (*prepare_v3)(sqlite3*,const char*,int,unsigned int,
|
||||
sqlite3_stmt**,const char**);
|
||||
int (*prepare16_v3)(sqlite3*,const void*,int,unsigned int,
|
||||
sqlite3_stmt**,const void**);
|
||||
int (*bind_pointer)(sqlite3_stmt*,int,void*,const char*,void(*)(void*));
|
||||
void (*result_pointer)(sqlite3_context*,void*,const char*,void(*)(void*));
|
||||
void *(*value_pointer)(sqlite3_value*,const char*);
|
||||
int (*vtab_nochange)(sqlite3_context*);
|
||||
int (*value_nochange)(sqlite3_value*);
|
||||
const char *(*vtab_collation)(sqlite3_index_info*,int);
|
||||
/* Version 3.24.0 and later */
|
||||
int (*keyword_count)(void);
|
||||
int (*keyword_name)(int,const char**,int*);
|
||||
int (*keyword_check)(const char*,int);
|
||||
sqlite3_str *(*str_new)(sqlite3*);
|
||||
char *(*str_finish)(sqlite3_str*);
|
||||
void (*str_appendf)(sqlite3_str*, const char *zFormat, ...);
|
||||
void (*str_vappendf)(sqlite3_str*, const char *zFormat, va_list);
|
||||
void (*str_append)(sqlite3_str*, const char *zIn, int N);
|
||||
void (*str_appendall)(sqlite3_str*, const char *zIn);
|
||||
void (*str_appendchar)(sqlite3_str*, int N, char C);
|
||||
void (*str_reset)(sqlite3_str*);
|
||||
int (*str_errcode)(sqlite3_str*);
|
||||
int (*str_length)(sqlite3_str*);
|
||||
char *(*str_value)(sqlite3_str*);
|
||||
/* Version 3.25.0 and later */
|
||||
int (*create_window_function)(sqlite3*,const char*,int,int,void*,
|
||||
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xFinal)(sqlite3_context*),
|
||||
void (*xValue)(sqlite3_context*),
|
||||
void (*xInv)(sqlite3_context*,int,sqlite3_value**),
|
||||
void(*xDestroy)(void*));
|
||||
/* Version 3.26.0 and later */
|
||||
const char *(*normalized_sql)(sqlite3_stmt*);
|
||||
/* Version 3.28.0 and later */
|
||||
int (*stmt_isexplain)(sqlite3_stmt*);
|
||||
int (*value_frombind)(sqlite3_value*);
|
||||
/* Version 3.30.0 and later */
|
||||
int (*drop_modules)(sqlite3*,const char**);
|
||||
/* Version 3.31.0 and later */
|
||||
sqlite3_int64 (*hard_heap_limit64)(sqlite3_int64);
|
||||
const char *(*uri_key)(const char*,int);
|
||||
const char *(*filename_database)(const char*);
|
||||
const char *(*filename_journal)(const char*);
|
||||
const char *(*filename_wal)(const char*);
|
||||
/* Version 3.32.0 and later */
|
||||
const char *(*create_filename)(const char*,const char*,const char*,
|
||||
int,const char**);
|
||||
void (*free_filename)(const char*);
|
||||
sqlite3_file *(*database_file_object)(const char*);
|
||||
/* Version 3.34.0 and later */
|
||||
int (*txn_state)(sqlite3*,const char*);
|
||||
/* Version 3.36.1 and later */
|
||||
sqlite3_int64 (*changes64)(sqlite3*);
|
||||
sqlite3_int64 (*total_changes64)(sqlite3*);
|
||||
/* Version 3.37.0 and later */
|
||||
int (*autovacuum_pages)(sqlite3*,
|
||||
unsigned int(*)(void*,const char*,unsigned int,unsigned int,unsigned int),
|
||||
void*, void(*)(void*));
|
||||
/* Version 3.38.0 and later */
|
||||
int (*error_offset)(sqlite3*);
|
||||
int (*vtab_rhs_value)(sqlite3_index_info*,int,sqlite3_value**);
|
||||
int (*vtab_distinct)(sqlite3_index_info*);
|
||||
int (*vtab_in)(sqlite3_index_info*,int,int);
|
||||
int (*vtab_in_first)(sqlite3_value*,sqlite3_value**);
|
||||
int (*vtab_in_next)(sqlite3_value*,sqlite3_value**);
|
||||
/* Version 3.39.0 and later */
|
||||
int (*deserialize)(sqlite3*,const char*,unsigned char*,
|
||||
sqlite3_int64,sqlite3_int64,unsigned);
|
||||
unsigned char *(*serialize)(sqlite3*,const char *,sqlite3_int64*,
|
||||
unsigned int);
|
||||
const char *(*db_name)(sqlite3*,int);
|
||||
/* Version 3.40.0 and later */
|
||||
int (*value_encoding)(sqlite3_value*);
|
||||
/* Version 3.41.0 and later */
|
||||
int (*is_interrupted)(sqlite3*);
|
||||
/* Version 3.43.0 and later */
|
||||
int (*stmt_explain)(sqlite3_stmt*,int);
|
||||
/* Version 3.44.0 and later */
|
||||
void *(*get_clientdata)(sqlite3*,const char*);
|
||||
int (*set_clientdata)(sqlite3*, const char*, void*, void(*)(void*));
|
||||
};
|
||||
|
||||
/*
|
||||
** This is the function signature used for all extension entry points. It
|
||||
** is also defined in the file "loadext.c".
|
||||
*/
|
||||
typedef int (*sqlite3_loadext_entry)(
|
||||
sqlite3 *db, /* Handle to the database. */
|
||||
char **pzErrMsg, /* Used to set error string on failure. */
|
||||
const sqlite3_api_routines *pThunk /* Extension API function pointers. */
|
||||
);
|
||||
|
||||
/*
|
||||
** The following macros redefine the API routines so that they are
|
||||
** redirected through the global sqlite3_api structure.
|
||||
**
|
||||
** This header file is also used by the loadext.c source file
|
||||
** (part of the main SQLite library - not an extension) so that
|
||||
** it can get access to the sqlite3_api_routines structure
|
||||
** definition. But the main library does not want to redefine
|
||||
** the API. So the redefinition macros are only valid if the
|
||||
** SQLITE_CORE macros is undefined.
|
||||
*/
|
||||
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
|
||||
#define sqlite3_aggregate_context sqlite3_api->aggregate_context
|
||||
#ifndef SQLITE_OMIT_DEPRECATED
|
||||
#define sqlite3_aggregate_count sqlite3_api->aggregate_count
|
||||
#endif
|
||||
#define sqlite3_bind_blob sqlite3_api->bind_blob
|
||||
#define sqlite3_bind_double sqlite3_api->bind_double
|
||||
#define sqlite3_bind_int sqlite3_api->bind_int
|
||||
#define sqlite3_bind_int64 sqlite3_api->bind_int64
|
||||
#define sqlite3_bind_null sqlite3_api->bind_null
|
||||
#define sqlite3_bind_parameter_count sqlite3_api->bind_parameter_count
|
||||
#define sqlite3_bind_parameter_index sqlite3_api->bind_parameter_index
|
||||
#define sqlite3_bind_parameter_name sqlite3_api->bind_parameter_name
|
||||
#define sqlite3_bind_text sqlite3_api->bind_text
|
||||
#define sqlite3_bind_text16 sqlite3_api->bind_text16
|
||||
#define sqlite3_bind_value sqlite3_api->bind_value
|
||||
#define sqlite3_busy_handler sqlite3_api->busy_handler
|
||||
#define sqlite3_busy_timeout sqlite3_api->busy_timeout
|
||||
#define sqlite3_changes sqlite3_api->changes
|
||||
#define sqlite3_close sqlite3_api->close
|
||||
#define sqlite3_collation_needed sqlite3_api->collation_needed
|
||||
#define sqlite3_collation_needed16 sqlite3_api->collation_needed16
|
||||
#define sqlite3_column_blob sqlite3_api->column_blob
|
||||
#define sqlite3_column_bytes sqlite3_api->column_bytes
|
||||
#define sqlite3_column_bytes16 sqlite3_api->column_bytes16
|
||||
#define sqlite3_column_count sqlite3_api->column_count
|
||||
#define sqlite3_column_database_name sqlite3_api->column_database_name
|
||||
#define sqlite3_column_database_name16 sqlite3_api->column_database_name16
|
||||
#define sqlite3_column_decltype sqlite3_api->column_decltype
|
||||
#define sqlite3_column_decltype16 sqlite3_api->column_decltype16
|
||||
#define sqlite3_column_double sqlite3_api->column_double
|
||||
#define sqlite3_column_int sqlite3_api->column_int
|
||||
#define sqlite3_column_int64 sqlite3_api->column_int64
|
||||
#define sqlite3_column_name sqlite3_api->column_name
|
||||
#define sqlite3_column_name16 sqlite3_api->column_name16
|
||||
#define sqlite3_column_origin_name sqlite3_api->column_origin_name
|
||||
#define sqlite3_column_origin_name16 sqlite3_api->column_origin_name16
|
||||
#define sqlite3_column_table_name sqlite3_api->column_table_name
|
||||
#define sqlite3_column_table_name16 sqlite3_api->column_table_name16
|
||||
#define sqlite3_column_text sqlite3_api->column_text
|
||||
#define sqlite3_column_text16 sqlite3_api->column_text16
|
||||
#define sqlite3_column_type sqlite3_api->column_type
|
||||
#define sqlite3_column_value sqlite3_api->column_value
|
||||
#define sqlite3_commit_hook sqlite3_api->commit_hook
|
||||
#define sqlite3_complete sqlite3_api->complete
|
||||
#define sqlite3_complete16 sqlite3_api->complete16
|
||||
#define sqlite3_create_collation sqlite3_api->create_collation
|
||||
#define sqlite3_create_collation16 sqlite3_api->create_collation16
|
||||
#define sqlite3_create_function sqlite3_api->create_function
|
||||
#define sqlite3_create_function16 sqlite3_api->create_function16
|
||||
#define sqlite3_create_module sqlite3_api->create_module
|
||||
#define sqlite3_create_module_v2 sqlite3_api->create_module_v2
|
||||
#define sqlite3_data_count sqlite3_api->data_count
|
||||
#define sqlite3_db_handle sqlite3_api->db_handle
|
||||
#define sqlite3_declare_vtab sqlite3_api->declare_vtab
|
||||
#define sqlite3_enable_shared_cache sqlite3_api->enable_shared_cache
|
||||
#define sqlite3_errcode sqlite3_api->errcode
|
||||
#define sqlite3_errmsg sqlite3_api->errmsg
|
||||
#define sqlite3_errmsg16 sqlite3_api->errmsg16
|
||||
#define sqlite3_exec sqlite3_api->exec
|
||||
#ifndef SQLITE_OMIT_DEPRECATED
|
||||
#define sqlite3_expired sqlite3_api->expired
|
||||
#endif
|
||||
#define sqlite3_finalize sqlite3_api->finalize
|
||||
#define sqlite3_free sqlite3_api->free
|
||||
#define sqlite3_free_table sqlite3_api->free_table
|
||||
#define sqlite3_get_autocommit sqlite3_api->get_autocommit
|
||||
#define sqlite3_get_auxdata sqlite3_api->get_auxdata
|
||||
#define sqlite3_get_table sqlite3_api->get_table
|
||||
#ifndef SQLITE_OMIT_DEPRECATED
|
||||
#define sqlite3_global_recover sqlite3_api->global_recover
|
||||
#endif
|
||||
#define sqlite3_interrupt sqlite3_api->interruptx
|
||||
#define sqlite3_last_insert_rowid sqlite3_api->last_insert_rowid
|
||||
#define sqlite3_libversion sqlite3_api->libversion
|
||||
#define sqlite3_libversion_number sqlite3_api->libversion_number
|
||||
#define sqlite3_malloc sqlite3_api->malloc
|
||||
#define sqlite3_mprintf sqlite3_api->mprintf
|
||||
#define sqlite3_open sqlite3_api->open
|
||||
#define sqlite3_open16 sqlite3_api->open16
|
||||
#define sqlite3_prepare sqlite3_api->prepare
|
||||
#define sqlite3_prepare16 sqlite3_api->prepare16
|
||||
#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
|
||||
#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
|
||||
#define sqlite3_profile sqlite3_api->profile
|
||||
#define sqlite3_progress_handler sqlite3_api->progress_handler
|
||||
#define sqlite3_realloc sqlite3_api->realloc
|
||||
#define sqlite3_reset sqlite3_api->reset
|
||||
#define sqlite3_result_blob sqlite3_api->result_blob
|
||||
#define sqlite3_result_double sqlite3_api->result_double
|
||||
#define sqlite3_result_error sqlite3_api->result_error
|
||||
#define sqlite3_result_error16 sqlite3_api->result_error16
|
||||
#define sqlite3_result_int sqlite3_api->result_int
|
||||
#define sqlite3_result_int64 sqlite3_api->result_int64
|
||||
#define sqlite3_result_null sqlite3_api->result_null
|
||||
#define sqlite3_result_text sqlite3_api->result_text
|
||||
#define sqlite3_result_text16 sqlite3_api->result_text16
|
||||
#define sqlite3_result_text16be sqlite3_api->result_text16be
|
||||
#define sqlite3_result_text16le sqlite3_api->result_text16le
|
||||
#define sqlite3_result_value sqlite3_api->result_value
|
||||
#define sqlite3_rollback_hook sqlite3_api->rollback_hook
|
||||
#define sqlite3_set_authorizer sqlite3_api->set_authorizer
|
||||
#define sqlite3_set_auxdata sqlite3_api->set_auxdata
|
||||
#define sqlite3_snprintf sqlite3_api->xsnprintf
|
||||
#define sqlite3_step sqlite3_api->step
|
||||
#define sqlite3_table_column_metadata sqlite3_api->table_column_metadata
|
||||
#define sqlite3_thread_cleanup sqlite3_api->thread_cleanup
|
||||
#define sqlite3_total_changes sqlite3_api->total_changes
|
||||
#define sqlite3_trace sqlite3_api->trace
|
||||
#ifndef SQLITE_OMIT_DEPRECATED
|
||||
#define sqlite3_transfer_bindings sqlite3_api->transfer_bindings
|
||||
#endif
|
||||
#define sqlite3_update_hook sqlite3_api->update_hook
|
||||
#define sqlite3_user_data sqlite3_api->user_data
|
||||
#define sqlite3_value_blob sqlite3_api->value_blob
|
||||
#define sqlite3_value_bytes sqlite3_api->value_bytes
|
||||
#define sqlite3_value_bytes16 sqlite3_api->value_bytes16
|
||||
#define sqlite3_value_double sqlite3_api->value_double
|
||||
#define sqlite3_value_int sqlite3_api->value_int
|
||||
#define sqlite3_value_int64 sqlite3_api->value_int64
|
||||
#define sqlite3_value_numeric_type sqlite3_api->value_numeric_type
|
||||
#define sqlite3_value_text sqlite3_api->value_text
|
||||
#define sqlite3_value_text16 sqlite3_api->value_text16
|
||||
#define sqlite3_value_text16be sqlite3_api->value_text16be
|
||||
#define sqlite3_value_text16le sqlite3_api->value_text16le
|
||||
#define sqlite3_value_type sqlite3_api->value_type
|
||||
#define sqlite3_vmprintf sqlite3_api->vmprintf
|
||||
#define sqlite3_vsnprintf sqlite3_api->xvsnprintf
|
||||
#define sqlite3_overload_function sqlite3_api->overload_function
|
||||
#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
|
||||
#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
|
||||
#define sqlite3_clear_bindings sqlite3_api->clear_bindings
|
||||
#define sqlite3_bind_zeroblob sqlite3_api->bind_zeroblob
|
||||
#define sqlite3_blob_bytes sqlite3_api->blob_bytes
|
||||
#define sqlite3_blob_close sqlite3_api->blob_close
|
||||
#define sqlite3_blob_open sqlite3_api->blob_open
|
||||
#define sqlite3_blob_read sqlite3_api->blob_read
|
||||
#define sqlite3_blob_write sqlite3_api->blob_write
|
||||
#define sqlite3_create_collation_v2 sqlite3_api->create_collation_v2
|
||||
#define sqlite3_file_control sqlite3_api->file_control
|
||||
#define sqlite3_memory_highwater sqlite3_api->memory_highwater
|
||||
#define sqlite3_memory_used sqlite3_api->memory_used
|
||||
#define sqlite3_mutex_alloc sqlite3_api->mutex_alloc
|
||||
#define sqlite3_mutex_enter sqlite3_api->mutex_enter
|
||||
#define sqlite3_mutex_free sqlite3_api->mutex_free
|
||||
#define sqlite3_mutex_leave sqlite3_api->mutex_leave
|
||||
#define sqlite3_mutex_try sqlite3_api->mutex_try
|
||||
#define sqlite3_open_v2 sqlite3_api->open_v2
|
||||
#define sqlite3_release_memory sqlite3_api->release_memory
|
||||
#define sqlite3_result_error_nomem sqlite3_api->result_error_nomem
|
||||
#define sqlite3_result_error_toobig sqlite3_api->result_error_toobig
|
||||
#define sqlite3_sleep sqlite3_api->sleep
|
||||
#define sqlite3_soft_heap_limit sqlite3_api->soft_heap_limit
|
||||
#define sqlite3_vfs_find sqlite3_api->vfs_find
|
||||
#define sqlite3_vfs_register sqlite3_api->vfs_register
|
||||
#define sqlite3_vfs_unregister sqlite3_api->vfs_unregister
|
||||
#define sqlite3_threadsafe sqlite3_api->xthreadsafe
|
||||
#define sqlite3_result_zeroblob sqlite3_api->result_zeroblob
|
||||
#define sqlite3_result_error_code sqlite3_api->result_error_code
|
||||
#define sqlite3_test_control sqlite3_api->test_control
|
||||
#define sqlite3_randomness sqlite3_api->randomness
|
||||
#define sqlite3_context_db_handle sqlite3_api->context_db_handle
|
||||
#define sqlite3_extended_result_codes sqlite3_api->extended_result_codes
|
||||
#define sqlite3_limit sqlite3_api->limit
|
||||
#define sqlite3_next_stmt sqlite3_api->next_stmt
|
||||
#define sqlite3_sql sqlite3_api->sql
|
||||
#define sqlite3_status sqlite3_api->status
|
||||
#define sqlite3_backup_finish sqlite3_api->backup_finish
|
||||
#define sqlite3_backup_init sqlite3_api->backup_init
|
||||
#define sqlite3_backup_pagecount sqlite3_api->backup_pagecount
|
||||
#define sqlite3_backup_remaining sqlite3_api->backup_remaining
|
||||
#define sqlite3_backup_step sqlite3_api->backup_step
|
||||
#define sqlite3_compileoption_get sqlite3_api->compileoption_get
|
||||
#define sqlite3_compileoption_used sqlite3_api->compileoption_used
|
||||
#define sqlite3_create_function_v2 sqlite3_api->create_function_v2
|
||||
#define sqlite3_db_config sqlite3_api->db_config
|
||||
#define sqlite3_db_mutex sqlite3_api->db_mutex
|
||||
#define sqlite3_db_status sqlite3_api->db_status
|
||||
#define sqlite3_extended_errcode sqlite3_api->extended_errcode
|
||||
#define sqlite3_log sqlite3_api->log
|
||||
#define sqlite3_soft_heap_limit64 sqlite3_api->soft_heap_limit64
|
||||
#define sqlite3_sourceid sqlite3_api->sourceid
|
||||
#define sqlite3_stmt_status sqlite3_api->stmt_status
|
||||
#define sqlite3_strnicmp sqlite3_api->strnicmp
|
||||
#define sqlite3_unlock_notify sqlite3_api->unlock_notify
|
||||
#define sqlite3_wal_autocheckpoint sqlite3_api->wal_autocheckpoint
|
||||
#define sqlite3_wal_checkpoint sqlite3_api->wal_checkpoint
|
||||
#define sqlite3_wal_hook sqlite3_api->wal_hook
|
||||
#define sqlite3_blob_reopen sqlite3_api->blob_reopen
|
||||
#define sqlite3_vtab_config sqlite3_api->vtab_config
|
||||
#define sqlite3_vtab_on_conflict sqlite3_api->vtab_on_conflict
|
||||
/* Version 3.7.16 and later */
|
||||
#define sqlite3_close_v2 sqlite3_api->close_v2
|
||||
#define sqlite3_db_filename sqlite3_api->db_filename
|
||||
#define sqlite3_db_readonly sqlite3_api->db_readonly
|
||||
#define sqlite3_db_release_memory sqlite3_api->db_release_memory
|
||||
#define sqlite3_errstr sqlite3_api->errstr
|
||||
#define sqlite3_stmt_busy sqlite3_api->stmt_busy
|
||||
#define sqlite3_stmt_readonly sqlite3_api->stmt_readonly
|
||||
#define sqlite3_stricmp sqlite3_api->stricmp
|
||||
#define sqlite3_uri_boolean sqlite3_api->uri_boolean
|
||||
#define sqlite3_uri_int64 sqlite3_api->uri_int64
|
||||
#define sqlite3_uri_parameter sqlite3_api->uri_parameter
|
||||
#define sqlite3_uri_vsnprintf sqlite3_api->xvsnprintf
|
||||
#define sqlite3_wal_checkpoint_v2 sqlite3_api->wal_checkpoint_v2
|
||||
/* Version 3.8.7 and later */
|
||||
#define sqlite3_auto_extension sqlite3_api->auto_extension
|
||||
#define sqlite3_bind_blob64 sqlite3_api->bind_blob64
|
||||
#define sqlite3_bind_text64 sqlite3_api->bind_text64
|
||||
#define sqlite3_cancel_auto_extension sqlite3_api->cancel_auto_extension
|
||||
#define sqlite3_load_extension sqlite3_api->load_extension
|
||||
#define sqlite3_malloc64 sqlite3_api->malloc64
|
||||
#define sqlite3_msize sqlite3_api->msize
|
||||
#define sqlite3_realloc64 sqlite3_api->realloc64
|
||||
#define sqlite3_reset_auto_extension sqlite3_api->reset_auto_extension
|
||||
#define sqlite3_result_blob64 sqlite3_api->result_blob64
|
||||
#define sqlite3_result_text64 sqlite3_api->result_text64
|
||||
#define sqlite3_strglob sqlite3_api->strglob
|
||||
/* Version 3.8.11 and later */
|
||||
#define sqlite3_value_dup sqlite3_api->value_dup
|
||||
#define sqlite3_value_free sqlite3_api->value_free
|
||||
#define sqlite3_result_zeroblob64 sqlite3_api->result_zeroblob64
|
||||
#define sqlite3_bind_zeroblob64 sqlite3_api->bind_zeroblob64
|
||||
/* Version 3.9.0 and later */
|
||||
#define sqlite3_value_subtype sqlite3_api->value_subtype
|
||||
#define sqlite3_result_subtype sqlite3_api->result_subtype
|
||||
/* Version 3.10.0 and later */
|
||||
#define sqlite3_status64 sqlite3_api->status64
|
||||
#define sqlite3_strlike sqlite3_api->strlike
|
||||
#define sqlite3_db_cacheflush sqlite3_api->db_cacheflush
|
||||
/* Version 3.12.0 and later */
|
||||
#define sqlite3_system_errno sqlite3_api->system_errno
|
||||
/* Version 3.14.0 and later */
|
||||
#define sqlite3_trace_v2 sqlite3_api->trace_v2
|
||||
#define sqlite3_expanded_sql sqlite3_api->expanded_sql
|
||||
/* Version 3.18.0 and later */
|
||||
#define sqlite3_set_last_insert_rowid sqlite3_api->set_last_insert_rowid
|
||||
/* Version 3.20.0 and later */
|
||||
#define sqlite3_prepare_v3 sqlite3_api->prepare_v3
|
||||
#define sqlite3_prepare16_v3 sqlite3_api->prepare16_v3
|
||||
#define sqlite3_bind_pointer sqlite3_api->bind_pointer
|
||||
#define sqlite3_result_pointer sqlite3_api->result_pointer
|
||||
#define sqlite3_value_pointer sqlite3_api->value_pointer
|
||||
/* Version 3.22.0 and later */
|
||||
#define sqlite3_vtab_nochange sqlite3_api->vtab_nochange
|
||||
#define sqlite3_value_nochange sqlite3_api->value_nochange
|
||||
#define sqlite3_vtab_collation sqlite3_api->vtab_collation
|
||||
/* Version 3.24.0 and later */
|
||||
#define sqlite3_keyword_count sqlite3_api->keyword_count
|
||||
#define sqlite3_keyword_name sqlite3_api->keyword_name
|
||||
#define sqlite3_keyword_check sqlite3_api->keyword_check
|
||||
#define sqlite3_str_new sqlite3_api->str_new
|
||||
#define sqlite3_str_finish sqlite3_api->str_finish
|
||||
#define sqlite3_str_appendf sqlite3_api->str_appendf
|
||||
#define sqlite3_str_vappendf sqlite3_api->str_vappendf
|
||||
#define sqlite3_str_append sqlite3_api->str_append
|
||||
#define sqlite3_str_appendall sqlite3_api->str_appendall
|
||||
#define sqlite3_str_appendchar sqlite3_api->str_appendchar
|
||||
#define sqlite3_str_reset sqlite3_api->str_reset
|
||||
#define sqlite3_str_errcode sqlite3_api->str_errcode
|
||||
#define sqlite3_str_length sqlite3_api->str_length
|
||||
#define sqlite3_str_value sqlite3_api->str_value
|
||||
/* Version 3.25.0 and later */
|
||||
#define sqlite3_create_window_function sqlite3_api->create_window_function
|
||||
/* Version 3.26.0 and later */
|
||||
#define sqlite3_normalized_sql sqlite3_api->normalized_sql
|
||||
/* Version 3.28.0 and later */
|
||||
#define sqlite3_stmt_isexplain sqlite3_api->stmt_isexplain
|
||||
#define sqlite3_value_frombind sqlite3_api->value_frombind
|
||||
/* Version 3.30.0 and later */
|
||||
#define sqlite3_drop_modules sqlite3_api->drop_modules
|
||||
/* Version 3.31.0 and later */
|
||||
#define sqlite3_hard_heap_limit64 sqlite3_api->hard_heap_limit64
|
||||
#define sqlite3_uri_key sqlite3_api->uri_key
|
||||
#define sqlite3_filename_database sqlite3_api->filename_database
|
||||
#define sqlite3_filename_journal sqlite3_api->filename_journal
|
||||
#define sqlite3_filename_wal sqlite3_api->filename_wal
|
||||
/* Version 3.32.0 and later */
|
||||
#define sqlite3_create_filename sqlite3_api->create_filename
|
||||
#define sqlite3_free_filename sqlite3_api->free_filename
|
||||
#define sqlite3_database_file_object sqlite3_api->database_file_object
|
||||
/* Version 3.34.0 and later */
|
||||
#define sqlite3_txn_state sqlite3_api->txn_state
|
||||
/* Version 3.36.1 and later */
|
||||
#define sqlite3_changes64 sqlite3_api->changes64
|
||||
#define sqlite3_total_changes64 sqlite3_api->total_changes64
|
||||
/* Version 3.37.0 and later */
|
||||
#define sqlite3_autovacuum_pages sqlite3_api->autovacuum_pages
|
||||
/* Version 3.38.0 and later */
|
||||
#define sqlite3_error_offset sqlite3_api->error_offset
|
||||
#define sqlite3_vtab_rhs_value sqlite3_api->vtab_rhs_value
|
||||
#define sqlite3_vtab_distinct sqlite3_api->vtab_distinct
|
||||
#define sqlite3_vtab_in sqlite3_api->vtab_in
|
||||
#define sqlite3_vtab_in_first sqlite3_api->vtab_in_first
|
||||
#define sqlite3_vtab_in_next sqlite3_api->vtab_in_next
|
||||
/* Version 3.39.0 and later */
|
||||
#ifndef SQLITE_OMIT_DESERIALIZE
|
||||
#define sqlite3_deserialize sqlite3_api->deserialize
|
||||
#define sqlite3_serialize sqlite3_api->serialize
|
||||
#endif
|
||||
#define sqlite3_db_name sqlite3_api->db_name
|
||||
/* Version 3.40.0 and later */
|
||||
#define sqlite3_value_encoding sqlite3_api->value_encoding
|
||||
/* Version 3.41.0 and later */
|
||||
#define sqlite3_is_interrupted sqlite3_api->is_interrupted
|
||||
/* Version 3.43.0 and later */
|
||||
#define sqlite3_stmt_explain sqlite3_api->stmt_explain
|
||||
/* Version 3.44.0 and later */
|
||||
#define sqlite3_get_clientdata sqlite3_api->get_clientdata
|
||||
#define sqlite3_set_clientdata sqlite3_api->set_clientdata
|
||||
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
|
||||
|
||||
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
|
||||
/* This case when the file really is being compiled as a loadable
|
||||
** extension */
|
||||
# define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api=0;
|
||||
# define SQLITE_EXTENSION_INIT2(v) sqlite3_api=v;
|
||||
# define SQLITE_EXTENSION_INIT3 \
|
||||
extern const sqlite3_api_routines *sqlite3_api;
|
||||
#else
|
||||
/* This case when the file is being statically linked into the
|
||||
** application */
|
||||
# define SQLITE_EXTENSION_INIT1 /*no-op*/
|
||||
# define SQLITE_EXTENSION_INIT2(v) (void)v; /* unused parameter */
|
||||
# define SQLITE_EXTENSION_INIT3 /*no-op*/
|
||||
#endif
|
||||
|
||||
#endif /* SQLITE3EXT_H */
|
||||
@@ -316,6 +316,118 @@ String compiler_process_text_literal(Request* context, SharedUnit* su, String co
|
||||
return(parsed_content);
|
||||
}
|
||||
|
||||
bool compiler_line_starts_entrypoint(String trimmed, String macro_name)
|
||||
{
|
||||
if(trimmed.rfind(macro_name + "(", 0) == 0)
|
||||
return(true);
|
||||
return(trimmed.rfind(macro_name + ":", 0) == 0 && trimmed.find("(") != String::npos);
|
||||
}
|
||||
|
||||
bool compiler_line_starts_fragmentable_entrypoint(String trimmed, String& kind)
|
||||
{
|
||||
if(compiler_line_starts_entrypoint(trimmed, "ONCE"))
|
||||
{
|
||||
kind = "ONCE";
|
||||
return(true);
|
||||
}
|
||||
if(compiler_line_starts_entrypoint(trimmed, "RENDER"))
|
||||
{
|
||||
kind = "RENDER";
|
||||
return(true);
|
||||
}
|
||||
if(compiler_line_starts_entrypoint(trimmed, "COMPONENT"))
|
||||
{
|
||||
kind = "COMPONENT";
|
||||
return(true);
|
||||
}
|
||||
return(false);
|
||||
}
|
||||
|
||||
String compiler_fragment_capture_prelude(String slot)
|
||||
{
|
||||
return("\nstruct __UceFragmentCapture { Request& context; String slot; __UceFragmentCapture(Request& c, String s) : context(c), slot(s) { ob_start(); } ~__UceFragmentCapture() { String html = ob_get_close(); if(html != \"\") context.call[\"fragments\"][slot] = context.call[\"fragments\"][slot].to_string() + html; } }; __UceFragmentCapture __uce_fragment_capture(context, " + compiler_cpp_string_literal(slot) + ");\n");
|
||||
}
|
||||
|
||||
String compiler_rewrite_fragment_attributes(String content)
|
||||
{
|
||||
StringList lines = split(content, "\n");
|
||||
String result;
|
||||
for(u32 i = 0; i < lines.size(); i++)
|
||||
{
|
||||
String line = lines[i];
|
||||
String kind;
|
||||
if(!compiler_line_starts_fragmentable_entrypoint(trim(line), kind))
|
||||
{
|
||||
result += line;
|
||||
if(i + 1 < lines.size())
|
||||
result += "\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
String slot = (kind == "ONCE" ? "once" : "");
|
||||
StringList pending;
|
||||
bool has_fragment_attr = false;
|
||||
u32 j = i + 1;
|
||||
while(j < lines.size())
|
||||
{
|
||||
String attr_line = lines[j];
|
||||
String attr_trimmed = trim(attr_line);
|
||||
if(attr_trimmed.rfind("@fragment", 0) == 0 && (attr_trimmed.length() == 9 || isspace((unsigned char)attr_trimmed[9])))
|
||||
{
|
||||
slot = trim(attr_trimmed.substr(9));
|
||||
has_fragment_attr = true;
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
bool should_capture = (slot != "") && (kind == "ONCE" || has_fragment_attr);
|
||||
if(!should_capture)
|
||||
{
|
||||
result += line;
|
||||
if(j < lines.size())
|
||||
result += "\n";
|
||||
i = j - 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
auto declaration_brace_pos = line.find("{");
|
||||
if(declaration_brace_pos != String::npos)
|
||||
{
|
||||
result += line.substr(0, declaration_brace_pos + 1) + compiler_fragment_capture_prelude(slot) + line.substr(declaration_brace_pos + 1);
|
||||
if(j < lines.size())
|
||||
result += "\n";
|
||||
i = j - 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
result += line;
|
||||
if(j < lines.size())
|
||||
result += "\n";
|
||||
|
||||
while(j < lines.size())
|
||||
{
|
||||
String body_line = lines[j];
|
||||
auto brace_pos = body_line.find("{");
|
||||
if(brace_pos == String::npos)
|
||||
{
|
||||
result += body_line;
|
||||
if(j + 1 < lines.size())
|
||||
result += "\n";
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
result += body_line.substr(0, brace_pos + 1) + compiler_fragment_capture_prelude(slot) + body_line.substr(brace_pos + 1);
|
||||
if(j + 1 < lines.size())
|
||||
result += "\n";
|
||||
i = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
bool compiler_rewrite_named_entrypoint_line(String& line, String macro_prefix, String symbol_prefix)
|
||||
{
|
||||
u32 indent_length = 0;
|
||||
@@ -484,6 +596,7 @@ String compiler_preprocess_shared_unit_char_wise(Request* context, SharedUnit* s
|
||||
|
||||
String compiler_preprocess_source(Request* context, SharedUnit* su, String content)
|
||||
{
|
||||
content = compiler_rewrite_fragment_attributes(content);
|
||||
content = compiler_rewrite_named_render_syntax(content);
|
||||
return(compiler_preprocess_shared_unit_char_wise(context, su, content));
|
||||
}
|
||||
|
||||
+109
-12
@@ -3,6 +3,7 @@
|
||||
#include "hash.h"
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <cctype>
|
||||
#include <filesystem>
|
||||
#include <sys/file.h>
|
||||
#include <unistd.h>
|
||||
@@ -17,7 +18,7 @@ const char* UCE_CLI_SYMBOL = "__uce_cli";
|
||||
const char* UCE_SERVE_HTTP_SYMBOL = "__uce_serve_http";
|
||||
const char* UCE_ONCE_SYMBOL = "__uce_once";
|
||||
const char* UCE_INIT_SYMBOL = "__uce_init";
|
||||
const u64 UCE_UNIT_ABI_VERSION = 1;
|
||||
const u64 UCE_UNIT_ABI_VERSION = 2;
|
||||
|
||||
struct SharedUnitFilesystemState
|
||||
{
|
||||
@@ -282,9 +283,19 @@ auto compiler_with_registry_lock(Request* context, TCallback callback) -> declty
|
||||
{
|
||||
auto lock_file_name = compiler_registry_lock_file_name(context);
|
||||
int fdlock = compiler_open_lock_file(lock_file_name, "compiler-registry");
|
||||
auto result = callback();
|
||||
compiler_close_lock_file(fdlock);
|
||||
return(result);
|
||||
if(fdlock == -1)
|
||||
throw std::runtime_error("could not open compiler registry lock: " + lock_file_name);
|
||||
try
|
||||
{
|
||||
auto result = callback();
|
||||
compiler_close_lock_file(fdlock);
|
||||
return(result);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
compiler_close_lock_file(fdlock);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
bool compiler_has_known_unit_cached(Request* context, String file_name)
|
||||
@@ -609,6 +620,20 @@ String preprocess_shared_unit(Request* context, SharedUnit* su)
|
||||
return(compiler_preprocess_source(context, su, content));
|
||||
}
|
||||
|
||||
String compiler_generated_cpp_path(Request* context, String source_file)
|
||||
{
|
||||
if(!context || !context->server || source_file == "")
|
||||
return("");
|
||||
return(context->server->config["BIN_DIRECTORY"] + dirname(source_file) + "/" + basename(source_file) + ".cpp");
|
||||
}
|
||||
|
||||
String compiler_generated_cpp_path(SharedUnit* su)
|
||||
{
|
||||
if(!su)
|
||||
return("");
|
||||
return(su->pre_path + "/" + su->pre_file_name);
|
||||
}
|
||||
|
||||
void setup_unit_paths(Request* context, SharedUnit* su, String file_name)
|
||||
{
|
||||
su->file_name = file_name;
|
||||
@@ -722,6 +747,72 @@ void load_shared_unit(Request* context, SharedUnit* su)
|
||||
return(result);
|
||||
}*/
|
||||
|
||||
s64 compiler_first_error_line_for_path(String messages, String path)
|
||||
{
|
||||
if(path == "")
|
||||
return(-1);
|
||||
String needle = path + ":";
|
||||
auto pos = messages.find(needle);
|
||||
if(pos == String::npos)
|
||||
return(-1);
|
||||
pos += needle.length();
|
||||
String digits;
|
||||
while(pos < messages.length() && isdigit((unsigned char)messages[pos]))
|
||||
{
|
||||
digits.append(1, messages[pos]);
|
||||
pos += 1;
|
||||
}
|
||||
if(digits == "")
|
||||
return(-1);
|
||||
return(int_val(digits));
|
||||
}
|
||||
|
||||
String compiler_source_excerpt(String file_name, s64 line_number, u64 radius = 3)
|
||||
{
|
||||
if(file_name == "" || line_number <= 0 || !file_exists(file_name))
|
||||
return("");
|
||||
auto lines = split(file_get_contents(file_name), "\n");
|
||||
if(lines.size() == 0)
|
||||
return("");
|
||||
s64 start = line_number - (s64)radius;
|
||||
if(start < 1)
|
||||
start = 1;
|
||||
s64 end = line_number + (s64)radius;
|
||||
if(end > (s64)lines.size())
|
||||
end = lines.size();
|
||||
String result;
|
||||
for(s64 i = start; i <= end; i++)
|
||||
{
|
||||
String marker = (i == line_number ? "> " : " ");
|
||||
result += marker + std::to_string((u64)i) + " | " + lines[i - 1] + "\n";
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
String compiler_format_compile_failure(SharedUnit* su, String raw_messages)
|
||||
{
|
||||
String generated_file = compiler_generated_cpp_path(su);
|
||||
String result = "UCE compile error\n";
|
||||
result += "Source: " + su->file_name + "\n";
|
||||
result += "Generated C++: " + generated_file + "\n";
|
||||
result += "Compile output: " + su->compile_output_file_name + "\n";
|
||||
|
||||
s64 source_line = compiler_first_error_line_for_path(raw_messages, su->file_name);
|
||||
String excerpt = compiler_source_excerpt(su->file_name, source_line);
|
||||
if(excerpt != "")
|
||||
result += "\nSource excerpt:\n" + excerpt;
|
||||
else
|
||||
{
|
||||
s64 generated_line = compiler_first_error_line_for_path(raw_messages, generated_file);
|
||||
String generated_excerpt = compiler_source_excerpt(generated_file, generated_line);
|
||||
if(generated_excerpt != "")
|
||||
result += "\nGenerated C++ excerpt:\n" + generated_excerpt;
|
||||
}
|
||||
|
||||
result += "\nCompiler output:\n" + trim(raw_messages) + "\n";
|
||||
return(result);
|
||||
}
|
||||
|
||||
void compile_shared_unit(Request* context, SharedUnit* su)
|
||||
{
|
||||
f64 comp_start = time_precise();
|
||||
@@ -737,11 +828,10 @@ void compile_shared_unit(Request* context, SharedUnit* su)
|
||||
|
||||
shell_exec("mkdir -p " + shell_escape(su->pre_path));
|
||||
file_put_contents(su->pre_path + "/" + su->pre_file_name, preprocess_shared_unit(context, su));
|
||||
//file_put_contents(su->setup_file_name, compile_setup_file(context, su));
|
||||
file_put_contents(su->api_file_name, join(su->api_declarations, "\n"));
|
||||
|
||||
if(!su->opt_so_optional)
|
||||
su->compiler_messages = trim(shell_exec(context->server->config["COMPILE_SCRIPT"]+" "+
|
||||
su->compiler_messages = trim(shell_exec(shell_escape(context->server->config["COMPILE_SCRIPT"])+" "+
|
||||
shell_escape(su->src_path)+" "+
|
||||
shell_escape(su->bin_path)+" "+
|
||||
shell_escape(su->file_name)+" "+
|
||||
@@ -751,9 +841,10 @@ void compile_shared_unit(Request* context, SharedUnit* su)
|
||||
|
||||
if(su->compiler_messages.length() > 0)
|
||||
{
|
||||
file_put_contents(su->compile_output_file_name, su->compiler_messages + "\n");
|
||||
compiler_record_compile_result(su, time_precise() - comp_start, false, "compile_error", su->compiler_messages);
|
||||
printf("%s \n", su->compiler_messages.c_str());
|
||||
String raw_messages = su->compiler_messages;
|
||||
file_put_contents(su->compile_output_file_name, raw_messages + "\n");
|
||||
compiler_record_compile_result(su, time_precise() - comp_start, false, "compile_error", raw_messages);
|
||||
printf("%s \n", compiler_format_compile_failure(su, raw_messages).c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -898,11 +989,17 @@ SharedUnit* compiler_load_shared_unit(Request* context, String file_name, String
|
||||
}
|
||||
else if(su->compiler_messages.length() > 0)
|
||||
{
|
||||
printf("%s\n", su->compiler_messages.c_str());
|
||||
String display_messages = su->compiler_messages;
|
||||
if(su->compile_status == "compile_error")
|
||||
display_messages = compiler_format_compile_failure(su, su->compiler_messages);
|
||||
printf("%s\n", display_messages.c_str());
|
||||
if(compiler_can_write_response(context) && context->stats.invoke_count == 1)
|
||||
context->header["Content-Type"] = "text/plain";
|
||||
{
|
||||
context->set_status(500, "UCE Unit Compile Error");
|
||||
context->header["Content-Type"] = "text/plain; charset=utf-8";
|
||||
}
|
||||
if(compiler_can_write_response(context))
|
||||
print(su->compiler_messages);
|
||||
print(display_messages);
|
||||
return(0);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#define EXPORT extern "C"
|
||||
|
||||
String preprocess_shared_unit(Request* context, SharedUnit* su);
|
||||
String compiler_generated_cpp_path(Request* context, String source_file);
|
||||
String compiler_generated_cpp_path(SharedUnit* su);
|
||||
void setup_unit_paths(Request* context, SharedUnit* su, String file_name);
|
||||
void load_shared_unit(Request* context, SharedUnit* su);
|
||||
void compile_shared_unit(Request* context, SharedUnit* su);
|
||||
|
||||
+7
-2
@@ -140,7 +140,7 @@ u64 dtree_clamp_to_u64_range(long double value)
|
||||
|
||||
}
|
||||
|
||||
void DTree::each(std::function <void (DTree t, String key)> f)
|
||||
void DTree::each(std::function <void (const DTree& t, String key)> f)
|
||||
{
|
||||
const DTree& target = deref();
|
||||
switch(target.type)
|
||||
@@ -695,7 +695,7 @@ void DTree::operator = (void* v) { set(v); }
|
||||
void DTree::operator = (DTree v) { set(v); }
|
||||
void DTree::operator = (StringMap v) { set(v); }
|
||||
|
||||
void DTree::push(DTree& child)
|
||||
void DTree::push(const DTree& child)
|
||||
{
|
||||
DTree* target = reference_target();
|
||||
if(target)
|
||||
@@ -733,6 +733,11 @@ DTree DTree::pop()
|
||||
if(target)
|
||||
return(target->pop());
|
||||
set_type('M');
|
||||
if(_map.empty())
|
||||
{
|
||||
_array_index = 0;
|
||||
return(DTree());
|
||||
}
|
||||
auto last = _map.rbegin();
|
||||
DTree result = last->second;
|
||||
_map.erase(last->first);
|
||||
|
||||
+2
-2
@@ -19,7 +19,7 @@ struct DTree {
|
||||
void* _ptr;
|
||||
std::map<String, DTree> _map;
|
||||
|
||||
void each(std::function <void (DTree t, String key)> f);
|
||||
void each(std::function <void (const DTree& t, String key)> f);
|
||||
bool is_array();
|
||||
bool is_list() const;
|
||||
String to_string();
|
||||
@@ -56,7 +56,7 @@ struct DTree {
|
||||
void operator = (DTree v);
|
||||
void operator = (StringMap v);
|
||||
|
||||
void push(DTree& child);
|
||||
void push(const DTree& child);
|
||||
DTree pop();
|
||||
void remove(String s);
|
||||
void clear();
|
||||
|
||||
+192
-61
@@ -4,6 +4,7 @@
|
||||
#include <pcre2.h>
|
||||
#include <cctype>
|
||||
#include <stdexcept>
|
||||
#include <algorithm>
|
||||
|
||||
String var_dump(StringMap map, String prefix, String postfix)
|
||||
{
|
||||
@@ -59,6 +60,145 @@ String to_upper(String s)
|
||||
return(result);
|
||||
}
|
||||
|
||||
StringList list_unique(StringList items)
|
||||
{
|
||||
StringList result;
|
||||
std::set<String> seen;
|
||||
for(auto item : items)
|
||||
{
|
||||
if(seen.find(item) != seen.end())
|
||||
continue;
|
||||
seen.insert(item);
|
||||
result.push_back(item);
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
StringList list_sort(StringList items)
|
||||
{
|
||||
std::sort(items.begin(), items.end());
|
||||
return(items);
|
||||
}
|
||||
|
||||
bool list_some(StringList items, std::function<bool (String)> f)
|
||||
{
|
||||
for(auto item : items)
|
||||
{
|
||||
if(f(item))
|
||||
return(true);
|
||||
}
|
||||
return(false);
|
||||
}
|
||||
|
||||
bool list_every(StringList items, std::function<bool (String)> f)
|
||||
{
|
||||
for(auto item : items)
|
||||
{
|
||||
if(!f(item))
|
||||
return(false);
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
|
||||
String list_find(StringList items, std::function<bool (String)> f, String fallback)
|
||||
{
|
||||
for(auto item : items)
|
||||
{
|
||||
if(f(item))
|
||||
return(item);
|
||||
}
|
||||
return(fallback);
|
||||
}
|
||||
|
||||
StringList dtree_keys(DTree tree)
|
||||
{
|
||||
StringList result;
|
||||
tree.each([&](const DTree& item, String key) {
|
||||
if(key != "")
|
||||
result.push_back(key);
|
||||
});
|
||||
return(result);
|
||||
}
|
||||
|
||||
DTree dtree_values(DTree tree)
|
||||
{
|
||||
DTree result;
|
||||
result.set_array();
|
||||
tree.each([&](const DTree& item, String key) {
|
||||
result.push(item);
|
||||
});
|
||||
return(result);
|
||||
}
|
||||
|
||||
DTree dtree_pick(DTree tree, StringList keys)
|
||||
{
|
||||
DTree result;
|
||||
for(auto key : keys)
|
||||
{
|
||||
DTree* item = tree.key(key);
|
||||
if(item)
|
||||
result[key] = *item;
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
DTree dtree_omit(DTree tree, StringList keys)
|
||||
{
|
||||
DTree result;
|
||||
std::set<String> omitted(keys.begin(), keys.end());
|
||||
tree.each([&](const DTree& item, String key) {
|
||||
if(key != "" && omitted.find(key) == omitted.end())
|
||||
result[key] = item;
|
||||
});
|
||||
return(result);
|
||||
}
|
||||
|
||||
DTree dtree_map(DTree tree, std::function<DTree (const DTree&, String)> f)
|
||||
{
|
||||
DTree result;
|
||||
bool input_is_list = tree.is_list();
|
||||
if(input_is_list)
|
||||
result.set_array();
|
||||
tree.each([&](const DTree& item, String key) {
|
||||
DTree mapped = f(item, key);
|
||||
if(key != "" && !input_is_list)
|
||||
result[key] = mapped;
|
||||
else
|
||||
result.push(mapped);
|
||||
});
|
||||
return(result);
|
||||
}
|
||||
|
||||
DTree dtree_filter(DTree tree, std::function<bool (const DTree&, String)> f)
|
||||
{
|
||||
DTree result;
|
||||
bool input_is_list = tree.is_list();
|
||||
if(input_is_list)
|
||||
result.set_array();
|
||||
tree.each([&](const DTree& item, String key) {
|
||||
if(!f(item, key))
|
||||
return;
|
||||
if(key != "" && !input_is_list)
|
||||
result[key] = item;
|
||||
else
|
||||
result.push(item);
|
||||
});
|
||||
return(result);
|
||||
}
|
||||
|
||||
DTree dtree_group_by(DTree tree, std::function<String (const DTree&, String)> f)
|
||||
{
|
||||
DTree result;
|
||||
tree.each([&](const DTree& item, String key) {
|
||||
String group = f(item, key);
|
||||
DTree* group_items = result.get_or_create(group);
|
||||
if(!group_items->is_array())
|
||||
group_items->set_array();
|
||||
group_items->push(item);
|
||||
});
|
||||
return(result);
|
||||
}
|
||||
|
||||
String substr(String s, s64 start_pos)
|
||||
{
|
||||
s64 len = s.length();
|
||||
@@ -502,11 +642,11 @@ String trim(String raw)
|
||||
s64 len = raw.length();
|
||||
s64 start_pos = 0;
|
||||
s64 end_pos = len - 1;
|
||||
if(len == 0 || (len == 1 && isspace(raw[0])))
|
||||
if(len == 0 || (len == 1 && isspace((unsigned char)raw[0])))
|
||||
return("");
|
||||
while(start_pos < len && isspace(raw[start_pos]))
|
||||
while(start_pos < len && isspace((unsigned char)raw[start_pos]))
|
||||
start_pos++;
|
||||
while(end_pos >= 0 && isspace(raw[end_pos]))
|
||||
while(end_pos >= 0 && isspace((unsigned char)raw[end_pos]))
|
||||
end_pos--;
|
||||
if(end_pos < start_pos)
|
||||
return("");
|
||||
@@ -519,7 +659,7 @@ StringList split_space(String str)
|
||||
String current_token = "";
|
||||
for(auto c : str)
|
||||
{
|
||||
if(isspace(c))
|
||||
if(isspace((unsigned char)c))
|
||||
{
|
||||
if(current_token != "")
|
||||
{
|
||||
@@ -540,6 +680,11 @@ StringList split_space(String str)
|
||||
StringList split(String str, String delim)
|
||||
{
|
||||
StringList result;
|
||||
if(delim == "")
|
||||
{
|
||||
result.push_back(str);
|
||||
return(result);
|
||||
}
|
||||
int start = 0;
|
||||
int end = str.find(delim);
|
||||
while (end != String::npos)
|
||||
@@ -562,14 +707,16 @@ StringMap split_kv(String s, char separator, bool trim_whitespace, bool uppercas
|
||||
u8 mode = 0;
|
||||
k = "";
|
||||
v = "";
|
||||
if(s[0] != '#') for(auto c : s)
|
||||
if(s == "" || s[0] == '#')
|
||||
continue;
|
||||
for(auto c : s)
|
||||
{
|
||||
if(mode == 0)
|
||||
{
|
||||
if(c == separator)
|
||||
mode = 1;
|
||||
else
|
||||
k.append(1, uppercase_keys ? toupper(c) : c);
|
||||
k.append(1, uppercase_keys ? toupper((unsigned char)c) : c);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -590,62 +737,43 @@ StringMap split_kv(String s, char separator, bool trim_whitespace, bool uppercas
|
||||
StringMap split_http_headers(String s)
|
||||
{
|
||||
StringMap result;
|
||||
String k;
|
||||
String v;
|
||||
String query_string;
|
||||
String base_uri;
|
||||
for(auto s : split(s, "\n"))
|
||||
StringList lines = split(s, "\n");
|
||||
if(lines.size() == 0)
|
||||
return(result);
|
||||
|
||||
u64 header_start = 0;
|
||||
while(header_start < lines.size() && trim(lines[header_start]) == "")
|
||||
header_start++;
|
||||
|
||||
if(header_start < lines.size() && lines[header_start].find(':') == String::npos)
|
||||
{
|
||||
u8 mode = 0;
|
||||
k = "";
|
||||
v = "";
|
||||
for(auto c : s)
|
||||
{
|
||||
if(mode == 0)
|
||||
{
|
||||
if(c == ':')
|
||||
mode = 1;
|
||||
else
|
||||
k.append(1, c);
|
||||
}
|
||||
else
|
||||
{
|
||||
v.append(1, c);
|
||||
}
|
||||
}
|
||||
if(k != "")
|
||||
{
|
||||
k = trim(k);
|
||||
v = trim(v);
|
||||
if(v == "")
|
||||
{
|
||||
if(result["REQUEST_METHOD"] == "")
|
||||
{
|
||||
result["REQUEST_METHOD"] = nibble(k, " ");
|
||||
result["REQUEST_URI"] = nibble(k, " ");
|
||||
String query_string = result["REQUEST_URI"];
|
||||
String base_uri = nibble(query_string, "?");
|
||||
result["SERVER_PROTOCOL"] = k;
|
||||
result["SCRIPT_NAME"] = base_uri;
|
||||
result["DOCUMENT_URI"] = base_uri;
|
||||
result["QUERY_STRING"] = query_string;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(k != "")
|
||||
result["_"] = k;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
String header_key = to_upper(k);
|
||||
std::replace(header_key.begin(), header_key.end(), '-', '_');
|
||||
result["HTTP_"+header_key] = v;
|
||||
if(header_key == "CONTENT_TYPE" || header_key == "CONTENT_LENGTH")
|
||||
result[header_key] = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
String request_line = trim(lines[header_start]);
|
||||
result["REQUEST_METHOD"] = nibble(request_line, " ");
|
||||
result["REQUEST_URI"] = nibble(request_line, " ");
|
||||
String query_string = result["REQUEST_URI"];
|
||||
String base_uri = nibble(query_string, "?");
|
||||
result["SERVER_PROTOCOL"] = trim(request_line);
|
||||
result["SCRIPT_NAME"] = base_uri;
|
||||
result["DOCUMENT_URI"] = base_uri;
|
||||
result["QUERY_STRING"] = query_string;
|
||||
header_start++;
|
||||
}
|
||||
|
||||
for(u64 i = header_start; i < lines.size(); i++)
|
||||
{
|
||||
String line = lines[i];
|
||||
size_t colon = line.find(':');
|
||||
if(colon == String::npos)
|
||||
continue;
|
||||
String header_key = to_upper(trim(line.substr(0, colon)));
|
||||
String value = trim(line.substr(colon + 1));
|
||||
if(header_key == "")
|
||||
continue;
|
||||
std::replace(header_key.begin(), header_key.end(), '-', '_');
|
||||
result["HTTP_" + header_key] = value;
|
||||
if(header_key == "CONTENT_TYPE" || header_key == "CONTENT_LENGTH")
|
||||
result[header_key] = value;
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
@@ -814,6 +942,9 @@ String html_escape(String s)
|
||||
case('"'):
|
||||
result.append(""");
|
||||
break;
|
||||
case('\''):
|
||||
result.append("'");
|
||||
break;
|
||||
default:
|
||||
result.append(1, c);
|
||||
break;
|
||||
|
||||
+25
-2
@@ -65,8 +65,8 @@ String to_hex(ITYPE w, size_t hex_len = sizeof(ITYPE)<<1)
|
||||
return(rc);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::vector<T> filter(std::vector<T> items, std::function<bool (T)> f)
|
||||
template<typename T, typename F>
|
||||
std::vector<T> filter(std::vector<T> items, F f)
|
||||
{
|
||||
std::vector<T> new_items;
|
||||
for(auto item : items)
|
||||
@@ -77,6 +77,29 @@ std::vector<T> filter(std::vector<T> items, std::function<bool (T)> f)
|
||||
return(new_items);
|
||||
}
|
||||
|
||||
template<typename T, typename F>
|
||||
auto map(std::vector<T> items, F f)
|
||||
{
|
||||
using ResultType = decltype(f(items[0]));
|
||||
std::vector<ResultType> new_items;
|
||||
for(auto item : items)
|
||||
new_items.push_back(f(item));
|
||||
return(new_items);
|
||||
}
|
||||
|
||||
StringList list_unique(StringList items);
|
||||
StringList list_sort(StringList items);
|
||||
bool list_some(StringList items, std::function<bool (String)> f);
|
||||
bool list_every(StringList items, std::function<bool (String)> f);
|
||||
String list_find(StringList items, std::function<bool (String)> f, String fallback = "");
|
||||
StringList dtree_keys(DTree tree);
|
||||
DTree dtree_values(DTree tree);
|
||||
DTree dtree_pick(DTree tree, StringList keys);
|
||||
DTree dtree_omit(DTree tree, StringList keys);
|
||||
DTree dtree_map(DTree tree, std::function<DTree (const DTree&, String)> f);
|
||||
DTree dtree_filter(DTree tree, std::function<bool (const DTree&, String)> f);
|
||||
DTree dtree_group_by(DTree tree, std::function<String (const DTree&, String)> f);
|
||||
|
||||
template <class ...Args>
|
||||
String first(Args... args)
|
||||
{
|
||||
|
||||
@@ -37,7 +37,8 @@ bool MySQL::connect(String host, String username, String password)
|
||||
*/
|
||||
//switch_to_arena(context->mem);
|
||||
statement_info = String("connected");
|
||||
context->resources.mysql_connections.push_back(connection);
|
||||
if(context)
|
||||
context->resources.mysql_connections.push_back(this);
|
||||
return(true);
|
||||
}
|
||||
|
||||
@@ -181,8 +182,16 @@ DTree MySQL::get_pending_result()
|
||||
return(result_data);
|
||||
}
|
||||
|
||||
static bool mysql_has_unquoted_positional_placeholder(String query);
|
||||
|
||||
DTree MySQL::query(String q)
|
||||
{
|
||||
if(mysql_has_unquoted_positional_placeholder(q))
|
||||
{
|
||||
_preload_next_error_code = CR_UNKNOWN_ERROR;
|
||||
statement_info = "mysql positional ? placeholders are not supported; use named :name placeholders";
|
||||
return(DTree());
|
||||
}
|
||||
_preload_next_error_code = mysql_query((MYSQL*)connection, q.c_str());
|
||||
DTree result;
|
||||
if(_preload_next_error_code == 0)
|
||||
@@ -190,8 +199,50 @@ DTree MySQL::query(String q)
|
||||
return(result);
|
||||
}
|
||||
|
||||
static bool mysql_has_unquoted_positional_placeholder(String query)
|
||||
{
|
||||
bool quoted = false;
|
||||
char quote = 0;
|
||||
bool escaped = false;
|
||||
for(u32 i = 0; i < query.length(); i++)
|
||||
{
|
||||
char c = query[i];
|
||||
if(quoted)
|
||||
{
|
||||
if(escaped)
|
||||
{
|
||||
escaped = false;
|
||||
continue;
|
||||
}
|
||||
if(c == '\\')
|
||||
{
|
||||
escaped = true;
|
||||
continue;
|
||||
}
|
||||
if(c == quote)
|
||||
quoted = false;
|
||||
continue;
|
||||
}
|
||||
if(c == '\'' || c == '"')
|
||||
{
|
||||
quoted = true;
|
||||
quote = c;
|
||||
continue;
|
||||
}
|
||||
if(c == '?')
|
||||
return(true);
|
||||
}
|
||||
return(false);
|
||||
}
|
||||
|
||||
DTree MySQL::query(String q, StringMap params)
|
||||
{
|
||||
if(mysql_has_unquoted_positional_placeholder(q))
|
||||
{
|
||||
_preload_next_error_code = CR_UNKNOWN_ERROR;
|
||||
statement_info = "mysql positional ? placeholders are not supported; use named :name placeholders";
|
||||
return(DTree());
|
||||
}
|
||||
return(query(
|
||||
parse_query_parameters(q, params).c_str()
|
||||
));
|
||||
@@ -255,12 +306,24 @@ void MySQL::disconnect()
|
||||
if(connection)
|
||||
mysql_close((MYSQL*)connection);
|
||||
connection = NULL;
|
||||
if(context)
|
||||
{
|
||||
auto& connections = context->resources.mysql_connections;
|
||||
connections.erase(std::remove(connections.begin(), connections.end(), this), connections.end());
|
||||
}
|
||||
}
|
||||
|
||||
String MySQL::error()
|
||||
{
|
||||
if(_preload_next_error_code)
|
||||
{
|
||||
if(statement_info != "")
|
||||
{
|
||||
String result = statement_info;
|
||||
statement_info = "";
|
||||
_preload_next_error_code = 0;
|
||||
return(result);
|
||||
}
|
||||
String p = "Unknown error";
|
||||
switch(_preload_next_error_code)
|
||||
{
|
||||
@@ -298,8 +361,16 @@ String MySQL::error()
|
||||
void cleanup_mysql_connections()
|
||||
{
|
||||
//switch_to_system_alloc();
|
||||
for(auto& con : context->resources.mysql_connections)
|
||||
mysql_close((MYSQL*)con);
|
||||
context->resources.mysql_connections.clear();
|
||||
if(!context)
|
||||
return;
|
||||
while(!context->resources.mysql_connections.empty())
|
||||
{
|
||||
MySQL* db = (MySQL*)context->resources.mysql_connections.back();
|
||||
context->resources.mysql_connections.pop_back();
|
||||
bool should_delete = db->request_cleanup_delete;
|
||||
db->disconnect();
|
||||
if(should_delete)
|
||||
delete db;
|
||||
}
|
||||
//switch_to_arena(context->mem);
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ struct MySQL {
|
||||
u32 row_count = 0;
|
||||
u64 insert_id = 0;
|
||||
String statement_info = ""; //
|
||||
bool request_cleanup_delete = false;
|
||||
|
||||
std::vector<MySQLFieldInfo> field_info;
|
||||
|
||||
@@ -37,6 +38,7 @@ struct MySQL {
|
||||
MySQL* mysql_connect(String host = "localhost", String username = "root", String password = "")
|
||||
{
|
||||
MySQL* m = new MySQL();
|
||||
m->request_cleanup_delete = true;
|
||||
m->connect(host, username, password);
|
||||
return(m);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,353 @@
|
||||
#include "../3rdparty/sqlite/sqlite3.h"
|
||||
#include "sqlite-connector.h"
|
||||
|
||||
namespace {
|
||||
|
||||
std::map<String, SQLite*> sqlite_worker_connection_cache;
|
||||
|
||||
void sqlite_register_request_connection(SQLite* db)
|
||||
{
|
||||
if(!context || !db)
|
||||
return;
|
||||
auto& connections = context->resources.sqlite_connections;
|
||||
if(std::find(connections.begin(), connections.end(), db) == connections.end())
|
||||
connections.push_back(db);
|
||||
}
|
||||
|
||||
void sqlite_unregister_request_connection(SQLite* db)
|
||||
{
|
||||
if(!context || !db)
|
||||
return;
|
||||
auto& connections = context->resources.sqlite_connections;
|
||||
connections.erase(std::remove(connections.begin(), connections.end(), db), connections.end());
|
||||
}
|
||||
|
||||
void sqlite_forget_worker_cached_connection(SQLite* db)
|
||||
{
|
||||
if(!db || db->path == "")
|
||||
return;
|
||||
auto found = sqlite_worker_connection_cache.find(db->path);
|
||||
if(found != sqlite_worker_connection_cache.end() && found->second == db)
|
||||
sqlite_worker_connection_cache.erase(found);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SQLite::set_error(s32 code, String info)
|
||||
{
|
||||
error_code = code;
|
||||
if(connection)
|
||||
statement_info = sqlite3_errmsg((sqlite3*)connection);
|
||||
else
|
||||
statement_info = info;
|
||||
if(info != "")
|
||||
statement_info = info + (statement_info != "" ? ": " + statement_info : "");
|
||||
}
|
||||
|
||||
bool SQLite::apply_default_pragmas()
|
||||
{
|
||||
char* err = 0;
|
||||
const char* pragmas =
|
||||
"PRAGMA foreign_keys = ON;"
|
||||
"PRAGMA journal_mode = WAL;"
|
||||
"PRAGMA synchronous = NORMAL;";
|
||||
s32 rc = sqlite3_exec((sqlite3*)connection, pragmas, 0, 0, &err);
|
||||
if(rc != SQLITE_OK)
|
||||
{
|
||||
String message;
|
||||
if(err)
|
||||
{
|
||||
message = err;
|
||||
sqlite3_free(err);
|
||||
}
|
||||
set_error(rc, "sqlite default pragmas failed" + (message != "" ? ": " + message : ""));
|
||||
return(false);
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
|
||||
bool SQLite::connect(String path)
|
||||
{
|
||||
disconnect();
|
||||
this->path = path;
|
||||
s32 rc = sqlite3_open_v2(path.c_str(), (sqlite3**)&connection, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX, 0);
|
||||
if(rc != SQLITE_OK)
|
||||
{
|
||||
set_error(rc, "sqlite open failed for " + path);
|
||||
disconnect();
|
||||
return(false);
|
||||
}
|
||||
sqlite3_busy_timeout((sqlite3*)connection, 5000);
|
||||
sqlite_register_request_connection(this);
|
||||
if(!apply_default_pragmas())
|
||||
return(false);
|
||||
statement_info = "connected";
|
||||
return(true);
|
||||
}
|
||||
|
||||
void SQLite::disconnect()
|
||||
{
|
||||
sqlite_forget_worker_cached_connection(this);
|
||||
if(!connection)
|
||||
{
|
||||
sqlite_unregister_request_connection(this);
|
||||
return;
|
||||
}
|
||||
sqlite3_close((sqlite3*)connection);
|
||||
connection = 0;
|
||||
sqlite_unregister_request_connection(this);
|
||||
}
|
||||
|
||||
String SQLite::error()
|
||||
{
|
||||
if(statement_info != "")
|
||||
return(statement_info);
|
||||
if(connection)
|
||||
return(sqlite3_errmsg((sqlite3*)connection));
|
||||
return("");
|
||||
}
|
||||
|
||||
bool SQLite::bind_params(void* statement, const StringMap& params)
|
||||
{
|
||||
sqlite3_stmt* stmt = (sqlite3_stmt*)statement;
|
||||
s32 count = sqlite3_bind_parameter_count(stmt);
|
||||
for(s32 i = 1; i <= count; i++)
|
||||
{
|
||||
const char* raw_name = sqlite3_bind_parameter_name(stmt, i);
|
||||
if(!raw_name || raw_name[0] == '\0')
|
||||
{
|
||||
set_error(SQLITE_MISUSE, "sqlite positional ? placeholders are not supported; use named :name placeholders");
|
||||
return(false);
|
||||
}
|
||||
String name = raw_name;
|
||||
if(name[0] != ':')
|
||||
{
|
||||
set_error(SQLITE_MISUSE, "sqlite only supports :name placeholders; found " + name);
|
||||
return(false);
|
||||
}
|
||||
String key = name.substr(1);
|
||||
auto found = params.find(key);
|
||||
s32 rc;
|
||||
if(found == params.end())
|
||||
rc = sqlite3_bind_null(stmt, i);
|
||||
else
|
||||
rc = sqlite3_bind_text(stmt, i, found->second.c_str(), found->second.length(), SQLITE_STATIC);
|
||||
if(rc != SQLITE_OK)
|
||||
{
|
||||
set_error(rc, "sqlite bind failed for " + name);
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
|
||||
DTree SQLite::collect_rows(void* statement)
|
||||
{
|
||||
sqlite3_stmt* stmt = (sqlite3_stmt*)statement;
|
||||
DTree result;
|
||||
s32 column_count = sqlite3_column_count(stmt);
|
||||
std::vector<String> column_names;
|
||||
column_names.reserve(column_count);
|
||||
for(s32 i = 0; i < column_count; i++)
|
||||
column_names.push_back(sqlite3_column_name(stmt, i));
|
||||
while(true)
|
||||
{
|
||||
s32 rc = sqlite3_step(stmt);
|
||||
if(rc == SQLITE_ROW)
|
||||
{
|
||||
DTree row;
|
||||
for(s32 i = 0; i < column_count; i++)
|
||||
{
|
||||
const String& name = column_names[i];
|
||||
switch(sqlite3_column_type(stmt, i))
|
||||
{
|
||||
case SQLITE_INTEGER:
|
||||
row[name].set((s64)sqlite3_column_int64(stmt, i));
|
||||
break;
|
||||
case SQLITE_FLOAT:
|
||||
row[name].set((f64)sqlite3_column_double(stmt, i));
|
||||
break;
|
||||
case SQLITE_TEXT:
|
||||
{
|
||||
const unsigned char* text = sqlite3_column_text(stmt, i);
|
||||
row[name].set(text ? String((const char*)text) : "");
|
||||
break;
|
||||
}
|
||||
case SQLITE_BLOB:
|
||||
{
|
||||
const char* data = (const char*)sqlite3_column_blob(stmt, i);
|
||||
s32 bytes = sqlite3_column_bytes(stmt, i);
|
||||
row[name].set(data && bytes > 0 ? String(data, bytes) : "");
|
||||
break;
|
||||
}
|
||||
case SQLITE_NULL:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
result.push(row);
|
||||
continue;
|
||||
}
|
||||
if(rc == SQLITE_DONE)
|
||||
{
|
||||
affected_rows = sqlite3_changes((sqlite3*)connection);
|
||||
insert_id = sqlite3_last_insert_rowid((sqlite3*)connection);
|
||||
return(result);
|
||||
}
|
||||
set_error(rc, "sqlite step failed");
|
||||
return(DTree());
|
||||
}
|
||||
}
|
||||
|
||||
DTree SQLite::query(String q)
|
||||
{
|
||||
StringMap params;
|
||||
return(query(q, params));
|
||||
}
|
||||
|
||||
DTree SQLite::query(String q, const StringMap& params)
|
||||
{
|
||||
DTree result;
|
||||
affected_rows = 0;
|
||||
insert_id = 0;
|
||||
error_code = SQLITE_OK;
|
||||
statement_info = "";
|
||||
if(!connection)
|
||||
{
|
||||
set_error(SQLITE_MISUSE, "sqlite query called without an open connection");
|
||||
return(result);
|
||||
}
|
||||
sqlite3_stmt* stmt = 0;
|
||||
const char* tail = 0;
|
||||
s32 rc = sqlite3_prepare_v2((sqlite3*)connection, q.c_str(), q.length(), &stmt, &tail);
|
||||
if(rc != SQLITE_OK)
|
||||
{
|
||||
set_error(rc, "sqlite prepare failed");
|
||||
return(result);
|
||||
}
|
||||
if(!stmt)
|
||||
{
|
||||
statement_info = "ok";
|
||||
return(result);
|
||||
}
|
||||
if(tail && trim(String(tail)) != "")
|
||||
{
|
||||
sqlite3_stmt* trailing_stmt = 0;
|
||||
const char* trailing_tail = 0;
|
||||
rc = sqlite3_prepare_v2((sqlite3*)connection, tail, -1, &trailing_stmt, &trailing_tail);
|
||||
if(rc != SQLITE_OK)
|
||||
{
|
||||
sqlite3_finalize(stmt);
|
||||
set_error(rc, "sqlite_query accepts exactly one SQL statement per call; trailing SQL after the first statement was rejected");
|
||||
return(result);
|
||||
}
|
||||
if(trailing_stmt)
|
||||
{
|
||||
sqlite3_finalize(trailing_stmt);
|
||||
sqlite3_finalize(stmt);
|
||||
set_error(SQLITE_MISUSE, "sqlite_query accepts exactly one SQL statement per call; trailing SQL after the first statement was rejected");
|
||||
return(result);
|
||||
}
|
||||
}
|
||||
if(!bind_params(stmt, params))
|
||||
{
|
||||
sqlite3_finalize(stmt);
|
||||
return(result);
|
||||
}
|
||||
result = collect_rows(stmt);
|
||||
rc = sqlite3_finalize(stmt);
|
||||
if(rc != SQLITE_OK && error_code == SQLITE_OK)
|
||||
set_error(rc, "sqlite finalize failed");
|
||||
if(statement_info == "")
|
||||
statement_info = "ok";
|
||||
return(result);
|
||||
}
|
||||
|
||||
SQLite* sqlite_connect(String path)
|
||||
{
|
||||
auto found = sqlite_worker_connection_cache.find(path);
|
||||
if(found != sqlite_worker_connection_cache.end() && found->second && found->second->connection)
|
||||
{
|
||||
SQLite* cached = found->second;
|
||||
cached->error_code = SQLITE_OK;
|
||||
cached->affected_rows = 0;
|
||||
cached->insert_id = 0;
|
||||
cached->statement_info = "connected";
|
||||
sqlite_register_request_connection(cached);
|
||||
return(cached);
|
||||
}
|
||||
|
||||
SQLite* db = new SQLite();
|
||||
db->worker_cache = true;
|
||||
if(db->connect(path) && db->connection)
|
||||
sqlite_worker_connection_cache[path] = db;
|
||||
else
|
||||
db->request_cleanup_delete = true;
|
||||
return(db);
|
||||
}
|
||||
|
||||
void sqlite_disconnect(SQLite* db)
|
||||
{
|
||||
if(!db)
|
||||
return;
|
||||
db->disconnect();
|
||||
delete db;
|
||||
}
|
||||
|
||||
String sqlite_error(SQLite* db)
|
||||
{
|
||||
if(!db)
|
||||
return("sqlite connection is null");
|
||||
return(db->error());
|
||||
}
|
||||
|
||||
DTree sqlite_query(SQLite* db, String q)
|
||||
{
|
||||
if(!db)
|
||||
return(DTree());
|
||||
return(db->query(q));
|
||||
}
|
||||
|
||||
DTree sqlite_query(SQLite* db, String q, const StringMap& params)
|
||||
{
|
||||
if(!db)
|
||||
return(DTree());
|
||||
return(db->query(q, params));
|
||||
}
|
||||
|
||||
u64 sqlite_insert_id(SQLite* db)
|
||||
{
|
||||
if(!db)
|
||||
return(0);
|
||||
return(db->insert_id);
|
||||
}
|
||||
|
||||
u32 sqlite_affected_rows(SQLite* db)
|
||||
{
|
||||
if(!db)
|
||||
return(0);
|
||||
return(db->affected_rows);
|
||||
}
|
||||
|
||||
void cleanup_sqlite_connections()
|
||||
{
|
||||
if(!context)
|
||||
return;
|
||||
while(!context->resources.sqlite_connections.empty())
|
||||
{
|
||||
SQLite* db = (SQLite*)context->resources.sqlite_connections.back();
|
||||
context->resources.sqlite_connections.pop_back();
|
||||
if(db->worker_cache)
|
||||
{
|
||||
db->affected_rows = 0;
|
||||
db->insert_id = 0;
|
||||
db->error_code = SQLITE_OK;
|
||||
db->statement_info = "";
|
||||
continue;
|
||||
}
|
||||
bool should_delete = db->request_cleanup_delete;
|
||||
db->disconnect();
|
||||
if(should_delete)
|
||||
delete db;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
struct SQLite {
|
||||
|
||||
void* connection = 0;
|
||||
s32 error_code = 0;
|
||||
u32 affected_rows = 0;
|
||||
u64 insert_id = 0;
|
||||
String statement_info = "";
|
||||
String path = "";
|
||||
bool request_cleanup_delete = false;
|
||||
bool worker_cache = false;
|
||||
|
||||
bool connect(String path);
|
||||
void disconnect();
|
||||
String error();
|
||||
DTree query(String q);
|
||||
DTree query(String q, const StringMap& params);
|
||||
|
||||
private:
|
||||
void set_error(s32 code, String info = "");
|
||||
bool apply_default_pragmas();
|
||||
bool bind_params(void* statement, const StringMap& params);
|
||||
DTree collect_rows(void* statement);
|
||||
};
|
||||
|
||||
SQLite* sqlite_connect(String path);
|
||||
void sqlite_disconnect(SQLite* db);
|
||||
String sqlite_error(SQLite* db);
|
||||
DTree sqlite_query(SQLite* db, String q);
|
||||
DTree sqlite_query(SQLite* db, String q, const StringMap& params);
|
||||
u64 sqlite_insert_id(SQLite* db);
|
||||
u32 sqlite_affected_rows(SQLite* db);
|
||||
void cleanup_sqlite_connections();
|
||||
@@ -208,6 +208,7 @@ struct Request {
|
||||
struct Resources {
|
||||
std::vector<u64> sockets;
|
||||
std::vector<void*> mysql_connections;
|
||||
std::vector<void*> sqlite_connections;
|
||||
u64 client_socket = 0;
|
||||
u64 server_socket = 0;
|
||||
bool is_websocket = false;
|
||||
|
||||
+6
-1
@@ -1,4 +1,8 @@
|
||||
|
||||
// UCE runtime amalgamation include.
|
||||
//
|
||||
// The worker and generated units include this file to build the runtime in a
|
||||
// single translation unit. Do not compile the listed .cpp files separately
|
||||
// unless the build/compiler model is deliberately changed.
|
||||
|
||||
#include "types.cpp"
|
||||
#include "dtree.cpp"
|
||||
@@ -12,3 +16,4 @@
|
||||
#include "markdown.cpp"
|
||||
#include "zip.cpp"
|
||||
#include "mysql-connector.cpp"
|
||||
#include "sqlite-connector.cpp"
|
||||
|
||||
@@ -11,3 +11,4 @@
|
||||
#include "markdown.h"
|
||||
#include "zip.h"
|
||||
#include "mysql-connector.h"
|
||||
#include "sqlite-connector.h"
|
||||
|
||||
+143
-24
@@ -220,38 +220,31 @@ String uri_encode(String q)
|
||||
|
||||
StringMap parse_query(String q)
|
||||
{
|
||||
StringMap result;
|
||||
if(q.length() == 0)
|
||||
return(result);
|
||||
return(parse_query(q, 0));
|
||||
}
|
||||
|
||||
bool is_key = true;
|
||||
String key = "";
|
||||
String value = "";
|
||||
for (char &c: q)
|
||||
StringMap parse_query(String q, String* first_keyless_path)
|
||||
{
|
||||
StringMap result;
|
||||
if(first_keyless_path)
|
||||
*first_keyless_path = "";
|
||||
for(String part : split(q, "&"))
|
||||
{
|
||||
if(c == '=')
|
||||
if(part == "")
|
||||
continue;
|
||||
size_t equals = part.find('=');
|
||||
if(equals == String::npos)
|
||||
{
|
||||
is_key = !is_key;
|
||||
}
|
||||
else if(c == '&')
|
||||
{
|
||||
result[uri_decode(key)] = uri_decode(value);
|
||||
key = "";
|
||||
value = "";
|
||||
is_key = true;
|
||||
}
|
||||
else if(is_key)
|
||||
{
|
||||
key.append(1, c);
|
||||
String key = uri_decode(part);
|
||||
if(first_keyless_path && *first_keyless_path == "")
|
||||
*first_keyless_path = key;
|
||||
result[key] = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
value.append(1, c);
|
||||
result[uri_decode(part.substr(0, equals))] = uri_decode(part.substr(equals + 1));
|
||||
}
|
||||
}
|
||||
|
||||
result[uri_decode(key)] = uri_decode(value);
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
@@ -269,6 +262,132 @@ String encode_query(StringMap map)
|
||||
return(result);
|
||||
}
|
||||
|
||||
String route_path_normalize(String path)
|
||||
{
|
||||
path = trim(path);
|
||||
size_t start = path.find_first_not_of('/');
|
||||
if(start == String::npos)
|
||||
return("");
|
||||
size_t end = path.find_last_not_of('/');
|
||||
return(path.substr(start, end - start + 1));
|
||||
}
|
||||
|
||||
bool route_path_normalized_is_safe(String path)
|
||||
{
|
||||
if(path == "")
|
||||
return(true);
|
||||
for(String part : split(path, "/"))
|
||||
{
|
||||
if(part == "" || part == "." || part == "..")
|
||||
return(false);
|
||||
for(unsigned char c : part)
|
||||
{
|
||||
if(!(std::isalnum(c) || c == '-' || c == '_'))
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
|
||||
bool route_path_is_safe(String path)
|
||||
{
|
||||
return(route_path_normalized_is_safe(route_path_normalize(path)));
|
||||
}
|
||||
|
||||
String route_path_sanitize(String path, String default_path)
|
||||
{
|
||||
path = route_path_normalize(path);
|
||||
if(path == "")
|
||||
path = route_path_normalize(default_path);
|
||||
if(!route_path_normalized_is_safe(path))
|
||||
return("");
|
||||
return(path);
|
||||
}
|
||||
|
||||
String route_path_sanitize_normalized(String path, String default_path)
|
||||
{
|
||||
if(path == "")
|
||||
path = route_path_normalize(default_path);
|
||||
if(!route_path_normalized_is_safe(path))
|
||||
return("");
|
||||
return(path);
|
||||
}
|
||||
|
||||
String request_script_url(Request& context)
|
||||
{
|
||||
String url = first(context.params["DOCUMENT_URI"], context.params["SCRIPT_NAME"]);
|
||||
if(str_ends_with(url, "/index.uce"))
|
||||
url = url.substr(0, url.length() - String("index.uce").length());
|
||||
return(url);
|
||||
}
|
||||
|
||||
String request_base_url_from_script_url(String script_url)
|
||||
{
|
||||
String base = dirname(script_url);
|
||||
if(base == "")
|
||||
base = "/";
|
||||
if(base[base.length() - 1] != '/')
|
||||
base.append(1, '/');
|
||||
return(base);
|
||||
}
|
||||
|
||||
String request_base_url(Request& context)
|
||||
{
|
||||
return(request_base_url_from_script_url(request_script_url(context)));
|
||||
}
|
||||
|
||||
String request_query_path(Request& context, String default_path)
|
||||
{
|
||||
return(request_query_route(context, default_path)["l_path"].to_string());
|
||||
}
|
||||
|
||||
DTree request_query_route(Request& context, String default_path)
|
||||
{
|
||||
String raw_path = "";
|
||||
parse_query(context.params["QUERY_STRING"], &raw_path);
|
||||
return(request_route_from_raw_path(raw_path, default_path));
|
||||
}
|
||||
|
||||
DTree request_route_from_raw_path(String raw_path, String default_path)
|
||||
{
|
||||
DTree route;
|
||||
String normalized_path = route_path_normalize(raw_path);
|
||||
String route_path = route_path_sanitize_normalized(normalized_path, default_path);
|
||||
bool valid = route_path != "";
|
||||
route["raw_path"] = normalized_path;
|
||||
route["l_path"] = route_path;
|
||||
String page = route_path;
|
||||
route["page"] = valid ? nibble(page, "/") : "";
|
||||
if(valid && route["page"].to_string() == "")
|
||||
route["page"] = default_path;
|
||||
route["valid"].set_bool(valid);
|
||||
return(route);
|
||||
}
|
||||
|
||||
void request_populate_context_params(Request& context, String default_path)
|
||||
{
|
||||
DTree route = request_query_route(context, default_path);
|
||||
String script_url = request_script_url(context);
|
||||
context.params["SCRIPT_URL"] = script_url;
|
||||
context.params["BASE_URL"] = request_base_url_from_script_url(script_url);
|
||||
context.params["ROUTE_PATH"] = route["l_path"].to_string();
|
||||
context.params["ROUTE_PAGE"] = route["page"].to_string();
|
||||
context.params["ROUTE_PATH_RAW"] = route["raw_path"].to_string();
|
||||
context.params["ROUTE_VALID"] = route["valid"].to_bool() ? "1" : "0";
|
||||
}
|
||||
|
||||
void request_populate_context_params_from_route(Request& context, String raw_path, String default_path)
|
||||
{
|
||||
DTree route = request_route_from_raw_path(raw_path, default_path);
|
||||
String script_url = request_script_url(context);
|
||||
context.params["SCRIPT_URL"] = script_url;
|
||||
context.params["BASE_URL"] = request_base_url_from_script_url(script_url);
|
||||
context.params["ROUTE_PATH"] = route["l_path"].to_string();
|
||||
context.params["ROUTE_PAGE"] = route["page"].to_string();
|
||||
context.params["ROUTE_PATH_RAW"] = route["raw_path"].to_string();
|
||||
context.params["ROUTE_VALID"] = route["valid"].to_bool() ? "1" : "0";
|
||||
}
|
||||
|
||||
bool http_header_name_valid(String name)
|
||||
{
|
||||
if(name == "")
|
||||
|
||||
@@ -8,7 +8,18 @@ String base64_decode(String raw, bool& ok);
|
||||
String uri_decode(String q);
|
||||
String uri_encode(String q);
|
||||
StringMap parse_query(String q);
|
||||
StringMap parse_query(String q, String* first_keyless_path);
|
||||
String encode_query(StringMap map);
|
||||
String route_path_normalize(String path);
|
||||
bool route_path_is_safe(String path);
|
||||
String route_path_sanitize(String path, String default_path = "index");
|
||||
String request_script_url(Request& context);
|
||||
String request_base_url(Request& context);
|
||||
String request_query_path(Request& context, String default_path = "index");
|
||||
DTree request_query_route(Request& context, String default_path = "index");
|
||||
DTree request_route_from_raw_path(String raw_path, String default_path = "index");
|
||||
void request_populate_context_params(Request& context, String default_path = "index");
|
||||
void request_populate_context_params_from_route(Request& context, String raw_path, String default_path = "index");
|
||||
void redirect(String url, s32 code = 302);
|
||||
StringMap parse_multipart(String q, String boundary, std::vector<UploadedFile>& uploaded_files);
|
||||
URI parse_uri(String uri_String);
|
||||
|
||||
+62
-38
@@ -27,6 +27,7 @@ static String websocket_exec_write_buffer = "";
|
||||
|
||||
void close_inherited_server_sockets();
|
||||
u64 request_seed_from_time(f64 time_value);
|
||||
void prepare_request_body_maps(Request& request);
|
||||
|
||||
Request* set_active_request(Request& request)
|
||||
{
|
||||
@@ -67,40 +68,34 @@ void render_request_failure(Request& request, String title, String details, Stri
|
||||
Request* previous_context = set_active_request(request);
|
||||
clear_request_output(request);
|
||||
|
||||
print("UCE runtime error\n");
|
||||
print("Request: ", first(request.params["REQUEST_URI"], request.params["SCRIPT_FILENAME"]), "\n");
|
||||
print("Script: ", request.params["SCRIPT_FILENAME"], "\n");
|
||||
print("Error: ", title, "\n");
|
||||
String body;
|
||||
body += "UCE runtime error\n";
|
||||
body += "Request: " + first(request.params["REQUEST_URI"], request.params["SCRIPT_FILENAME"]) + "\n";
|
||||
body += "Script: " + request.params["SCRIPT_FILENAME"] + "\n";
|
||||
body += "Error: " + title + "\n";
|
||||
if(details != "")
|
||||
print("Details: ", details, "\n");
|
||||
body += "Details: " + details + "\n";
|
||||
if(request.server && request.params["SCRIPT_FILENAME"] != "")
|
||||
{
|
||||
String generated = compiler_generated_cpp_path(&request, request.params["SCRIPT_FILENAME"]);
|
||||
body += "Generated C++: " + generated + "\n";
|
||||
body += "Hint: if this came from template code, inspect the generated C++ and the nearest .uce literal/code delimiter before changing runtime code.\n";
|
||||
}
|
||||
else
|
||||
body += "Hint: inspect the requested .uce file, its generated C++, and any component/unit called immediately before this failure.\n";
|
||||
if(request_fault_signal != 0)
|
||||
{
|
||||
String sig_label = signal_name((int)request_fault_signal);
|
||||
print("Signal: ", (s64)request_fault_signal);
|
||||
body += "Signal: " + std::to_string((int)request_fault_signal);
|
||||
if(sig_label != "")
|
||||
print(" (", sig_label, ")");
|
||||
print("\n");
|
||||
body += " (" + sig_label + ")";
|
||||
body += "\n";
|
||||
}
|
||||
if(trace != "")
|
||||
print("\nTrace:\n", trace);
|
||||
|
||||
request.err += "UCE runtime error\n";
|
||||
request.err += "Request: " + first(request.params["REQUEST_URI"], request.params["SCRIPT_FILENAME"]) + "\n";
|
||||
request.err += "Script: " + request.params["SCRIPT_FILENAME"] + "\n";
|
||||
request.err += "Error: " + title + "\n";
|
||||
if(details != "")
|
||||
request.err += "Details: " + details + "\n";
|
||||
if(request_fault_signal != 0)
|
||||
{
|
||||
String sig_label = signal_name((int)request_fault_signal);
|
||||
request.err += "Signal: " + std::to_string((int)request_fault_signal);
|
||||
if(sig_label != "")
|
||||
request.err += " (" + sig_label + ")";
|
||||
request.err += "\n";
|
||||
}
|
||||
if(trace != "")
|
||||
request.err += "\nTrace:\n" + trace;
|
||||
body += "\nTrace:\n" + trace;
|
||||
|
||||
print(body);
|
||||
request.err = body;
|
||||
request.flags.status = status_code;
|
||||
restore_active_request(previous_context);
|
||||
}
|
||||
@@ -108,9 +103,11 @@ void render_request_failure(Request& request, String title, String details, Stri
|
||||
void on_request_fault_signal(int sig)
|
||||
{
|
||||
request_fault_signal = sig;
|
||||
request_fault_trace = capture_backtrace_string(32, 1);
|
||||
if(request_fault_active && request_fault_request)
|
||||
{
|
||||
request_fault_trace = capture_backtrace_string(32, 1);
|
||||
siglongjmp(request_fault_jmp, 1);
|
||||
}
|
||||
on_segfault(sig);
|
||||
}
|
||||
|
||||
@@ -393,7 +390,7 @@ Request websocket_exec_build_event_request(DTree job, String message)
|
||||
event_request.server = &server_state;
|
||||
event_request.params = job["params"].to_stringmap();
|
||||
event_request.params["REQUEST_METHOD"] = "WEBSOCKET";
|
||||
event_request.get = parse_query(event_request.params["QUERY_STRING"]);
|
||||
prepare_request_body_maps(event_request);
|
||||
event_request.resources.is_websocket = true;
|
||||
event_request.resources.websocket_connection_id = job["connection_id"].to_string();
|
||||
event_request.resources.websocket_scope = job["scope"].to_string();
|
||||
@@ -413,9 +410,6 @@ Request websocket_exec_build_event_request(DTree job, String message)
|
||||
event_request.header["Content-Type"] = server_state.config["CONTENT_TYPE"];
|
||||
event_request.in = message;
|
||||
|
||||
if(event_request.params["HTTP_COOKIE"].length() > 0)
|
||||
event_request.cookies = parse_cookies(event_request.params["HTTP_COOKIE"]);
|
||||
|
||||
event_request.params["WS_MESSAGE"] = message;
|
||||
event_request.params["WS_CONNECTION_ID"] = event_request.resources.websocket_connection_id;
|
||||
event_request.params["WS_SCOPE"] = event_request.resources.websocket_scope;
|
||||
@@ -475,6 +469,7 @@ void websocket_exec_process_job_line(int fd, String line)
|
||||
if(event_request.session_id.length() > 0)
|
||||
save_session_data(event_request.session_id, event_request.session);
|
||||
cleanup_mysql_connections();
|
||||
cleanup_sqlite_connections();
|
||||
|
||||
DTree response;
|
||||
response["type"] = "result";
|
||||
@@ -750,7 +745,9 @@ u64 request_seed_from_time(f64 time_value)
|
||||
|
||||
void prepare_request_body_maps(Request& request)
|
||||
{
|
||||
request.get = parse_query(request.params["QUERY_STRING"]);
|
||||
String route_path;
|
||||
request.get = parse_query(request.params["QUERY_STRING"], &route_path);
|
||||
request_populate_context_params_from_route(request, route_path);
|
||||
if(request.params["HTTP_COOKIE"].length() > 0)
|
||||
request.cookies = parse_cookies(request.params["HTTP_COOKIE"]);
|
||||
|
||||
@@ -782,7 +779,6 @@ int handle_cli_complete(FastCGIRequest& request)
|
||||
request.random_index = 0;
|
||||
request.random_seed = request_seed_from_time(request.stats.time_start);
|
||||
request.ob_start();
|
||||
prepare_request_body_maps(request);
|
||||
|
||||
String method = trim(request.params["REQUEST_METHOD"]);
|
||||
String command = trim(first(request.params["DOCUMENT_URI"], request.params["REQUEST_URI"]));
|
||||
@@ -827,6 +823,7 @@ int handle_cli_complete(FastCGIRequest& request)
|
||||
{
|
||||
request.params["DOCUMENT_ROOT"] = document_root;
|
||||
request.params["SCRIPT_FILENAME"] = script_filename;
|
||||
prepare_request_body_maps(request);
|
||||
request.props = DTree();
|
||||
compiler_invoke_cli(&request, script_filename);
|
||||
}
|
||||
@@ -850,6 +847,7 @@ int handle_cli_complete(FastCGIRequest& request)
|
||||
for(auto &f : request.uploaded_files)
|
||||
file_unlink(f.tmp_name);
|
||||
cleanup_mysql_connections();
|
||||
cleanup_sqlite_connections();
|
||||
restore_active_request(previous_context);
|
||||
return(request.flags.status);
|
||||
}
|
||||
@@ -883,7 +881,6 @@ int handle_complete(FastCGIRequest& request) {
|
||||
//request.stats.mem_alloc = 0;
|
||||
//request.stats.mem_high = 0;
|
||||
request.header["Content-Type"] = (request.resources.is_cli ? "text/plain; charset=utf-8" : context->server->config["CONTENT_TYPE"]);
|
||||
request.get = parse_query(request.params["QUERY_STRING"]);
|
||||
request.random_index = 0;
|
||||
request.random_seed = request_seed_from_time(request.stats.time_start);
|
||||
request.ob_start();
|
||||
@@ -945,6 +942,7 @@ int handle_complete(FastCGIRequest& request) {
|
||||
save_session_data(request.session_id, request.session);
|
||||
|
||||
cleanup_mysql_connections();
|
||||
cleanup_sqlite_connections();
|
||||
restore_active_request(previous_context);
|
||||
|
||||
return request.flags.status;
|
||||
@@ -1305,14 +1303,27 @@ void run_proactive_compiler()
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
setpriority(PRIO_PROCESS, 0, 10);
|
||||
|
||||
auto known_units = compiler_list_known_units(&background_context);
|
||||
auto site_units = compiler_scan_site_units(&background_context);
|
||||
known_units.insert(known_units.end(), site_units.begin(), site_units.end());
|
||||
compiler_set_known_units(&background_context, known_units);
|
||||
try
|
||||
{
|
||||
auto known_units = compiler_list_known_units(&background_context);
|
||||
auto site_units = compiler_scan_site_units(&background_context);
|
||||
known_units.insert(known_units.end(), site_units.begin(), site_units.end());
|
||||
compiler_set_known_units(&background_context, known_units);
|
||||
}
|
||||
catch(const std::exception& e)
|
||||
{
|
||||
printf("(!) proactive compiler initial scan failed: %s\n", e.what());
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
printf("(!) proactive compiler initial scan failed: unknown exception\n");
|
||||
}
|
||||
next_scan_at = time_precise();
|
||||
|
||||
for(;;)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(compile_queue.size() == 0 && time_precise() >= next_scan_at)
|
||||
{
|
||||
auto tracked_units = compiler_list_known_units(&background_context);
|
||||
@@ -1375,6 +1386,19 @@ void run_proactive_compiler()
|
||||
}
|
||||
|
||||
usleep(250000);
|
||||
}
|
||||
catch(const std::exception& e)
|
||||
{
|
||||
printf("(!) proactive compiler scan failed: %s\n", e.what());
|
||||
next_scan_at = time_precise() + check_interval;
|
||||
usleep(250000);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
printf("(!) proactive compiler scan failed: unknown exception\n");
|
||||
next_scan_at = time_precise() + check_interval;
|
||||
usleep(250000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user