diff --git a/.gitignore b/.gitignore index 4e911395fe3ba..462591005e655 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,10 @@ lib*.pc /Release/ /tmp_install/ /portlock/ + +# libpglite +/configure +/src/Makefile.shlib +/src/backend/commands/async.c +/src/bin/initdb/initdb.c +/src/bin/pg_verifybackup/pg_verifybackup.c diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c index 5c06ba6db438e..0ea74cef43f23 100644 --- a/contrib/pgstattuple/pgstatindex.c +++ b/contrib/pgstattuple/pgstatindex.c @@ -656,9 +656,9 @@ pgstathashindex(PG_FUNCTION_ARGS) stats.unused_pages++; else if (PageGetSpecialSize(page) != MAXALIGN(sizeof(HashPageOpaqueData))) - ereport(ERROR, + ereport(WARNING, (errcode(ERRCODE_INDEX_CORRUPTED), - errmsg("index \"%s\" contains corrupted page at block %u", + errmsg("# 661(FATAL block=%d): index \"%s\" contains corrupted page at block %u", blkno, RelationGetRelationName(rel), BufferGetBlockNumber(buf)))); else diff --git a/contrib/xml2/Makefile b/contrib/xml2/Makefile index 0d703fe0e8f94..926649f63d3f2 100644 --- a/contrib/xml2/Makefile +++ b/contrib/xml2/Makefile @@ -11,7 +11,7 @@ DATA = xml2--1.1.sql xml2--1.0--1.1.sql PGFILEDESC = "xml2 - XPath querying and XSLT" REGRESS = xml2 - +PG_CFLAGS=$(shell xml2-config --cflags) SHLIB_LINK += $(filter -lxslt, $(LIBS)) -lxml2 ifdef USE_PGXS diff --git a/src/backend/Makefile b/src/backend/Makefile index 84302cc6dab7b..dbc1d4a148f3a 100644 --- a/src/backend/Makefile +++ b/src/backend/Makefile @@ -37,9 +37,11 @@ LOCALOBJS += utils/probes.o endif endif -OBJS = \ +ONLYOBJS = \ $(LOCALOBJS) \ - $(SUBDIROBJS) \ + $(SUBDIROBJS) +OBJS = \ + $(ONLYOBJS) \ $(top_builddir)/src/common/libpgcommon_srv.a \ $(top_builddir)/src/port/libpgport_srv.a @@ -60,6 +62,7 @@ override LDFLAGS := $(LDFLAGS) $(LDFLAGS_EX) $(LDFLAGS_EX_BE) all: submake-libpgport submake-catalog-headers submake-utils-headers postgres $(POSTGRES_IMP) +ifneq ($(PORTNAME), emscripten) ifneq ($(PORTNAME), cygwin) ifneq ($(PORTNAME), win32) @@ -68,6 +71,37 @@ postgres: $(OBJS) endif endif +endif + +ifeq ($(PORTNAME), emscripten) +AR ?= llvm-ar +LIBPGCORE ?= $(top_builddir)/libpgcore.a +LIBPG = $(top_builddir)/libpostgres.a +PGCORE = $(top_builddir)/src/common/libpgcommon_srv.a $(top_builddir)/src/port/libpgport_srv.a $(LIBPG) +PGMAIN = main/main.o tcop/postgres.o +postgres: $(OBJS) + $(AR) rcs $(top_builddir)/libpgmain.a $(PGMAIN) + $(AR) rcs $(LIBPG) $(filter-out $(PGMAIN),$(call expand_subsys,$(ONLYOBJS))) + $(CC) -r -o $(top_builddir)/libpgcore.o -Wl,--whole-archive $(PGCORE) + $(AR) rcs $(LIBPGCORE) $(top_builddir)/libpgcore.o + COPTS="$(LOPTS)" $(CC) $(MAIN_MODULE) $(CFLAGS) $(LDFLAGS) -o $@ $(LIBPGCORE) $(top_builddir)/libpgmain.a $(LIBS) +endif + +ifeq ($(PORTNAME), wasi) +AR ?= llvm-ar +LIBPGCORE ?= $(top_builddir)/libpgcore.a +LIBPG = $(top_builddir)/libpostgres.a +PGCORE = $(top_builddir)/src/common/libpgcommon_srv.a $(top_builddir)/src/port/libpgport_srv.a $(LIBPG) +PGMAIN = main/main.o tcop/postgres.o +postgres: $(OBJS) + $(AR) rcs $(top_builddir)/libpgmain.a $(PGMAIN) + $(AR) rcs $(LIBPG) $(filter-out $(PGMAIN),$(call expand_subsys,$(ONLYOBJS))) + $(CC) -r -o $(top_builddir)/libpgcore.o -Wl,--whole-archive $(PGCORE) + $(AR) rcs $(LIBPGCORE) $(top_builddir)/libpgcore.o + COPTS="$(LOPTS)" $(CC) $(MAIN_MODULE) $(CFLAGS) $(LDFLAGS) -nostartfiles -o $@ $(LIBPGCORE) $(top_builddir)/libpgmain.a $(LIBS) + mv $@ $@.wasi + touch $@ +endif ifeq ($(PORTNAME), cygwin) diff --git a/src/backend/access/nbtree/nbtutils.c b/src/backend/access/nbtree/nbtutils.c index 878f4b2e7b843..5c5061fbc709a 100644 --- a/src/backend/access/nbtree/nbtutils.c +++ b/src/backend/access/nbtree/nbtutils.c @@ -5163,7 +5163,7 @@ _bt_allequalimage(Relation rel, bool debugmessage) break; } } - +#if !defined(__EMSCRIPTEN__) if (debugmessage) { if (allequalimage) @@ -5173,6 +5173,6 @@ _bt_allequalimage(Relation rel, bool debugmessage) elog(DEBUG1, "index \"%s\" cannot use deduplication", RelationGetRelationName(rel)); } - +#endif return allequalimage; } diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c index 4cecf63006043..1c9dfc10184d0 100644 --- a/src/backend/access/transam/xact.c +++ b/src/backend/access/transam/xact.c @@ -1761,6 +1761,7 @@ RecordTransactionAbort(bool isSubXact) if (TransactionIdDidCommit(xid)) elog(PANIC, "cannot abort transaction %u, it was already committed", xid); + else elog(WARNING, "# 1743: aborting transaction %u", xid); /* * Are we using the replication origins feature? Or, in other words, are @@ -2804,7 +2805,9 @@ AbortTransaction(void) * handler. We do this fairly early in the sequence so that the timeout * infrastructure will be functional if needed while aborting. */ +#if !defined(__EMSCRIPTEN__) && !defined(__wasi__) sigprocmask(SIG_SETMASK, &UnBlockSig, NULL); +#endif /* * check the current transaction state @@ -5211,7 +5214,10 @@ AbortSubTransaction(void) * handler. We do this fairly early in the sequence so that the timeout * infrastructure will be functional if needed while aborting. */ +#if !defined(__EMSCRIPTEN__) && !defined(__wasi__) sigprocmask(SIG_SETMASK, &UnBlockSig, NULL); +#endif + /* * check the current transaction state diff --git a/src/backend/access/transam/xlogarchive.c b/src/backend/access/transam/xlogarchive.c index 81999b48200be..8e3b1f04c1d56 100644 --- a/src/backend/access/transam/xlogarchive.c +++ b/src/backend/access/transam/xlogarchive.c @@ -32,6 +32,10 @@ #include "storage/fd.h" #include "storage/ipc.h" +#if defined(__wasi__) +#define system(cmd) system_wasi(cmd) +#endif + /* * Attempt to retrieve the specified file from off-line archival storage. * If successful, fill "path" with its complete path (note that this will be diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c index 986f6f1d9ca07..8b226b212f5b3 100644 --- a/src/backend/bootstrap/bootstrap.c +++ b/src/backend/bootstrap/bootstrap.c @@ -195,7 +195,11 @@ CheckerModeMain(void) * to shared memory sizing, options work (or at least do not cause an error * up to shared memory creation). */ +#if !defined(__EMSCRIPTEN__) && !defined(__wasi__) void +#else +int +#endif BootstrapModeMain(int argc, char *argv[], bool check_only) { int i; @@ -365,7 +369,12 @@ BootstrapModeMain(int argc, char *argv[], bool check_only) /* Clean up and exit */ cleanup(); +#if !defined(__EMSCRIPTEN__) && !defined(__wasi__) proc_exit(0); +#else + puts("# 338 cleanup(boot): " __FILE__); + return 0; +#endif } diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index abd8eef08651a..225be70358437 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -2967,7 +2967,7 @@ index_build(Relation heapRelation, indexInfo->ii_ParallelWorkers = plan_create_index_workers(RelationGetRelid(heapRelation), RelationGetRelid(indexRelation)); - +#if !defined(__EMSCRIPTEN__) if (indexInfo->ii_ParallelWorkers == 0) ereport(DEBUG1, (errmsg_internal("building index \"%s\" on table \"%s\" serially", @@ -2979,7 +2979,7 @@ index_build(Relation heapRelation, RelationGetRelationName(indexRelation), RelationGetRelationName(heapRelation), indexInfo->ii_ParallelWorkers))); - +#endif /* * Switch to the table owner's userid, so that any index functions are run * as that user. Also lock down security-restricted operations and diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c index 3d7d1e9becad8..172692281bc29 100644 --- a/src/backend/commands/async.c +++ b/src/backend/commands/async.c @@ -1651,8 +1651,12 @@ SignalBackends(void) * NotifyQueueLock; which is unlikely but certainly possible. So we * just log a low-level debug message if it happens. */ +#if defined(__EMSCRIPTEN__) || defined(__wasi__) + HandleNotifyInterrupt(); +#else if (SendProcSignal(pid, PROCSIG_NOTIFY_INTERRUPT, procnos[i]) < 0) elog(DEBUG3, "could not signal backend with PID %d: %m", pid); +#endif } pfree(pids); diff --git a/src/backend/commands/collationcmds.c b/src/backend/commands/collationcmds.c index 63ef9a08411b0..3167e66ac6724 100644 --- a/src/backend/commands/collationcmds.c +++ b/src/backend/commands/collationcmds.c @@ -868,14 +868,14 @@ pg_import_system_collations(PG_FUNCTION_ARGS) maxaliases = 100; aliases = (CollAliasData *) palloc(maxaliases * sizeof(CollAliasData)); naliases = 0; - locale_a_handle = OpenPipeStream("locale -a", "r"); - if (locale_a_handle == NULL) + if (locale_a_handle == NULL) { + puts("======================== ERROR ================"); ereport(ERROR, (errcode_for_file_access(), errmsg("could not execute command \"%s\": %m", "locale -a"))); - + } while (fgets(localebuf, sizeof(localebuf), locale_a_handle)) { size_t len; diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c index 2505b3084b069..9db4495facea3 100644 --- a/src/backend/commands/dbcommands.c +++ b/src/backend/commands/dbcommands.c @@ -1834,8 +1834,9 @@ dropdb(const char *dbname, bool missing_ok, bool force) RequestCheckpoint(CHECKPOINT_IMMEDIATE | CHECKPOINT_FORCE | CHECKPOINT_WAIT); /* Close all smgr fds in all backends. */ +#if !defined(__wasi__) && !defined(__EMSCRIPTEN__) WaitForProcSignalBarrier(EmitProcSignalBarrier(PROCSIGNAL_BARRIER_SMGRRELEASE)); - +#endif /* * Remove all tablespace subdirs belonging to the database. */ diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c index 05a6de68ba3b0..a84cf281c5906 100644 --- a/src/backend/commands/event_trigger.c +++ b/src/backend/commands/event_trigger.c @@ -723,6 +723,7 @@ EventTriggerDDLCommandStart(Node *parsetree) List *runlist; EventTriggerData trigdata; +#if !defined(__EMSCRIPTEN__) && !defined(__wasi__) /* * Event Triggers are completely disabled in standalone mode. There are * (at least) two reasons for this: @@ -744,6 +745,10 @@ EventTriggerDDLCommandStart(Node *parsetree) */ if (!IsUnderPostmaster || !event_triggers) return; +#else + if (!event_triggers) + return; +#endif runlist = EventTriggerCommonSetup(parsetree, EVT_DDLCommandStart, @@ -773,14 +778,17 @@ EventTriggerDDLCommandEnd(Node *parsetree) { List *runlist; EventTriggerData trigdata; - +#if !defined(__EMSCRIPTEN__) && !defined(__wasi__) /* * See EventTriggerDDLCommandStart for a discussion about why event * triggers are disabled in single user mode or via GUC. */ if (!IsUnderPostmaster || !event_triggers) return; - +#else + if (!event_triggers) + return; +#endif /* * Also do nothing if our state isn't set up, which it won't be if there * weren't any relevant event triggers at the start of the current DDL @@ -821,14 +829,17 @@ EventTriggerSQLDrop(Node *parsetree) { List *runlist; EventTriggerData trigdata; - +#if !defined(__EMSCRIPTEN__) && !defined(__wasi__) /* * See EventTriggerDDLCommandStart for a discussion about why event * triggers are disabled in single user mode or via a GUC. */ if (!IsUnderPostmaster || !event_triggers) return; - +#else + if (!event_triggers) + return; +#endif /* * Use current state to determine whether this event fires at all. If * there are no triggers for the sql_drop event, then we don't have @@ -894,7 +905,7 @@ EventTriggerOnLogin(void) { List *runlist; EventTriggerData trigdata; - +#if !defined(__EMSCRIPTEN__) && !defined(__wasi__) /* * See EventTriggerDDLCommandStart for a discussion about why event * triggers are disabled in single user mode or via a GUC. We also need a @@ -903,7 +914,10 @@ EventTriggerOnLogin(void) if (!IsUnderPostmaster || !event_triggers || !OidIsValid(MyDatabaseId) || !MyDatabaseHasLoginEventTriggers) return; - +#else + if (!event_triggers || !OidIsValid(MyDatabaseId) || !MyDatabaseHasLoginEventTriggers) + return; +#endif StartTransactionCommand(); runlist = EventTriggerCommonSetup(NULL, EVT_Login, "login", @@ -1005,14 +1019,17 @@ EventTriggerTableRewrite(Node *parsetree, Oid tableOid, int reason) { List *runlist; EventTriggerData trigdata; - +#if !defined(__EMSCRIPTEN__) && !defined(__wasi__) /* * See EventTriggerDDLCommandStart for a discussion about why event * triggers are disabled in single user mode or via a GUC. */ if (!IsUnderPostmaster || !event_triggers) return; - +#else + if (!event_triggers) + return; +#endif /* * Also do nothing if our state isn't set up, which it won't be if there * weren't any relevant event triggers at the start of the current DDL diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c index 2b607c52704ca..08d9aa466ad5b 100644 --- a/src/backend/libpq/auth.c +++ b/src/backend/libpq/auth.c @@ -1875,7 +1875,7 @@ auth_peer(hbaPort *port) return STATUS_ERROR; } -#ifndef WIN32 +#if !defined(WIN32) && !defined(__wasi__) errno = 0; /* clear errno before call */ pw = getpwuid(uid); if (!pw) diff --git a/src/backend/libpq/be-fsstubs.c b/src/backend/libpq/be-fsstubs.c index 27d317dfdc087..afc579fd20683 100644 --- a/src/backend/libpq/be-fsstubs.c +++ b/src/backend/libpq/be-fsstubs.c @@ -150,8 +150,12 @@ be_lo_close(PG_FUNCTION_ARGS) * *****************************************************************************/ +#if defined(__EMSCRIPTEN__) || defined(__wasi__) +static int +#else int -lo_read(int fd, char *buf, int len) +#endif +lo_read3(int fd, char *buf, int len) { int status; LargeObjectDesc *lobj; @@ -178,8 +182,12 @@ lo_read(int fd, char *buf, int len) return status; } +#if defined(__EMSCRIPTEN__) || defined(__wasi__) +static int +#else int -lo_write(int fd, const char *buf, int len) +#endif +lo_write3(int fd, const char *buf, int len) { int status; LargeObjectDesc *lobj; @@ -190,7 +198,7 @@ lo_write(int fd, const char *buf, int len) errmsg("invalid large-object descriptor: %d", fd))); lobj = cookies[fd]; - /* see comment in lo_read() */ + /* see comment in lo_read3() */ if ((lobj->flags & IFS_WRLOCK) == 0) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), @@ -365,7 +373,7 @@ be_loread(PG_FUNCTION_ARGS) len = 0; retval = (bytea *) palloc(VARHDRSZ + len); - totalread = lo_read(fd, VARDATA(retval), len); + totalread = lo_read3(fd, VARDATA(retval), len); SET_VARSIZE(retval, totalread + VARHDRSZ); PG_RETURN_BYTEA_P(retval); @@ -382,7 +390,7 @@ be_lowrite(PG_FUNCTION_ARGS) PreventCommandIfReadOnly("lowrite()"); bytestowrite = VARSIZE_ANY_EXHDR(wbuf); - totalwritten = lo_write(fd, VARDATA_ANY(wbuf), bytestowrite); + totalwritten = lo_write3(fd, VARDATA_ANY(wbuf), bytestowrite); PG_RETURN_INT32(totalwritten); } @@ -560,7 +568,7 @@ lo_truncate_internal(int32 fd, int64 len) errmsg("invalid large-object descriptor: %d", fd))); lobj = cookies[fd]; - /* see comment in lo_read() */ + /* see comment in lo_read3() */ if ((lobj->flags & IFS_WRLOCK) == 0) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index daa0696146d0e..f8233d225201f 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -122,10 +122,16 @@ static char *PqSendBuffer; static int PqSendBufferSize; /* Size send buffer */ static size_t PqSendPointer; /* Next index to store a byte in PqSendBuffer */ static size_t PqSendStart; /* Next index to send a byte in PqSendBuffer */ - +#if !defined(__EMSCRIPTEN__) && !defined(__wasi__) static char PqRecvBuffer[PQ_RECV_BUFFER_SIZE]; static int PqRecvPointer; /* Next index to read a byte from PqRecvBuffer */ static int PqRecvLength; /* End of data available in PqRecvBuffer */ +#else +static char PqRecvBuffer_static[PQ_RECV_BUFFER_SIZE]; +static char *PqRecvBuffer; +static int PqRecvPointer; +static int PqRecvLength; +#endif /* * Message status @@ -135,6 +141,7 @@ static bool PqCommReadingMsg; /* in the middle of reading a message */ /* Internal functions */ + static void socket_comm_reset(void); static void socket_close(int code, Datum arg); static void socket_set_nonblocking(bool nonblocking); @@ -148,9 +155,6 @@ static inline int internal_flush(void); static pg_noinline int internal_flush_buffer(const char *buf, size_t *start, size_t *end); -static int Lock_AF_UNIX(const char *unixSocketDir, const char *unixSocketPath); -static int Setup_AF_UNIX(const char *sock_path); - static const PQcommMethods PqCommSocketMethods = { .comm_reset = socket_comm_reset, .flush = socket_flush, @@ -160,6 +164,10 @@ static const PQcommMethods PqCommSocketMethods = { .putmessage_noblock = socket_putmessage_noblock }; +static int Lock_AF_UNIX(const char *unixSocketDir, const char *unixSocketPath); +static int Setup_AF_UNIX(const char *sock_path); + + const PQcommMethods *PqCommMethods = &PqCommSocketMethods; WaitEventSet *FeBeWaitSet; @@ -181,7 +189,7 @@ pq_init(ClientSocket *client_sock) port->sock = client_sock->sock; memcpy(&port->raddr.addr, &client_sock->raddr.addr, client_sock->raddr.salen); port->raddr.salen = client_sock->raddr.salen; - +#if !defined(__EMSCRIPTEN__) && !defined(__wasi__) /* fill in the server (local) address */ port->laddr.salen = sizeof(port->laddr.addr); if (getsockname(port->sock, @@ -273,14 +281,15 @@ pq_init(ClientSocket *client_sock) (void) pq_setkeepalivescount(tcp_keepalives_count, port); (void) pq_settcpusertimeout(tcp_user_timeout, port); } - +#endif /* WASM */ +PDEBUG("# 285:" __FILE__); /* initialize state variables */ PqSendBufferSize = PQ_SEND_BUFFER_SIZE; PqSendBuffer = MemoryContextAlloc(TopMemoryContext, PqSendBufferSize); PqSendPointer = PqSendStart = PqRecvPointer = PqRecvLength = 0; PqCommBusy = false; PqCommReadingMsg = false; - +#if !defined(__EMSCRIPTEN__) && !defined(__wasi__) /* set up process-exit hook to close the socket */ on_proc_exit(socket_close, 0); @@ -310,7 +319,12 @@ pq_init(ClientSocket *client_sock) MyLatch, NULL); AddWaitEventToSet(FeBeWaitSet, WL_POSTMASTER_DEATH, PGINVALID_SOCKET, NULL, NULL); - +#else /* WASM */ + PDEBUG("# 220: FIXME: socketfile"); + #pragma message "FIXME: socketfile" + /* because we fill before starting reading message */ + PqRecvBuffer = &PqRecvBuffer_static[0]; +#endif /* WASM */ /* * The event positions match the order we added them, but let's sanity * check them to be sure. @@ -730,7 +744,7 @@ Setup_AF_UNIX(const char *sock_path) Assert(Unix_socket_group); if (Unix_socket_group[0] != '\0') { -#ifdef WIN32 +#if defined(WIN32) || defined(__wasi__) elog(WARNING, "configuration item \"unix_socket_group\" is not supported on this platform"); #else char *endptr; @@ -1136,6 +1150,20 @@ pq_buffer_remaining_data(void) * This must be called before any of the pq_get* functions. * -------------------------------- */ +#if defined(I_EMSCRIPTEN) || defined(I_WASI) +EMSCRIPTEN_KEEPALIVE void +pq_recvbuf_fill(FILE* fp, int packetlen) { + fread( PqRecvBuffer, packetlen, 1, fp); + PqRecvPointer = 0; + PqRecvLength = packetlen; +#if PDEBUG + printf("# 1199: pq_recvbuf_fill cma_rsize=%d PqRecvLength=%d buf=%p reply=%p\n", cma_rsize, PqRecvLength, &PqRecvBuffer[0], &PqSendBuffer[0]); +#endif + +} +#endif +extern int cma_rsize; +static char * PqSendBuffer_save; void pq_startmsgread(void) { @@ -1147,7 +1175,29 @@ pq_startmsgread(void) ereport(FATAL, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("terminating connection because protocol synchronization was lost"))); +#if defined(I_EMSCRIPTEN) || defined(I_WASI) + if (!pq_buffer_remaining_data()) { + if (cma_rsize) { + PqRecvPointer = 0; + PqRecvLength = cma_rsize; + PqRecvBuffer = (char*)0x1; + + PqSendPointer = 0; + PqSendBuffer_save = PqSendBuffer; + PqSendBuffer = 2 + (char*)(cma_rsize); + PqSendBufferSize = (CMA_MB*1024*1024) - (int)(&PqSendBuffer[0]); + } else { + PqRecvBuffer = &PqRecvBuffer_static[0]; + if (PqSendBuffer_save) + PqSendBuffer=PqSendBuffer_save; + PqSendBufferSize = PQ_SEND_BUFFER_SIZE; + } + } +#if PDEBUG + printf("# 1199: pq_startmsgread cma_rsize=%d PqRecvLength=%d buf=%p reply=%p\n", cma_rsize, PqRecvLength, &PqRecvBuffer[0], &PqSendBuffer[0]); +#endif +#endif PqCommReadingMsg = true; } @@ -1270,7 +1320,55 @@ pq_getmessage(StringInfo s, int maxlen) return 0; } +#if defined(__EMSCRIPTEN__) || defined(__wasi__) +extern FILE* SOCKET_FILE; +extern int SOCKET_DATA; +static int +internal_putbytes(const char *s, size_t len) { + if (PqSendPointer >= PqSendBufferSize) { + fprintf(stderr, "# 1329: overflow %d >= %d cma_rsize=%d CMA=%d\n", PqSendPointer, PqSendBufferSize,cma_rsize, CMA_MB); + } + + if (!cma_rsize) { + int wc= fwrite(s, 1, len, SOCKET_FILE); + SOCKET_DATA+=wc; + } else { + size_t amount; + while (len > 0) { + /* If buffer is full, then flush it out */ + if (PqSendPointer >= PqSendBufferSize) { + socket_set_nonblocking(false); + if (internal_flush()) + return EOF; + } + amount = PqSendBufferSize - PqSendPointer; + if (amount > len) + amount = len; + memcpy(PqSendBuffer + PqSendPointer, s, amount); + PqSendPointer += amount; + s += amount; + len -= amount; + SOCKET_DATA+=amount; + } + } + return 0; +} + +static int +socket_flush(void) { + return internal_flush(); +} + +static int +internal_flush(void) { + /* no flush for raw wire */ + if (!cma_rsize) { + PqSendStart = PqSendPointer = 0; + } + return 0; +} +#else static inline int internal_putbytes(const char *s, size_t len) @@ -1421,7 +1519,7 @@ internal_flush_buffer(const char *buf, size_t *start, size_t *end) *start = *end = 0; return 0; } - +#endif /* wasm */ /* -------------------------------- * pq_flush_if_writable - flush pending output if writable without blocking * diff --git a/src/backend/port/posix_sema.c b/src/backend/port/posix_sema.c index 5886d2233f5bd..f7d5e2b2007f2 100644 --- a/src/backend/port/posix_sema.c +++ b/src/backend/port/posix_sema.c @@ -298,10 +298,16 @@ PGSemaphoreReset(PGSemaphore sema) * There's no direct API for this in POSIX, so we have to ratchet the * semaphore down to 0 with repeated trywait's. */ +#if defined(__EMSCRIPTEN__) || defined(__wasi__) + sem_trywait(PG_SEM_REF(sema)); + return; +#else for (;;) { if (sem_trywait(PG_SEM_REF(sema)) < 0) { + + if (errno == EAGAIN || errno == EDEADLK) break; /* got it down to 0 */ if (errno == EINTR) @@ -309,6 +315,7 @@ PGSemaphoreReset(PGSemaphore sema) elog(FATAL, "sem_trywait failed: %m"); } } +#endif } /* diff --git a/src/backend/port/sysv_shmem.c b/src/backend/port/sysv_shmem.c index 362a37d3b3a21..c11f963ab6f6d 100644 --- a/src/backend/port/sysv_shmem.c +++ b/src/backend/port/sysv_shmem.c @@ -17,8 +17,8 @@ * *------------------------------------------------------------------------- */ +#define PG_SHMEM #include "postgres.h" - #include #include #include @@ -700,12 +700,47 @@ PGShmemHeader * PGSharedMemoryCreate(Size size, PGShmemHeader **shim) { - IpcMemoryKey NextShmemSegID; - void *memAddress; + IpcMemoryKey NextShmemSegID = 0; + void *memAddress = NULL; PGShmemHeader *hdr; struct stat statbuf; Size sysvsize; +/* + puts("@\n@\n@\n@\n@\n@\n PGSharedMemoryCreate @\n@\n@\n@\n@\n@\n"); + + elog(NOTICE, "Init WASM shared memory"); + + hdr = (PGShmemHeader *) malloc(size); + hdr->creatorPID = getpid(); + hdr->magic = PGShmemMagic; + hdr->dsm_control = 0; + + + hdr->device = statbuf.st_dev; + hdr->inode = statbuf.st_ino; + + hdr->totalsize = size; + hdr->freeoffset = MAXALIGN(sizeof(PGShmemHeader)); + *shim = hdr; + + UsedShmemSegAddr = memAddress; + UsedShmemSegID = (unsigned long) NextShmemSegID; + + if (AnonymousShmem == NULL) + return hdr; + memcpy(AnonymousShmem, hdr, sizeof(PGShmemHeader)); + return (PGShmemHeader *) AnonymousShmem; +*/ + + + + + + + + + /* * We use the data directory's ID info (inode and device numbers) to * positively identify shmem segments associated with this data dir, and diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c index 199f008bcda81..f8e3f4ed102c6 100644 --- a/src/backend/postmaster/checkpointer.c +++ b/src/backend/postmaster/checkpointer.c @@ -947,7 +947,9 @@ RequestCheckpoint(int flags) /* * If in a standalone backend, just do it ourselves. */ +#if !defined(__wasi__) && !defined(__EMSCRIPTEN__) if (!IsPostmasterEnvironment) +#endif { /* * There's no point in doing slow checkpoints in a standalone backend, diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index d032091495b1e..12623d4e444e9 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -1439,7 +1439,7 @@ getInstallationPaths(const char *argv0) /* Locate the postgres executable itself */ if (find_my_exec(argv0, my_exec_path) < 0) ereport(FATAL, - (errmsg("%s: could not locate my own executable path", argv0))); + (errmsg("%s:1536: could not locate my own executable path", argv0))); #ifdef EXEC_BACKEND /* Locate executable backend before we change working directory */ diff --git a/src/backend/storage/file/fd.c b/src/backend/storage/file/fd.c index a7c05b0a6fd86..d7a35c655773d 100644 --- a/src/backend/storage/file/fd.c +++ b/src/backend/storage/file/fd.c @@ -69,7 +69,7 @@ * *------------------------------------------------------------------------- */ - +#define PG_FD #include "postgres.h" #include @@ -524,6 +524,11 @@ pg_file_exists(const char *name) void pg_flush_data(int fd, off_t offset, off_t nbytes) { +#if defined(__EMSCRIPTEN__) || defined(__wasi__) + //int res = sync_file_range(fd, offset, nbytes, SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE | SYNC_FILE_RANGE_WAIT_AFTER); + (void)fsync(fd); + // fprintf(stderr, "# pg_flush_data(int fd=%d, off_t offset=%lld, off_t nbytes=%lld res=%d\n", fd,offset,nbytes, res); +#else /* * Right now file flushing is primarily used to avoid making later * fsync()/fdatasync() calls have less impact. Thus don't trigger flushes @@ -694,6 +699,7 @@ pg_flush_data(int fd, off_t offset, off_t nbytes) return; } #endif +#endif /* wasm */ } /* @@ -706,7 +712,7 @@ pg_ftruncate(int fd, off_t length) retry: ret = ftruncate(fd, length); - +printf("# 670 pg_ftruncate(int fd=%d, off_t length=%lld)=%d\n" __FILE__, fd, length, ret); if (ret == -1 && errno == EINTR) goto retry; @@ -738,7 +744,7 @@ pg_truncate(const char *path, off_t length) retry: ret = truncate(path, length); - +printf("# 670 pg_truncate(path=%s, off_t length=%lld)=%d\n" __FILE__, path, length, ret); if (ret == -1 && errno == EINTR) goto retry; #endif @@ -2672,7 +2678,7 @@ OpenTransientFilePerm(const char *fileName, int fileFlags, mode_t fileMode) return -1; /* failure */ } - +#if !defined(__EMSCRIPTEN__) && !defined(__wasi__) /* * Routines that want to initiate a pipe stream should use OpenPipeStream * rather than plain popen(). This lets fd.c deal with freeing FDs if @@ -2732,7 +2738,7 @@ OpenPipeStream(const char *command, const char *mode) return NULL; } - +#endif /* * Free an AllocateDesc of any type. * diff --git a/src/backend/storage/ipc/ipc.c b/src/backend/storage/ipc/ipc.c index b06e4b845288e..89f9e7355e80e 100644 --- a/src/backend/storage/ipc/ipc.c +++ b/src/backend/storage/ipc/ipc.c @@ -103,6 +103,48 @@ static int on_proc_exit_index, void proc_exit(int code) { +#if defined(__EMSCRIPTEN__) || defined(__wasi__) + if (code==66) { + fprintf(stderr,"# 108:fake shutdown\n"); + proc_exit_inprogress = true; + InterruptPending = false; + ProcDiePending = false; + QueryCancelPending = false; + InterruptHoldoffCount = 1; + CritSectionCount = 0; + + error_context_stack = NULL; + debug_query_string = NULL; + + shmem_exit_inprogress = true; + int save_before_shmem_exit_index = before_shmem_exit_index; + while (--before_shmem_exit_index >= 0) { + if (before_shmem_exit_index!=4) { + printf("# skipped shmem_exit_index=%d/%d\n", before_shmem_exit_index, save_before_shmem_exit_index); + continue; + } else + printf("# before_shmem_exit_index=%d/%d\n", before_shmem_exit_index, save_before_shmem_exit_index); + before_shmem_exit_list[before_shmem_exit_index].function(code, before_shmem_exit_list[before_shmem_exit_index].arg); + } + before_shmem_exit_index = save_before_shmem_exit_index; + puts("# dsm_backend_shutdown ?"); + // dsm_backend_shutdown(); + shmem_exit_inprogress = false; + /* + + int save_on_proc_exit_index = on_proc_exit_index; + while (--on_proc_exit_index >= 0) { + printf("# on_proc_exit_list=%d/%d\n", on_proc_exit_list, save_on_proc_exit_index); + on_proc_exit_list[on_proc_exit_index].function(code, on_proc_exit_list[on_proc_exit_index].arg); + } + on_proc_exit_index = save_on_proc_exit_index; + */ + } else { + proc_exit_inprogress = true; + fprintf(stderr,"# proc_exit(%d) ignored at 118:%s\n",code, __FILE__); + } + return; +#endif /* not safe if forked by system(), etc. */ if (MyProcPid != (int) getpid()) elog(PANIC, "proc_exit() called in child process"); @@ -152,7 +194,6 @@ proc_exit(int code) #endif elog(DEBUG3, "exit(%d)", code); - exit(code); } @@ -228,7 +269,7 @@ void shmem_exit(int code) { shmem_exit_inprogress = true; - +if (code!=66){ /* * Call before_shmem_exit callbacks. * @@ -276,7 +317,7 @@ shmem_exit(int code) on_shmem_exit_list[on_shmem_exit_index].function(code, on_shmem_exit_list[on_shmem_exit_index].arg); on_shmem_exit_index = 0; - +} shmem_exit_inprogress = false; } @@ -364,6 +405,17 @@ before_shmem_exit(pg_on_exit_callback function, Datum arg) void on_shmem_exit(pg_on_exit_callback function, Datum arg) { +#if defined(__wasi__) || defined(__EMSCRIPTEN__) + if (!atexit_callback_setup) { + PDEBUG("# 410:" __FILE__ " on_shmem_exit(pg_on_exit_callback function, Datum arg) FIRST CALL"); + if (on_shmem_exit_index >= MAX_ON_EXITS) { + PDEBUG("# 412:" __FILE__ " on_shmem_exit(pg_on_exit_callback function, Datum arg) OVERFLOW"); + } + } else { + PDEBUG("# 415:" __FILE__ " on_shmem_exit(pg_on_exit_callback function, Datum arg) STUB"); + return; + } +#endif if (on_shmem_exit_index >= MAX_ON_EXITS) ereport(FATAL, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), diff --git a/src/backend/storage/ipc/latch.c b/src/backend/storage/ipc/latch.c index 2b4ded38893af..aeeab4544693f 100644 --- a/src/backend/storage/ipc/latch.c +++ b/src/backend/storage/ipc/latch.c @@ -231,6 +231,7 @@ ResourceOwnerForgetWaitEventSet(ResourceOwner owner, WaitEventSet *set) void InitializeLatchSupport(void) { +#if !defined(__wasi__) #if defined(WAIT_USE_SELF_PIPE) int pipefd[2]; @@ -340,6 +341,7 @@ InitializeLatchSupport(void) /* Ignore SIGURG, because we'll receive it via kqueue. */ pqsignal(SIGURG, SIG_IGN); #endif +#endif /* __wasi__ */ } void diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c index 4ed9cedcdd4e5..f4f73b0652ab4 100644 --- a/src/backend/storage/ipc/procsignal.c +++ b/src/backend/storage/ipc/procsignal.c @@ -416,6 +416,9 @@ WaitForProcSignalBarrier(uint64 generation) (errmsg("still waiting for backend with PID %d to accept ProcSignalBarrier", (int) slot->pss_pid))); oldval = pg_atomic_read_u64(&slot->pss_barrierGeneration); +#if defined(__EMSCRIPTEN__) || defined(__wasi__) + break; +#endif } ConditionVariableCancelSleep(); } diff --git a/src/backend/storage/ipc/signalfuncs.c b/src/backend/storage/ipc/signalfuncs.c index 88e9bf8125d11..2db7ccfa5edb7 100644 --- a/src/backend/storage/ipc/signalfuncs.c +++ b/src/backend/storage/ipc/signalfuncs.c @@ -98,7 +98,12 @@ pg_signal_backend(int pid, int sig) */ /* If we have setsid(), signal the backend's whole process group */ -#ifdef HAVE_SETSID +#if defined(__EMSCRIPTEN__) || defined(__wasi__) +# if PGDEBUG + printf("# 103: FIXME: kill(pid=%d, sig=%d) ", pid, sig); +# endif + if (0) +#elif defined(HAVE_SETSID) if (kill(-pid, sig)) #else if (kill(pid, sig)) @@ -106,7 +111,7 @@ pg_signal_backend(int pid, int sig) { /* Again, just a warning to allow loops */ ereport(WARNING, - (errmsg("could not send signal to process %d: %m", pid))); + (errmsg("# 109: could not send signal to process %d: %m", pid))); return SIGNAL_BACKEND_ERROR; } return SIGNAL_BACKEND_SUCCESS; diff --git a/src/backend/storage/ipc/sinvaladt.c b/src/backend/storage/ipc/sinvaladt.c index 271212987e0ce..2b37b1779558b 100644 --- a/src/backend/storage/ipc/sinvaladt.c +++ b/src/backend/storage/ipc/sinvaladt.c @@ -288,17 +288,20 @@ SharedInvalBackendInit(bool sendOnly) * set hasMessages appropriately. */ LWLockAcquire(SInvalWriteLock, LW_EXCLUSIVE); - +#if defined(__EMSCRIPTEN__) || defined(__wasi__) +#else oldPid = stateP->procPid; if (oldPid != 0) { + + elog(WARNING, "sinval slot for backend %d is already in use by process %d", + MyProcNumber, (int) oldPid); LWLockRelease(SInvalWriteLock); elog(ERROR, "sinval slot for backend %d is already in use by process %d", MyProcNumber, (int) oldPid); } - shmInvalBuffer->pgprocnos[shmInvalBuffer->numProcs++] = MyProcNumber; - +#endif /* Fetch next local transaction ID into local memory */ nextLocalTransactionId = stateP->nextLXID; diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c index b50e2eff21877..7f1b5faa2b713 100644 --- a/src/backend/storage/lmgr/proc.c +++ b/src/backend/storage/lmgr/proc.c @@ -307,7 +307,11 @@ InitProcess(void) elog(PANIC, "proc header uninitialized"); if (MyProc != NULL) - elog(ERROR, "you already exist"); +#if defined(__wasi__) || defined(__EMSCRIPTEN__) + elog(WARNING, "# 309: you already exist"); +#else + elog(ERROR, "# 309: you already exist"); +#endif /* * Decide which list should supply our PGPROC. This logic must match the @@ -538,7 +542,7 @@ InitAuxiliaryProcess(void) elog(PANIC, "proc header uninitialized"); if (MyProc != NULL) - elog(ERROR, "you already exist"); + elog(ERROR, "# 522: you already exist"); /* * We use the ProcStructLock to protect assignment and releasing of diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 9cd1d0abe35fb..767cda0ceebcd 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -107,6 +107,18 @@ int client_connection_check_interval = 0; /* flags for non-system relation kinds to restrict use */ int restrict_nonsystem_relation_kind; +#if (defined(__EMSCRIPTEN__) || defined(__wasi__)) +#if !defined(PGL_MAIN) + volatile int cma_rsize = 0; +#endif // PGL_MAIN +bool quote_all_identifiers = false; +FILE* SOCKET_FILE = NULL; +int SOCKET_DATA = 0; +#endif // WASM + + + + /* ---------------- * private typedefs etc * ---------------- @@ -4115,7 +4127,7 @@ process_postgres_switches(int argc, char *argv[], GucContext ctx, #endif } - +#if !defined(PGL_MAIN) /* * PostgresSingleUserMain * Entry point for single user mode. argc/argv are the command line @@ -5014,7 +5026,7 @@ PostgresMain(const char *dbname, const char *username) } } /* end of input-reading loop */ } - +#endif /* PGL_MAIN */ /* * Throw an error if we're a WAL sender process. * @@ -5134,7 +5146,7 @@ ShowUsage(const char *title) (long) sys.tv_sec, (long) sys.tv_usec); #ifndef WIN32 - +#if !defined(__wasi__) /* * The following rusage fields are not defined by POSIX, but they're * present on all current Unix-like systems so we use them without any @@ -5176,6 +5188,7 @@ ShowUsage(const char *title) r.ru_nvcsw - Save_r.ru_nvcsw, r.ru_nivcsw - Save_r.ru_nivcsw, r.ru_nvcsw, r.ru_nivcsw); +#endif /* !__wasi__ */ #endif /* !WIN32 */ /* remove trailing newline */ diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index fa66b8017edea..1b17405ae4f9f 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -804,7 +804,7 @@ standard_ProcessUtility(PlannedStmt *pstmt, ListenStmt *stmt = (ListenStmt *) parsetree; CheckRestrictedOperation("LISTEN"); - +#if !defined(__EMSCRIPTEN__) && !defined(__wasi__) /* * We don't allow LISTEN in background processes, as there is * no mechanism for them to collect NOTIFY messages, so they'd @@ -820,7 +820,7 @@ standard_ProcessUtility(PlannedStmt *pstmt, /* translator: %s is name of a SQL command, eg LISTEN */ errmsg("cannot execute %s within a background process", "LISTEN"))); - +#endif Async_Listen(stmt->conditionname); } break; diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 7d6d9141a9417..940ce9a8757bd 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -321,8 +321,9 @@ static SPIPlanPtr plan_getviewrule = NULL; static const char *const query_getviewrule = "SELECT * FROM pg_catalog.pg_rewrite WHERE ev_class = $1 AND rulename = $2"; /* GUC parameters */ +#if !defined(__EMSCRIPTEN__) && !defined(__wasi__) bool quote_all_identifiers = false; - +#endif /* ---------- * Local functions diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c index 948bec886a228..9fda7d0dfc0b9 100644 --- a/src/backend/utils/error/elog.c +++ b/src/backend/utils/error/elog.c @@ -348,12 +348,16 @@ errstart(int elevel, const char *domain) ErrorData *edata; bool output_to_server; bool output_to_client = false; +#if defined(__EMSCRIPTEN__) || defined(__wasi__) +# warning "FIXME: error levels" +#else int i; /* * Check some cases in which we want to promote an error into a more * severe error. None of this logic applies for non-error messages. */ + if (elevel >= ERROR) { /* @@ -394,7 +398,7 @@ errstart(int elevel, const char *domain) for (i = 0; i <= errordata_stack_depth; i++) elevel = Max(elevel, errordata[i].elevel); } - +#endif /* * Now decide whether we need to process this report at all; if it's * warning or less and not enabled for logging, just return false without @@ -539,6 +543,7 @@ errfinish(const char *filename, int lineno, const char *funcname) */ recursion_depth--; + fprintf(stderr, "# 549: PG_RE_THROW(ERROR : %d)\n", recursion_depth); PG_RE_THROW(); } @@ -587,7 +592,11 @@ errfinish(const char *filename, int lineno, const char *funcname) * FATAL termination. The postmaster may or may not consider this * worthy of panic, depending on which subprocess returns it. */ +#if defined(__EMSCRIPTEN__) || defined(__wasi__) + puts("# 599: proc_exit(FATAL) ignored"); +#else proc_exit(1); +#endif } if (elevel >= PANIC) @@ -697,6 +706,7 @@ errsave_finish(struct Node *context, const char *filename, int lineno, */ if (edata->elevel >= ERROR) { +puts("#712"); errfinish(filename, lineno, funcname); pg_unreachable(); } diff --git a/src/backend/utils/fmgr/dfmgr.c b/src/backend/utils/fmgr/dfmgr.c index 092004dcf3b3f..55c606dc74631 100644 --- a/src/backend/utils/fmgr/dfmgr.c +++ b/src/backend/utils/fmgr/dfmgr.c @@ -121,12 +121,15 @@ load_external_function(const char *filename, const char *funcname, /* Look up the function within the library. */ retval = dlsym(lib_handle, funcname); - +#if !defined(__wasi__) if (retval == NULL && signalNotFound) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("could not find function \"%s\" in file \"%s\"", funcname, fullname))); +#else + fprintf(stderr, "could not find function \"%s\" in file \"%s\" rv=%p snf=%b\n", funcname, fullname, retval, signalNotFound); +#endif pfree(fullname); return retval; diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c index 8ac8ecc0dbb9d..0590684a85980 100644 --- a/src/backend/utils/init/miscinit.c +++ b/src/backend/utils/init/miscinit.c @@ -144,7 +144,7 @@ InitPostmasterChild(void) * children, but for consistency we make all postmaster child processes do * this. */ -#ifdef HAVE_SETSID +#if defined(HAVE_SETSID) && !defined(__wasi__) if (setsid() < 0) elog(FATAL, "setsid() failed: %m"); #endif @@ -210,7 +210,7 @@ InitStandaloneProcess(const char *argv0) if (my_exec_path[0] == '\0') { if (find_my_exec(argv0, my_exec_path) < 0) - elog(FATAL, "%s: could not locate my own executable path", + elog(WARNING, "%s:212: could not locate my own executable path", argv0); } @@ -375,7 +375,7 @@ checkDataDir(void) * * XXX can we safely enable this check on Windows? */ -#if !defined(WIN32) && !defined(__CYGWIN__) +#if !defined(WIN32) && !defined(__CYGWIN__) && !defined(__EMSCRIPTEN__) && !defined(__wasi__) if (stat_buf.st_uid != geteuid()) ereport(FATAL, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), @@ -395,7 +395,7 @@ checkDataDir(void) * be proper support for Unix-y file permissions. Need to think of a * reasonable check to apply on Windows. */ -#if !defined(WIN32) && !defined(__CYGWIN__) +#if !defined(WIN32) && !defined(__CYGWIN__) && !defined(__EMSCRIPTEN__) && !defined(__wasi__) if (stat_buf.st_mode & PG_MODE_MASK_GROUP) ereport(FATAL, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), @@ -416,7 +416,7 @@ checkDataDir(void) * Suppress when on Windows, because there may not be proper support for * Unix-y file permissions. */ -#if !defined(WIN32) && !defined(__CYGWIN__) +#if !defined(WIN32) && !defined(__CYGWIN__) && !defined(__EMSCRIPTEN__) && !defined(__wasi__) SetDataDirectoryCreatePerm(stat_buf.st_mode); umask(pg_mode_mask); @@ -1266,7 +1266,13 @@ CreateLockFile(const char *filename, bool amPostmaster, * Think not to make the file protection weaker than 0600/0640. See * comments below. */ + +#if defined(__wasi__) +printf("# 1228: CreateLockFile(%s) w+ (forced)\n", filename); + fd = fileno(fopen(filename, "w+")); +#else fd = open(filename, O_RDWR | O_CREAT | O_EXCL, pg_file_create_mode); +#endif if (fd >= 0) break; /* Success; exit the retry loop */ diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c index 2ed7c7c02dbce..dc94e69b2ef95 100644 --- a/src/backend/utils/init/postinit.c +++ b/src/backend/utils/init/postinit.c @@ -13,6 +13,7 @@ * *------------------------------------------------------------------------- */ +#define PG_POSTINIT #include "postgres.h" #include @@ -734,6 +735,7 @@ BaseInit(void) * Be very careful with the order of calls in the InitPostgres function. * -------------------------------- */ + void InitPostgres(const char *in_dbname, Oid dboid, const char *username, Oid useroid, @@ -754,15 +756,15 @@ InitPostgres(const char *in_dbname, Oid dboid, * Once I have done this, I am visible to other backends! */ InitProcessPhase2(); - +puts("# 758:"__FILE__); /* * Initialize my entry in the shared-invalidation manager's array of * per-backend data. */ SharedInvalBackendInit(false); - +puts("# 764:"__FILE__); ProcSignalInit(); - +puts("# 766:"__FILE__); /* * Also set up timeout handlers needed for backend operation. We need * these in every case except bootstrap. @@ -896,8 +898,18 @@ InitPostgres(const char *in_dbname, Oid dboid, } else if (!IsUnderPostmaster) { +#if defined(__EMSCRIPTEN__) || defined(__wasi__) +if (!strcmp( username , WASM_USERNAME )) { +#endif InitializeSessionUserIdStandalone(); am_superuser = true; +#if defined(__EMSCRIPTEN__) || defined(__wasi__) +} else { + //puts("# 894: switching session id"); + InitializeSessionUserId(username, InvalidOid, false); + am_superuser = superuser(); +} +#endif if (!ThereIsAtLeastOneRole()) ereport(WARNING, (errcode(ERRCODE_UNDEFINED_OBJECT), @@ -1254,6 +1266,32 @@ InitPostgres(const char *in_dbname, Oid dboid, CommitTransactionCommand(); } +/* ========================================================================*/ +/* +void +ReInitPostgres(const char *in_dbname, Oid dboid, + const char *username, Oid useroid, + bool load_session_libraries, + bool override_allow_connections, + char *out_dbname) +{ + puts("ReInitPostgres:Begin"); + InitPostgres(in_dbname, dboid, username, useroid, load_session_libraries, override_allow_connections, out_dbname); + puts("ReInitPostgres:End"); +} +*/ +/* ========================================================================*/ + + + + + + + + + + + /* * Process any command-line switches and any additional GUC variable * settings passed in the startup packet. @@ -1360,14 +1398,15 @@ process_settings(Oid databaseid, Oid roleid) static void ShutdownPostgres(int code, Datum arg) { +puts("# 1348: " __FILE__); /* Make sure we've killed any active transaction */ AbortOutOfAnyTransaction(); - /* * User locks are not released by transaction end, so be sure to release * them explicitly. */ LockReleaseAll(USER_LOCKMETHOD, true); +puts("# 1356: " __FILE__); } diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 0831d45aba3ac..9da1fad9fcb64 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -1861,7 +1861,7 @@ SelectConfigFiles(const char *userDoption, const char *progname) * data_directory parameter is picked up to determine the data directory, * so that we can read the PG_AUTOCONF_FILENAME file next time. */ - ProcessConfigFile(PGC_POSTMASTER); +PDEBUG("# 1830 ProcessConfigFile(PGC_POSTMASTER);"); /* * If the data_directory GUC variable has been set, use that as DataDir; @@ -1902,7 +1902,7 @@ SelectConfigFiles(const char *userDoption, const char *progname) * since we have to determine the DataDir before we can find the autoconf * file, the alternatives seem worse.) */ - ProcessConfigFile(PGC_POSTMASTER); +PDEBUG("# 1871 ProcessConfigFile(PGC_POSTMASTER);"); /* * If timezone_abbreviations wasn't set in the configuration file, install diff --git a/src/backend/utils/misc/timeout.c b/src/backend/utils/misc/timeout.c index ec7e570920a5d..980a7de8ebf8d 100644 --- a/src/backend/utils/misc/timeout.c +++ b/src/backend/utils/misc/timeout.c @@ -110,10 +110,20 @@ find_active_timeout(TimeoutId id) * Insert specified timeout reason into the list of active timeouts * at the given index. */ + +bool insert_timeout_warned = false; static void insert_timeout(TimeoutId id, int index) { int i; +#if defined(__EMSCRIPTEN__) || defined(__wasi__) + if (!insert_timeout_warned) //(index<0) + { + insert_timeout_warned = true; + fprintf(stderr, "# 117(FATAL): insert_timeout(TimeoutId id=%d, int index=%d): " __FILE__ "\n", id, index); + } + return; +#endif if (index < 0 || index > num_active_timeouts) elog(FATAL, "timeout index %d out of range 0..%d", index, @@ -128,6 +138,7 @@ insert_timeout(TimeoutId id, int index) active_timeouts[index] = &all_timeouts[id]; num_active_timeouts++; + } /* @@ -209,6 +220,10 @@ enable_timeout(TimeoutId id, TimestampTz now, TimestampTz fin_time, static void schedule_alarm(TimestampTz now) { +#if defined(__wasi__) + puts("# 224: schedule_alarm(TimestampTz now)"); + (void)signal_due_at; +#else if (num_active_timeouts > 0) { struct itimerval timeval; @@ -347,6 +362,7 @@ schedule_alarm(TimestampTz now) elog(FATAL, "could not enable SIGALRM timer: %m"); } } +#endif } diff --git a/src/bin/pg_config/pg_config.c b/src/bin/pg_config/pg_config.c index 77d09ccfc47ca..1fc3e6298d532 100644 --- a/src/bin/pg_config/pg_config.c +++ b/src/bin/pg_config/pg_config.c @@ -152,7 +152,9 @@ main(int argc, char **argv) if (find_my_exec(argv[0], my_exec_path) < 0) { fprintf(stderr, _("%s: could not find own program executable\n"), progname); +#if !defined(__EMSCRIPTEN__) && !defined(__wasi__) exit(1); +#endif } configdata = get_configdata(my_exec_path, &configdata_len); @@ -162,6 +164,7 @@ main(int argc, char **argv) for (i = 0; i < configdata_len; i++) printf("%s = %s\n", configdata[i].name, configdata[i].setting); exit(0); + } /* otherwise print requested items */ diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c index ed97eb3f5042c..ab34be3fa779e 100644 --- a/src/bin/pg_ctl/pg_ctl.c +++ b/src/bin/pg_ctl/pg_ctl.c @@ -154,6 +154,16 @@ static bool wait_for_postmaster_stop(void); static bool wait_for_postmaster_promote(void); static bool postmaster_is_alive(pid_t pid); +#if defined(__wasi__) +#if defined(HAVE_SETSID) +#undef HAVE_SETSID +#endif + +#if defined(HAVE_GETRLIMIT) +#undef HAVE_GETRLIMIT +#endif +#endif /* __wasi__ */ + #if defined(HAVE_GETRLIMIT) static void unlimit_core_size(void); #endif @@ -492,9 +502,9 @@ start_postmaster(void) else cmd = psprintf("exec \"%s\" %s%s < \"%s\" 2>&1", exec_path, pgdata_opt, post_opts, DEVNULL); - +#if !defined(__wasi__) (void) execl("/bin/sh", "/bin/sh", "-c", cmd, (char *) NULL); - +#endif /* exec failed */ write_stderr(_("%s: could not start server: %m\n"), progname); diff --git a/src/bin/pg_dump/parallel.c b/src/bin/pg_dump/parallel.c index a09247fae47e3..c1b141a5c32cb 100644 --- a/src/bin/pg_dump/parallel.c +++ b/src/bin/pg_dump/parallel.c @@ -49,7 +49,7 @@ * The pstate->te[] entry for each worker is valid when it's in WRKR_WORKING * state, and must be NULL in other states. */ - +#define PG_DUMP_PARALLEL #include "postgres_fe.h" #ifndef WIN32 @@ -445,6 +445,7 @@ ShutdownWorkersHard(ParallelState *pstate) static void WaitForTerminatingWorkers(ParallelState *pstate) { +#if !defined(__wasi__) while (!HasEveryWorkerTerminated(pstate)) { ParallelSlot *slot = NULL; @@ -504,6 +505,7 @@ WaitForTerminatingWorkers(ParallelState *pstate) slot->workerStatus = WRKR_TERMINATED; pstate->te[j] = NULL; } +#endif /* __wasi__ */ } diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 85adb5dee7654..baa447a3e9d42 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -30,6 +30,13 @@ *------------------------------------------------------------------------- */ #include "postgres_fe.h" +#if !defined(__EMSCRIPTEN__) && !defined(__wasi__) +#ifdef quote_all_identifiers +#undef quote_all_identifiers +#endif +#define fe_utils_quote_all_identifiers quote_all_identifiers +static bool quote_all_identifiers; +#endif #include #include @@ -425,7 +432,7 @@ main(int argc, char **argv) {"lock-wait-timeout", required_argument, NULL, 2}, {"no-table-access-method", no_argument, &dopt.outputNoTableAm, 1}, {"no-tablespaces", no_argument, &dopt.outputNoTablespaces, 1}, - {"quote-all-identifiers", no_argument, "e_all_identifiers, 1}, + {"quote-all-identifiers", no_argument, &fe_utils_quote_all_identifiers, true}, {"load-via-partition-root", no_argument, &dopt.load_via_partition_root, 1}, {"role", required_argument, NULL, 3}, {"section", required_argument, NULL, 5}, @@ -452,7 +459,9 @@ main(int argc, char **argv) {NULL, 0, NULL, 0} }; - +#if defined(__wasi__) +chdir("/"); +#endif pg_logging_init(argv[0]); pg_logging_set_level(PG_LOG_WARNING); set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump")); @@ -834,9 +843,12 @@ main(int argc, char **argv) * Open the database using the Archiver, so it knows about it. Errors mean * death. */ +puts("# 813 : " __FILE__); + //setup(); ConnectDatabase(fout, &dopt.cparams, false); +puts("# 815 : " __FILE__); setup_connection(fout, dumpencoding, dumpsnapshot, use_role); - +puts("# 817 : " __FILE__); /* * On hot standbys, never try to dump unlogged table data, since it will * just throw an error. @@ -1191,9 +1203,10 @@ setup_connection(Archive *AH, const char *dumpencoding, const char *dumpsnapshot, char *use_role) { DumpOptions *dopt = AH->dopt; +puts("# 1164 : get_connection : "__FILE__); PGconn *conn = GetConnection(AH); const char *std_strings; - +puts("# 1164 : setup_connection"); PQclear(ExecuteSqlQueryForSingleRow(AH, ALWAYS_SECURE_SEARCH_PATH_SQL)); /* @@ -1281,8 +1294,8 @@ setup_connection(Archive *AH, const char *dumpencoding, /* * Quote all identifiers, if requested. */ - if (quote_all_identifiers) - ExecuteSqlStatement(AH, "SET quote_all_identifiers = true"); + if (fe_utils_quote_all_identifiers) + ExecuteSqlStatement(AH, "SET fe_utils_quote_all_identifiers = true"); /* * Adjust row-security mode, if supported. diff --git a/src/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.c index c0b8467a2fc72..ac1718b2647ce 100644 --- a/src/bin/pg_dump/pg_dumpall.c +++ b/src/bin/pg_dump/pg_dumpall.c @@ -14,7 +14,13 @@ */ #include "postgres_fe.h" - +#if !defined(__EMSCRIPTEN__) && !defined(__wasi__) +#ifdef quote_all_identifiers +#undef quote_all_identifiers +#endif +#define fe_utils_quote_all_identifiers quote_all_identifiers +static bool quote_all_identifiers; +#endif #include #include @@ -163,7 +169,7 @@ main(int argc, char *argv[]) {"lock-wait-timeout", required_argument, NULL, 2}, {"no-table-access-method", no_argument, &no_table_access_method, 1}, {"no-tablespaces", no_argument, &no_tablespaces, 1}, - {"quote-all-identifiers", no_argument, "e_all_identifiers, 1}, + {"quote-all-identifiers", no_argument, &fe_utils_quote_all_identifiers, true}, {"load-via-partition-root", no_argument, &load_via_partition_root, 1}, {"role", required_argument, NULL, 3}, {"use-set-session-authorization", no_argument, &use_setsessauth, 1}, @@ -439,7 +445,7 @@ main(int argc, char *argv[]) appendPQExpBufferStr(pgdumpopts, " --no-table-access-method"); if (no_tablespaces) appendPQExpBufferStr(pgdumpopts, " --no-tablespaces"); - if (quote_all_identifiers) + if (fe_utils_quote_all_identifiers) appendPQExpBufferStr(pgdumpopts, " --quote-all-identifiers"); if (load_via_partition_root) appendPQExpBufferStr(pgdumpopts, " --load-via-partition-root"); @@ -540,8 +546,8 @@ main(int argc, char *argv[]) } /* Force quoting of all identifiers if requested. */ - if (quote_all_identifiers) - executeCommand(conn, "SET quote_all_identifiers = true"); + if (fe_utils_quote_all_identifiers) + executeCommand(conn, "SET fe_utils_quote_all_identifiers = true"); fprintf(OPF, "--\n-- PostgreSQL database cluster dump\n--\n\n"); if (verbose) diff --git a/src/bin/pg_resetwal/pg_resetwal.c b/src/bin/pg_resetwal/pg_resetwal.c index e9dcb5a6d89d1..ebfe9256a819f 100644 --- a/src/bin/pg_resetwal/pg_resetwal.c +++ b/src/bin/pg_resetwal/pg_resetwal.c @@ -334,7 +334,7 @@ main(int argc, char *argv[]) * -- any other user won't have sufficient permissions to modify files in * the data directory. */ -#ifndef WIN32 +#if !defined(WIN32) && !defined(__EMSCRIPTEN__) && !defined(__wasi__) if (geteuid() == 0) { pg_log_error("cannot be executed by \"root\""); diff --git a/src/bin/pg_upgrade/parallel.c b/src/bin/pg_upgrade/parallel.c index 05313a9b15641..e19e2efb1fdbd 100644 --- a/src/bin/pg_upgrade/parallel.c +++ b/src/bin/pg_upgrade/parallel.c @@ -277,6 +277,7 @@ win32_transfer_all_new_dbs(transfer_thread_arg *args) bool reap_child(bool wait_for_child) { +#if !defined(__wasi__) #ifndef WIN32 int work_status; pid_t child; @@ -336,6 +337,6 @@ reap_child(bool wait_for_child) /* do this after job has been removed */ parallel_jobs--; - +#endif /* __wasi__ */ return true; } diff --git a/src/bin/pg_verifybackup/pg_verifybackup.c b/src/bin/pg_verifybackup/pg_verifybackup.c index d77e70fbe3874..f588d61c6fdff 100644 --- a/src/bin/pg_verifybackup/pg_verifybackup.c +++ b/src/bin/pg_verifybackup/pg_verifybackup.c @@ -1,1104 +1 @@ -/*------------------------------------------------------------------------- - * - * pg_verifybackup.c - * Verify a backup against a backup manifest. - * - * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * src/bin/pg_verifybackup/pg_verifybackup.c - * - *------------------------------------------------------------------------- - */ - -#include "postgres_fe.h" - -#include -#include -#include -#include - -#include "common/controldata_utils.h" -#include "common/hashfn_unstable.h" -#include "common/logging.h" -#include "common/parse_manifest.h" -#include "fe_utils/simple_list.h" -#include "getopt_long.h" -#include "pgtime.h" - -/* - * For efficiency, we'd like our hash table containing information about the - * manifest to start out with approximately the correct number of entries. - * There's no way to know the exact number of entries without reading the whole - * file, but we can get an estimate by dividing the file size by the estimated - * number of bytes per line. - * - * This could be off by about a factor of two in either direction, because the - * checksum algorithm has a big impact on the line lengths; e.g. a SHA512 - * checksum is 128 hex bytes, whereas a CRC-32C value is only 8, and there - * might be no checksum at all. - */ -#define ESTIMATED_BYTES_PER_MANIFEST_LINE 100 - -/* - * How many bytes should we try to read from a file at once? - */ -#define READ_CHUNK_SIZE (128 * 1024) - -/* - * Each file described by the manifest file is parsed to produce an object - * like this. - */ -typedef struct manifest_file -{ - uint32 status; /* hash status */ - const char *pathname; - size_t size; - pg_checksum_type checksum_type; - int checksum_length; - uint8 *checksum_payload; - bool matched; - bool bad; -} manifest_file; - -#define should_verify_checksum(m) \ - (((m)->matched) && !((m)->bad) && (((m)->checksum_type) != CHECKSUM_TYPE_NONE)) - -/* - * Define a hash table which we can use to store information about the files - * mentioned in the backup manifest. - */ -#define SH_PREFIX manifest_files -#define SH_ELEMENT_TYPE manifest_file -#define SH_KEY_TYPE const char * -#define SH_KEY pathname -#define SH_HASH_KEY(tb, key) hash_string(key) -#define SH_EQUAL(tb, a, b) (strcmp(a, b) == 0) -#define SH_SCOPE static inline -#define SH_RAW_ALLOCATOR pg_malloc0 -#define SH_DECLARE -#define SH_DEFINE -#include "lib/simplehash.h" - -/* - * Each WAL range described by the manifest file is parsed to produce an - * object like this. - */ -typedef struct manifest_wal_range -{ - TimeLineID tli; - XLogRecPtr start_lsn; - XLogRecPtr end_lsn; - struct manifest_wal_range *next; - struct manifest_wal_range *prev; -} manifest_wal_range; - -/* - * All the data parsed from a backup_manifest file. - */ -typedef struct manifest_data -{ - int version; - uint64 system_identifier; - manifest_files_hash *files; - manifest_wal_range *first_wal_range; - manifest_wal_range *last_wal_range; -} manifest_data; - -/* - * All of the context information we need while checking a backup manifest. - */ -typedef struct verifier_context -{ - manifest_data *manifest; - char *backup_directory; - SimpleStringList ignore_list; - bool exit_on_error; - bool saw_any_error; -} verifier_context; - -static manifest_data *parse_manifest_file(char *manifest_path); -static void verifybackup_version_cb(JsonManifestParseContext *context, - int manifest_version); -static void verifybackup_system_identifier(JsonManifestParseContext *context, - uint64 manifest_system_identifier); -static void verifybackup_per_file_cb(JsonManifestParseContext *context, - const char *pathname, size_t size, - pg_checksum_type checksum_type, - int checksum_length, - uint8 *checksum_payload); -static void verifybackup_per_wal_range_cb(JsonManifestParseContext *context, - TimeLineID tli, - XLogRecPtr start_lsn, - XLogRecPtr end_lsn); -static void report_manifest_error(JsonManifestParseContext *context, - const char *fmt,...) - pg_attribute_printf(2, 3) pg_attribute_noreturn(); - -static void verify_backup_directory(verifier_context *context, - char *relpath, char *fullpath); -static void verify_backup_file(verifier_context *context, - char *relpath, char *fullpath); -static void verify_control_file(const char *controlpath, - uint64 manifest_system_identifier); -static void report_extra_backup_files(verifier_context *context); -static void verify_backup_checksums(verifier_context *context); -static void verify_file_checksum(verifier_context *context, - manifest_file *m, char *fullpath, - uint8 *buffer); -static void parse_required_wal(verifier_context *context, - char *pg_waldump_path, - char *wal_directory); - -static void report_backup_error(verifier_context *context, - const char *pg_restrict fmt,...) - pg_attribute_printf(2, 3); -static void report_fatal_error(const char *pg_restrict fmt,...) - pg_attribute_printf(1, 2) pg_attribute_noreturn(); -static bool should_ignore_relpath(verifier_context *context, const char *relpath); - -static void progress_report(bool finished); -static void usage(void); - -static const char *progname; - -/* options */ -static bool show_progress = false; -static bool skip_checksums = false; - -/* Progress indicators */ -static uint64 total_size = 0; -static uint64 done_size = 0; - -/* - * Main entry point. - */ -int -main(int argc, char **argv) -{ - static struct option long_options[] = { - {"exit-on-error", no_argument, NULL, 'e'}, - {"ignore", required_argument, NULL, 'i'}, - {"manifest-path", required_argument, NULL, 'm'}, - {"no-parse-wal", no_argument, NULL, 'n'}, - {"progress", no_argument, NULL, 'P'}, - {"quiet", no_argument, NULL, 'q'}, - {"skip-checksums", no_argument, NULL, 's'}, - {"wal-directory", required_argument, NULL, 'w'}, - {NULL, 0, NULL, 0} - }; - - int c; - verifier_context context; - char *manifest_path = NULL; - bool no_parse_wal = false; - bool quiet = false; - char *wal_directory = NULL; - char *pg_waldump_path = NULL; - - pg_logging_init(argv[0]); - set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_verifybackup")); - progname = get_progname(argv[0]); - - memset(&context, 0, sizeof(context)); - - if (argc > 1) - { - if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0) - { - usage(); - exit(0); - } - if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0) - { - puts("pg_verifybackup (PostgreSQL) " PG_VERSION); - exit(0); - } - } - - /* - * Skip certain files in the toplevel directory. - * - * Ignore the backup_manifest file, because it's not included in the - * backup manifest. - * - * Ignore the pg_wal directory, because those files are not included in - * the backup manifest either, since they are fetched separately from the - * backup itself, and verified via a separate mechanism. - * - * Ignore postgresql.auto.conf, recovery.signal, and standby.signal, - * because we expect that those files may sometimes be created or changed - * as part of the backup process. For example, pg_basebackup -R will - * modify postgresql.auto.conf and create standby.signal. - */ - simple_string_list_append(&context.ignore_list, "backup_manifest"); - simple_string_list_append(&context.ignore_list, "pg_wal"); - simple_string_list_append(&context.ignore_list, "postgresql.auto.conf"); - simple_string_list_append(&context.ignore_list, "recovery.signal"); - simple_string_list_append(&context.ignore_list, "standby.signal"); - - while ((c = getopt_long(argc, argv, "ei:m:nPqsw:", long_options, NULL)) != -1) - { - switch (c) - { - case 'e': - context.exit_on_error = true; - break; - case 'i': - { - char *arg = pstrdup(optarg); - - canonicalize_path(arg); - simple_string_list_append(&context.ignore_list, arg); - break; - } - case 'm': - manifest_path = pstrdup(optarg); - canonicalize_path(manifest_path); - break; - case 'n': - no_parse_wal = true; - break; - case 'P': - show_progress = true; - break; - case 'q': - quiet = true; - break; - case 's': - skip_checksums = true; - break; - case 'w': - wal_directory = pstrdup(optarg); - canonicalize_path(wal_directory); - break; - default: - /* getopt_long already emitted a complaint */ - pg_log_error_hint("Try \"%s --help\" for more information.", progname); - exit(1); - } - } - - /* Get backup directory name */ - if (optind >= argc) - { - pg_log_error("no backup directory specified"); - pg_log_error_hint("Try \"%s --help\" for more information.", progname); - exit(1); - } - context.backup_directory = pstrdup(argv[optind++]); - canonicalize_path(context.backup_directory); - - /* Complain if any arguments remain */ - if (optind < argc) - { - pg_log_error("too many command-line arguments (first is \"%s\")", - argv[optind]); - pg_log_error_hint("Try \"%s --help\" for more information.", progname); - exit(1); - } - - /* Complain if the specified arguments conflict */ - if (show_progress && quiet) - pg_fatal("cannot specify both %s and %s", - "-P/--progress", "-q/--quiet"); - - /* Unless --no-parse-wal was specified, we will need pg_waldump. */ - if (!no_parse_wal) - { - int ret; - - pg_waldump_path = pg_malloc(MAXPGPATH); - ret = find_other_exec(argv[0], "pg_waldump", - "pg_waldump (PostgreSQL) " PG_VERSION "\n", - pg_waldump_path); - if (ret < 0) - { - char full_path[MAXPGPATH]; - - if (find_my_exec(argv[0], full_path) < 0) - strlcpy(full_path, progname, sizeof(full_path)); - - if (ret == -1) - pg_fatal("program \"%s\" is needed by %s but was not found in the same directory as \"%s\"", - "pg_waldump", "pg_verifybackup", full_path); - else - pg_fatal("program \"%s\" was found by \"%s\" but was not the same version as %s", - "pg_waldump", full_path, "pg_verifybackup"); - } - } - - /* By default, look for the manifest in the backup directory. */ - if (manifest_path == NULL) - manifest_path = psprintf("%s/backup_manifest", - context.backup_directory); - - /* By default, look for the WAL in the backup directory, too. */ - if (wal_directory == NULL) - wal_directory = psprintf("%s/pg_wal", context.backup_directory); - - /* - * Try to read the manifest. We treat any errors encountered while parsing - * the manifest as fatal; there doesn't seem to be much point in trying to - * verify the backup directory against a corrupted manifest. - */ - context.manifest = parse_manifest_file(manifest_path); - - /* - * Now scan the files in the backup directory. At this stage, we verify - * that every file on disk is present in the manifest and that the sizes - * match. We also set the "matched" flag on every manifest entry that - * corresponds to a file on disk. - */ - verify_backup_directory(&context, NULL, context.backup_directory); - - /* - * The "matched" flag should now be set on every entry in the hash table. - * Any entries for which the bit is not set are files mentioned in the - * manifest that don't exist on disk. - */ - report_extra_backup_files(&context); - - /* - * Now do the expensive work of verifying file checksums, unless we were - * told to skip it. - */ - if (!skip_checksums) - verify_backup_checksums(&context); - - /* - * Try to parse the required ranges of WAL records, unless we were told - * not to do so. - */ - if (!no_parse_wal) - parse_required_wal(&context, pg_waldump_path, wal_directory); - - /* - * If everything looks OK, tell the user this, unless we were asked to - * work quietly. - */ - if (!context.saw_any_error && !quiet) - printf(_("backup successfully verified\n")); - - return context.saw_any_error ? 1 : 0; -} - -/* - * Parse a manifest file and return a data structure describing the contents. - */ -static manifest_data * -parse_manifest_file(char *manifest_path) -{ - int fd; - struct stat statbuf; - off_t estimate; - uint32 initial_size; - manifest_files_hash *ht; - char *buffer; - int rc; - JsonManifestParseContext context; - manifest_data *result; - - int chunk_size = READ_CHUNK_SIZE; - - /* Open the manifest file. */ - if ((fd = open(manifest_path, O_RDONLY | PG_BINARY, 0)) < 0) - report_fatal_error("could not open file \"%s\": %m", manifest_path); - - /* Figure out how big the manifest is. */ - if (fstat(fd, &statbuf) != 0) - report_fatal_error("could not stat file \"%s\": %m", manifest_path); - - /* Guess how large to make the hash table based on the manifest size. */ - estimate = statbuf.st_size / ESTIMATED_BYTES_PER_MANIFEST_LINE; - initial_size = Min(PG_UINT32_MAX, Max(estimate, 256)); - - /* Create the hash table. */ - ht = manifest_files_create(initial_size, NULL); - - result = pg_malloc0(sizeof(manifest_data)); - result->files = ht; - context.private_data = result; - context.version_cb = verifybackup_version_cb; - context.system_identifier_cb = verifybackup_system_identifier; - context.per_file_cb = verifybackup_per_file_cb; - context.per_wal_range_cb = verifybackup_per_wal_range_cb; - context.error_cb = report_manifest_error; - - /* - * Parse the file, in chunks if necessary. - */ - if (statbuf.st_size <= chunk_size) - { - buffer = pg_malloc(statbuf.st_size); - rc = read(fd, buffer, statbuf.st_size); - if (rc != statbuf.st_size) - { - if (rc < 0) - pg_fatal("could not read file \"%s\": %m", manifest_path); - else - pg_fatal("could not read file \"%s\": read %d of %lld", - manifest_path, rc, (long long int) statbuf.st_size); - } - - /* Close the manifest file. */ - close(fd); - - /* Parse the manifest. */ - json_parse_manifest(&context, buffer, statbuf.st_size); - } - else - { - int bytes_left = statbuf.st_size; - JsonManifestParseIncrementalState *inc_state; - - inc_state = json_parse_manifest_incremental_init(&context); - - buffer = pg_malloc(chunk_size + 1); - - while (bytes_left > 0) - { - int bytes_to_read = chunk_size; - - /* - * Make sure that the last chunk is sufficiently large. (i.e. at - * least half the chunk size) so that it will contain fully the - * piece at the end with the checksum. - */ - if (bytes_left < chunk_size) - bytes_to_read = bytes_left; - else if (bytes_left < 2 * chunk_size) - bytes_to_read = bytes_left / 2; - rc = read(fd, buffer, bytes_to_read); - if (rc != bytes_to_read) - { - if (rc < 0) - pg_fatal("could not read file \"%s\": %m", manifest_path); - else - pg_fatal("could not read file \"%s\": read %lld of %lld", - manifest_path, - (long long int) (statbuf.st_size + rc - bytes_left), - (long long int) statbuf.st_size); - } - bytes_left -= rc; - json_parse_manifest_incremental_chunk(inc_state, buffer, rc, - bytes_left == 0); - } - - /* Release the incremental state memory */ - json_parse_manifest_incremental_shutdown(inc_state); - - close(fd); - } - - /* Done with the buffer. */ - pfree(buffer); - - return result; -} - -/* - * Report an error while parsing the manifest. - * - * We consider all such errors to be fatal errors. The manifest parser - * expects this function not to return. - */ -static void -report_manifest_error(JsonManifestParseContext *context, const char *fmt,...) -{ - va_list ap; - - va_start(ap, fmt); - pg_log_generic_v(PG_LOG_ERROR, PG_LOG_PRIMARY, gettext(fmt), ap); - va_end(ap); - - exit(1); -} - -/* - * Record details extracted from the backup manifest. - */ -static void -verifybackup_version_cb(JsonManifestParseContext *context, - int manifest_version) -{ - manifest_data *manifest = context->private_data; - - /* Validation will be at the later stage */ - manifest->version = manifest_version; -} - -/* - * Record details extracted from the backup manifest. - */ -static void -verifybackup_system_identifier(JsonManifestParseContext *context, - uint64 manifest_system_identifier) -{ - manifest_data *manifest = context->private_data; - - /* Validation will be at the later stage */ - manifest->system_identifier = manifest_system_identifier; -} - -/* - * Record details extracted from the backup manifest for one file. - */ -static void -verifybackup_per_file_cb(JsonManifestParseContext *context, - const char *pathname, size_t size, - pg_checksum_type checksum_type, - int checksum_length, uint8 *checksum_payload) -{ - manifest_data *manifest = context->private_data; - manifest_files_hash *ht = manifest->files; - manifest_file *m; - bool found; - - /* Make a new entry in the hash table for this file. */ - m = manifest_files_insert(ht, pathname, &found); - if (found) - report_fatal_error("duplicate path name in backup manifest: \"%s\"", - pathname); - - /* Initialize the entry. */ - m->size = size; - m->checksum_type = checksum_type; - m->checksum_length = checksum_length; - m->checksum_payload = checksum_payload; - m->matched = false; - m->bad = false; -} - -/* - * Record details extracted from the backup manifest for one WAL range. - */ -static void -verifybackup_per_wal_range_cb(JsonManifestParseContext *context, - TimeLineID tli, - XLogRecPtr start_lsn, XLogRecPtr end_lsn) -{ - manifest_data *manifest = context->private_data; - manifest_wal_range *range; - - /* Allocate and initialize a struct describing this WAL range. */ - range = palloc(sizeof(manifest_wal_range)); - range->tli = tli; - range->start_lsn = start_lsn; - range->end_lsn = end_lsn; - range->prev = manifest->last_wal_range; - range->next = NULL; - - /* Add it to the end of the list. */ - if (manifest->first_wal_range == NULL) - manifest->first_wal_range = range; - else - manifest->last_wal_range->next = range; - manifest->last_wal_range = range; -} - -/* - * Verify one directory. - * - * 'relpath' is NULL if we are to verify the top-level backup directory, - * and otherwise the relative path to the directory that is to be verified. - * - * 'fullpath' is the backup directory with 'relpath' appended; i.e. the actual - * filesystem path at which it can be found. - */ -static void -verify_backup_directory(verifier_context *context, char *relpath, - char *fullpath) -{ - DIR *dir; - struct dirent *dirent; - - dir = opendir(fullpath); - if (dir == NULL) - { - /* - * If even the toplevel backup directory cannot be found, treat this - * as a fatal error. - */ - if (relpath == NULL) - report_fatal_error("could not open directory \"%s\": %m", fullpath); - - /* - * Otherwise, treat this as a non-fatal error, but ignore any further - * errors related to this path and anything beneath it. - */ - report_backup_error(context, - "could not open directory \"%s\": %m", fullpath); - simple_string_list_append(&context->ignore_list, relpath); - - return; - } - - while (errno = 0, (dirent = readdir(dir)) != NULL) - { - char *filename = dirent->d_name; - char *newfullpath = psprintf("%s/%s", fullpath, filename); - char *newrelpath; - - /* Skip "." and ".." */ - if (filename[0] == '.' && (filename[1] == '\0' - || strcmp(filename, "..") == 0)) - continue; - - if (relpath == NULL) - newrelpath = pstrdup(filename); - else - newrelpath = psprintf("%s/%s", relpath, filename); - - if (!should_ignore_relpath(context, newrelpath)) - verify_backup_file(context, newrelpath, newfullpath); - - pfree(newfullpath); - pfree(newrelpath); - } - - if (closedir(dir)) - { - report_backup_error(context, - "could not close directory \"%s\": %m", fullpath); - return; - } -} - -/* - * Verify one file (which might actually be a directory or a symlink). - * - * The arguments to this function have the same meaning as the arguments to - * verify_backup_directory. - */ -static void -verify_backup_file(verifier_context *context, char *relpath, char *fullpath) -{ - struct stat sb; - manifest_file *m; - - if (stat(fullpath, &sb) != 0) - { - report_backup_error(context, - "could not stat file or directory \"%s\": %m", - relpath); - - /* - * Suppress further errors related to this path name and, if it's a - * directory, anything underneath it. - */ - simple_string_list_append(&context->ignore_list, relpath); - - return; - } - - /* If it's a directory, just recurse. */ - if (S_ISDIR(sb.st_mode)) - { - verify_backup_directory(context, relpath, fullpath); - return; - } - - /* If it's not a directory, it should be a plain file. */ - if (!S_ISREG(sb.st_mode)) - { - report_backup_error(context, - "\"%s\" is not a file or directory", - relpath); - return; - } - - /* Check whether there's an entry in the manifest hash. */ - m = manifest_files_lookup(context->manifest->files, relpath); - if (m == NULL) - { - report_backup_error(context, - "\"%s\" is present on disk but not in the manifest", - relpath); - return; - } - - /* Flag this entry as having been encountered in the filesystem. */ - m->matched = true; - - /* Check that the size matches. */ - if (m->size != sb.st_size) - { - report_backup_error(context, - "\"%s\" has size %lld on disk but size %zu in the manifest", - relpath, (long long int) sb.st_size, m->size); - m->bad = true; - } - - /* - * Validate the manifest system identifier, not available in manifest - * version 1. - */ - if (context->manifest->version != 1 && - strcmp(relpath, "global/pg_control") == 0) - verify_control_file(fullpath, context->manifest->system_identifier); - - /* Update statistics for progress report, if necessary */ - if (show_progress && !skip_checksums && should_verify_checksum(m)) - total_size += m->size; - - /* - * We don't verify checksums at this stage. We first finish verifying that - * we have the expected set of files with the expected sizes, and only - * afterwards verify the checksums. That's because computing checksums may - * take a while, and we'd like to report more obvious problems quickly. - */ -} - -/* - * Sanity check control file and validate system identifier against manifest - * system identifier. - */ -static void -verify_control_file(const char *controlpath, uint64 manifest_system_identifier) -{ - ControlFileData *control_file; - bool crc_ok; - - pg_log_debug("reading \"%s\"", controlpath); - control_file = get_controlfile_by_exact_path(controlpath, &crc_ok); - - /* Control file contents not meaningful if CRC is bad. */ - if (!crc_ok) - report_fatal_error("%s: CRC is incorrect", controlpath); - - /* Can't interpret control file if not current version. */ - if (control_file->pg_control_version != PG_CONTROL_VERSION) - report_fatal_error("%s: unexpected control file version", - controlpath); - - /* System identifiers should match. */ - if (manifest_system_identifier != control_file->system_identifier) - report_fatal_error("%s: manifest system identifier is %llu, but control file has %llu", - controlpath, - (unsigned long long) manifest_system_identifier, - (unsigned long long) control_file->system_identifier); - - /* Release memory. */ - pfree(control_file); -} - -/* - * Scan the hash table for entries where the 'matched' flag is not set; report - * that such files are present in the manifest but not on disk. - */ -static void -report_extra_backup_files(verifier_context *context) -{ - manifest_data *manifest = context->manifest; - manifest_files_iterator it; - manifest_file *m; - - manifest_files_start_iterate(manifest->files, &it); - while ((m = manifest_files_iterate(manifest->files, &it)) != NULL) - if (!m->matched && !should_ignore_relpath(context, m->pathname)) - report_backup_error(context, - "\"%s\" is present in the manifest but not on disk", - m->pathname); -} - -/* - * Verify checksums for hash table entries that are otherwise unproblematic. - * If we've already reported some problem related to a hash table entry, or - * if it has no checksum, just skip it. - */ -static void -verify_backup_checksums(verifier_context *context) -{ - manifest_data *manifest = context->manifest; - manifest_files_iterator it; - manifest_file *m; - uint8 *buffer; - - progress_report(false); - - buffer = pg_malloc(READ_CHUNK_SIZE * sizeof(uint8)); - - manifest_files_start_iterate(manifest->files, &it); - while ((m = manifest_files_iterate(manifest->files, &it)) != NULL) - { - if (should_verify_checksum(m) && - !should_ignore_relpath(context, m->pathname)) - { - char *fullpath; - - /* Compute the full pathname to the target file. */ - fullpath = psprintf("%s/%s", context->backup_directory, - m->pathname); - - /* Do the actual checksum verification. */ - verify_file_checksum(context, m, fullpath, buffer); - - /* Avoid leaking memory. */ - pfree(fullpath); - } - } - - pfree(buffer); - - progress_report(true); -} - -/* - * Verify the checksum of a single file. - */ -static void -verify_file_checksum(verifier_context *context, manifest_file *m, - char *fullpath, uint8 *buffer) -{ - pg_checksum_context checksum_ctx; - const char *relpath = m->pathname; - int fd; - int rc; - size_t bytes_read = 0; - uint8 checksumbuf[PG_CHECKSUM_MAX_LENGTH]; - int checksumlen; - - /* Open the target file. */ - if ((fd = open(fullpath, O_RDONLY | PG_BINARY, 0)) < 0) - { - report_backup_error(context, "could not open file \"%s\": %m", - relpath); - return; - } - - /* Initialize checksum context. */ - if (pg_checksum_init(&checksum_ctx, m->checksum_type) < 0) - { - report_backup_error(context, "could not initialize checksum of file \"%s\"", - relpath); - close(fd); - return; - } - - /* Read the file chunk by chunk, updating the checksum as we go. */ - while ((rc = read(fd, buffer, READ_CHUNK_SIZE)) > 0) - { - bytes_read += rc; - if (pg_checksum_update(&checksum_ctx, buffer, rc) < 0) - { - report_backup_error(context, "could not update checksum of file \"%s\"", - relpath); - close(fd); - return; - } - - /* Report progress */ - done_size += rc; - progress_report(false); - } - if (rc < 0) - report_backup_error(context, "could not read file \"%s\": %m", - relpath); - - /* Close the file. */ - if (close(fd) != 0) - { - report_backup_error(context, "could not close file \"%s\": %m", - relpath); - return; - } - - /* If we didn't manage to read the whole file, bail out now. */ - if (rc < 0) - return; - - /* - * Double-check that we read the expected number of bytes from the file. - * Normally, a file size mismatch would be caught in verify_backup_file - * and this check would never be reached, but this provides additional - * safety and clarity in the event of concurrent modifications or - * filesystem misbehavior. - */ - if (bytes_read != m->size) - { - report_backup_error(context, - "file \"%s\" should contain %zu bytes, but read %zu bytes", - relpath, m->size, bytes_read); - return; - } - - /* Get the final checksum. */ - checksumlen = pg_checksum_final(&checksum_ctx, checksumbuf); - if (checksumlen < 0) - { - report_backup_error(context, - "could not finalize checksum of file \"%s\"", - relpath); - return; - } - - /* And check it against the manifest. */ - if (checksumlen != m->checksum_length) - report_backup_error(context, - "file \"%s\" has checksum of length %d, but expected %d", - relpath, m->checksum_length, checksumlen); - else if (memcmp(checksumbuf, m->checksum_payload, checksumlen) != 0) - report_backup_error(context, - "checksum mismatch for file \"%s\"", - relpath); -} - -/* - * Attempt to parse the WAL files required to restore from backup using - * pg_waldump. - */ -static void -parse_required_wal(verifier_context *context, char *pg_waldump_path, - char *wal_directory) -{ - manifest_data *manifest = context->manifest; - manifest_wal_range *this_wal_range = manifest->first_wal_range; - - while (this_wal_range != NULL) - { - char *pg_waldump_cmd; - - pg_waldump_cmd = psprintf("\"%s\" --quiet --path=\"%s\" --timeline=%u --start=%X/%X --end=%X/%X\n", - pg_waldump_path, wal_directory, this_wal_range->tli, - LSN_FORMAT_ARGS(this_wal_range->start_lsn), - LSN_FORMAT_ARGS(this_wal_range->end_lsn)); - fflush(NULL); - if (system(pg_waldump_cmd) != 0) - report_backup_error(context, - "WAL parsing failed for timeline %u", - this_wal_range->tli); - - this_wal_range = this_wal_range->next; - } -} - -/* - * Report a problem with the backup. - * - * Update the context to indicate that we saw an error, and exit if the - * context says we should. - */ -static void -report_backup_error(verifier_context *context, const char *pg_restrict fmt,...) -{ - va_list ap; - - va_start(ap, fmt); - pg_log_generic_v(PG_LOG_ERROR, PG_LOG_PRIMARY, gettext(fmt), ap); - va_end(ap); - - context->saw_any_error = true; - if (context->exit_on_error) - exit(1); -} - -/* - * Report a fatal error and exit - */ -static void -report_fatal_error(const char *pg_restrict fmt,...) -{ - va_list ap; - - va_start(ap, fmt); - pg_log_generic_v(PG_LOG_ERROR, PG_LOG_PRIMARY, gettext(fmt), ap); - va_end(ap); - - exit(1); -} - -/* - * Is the specified relative path, or some prefix of it, listed in the set - * of paths to ignore? - * - * Note that by "prefix" we mean a parent directory; for this purpose, - * "aa/bb" is not a prefix of "aa/bbb", but it is a prefix of "aa/bb/cc". - */ -static bool -should_ignore_relpath(verifier_context *context, const char *relpath) -{ - SimpleStringListCell *cell; - - for (cell = context->ignore_list.head; cell != NULL; cell = cell->next) - { - const char *r = relpath; - char *v = cell->val; - - while (*v != '\0' && *r == *v) - ++r, ++v; - - if (*v == '\0' && (*r == '\0' || *r == '/')) - return true; - } - - return false; -} - -/* - * Print a progress report based on the global variables. - * - * Progress report is written at maximum once per second, unless the finished - * parameter is set to true. - * - * If finished is set to true, this is the last progress report. The cursor - * is moved to the next line. - */ -static void -progress_report(bool finished) -{ - static pg_time_t last_progress_report = 0; - pg_time_t now; - int percent_size = 0; - char totalsize_str[32]; - char donesize_str[32]; - - if (!show_progress) - return; - - now = time(NULL); - if (now == last_progress_report && !finished) - return; /* Max once per second */ - - last_progress_report = now; - percent_size = total_size ? (int) ((done_size * 100 / total_size)) : 0; - - snprintf(totalsize_str, sizeof(totalsize_str), UINT64_FORMAT, - total_size / 1024); - snprintf(donesize_str, sizeof(donesize_str), UINT64_FORMAT, - done_size / 1024); - - fprintf(stderr, - _("%*s/%s kB (%d%%) verified"), - (int) strlen(totalsize_str), - donesize_str, totalsize_str, percent_size); - - /* - * Stay on the same line if reporting to a terminal and we're not done - * yet. - */ - fputc((!finished && isatty(fileno(stderr))) ? '\r' : '\n', stderr); -} - -/* - * Print out usage information and exit. - */ -static void -usage(void) -{ - printf(_("%s verifies a backup against the backup manifest.\n\n"), progname); - printf(_("Usage:\n %s [OPTION]... BACKUPDIR\n\n"), progname); - printf(_("Options:\n")); - printf(_(" -e, --exit-on-error exit immediately on error\n")); - printf(_(" -i, --ignore=RELATIVE_PATH ignore indicated path\n")); - printf(_(" -m, --manifest-path=PATH use specified path for manifest\n")); - printf(_(" -n, --no-parse-wal do not try to parse WAL files\n")); - printf(_(" -P, --progress show progress information\n")); - printf(_(" -q, --quiet do not print any output, except for errors\n")); - printf(_(" -s, --skip-checksums skip checksum verification\n")); - printf(_(" -w, --wal-directory=PATH use specified path for WAL files\n")); - printf(_(" -V, --version output version information, then exit\n")); - printf(_(" -?, --help show this help, then exit\n")); - printf(_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); - printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL); -} +int main(int argc, char *argv[]){return 0;} diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c index f3f8fd0765ac7..3fb6a4c88c3fe 100644 --- a/src/bin/psql/command.c +++ b/src/bin/psql/command.c @@ -5242,6 +5242,10 @@ do_shell(const char *command) static bool do_watch(PQExpBuffer query_buf, double sleep, int iter, int min_rows) { +#if defined(__wasi__) + pg_log_error("#5150 wasi: could not set timer"); + return false; +#else long sleep_ms = (long) (sleep * 1000); printQueryOpt myopt = pset.popt; const char *strftime_fmt; @@ -5474,6 +5478,7 @@ do_watch(PQExpBuffer query_buf, double sleep, int iter, int min_rows) pg_free(title); return (res >= 0); +#endif /* __wasi__ */ } /* diff --git a/src/common/exec.c b/src/common/exec.c index 0bee19c1e539f..379a67994b182 100644 --- a/src/common/exec.c +++ b/src/common/exec.c @@ -22,7 +22,7 @@ * This should be harmless everywhere else. */ #define _DARWIN_BETTER_REALPATH - +#define PG_EXEC #ifndef FRONTEND #include "postgres.h" #else diff --git a/src/common/logging.c b/src/common/logging.c index e9a02e3e46a51..878853c1c4025 100644 --- a/src/common/logging.c +++ b/src/common/logging.c @@ -19,8 +19,9 @@ #include "common/logging.h" enum pg_log_level __pg_log_level; - +#if !defined(PGL_MAIN) static const char *progname; +#endif static int log_flags; static void (*log_pre_callback) (void); diff --git a/src/fe_utils/print.c b/src/fe_utils/print.c index d6c4d78f98161..8616b4fae2d81 100644 --- a/src/fe_utils/print.c +++ b/src/fe_utils/print.c @@ -15,6 +15,7 @@ * *------------------------------------------------------------------------- */ +#define FE_UTILS_PRINT #include "postgres_fe.h" #include diff --git a/src/fe_utils/string_utils.c b/src/fe_utils/string_utils.c index 8e062c70379a6..f2da2fc8425a3 100644 --- a/src/fe_utils/string_utils.c +++ b/src/fe_utils/string_utils.c @@ -24,7 +24,9 @@ static PQExpBuffer defaultGetLocalPQExpBuffer(void); /* Globals exported by this file */ -int quote_all_identifiers = 0; +bool fe_utils_quote_all_identifiers = false; + + PQExpBuffer (*getLocalPQExpBuffer) (void) = defaultGetLocalPQExpBuffer; static int fmtIdEncoding = -1; @@ -110,7 +112,7 @@ fmtIdEnc(const char *rawid, int encoding) * These checks need to match the identifier production in scan.l. Don't * use islower() etc. */ - if (quote_all_identifiers) + if (fe_utils_quote_all_identifiers) need_quotes = true; /* slightly different rules for first character */ else if (!((rawid[0] >= 'a' && rawid[0] <= 'z') || rawid[0] == '_')) diff --git a/src/include/bootstrap/bootstrap.h b/src/include/bootstrap/bootstrap.h index 73b78b31335d3..a48899dca4e40 100644 --- a/src/include/bootstrap/bootstrap.h +++ b/src/include/bootstrap/bootstrap.h @@ -32,8 +32,11 @@ extern PGDLLIMPORT Relation boot_reldesc; extern PGDLLIMPORT Form_pg_attribute attrtypes[MAXATTR]; extern PGDLLIMPORT int numattr; - +#if defined(__EMSCRIPTEN__) || defined(__wasi__) + int BootstrapModeMain(int argc, char *argv[], bool check_only); +#else extern void BootstrapModeMain(int argc, char *argv[], bool check_only) pg_attribute_noreturn(); +#endif extern void closerel(char *relname); extern void boot_openrel(char *relname); diff --git a/src/include/common/file_utils.h b/src/include/common/file_utils.h index e4339fb7b6c14..ad07b3cb0275f 100644 --- a/src/include/common/file_utils.h +++ b/src/include/common/file_utils.h @@ -33,11 +33,15 @@ typedef enum DataDirSyncMethod struct iovec; /* avoid including port/pg_iovec.h here */ #ifdef FRONTEND +#if !defined(fsync_fname) extern int fsync_fname(const char *fname, bool isdir); +#endif /* src/include/storage/fd.h */ extern void sync_pgdata(const char *pg_data, int serverVersion, DataDirSyncMethod sync_method); extern void sync_dir_recurse(const char *dir, DataDirSyncMethod sync_method); +#if !defined(durable_rename) extern int durable_rename(const char *oldfile, const char *newfile); +#endif /* src/include/storage/fd.h */ extern int fsync_parent_path(const char *fname); #endif diff --git a/src/include/common/logging.h b/src/include/common/logging.h index afbd9c059a952..999615e7aa0c7 100644 --- a/src/include/common/logging.h +++ b/src/include/common/logging.h @@ -91,7 +91,6 @@ void pg_logging_set_level(enum pg_log_level new_level); void pg_logging_increase_verbosity(void); void pg_logging_set_pre_callback(void (*cb) (void)); void pg_logging_set_locus_callback(void (*cb) (const char **filename, uint64 *lineno)); - void pg_log_generic(enum pg_log_level level, enum pg_log_part part, const char *pg_restrict fmt,...) pg_attribute_printf(3, 4); diff --git a/src/include/fe_utils/string_utils.h b/src/include/fe_utils/string_utils.h index 500f585a4a585..34c94e603e455 100644 --- a/src/include/fe_utils/string_utils.h +++ b/src/include/fe_utils/string_utils.h @@ -16,11 +16,16 @@ #ifndef STRING_UTILS_H #define STRING_UTILS_H +#if !defined(__wasi__) #include "libpq-fe.h" #include "pqexpbuffer.h" +#else +#include "../interfaces/libpq/libpq-fe.h" +#include "../interfaces/libpq/pqexpbuffer.h" +#endif /* Global variables controlling behavior of fmtId() and fmtQualifiedId() */ -extern PGDLLIMPORT int quote_all_identifiers; +extern PGDLLIMPORT bool quote_all_identifiers; extern PQExpBuffer (*getLocalPQExpBuffer) (void); /* Functions */ diff --git a/src/include/fmgr.h b/src/include/fmgr.h index ccb4070a25140..7c960bcc4af68 100644 --- a/src/include/fmgr.h +++ b/src/include/fmgr.h @@ -505,7 +505,10 @@ PG_MAGIC_FUNCTION_NAME(void) \ return &Pg_magic_data; \ } \ extern int no_such_variable - +#if defined(__wasi__) && !defined(__EMSCRIPTEN__) +#undef PG_MODULE_MAGIC +#define PG_MODULE_MAGIC +#endif /*------------------------------------------------------------------------- * Support routines and macros for callers of fmgr-compatible functions diff --git a/src/include/libpq/be-fsstubs.h b/src/include/libpq/be-fsstubs.h index 336b9cef12508..0d6c7124b5400 100644 --- a/src/include/libpq/be-fsstubs.h +++ b/src/include/libpq/be-fsstubs.h @@ -19,8 +19,10 @@ * Probably these should have had the underscore-free names, * but too late now... */ -extern int lo_read(int fd, char *buf, int len); -extern int lo_write(int fd, const char *buf, int len); +#if !defined(__EMSCRIPTEN__) && !defined(__wasi__) +extern int lo_read3(int fd, char *buf, int len); +extern int lo_write3(int fd, const char *buf, int len); +#endif /* * Cleanup LOs at xact commit/abort diff --git a/src/include/port/emscripten.h b/src/include/port/emscripten.h new file mode 100644 index 0000000000000..616a4f43f4ab4 --- /dev/null +++ b/src/include/port/emscripten.h @@ -0,0 +1,17 @@ +/* src/include/port/emscripten.h */ + +#ifndef I_EMSCRIPTEN +#define I_EMSCRIPTEN + +#if !defined(__cplusplus) +#include +#endif + +#include "/tmp/pglite/include/wasm_common.h" + + +#define BOOT_END_MARK "build indices" +#define FD_BUFFER_MAX 16384 + + +#endif // I_EMSCRIPTEN diff --git a/src/include/port/pg_pthread.h b/src/include/port/pg_pthread.h index d102ce9d6f33e..6922eb423b945 100644 --- a/src/include/port/pg_pthread.h +++ b/src/include/port/pg_pthread.h @@ -12,7 +12,9 @@ #ifndef PG_PTHREAD_H #define PG_PTHREAD_H - +#if defined(__wasi__) +#define PYDK +#endif /* __wasi__ */ #include #ifndef HAVE_PTHREAD_BARRIER_WAIT @@ -20,7 +22,7 @@ #ifndef PTHREAD_BARRIER_SERIAL_THREAD #define PTHREAD_BARRIER_SERIAL_THREAD (-1) #endif - +#if !defined(__wasi__) typedef struct pg_pthread_barrier { bool sense; /* we only need a one bit phase */ @@ -29,10 +31,12 @@ typedef struct pg_pthread_barrier pthread_mutex_t mutex; pthread_cond_t cond; } pthread_barrier_t; - extern int pthread_barrier_init(pthread_barrier_t *barrier, const void *attr, int count); +#else + extern int pthread_barrier_init(pthread_barrier_t *__restrict, const pthread_barrierattr_t *__restrict, unsigned); +#endif extern int pthread_barrier_wait(pthread_barrier_t *barrier); extern int pthread_barrier_destroy(pthread_barrier_t *barrier); diff --git a/src/include/port/wasi.h b/src/include/port/wasi.h new file mode 100644 index 0000000000000..4c3bba4e6e4a1 --- /dev/null +++ b/src/include/port/wasi.h @@ -0,0 +1,283 @@ +#ifndef I_WASI +#define I_WASI + +#undef HAVE_PTHREAD + +#if defined(HAVE_SETSID) +#undef HAVE_SETSID +#endif + +#if defined(HAVE_GETRLIMIT) +#undef HAVE_GETRLIMIT +#endif + + +#define PLATFORM_DEFAULT_SYNC_METHOD SYNC_METHOD_FDATASYNC + +#define EMSCRIPTEN_KEEPALIVE __attribute__((used)) +#define __declspec( dllimport ) __attribute__((used)) + +#define em_callback_func void +#define emscripten_set_main_loop(...) +#define emscripten_force_exit(...) +#define EM_JS(...) + +#include "/tmp/pglite/include/wasm_common.h" + + +static pid_t +fork(void) { + puts("# 31: fork -1"); + return -1; +} + +// ======== signal ======================== +#define SA_RESTART 4 +#define SIG_SETMASK 2 + +#define SIG_BLOCK 0 +#define SIG_UNBLOCK 1 + +/* A signal handler. */ +typedef void (*handler_t) (int signal); +typedef unsigned char sigset_t; +typedef void (*__sighandler_t) (int); + +struct sigaction { + __sighandler_t sa_handler; + unsigned long sa_flags; +#ifdef SA_RESTORER + __sigrestore_t sa_restorer; +#endif + sigset_t sa_mask; +}; +extern int sigemptyset(sigset_t *set); +extern int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact); +extern int sigdelset (sigset_t *set, int sig); +extern int sigfillset (sigset_t *set); +extern int sigprocmask (int operation, const sigset_t *set, sigset_t *old_set); +extern int sigaddset (sigset_t *set, int sig); + +// STUBS +extern int pthread_sigmask(int how, const sigset_t *set, sigset_t *oldset); +extern int sigismember(const sigset_t *set, int signum); +extern int sigpending(sigset_t *set); +extern int sigwait(const sigset_t *restrict set, int *restrict sig); + +// ==================================================== +// unistd +extern unsigned int alarm(unsigned int seconds); + +// ==================================================== + + +#include + +static int +sigsetjmp(sigjmp_buf env, int savesigs) { +// puts("# 120: sigsetjmp"); + return 0; +} + +static void +siglongjmp(sigjmp_buf env, int val) { + puts("# 120: siglongjmp"); +} + + + +// WIP : + +#include +static uid_t +getuid(void) { + return 1000; +} + +static int +dup(int fd) { + puts("# 128: dup"); + return fd; +} +static int +dup2(int old, int new) { + puts("# 140: dup2"); + return -1; +} +static int +pipe(int fd[2]) { + puts("# 145: pipe"); + abort(); + return -1; +} + +#include +#define RLIMIT_NOFILE 7 +#define RLIMIT_STACK 3 +#define RLIM_INFINITY ((unsigned long int)(~0UL)) + +struct rlimit { + unsigned long rlim_cur; + unsigned long rlim_max; +}; +static int +getrlimit(int resource, struct rlimit *rlim) { + return -1; +} + + +static const char *gai_strerror_msg = "# 165: gai_strerror_msg"; +static const char * +gai_strerror(int errcode) { + return gai_strerror_msg; +} + + +static int +getrusage(int who, struct rusage *usage) { + return -1; +} + +// WIP: semaphores here +// ================================================================== +#include + +static int +semctl(int semid, int semnum, int cmd, ...) { + return 0; // -1; +} + +static int +semget(key_t key, int nsems, int semflg) { +#if 0 // PGDEBUG + printf("# 213: semget(key_t key = %d, int nsems=%d, int semflg=%d)\n", key, nsems, semflg); +#endif + return 1; +} + +static int +semop(int semid, struct sembuf *sops, size_t nsops) { + return 0; // -1; +} + + + +#include +#if defined(PYDK) +extern int shm_open(const char *name, int oflag, mode_t mode); +extern int shm_unlink(const char *name); +#else +static int +shm_open(const char *name, int oflag, mode_t mode) { + char tmpnam[128]; + int fd; + snprintf(tmpnam, 128, "/tmp%s", name); + fd=fileno(fopen(tmpnam, "w+")); + fprintf(stderr, "# 212: shm_open(%s) => %d\n", tmpnam, fd); + return fd; +} + +static int +shm_unlink(const char *name) { + char tmpnam[128]; + snprintf(tmpnam, 128, "/tmp%s", name); + fprintf(stderr, "# 220: shm_unlink(%s) STUB\n", tmpnam); + return remove(tmpnam); // -1 +} + +#endif + +// initdb chmod +#if defined(__wasi__) + #define chmod(...) 0 +#endif + + + +#define system(command) system_wasi(command) +extern int system_wasi(const char *command); + + + +// time.h + +static void +tzset(void) { + puts("# 241: tzset(void) STUB"); +} + +#if defined(PG_INITDB) || defined(FE_UTILS_PRINT) || defined(PG_DUMP_PARALLEL) +static void +__SIG_IGN(int param) { +} +#endif + + +extern void sock_flush(); + + +// TODO: socket here +// ================================================================== + +#include + +extern ssize_t sdk_recv(int sockfd, void *buf, size_t len, int flags); +extern ssize_t recvfrom(int socket, void *buffer, size_t length, int flags, void *address, socklen_t *address_len); + +extern ssize_t sdk_send(int sockfd, const void *buf, size_t len, int flags); +extern ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, void *dest_addr, socklen_t addrlen); + +#define recv(sockfd, buf, len, flags) sdk_recv(sockfd, buf, len, flags) + + + + +static int +listen(int sockfd, int backlog) { + return 0; +} + +static struct group *_Nullable +getgrnam(const char *_Nullable name) { + return NULL; +} + +static int +getsockname(int sockfd, struct sockaddr *restrict addr, socklen_t *restrict addrlen) { + return -1; +} + +static int +getaddrinfo(const char *restrict node, + const char *restrict service, + void *restrict hints, + void **restrict res) { + puts("# 60: getaddrinfo"); + return -1; +} +static void +freeaddrinfo(void *res) { + puts("# 65: freeaddrinfo"); +} + +extern ssize_t recvfrom_bc(int socket, void *buffer, size_t length, int flags, void *address, socklen_t *address_len); + + +#define getpid sdk_getpid +extern pid_t sdk_getpid(void); + + +//#define pthread_mutex_lock(mut) sdk_pthread_mutex_lock(mut) +//extern int sdk_pthread_mutex_lock(void *mutex); + +/* + int pthread_mutex_lock(pthread_mutex_t *mutex); + int pthread_mutex_trylock(pthread_mutex_t *mutex); + int pthread_mutex_unlock(pthread_mutex_t *mutex); +*/ + + +#endif // I_WASI + + + diff --git a/src/include/port/wasm_common.h b/src/include/port/wasm_common.h new file mode 100644 index 0000000000000..00e68cadd77f1 --- /dev/null +++ b/src/include/port/wasm_common.h @@ -0,0 +1,240 @@ +#pragma once + +#define WAIT_USE_POLL 1 + +#define HAVE_LINUX_EIDRM_BUG +/* + * Set the default wal_sync_method to fdatasync. With recent Linux versions, + * xlogdefs.h's normal rules will prefer open_datasync, which (a) doesn't + * perform better and (b) causes outright failures on ext4 data=journal + * filesystems, because those don't support O_DIRECT. + */ +#define PLATFORM_DEFAULT_WAL_SYNC_METHOD WAL_SYNC_METHOD_FDATASYNC + +// force the name used with --single +#if !defined(WASM_USERNAME) +#define WASM_USERNAME "postgres" +#endif + + + +/* --------------- how to configure those when installed ? ---------------- */ + +// socket emulation via file, need to go in PGDATA for nodefs mount in web mode +#define PGS_ILOCK "/tmp/pglite/base/.s.PGSQL.5432.lock.in" +#define PGS_IN "/tmp/pglite/base/.s.PGSQL.5432.in" +#define PGS_OLOCK "/tmp/pglite/base/.s.PGSQL.5432.lock.out" +#define PGS_OUT "/tmp/pglite/base/.s.PGSQL.5432.out" + + + +#if defined(PG_PREFIX) +#define em_xstr(s) em_str(s) +#define em_str(s) #s +# define WASM_PREFIX em_xstr(PG_PREFIX) +# define PG_MAIN_INCLUDE em_xstr(PATCH_MAIN) +# define PG_PLUGIN_INCLUDE em_xstr(PATCH_PLUGIN +# undef PG_PREFIX +#else +# define WASM_PREFIX "/pgdata" +# define PG_MAIN_INCLUDE "/pgdata/pg_main.c" +# define PG_PLUGIN_INCLUDE "/pgdata/pg_plugin.h" +#endif + +#include "pg_debug.h" + +// #define COPY_INTERNAL +#define COPY_OFF +#define PGDLLIMPORT +#define PG_FORCE_DISABLE_INLINE + + +#define WASM_PGOPTS \ + "-c", "log_checkpoints=false",\ + "-c", "search_path=pg_catalog",\ + "-c", "exit_on_error=true",\ + "-c", "ignore_invalid_pages=on",\ + "-c", "temp_buffers=8MB",\ + "-c", "work_mem=4MB",\ + "-c", "fsync=on",\ + "-c", "synchronous_commit=on",\ + "-c", "wal_buffers=4MB",\ + "-c", "min_wal_size=80MB",\ + "-c", "shared_buffers=128MB" + +// we want client and server in the same lib for now. +#if defined(PG_INITDB) && defined(PG_MAIN) +extern const char *progname; +#endif + +// exported in ./src/fe_utils/string_utils.c +#include +extern PGDLLIMPORT bool fe_utils_quote_all_identifiers; + +extern int pg_char_to_encoding_private(const char *name); +extern const char *pg_encoding_to_char_private(int encoding); +extern int pg_valid_server_encoding_id_private(int encoding); + + +#if defined(pg_char_to_encoding) +#undef pg_char_to_encoding +#endif +#define pg_char_to_encoding(encoding) pg_char_to_encoding_private(encoding) + +#if defined(pg_encoding_to_char) +#undef pg_encoding_to_char +#endif +#define pg_encoding_to_char(encoding) pg_encoding_to_char_private(encoding) + +#if defined(pg_valid_server_encoding_id) +#undef pg_valid_server_encoding_id +#endif +#define pg_valid_server_encoding_id(encoding) pg_valid_server_encoding_id_private(encoding) + + +/* + * 'proc_exit' is a wasi system call, so change its name everywhere. + */ + +#define proc_exit(arg) pg_proc_exit(arg) + +/* +extern FILE* IDB_PIPE_FP; +extern int IDB_STAGE; +*/ +extern FILE* SOCKET_FILE; +extern int SOCKET_DATA; +extern int pgl_pclose(FILE *stream); +/* +#if !defined(PGL_MAIN) && !defined(PGL_INITDB_MAIN) +# if !defined(PG_EXEC) +extern int pgl_pclose(FILE *stream); +#define pclose(stream) pg_pclose(stream) +# else +#if 1 +#include +int +pg_pclose(FILE *stream) { + puts("# 118:" __FILE__ " int pg_pclose(FILE *stream) STUB"); + return 0; +} +#endif +# endif // PG_EXEC +#endif // pgl +*/ + +/* + * OpenPipeStream : another kind of pipe open in fd.c + * known to try "locale -a" from collationcmds.c when in initdb. + * + */ +#if defined(PG_FD) +#include // strlen +#include // access+F_OK +#include // FILE+fprintf + +FILE *wasm_OpenPipeStream(const char *command, const char *mode); +FILE * +wasm_OpenPipeStream(const char *command, const char *mode) { + + FILE *result = NULL; + const char *prefix = getenv("PGSYSCONFDIR"); + const char *locale = "/locale"; + char *localefile = malloc( strlen(prefix) + strlen(locale) + 1 ); + localefile = strcat(prefix,locale); +#if PGDEBUG + fprintf(stderr, "# 232:%s: OpenPipeStream(command=%s, mode=%s)\n#\tredirected to %s\n", __FILE__, command, mode, localefile); +#endif + if (localefile) { + if (access(localefile, F_OK) != 0) { + FILE *fakeloc = fopen(localefile, "w"); + { + const char* encoding = getenv("PGCLIENTENCODING"); + fprintf(fakeloc, "C\nC.%s\nPOSIX\n%s\n", encoding, encoding); + } + if (fakeloc) + fclose(fakeloc); + } + result = fopen(localefile, "r"); + free(localefile); + } + + return result; +} + +#else +# define OpenPipeStream(cmd, mode) wasm_OpenPipeStream(cmd, mode) +#endif + + + + + + +/* + * handle pg_shmem.c special case + */ + +#if defined(PG_SHMEM) +#include // print +#include // malloc +#include // SC_ +#include +#include + +/* + * Shared memory control operation. + */ + +//extern int shmctl (int __shmid, int __cmd, struct shmid_ds *__buf); + +int +shmctl (int __shmid, int __cmd, struct shmid_ds *__buf) { + printf("FIXME: int shmctl (int __shmid=%d, int __cmd=%d, struct shmid_ds *__buf=%p)\n", __shmid, __cmd, __buf); + return 0; +} + + +volatile void *FAKE_SHM ; +volatile key_t FAKE_KEY = 0; + +/* Get shared memory segment. */ +// extern int shmget (key_t __key, size_t __size, int __shmflg); +int +shmget (key_t __key, size_t __size, int __shmflg) { + printf("# FIXING: int shmget (key_t __key=%d, size_t __size=%zu, int __shmflg=%d) pagesize default=%d\n", __key, __size, __shmflg, getpagesize()); + if (!FAKE_KEY) { + FAKE_SHM = malloc(__size); + FAKE_KEY = 666; + return (int)FAKE_KEY; + } else { + printf("# ERROR: int shmget (key_t __key=%d, size_t __size=%zu, int __shmflg=%d)\n", __key, __size, __shmflg); + //abort(); + return (int)FAKE_KEY; + } + return -1; +} + +/* Attach shared memory segment. */ +// extern void *shmat (int __shmid, const void *__shmaddr, int __shmflg); +void *shmat (int __shmid, const void *__shmaddr, int __shmflg) { + printf("# FIXING: void *shmat (int __shmid=%d, const void *__shmaddr=%p, int __shmflg=%d)\n", __shmid, __shmaddr, __shmflg); + if (__shmid==666) { + return (void *)FAKE_SHM; + } else { + printf("# ERROR: void *shmat (int __shmid=%d, const void *__shmaddr=%p, int __shmflg=%d)\n", __shmid, __shmaddr, __shmflg); + abort(); + } + return NULL; +} + +/* Detach shared memory segment. */ +// extern int shmdt (const void *__shmaddr); +int +shmdt (const void *__shmaddr) { + puts("# FIXME: int shmdt (const void *__shmaddr)"); + return 0; +} + + +#endif // PG_SHMEM diff --git a/src/include/storage/dsm_impl.h b/src/include/storage/dsm_impl.h index 882269603daf7..5246c84161b75 100644 --- a/src/include/storage/dsm_impl.h +++ b/src/include/storage/dsm_impl.h @@ -23,20 +23,49 @@ * Determine which dynamic shared memory implementations will be supported * on this platform, and which one will be the default. */ +#if 0 // defined(__wasi__) || defined(__EMSCRIPTEN__) + #define DEFAULT_DYNAMIC_SHARED_MEMORY_TYPE DSM_IMPL_SYSV + #define USE_DSM_SYSV + extern PGDLLIMPORT int dynamic_shared_memory_type; + extern PGDLLIMPORT int min_dynamic_shared_memory; + #define PG_DYNSHMEM_DIR "/tmp/pglite" + #define PG_DYNSHMEM_MMAP_FILE_PREFIX "mmap." + +#elif 0 // defined(__wasi__) || defined(__EMSCRIPTEN__) + #define DEFAULT_DYNAMIC_SHARED_MEMORY_TYPE DSM_IMPL_MMAP + #define USE_DSM_MMAP + extern PGDLLIMPORT int dynamic_shared_memory_type; + extern PGDLLIMPORT int min_dynamic_shared_memory; + #define PG_DYNSHMEM_DIR "/tmp/pglite" + #define PG_DYNSHMEM_MMAP_FILE_PREFIX "mmap." + +#elif defined(__wasi__) || defined(__EMSCRIPTEN__) + #define DEFAULT_DYNAMIC_SHARED_MEMORY_TYPE DSM_IMPL_POSIX + #define USE_DSM_POSIX + extern PGDLLIMPORT int dynamic_shared_memory_type; + extern PGDLLIMPORT int min_dynamic_shared_memory; + #define PG_DYNSHMEM_DIR "/tmp/pglite" + #define PG_DYNSHMEM_MMAP_FILE_PREFIX "mmap." + +#else + #ifdef WIN32 -#define USE_DSM_WINDOWS -#define DEFAULT_DYNAMIC_SHARED_MEMORY_TYPE DSM_IMPL_WINDOWS +# define USE_DSM_WINDOWS +# define DEFAULT_DYNAMIC_SHARED_MEMORY_TYPE DSM_IMPL_WINDOWS #else -#ifdef HAVE_SHM_OPEN -#define USE_DSM_POSIX -#define DEFAULT_DYNAMIC_SHARED_MEMORY_TYPE DSM_IMPL_POSIX -#endif -#define USE_DSM_SYSV -#ifndef DEFAULT_DYNAMIC_SHARED_MEMORY_TYPE -#define DEFAULT_DYNAMIC_SHARED_MEMORY_TYPE DSM_IMPL_SYSV -#endif +# ifdef HAVE_SHM_OPEN +# define USE_DSM_POSIX +# define DEFAULT_DYNAMIC_SHARED_MEMORY_TYPE DSM_IMPL_POSIX +# endif +# define USE_DSM_SYSV +# ifndef DEFAULT_DYNAMIC_SHARED_MEMORY_TYPE +# define DEFAULT_DYNAMIC_SHARED_MEMORY_TYPE DSM_IMPL_SYSV +# endif #define USE_DSM_MMAP -#endif + +#endif /* defined(__wasi__) || defined(__EMSCRIPTEN__) */ + + /* GUC. */ extern PGDLLIMPORT int dynamic_shared_memory_type; @@ -50,7 +79,7 @@ extern PGDLLIMPORT int min_dynamic_shared_memory; */ #define PG_DYNSHMEM_DIR "pg_dynshmem" #define PG_DYNSHMEM_MMAP_FILE_PREFIX "mmap." - +#endif /* A "name" for a dynamic shared memory segment. */ typedef uint32 dsm_handle; diff --git a/src/include/storage/fd.h b/src/include/storage/fd.h index 1456ab383a424..880f53ace48e7 100644 --- a/src/include/storage/fd.h +++ b/src/include/storage/fd.h @@ -185,13 +185,23 @@ extern int pg_fdatasync(int fd); extern bool pg_file_exists(const char *name); extern void pg_flush_data(int fd, off_t offset, off_t nbytes); extern int pg_truncate(const char *path, off_t length); -extern void fsync_fname(const char *fname, bool isdir); +/* extern void fsync_fname(const char *fname, bool isdir); + * does not match ./src/common/file_utils.c + */ +extern void fd_fsync_fname(const char *fname, bool isdir); extern int fsync_fname_ext(const char *fname, bool isdir, bool ignore_perm, int elevel); -extern int durable_rename(const char *oldfile, const char *newfile, int elevel); + +/* extern int durable_rename(const char *oldfile, const char *newfile, int elevel); + * does not mach ./src/common/file_utils.c + */ +extern int fd_durable_rename(const char *oldfile, const char *newfile, int elevel); extern int durable_unlink(const char *fname, int elevel); extern void SyncDataDirectory(void); extern int data_sync_elevel(int elevel); +#define durable_rename(oldfile, newfile, elevel) fd_durable_rename(oldfile, newfile, elevel) +#define fsync_fname(fname, isdir) fd_fsync_fname(fname, isdir) + static inline ssize_t FileRead(File file, void *buffer, size_t amount, off_t offset, uint32 wait_event_info) diff --git a/src/include/storage/ipc.h b/src/include/storage/ipc.h index b2d062781ecdb..d5aebb72dc15b 100644 --- a/src/include/storage/ipc.h +++ b/src/include/storage/ipc.h @@ -64,8 +64,11 @@ typedef void (*shmem_startup_hook_type) (void); /* ipc.c */ extern PGDLLIMPORT bool proc_exit_inprogress; extern PGDLLIMPORT bool shmem_exit_inprogress; - +#if defined(__EMSCRIPTEN__) || defined(__wasi__) +extern void pg_proc_exit(int code); +#else extern void proc_exit(int code) pg_attribute_noreturn(); +#endif extern void shmem_exit(int code); extern void on_proc_exit(pg_on_exit_callback function, Datum arg); extern void on_shmem_exit(pg_on_exit_callback function, Datum arg); diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h index e54eca5b4891e..751a6a414ec83 100644 --- a/src/include/utils/elog.h +++ b/src/include/utils/elog.h @@ -137,6 +137,19 @@ struct Node; * prevents gcc from making the unreachability deduction at optlevel -O0. *---------- */ +#if defined(__EMSCRIPTEN__) || defined(__wasi__) +#define ereport_domain(elevel, domain, ...) \ + do { \ + pg_prevent_errno_in_scope(); \ + if (__builtin_constant_p(elevel) && (elevel) >= ERROR ? \ + errstart_cold(elevel, domain) : \ + errstart(elevel, domain)) \ + __VA_ARGS__, errfinish(__FILE__, __LINE__, __func__); \ + if (__builtin_constant_p(elevel) && (elevel) >= ERROR) \ + { puts("# 149:pg_unreachable():" __FILE__); pg_unreachable(); } \ + } while(0) + +#else #ifdef HAVE__BUILTIN_CONSTANT_P #define ereport_domain(elevel, domain, ...) \ do { \ @@ -159,7 +172,7 @@ struct Node; pg_unreachable(); \ } while(0) #endif /* HAVE__BUILTIN_CONSTANT_P */ - +#endif #define ereport(elevel, ...) \ ereport_domain(elevel, TEXTDOMAIN, __VA_ARGS__) diff --git a/src/include/utils/palloc.h b/src/include/utils/palloc.h index 773a5d2c34738..39f4e429ed7d8 100644 --- a/src/include/utils/palloc.h +++ b/src/include/utils/palloc.h @@ -56,7 +56,9 @@ typedef struct MemoryContextCallback * Avoid accessing it directly! Instead, use MemoryContextSwitchTo() * to change the setting. */ +#if !defined(PG_EXTERN) extern PGDLLIMPORT MemoryContext CurrentMemoryContext; +#endif /* * Flags for MemoryContextAllocExtended. @@ -118,7 +120,7 @@ extern pg_nodiscard void *repalloc_huge(void *pointer, Size size); * it's necessary to hide the inline definition of MemoryContextSwitchTo in * this scenario; hence the #ifndef FRONTEND. */ - +#if !defined(PG_EXTERN) #ifndef FRONTEND static inline MemoryContext MemoryContextSwitchTo(MemoryContext context) @@ -129,7 +131,8 @@ MemoryContextSwitchTo(MemoryContext context) return old; } #endif /* FRONTEND */ - +#else +#endif /* Registration of memory context reset/delete callbacks */ extern void MemoryContextRegisterResetCallback(MemoryContext context, MemoryContextCallback *cb); diff --git a/src/interfaces/libpq/fe-auth.c b/src/interfaces/libpq/fe-auth.c index 3b25d8afda475..ffc70150600e1 100644 --- a/src/interfaces/libpq/fe-auth.c +++ b/src/interfaces/libpq/fe-auth.c @@ -961,10 +961,10 @@ int pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn) { int oldmsglen; - +puts("965"); if (!check_expected_areq(areq, conn)) return STATUS_ERROR; - +puts("968"); switch (areq) { case AUTH_REQ_OK: @@ -1090,7 +1090,7 @@ pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn) case AUTH_REQ_PASSWORD: { char *password; - +puts("1094"); conn->password_needed = true; password = conn->connhost[conn->whichhost].password; if (password == NULL) @@ -1105,9 +1105,10 @@ pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn) { appendPQExpBufferStr(&conn->errorMessage, "fe_sendauth: error sending password authentication\n"); +puts("1109"); return STATUS_ERROR; } - +puts("1112"); /* We expect no further authentication requests. */ conn->client_finished_auth = true; break; @@ -1147,10 +1148,11 @@ pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn) break; default: +puts(" ----------- 1151 ---------------"); libpq_append_conn_error(conn, "authentication method %u not supported", areq); return STATUS_ERROR; } - +puts("1156"); return STATUS_OK; } @@ -1169,6 +1171,7 @@ char * pg_fe_getusername(uid_t user_id, PQExpBuffer errorMessage) { char *result = NULL; +#if !defined(__EMSCRIPTEN__) && !defined(__wasi__) const char *name = NULL; #ifdef WIN32 @@ -1192,7 +1195,9 @@ pg_fe_getusername(uid_t user_id, PQExpBuffer errorMessage) else if (errorMessage) appendPQExpBuffer(errorMessage, "%s\n", pwdbuf); #endif - +#else + const char *name = getenv("PGUSER"); +#endif if (name) { result = strdup(name); diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index 2f87961a71ede..bfc9b4929945b 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -2033,7 +2033,8 @@ PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions, static int connectNoDelay(PGconn *conn) { -#ifdef TCP_NODELAY +#if !defined(__EMSCRIPTEN__) && !defined(__wasi__) +#ifdef TCP_NODELAY int on = 1; if (setsockopt(conn->sock, IPPROTO_TCP, TCP_NODELAY, @@ -2047,7 +2048,7 @@ connectNoDelay(PGconn *conn) return 0; } #endif - +#endif return 1; } @@ -2168,6 +2169,9 @@ connectFailureMessage(PGconn *conn, int errorno) static int useKeepalives(PGconn *conn) { +#if defined(__EMSCRIPTEN__) || defined(__wasi__) +return 0; +#else int val; if (conn->keepalives == NULL) @@ -2177,6 +2181,7 @@ useKeepalives(PGconn *conn) return -1; return val != 0 ? 1 : 0; +#endif } #ifndef WIN32 @@ -2403,13 +2408,14 @@ pqConnectDBStart(PGconn *conn) * Nobody but developers should see this message, so we don't bother * translating it. */ +#if !defined(__EMSCRIPTEN__) && !defined(__wasi__) if (!pg_link_canary_is_frontend()) { appendPQExpBufferStr(&conn->errorMessage, "libpq is incorrectly linked to backend functions\n"); goto connect_errReturn; } - +#endif /* Ensure our buffers are empty */ conn->inStart = conn->inCursor = conn->inEnd = 0; conn->outCount = 0; @@ -2435,7 +2441,7 @@ pqConnectDBStart(PGconn *conn) /* Also reset the target_server_type state if needed */ if (conn->target_server_type == SERVER_TYPE_PREFER_STANDBY_PASS2) conn->target_server_type = SERVER_TYPE_PREFER_STANDBY; - +PDEBUG("# 2381: connectDBStart"); /* * The code for processing CONNECTION_NEEDED state is in PQconnectPoll(), * so that it can easily be re-executed if needed again during the @@ -2447,7 +2453,7 @@ pqConnectDBStart(PGconn *conn) return 1; connect_errReturn: - + PDEBUG("# 2395: CONNECTION_BAD"); /* * If we managed to open a socket, close it immediately rather than * waiting till PQfinish. (The application cannot have gotten the socket @@ -2474,7 +2480,7 @@ pqConnectDBComplete(PGconn *conn) int timeout = 0; int last_whichhost = -2; /* certainly different from whichhost */ int last_whichaddr = -2; /* certainly different from whichaddr */ - +PDEBUG("# 2420: connectDBComplete Begin " __FILE__ ); if (conn == NULL || conn->status == CONNECTION_BAD) return 0; @@ -2510,7 +2516,8 @@ pqConnectDBComplete(PGconn *conn) last_whichhost = conn->whichhost; last_whichaddr = conn->whichaddr; } - +printf("# 2476: switch (%d) PGRES_POLLING_OK=%d PGRES_POLLING_READING=%d PGRES_POLLING_WRITING=%d\n", flag, PGRES_POLLING_OK, PGRES_POLLING_READING,PGRES_POLLING_WRITING); +if(!flag) abort(); /* * Wait, if necessary. Note that the initial state (just after * PQconnectStart) is to wait for the socket to select for writing. @@ -2521,6 +2528,7 @@ pqConnectDBComplete(PGconn *conn) return 1; /* success! */ case PGRES_POLLING_READING: +#if !defined(__wasi__) ret = pqWaitTimed(1, 0, conn, end_time); if (ret == -1) { @@ -2538,9 +2546,11 @@ pqConnectDBComplete(PGconn *conn) conn->status = CONNECTION_BAD; return 0; } +#endif break; default: +PDEBUG("# 2508: CONNECTION_BAD"); /* Just in case we failed to set it in PQconnectPoll */ conn->status = CONNECTION_BAD; return 0; @@ -2548,6 +2558,7 @@ pqConnectDBComplete(PGconn *conn) if (ret == 1) /* connect_timeout elapsed */ { +PDEBUG("# 2535: timeout !"); /* * Give up on current server/address, try the next one. */ @@ -2607,11 +2618,13 @@ PQconnectPoll(PGconn *conn) /* Get the new data */ switch (conn->status) { +printf("# 2577: conn->status(%d)\n", conn->status ); /* * We really shouldn't have been polled in these two cases, but we * can handle it. */ case CONNECTION_BAD: +PDEBUG("# FSM2580: CONNECTION_BAD"); return PGRES_POLLING_FAILED; case CONNECTION_OK: return PGRES_POLLING_OK; @@ -2624,8 +2637,18 @@ PQconnectPoll(PGconn *conn) case CONNECTION_CHECK_STANDBY: { /* Load waiting data */ +#if defined(__wasi__) + puts("# 2597: CONNECTION_CHECK_STANDBY -> ?????"); int n = pqReadData(conn); + if (!n) { + puts("YIELD!"); + sched_yield(); + } + printf("# 2604: pqReadData-> %d\n", n); +#else +int n = pqReadData(conn); +#endif if (n < 0) goto error_return; if (n == 0) @@ -2654,10 +2677,11 @@ PQconnectPoll(PGconn *conn) keep_going: /* We will come back to here until there is * nothing left to do. */ - +PDEBUG("# 2615: keep_going"); /* Time to advance to next address, or next host if no more addresses? */ if (conn->try_next_addr) { +PDEBUG("# 2615: keep_going -> try_next_addr "); if (conn->whichaddr < conn->naddr) { conn->whichaddr++; @@ -2668,9 +2692,11 @@ PQconnectPoll(PGconn *conn) conn->try_next_addr = false; } + /* Time to advance to next connhost[] entry? */ if (conn->try_next_host) { +PDEBUG("# 2615: keep_going -> try_next_host "); pg_conn_host *ch; struct addrinfo hint; struct addrinfo *addrlist; @@ -3207,6 +3233,7 @@ PQconnectPoll(PGconn *conn) case CONNECTION_STARTED: { +puts("# 3168: CONNECTION_STARTED"); socklen_t optlen = sizeof(optval); /* @@ -3218,7 +3245,7 @@ PQconnectPoll(PGconn *conn) * Now check (using getsockopt) that there is not an error * state waiting for us on the socket. */ - +#if !defined(__wasi__) if (getsockopt(conn->sock, SOL_SOCKET, SO_ERROR, (char *) &optval, &optlen) == -1) { @@ -3305,6 +3332,9 @@ PQconnectPoll(PGconn *conn) /* * Make sure we can write before advancing to next step. */ +#else + PDEBUG("# 3142: CONNECTION_STARTED->CONNECTION_MADE getsockopt/getsockname skipped in " __FILE__); +#endif // __wasi__ conn->status = CONNECTION_MADE; return PGRES_POLLING_WRITING; } @@ -3338,7 +3368,7 @@ PQconnectPoll(PGconn *conn) return PGRES_POLLING_READING; } #endif - +puts("# 3263"); #ifdef USE_SSL /* @@ -3430,7 +3460,7 @@ PQconnectPoll(PGconn *conn) libpq_append_conn_error(conn, "out of memory"); goto error_return; } - +puts("# 3320"); /* * Send the startup packet. * @@ -3446,7 +3476,7 @@ PQconnectPoll(PGconn *conn) } free(startpacket); - +puts("# 3336"); conn->status = CONNECTION_AWAITING_RESPONSE; return PGRES_POLLING_READING; } @@ -3678,6 +3708,7 @@ PQconnectPoll(PGconn *conn) */ case CONNECTION_AWAITING_RESPONSE: { +puts("# 3609: CONNECTION_AWAITING_RESPONSE"); char beresp; int msgLength; int avail; @@ -3871,14 +3902,22 @@ PQconnectPoll(PGconn *conn) * Note that conn->pghost must be non-NULL if we are going to * avoid the Kerberos code doing a hostname look-up. */ + +if (!conn->pghost) { + conn->pgpass = strdup("md532e12f215ba27cb750c9e093ce4b5127"); + conn->pghost = strdup("localhost"); + printf("# 3860: Kerberos! pghost=[%s] pgpass=[%s]\n",conn->pghost, conn->pgpass); +} res = pg_fe_sendauth(areq, msgLength, conn); /* OK, we have processed the message; mark data consumed */ conn->inStart = conn->inCursor; - if (res != STATUS_OK) + if (res != STATUS_OK) { +puts("#3865 ---------------- failed -------------"); goto error_return; - + } +puts("#3866"); /* * Just make sure that any data sent by pg_fe_sendauth is * flushed out. Although this theoretically could block, it @@ -3906,6 +3945,7 @@ PQconnectPoll(PGconn *conn) case CONNECTION_AUTH_OK: { +puts("# 3876: CONNECTION_AUTH_OK"); /* * Now we expect to hear from the backend. A ReadyForQuery * message indicates that startup is successful, but we might @@ -3977,6 +4017,7 @@ PQconnectPoll(PGconn *conn) case CONNECTION_CHECK_TARGET: { +puts("# 3947: CONNECTION_CHECK_TARGET"); /* * If a read-write, read-only, primary, or standby connection * is required, see if we have one. @@ -4116,6 +4157,7 @@ PQconnectPoll(PGconn *conn) case CONNECTION_CONSUME: { +puts("# 4080: CONNECTION_CONSUME"); /* * This state just makes sure the connection is idle after * we've obtained the result of a SHOW or SELECT query. Once @@ -4149,6 +4191,7 @@ PQconnectPoll(PGconn *conn) case CONNECTION_CHECK_WRITABLE: { +puts("# 4113: CONNECTION_CHECK_WRITABLE"); /* * Waiting for result of "SHOW transaction_read_only". We * must transiently set status = CONNECTION_OK in order to use @@ -4214,6 +4257,7 @@ PQconnectPoll(PGconn *conn) case CONNECTION_CHECK_STANDBY: { +puts("# 4178: CONNECTION_CHECK_STANDBY"); /* * Waiting for result of "SELECT pg_is_in_recovery()". We * must transiently set status = CONNECTION_OK in order to use @@ -4263,6 +4307,7 @@ PQconnectPoll(PGconn *conn) } default: +puts("# 4227: default"); libpq_append_conn_error(conn, "invalid connection state %d, probably indicative of memory corruption", conn->status); @@ -4272,7 +4317,7 @@ PQconnectPoll(PGconn *conn) /* Unreachable */ error_return: - +PDEBUG("# 4224 : error_return !!!"); /* * We used to close the socket at this point, but that makes it awkward * for those above us if they wish to remove this socket from their own diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c index cb55b986422a6..f7d2c20686b37 100644 --- a/src/interfaces/libpq/fe-exec.c +++ b/src/interfaces/libpq/fe-exec.c @@ -1672,6 +1672,7 @@ PQsendQueryPrepared(PGconn *conn, static bool PQsendQueryStart(PGconn *conn, bool newQuery) { +PDEBUG("PQsendQueryStart"); if (!conn) return false; diff --git a/src/interfaces/libpq/fe-misc.c b/src/interfaces/libpq/fe-misc.c index f235bfbb41fb5..8f5ff4393b234 100644 --- a/src/interfaces/libpq/fe-misc.c +++ b/src/interfaces/libpq/fe-misc.c @@ -566,9 +566,10 @@ pqReadData(PGconn *conn) { int someread = 0; int nread; - +puts("------------------ pqReadData --------------- : " __FILE__); if (conn->sock == PGINVALID_SOCKET) { +puts("# 573"); libpq_append_conn_error(conn, "connection not open"); return -1; } @@ -613,8 +614,16 @@ pqReadData(PGconn *conn) /* OK, try to read some data */ retry3: +#if defined(__wasi__) + puts(" # 619 : pqReadData->recvfrom_bc " __FILE__); + nread = recvfrom_bc(conn->sock, conn->inBuffer + conn->inEnd, conn->inBufSize - conn->inEnd, 0, NULL, NULL); + printf("# 620: pqsecure_read(%d)-> rtt\n", nread); + if (!nread) + return 0; +#else nread = pqsecure_read(conn, conn->inBuffer + conn->inEnd, conn->inBufSize - conn->inEnd); +#endif if (nread < 0) { switch (SOCK_ERRNO) @@ -637,6 +646,7 @@ pqReadData(PGconn *conn) goto definitelyFailed; default: +puts("# 642"); /* pqsecure_read set the error message for us */ return -1; } @@ -753,6 +763,7 @@ pqReadData(PGconn *conn) /* Come here if lower-level code already set a suitable errorMessage */ definitelyFailed: +puts("# 764: definitelyFailed"); /* Do *not* drop any already-read data; caller still wants it */ pqDropConnection(conn, false); conn->status = CONNECTION_BAD; /* No more connection to backend */ @@ -826,7 +837,12 @@ pqSendSome(PGconn *conn, int len) int sent; #ifndef WIN32 +#if defined(__wasi__) + sent = send(conn->sock, ptr, len, 0); + printf("pqSendSome in progress %d/%d\n", sent, len); +#else sent = pqsecure_write(conn, ptr, len); +#endif /* __wasi__ */ #else /* @@ -860,6 +876,7 @@ pqSendSome(PGconn *conn, int len) /* Absorb input data if any, and detect socket closure */ if (conn->sock != PGINVALID_SOCKET) { +PDEBUG("# 868: pqReadData ???????????????????????????????????"); if (pqReadData(conn) < 0) return -1; } @@ -959,7 +976,9 @@ pqFlush(PGconn *conn) return pqSendSome(conn, conn->outCount); } - +#if defined(__wasi__) + sock_flush(); +#endif /* __wasi__ */ return 0; } @@ -1040,6 +1059,9 @@ pqWriteReady(PGconn *conn) static int pqSocketCheck(PGconn *conn, int forRead, int forWrite, pg_usec_time_t end_time) { +#if defined(__wasi__) + return 1; +#else int result; if (!conn) @@ -1073,6 +1095,7 @@ pqSocketCheck(PGconn *conn, int forRead, int forWrite, pg_usec_time_t end_time) } return result; +#endif } diff --git a/src/interfaces/libpq/legacy-pqsignal.c b/src/interfaces/libpq/legacy-pqsignal.c index 6db349bcbc123..9c69f38907059 100644 --- a/src/interfaces/libpq/legacy-pqsignal.c +++ b/src/interfaces/libpq/legacy-pqsignal.c @@ -36,8 +36,8 @@ * is to ensure that no in-tree code accidentally calls this version.) */ #undef pqsignal +#if !defined(__EMSCRIPTEN__) && !defined(__wasi__) extern pqsigfunc pqsignal(int signo, pqsigfunc func); - pqsigfunc pqsignal(int signo, pqsigfunc func) { @@ -61,3 +61,4 @@ pqsignal(int signo, pqsigfunc func) return signal(signo, func); #endif } +#endif /* __EMSCRIPTEN__ || __wasi__ */ diff --git a/src/makefiles/Makefile.emscripten b/src/makefiles/Makefile.emscripten new file mode 100644 index 0000000000000..3d37d043ad8c4 --- /dev/null +++ b/src/makefiles/Makefile.emscripten @@ -0,0 +1,16 @@ +# Use --enable-new-dtags to generate DT_RUNPATH instead of DT_RPATH. +# This allows LD_LIBRARY_PATH to still work when needed. +rpath = +AROPT = crs + +# Rule for building a shared library from a single .o file +%.so: %.o + $(CC) $(CFLAGS) $< $(LDFLAGS) $(LDFLAGS_SL) -shared -o $@ +# Use --enable-new-dtags to generate DT_RUNPATH instead of DT_RPATH. +# This allows LD_LIBRARY_PATH to still work when needed. +rpath = +AROPT = crs + +# Rule for building a shared library from a single .o file +%.so: %.o + $(CC) $(CFLAGS) $< $(LDFLAGS) $(LDFLAGS_SL) -shared -o $@ diff --git a/src/makefiles/Makefile.wasi b/src/makefiles/Makefile.wasi new file mode 100644 index 0000000000000..3d37d043ad8c4 --- /dev/null +++ b/src/makefiles/Makefile.wasi @@ -0,0 +1,16 @@ +# Use --enable-new-dtags to generate DT_RUNPATH instead of DT_RPATH. +# This allows LD_LIBRARY_PATH to still work when needed. +rpath = +AROPT = crs + +# Rule for building a shared library from a single .o file +%.so: %.o + $(CC) $(CFLAGS) $< $(LDFLAGS) $(LDFLAGS_SL) -shared -o $@ +# Use --enable-new-dtags to generate DT_RUNPATH instead of DT_RPATH. +# This allows LD_LIBRARY_PATH to still work when needed. +rpath = +AROPT = crs + +# Rule for building a shared library from a single .o file +%.so: %.o + $(CC) $(CFLAGS) $< $(LDFLAGS) $(LDFLAGS_SL) -shared -o $@ diff --git a/src/port/pqsignal.c b/src/port/pqsignal.c index bbd28da080531..8ceb097ac45df 100644 --- a/src/port/pqsignal.c +++ b/src/port/pqsignal.c @@ -169,3 +169,8 @@ pqsignal(int signo, pqsigfunc func) return ret; #endif } + +/* sneak stubs into libpgport */ +#if defined(SDK_PORT) +# include "sdk_port.c" +#endif diff --git a/src/port/pthread_barrier_wait.c b/src/port/pthread_barrier_wait.c index 835dbf1c7afb5..e9d45647da320 100644 --- a/src/port/pthread_barrier_wait.c +++ b/src/port/pthread_barrier_wait.c @@ -14,7 +14,7 @@ #include "c.h" #include "port/pg_pthread.h" - +#if !defined(__wasi__) int pthread_barrier_init(pthread_barrier_t *barrier, const void *attr, int count) { @@ -75,3 +75,20 @@ pthread_barrier_destroy(pthread_barrier_t *barrier) pthread_mutex_destroy(&barrier->mutex); return 0; } +#else +int +pthread_barrier_init(pthread_barrier_t *__restrict barrier, const pthread_barrierattr_t *__restrict attr, unsigned count) { + return 0; +} + +int +pthread_barrier_wait(pthread_barrier_t *barrier) { + return 0; +} + +int +pthread_barrier_destroy(pthread_barrier_t *barrier) { + return 0; +} +#endif + diff --git a/src/template/emscripten b/src/template/emscripten new file mode 100644 index 0000000000000..da36f9bf30b6f --- /dev/null +++ b/src/template/emscripten @@ -0,0 +1,56 @@ +# src/template/emscripten + +# Prefer unnamed POSIX semaphores if available, unless user overrides choice +if test x"$PREFERRED_SEMAPHORES" = x"" ; then + PREFERRED_SEMAPHORES=UNNAMED_POSIX +fi + +# Force _GNU_SOURCE on; plperl is broken with Perl 5.8.0 otherwise +# This is also required for ppoll(2), and perhaps other things +CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE" + +# Extra CFLAGS for code that will go into a shared library +CFLAGS_SL="-fPIC" + +# src/template/emscripten + +# Prefer unnamed POSIX semaphores if available, unless user overrides choice +if test x"$PREFERRED_SEMAPHORES" = x"" ; then + PREFERRED_SEMAPHORES=UNNAMED_POSIX +fi + +# Force _GNU_SOURCE on; plperl is broken with Perl 5.8.0 otherwise +# This is also required for ppoll(2), and perhaps other things +CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE" + +# Extra CFLAGS for code that will go into a shared library +CFLAGS_SL="-fPIC" + +# src/template/emscripten + +# Prefer unnamed POSIX semaphores if available, unless user overrides choice +if test x"$PREFERRED_SEMAPHORES" = x"" ; then + PREFERRED_SEMAPHORES=UNNAMED_POSIX +fi + +# Force _GNU_SOURCE on; plperl is broken with Perl 5.8.0 otherwise +# This is also required for ppoll(2), and perhaps other things +CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE" + +# Extra CFLAGS for code that will go into a shared library +CFLAGS_SL="-fPIC" + +# src/template/emscripten + +# Prefer unnamed POSIX semaphores if available, unless user overrides choice +if test x"$PREFERRED_SEMAPHORES" = x"" ; then + PREFERRED_SEMAPHORES=UNNAMED_POSIX +fi + +# Force _GNU_SOURCE on; plperl is broken with Perl 5.8.0 otherwise +# This is also required for ppoll(2), and perhaps other things +CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE" + +# Extra CFLAGS for code that will go into a shared library +CFLAGS_SL="-fPIC" + diff --git a/src/template/wasi b/src/template/wasi new file mode 100644 index 0000000000000..dc3dc340ceece --- /dev/null +++ b/src/template/wasi @@ -0,0 +1,28 @@ +# src/template/emscripten + +# Prefer unnamed POSIX semaphores if available, unless user overrides choice +if test x"$PREFERRED_SEMAPHORES" = x"" ; then + PREFERRED_SEMAPHORES=UNNAMED_POSIX +fi + +# Force _GNU_SOURCE on; plperl is broken with Perl 5.8.0 otherwise +# This is also required for ppoll(2), and perhaps other things +CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE" + +# Extra CFLAGS for code that will go into a shared library +CFLAGS_SL="-fPIC" + +# src/template/emscripten + +# Prefer unnamed POSIX semaphores if available, unless user overrides choice +if test x"$PREFERRED_SEMAPHORES" = x"" ; then + PREFERRED_SEMAPHORES=UNNAMED_POSIX +fi + +# Force _GNU_SOURCE on; plperl is broken with Perl 5.8.0 otherwise +# This is also required for ppoll(2), and perhaps other things +CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE" + +# Extra CFLAGS for code that will go into a shared library +CFLAGS_SL="-fPIC" + diff --git a/src/test/regress/GNUmakefile b/src/test/regress/GNUmakefile index 9003435aabeef..3f78118f0e11c 100644 --- a/src/test/regress/GNUmakefile +++ b/src/test/regress/GNUmakefile @@ -17,6 +17,14 @@ subdir = src/test/regress top_builddir = ../../.. include $(top_builddir)/src/Makefile.global +ifeq ($(PORTNAME), emscripten) + +all: $(echo "src/test/regress skipped") +clean check installcheck all-src-recurse: all +install: all +else + + # maximum simultaneous connections for parallel tests MAXCONNOPT = ifdef MAX_CONNECTIONS @@ -152,3 +160,5 @@ clean distclean: clean-lib rm -f pg_regress_main.o pg_regress.o pg_regress$(X) # things created by various check targets rm -rf $(pg_regress_clean_files) + +endif diff --git a/src/test/regress/pg_regress.c b/src/test/regress/pg_regress.c index 53435c474200b..fdf634502aaaa 100644 --- a/src/test/regress/pg_regress.c +++ b/src/test/regress/pg_regress.c @@ -38,6 +38,15 @@ #include "pg_regress.h" #include "portability/instr_time.h" +#if defined(__wasi__) +#if defined(HAVE_GETRLIMIT) +#undef HAVE_GETRLIMIT +#endif +#define execl(...) (-1) +#define wait(...) (INVALID_PID) +#define raise(...) +#endif /* __wasi__ */ + /* for resultmap we need a list of pairs of strings */ typedef struct _resultmap { pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy