Skip to content

Static linking of plpgsql #7

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/Makefile.shlib
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
11 changes: 10 additions & 1 deletion src/backend/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
171 changes: 95 additions & 76 deletions src/backend/tcop/postgres.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
*
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand All @@ -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]);
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -4522,7 +4542,7 @@ PostgresMain(int argc, char *argv[],
* Sync.
*/
if (ignore_till_sync && firstchar != EOF)
continue;
return;

switch (firstchar)
{
Expand Down Expand Up @@ -4775,7 +4795,6 @@ PostgresMain(int argc, char *argv[],
errmsg("invalid frontend message type %d",
firstchar)));
}
} /* end of input-reading loop */
}

/*
Expand Down
62 changes: 62 additions & 0 deletions src/backend/utils/fmgr/dfmgr.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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.
Expand All @@ -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;
Expand Down Expand Up @@ -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 */
Expand All @@ -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);
}

Expand Down Expand Up @@ -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);
Expand Down
Loading