From cbdae80677ac550ddb468e10b2427896b6f84983 Mon Sep 17 00:00:00 2001 From: abbuehlj Date: Tue, 23 Dec 2025 09:47:10 +0100 Subject: [PATCH 1/7] feat: Add 32-bit platform support for graphid type This enables AGE to work on 32-bit platforms including WebAssembly (WASM). Problem: - graphid is int64 (8 bytes) with PASSEDBYVALUE - On 32-bit systems, Datum is only 4 bytes - PostgreSQL rejects pass-by-value types larger than Datum Solution: - Add conditional compilation in graphid.h - Use pass-by-value on 64-bit (SIZEOF_DATUM >= 8) - Use pass-by-reference on 32-bit (SIZEOF_DATUM < 8) - Remove PASSEDBYVALUE from SQL type definition This change is backward compatible: - 64-bit systems continue using pass-by-value - 32-bit systems now work with pass-by-reference Motivation: PGlite (PostgreSQL compiled to WebAssembly) uses 32-bit pointers and requires this patch to run AGE. Tested on: - 64-bit Linux (regression tests pass) - 32-bit WebAssembly via PGlite (all operations work) --- sql/age_main.sql | 3 ++- src/include/utils/graphid.h | 28 +++++++++++++++++++++++++++- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/sql/age_main.sql b/sql/age_main.sql index 59ada0f9f..60e79b9c1 100644 --- a/sql/age_main.sql +++ b/sql/age_main.sql @@ -189,7 +189,8 @@ CREATE TYPE graphid ( SEND = ag_catalog.graphid_send, RECEIVE = ag_catalog.graphid_recv, INTERNALLENGTH = 8, - PASSEDBYVALUE, + -- Note: PASSEDBYVALUE removed for 32-bit WASM compatibility (PGlite) + -- On 32-bit systems, Datum is 4 bytes and cannot hold 8-byte graphid by value ALIGNMENT = float8, STORAGE = plain ); diff --git a/src/include/utils/graphid.h b/src/include/utils/graphid.h index 407e9a585..87a4eab66 100644 --- a/src/include/utils/graphid.h +++ b/src/include/utils/graphid.h @@ -22,6 +22,7 @@ #include "utils/fmgroids.h" #include "utils/syscache.h" +#include "utils/palloc.h" #include "catalog/ag_namespace.h" #include "catalog/pg_type.h" @@ -46,11 +47,36 @@ typedef int64 graphid; #define ENTRY_ID_BITS (32 + 16) #define ENTRY_ID_MASK INT64CONST(0x0000ffffffffffff) +/* + * graphid Datum conversion macros + * + * On 64-bit systems (SIZEOF_DATUM == 8), graphid is passed by value. + * On 32-bit systems (SIZEOF_DATUM == 4), graphid must be passed by reference + * because a 64-bit value cannot fit in a 32-bit Datum. + * + * PGlite compiles to 32-bit WebAssembly, so we need pass-by-reference there. + */ +#if SIZEOF_DATUM >= 8 +/* 64-bit: pass by value (original behavior) */ #define DATUM_GET_GRAPHID(d) DatumGetInt64(d) #define GRAPHID_GET_DATUM(x) Int64GetDatum(x) - #define AG_GETARG_GRAPHID(a) DATUM_GET_GRAPHID(PG_GETARG_DATUM(a)) #define AG_RETURN_GRAPHID(x) return GRAPHID_GET_DATUM(x) +#else +/* 32-bit: pass by reference */ +#define DATUM_GET_GRAPHID(d) (*((graphid *) DatumGetPointer(d))) +#define GRAPHID_GET_DATUM(x) ag_graphid_get_datum(x) +#define AG_GETARG_GRAPHID(a) DATUM_GET_GRAPHID(PG_GETARG_DATUM(a)) +#define AG_RETURN_GRAPHID(x) return GRAPHID_GET_DATUM(x) + +/* Helper function for 32-bit pass-by-reference - allocates and returns Datum */ +static inline Datum ag_graphid_get_datum(graphid gid) +{ + graphid *result = (graphid *) palloc(sizeof(graphid)); + *result = gid; + return PointerGetDatum(result); +} +#endif /* Oid accessors for GRAPHID */ #define GRAPHIDOID get_GRAPHIDOID() From 09c7d3aa2dab365e8adc838dc5d19feda387ae04 Mon Sep 17 00:00:00 2001 From: abbuehlj Date: Wed, 7 Jan 2026 13:40:31 +0100 Subject: [PATCH 2/7] feat: Enhance 32-bit platform support for graphid type This update introduces conditional compilation in the Makefile to support 32-bit platforms by detecting the size of Datum. The graphid type now uses pass-by-reference on 32-bit systems, ensuring compatibility with PostgreSQL's limitations on pass-by-value types larger than Datum. Changes include: - Added SIZEOF_DATUM detection in the Makefile. - Updated the SQL definition of graphid to conditionally remove PASSEDBYVALUE for 32-bit systems. This change maintains backward compatibility for 64-bit systems while enabling functionality on 32-bit platforms, including WebAssembly. --- Makefile | 13 ++++++++++++- sql/age_main.sql | 3 +-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 3e73f3e68..d42abf6be 100644 --- a/Makefile +++ b/Makefile @@ -138,6 +138,13 @@ PG_CONFIG ?= pg_config PGXS := $(shell $(PG_CONFIG) --pgxs) include $(PGXS) +# 32-bit platform support: detect SIZEOF_DATUM (override with make SIZEOF_DATUM=4) +SIZEOF_DATUM ?= $(shell printf '%s\n%s\n' '\#include "pg_config.h"' 'SIZEOF_VOID_P' | \ + $(CC) -I$(shell $(PG_CONFIG) --includedir-server) -E -x c - 2>/dev/null | grep -E '^[0-9]+$$' | tail -1) +ifeq ($(SIZEOF_DATUM),) + SIZEOF_DATUM := 8 +endif + src/backend/parser/cypher_keywords.o: src/include/parser/cypher_kwlist_d.h src/include/parser/cypher_kwlist_d.h: src/include/parser/cypher_kwlist.h $(GEN_KEYWORDLIST_DEPS) @@ -150,8 +157,12 @@ src/backend/parser/cypher_gram.c: BISONFLAGS += --defines=src/include/parser/cyp src/backend/parser/cypher_parser.o: src/backend/parser/cypher_gram.c src/backend/parser/cypher_keywords.o: src/backend/parser/cypher_gram.c -$(age_sql): +# Strip PASSEDBYVALUE on 32-bit (SIZEOF_DATUM=4) for graphid pass-by-reference +$(age_sql): $(SQLS) @cat $(SQLS) > $@ +ifeq ($(SIZEOF_DATUM),4) + @sed 's/^[[:space:]]*PASSEDBYVALUE,$$/ -- PASSEDBYVALUE removed for 32-bit/' $@ > $@.tmp && mv $@.tmp $@ +endif src/backend/parser/ag_scanner.c: FLEX_NO_BACKUP=yes diff --git a/sql/age_main.sql b/sql/age_main.sql index 60e79b9c1..59ada0f9f 100644 --- a/sql/age_main.sql +++ b/sql/age_main.sql @@ -189,8 +189,7 @@ CREATE TYPE graphid ( SEND = ag_catalog.graphid_send, RECEIVE = ag_catalog.graphid_recv, INTERNALLENGTH = 8, - -- Note: PASSEDBYVALUE removed for 32-bit WASM compatibility (PGlite) - -- On 32-bit systems, Datum is 4 bytes and cannot hold 8-byte graphid by value + PASSEDBYVALUE, ALIGNMENT = float8, STORAGE = plain ); From ef3fed9289ea3abce111ad919d43ecff388f12d1 Mon Sep 17 00:00:00 2001 From: abbuehlj Date: Wed, 7 Jan 2026 13:46:27 +0100 Subject: [PATCH 3/7] revert graphid.h to upstream --- src/include/utils/graphid.h | 28 +--------------------------- 1 file changed, 1 insertion(+), 27 deletions(-) diff --git a/src/include/utils/graphid.h b/src/include/utils/graphid.h index 87a4eab66..407e9a585 100644 --- a/src/include/utils/graphid.h +++ b/src/include/utils/graphid.h @@ -22,7 +22,6 @@ #include "utils/fmgroids.h" #include "utils/syscache.h" -#include "utils/palloc.h" #include "catalog/ag_namespace.h" #include "catalog/pg_type.h" @@ -47,36 +46,11 @@ typedef int64 graphid; #define ENTRY_ID_BITS (32 + 16) #define ENTRY_ID_MASK INT64CONST(0x0000ffffffffffff) -/* - * graphid Datum conversion macros - * - * On 64-bit systems (SIZEOF_DATUM == 8), graphid is passed by value. - * On 32-bit systems (SIZEOF_DATUM == 4), graphid must be passed by reference - * because a 64-bit value cannot fit in a 32-bit Datum. - * - * PGlite compiles to 32-bit WebAssembly, so we need pass-by-reference there. - */ -#if SIZEOF_DATUM >= 8 -/* 64-bit: pass by value (original behavior) */ #define DATUM_GET_GRAPHID(d) DatumGetInt64(d) #define GRAPHID_GET_DATUM(x) Int64GetDatum(x) + #define AG_GETARG_GRAPHID(a) DATUM_GET_GRAPHID(PG_GETARG_DATUM(a)) #define AG_RETURN_GRAPHID(x) return GRAPHID_GET_DATUM(x) -#else -/* 32-bit: pass by reference */ -#define DATUM_GET_GRAPHID(d) (*((graphid *) DatumGetPointer(d))) -#define GRAPHID_GET_DATUM(x) ag_graphid_get_datum(x) -#define AG_GETARG_GRAPHID(a) DATUM_GET_GRAPHID(PG_GETARG_DATUM(a)) -#define AG_RETURN_GRAPHID(x) return GRAPHID_GET_DATUM(x) - -/* Helper function for 32-bit pass-by-reference - allocates and returns Datum */ -static inline Datum ag_graphid_get_datum(graphid gid) -{ - graphid *result = (graphid *) palloc(sizeof(graphid)); - *result = gid; - return PointerGetDatum(result); -} -#endif /* Oid accessors for GRAPHID */ #define GRAPHIDOID get_GRAPHIDOID() From d16be3234a8ed1d92a2306fc1769dfa48cf0f032 Mon Sep 17 00:00:00 2001 From: Jean-Paul Abbuehl Date: Thu, 8 Jan 2026 05:42:19 +0100 Subject: [PATCH 4/7] Update Makefile Ensures replacement succeeds; fails fast if format changes Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index d42abf6be..a0dd908cb 100644 --- a/Makefile +++ b/Makefile @@ -161,7 +161,7 @@ src/backend/parser/cypher_keywords.o: src/backend/parser/cypher_gram.c $(age_sql): $(SQLS) @cat $(SQLS) > $@ ifeq ($(SIZEOF_DATUM),4) - @sed 's/^[[:space:]]*PASSEDBYVALUE,$$/ -- PASSEDBYVALUE removed for 32-bit/' $@ > $@.tmp && mv $@.tmp $@ + @sed 's/^[[:space:]]*PASSEDBYVALUE[[:space:]]*,\?[[:space:]]*$$/ -- PASSEDBYVALUE removed for 32-bit/' $@ > $@.tmp && mv $@.tmp $@ && grep -q 'PASSEDBYVALUE removed for 32-bit' $@ || { echo "PASSEDBYVALUE marker not found or not replaced in $@"; exit 1; } endif src/backend/parser/ag_scanner.c: FLEX_NO_BACKUP=yes From 9c3f4095485b8dc5a998fb31ab79218553c3b3b5 Mon Sep 17 00:00:00 2001 From: Jean-Paul Abbuehl Date: Thu, 8 Jan 2026 05:43:30 +0100 Subject: [PATCH 5/7] Update Makefile Validates values (4 or 8); clearer warnings; uses $(origin) Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- Makefile | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index a0dd908cb..af64e606a 100644 --- a/Makefile +++ b/Makefile @@ -139,10 +139,18 @@ PGXS := $(shell $(PG_CONFIG) --pgxs) include $(PGXS) # 32-bit platform support: detect SIZEOF_DATUM (override with make SIZEOF_DATUM=4) -SIZEOF_DATUM ?= $(shell printf '%s\n%s\n' '\#include "pg_config.h"' 'SIZEOF_VOID_P' | \ - $(CC) -I$(shell $(PG_CONFIG) --includedir-server) -E -x c - 2>/dev/null | grep -E '^[0-9]+$$' | tail -1) -ifeq ($(SIZEOF_DATUM),) - SIZEOF_DATUM := 8 +# Only attempt auto-detection if SIZEOF_DATUM was not provided on the command line. +ifeq ($(origin SIZEOF_DATUM), undefined) + SIZEOF_DATUM := $(shell printf '%s\n%s\n' '\#include "pg_config.h"' 'SIZEOF_VOID_P' | \ + $(CC) -I$(shell $(PG_CONFIG) --includedir-server) -E -x c - 2>/dev/null | grep -E '^[0-9]+$$' | tail -1) + ifeq ($(SIZEOF_DATUM),) + $(warning Unable to detect SIZEOF_DATUM from pg_config.h; defaulting to 8. Check that PostgreSQL server headers are installed and that pg_config and the compiler are correctly configured.) + SIZEOF_DATUM := 8 + endif + ifeq ($(filter 4 8,$(SIZEOF_DATUM)),) + $(warning Detected unexpected SIZEOF_DATUM '$(SIZEOF_DATUM)'; expected 4 or 8. Defaulting to 8.) + SIZEOF_DATUM := 8 + endif endif src/backend/parser/cypher_keywords.o: src/include/parser/cypher_kwlist_d.h From 039da8adc7ee43e4cac0c07f8d13dabdbed318ba Mon Sep 17 00:00:00 2001 From: abbuehlj Date: Thu, 8 Jan 2026 05:49:17 +0100 Subject: [PATCH 6/7] Helps debugging by pointing to Makefile source --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index af64e606a..832db3806 100644 --- a/Makefile +++ b/Makefile @@ -169,7 +169,7 @@ src/backend/parser/cypher_keywords.o: src/backend/parser/cypher_gram.c $(age_sql): $(SQLS) @cat $(SQLS) > $@ ifeq ($(SIZEOF_DATUM),4) - @sed 's/^[[:space:]]*PASSEDBYVALUE[[:space:]]*,\?[[:space:]]*$$/ -- PASSEDBYVALUE removed for 32-bit/' $@ > $@.tmp && mv $@.tmp $@ && grep -q 'PASSEDBYVALUE removed for 32-bit' $@ || { echo "PASSEDBYVALUE marker not found or not replaced in $@"; exit 1; } + @sed 's/^[[:space:]]*PASSEDBYVALUE[[:space:]]*,\?[[:space:]]*$$/ -- PASSEDBYVALUE disabled on 32-bit (replaced at build time; see Makefile SIZEOF_DATUM rule)/' $@ > $@.tmp && mv $@.tmp $@ && grep -q 'PASSEDBYVALUE disabled on 32-bit' $@ || { echo "PASSEDBYVALUE marker not found or not replaced in $@"; exit 1; } endif src/backend/parser/ag_scanner.c: FLEX_NO_BACKUP=yes From 0a4f4b35706b4ff2ef531e49c64b63c526ffce7f Mon Sep 17 00:00:00 2001 From: abbuehlj Date: Sun, 11 Jan 2026 17:18:48 +0100 Subject: [PATCH 7/7] Refactor Makefile for 32-bit platform support This update simplifies the handling of SIZEOF_DATUM in the Makefile for 32-bit builds. The previous auto-detection logic has been removed in favor of a clearer instruction to pass SIZEOF_DATUM=4 when needed. Additionally, the replacement logic for PASSEDBYVALUE in the SQL definition has been enhanced to provide better error handling and messaging. Changes include: - Removed complex SIZEOF_DATUM detection logic. - Updated comments for clarity on 32-bit support. - Improved error messages for PASSEDBYVALUE replacement failures. --- Makefile | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/Makefile b/Makefile index 832db3806..0283ee083 100644 --- a/Makefile +++ b/Makefile @@ -138,20 +138,9 @@ PG_CONFIG ?= pg_config PGXS := $(shell $(PG_CONFIG) --pgxs) include $(PGXS) -# 32-bit platform support: detect SIZEOF_DATUM (override with make SIZEOF_DATUM=4) -# Only attempt auto-detection if SIZEOF_DATUM was not provided on the command line. -ifeq ($(origin SIZEOF_DATUM), undefined) - SIZEOF_DATUM := $(shell printf '%s\n%s\n' '\#include "pg_config.h"' 'SIZEOF_VOID_P' | \ - $(CC) -I$(shell $(PG_CONFIG) --includedir-server) -E -x c - 2>/dev/null | grep -E '^[0-9]+$$' | tail -1) - ifeq ($(SIZEOF_DATUM),) - $(warning Unable to detect SIZEOF_DATUM from pg_config.h; defaulting to 8. Check that PostgreSQL server headers are installed and that pg_config and the compiler are correctly configured.) - SIZEOF_DATUM := 8 - endif - ifeq ($(filter 4 8,$(SIZEOF_DATUM)),) - $(warning Detected unexpected SIZEOF_DATUM '$(SIZEOF_DATUM)'; expected 4 or 8. Defaulting to 8.) - SIZEOF_DATUM := 8 - endif -endif +# 32-bit platform support: pass SIZEOF_DATUM=4 to enable (e.g., make SIZEOF_DATUM=4) +# When SIZEOF_DATUM=4, PASSEDBYVALUE is stripped from graphid type for pass-by-reference. +# If not specified, normal 64-bit behavior is used (PASSEDBYVALUE preserved). src/backend/parser/cypher_keywords.o: src/include/parser/cypher_kwlist_d.h @@ -169,7 +158,9 @@ src/backend/parser/cypher_keywords.o: src/backend/parser/cypher_gram.c $(age_sql): $(SQLS) @cat $(SQLS) > $@ ifeq ($(SIZEOF_DATUM),4) - @sed 's/^[[:space:]]*PASSEDBYVALUE[[:space:]]*,\?[[:space:]]*$$/ -- PASSEDBYVALUE disabled on 32-bit (replaced at build time; see Makefile SIZEOF_DATUM rule)/' $@ > $@.tmp && mv $@.tmp $@ && grep -q 'PASSEDBYVALUE disabled on 32-bit' $@ || { echo "PASSEDBYVALUE marker not found or not replaced in $@"; exit 1; } + @echo "32-bit build: removing PASSEDBYVALUE from graphid type" + @sed 's/^ PASSEDBYVALUE,$$/ -- PASSEDBYVALUE removed for 32-bit (see Makefile)/' $@ > $@.tmp && mv $@.tmp $@ + @grep -q 'PASSEDBYVALUE removed for 32-bit' $@ || { echo "Error: PASSEDBYVALUE replacement failed in $@"; exit 1; } endif src/backend/parser/ag_scanner.c: FLEX_NO_BACKUP=yes