diff --git a/Dockerfile b/Dockerfile index dc03c83..67b82fa 100644 --- a/Dockerfile +++ b/Dockerfile @@ -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 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 # @@ -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 \ diff --git a/codegen/res/bindings_c_header.c.template b/codegen/res/bindings_c_header.c.template index 815c573..ecd4463 100644 --- a/codegen/res/bindings_c_header.c.template +++ b/codegen/res/bindings_c_header.c.template @@ -1,7 +1,21 @@ #include -#include -#include +#include +/* + * stands in for here, and including both breaks it. + * + * The installed 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 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 #include #include @@ -14,23 +28,62 @@ #include /* - * 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 + +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 diff --git a/core/c-src/bindings.c b/core/c-src/bindings.c index f14637c..e1d0fb2 100644 --- a/core/c-src/bindings.c +++ b/core/c-src/bindings.c @@ -1,8 +1,22 @@ /* AUTO-GENERATED - DO NOT EDIT. Run: npm run generate */ #include -#include -#include +#include +/* + * stands in for here, and including both breaks it. + * + * The installed 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 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 #include #include @@ -15,23 +29,62 @@ #include /* - * 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 + +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