Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,49 @@ jobs:

- name: Type-check
run: npx tsc --noEmit

wasm:
name: Build the WebAssembly module
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: docker/setup-buildx-action@v3

- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm

- run: npm ci

# The MEOS the module embeds comes from a clone of MobilityDB master made
# inside the image, so the clone layer must not be served from the cache:
# a cached mobilitydb_src freezes MEOS at whatever commit first populated
# it, and the tests would then pass against a MEOS nobody is running. The
# dependency stages (sqlite, geos, proj, json-c, gsl, h3) are pure builds
# of pinned releases, so they cache safely and carry the cost of this job.
- name: Build the WebAssembly module
uses: docker/build-push-action@v6
with:
context: .
target: wasm
outputs: type=local,dest=./wasm
cache-from: type=gha
cache-to: type=gha,mode=max
no-cache-filters: mobilitydb_src

# `npm test` belongs here and is left out for two reasons, both outside
# what this job builds.
#
# The module is built with -sMEMORY64=1, whose 64-bit tables need a V8 that
# accepts them: Node 22 (V8 12.4) raises "CompileError: invalid table
# elements limits flags" before any test body runs, while Node 24
# (V8 13.6) instantiates the module and the suite executes. So the test job
# pins node-version 24 or newer, not the 20 above.
#
# The suite then still has failures that predate this workflow — three
# files import interval_make, which libmeos exports but the installed
# umbrella header does not declare, so the generator cannot emit it. That
# gap is upstream in MEOS. Adding the step before it closes would report
# someone else's gap as a failure on every pull request.
9 changes: 7 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,12 @@ RUN PG_CONFIG_H=/root/MobilityDB/build/pgtypes/pg_config.h \
"$PG_CONFIG_H"

# COMPILING: libmeos.a
RUN cmake --build /root/MobilityDB/build --target meos --parallel "$(nproc)"
# The install step produces the header this module compiles against. MEOS
# assembles the installed <meos.h> rather than shipping the source one: it
# splices the PostgreSQL-compat definitions and the de-prefixed base I/O into
# it, so interval_in, date_in and their siblings are declared only there.
RUN cmake --build /root/MobilityDB/build --target meos --parallel "$(nproc)" \
&& cmake --install /root/MobilityDB/build --prefix /root/meos-install

# EMCC: link everything into meos.js + meos.wasm
#
Expand Down Expand Up @@ -264,7 +269,7 @@ RUN mkdir -p /app/wasm \
/root/gsl-wasm/lib/libgslcblas.a \
/root/json-c-install/lib/libjson-c.a \
/root/h3-install/lib/libh3.a \
-I/root/MobilityDB/meos/include \
-I/root/meos-install/include \
-I/root/geos/include \
-I/root/geos/build/capi \
-I/root/MobilityDB/pgtypes \
Expand Down
67 changes: 60 additions & 7 deletions codegen/res/bindings_c_header.c.template
Original file line number Diff line number Diff line change
@@ -1,7 +1,21 @@

#include <stdlib.h>
#include <postgres.h>
#include <utils/timestamp.h>
#include <string.h>
/*
* <meos.h> stands in for <postgres.h> here, and including both breaks it.
*
* The installed <meos.h> is assembled rather than copied from the source tree:
* MEOS splices its PostgreSQL-compat definitions into it under `#ifndef
* POSTGRES_H`, which supplies Datum, DateADT, TimestampTz, Interval and the
* de-prefixed base I/O (interval_in, date_in, timestamptz_in, …) that carry no
* meos_ prefix precisely so they do not collide with a real PostgreSQL. Pulling
* in the vendored <postgres.h> first defines POSTGRES_H, the spliced block is
* skipped, and those types and declarations vanish.
*
* So the module compiles against the installed umbrella alone. Only the Datum
* accessors are missing from it, and they are defined below beside the
* Int64GetDatum/Float8GetDatum this file already supplies for the same reason.
*/
#include <meos.h>
#include <meos_geo.h>
#include <meos_cbuffer.h>
Expand All @@ -14,23 +28,62 @@
#include <emscripten.h>

/*
* Implementations of Int64GetDatum and Float8GetDatum required when
* USE_FLOAT8_BYVAL is disabled (by-reference mode for 64-bit types).
* The Datum accessors PostgreSQL declares in postgres.h.
*
* Whether a 64-bit value rides inside a Datum or behind a pointer is decided by
* the pointer width: PostgreSQL sets USE_FLOAT8_BYVAL when SIZEOF_VOID_P >= 8,
* and Datum is uintptr_t. This module builds with -sMEMORY64=1, so pointers are
* 8 bytes and a TimestampTz or an int64 span bound rides inside the Datum
* itself. Reading such a Datum through a pointer returns whatever the value
* happens to address, which is how a bigint span reports a neighbour it does
* not touch as adjacent.
*
* The condition below reproduces PostgreSQL's, so both widths stay correct.
*/
#ifndef USE_FLOAT8_BYVAL
Datum Int64GetDatum(int64 X) {
#include <stdint.h>

typedef double float8;

#if UINTPTR_MAX > 0xFFFFFFFFu
#define USE_FLOAT8_BYVAL 1
#endif

#ifndef PointerGetDatum
#define PointerGetDatum(X) ((Datum) (X))
#endif

#ifdef USE_FLOAT8_BYVAL

#define DatumGetInt64(X) ((int64) (X))
#define Int64GetDatum(X) ((Datum) (X))

static inline Datum Float8GetDatum(float8 X) {
union { float8 value; int64 retval; } myunion;
myunion.value = X;
return (Datum) myunion.retval;
}

#else

#define DatumGetInt64(X) (*((int64 *) DatumGetPointer(X)))

static inline Datum Int64GetDatum(int64 X) {
int64 *ptr = (int64 *) malloc(sizeof(int64));
*ptr = X;
return PointerGetDatum(ptr);
}

Datum Float8GetDatum(float8 X) {
static inline Datum Float8GetDatum(float8 X) {
float8 *ptr = (float8 *) malloc(sizeof(float8));
*ptr = X;
return PointerGetDatum(ptr);
}

#endif

#define DatumGetTimestampTz(X) ((TimestampTz) DatumGetInt64(X))
#define TimestampTzGetDatum(X) Int64GetDatum(X)

/* --- Error handler --- */
/*
* A static C error handler stores the last errlevel/errcode/errmsg produced
Expand Down
67 changes: 60 additions & 7 deletions core/c-src/bindings.c
Original file line number Diff line number Diff line change
@@ -1,8 +1,22 @@
/* AUTO-GENERATED - DO NOT EDIT. Run: npm run generate */

#include <stdlib.h>
#include <postgres.h>
#include <utils/timestamp.h>
#include <string.h>
/*
* <meos.h> stands in for <postgres.h> here, and including both breaks it.
*
* The installed <meos.h> is assembled rather than copied from the source tree:
* MEOS splices its PostgreSQL-compat definitions into it under `#ifndef
* POSTGRES_H`, which supplies Datum, DateADT, TimestampTz, Interval and the
* de-prefixed base I/O (interval_in, date_in, timestamptz_in, …) that carry no
* meos_ prefix precisely so they do not collide with a real PostgreSQL. Pulling
* in the vendored <postgres.h> first defines POSTGRES_H, the spliced block is
* skipped, and those types and declarations vanish.
*
* So the module compiles against the installed umbrella alone. Only the Datum
* accessors are missing from it, and they are defined below beside the
* Int64GetDatum/Float8GetDatum this file already supplies for the same reason.
*/
#include <meos.h>
#include <meos_geo.h>
#include <meos_cbuffer.h>
Expand All @@ -15,23 +29,62 @@
#include <emscripten.h>

/*
* Implementations of Int64GetDatum and Float8GetDatum required when
* USE_FLOAT8_BYVAL is disabled (by-reference mode for 64-bit types).
* The Datum accessors PostgreSQL declares in postgres.h.
*
* Whether a 64-bit value rides inside a Datum or behind a pointer is decided by
* the pointer width: PostgreSQL sets USE_FLOAT8_BYVAL when SIZEOF_VOID_P >= 8,
* and Datum is uintptr_t. This module builds with -sMEMORY64=1, so pointers are
* 8 bytes and a TimestampTz or an int64 span bound rides inside the Datum
* itself. Reading such a Datum through a pointer returns whatever the value
* happens to address, which is how a bigint span reports a neighbour it does
* not touch as adjacent.
*
* The condition below reproduces PostgreSQL's, so both widths stay correct.
*/
#ifndef USE_FLOAT8_BYVAL
Datum Int64GetDatum(int64 X) {
#include <stdint.h>

typedef double float8;

#if UINTPTR_MAX > 0xFFFFFFFFu
#define USE_FLOAT8_BYVAL 1
#endif

#ifndef PointerGetDatum
#define PointerGetDatum(X) ((Datum) (X))
#endif

#ifdef USE_FLOAT8_BYVAL

#define DatumGetInt64(X) ((int64) (X))
#define Int64GetDatum(X) ((Datum) (X))

static inline Datum Float8GetDatum(float8 X) {
union { float8 value; int64 retval; } myunion;
myunion.value = X;
return (Datum) myunion.retval;
}

#else

#define DatumGetInt64(X) (*((int64 *) DatumGetPointer(X)))

static inline Datum Int64GetDatum(int64 X) {
int64 *ptr = (int64 *) malloc(sizeof(int64));
*ptr = X;
return PointerGetDatum(ptr);
}

Datum Float8GetDatum(float8 X) {
static inline Datum Float8GetDatum(float8 X) {
float8 *ptr = (float8 *) malloc(sizeof(float8));
*ptr = X;
return PointerGetDatum(ptr);
}

#endif

#define DatumGetTimestampTz(X) ((TimestampTz) DatumGetInt64(X))
#define TimestampTzGetDatum(X) Int64GetDatum(X)

/* --- Error handler --- */
/*
* A static C error handler stores the last errlevel/errcode/errmsg produced
Expand Down
Loading