diff --git a/src/Makefile.shlib b/src/Makefile.shlib index 29a7f6d38c8..bd10be44651 100644 --- a/src/Makefile.shlib +++ b/src/Makefile.shlib @@ -122,13 +122,13 @@ ifeq ($(PORTNAME), darwin) ifneq ($(SO_MAJOR_VERSION), 0) version_link = -compatibility_version $(SO_MAJOR_VERSION) -current_version $(SO_MAJOR_VERSION).$(SO_MINOR_VERSION) endif - LINK.shared = $(COMPILER) -dynamiclib -install_name '$(libdir)/lib$(NAME).$(SO_MAJOR_VERSION)$(DLSUFFIX)' $(version_link) $(exported_symbols_list) -multiply_defined suppress + LINK.shared = $(COMPILER) -dynamiclib -install_name '$(libdir)/lib$(NAME).$(SO_MAJOR_VERSION)$(DLSUFFIX)' $(version_link) $(exported_symbols_list) shlib = lib$(NAME).$(SO_MAJOR_VERSION).$(SO_MINOR_VERSION)$(DLSUFFIX) shlib_major = lib$(NAME).$(SO_MAJOR_VERSION)$(DLSUFFIX) else # loadable module DLSUFFIX = .so - LINK.shared = $(COMPILER) -bundle -multiply_defined suppress + LINK.shared = $(COMPILER) -bundle endif BUILD.exports = $(AWK) '/^[^\#]/ {printf "_%s\n",$$1}' $< >$@ exports_file = $(SHLIB_EXPORTS:%.txt=%.list) diff --git a/src/backend/Makefile b/src/backend/Makefile index f246214181c..0f807d4fc02 100644 --- a/src/backend/Makefile +++ b/src/backend/Makefile @@ -62,8 +62,17 @@ ifneq ($(PORTNAME), cygwin) ifneq ($(PORTNAME), win32) ifneq ($(PORTNAME), aix) +OBJS += \ + $(top_builddir)/src/pl/plpgsql/src/pl_comp.o \ + $(top_builddir)/src/pl/plpgsql/src/pl_exec.o \ + $(top_builddir)/src/pl/plpgsql/src/pl_funcs.o \ + $(top_builddir)/src/pl/plpgsql/src/pl_gram.o \ + $(top_builddir)/src/pl/plpgsql/src/pl_handler.o \ + $(top_builddir)/src/pl/plpgsql/src/pl_scanner.o + postgres: $(OBJS) - $(CC) $(CFLAGS) $(call expand_subsys,$^) $(LDFLAGS) $(LDFLAGS_EX) $(export_dynamic) $(LIBS) -s FORCE_FILESYSTEM=1 -s ASYNCIFY=1 -lnodefs.js -lproxyfs.js -lidbfs.js -o $@ + $(CC) $(CFLAGS) $(call expand_subsys,$^) $(LDFLAGS) $(LDFLAGS_EX) $(export_dynamic) $(LIBS) -sALLOW_MEMORY_GROWTH=1 -sFORCE_FILESYSTEM=1 -lnodefs.js -lproxyfs.js -lidbfs.js -o $@ + endif endif endif diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index f13b1977ccb..63c7af4c946 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -211,6 +211,14 @@ static void log_disconnections(int code, Datum arg); static void enable_statement_timeout(void); static void disable_statement_timeout(void); +/* ---------------------------------------------------------------- + * decls for PGlite routines + * ---------------------------------------------------------------- + */ +static void PostgresMain_Part0(void); +static void PostgresMain_Part1(void); +static void PostgresMain_Part2(void); +extern void ExecProtocolMsg(char *query); /* ---------------------------------------------------------------- * routines to obtain user input @@ -335,51 +343,6 @@ interactive_getc(void) return c; } -/* ---------------- - * EmscriptenBackend() - * - * ---------------- - */ - -#ifdef EMSCRIPTEN -EM_ASYNC_JS(char *, await_query, (), { - // Await a query from JS land - Module.eventTarget.dispatchEvent(new Module.Event("waiting")); - var query = await new Promise((resolve, reject) => { - Module.eventTarget.addEventListener("query", (e) => { - resolve(e.detail); - }, {once: true}); - }); - // `query` is a Uint8Array containing the query in pg wire format - var bytes = query.length; - var ptr = _malloc(bytes); - Module.HEAPU8.set(query, ptr); - return ptr; -}); -#endif - -static int -EmscriptenBackend(StringInfo inBuf) -{ - char *query = await_query(); - char qtype = *query; // First byte is qtype - - int32 msgLen = *((int32 *)(query + 1)); // Next 4 bytes are message length - msgLen = pg_ntoh32(msgLen); - int dataLen = msgLen - 4; // The rest of the message is the data - - resetStringInfo(inBuf); - if (dataLen > 0) - { - // Append the data to the buffer - appendBinaryStringInfo(inBuf, query + 5, dataLen); - } - - free(query); - - return qtype; -} - /* ---------------- * SocketBackend() Is called for frontend-backend connections * @@ -522,11 +485,7 @@ ReadCommand(StringInfo inBuf) int result; if (whereToSendOutput == DestRemote) -#ifdef EMSCRIPTEN - result = EmscriptenBackend(inBuf); -#else result = SocketBackend(inBuf); -#endif else result = InteractiveBackend(inBuf); return result; @@ -3974,6 +3933,58 @@ process_postgres_switches(int argc, char *argv[], GucContext ctx, } +/* ---------------------------------------------------------------- + * ExecProtocolMsg + * PGlite main execute protocol message + * ---------------------------------------------------------------- + */ + +int firstchar; +StringInfoData input_message; +sigjmp_buf local_sigjmp_buf; +volatile bool send_ready_for_query = true; +bool idle_in_transaction_timeout_enabled = false; +bool idle_session_timeout_enabled = false; + +extern void +ExecProtocolMsg(char *query) +{ + char qtype = *query; // First byte is qtype + + int32 msgLen = *((int32 *)(query + 1)); // Next 4 bytes are message length + msgLen = pg_ntoh32(msgLen); + int dataLen = msgLen - 4; // The rest of the message is the data + + resetStringInfo(&input_message); + if (dataLen > 0) + { + // Append the data to the buffer + appendBinaryStringInfo(&input_message, query + 5, dataLen); + } + + firstchar = qtype; + free(query); + + /* Setup error handling */ + if (sigsetjmp(local_sigjmp_buf, 1) != 0) + { + PostgresMain_Part0(); + + /* We can now handle ereport(ERROR) */ + PG_exception_stack = &local_sigjmp_buf; + + if (!ignore_till_sync) + send_ready_for_query = true; /* initially, or after error */ + + return; // Return to the caller + } + + /* Process the query */ + PostgresMain_Part2(); + PostgresMain_Part1(); +} + + /* ---------------------------------------------------------------- * PostgresMain * postgres main loop -- all backends, interactive or otherwise start here @@ -3983,20 +3994,20 @@ process_postgres_switches(int argc, char *argv[], GucContext ctx, * dbname is the name of the database to connect to, or NULL if the database * name should be extracted from the command line arguments or defaulted. * username is the PostgreSQL user name to be used for the session. + * + * Mods: + * + * This has been modified to be called from PGlite and exits early once + * initialisation is complete. + * ExecProtocolMsg above is called to process the query. * ---------------------------------------------------------------- */ + void PostgresMain(int argc, char *argv[], const char *dbname, const char *username) { - int firstchar; - StringInfoData input_message; - sigjmp_buf local_sigjmp_buf; - volatile bool send_ready_for_query = true; - bool idle_in_transaction_timeout_enabled = false; - bool idle_session_timeout_enabled = false; - /* Initialize startup process environment if necessary. */ if (!IsUnderPostmaster) InitStandaloneProcess(argv[0]); @@ -4245,9 +4256,27 @@ PostgresMain(int argc, char *argv[], * unblock in AbortTransaction() because the latter is only called if we * were inside a transaction. */ - if (sigsetjmp(local_sigjmp_buf, 1) != 0) { + PostgresMain_Part0(); + } + + /* We can now handle ereport(ERROR) */ + PG_exception_stack = &local_sigjmp_buf; + + if (!ignore_till_sync) + send_ready_for_query = true; /* initially, or after error */ + + /* + * Non-error queries loop here. + */ + PostgresMain_Part1(); + exit(0); +} + +void +PostgresMain_Part0() +{ /* * NOTE: if you are tempted to add more code in this if-block, * consider the high probability that it should be in @@ -4350,20 +4379,11 @@ PostgresMain(int argc, char *argv[], /* Now we can allow interrupts again */ RESUME_INTERRUPTS(); - } - - /* We can now handle ereport(ERROR) */ - PG_exception_stack = &local_sigjmp_buf; - - if (!ignore_till_sync) - send_ready_for_query = true; /* initially, or after error */ - - /* - * Non-error queries loop here. - */ +} - for (;;) - { +void +PostgresMain_Part1() +{ /* * At top of loop, reset extended-query-message flag, so that any * errors encountered in "idle" state don't provoke skip. @@ -4470,12 +4490,12 @@ PostgresMain(int argc, char *argv[], * STDIN doing the same thing.) */ DoingCommandRead = true; +} - /* - * (3) read a command (loop blocks here) - */ - firstchar = ReadCommand(&input_message); +void +PostgresMain_Part2() +{ /* * (4) turn off the idle-in-transaction and idle-session timeouts, if * active. We do this before step (5) so that any last-moment timeout @@ -4522,7 +4542,7 @@ PostgresMain(int argc, char *argv[], * Sync. */ if (ignore_till_sync && firstchar != EOF) - continue; + return; switch (firstchar) { @@ -4775,7 +4795,6 @@ PostgresMain(int argc, char *argv[], errmsg("invalid frontend message type %d", firstchar))); } - } /* end of input-reading loop */ } /* diff --git a/src/backend/utils/fmgr/dfmgr.c b/src/backend/utils/fmgr/dfmgr.c index e8c6cdde972..764793ce212 100644 --- a/src/backend/utils/fmgr/dfmgr.c +++ b/src/backend/utils/fmgr/dfmgr.c @@ -36,6 +36,7 @@ #include "storage/shmem.h" #include "utils/hsearch.h" +#include "extensions/plpgsql.h" /* signatures for PostgreSQL-specific library init/fini functions */ typedef void (*PG_init_t) (void); @@ -90,6 +91,26 @@ static char *find_in_dynamic_libpath(const char *basename); static const Pg_magic_struct magic_data = PG_MODULE_MAGIC_DATA; +/* PGlite static handling of extensions */ + +bool plpgsql_loaded = false; + +typedef struct { + const char *name; + void *function; +} func_map; + +static const func_map function_map[] = { + {"plpgsql_call_handler", plpgsql_call_handler}, + {"plpgsql_inline_handler", plpgsql_inline_handler}, + {"plpgsql_validator", plpgsql_validator}, + {"pg_finfo_plpgsql_call_handler", pg_finfo_plpgsql_call_handler}, + {"pg_finfo_plpgsql_inline_handler", pg_finfo_plpgsql_inline_handler}, + {"pg_finfo_plpgsql_validator", pg_finfo_plpgsql_validator}, + {NULL, NULL} +}; + + /* * Load the specified dynamic-link library file, and look for a function * named funcname in it. @@ -107,6 +128,24 @@ void * load_external_function(const char *filename, const char *funcname, bool signalNotFound, void **filehandle) { + // printf("load_external_function - filename: %s, funcname: %s, signalNotFound: %d, filehandle: %p\n", filename, funcname, signalNotFound, filehandle); + + /* PGlite static handling of extensions */ + if (strcmp(filename, "$libdir/plpgsql") == 0) + { + if (!plpgsql_loaded) + { + plpgsql_PG_init(); + plpgsql_loaded = true; + } + + for (int i = 0; function_map[i].name != NULL; i++) { + if (strcmp(funcname, function_map[i].name) == 0) { + return function_map[i].function; + } + } + } + char *fullname; void *lib_handle; void *retval; @@ -145,6 +184,19 @@ load_external_function(const char *filename, const char *funcname, void load_file(const char *filename, bool restricted) { + // printf("load_file - filename: %s, restricted: %d\n", filename, restricted); + + /* PGlite static handling of extensions */ + if (strcmp(filename, "$libdir/plpgsql") == 0) + { + if (!plpgsql_loaded) + { + plpgsql_PG_init(); + plpgsql_loaded = true; + } + return; + } + char *fullname; /* Apply security restriction if requested */ @@ -170,6 +222,15 @@ load_file(const char *filename, bool restricted) void * lookup_external_function(void *filehandle, const char *funcname) { + // printf("lookup_external_function - filehandle: %p, funcname: %s\n", filehandle, funcname); + + /* PGlite static handling of extensions */ + for (int i = 0; function_map[i].name != NULL; i++) { + if (strcmp(funcname, function_map[i].name) == 0) { + return function_map[i].function; + } + } + return dlsym(filehandle, funcname); } @@ -453,6 +514,7 @@ internal_unload_library(const char *libname) static bool file_exists(const char *name) { + // printf("file_exists - name: %s\n", name); struct stat st; AssertArg(name != NULL); diff --git a/src/include/extensions/plpgsql.h b/src/include/extensions/plpgsql.h new file mode 100644 index 00000000000..29963fbba18 --- /dev/null +++ b/src/include/extensions/plpgsql.h @@ -0,0 +1,12 @@ +#include "postgres.h" + +extern void plpgsql_PG_init(void); +extern Datum plpgsql_call_handler(PG_FUNCTION_ARGS); +extern Datum plpgsql_inline_handler(PG_FUNCTION_ARGS); +extern Datum plpgsql_validator(PG_FUNCTION_ARGS); + +#ifndef PLPGSQL_INFO_DEF +extern Pg_finfo_record *pg_finfo_plpgsql_call_handler(void); +extern Pg_finfo_record *pg_finfo_plpgsql_inline_handler(void); +extern Pg_finfo_record *pg_finfo_plpgsql_validator(void); +#endif \ No newline at end of file diff --git a/src/makefiles/Makefile.darwin b/src/makefiles/Makefile.darwin index b17598f0586..65a08812b82 100644 --- a/src/makefiles/Makefile.darwin +++ b/src/makefiles/Makefile.darwin @@ -5,11 +5,11 @@ DLSUFFIX = .so # env var name to use in place of LD_LIBRARY_PATH ld_library_path_var = DYLD_LIBRARY_PATH -ifdef PGXS - BE_DLLLIBS = -bundle_loader $(bindir)/postgres -else - BE_DLLLIBS = -bundle_loader $(top_builddir)/src/backend/postgres -endif +# ifdef PGXS +# BE_DLLLIBS = -bundle_loader $(bindir)/postgres +# else +# BE_DLLLIBS = -bundle_loader $(top_builddir)/src/backend/postgres +# endif # Rule for building a shared library from a single .o file %.so: %.o diff --git a/src/pl/plpgsql/src/pl_handler.c b/src/pl/plpgsql/src/pl_handler.c index 00aace2f39f..5844f8052e7 100644 --- a/src/pl/plpgsql/src/pl_handler.c +++ b/src/pl/plpgsql/src/pl_handler.c @@ -27,6 +27,10 @@ #include "utils/syscache.h" #include "utils/varlena.h" +#ifdef EMSCRIPTEN +#include +#endif + static bool plpgsql_extra_checks_check_hook(char **newvalue, void **extra, GucSource source); static void plpgsql_extra_warnings_assign_hook(const char *newvalue, void *extra); static void plpgsql_extra_errors_assign_hook(const char *newvalue, void *extra); @@ -141,8 +145,8 @@ plpgsql_extra_errors_assign_hook(const char *newvalue, void *extra) * * DO NOT make this static nor change its name! */ -void -_PG_init(void) +extern void EMSCRIPTEN_KEEPALIVE +plpgsql_PG_init(void) { /* Be sure we do initialization only once (should be redundant now) */ static bool inited = false; @@ -218,7 +222,7 @@ _PG_init(void) */ PG_FUNCTION_INFO_V1(plpgsql_call_handler); -Datum +extern Datum EMSCRIPTEN_KEEPALIVE plpgsql_call_handler(PG_FUNCTION_ARGS) { bool nonatomic; @@ -311,7 +315,7 @@ plpgsql_call_handler(PG_FUNCTION_ARGS) */ PG_FUNCTION_INFO_V1(plpgsql_inline_handler); -Datum +extern Datum EMSCRIPTEN_KEEPALIVE plpgsql_inline_handler(PG_FUNCTION_ARGS) { LOCAL_FCINFO(fake_fcinfo, 0); @@ -438,7 +442,7 @@ plpgsql_inline_handler(PG_FUNCTION_ARGS) */ PG_FUNCTION_INFO_V1(plpgsql_validator); -Datum +extern Datum EMSCRIPTEN_KEEPALIVE plpgsql_validator(PG_FUNCTION_ARGS) { Oid funcoid = PG_GETARG_OID(0); diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h index fcbfcd678b1..bcc41b55faa 100644 --- a/src/pl/plpgsql/src/plpgsql.h +++ b/src/pl/plpgsql/src/plpgsql.h @@ -23,6 +23,8 @@ #include "utils/expandedrecord.h" #include "utils/typcache.h" +#define PLPGSQL_INFO_DEF +#include "extensions/plpgsql.h" /********************************************************************** * Definitions