From f0066eab811455455b8773656b1006443bad958a Mon Sep 17 00:00:00 2001 From: Sid Jain Date: Mon, 19 Oct 2026 06:08:39 +0000 Subject: [PATCH 01/11] feat(extensions): upgrade pgvector and pg_ivm with lifecycle coverage --- .../src/generated/extension-smoke.ts | 15 +++++++++-- src/extensions/external/pg_ivm/source.toml | 4 +-- .../pg_ivm/upstream-license-data.json | 8 +++--- src/extensions/external/vector/source.toml | 4 +-- .../vector/upstream-license-data.json | 4 +-- .../generated/docs/extension-evidence.json | 2 +- .../generated/extensions.catalog.json | 4 +-- .../android/extension-legal-catalog.json | 8 +++--- src/test-fixtures/extensions/pg_ivm.sql | 20 ++++++++++++++- src/test-fixtures/extensions/vector.sql | 25 +++++++++++++++++++ 10 files changed, 74 insertions(+), 20 deletions(-) diff --git a/src/examples/native/react-native-expo/src/generated/extension-smoke.ts b/src/examples/native/react-native-expo/src/generated/extension-smoke.ts index ae3ac7f05..fb4aa2420 100644 --- a/src/examples/native/react-native-expo/src/generated/extension-smoke.ts +++ b/src/examples/native/react-native-expo/src/generated/extension-smoke.ts @@ -304,12 +304,15 @@ export const GENERATED_MOBILE_EXTENSION_SMOKE = { "DO $$ BEGIN IF id_encode(1001) <> 'jNl' THEN RAISE EXCEPTION 'pg_hashids encode failed'; END IF; IF id_decode_once('jNl') <> 1001 THEN RAISE EXCEPTION 'pg_hashids decode failed'; END IF; END $$;" ], "pg_ivm": [ + "DROP TABLE IF EXISTS oliphaunt_ivm_restored;", "DROP TABLE IF EXISTS oliphaunt_ivm_summary;", "DROP TABLE IF EXISTS oliphaunt_ivm_orders;", "CREATE TABLE oliphaunt_ivm_orders (id int, amount int);", "INSERT INTO oliphaunt_ivm_orders VALUES (1, 10), (2, 20);", "SELECT pgivm.create_immv('oliphaunt_ivm_summary', $$ SELECT id, amount FROM oliphaunt_ivm_orders $$);", - "-- oliphaunt-verify\nDO $$\nDECLARE n int;\nBEGIN\n SELECT count(*) INTO n FROM oliphaunt_ivm_summary;\n IF n <> 2 THEN RAISE EXCEPTION 'pg_ivm count failed: %', n; END IF;\n UPDATE oliphaunt_ivm_orders SET amount = 11 WHERE id = 1;\n SELECT amount INTO n FROM oliphaunt_ivm_summary WHERE id = 1;\n IF n IS DISTINCT FROM 11 THEN RAISE EXCEPTION 'pg_ivm maintenance failed: %', n; END IF;\n UPDATE oliphaunt_ivm_orders SET amount = 10 WHERE id = 1;\nEND $$;" + "-- Recreate metadata for an existing populated relation, as after pg_dump.\nCREATE TABLE oliphaunt_ivm_restored AS SELECT id, amount FROM oliphaunt_ivm_orders;", + "SELECT pgivm.restore_immv('oliphaunt_ivm_restored', $$ SELECT id, amount FROM oliphaunt_ivm_orders $$);", + "-- oliphaunt-verify\nDO $$\nDECLARE n int; populated boolean;\nBEGIN\n SELECT count(*) INTO n FROM oliphaunt_ivm_summary;\n IF n <> 2 THEN RAISE EXCEPTION 'pg_ivm count failed: %', n; END IF;\n UPDATE oliphaunt_ivm_orders SET amount = 11 WHERE id = 1;\n SELECT amount INTO n FROM oliphaunt_ivm_summary WHERE id = 1;\n IF n IS DISTINCT FROM 11 THEN RAISE EXCEPTION 'pg_ivm maintenance failed: %', n; END IF;\n UPDATE oliphaunt_ivm_orders SET amount = 10 WHERE id = 1;\n SELECT ispopulated INTO populated FROM pgivm.pg_ivm_immv\n WHERE immvrelid = 'oliphaunt_ivm_restored'::regclass;\n IF populated IS DISTINCT FROM true THEN\n RAISE EXCEPTION 'pg_ivm restored relation lost populated state';\n END IF;\n -- Before 1.17 this refresh added duplicate maintenance triggers after restore.\n PERFORM pgivm.refresh_immv('oliphaunt_ivm_restored');\n INSERT INTO oliphaunt_ivm_orders VALUES (99, 30);\n SELECT count(*) INTO n FROM oliphaunt_ivm_restored WHERE id = 99;\n IF n <> 1 THEN RAISE EXCEPTION 'pg_ivm restored maintenance duplicated rows: %', n; END IF;\n DELETE FROM oliphaunt_ivm_orders WHERE id = 99;\nEND $$;" ], "pg_surgery": [ "DO $$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_proc WHERE proname = 'heap_force_kill') THEN RAISE EXCEPTION 'pg_surgery function missing'; END IF; END $$;" @@ -390,6 +393,14 @@ export const GENERATED_MOBILE_EXTENSION_SMOKE = { "DROP TABLE IF EXISTS oliphaunt_vector;", "CREATE TABLE oliphaunt_vector (id int PRIMARY KEY, embedding vector(3));", "INSERT INTO oliphaunt_vector VALUES (1, '[1,2,3]');", - "-- oliphaunt-verify\nDO $$ DECLARE d float8; BEGIN SELECT embedding <-> '[1,2,4]'::vector INTO d FROM oliphaunt_vector WHERE id = 1; IF d IS DISTINCT FROM 1 THEN RAISE EXCEPTION 'vector distance failed: %', d; END IF; END $$;" + "DROP TABLE IF EXISTS oliphaunt_vector_indexed;", + "CREATE TABLE oliphaunt_vector_indexed (id int PRIMARY KEY, embedding vector(3));", + "INSERT INTO oliphaunt_vector_indexed SELECT i, ARRAY[i, i, i]::vector FROM generate_series(1, 64) i;", + "CREATE INDEX ON oliphaunt_vector_indexed USING hnsw (embedding vector_l2_ops);", + "DELETE FROM oliphaunt_vector_indexed WHERE id = 32;", + "VACUUM oliphaunt_vector_indexed;", + "INSERT INTO oliphaunt_vector_indexed VALUES (32, '[32,32,32]');", + "-- oliphaunt-verify\nDO $$ DECLARE d float8; BEGIN SELECT embedding <-> '[1,2,4]'::vector INTO d FROM oliphaunt_vector WHERE id = 1; IF d IS DISTINCT FROM 1 THEN RAISE EXCEPTION 'vector distance failed: %', d; END IF; END $$;", + "DO $$\nDECLARE nearest int;\nBEGIN\n PERFORM set_config('enable_seqscan', 'off', true);\n SELECT id INTO nearest FROM oliphaunt_vector_indexed ORDER BY embedding <-> '[32,32,32]'::vector LIMIT 1;\n IF nearest IS DISTINCT FROM 32 THEN\n RAISE EXCEPTION 'vector HNSW search after vacuum/insert failed: %', nearest;\n END IF;\nEND $$;" ] } as const satisfies Readonly>; diff --git a/src/extensions/external/pg_ivm/source.toml b/src/extensions/external/pg_ivm/source.toml index 30babd02e..94684a1f0 100644 --- a/src/extensions/external/pg_ivm/source.toml +++ b/src/extensions/external/pg_ivm/source.toml @@ -1,9 +1,9 @@ name = "pg_ivm" url = "https://github.com/sraoss/pg_ivm.git" branch = "pinned" -commit = "b66487f7a6f8deee3998e858d773e19923e4bd4b" +commit = "678c37861080aa221b859cefaca98725646dbf7c" [extension-control] sql-name = "pg_ivm" source-path = "pg_ivm.control" -default-version = "1.13" +default-version = "1.17" diff --git a/src/extensions/external/pg_ivm/upstream-license-data.json b/src/extensions/external/pg_ivm/upstream-license-data.json index b07587576..e38b593fc 100644 --- a/src/extensions/external/pg_ivm/upstream-license-data.json +++ b/src/extensions/external/pg_ivm/upstream-license-data.json @@ -7,7 +7,7 @@ "kind": "git", "url": "https://github.com/sraoss/pg_ivm.git", "branch": "pinned", - "commit": "b66487f7a6f8deee3998e858d773e19923e4bd4b" + "commit": "678c37861080aa221b859cefaca98725646dbf7c" } ], "extension": { @@ -19,12 +19,12 @@ "destination": "share/licenses/pg_ivm/LICENSE", "role": "license", "spdx": "PostgreSQL", - "license_url": "https://github.com/sraoss/pg_ivm/blob/b66487f7a6f8deee3998e858d773e19923e4bd4b/LICENSE", - "sha256": "22e995337ca75d05f5057e741e063acb802ff10cb8a13dc822bae749d9df59f4" + "license_url": "https://github.com/sraoss/pg_ivm/blob/678c37861080aa221b859cefaca98725646dbf7c/LICENSE", + "sha256": "f395253af7c50689bdfcd7df4ea247dc2fc39fa0627100699f006639df406d2b" } ] }, "blobs": { - "22e995337ca75d05f5057e741e063acb802ff10cb8a13dc822bae749d9df59f4": "UG9ydGlvbnMgQ29weXJpZ2h0IChjKSAxOTk2LTIwMjIsIFBvc3RncmVTUUwgR2xvYmFsIERldmVsb3BtZW50IEdyb3VwCgpQb3J0aW9ucyBDb3B5cmlnaHQgKGMpIDIwMjIsIElWTSBEZXZlbG9wbWVudCBHcm91cAoKUGVybWlzc2lvbiB0byB1c2UsIGNvcHksIG1vZGlmeSwgYW5kIGRpc3RyaWJ1dGUgdGhpcyBzb2Z0d2FyZSBhbmQgaXRzCmRvY3VtZW50YXRpb24gZm9yIGFueSBwdXJwb3NlLCB3aXRob3V0IGZlZSwgYW5kIHdpdGhvdXQgYSB3cml0dGVuIGFncmVlbWVudAppcyBoZXJlYnkgZ3JhbnRlZCwgcHJvdmlkZWQgdGhhdCB0aGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQgdGhpcwpwYXJhZ3JhcGggYW5kIHRoZSBmb2xsb3dpbmcgdHdvIHBhcmFncmFwaHMgYXBwZWFyIGluIGFsbCBjb3BpZXMuCgpJTiBOTyBFVkVOVCBTSEFMTCBUSEUgQVVUSE9SUyBCRSBMSUFCTEUgVE8gQU5ZIFBBUlRZIEZPUiBESVJFQ1QsCklORElSRUNULCBTUEVDSUFMLCBJTkNJREVOVEFMLCBPUiBDT05TRVFVRU5USUFMIERBTUFHRVMsIElOQ0xVRElORwpMT1NUIFBST0ZJVFMsIEFSSVNJTkcgT1VUIE9GIFRIRSBVU0UgT0YgVEhJUyBTT0ZUV0FSRSBBTkQgSVRTCkRPQ1VNRU5UQVRJT04sIEVWRU4gSUYgVEhFIEFVVEhPUlMgSEFWRSBCRUVOIEFEVklTRUQgT0YgVEhFClBPU1NJQklMSVRZIE9GIFNVQ0ggREFNQUdFLgoKVEhFIEFVVEhPUlMgU1BFQ0lGSUNBTExZIERJU0NMQUlNIEFOWSBXQVJSQU5USUVTLCBJTkNMVURJTkcsIEJVVCBOT1QKTElNSVRFRCBUTywgVEhFIElNUExJRUQgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFkgQU5EIEZJVE5FU1MgRk9SCkEgUEFSVElDVUxBUiBQVVJQT1NFLiAgVEhFIFNPRlRXQVJFIFBST1ZJREVEIEhFUkVVTkRFUiBJUyBPTiBBTiAiQVMKSVMiIEJBU0lTLCBBTkQgVEhFIEFVVEhPUlMgSEFWRSBOTyBPQkxJR0FUSU9OUyBUTyBQUk9WSURFIE1BSU5URU5BTkNFLApTVVBQT1JULCBVUERBVEVTLCBFTkhBTkNFTUVOVFMsIE9SIE1PRElGSUNBVElPTlMuCg==" + "f395253af7c50689bdfcd7df4ea247dc2fc39fa0627100699f006639df406d2b": "UG9ydGlvbnMgQ29weXJpZ2h0IChjKSAxOTk2LTIwMjIsIFBvc3RncmVTUUwgR2xvYmFsIERldmVsb3BtZW50IEdyb3VwCgpQb3J0aW9ucyBDb3B5cmlnaHQgKGMpIDIwMjYsIElWTSBEZXZlbG9wbWVudCBHcm91cAoKUGVybWlzc2lvbiB0byB1c2UsIGNvcHksIG1vZGlmeSwgYW5kIGRpc3RyaWJ1dGUgdGhpcyBzb2Z0d2FyZSBhbmQgaXRzCmRvY3VtZW50YXRpb24gZm9yIGFueSBwdXJwb3NlLCB3aXRob3V0IGZlZSwgYW5kIHdpdGhvdXQgYSB3cml0dGVuIGFncmVlbWVudAppcyBoZXJlYnkgZ3JhbnRlZCwgcHJvdmlkZWQgdGhhdCB0aGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQgdGhpcwpwYXJhZ3JhcGggYW5kIHRoZSBmb2xsb3dpbmcgdHdvIHBhcmFncmFwaHMgYXBwZWFyIGluIGFsbCBjb3BpZXMuCgpJTiBOTyBFVkVOVCBTSEFMTCBUSEUgQVVUSE9SUyBCRSBMSUFCTEUgVE8gQU5ZIFBBUlRZIEZPUiBESVJFQ1QsCklORElSRUNULCBTUEVDSUFMLCBJTkNJREVOVEFMLCBPUiBDT05TRVFVRU5USUFMIERBTUFHRVMsIElOQ0xVRElORwpMT1NUIFBST0ZJVFMsIEFSSVNJTkcgT1VUIE9GIFRIRSBVU0UgT0YgVEhJUyBTT0ZUV0FSRSBBTkQgSVRTCkRPQ1VNRU5UQVRJT04sIEVWRU4gSUYgVEhFIEFVVEhPUlMgSEFWRSBCRUVOIEFEVklTRUQgT0YgVEhFClBPU1NJQklMSVRZIE9GIFNVQ0ggREFNQUdFLgoKVEhFIEFVVEhPUlMgU1BFQ0lGSUNBTExZIERJU0NMQUlNIEFOWSBXQVJSQU5USUVTLCBJTkNMVURJTkcsIEJVVCBOT1QKTElNSVRFRCBUTywgVEhFIElNUExJRUQgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFkgQU5EIEZJVE5FU1MgRk9SCkEgUEFSVElDVUxBUiBQVVJQT1NFLiAgVEhFIFNPRlRXQVJFIFBST1ZJREVEIEhFUkVVTkRFUiBJUyBPTiBBTiAiQVMKSVMiIEJBU0lTLCBBTkQgVEhFIEFVVEhPUlMgSEFWRSBOTyBPQkxJR0FUSU9OUyBUTyBQUk9WSURFIE1BSU5URU5BTkNFLApTVVBQT1JULCBVUERBVEVTLCBFTkhBTkNFTUVOVFMsIE9SIE1PRElGSUNBVElPTlMuCg==" } } diff --git a/src/extensions/external/vector/source.toml b/src/extensions/external/vector/source.toml index 9793cfe07..6f58b3348 100644 --- a/src/extensions/external/vector/source.toml +++ b/src/extensions/external/vector/source.toml @@ -1,9 +1,9 @@ name = "pgvector" url = "https://github.com/pgvector/pgvector.git" branch = "master" -commit = "d238409becebb8172fe696ffa776badfad4b631c" +commit = "f37c13f68b57d2c3472b2214fbcff699d6d34876" [extension-control] sql-name = "vector" source-path = "vector.control" -default-version = "0.8.2" +default-version = "0.8.7" diff --git a/src/extensions/external/vector/upstream-license-data.json b/src/extensions/external/vector/upstream-license-data.json index ae8bd584a..f59751ed1 100644 --- a/src/extensions/external/vector/upstream-license-data.json +++ b/src/extensions/external/vector/upstream-license-data.json @@ -7,7 +7,7 @@ "kind": "git", "url": "https://github.com/pgvector/pgvector.git", "branch": "master", - "commit": "d238409becebb8172fe696ffa776badfad4b631c" + "commit": "f37c13f68b57d2c3472b2214fbcff699d6d34876" } ], "extension": { @@ -19,7 +19,7 @@ "destination": "share/licenses/vector/LICENSE", "role": "license", "spdx": "PostgreSQL", - "license_url": "https://github.com/pgvector/pgvector/blob/d238409becebb8172fe696ffa776badfad4b631c/LICENSE", + "license_url": "https://github.com/pgvector/pgvector/blob/f37c13f68b57d2c3472b2214fbcff699d6d34876/LICENSE", "sha256": "6bba9ebeb73e27477463b05e5ef1bf303bccbddb3db9bbc95905d351604d6a87" } ] diff --git a/src/extensions/generated/docs/extension-evidence.json b/src/extensions/generated/docs/extension-evidence.json index 00b689fe6..ea6571921 100644 --- a/src/extensions/generated/docs/extension-evidence.json +++ b/src/extensions/generated/docs/extension-evidence.json @@ -1346,7 +1346,7 @@ "collector": "src/extensions/tools/collect-wasix-evidence.sh", "kind": "exact-sha-ci" }, - "source-digest": "sha256:05c44ce681c43857fb4b49081cb8a290cf3051ea102de324964ec61f4f9566d2", + "source-digest": "sha256:441125a3d2b9e9871a12f1e3ef7baa7b0b3bebac7f388d7d39fb1e27a6a846c7", "source-digest-inputs": [ "src/third-party/postgres/source.toml", "src/extensions/catalog/extensions.source.json", diff --git a/src/extensions/generated/extensions.catalog.json b/src/extensions/generated/extensions.catalog.json index 7ee933e81..fffd2f1be 100644 --- a/src/extensions/generated/extensions.catalog.json +++ b/src/extensions/generated/extensions.catalog.json @@ -831,7 +831,7 @@ "bundle-size": 24865, "control-file": "target/oliphaunt-sources/checkouts/pg_ivm/pg_ivm.control", "control": { - "default-version": "1.13", + "default-version": "1.17", "module-pathname": "$libdir/pg_ivm", "requires": [], "relocatable": "false", @@ -1476,7 +1476,7 @@ "bundle-size": 43953, "control-file": "target/oliphaunt-sources/checkouts/pgvector/vector.control", "control": { - "default-version": "0.8.2", + "default-version": "0.8.7", "module-pathname": "$libdir/vector", "requires": [], "relocatable": "true" diff --git a/src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extension-legal-catalog.json b/src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extension-legal-catalog.json index 9bd0307d2..2869b7cab 100644 --- a/src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extension-legal-catalog.json +++ b/src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extension-legal-catalog.json @@ -155,7 +155,7 @@ { "path": "share/licenses/pg_ivm/LICENSE", "bytes": 1015, - "sha256": "22e995337ca75d05f5057e741e063acb802ff10cb8a13dc822bae749d9df59f4", + "sha256": "f395253af7c50689bdfcd7df4ea247dc2fc39fa0627100699f006639df406d2b", "mode": "0644" } ] @@ -185,7 +185,7 @@ { "path": "share/licenses/pg_ivm/LICENSE", "bytes": 1015, - "sha256": "22e995337ca75d05f5057e741e063acb802ff10cb8a13dc822bae749d9df59f4", + "sha256": "f395253af7c50689bdfcd7df4ea247dc2fc39fa0627100699f006639df406d2b", "mode": "0644" } ] @@ -1919,7 +1919,7 @@ { "path": "files/share/licenses/pg_ivm/LICENSE", "bytes": 1015, - "sha256": "22e995337ca75d05f5057e741e063acb802ff10cb8a13dc822bae749d9df59f4", + "sha256": "f395253af7c50689bdfcd7df4ea247dc2fc39fa0627100699f006639df406d2b", "mode": "0644" } ] @@ -1949,7 +1949,7 @@ { "path": "files/share/licenses/pg_ivm/LICENSE", "bytes": 1015, - "sha256": "22e995337ca75d05f5057e741e063acb802ff10cb8a13dc822bae749d9df59f4", + "sha256": "f395253af7c50689bdfcd7df4ea247dc2fc39fa0627100699f006639df406d2b", "mode": "0644" } ] diff --git a/src/test-fixtures/extensions/pg_ivm.sql b/src/test-fixtures/extensions/pg_ivm.sql index 6fa633545..5a7c57879 100644 --- a/src/test-fixtures/extensions/pg_ivm.sql +++ b/src/test-fixtures/extensions/pg_ivm.sql @@ -1,3 +1,5 @@ +DROP TABLE IF EXISTS oliphaunt_ivm_restored; +-- oliphaunt-statement DROP TABLE IF EXISTS oliphaunt_ivm_summary; -- oliphaunt-statement DROP TABLE IF EXISTS oliphaunt_ivm_orders; @@ -8,9 +10,14 @@ INSERT INTO oliphaunt_ivm_orders VALUES (1, 10), (2, 20); -- oliphaunt-statement SELECT pgivm.create_immv('oliphaunt_ivm_summary', $$ SELECT id, amount FROM oliphaunt_ivm_orders $$); -- oliphaunt-statement +-- Recreate metadata for an existing populated relation, as after pg_dump. +CREATE TABLE oliphaunt_ivm_restored AS SELECT id, amount FROM oliphaunt_ivm_orders; +-- oliphaunt-statement +SELECT pgivm.restore_immv('oliphaunt_ivm_restored', $$ SELECT id, amount FROM oliphaunt_ivm_orders $$); +-- oliphaunt-statement -- oliphaunt-verify DO $$ -DECLARE n int; +DECLARE n int; populated boolean; BEGIN SELECT count(*) INTO n FROM oliphaunt_ivm_summary; IF n <> 2 THEN RAISE EXCEPTION 'pg_ivm count failed: %', n; END IF; @@ -18,4 +25,15 @@ BEGIN SELECT amount INTO n FROM oliphaunt_ivm_summary WHERE id = 1; IF n IS DISTINCT FROM 11 THEN RAISE EXCEPTION 'pg_ivm maintenance failed: %', n; END IF; UPDATE oliphaunt_ivm_orders SET amount = 10 WHERE id = 1; + SELECT ispopulated INTO populated FROM pgivm.pg_ivm_immv + WHERE immvrelid = 'oliphaunt_ivm_restored'::regclass; + IF populated IS DISTINCT FROM true THEN + RAISE EXCEPTION 'pg_ivm restored relation lost populated state'; + END IF; + -- Before 1.17 this refresh added duplicate maintenance triggers after restore. + PERFORM pgivm.refresh_immv('oliphaunt_ivm_restored'); + INSERT INTO oliphaunt_ivm_orders VALUES (99, 30); + SELECT count(*) INTO n FROM oliphaunt_ivm_restored WHERE id = 99; + IF n <> 1 THEN RAISE EXCEPTION 'pg_ivm restored maintenance duplicated rows: %', n; END IF; + DELETE FROM oliphaunt_ivm_orders WHERE id = 99; END $$; diff --git a/src/test-fixtures/extensions/vector.sql b/src/test-fixtures/extensions/vector.sql index 8e6f86da0..9fc26f2b7 100644 --- a/src/test-fixtures/extensions/vector.sql +++ b/src/test-fixtures/extensions/vector.sql @@ -4,5 +4,30 @@ CREATE TABLE oliphaunt_vector (id int PRIMARY KEY, embedding vector(3)); -- oliphaunt-statement INSERT INTO oliphaunt_vector VALUES (1, '[1,2,3]'); -- oliphaunt-statement +DROP TABLE IF EXISTS oliphaunt_vector_indexed; +-- oliphaunt-statement +CREATE TABLE oliphaunt_vector_indexed (id int PRIMARY KEY, embedding vector(3)); +-- oliphaunt-statement +INSERT INTO oliphaunt_vector_indexed SELECT i, ARRAY[i, i, i]::vector FROM generate_series(1, 64) i; +-- oliphaunt-statement +CREATE INDEX ON oliphaunt_vector_indexed USING hnsw (embedding vector_l2_ops); +-- oliphaunt-statement +DELETE FROM oliphaunt_vector_indexed WHERE id = 32; +-- oliphaunt-statement +VACUUM oliphaunt_vector_indexed; +-- oliphaunt-statement +INSERT INTO oliphaunt_vector_indexed VALUES (32, '[32,32,32]'); +-- oliphaunt-statement -- oliphaunt-verify DO $$ DECLARE d float8; BEGIN SELECT embedding <-> '[1,2,4]'::vector INTO d FROM oliphaunt_vector WHERE id = 1; IF d IS DISTINCT FROM 1 THEN RAISE EXCEPTION 'vector distance failed: %', d; END IF; END $$; + +-- oliphaunt-statement +DO $$ +DECLARE nearest int; +BEGIN + PERFORM set_config('enable_seqscan', 'off', true); + SELECT id INTO nearest FROM oliphaunt_vector_indexed ORDER BY embedding <-> '[32,32,32]'::vector LIMIT 1; + IF nearest IS DISTINCT FROM 32 THEN + RAISE EXCEPTION 'vector HNSW search after vacuum/insert failed: %', nearest; + END IF; +END $$; From b5654860c7899db87c7858b565aa9d15152ebb99 Mon Sep 17 00:00:00 2001 From: Sid Jain Date: Mon, 19 Oct 2026 06:15:31 +0000 Subject: [PATCH 02/11] feat(extensions): add PGMQ 1.13 with complete package contracts --- .release-please-manifest.json | 1 + release-please-config.json | 7 + .../src/generated/extension-smoke.ts | 19 ++- .../native/tools/build-windows-extensions.sh | 7 +- .../native/tools/package-release-assets.sh | 15 ++- .../tools/package-release-assets.test.sh | 28 +++- .../tools/windows-extension-sources.mts | 23 ++++ .../tools/windows-extension-sources.test.mts | 30 ++++- src/extensions/catalog/extensions.source.json | 32 +++++ src/extensions/evidence/matrix.toml | 15 +++ src/extensions/external/pgmq/CHANGELOG.md | 0 src/extensions/external/pgmq/VERSION | 1 + src/extensions/external/pgmq/moon.yml | 19 +++ src/extensions/external/pgmq/recipe.toml | 33 +++++ src/extensions/external/pgmq/release.toml | 55 ++++++++ src/extensions/external/pgmq/source.toml | 9 ++ .../pgmq/targets/native-static-registry.toml | 12 ++ .../external/pgmq/targets/native.toml | 5 + .../external/pgmq/targets/wasix.toml | 5 + .../external/pgmq/upstream-license-data.json | 30 +++++ .../generated/docs/extension-evidence.json | 43 +++++- .../generated/extensions.catalog.json | 41 ++++++ src/extensions/generated/pgxs-build.tsv | 1 + src/extensions/generated/sdk/extensions.json | 30 ++++- .../generated/wasix/extensions.json | 24 ++++ src/extensions/tools/extension-model.test.mts | 17 ++- .../tools/extension-projections.mts | 16 ++- .../runtime/bin/build-postgres18-linux.sh | 19 ++- .../runtime/bin/build-postgres18-macos.sh | 19 ++- .../rust-bindings/src/generated/extensions.rs | 18 +++ .../android/extension-legal-catalog.json | 122 +++++++++++++++++- .../oliphaunt/android/extensions.properties | 8 +- .../dev/oliphaunt/GeneratedExtensions.kt | 1 + .../dev/oliphaunt/OliphauntExtension.kt | 1 + .../react-native/src/generated/extensions.ts | 28 +++- .../OliphauntCore/OliphauntExtension.swift | 1 + .../sdks/ts/src/generated/extensions.ts | 27 +++- src/test-fixtures/extensions/manifest.json | 1 + src/test-fixtures/extensions/pgmq.sql | 69 ++++++++++ .../runtime/tools/xtask/src/asset_pipeline.rs | 74 +++++++++++ .../tools/xtask/src/extension_catalog.rs | 45 ++++++- .../src/oliphaunt/generated_extensions.rs | 21 +++ 42 files changed, 939 insertions(+), 33 deletions(-) create mode 100644 src/extensions/external/pgmq/CHANGELOG.md create mode 100644 src/extensions/external/pgmq/VERSION create mode 100644 src/extensions/external/pgmq/moon.yml create mode 100644 src/extensions/external/pgmq/recipe.toml create mode 100644 src/extensions/external/pgmq/release.toml create mode 100644 src/extensions/external/pgmq/source.toml create mode 100644 src/extensions/external/pgmq/targets/native-static-registry.toml create mode 100644 src/extensions/external/pgmq/targets/native.toml create mode 100644 src/extensions/external/pgmq/targets/wasix.toml create mode 100644 src/extensions/external/pgmq/upstream-license-data.json create mode 100644 src/test-fixtures/extensions/pgmq.sql diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 2dbb886e4..8a63fe375 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -12,6 +12,7 @@ "src/extensions/external/pg_ivm": "0.3.2", "src/extensions/external/pg_textsearch": "0.3.2", "src/extensions/external/pg_uuidv7": "0.3.2", + "src/extensions/external/pgmq": "0.0.0", "src/extensions/external/pgtap": "0.3.2", "src/extensions/external/postgis": "0.3.2", "src/extensions/external/vector": "0.3.2", diff --git a/release-please-config.json b/release-please-config.json index 7d7334c6e..06dbd73e6 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -259,6 +259,13 @@ "version-file": "VERSION", "changelog-path": "CHANGELOG.md" }, + "src/extensions/external/pgmq": { + "release-type": "simple", + "component": "oliphaunt-extension-pgmq", + "package-name": "oliphaunt-extension-pgmq", + "version-file": "VERSION", + "changelog-path": "CHANGELOG.md" + }, "src/extensions/external/pgtap": { "release-type": "simple", "component": "oliphaunt-extension-pgtap", diff --git a/src/examples/native/react-native-expo/src/generated/extension-smoke.ts b/src/examples/native/react-native-expo/src/generated/extension-smoke.ts index fb4aa2420..28e8718e9 100644 --- a/src/examples/native/react-native-expo/src/generated/extension-smoke.ts +++ b/src/examples/native/react-native-expo/src/generated/extension-smoke.ts @@ -7,7 +7,7 @@ export type GeneratedMobileExtensionProof = { readonly selectedExtensionDependencies: readonly string[]; }; -export const GENERATED_MOBILE_EXTENSION_METADATA_SHA256 = "c1d2e09905d7ecc0172173b34b9e4104dad58987503dd3dab7af4ae78890d9f3" as const; +export const GENERATED_MOBILE_EXTENSION_METADATA_SHA256 = "f6982b4f5ace1f2b8478bbb794dece00d6379545e64bf65a28fa28b459210028" as const; export const GENERATED_MOBILE_EXTENSION_PLAN = [ { @@ -157,6 +157,11 @@ export const GENERATED_MOBILE_EXTENSION_PLAN = [ "createsExtension": true, "selectedExtensionDependencies": [] }, + { + "sqlName": "pgmq", + "createsExtension": true, + "selectedExtensionDependencies": [] + }, { "sqlName": "pgtap", "createsExtension": true, @@ -348,6 +353,18 @@ export const GENERATED_MOBILE_EXTENSION_SMOKE = { "DO $$ DECLARE armored text; header_count int; BEGIN SELECT armor(digest('test', 'sha1'), ARRAY['Version'], ARRAY['oliphaunt']) INTO armored; IF position('Version: oliphaunt' in armored) = 0 THEN RAISE EXCEPTION 'armor header failed'; END IF; SELECT count(*) INTO header_count FROM pgp_armor_headers(armored); IF header_count <> 1 THEN RAISE EXCEPTION 'armor header count failed: %', header_count; END IF; END $$;", "DO $$ DECLARE encrypted bytea; crypto_key bytea := decode('000102030405060708090a0b0c0d0e0f', 'hex'); crypto_iv bytea := decode('101112131415161718191a1b1c1d1e1f', 'hex'); BEGIN SELECT pgp_sym_encrypt('oliphaunt secret', 'passphrase') INTO encrypted; IF pgp_key_id(encrypted) <> 'SYMKEY' THEN RAISE EXCEPTION 'PGP symmetric key id failed'; END IF; SELECT encrypt(convert_to('oliphaunt raw cipher', 'UTF8'), crypto_key, 'aes') INTO encrypted; IF convert_from(decrypt(encrypted, crypto_key, 'aes'), 'UTF8') <> 'oliphaunt raw cipher' THEN RAISE EXCEPTION 'raw decrypt failed'; END IF; SELECT encrypt_iv(convert_to('oliphaunt iv cipher', 'UTF8'), crypto_key, crypto_iv, 'aes-cbc') INTO encrypted; IF convert_from(decrypt_iv(encrypted, crypto_key, crypto_iv, 'aes-cbc'), 'UTF8') <> 'oliphaunt iv cipher' THEN RAISE EXCEPTION 'raw iv decrypt failed'; END IF; END $$;" ], + "pgmq": [ + "DO $proof$\nBEGIN\n IF EXISTS (SELECT FROM pgmq.meta WHERE queue_name = 'oliphaunt_queue') THEN\n PERFORM pgmq.drop_queue('oliphaunt_queue');\n END IF;\nEND\n$proof$;", + "SELECT pgmq.create('oliphaunt_queue');", + "SELECT pgmq.send('oliphaunt_queue', '{\"payload\":\"persistent\"}'::jsonb);", + "DO $proof$\nDECLARE\n message record;\nBEGIN\n SELECT * INTO STRICT message FROM pgmq.read('oliphaunt_queue', 30, 1);\n IF message.message <> '{\"payload\":\"persistent\"}'::jsonb OR message.read_ct <> 1 THEN\n RAISE EXCEPTION 'PGMQ read lost payload or delivery count';\n END IF;\n IF EXISTS (SELECT FROM pgmq.read('oliphaunt_queue', 30, 1)) THEN\n RAISE EXCEPTION 'PGMQ visibility timeout did not hide the leased message';\n END IF;\n IF NOT pgmq.archive('oliphaunt_queue', message.msg_id) THEN\n RAISE EXCEPTION 'PGMQ archive failed';\n END IF;\n IF (SELECT count(*) FROM pgmq.a_oliphaunt_queue) <> 1 THEN\n RAISE EXCEPTION 'PGMQ archive lost the message';\n END IF;\nEND\n$proof$;", + "SELECT pgmq.send('oliphaunt_queue', '{\"payload\":\"delete\"}'::jsonb);", + "DO $proof$\nDECLARE\n message record;\nBEGIN\n SELECT * INTO STRICT message FROM pgmq.pop('oliphaunt_queue');\n IF message.message <> '{\"payload\":\"delete\"}'::jsonb THEN\n RAISE EXCEPTION 'PGMQ pop returned the wrong message';\n END IF;\n IF EXISTS (SELECT FROM pgmq.read('oliphaunt_queue', 30, 1)) THEN\n RAISE EXCEPTION 'PGMQ pop did not remove the message';\n END IF;\nEND\n$proof$;", + "SELECT pgmq.create('oliphaunt_drop_queue');", + "SELECT pgmq.drop_queue('oliphaunt_drop_queue');", + "SELECT pgmq.send('oliphaunt_queue', '{\"payload\":\"restart-and-restore\"}'::jsonb);", + "-- oliphaunt-verify\nDO $proof$\nBEGIN\n IF (SELECT count(*) FROM pgmq.q_oliphaunt_queue) <> 1 OR\n NOT EXISTS (SELECT FROM pgmq.q_oliphaunt_queue\n WHERE message = '{\"payload\":\"restart-and-restore\"}'::jsonb) THEN\n RAISE EXCEPTION 'PGMQ persistent queue message did not survive';\n END IF;\n IF (SELECT count(*) FROM pgmq.a_oliphaunt_queue) <> 1 OR\n NOT EXISTS (SELECT FROM pgmq.a_oliphaunt_queue\n WHERE message = '{\"payload\":\"persistent\"}'::jsonb) THEN\n RAISE EXCEPTION 'PGMQ archived message did not survive';\n END IF;\nEND\n$proof$;" + ], "pgtap": [ "SELECT plan(2);", "SELECT ok(true, 'pgTAP ok() executes');", diff --git a/src/extensions/artifacts/native/tools/build-windows-extensions.sh b/src/extensions/artifacts/native/tools/build-windows-extensions.sh index eb17ffd30..6c5d025ca 100644 --- a/src/extensions/artifacts/native/tools/build-windows-extensions.sh +++ b/src/extensions/artifacts/native/tools/build-windows-extensions.sh @@ -141,7 +141,7 @@ windows_extension_postgis_flatgeobuf() { logged flatgeobuf-library.log native lib.exe /nologo "/OUT:$(native_path "$prefix/lib/flatgeobuf.lib")" "${objects[@]}" } -windows_extension_install() { +windows_extension_install_pgtap() { selected pgtap || return 0 local directory="$work_root/pgtap-windows" destination="$install_dir/share/postgresql/extension" windows_extension_generate pgtap @@ -152,3 +152,8 @@ windows_extension_install() { mkdir -p "$destination" cp "$directory/pgtap.control" "$directory/sql/"pgtap*.sql "$directory/sql/uninstall_pgtap.sql" "$destination/" } + +windows_extension_install() { + windows_extension_install_pgtap + if selected pgmq; then windows_extension_generate pgmq-install; fi +} diff --git a/src/extensions/artifacts/native/tools/package-release-assets.sh b/src/extensions/artifacts/native/tools/package-release-assets.sh index 4727a318b..aefc2cfb3 100755 --- a/src/extensions/artifacts/native/tools/package-release-assets.sh +++ b/src/extensions/artifacts/native/tools/package-release-assets.sh @@ -609,11 +609,13 @@ package_ios_target() { ios_device_root="$mobile_extension_work_root/$target_id/ios-device" macos_archive_root="$mobile_extension_work_root/$target_id/macos-extension-archives" ios_xcframework_root="$mobile_extension_work_root/$target_id/ios-extension-xcframeworks" - require_dir "$ios_xcframework_root/out" "iOS extension XCFramework output" - tools/dev/bun.sh tools/packaging/platform-binary-contract.mts \ - --target "$target_id" \ - --root "$ios_xcframework_root/out" \ - --required-apple-platforms macos,ios,ios-simulator + if [ -n "$mobile_extensions" ]; then + require_dir "$ios_xcframework_root/out" "iOS extension XCFramework output" + tools/dev/bun.sh tools/packaging/platform-binary-contract.mts \ + --target "$target_id" \ + --root "$ios_xcframework_root/out" \ + --required-apple-platforms macos,ios,ios-simulator + fi local sql_name pg_major creates_extension stem dependencies shared_preload desktop_prebuilt mobile_prebuilt mobile_static_required mobile_static_targets data_files artifact_policy runtime_artifact ios_artifact static_prefix registration_artifact dependency dependency_xcframework dependency_artifact while IFS=$'\t' read -r sql_name pg_major creates_extension stem dependencies shared_preload desktop_prebuilt mobile_prebuilt mobile_static_required mobile_static_targets data_files artifact_policy; do [ -n "$sql_name" ] || continue @@ -757,6 +759,9 @@ package_android_target() { done < <(catalog_rows) } +# Tests can call the real packaging functions with independently produced inputs. +if [ "${BASH_SOURCE[0]}" != "$0" ]; then return 0; fi + phase="${OLIPHAUNT_EXTENSION_PHASE:-all}" case "$phase:$target_id" in all:*) fetch_extension_source_assets ;; diff --git a/src/extensions/artifacts/native/tools/package-release-assets.test.sh b/src/extensions/artifacts/native/tools/package-release-assets.test.sh index b68aa39df..50c80fcee 100644 --- a/src/extensions/artifacts/native/tools/package-release-assets.test.sh +++ b/src/extensions/artifacts/native/tools/package-release-assets.test.sh @@ -40,4 +40,30 @@ if OLIPHAUNT_EXTENSION_PHASE=android-package OLIPHAUNT_EXTENSION_TARGET=ios-xcfr echo 'accepted Android phase for iOS' >&2; exit 1 fi grep -q 'invalid extension phase' "$scratch/wrong-phase.log" -echo 'Android split extension producer checks passed' + +# SQL-only iOS products do not produce an XCFramework. Exercise the real +# packager with a host fixture, replacing only the platform compiler producer. +( + export OLIPHAUNT_EXTENSION_TARGET=ios-xcframework + export OLIPHAUNT_EXTENSION_PRODUCTS=oliphaunt-extension-pgmq + export OLIPHAUNT_EXTENSION_HOST_RUNTIME_ROOT="$scratch/ios-host" + export OLIPHAUNT_EXTENSION_RELEASE_ASSET_DIR="$scratch/ios-assets" + export OLIPHAUNT_EXTENSION_RELEASE_STAGE_ROOT="$scratch/ios-stage" + ios_sql="$scratch/ios-host/share/postgresql/extension" + mkdir -p "$ios_sql" + bun - "$scratch/ios-host/postgres" <<'JS' +import {writeFileSync} from 'node:fs'; +import {machoFixture} from './tools/packaging/testdata/release-fixture-utils.mts'; +writeFileSync(process.argv[2], machoFixture()); +JS + printf "default_version = '1.13.0'\n" > "$ios_sql/pgmq.control" + printf 'select 1;\n' > "$ios_sql/pgmq--1.13.0.sql" + source "$producer" + build_mobile_static_artifacts() { [ -z "$1" ]; } + bun "$packager" list-catalog > "$catalog_file" + write_indexes + package_ios_target + [ ! -e "$mobile_extension_work_root/ios-xcframework/ios-extension-xcframeworks/out" ] + [ "$(find "$out_dir" -name '*-pgmq-*-runtime.tar.gz' | wc -l)" = 1 ] +) +echo 'Android split and SQL-only iOS extension producer checks passed' diff --git a/src/extensions/artifacts/native/tools/windows-extension-sources.mts b/src/extensions/artifacts/native/tools/windows-extension-sources.mts index c12b4e3cd..61ed72fc4 100644 --- a/src/extensions/artifacts/native/tools/windows-extension-sources.mts +++ b/src/extensions/artifacts/native/tools/windows-extension-sources.mts @@ -622,6 +622,26 @@ export function pgtap(config: Config, install = false) { } } +// PGMQ's PGXS build only copies the canonical SQL and all versioned upgrades. +// Keep this equivalent Windows path independent of GNU Make or a C compiler. +export function installPgmq(config: Config) { + const directory = path.join( + config.repo, + 'target/oliphaunt-sources/checkouts/pgmq/pgmq-extension', + ); + const destination = path.join(config.install, 'share/postgresql/extension'); + const release = version(directory, 'pgmq'); + assert(/^[a-zA-Z0-9._-]+$/.test(release) && !release.includes('--'), 'invalid PGMQ version'); + mkdirSync(destination, { recursive: true }); + copyFileSync(path.join(directory, 'pgmq.control'), path.join(destination, 'pgmq.control')); + for (const file of glob(path.join(directory, 'sql'), 'pgmq--*.sql')) + copyFileSync(path.join(directory, 'sql', file), path.join(destination, file)); + copyFileSync( + path.join(directory, 'sql/pgmq.sql'), + path.join(destination, `pgmq--${release}.sql`), + ); +} + if (import.meta.main) { const phase = process.argv[2]; const { values } = parseArgs({ @@ -672,6 +692,9 @@ if (import.meta.main) { case 'pgtap-install': pgtap(config, true); break; + case 'pgmq-install': + installPgmq(config); + break; default: throw new Error(`unknown Windows extension phase ${phase}`); } diff --git a/src/extensions/artifacts/native/tools/windows-extension-sources.test.mts b/src/extensions/artifacts/native/tools/windows-extension-sources.test.mts index fe2adb528..dd291a901 100644 --- a/src/extensions/artifacts/native/tools/windows-extension-sources.test.mts +++ b/src/extensions/artifacts/native/tools/windows-extension-sources.test.mts @@ -1,9 +1,35 @@ import { test } from 'bun:test'; import assert from 'node:assert/strict'; -import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; import { tmpdir } from 'node:os'; import path from 'node:path'; -import { patchTextsearch } from './windows-extension-sources.mts'; +import { installPgmq, patchTextsearch } from './windows-extension-sources.mts'; + +test('PGMQ SQL packaging includes the current installation and upgrades, without unrelated files', () => { + const root = mkdtempSync(path.join(tmpdir(), 'pgmq-windows-')); + const source = path.join(root, 'target/oliphaunt-sources/checkouts/pgmq/pgmq-extension'); + const install = path.join(root, 'install'); + try { + mkdirSync(path.join(source, 'sql'), { recursive: true }); + writeFileSync(path.join(source, 'pgmq.control'), "default_version = '1.13.0'\n"); + writeFileSync(path.join(source, 'sql/pgmq.sql'), '-- current SQL\n'); + writeFileSync(path.join(source, 'sql/pgmq--1.12.0--1.13.0.sql'), '-- upgrade SQL\n'); + writeFileSync(path.join(source, 'sql/unrelated.sql'), '-- foreign SQL\n'); + installPgmq({ repo: root, work: root, postgres: root, install }); + const destination = path.join(install, 'share/postgresql/extension'); + assert.deepEqual(readdirSync(destination).sort(), [ + 'pgmq--1.12.0--1.13.0.sql', + 'pgmq--1.13.0.sql', + 'pgmq.control', + ]); + assert.equal( + readFileSync(path.join(destination, 'pgmq--1.13.0.sql'), 'utf8'), + '-- current SQL\n', + ); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); test('Windows packing applies to each exact textsearch struct, including V3 predecessors', () => { const root = mkdtempSync(path.join(tmpdir(), 'textsearch-windows-')); diff --git a/src/extensions/catalog/extensions.source.json b/src/extensions/catalog/extensions.source.json index 6afb49f57..8ea54d61c 100644 --- a/src/extensions/catalog/extensions.source.json +++ b/src/extensions/catalog/extensions.source.json @@ -951,6 +951,38 @@ "native-module-file": "pgcrypto.so", "notes": [] }, + { + "id": "pgmq", + "sql-name": "pgmq", + "rust-constant": "PGMQ", + "display-name": "PGMQ", + "source-kind": "oliphaunt-other-extension", + "upstream-import-name": "pgmq", + "package-export": "./pgmq", + "tags": ["postgres extension"], + "control-file": "target/oliphaunt-sources/checkouts/pgmq/pgmq-extension/pgmq.control", + "control": { + "module-pathname": "$libdir/pgmq", + "requires": [], + "relocatable": "false", + "schema": "pgmq", + "superuser": "false" + }, + "dependencies": ["plpgsql"], + "load-order": [], + "lifecycle": { + "create-extension": true, + "create-schema": "pgmq", + "load-sql": [], + "post-create-sql": [], + "startup-config": [], + "preload-required": false, + "restart-required": false, + "shared-memory-required": false + }, + "tests": ["src/test-fixtures/extensions/pgmq.sql"], + "notes": ["Partitioned queues additionally require pg_partman; basic queues do not."] + }, { "id": "pgtap", "sql-name": "pgtap", diff --git a/src/extensions/evidence/matrix.toml b/src/extensions/evidence/matrix.toml index 3705288bc..54c1db353 100644 --- a/src/extensions/evidence/matrix.toml +++ b/src/extensions/evidence/matrix.toml @@ -12,6 +12,7 @@ source-digest-inputs = [ "src/extensions/external/pg_ivm/source.toml", "src/extensions/external/pg_textsearch/source.toml", "src/extensions/external/pg_uuidv7/source.toml", + "src/extensions/external/pgmq/source.toml", "src/extensions/external/pgtap/source.toml", "src/extensions/external/postgis/dependencies/geos/source.toml", "src/extensions/external/postgis/dependencies/json-c/source.toml", @@ -32,6 +33,11 @@ source-digest-inputs = [ "src/extensions/external/pg_textsearch/targets/native-static-registry.toml", "src/extensions/external/pg_textsearch/upstream-license-data.json", "src/extensions/external/pg_uuidv7/upstream-license-data.json", + "src/extensions/external/pgmq/recipe.toml", + "src/extensions/external/pgmq/targets/native-static-registry.toml", + "src/extensions/external/pgmq/targets/native.toml", + "src/extensions/external/pgmq/targets/wasix.toml", + "src/extensions/external/pgmq/upstream-license-data.json", "src/extensions/external/pgtap/recipe.toml", "src/extensions/external/pgtap/targets/native-static-registry.toml", "src/extensions/external/pgtap/targets/native.toml", @@ -83,6 +89,7 @@ source-digest-inputs = [ "src/test-fixtures/extensions/pg_visibility.sql", "src/test-fixtures/extensions/pg_walinspect.sql", "src/test-fixtures/extensions/pgcrypto.sql", + "src/test-fixtures/extensions/pgmq.sql", "src/test-fixtures/extensions/pgtap.sql", "src/test-fixtures/extensions/postgis.sql", "src/test-fixtures/extensions/seg.sql", @@ -327,6 +334,14 @@ platform-targets = ["portable"] runtime-modes = ["direct","server","restart","backup-restore","materialization"] evidence-required = ["wasix-full-lifecycle-v1"] +[[claims]] +extension = "pgmq" +postgres-major = 18 +artifact-family = "wasix-runtime" +platform-targets = ["portable"] +runtime-modes = ["direct","server","restart","backup-restore","materialization"] +evidence-required = ["wasix-full-lifecycle-v1"] + [[claims]] extension = "pgtap" postgres-major = 18 diff --git a/src/extensions/external/pgmq/CHANGELOG.md b/src/extensions/external/pgmq/CHANGELOG.md new file mode 100644 index 000000000..e69de29bb diff --git a/src/extensions/external/pgmq/VERSION b/src/extensions/external/pgmq/VERSION new file mode 100644 index 000000000..77d6f4ca2 --- /dev/null +++ b/src/extensions/external/pgmq/VERSION @@ -0,0 +1 @@ +0.0.0 diff --git a/src/extensions/external/pgmq/moon.yml b/src/extensions/external/pgmq/moon.yml new file mode 100644 index 000000000..a5a2ce6d5 --- /dev/null +++ b/src/extensions/external/pgmq/moon.yml @@ -0,0 +1,19 @@ +$schema: "https://moonrepo.dev/schemas/project.json" + +id: "oliphaunt-extension-pgmq" +language: "unknown" +layer: "library" +stack: "systems" +tags: ["extensions", "external", "release-product"] +dependsOn: + - id: "extension-runtime-contract" + scope: "build" + - id: "liboliphaunt-native" + scope: "build" + - id: "liboliphaunt-wasix" + scope: "build" + +project: + release: + component: "oliphaunt-extension-pgmq" + packagePath: "src/extensions/external/pgmq" diff --git a/src/extensions/external/pgmq/recipe.toml b/src/extensions/external/pgmq/recipe.toml new file mode 100644 index 000000000..4f150afa5 --- /dev/null +++ b/src/extensions/external/pgmq/recipe.toml @@ -0,0 +1,33 @@ +schema = "oliphaunt-extension-recipe-v1" +sql_name = "pgmq" +display_name = "PGMQ" +kind = "external-simple-pgxs" +license = "PostgreSQL" +source = "pgmq" +postgres_majors = [18] + +[lifecycle] +creates_extension = true +requires = [] +implicit_sql_dependencies = ["plpgsql"] +load_sql = [] +post_create_sql = [] +shared_preload_libraries = [] +restart_required = false +background_workers = false +shared_memory = false +session_load_required = false +needs_superuser = false +trusted = false + +[artifacts] +control_files = ["share/postgresql/extension/pgmq.control"] +sql_globs = ["share/postgresql/extension/pgmq--*.sql"] +native_modules = [] +native_dependency_modules = [] +data_files = [] +headers = [] +licenses = ["share/licenses/pgmq/LICENSE"] + +[build] +source_subdirectory = "pgmq-extension" diff --git a/src/extensions/external/pgmq/release.toml b/src/extensions/external/pgmq/release.toml new file mode 100644 index 000000000..a3a1d003f --- /dev/null +++ b/src/extensions/external/pgmq/release.toml @@ -0,0 +1,55 @@ +id = "oliphaunt-extension-pgmq" +owner = "@oliphaunt/extensions" +kind = "exact-extension-artifact" +shared_source_paths = ["src/extensions/artifacts/packages/tools/package-extension-cargo-facades.mts", "src/extensions/artifacts/packages/tools/package-extension-release-carriers.mts", "src/native/sdks/swift/tools/ios-carrier-manifest.mts", "src/wasix/runtime/tools/package_liboliphaunt_wasix_cargo_artifacts.mts", "tools/packaging/build-maven-artifact-manifest.mts", "tools/packaging/maven-artifact-staging.mts"] +publish_targets = [ + "github-release-assets", + "npm", + "maven-central", + "crates-io", +] +registry_packages = [ + "crates:oliphaunt-extension-pgmq", + "crates:oliphaunt-extension-pgmq-linux-arm64-gnu", + "crates:oliphaunt-extension-pgmq-linux-x64-gnu", + "crates:oliphaunt-extension-pgmq-macos-arm64", + "crates:oliphaunt-extension-pgmq-wasix", + "crates:oliphaunt-extension-pgmq-windows-x64-msvc", + "npm:@oliphaunt/extension-pgmq", + "npm:@oliphaunt/extension-pgmq-linux-arm64-gnu", + "npm:@oliphaunt/extension-pgmq-linux-x64-gnu", + "npm:@oliphaunt/extension-pgmq-macos-arm64", + "npm:@oliphaunt/extension-pgmq-wasix", + "npm:@oliphaunt/extension-pgmq-windows-x64-msvc", + "maven:dev.oliphaunt.extensions:oliphaunt-extension-pgmq-android-arm64-v8a", + "maven:dev.oliphaunt.extensions:oliphaunt-extension-pgmq-android-x86_64", +] +release_artifacts = ["exact-extension-artifacts"] +extension_sql_name = "pgmq" + +[extension] +sql_name = "pgmq" +class = "external" +versioning = "upstream-bound" + +[extension.source] +path = "src/extensions/external/pgmq/source.toml" + +[extension.compatibility] +postgres_major = "18" +extension_runtime_contract = "src/extensions/contracts/contract.toml" +native_runtime_product = "liboliphaunt-native" +native_runtime_version = "0.3.3" +wasix_runtime_product = "liboliphaunt-wasix" +wasix_runtime_version = "0.3.2" +[compatibility_versions.oliphaunt-extension-pgmq-liboliphaunt-native] +public_support = true +source_product = "liboliphaunt-native" +path = "src/extensions/external/pgmq/release.toml" +parser = "toml:extension.compatibility.native_runtime_version" + +[compatibility_versions.oliphaunt-extension-pgmq-liboliphaunt-wasix] +public_support = true +source_product = "liboliphaunt-wasix" +path = "src/extensions/external/pgmq/release.toml" +parser = "toml:extension.compatibility.wasix_runtime_version" diff --git a/src/extensions/external/pgmq/source.toml b/src/extensions/external/pgmq/source.toml new file mode 100644 index 000000000..fcc3a41eb --- /dev/null +++ b/src/extensions/external/pgmq/source.toml @@ -0,0 +1,9 @@ +name = "pgmq" +url = "https://github.com/pgmq/pgmq.git" +branch = "pinned" +commit = "32c075bb6dbed66a303d1a792393c93e36c09a97" + +[extension-control] +sql-name = "pgmq" +source-path = "pgmq-extension/pgmq.control" +default-version = "1.13.0" diff --git a/src/extensions/external/pgmq/targets/native-static-registry.toml b/src/extensions/external/pgmq/targets/native-static-registry.toml new file mode 100644 index 000000000..095968283 --- /dev/null +++ b/src/extensions/external/pgmq/targets/native-static-registry.toml @@ -0,0 +1,12 @@ +schema = "oliphaunt-extension-target-v1" +artifact_family = "sql-only" +build_kind = "pgxs-sql-only" +platform_targets = [ + "macos-arm64", + "ios-arm64", + "ios-simulator-arm64", + "android-arm64-v8a", + "android-x86_64", +] +module_files = [] +data_files = [] diff --git a/src/extensions/external/pgmq/targets/native.toml b/src/extensions/external/pgmq/targets/native.toml new file mode 100644 index 000000000..e693c7978 --- /dev/null +++ b/src/extensions/external/pgmq/targets/native.toml @@ -0,0 +1,5 @@ +schema = "oliphaunt-extension-target-v1" +artifact_family = "sql-only" +build_kind = "pgxs-sql-only" +module_files = [] +data_files = [] diff --git a/src/extensions/external/pgmq/targets/wasix.toml b/src/extensions/external/pgmq/targets/wasix.toml new file mode 100644 index 000000000..e693c7978 --- /dev/null +++ b/src/extensions/external/pgmq/targets/wasix.toml @@ -0,0 +1,5 @@ +schema = "oliphaunt-extension-target-v1" +artifact_family = "sql-only" +build_kind = "pgxs-sql-only" +module_files = [] +data_files = [] diff --git a/src/extensions/external/pgmq/upstream-license-data.json b/src/extensions/external/pgmq/upstream-license-data.json new file mode 100644 index 000000000..1415ec8c2 --- /dev/null +++ b/src/extensions/external/pgmq/upstream-license-data.json @@ -0,0 +1,30 @@ +{ + "schema": "oliphaunt-extension-upstream-license-data-v1", + "sources": [ + { + "id": "pgmq", + "manifest": "src/extensions/external/pgmq/source.toml", + "kind": "git", + "url": "https://github.com/pgmq/pgmq.git", + "branch": "pinned", + "commit": "32c075bb6dbed66a303d1a792393c93e36c09a97" + } + ], + "extension": { + "sql_name": "pgmq", + "files": [ + { + "source": "pgmq", + "path": "LICENSE", + "destination": "share/licenses/pgmq/LICENSE", + "role": "license", + "spdx": "PostgreSQL", + "license_url": "https://github.com/pgmq/pgmq/blob/32c075bb6dbed66a303d1a792393c93e36c09a97/LICENSE", + "sha256": "a3ce61e0031bdcad1024b1bf50ded2359602160f00e0cac8e509752273df6179" + } + ] + }, + "blobs": { + "a3ce61e0031bdcad1024b1bf50ded2359602160f00e0cac8e509752273df6179": "VGhlIFBvc3RncmVTUUwgTGljZW5zZQoKQ29weXJpZ2h0IChjKSAyMDIzLCBUZW1ibwoKUGVybWlzc2lvbiB0byB1c2UsIGNvcHksIG1vZGlmeSwgYW5kIGRpc3RyaWJ1dGUgdGhpcyBzb2Z0d2FyZSBhbmQgaXRzIGRvY3VtZW50YXRpb24gZm9yIGFueSBwdXJwb3NlLCB3aXRob3V0IGZlZSwgYW5kIHdpdGhvdXQgYSB3cml0dGVuIGFncmVlbWVudCBpcyBoZXJlYnkgZ3JhbnRlZCwgcHJvdmlkZWQgdGhhdCB0aGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQgdGhpcyBwYXJhZ3JhcGggYW5kIHRoZSBmb2xsb3dpbmcgdHdvIHBhcmFncmFwaHMgYXBwZWFyIGluIGFsbCBjb3BpZXMuCgpJTiBOTyBFVkVOVCBTSEFMTCBURU1CTyBCRSBMSUFCTEUgVE8gQU5ZIFBBUlRZIEZPUiBESVJFQ1QsIElORElSRUNULCBTUEVDSUFMLCBJTkNJREVOVEFMLCBPUiBDT05TRVFVRU5USUFMIERBTUFHRVMsIElOQ0xVRElORyBMT1NUIFBST0ZJVFMsIEFSSVNJTkcgT1VUIE9GIFRIRSBVU0UgT0YgVEhJUyBTT0ZUV0FSRSBBTkQgSVRTIERPQ1VNRU5UQVRJT04sIEVWRU4gSUYgVEVNQk8gSEFTIEJFRU4gQURWSVNFRCBPRiBUSEUgUE9TU0lCSUxJVFkgT0YgU1VDSCBEQU1BR0UuCgpURU1CTyBTUEVDSUZJQ0FMTFkgRElTQ0xBSU1TIEFOWSBXQVJSQU5USUVTLCBJTkNMVURJTkcsIEJVVCBOT1QgTElNSVRFRCBUTywgVEhFIElNUExJRUQgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFkgQU5EIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBUSEUgU09GVFdBUkUgUFJPVklERUQgSEVSRVVOREVSIElTIE9OIEFOICJBUyBJUyIgQkFTSVMsIEFORCBURU1CTyBIQVMgTk8gT0JMSUdBVElPTlMgVE8gUFJPVklERSBNQUlOVEVOQU5DRSwgU1VQUE9SVCwgVVBEQVRFUywgRU5IQU5DRU1FTlRTLCBPUiBNT0RJRklDQVRJT05TLgo=" + } +} diff --git a/src/extensions/generated/docs/extension-evidence.json b/src/extensions/generated/docs/extension-evidence.json index ea6571921..bd202add9 100644 --- a/src/extensions/generated/docs/extension-evidence.json +++ b/src/extensions/generated/docs/extension-evidence.json @@ -986,6 +986,40 @@ ], "sql-name": "pgcrypto" }, + { + "artifact-family": "wasix-runtime", + "evidence-required": [ + "wasix-full-lifecycle-v1" + ], + "extension": "pgmq", + "latest-accepted-evidence": [], + "missing-current-evidence": [ + { + "artifact-family": "wasix-runtime", + "evidence-tier": "wasix-full-lifecycle-v1", + "platform-target": "portable", + "runtime-modes": [ + "direct", + "server", + "restart", + "backup-restore", + "materialization" + ] + } + ], + "platform-targets": [ + "portable" + ], + "postgres-major": 18, + "runtime-modes": [ + "direct", + "server", + "restart", + "backup-restore", + "materialization" + ], + "sql-name": "pgmq" + }, { "artifact-family": "wasix-runtime", "evidence-required": [ @@ -1346,7 +1380,7 @@ "collector": "src/extensions/tools/collect-wasix-evidence.sh", "kind": "exact-sha-ci" }, - "source-digest": "sha256:441125a3d2b9e9871a12f1e3ef7baa7b0b3bebac7f388d7d39fb1e27a6a846c7", + "source-digest": "sha256:fc36c80f2b5f4b24e93e06f781b72d81fb14106de9f8588b32e45215d45e45f6", "source-digest-inputs": [ "src/third-party/postgres/source.toml", "src/extensions/catalog/extensions.source.json", @@ -1360,6 +1394,7 @@ "src/extensions/external/pg_ivm/source.toml", "src/extensions/external/pg_textsearch/source.toml", "src/extensions/external/pg_uuidv7/source.toml", + "src/extensions/external/pgmq/source.toml", "src/extensions/external/pgtap/source.toml", "src/extensions/external/postgis/dependencies/geos/source.toml", "src/extensions/external/postgis/dependencies/json-c/source.toml", @@ -1380,6 +1415,11 @@ "src/extensions/external/pg_textsearch/targets/native-static-registry.toml", "src/extensions/external/pg_textsearch/upstream-license-data.json", "src/extensions/external/pg_uuidv7/upstream-license-data.json", + "src/extensions/external/pgmq/recipe.toml", + "src/extensions/external/pgmq/targets/native-static-registry.toml", + "src/extensions/external/pgmq/targets/native.toml", + "src/extensions/external/pgmq/targets/wasix.toml", + "src/extensions/external/pgmq/upstream-license-data.json", "src/extensions/external/pgtap/recipe.toml", "src/extensions/external/pgtap/targets/native-static-registry.toml", "src/extensions/external/pgtap/targets/native.toml", @@ -1431,6 +1471,7 @@ "src/test-fixtures/extensions/pg_visibility.sql", "src/test-fixtures/extensions/pg_walinspect.sql", "src/test-fixtures/extensions/pgcrypto.sql", + "src/test-fixtures/extensions/pgmq.sql", "src/test-fixtures/extensions/pgtap.sql", "src/test-fixtures/extensions/postgis.sql", "src/test-fixtures/extensions/seg.sql", diff --git a/src/extensions/generated/extensions.catalog.json b/src/extensions/generated/extensions.catalog.json index fffd2f1be..ea61744ea 100644 --- a/src/extensions/generated/extensions.catalog.json +++ b/src/extensions/generated/extensions.catalog.json @@ -1120,6 +1120,47 @@ "native-module-file": "pgcrypto.so", "notes": [] }, + { + "id": "pgmq", + "sql-name": "pgmq", + "rust-constant": "PGMQ", + "display-name": "PGMQ", + "source-kind": "oliphaunt-other-extension", + "upstream-import-name": "pgmq", + "package-export": "./pgmq", + "tags": [ + "postgres extension" + ], + "control-file": "target/oliphaunt-sources/checkouts/pgmq/pgmq-extension/pgmq.control", + "control": { + "default-version": "1.13.0", + "module-pathname": "$libdir/pgmq", + "requires": [], + "relocatable": "false", + "schema": "pgmq", + "superuser": "false" + }, + "dependencies": [ + "plpgsql" + ], + "load-order": [], + "lifecycle": { + "create-extension": true, + "create-schema": "pgmq", + "load-sql": [], + "post-create-sql": [], + "startup-config": [], + "preload-required": false, + "restart-required": false, + "shared-memory-required": false + }, + "tests": [ + "src/test-fixtures/extensions/pgmq.sql" + ], + "notes": [ + "Partitioned queues additionally require pg_partman; basic queues do not." + ] + }, { "id": "pgtap", "sql-name": "pgtap", diff --git a/src/extensions/generated/pgxs-build.tsv b/src/extensions/generated/pgxs-build.tsv index 173f0cf1a..ac77a68d6 100644 --- a/src/extensions/generated/pgxs-build.tsv +++ b/src/extensions/generated/pgxs-build.tsv @@ -3,5 +3,6 @@ pg_hashids pg_hashids target/oliphaunt-sources/checkouts/pg_hashids pg_hashids.s pg_ivm pg_ivm target/oliphaunt-sources/checkouts/pg_ivm pg_ivm.so extensions/pg_ivm.tar.zst - pg_textsearch pg_textsearch target/oliphaunt-sources/checkouts/pg_textsearch pg_textsearch.so extensions/pg_textsearch.tar.zst - pg_uuidv7 pg_uuidv7 target/oliphaunt-sources/checkouts/pg_uuidv7 pg_uuidv7.so extensions/pg_uuidv7.tar.zst - +pgmq pgmq target/oliphaunt-sources/checkouts/pgmq/pgmq-extension - extensions/pgmq.tar.zst - pgtap pgtap target/oliphaunt-sources/checkouts/pgtap - extensions/pgtap.tar.zst - vector vector target/oliphaunt-sources/checkouts/pgvector vector.so extensions/vector.tar.zst - diff --git a/src/extensions/generated/sdk/extensions.json b/src/extensions/generated/sdk/extensions.json index c8a047409..e017a3886 100644 --- a/src/extensions/generated/sdk/extensions.json +++ b/src/extensions/generated/sdk/extensions.json @@ -1,5 +1,5 @@ { - "extension-catalog-sha256": "c1d2e09905d7ecc0172173b34b9e4104dad58987503dd3dab7af4ae78890d9f3", + "extension-catalog-sha256": "f6982b4f5ace1f2b8478bbb794dece00d6379545e64bf65a28fa28b459210028", "extensions": [ { "artifact-product": "oliphaunt-extension-contrib-pg18", @@ -864,6 +864,34 @@ "source-kind": "postgres-contrib", "sql-name": "pgcrypto" }, + { + "artifact-product": "oliphaunt-extension-pgmq", + "cargo-package": "oliphaunt-extension-pgmq", + "creates-extension": true, + "data-files": [], + "dependencies": [ + "plpgsql" + ], + "display-name": "PGMQ", + "extension-sql-file-names": [], + "extension-sql-file-prefixes": [], + "id": "pgmq", + "maven-artifact": "oliphaunt-extension-pgmq", + "maven-group": "dev.oliphaunt.extensions", + "native-component-requirements": [], + "native-components": [], + "native-module-stem": null, + "npm-package": "@oliphaunt/extension-pgmq", + "postgres-major": 18, + "release-product": "oliphaunt-extension-pgmq", + "runtime-bound": false, + "runtime-environment": [], + "runtime-share-data-files": [], + "selected-extension-dependencies": [], + "shared-preload-libraries": [], + "source-kind": "oliphaunt-other-extension", + "sql-name": "pgmq" + }, { "artifact-product": "oliphaunt-extension-pgtap", "cargo-package": "oliphaunt-extension-pgtap", diff --git a/src/extensions/generated/wasix/extensions.json b/src/extensions/generated/wasix/extensions.json index 8103c602e..5df6ca1aa 100644 --- a/src/extensions/generated/wasix/extensions.json +++ b/src/extensions/generated/wasix/extensions.json @@ -649,6 +649,30 @@ "native-support-modules": [], "sql-name": "pgcrypto" }, + { + "archive": "extensions/pgmq.tar.zst", + "dependencies": [ + "plpgsql" + ], + "id": "pgmq", + "lifecycle": { + "create-extension": true, + "create-schema": "pgmq", + "load-sql": [], + "post-create-sql": [], + "preload-required": false, + "restart-required": false, + "shared-memory-required": false, + "startup-config": [] + }, + "load-order": [], + "native-components": [], + "native-link-units": [], + "native-module-file": null, + "native-runtime-files": [], + "native-support-modules": [], + "sql-name": "pgmq" + }, { "archive": "extensions/pgtap.tar.zst", "dependencies": [ diff --git a/src/extensions/tools/extension-model.test.mts b/src/extensions/tools/extension-model.test.mts index 64b618a52..c05e267cb 100644 --- a/src/extensions/tools/extension-model.test.mts +++ b/src/extensions/tools/extension-model.test.mts @@ -10,9 +10,24 @@ import { sourceDigest, sourceDigestInputs, } from './extension-evidence.mts'; -import { discoverCatalog, extensionProjections, readJson } from './extension-projections.mts'; +import { + discoverCatalog, + extensionProjections, + pgxsSourceDirectory, + readJson, +} from './extension-projections.mts'; const identity = { commit: '1'.repeat(40), tree: '2'.repeat(40) }; + +test('nested PGXS roots remain inside the immutable source checkout', () => { + assert.equal( + pgxsSourceDirectory('pgmq', 'pgmq-extension'), + 'target/oliphaunt-sources/checkouts/pgmq/pgmq-extension', + ); + assert.equal(pgxsSourceDirectory('pgtap'), 'target/oliphaunt-sources/checkouts/pgtap'); + for (const value of ['', '.', '..', '../outside', '/absolute', 'a/../b', 'a//b', 'a\\b', 12]) + assert.throws(() => pgxsSourceDirectory('pgmq', value), /within the pinned checkout/); +}); const catalog = { extensions: [{ id: 'vector', 'sql-name': 'vector' }] }; const matrix = () => Bun.TOML.parse(evidenceMatrix(catalog)); function run() { diff --git a/src/extensions/tools/extension-projections.mts b/src/extensions/tools/extension-projections.mts index da44b182a..750f2372f 100644 --- a/src/extensions/tools/extension-projections.mts +++ b/src/extensions/tools/extension-projections.mts @@ -638,11 +638,13 @@ export function catalogProjections(catalog: Row): Map { ); } else if (row['source-kind'] === 'oliphaunt-other-extension') { const source = readToml(`${externalRoot}/${row['sql-name']}/source.toml`); + const recipePath = `${externalRoot}/${row['sql-name']}/recipe.toml`; + const recipe = existsSync(recipePath) ? readToml(recipePath) : {}; pgxs.push( [ row.id, row['sql-name'], - `target/oliphaunt-sources/checkouts/${source.name}`, + pgxsSourceDirectory(source.name, recipe.build?.source_subdirectory), row['native-module-file'] ?? '-', archive, row.id === 'age' ? 'SIZEOF_DATUM=4' : '-', @@ -659,6 +661,18 @@ export function catalogProjections(catalog: Row): Map { return outputs; } +export function pgxsSourceDirectory(sourceName: string, subdirectory?: unknown): string { + assert(/^[a-zA-Z0-9_-]+$/.test(sourceName), 'invalid PGXS source name'); + const root = `target/oliphaunt-sources/checkouts/${sourceName}`; + if (subdirectory === undefined) return root; + assert( + typeof subdirectory === 'string' && + subdirectory.split('/').every((part) => /^[a-zA-Z0-9_-][a-zA-Z0-9_.-]*$/.test(part)), + 'PGXS source subdirectory must stay within the pinned checkout', + ); + return `${root}/${subdirectory}`; +} + function wasixRustModule(rows: Row[]): string { const cfg = (_row: Row) => ''; // Metadata is available independently of embedded payload features. const array = (values: string[]) => `&[${values.map(literal).join(', ')}]`; diff --git a/src/native/runtime/bin/build-postgres18-linux.sh b/src/native/runtime/bin/build-postgres18-linux.sh index daf31cd91..c94233510 100755 --- a/src/native/runtime/bin/build-postgres18-linux.sh +++ b/src/native/runtime/bin/build-postgres18-linux.sh @@ -125,6 +125,7 @@ external_extensions=( pg_hashids pg_uuidv7 pgtap + pgmq pgvector pg_textsearch postgis @@ -161,6 +162,7 @@ required_extension_controls=( pg_visibility pg_walinspect pgtap + pgmq seg tablefunc tcn @@ -1146,12 +1148,17 @@ build_pgxs_extension() { cp -a "$checkout/." "$build_checkout/" rm -rf "$build_checkout/.git" make -C "$build_checkout" PG_CONFIG="$install_dir/bin/pg_config" clean >> "$make_log" 2>&1 || true - make -C "$build_checkout" \ - PG_CONFIG="$install_dir/bin/pg_config" \ - CC="$cc_string" \ - OPTFLAGS="" \ - "${normal_link_args[@]}" \ - install >> "$make_log" 2>&1 + # PGXS freezes DATA before building; generated SQL must exist before the + # separate install invocation (PGMQ derives its default-version script). + local target + for target in all install; do + make -C "$build_checkout" \ + PG_CONFIG="$install_dir/bin/pg_config" \ + CC="$cc_string" \ + OPTFLAGS="" \ + "${normal_link_args[@]}" \ + "$target" >> "$make_log" 2>&1 + done make -C "$build_checkout" PG_CONFIG="$install_dir/bin/pg_config" clean >> "$make_log" 2>&1 || true make -C "$build_checkout" \ PG_CONFIG="$install_dir/bin/pg_config" \ diff --git a/src/native/runtime/bin/build-postgres18-macos.sh b/src/native/runtime/bin/build-postgres18-macos.sh index f067404ba..a54414aa4 100755 --- a/src/native/runtime/bin/build-postgres18-macos.sh +++ b/src/native/runtime/bin/build-postgres18-macos.sh @@ -109,6 +109,7 @@ external_extensions=( pg_hashids pg_uuidv7 pgtap + pgmq pgvector pg_textsearch postgis @@ -145,6 +146,7 @@ required_extension_controls=( pg_visibility pg_walinspect pgtap + pgmq seg tablefunc tcn @@ -1981,12 +1983,17 @@ build_pgxs_extension() { make -C "$build_checkout" \ PG_CONFIG="$install_dir/bin/pg_config" \ clean - make -C "$build_checkout" \ - PG_CONFIG="$install_dir/bin/pg_config" \ - CC="$CC" \ - OPTFLAGS="" \ - "${normal_link_args[@]}" \ - install + # PGXS freezes DATA before building; generated SQL must exist before the + # separate install invocation (PGMQ derives its default-version script). + local target + for target in all install; do + make -C "$build_checkout" \ + PG_CONFIG="$install_dir/bin/pg_config" \ + CC="$CC" \ + OPTFLAGS="" \ + "${normal_link_args[@]}" \ + "$target" + done make -C "$build_checkout" \ PG_CONFIG="$install_dir/bin/pg_config" \ clean diff --git a/src/native/rust-bindings/src/generated/extensions.rs b/src/native/rust-bindings/src/generated/extensions.rs index 711cff99a..3356f9cc8 100644 --- a/src/native/rust-bindings/src/generated/extensions.rs +++ b/src/native/rust-bindings/src/generated/extensions.rs @@ -70,6 +70,8 @@ enum ExtensionId { PgWalinspect, /// PostgreSQL `pgcrypto`. Pgcrypto, + /// PostgreSQL `pgmq`. + Pgmq, /// PostgreSQL `pgtap`. Pgtap, /// PostgreSQL `postgis`. @@ -238,6 +240,11 @@ impl Extension { id: ExtensionId::Pgcrypto, package: None, }; + /// Select the `pgmq` artifact. + pub const PGMQ: Self = Self { + id: ExtensionId::Pgmq, + package: None, + }; /// Select the `pgtap` artifact. pub const PGTAP: Self = Self { id: ExtensionId::Pgtap, @@ -320,6 +327,7 @@ impl Extension { Extension::PG_VISIBILITY, Extension::PG_WALINSPECT, Extension::PGCRYPTO, + Extension::PGMQ, Extension::PGTAP, Extension::POSTGIS, Extension::SEG, @@ -365,6 +373,7 @@ pub(super) const fn sql_name(extension: Extension) -> &'static str { ExtensionId::PgVisibility => "pg_visibility", ExtensionId::PgWalinspect => "pg_walinspect", ExtensionId::Pgcrypto => "pgcrypto", + ExtensionId::Pgmq => "pgmq", ExtensionId::Pgtap => "pgtap", ExtensionId::Postgis => "postgis", ExtensionId::Seg => "seg", @@ -410,6 +419,7 @@ pub(super) const fn artifact_product(extension: Extension) -> &'static str { ExtensionId::PgVisibility => "oliphaunt-extension-contrib-pg18", ExtensionId::PgWalinspect => "oliphaunt-extension-contrib-pg18", ExtensionId::Pgcrypto => "oliphaunt-extension-contrib-pg18", + ExtensionId::Pgmq => "oliphaunt-extension-pgmq", ExtensionId::Pgtap => "oliphaunt-extension-pgtap", ExtensionId::Postgis => "oliphaunt-extension-postgis", ExtensionId::Seg => "oliphaunt-extension-contrib-pg18", @@ -455,6 +465,7 @@ pub(super) const fn native_module_stem(extension: Extension) -> Option<&'static ExtensionId::PgVisibility => Some("pg_visibility"), ExtensionId::PgWalinspect => Some("pg_walinspect"), ExtensionId::Pgcrypto => Some("pgcrypto"), + ExtensionId::Pgmq => None, ExtensionId::Pgtap => None, ExtensionId::Postgis => Some("postgis-3"), ExtensionId::Seg => Some("seg"), @@ -500,6 +511,7 @@ pub(super) const fn creates_extension(extension: Extension) -> bool { ExtensionId::PgVisibility => true, ExtensionId::PgWalinspect => true, ExtensionId::Pgcrypto => true, + ExtensionId::Pgmq => true, ExtensionId::Pgtap => true, ExtensionId::Postgis => true, ExtensionId::Seg => true, @@ -545,6 +557,7 @@ pub(super) const fn dependencies(extension: Extension) -> &'static [Extension] { ExtensionId::PgVisibility => &[], ExtensionId::PgWalinspect => &[], ExtensionId::Pgcrypto => &[], + ExtensionId::Pgmq => &[], ExtensionId::Pgtap => &[], ExtensionId::Postgis => &[], ExtensionId::Seg => &[], @@ -590,6 +603,7 @@ pub(super) const fn required_shared_preload_library(extension: Extension) -> Opt ExtensionId::PgVisibility => None, ExtensionId::PgWalinspect => None, ExtensionId::Pgcrypto => None, + ExtensionId::Pgmq => None, ExtensionId::Pgtap => None, ExtensionId::Postgis => None, ExtensionId::Seg => None, @@ -635,6 +649,7 @@ pub(super) const fn extension_data_files(extension: Extension) -> &'static [&'st ExtensionId::PgVisibility => &[], ExtensionId::PgWalinspect => &[], ExtensionId::Pgcrypto => &[], + ExtensionId::Pgmq => &[], ExtensionId::Pgtap => &[], ExtensionId::Postgis => &[ "contrib/postgis-3.6/legacy.sql", @@ -690,6 +705,7 @@ pub(super) const fn extension_sql_file_prefixes(extension: Extension) -> &'stati ExtensionId::PgVisibility => &[], ExtensionId::PgWalinspect => &[], ExtensionId::Pgcrypto => &[], + ExtensionId::Pgmq => &[], ExtensionId::Pgtap => &["pgtap-core", "pgtap-schema"], ExtensionId::Postgis => &[ "postgis_comments", @@ -739,6 +755,7 @@ pub(super) const fn extension_sql_file_names(extension: Extension) -> &'static [ ExtensionId::PgVisibility => &[], ExtensionId::PgWalinspect => &[], ExtensionId::Pgcrypto => &[], + ExtensionId::Pgmq => &[], ExtensionId::Pgtap => &["uninstall_pgtap.sql"], ExtensionId::Postgis => &["uninstall_postgis.sql"], ExtensionId::Seg => &[], @@ -786,6 +803,7 @@ pub(super) const fn runtime_environment( ExtensionId::PgVisibility => &[], ExtensionId::PgWalinspect => &[], ExtensionId::Pgcrypto => &[], + ExtensionId::Pgmq => &[], ExtensionId::Pgtap => &[], ExtensionId::Postgis => &[ExtensionRuntimeEnvironment { name: "PROJ_DATA", diff --git a/src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extension-legal-catalog.json b/src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extension-legal-catalog.json index 2869b7cab..7509350d0 100644 --- a/src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extension-legal-catalog.json +++ b/src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extension-legal-catalog.json @@ -1,6 +1,6 @@ { "schema": "oliphaunt-android-extension-legal-catalog-v1", - "sourceCatalogSha256": "c1d2e09905d7ecc0172173b34b9e4104dad58987503dd3dab7af4ae78890d9f3", + "sourceCatalogSha256": "f6982b4f5ace1f2b8478bbb794dece00d6379545e64bf65a28fa28b459210028", "contracts": [ { "scope": "aggregate", @@ -324,6 +324,66 @@ } ] }, + { + "scope": "aggregate", + "identity": "oliphaunt-extension-pgmq", + "product": "oliphaunt-extension-pgmq", + "target": "android-arm64-v8a", + "profile": "external-native", + "licenseFiles": [ + "share/licenses/pgmq/LICENSE" + ], + "members": [ + { + "path": "LICENSE", + "bytes": 1085, + "sha256": "6f8300e2f43c5a012d6f914fe5affa9090b97b0be39ddf3846f01b905edd8c10", + "mode": "0644" + }, + { + "path": "THIRD_PARTY_NOTICES.md", + "bytes": 821, + "sha256": "20fd67487d1a631ba959cf7ec3fdbaf4977997ed624c0188dcb3c8870eded830", + "mode": "0644" + }, + { + "path": "share/licenses/pgmq/LICENSE", + "bytes": 917, + "sha256": "a3ce61e0031bdcad1024b1bf50ded2359602160f00e0cac8e509752273df6179", + "mode": "0644" + } + ] + }, + { + "scope": "aggregate", + "identity": "oliphaunt-extension-pgmq", + "product": "oliphaunt-extension-pgmq", + "target": "android-x86_64", + "profile": "external-native", + "licenseFiles": [ + "share/licenses/pgmq/LICENSE" + ], + "members": [ + { + "path": "LICENSE", + "bytes": 1085, + "sha256": "6f8300e2f43c5a012d6f914fe5affa9090b97b0be39ddf3846f01b905edd8c10", + "mode": "0644" + }, + { + "path": "THIRD_PARTY_NOTICES.md", + "bytes": 821, + "sha256": "20fd67487d1a631ba959cf7ec3fdbaf4977997ed624c0188dcb3c8870eded830", + "mode": "0644" + }, + { + "path": "share/licenses/pgmq/LICENSE", + "bytes": 917, + "sha256": "a3ce61e0031bdcad1024b1bf50ded2359602160f00e0cac8e509752273df6179", + "mode": "0644" + } + ] + }, { "scope": "aggregate", "identity": "oliphaunt-extension-pgtap", @@ -2380,6 +2440,66 @@ } ] }, + { + "scope": "leaf", + "identity": "pgmq", + "product": "oliphaunt-extension-pgmq", + "target": "android-arm64-v8a", + "profile": "external-native", + "licenseFiles": [ + "share/licenses/pgmq/LICENSE" + ], + "members": [ + { + "path": "LICENSE", + "bytes": 1085, + "sha256": "6f8300e2f43c5a012d6f914fe5affa9090b97b0be39ddf3846f01b905edd8c10", + "mode": "0644" + }, + { + "path": "THIRD_PARTY_NOTICES.md", + "bytes": 821, + "sha256": "20fd67487d1a631ba959cf7ec3fdbaf4977997ed624c0188dcb3c8870eded830", + "mode": "0644" + }, + { + "path": "files/share/licenses/pgmq/LICENSE", + "bytes": 917, + "sha256": "a3ce61e0031bdcad1024b1bf50ded2359602160f00e0cac8e509752273df6179", + "mode": "0644" + } + ] + }, + { + "scope": "leaf", + "identity": "pgmq", + "product": "oliphaunt-extension-pgmq", + "target": "android-x86_64", + "profile": "external-native", + "licenseFiles": [ + "share/licenses/pgmq/LICENSE" + ], + "members": [ + { + "path": "LICENSE", + "bytes": 1085, + "sha256": "6f8300e2f43c5a012d6f914fe5affa9090b97b0be39ddf3846f01b905edd8c10", + "mode": "0644" + }, + { + "path": "THIRD_PARTY_NOTICES.md", + "bytes": 821, + "sha256": "20fd67487d1a631ba959cf7ec3fdbaf4977997ed624c0188dcb3c8870eded830", + "mode": "0644" + }, + { + "path": "files/share/licenses/pgmq/LICENSE", + "bytes": 917, + "sha256": "a3ce61e0031bdcad1024b1bf50ded2359602160f00e0cac8e509752273df6179", + "mode": "0644" + } + ] + }, { "scope": "leaf", "identity": "pgtap", diff --git a/src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extensions.properties b/src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extensions.properties index e7fcddbbd..66ece44aa 100644 --- a/src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extensions.properties +++ b/src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extensions.properties @@ -1,7 +1,7 @@ # This file is generated by src/extensions/tools/check-extension-model.sh. # Do not edit by hand. schema=oliphaunt-android-extension-catalog-v2 -catalogSha256=c1d2e09905d7ecc0172173b34b9e4104dad58987503dd3dab7af4ae78890d9f3 +catalogSha256=f6982b4f5ace1f2b8478bbb794dece00d6379545e64bf65a28fa28b459210028 extension.amcheck.artifactProduct=oliphaunt-extension-contrib-pg18 extension.amcheck.releaseProduct=liboliphaunt-native extension.amcheck.mavenGroup=dev.oliphaunt.extensions @@ -176,6 +176,12 @@ extension.pgcrypto.mavenGroup=dev.oliphaunt.extensions extension.pgcrypto.mavenArtifact=oliphaunt-extension-contrib-pg18 extension.pgcrypto.runtimeBound=true extension.pgcrypto.dependencies= +extension.pgmq.artifactProduct=oliphaunt-extension-pgmq +extension.pgmq.releaseProduct=oliphaunt-extension-pgmq +extension.pgmq.mavenGroup=dev.oliphaunt.extensions +extension.pgmq.mavenArtifact=oliphaunt-extension-pgmq +extension.pgmq.runtimeBound=false +extension.pgmq.dependencies= extension.pgtap.artifactProduct=oliphaunt-extension-pgtap extension.pgtap.releaseProduct=oliphaunt-extension-pgtap extension.pgtap.mavenGroup=dev.oliphaunt.extensions diff --git a/src/native/sdks/kotlin/oliphaunt/src/commonMain/kotlin/dev/oliphaunt/GeneratedExtensions.kt b/src/native/sdks/kotlin/oliphaunt/src/commonMain/kotlin/dev/oliphaunt/GeneratedExtensions.kt index 929af8cae..2fbdbbfdb 100644 --- a/src/native/sdks/kotlin/oliphaunt/src/commonMain/kotlin/dev/oliphaunt/GeneratedExtensions.kt +++ b/src/native/sdks/kotlin/oliphaunt/src/commonMain/kotlin/dev/oliphaunt/GeneratedExtensions.kt @@ -38,6 +38,7 @@ internal val generatedExtensionRuntimeContracts: Map '{"payload":"persistent"}'::jsonb OR message.read_ct <> 1 THEN + RAISE EXCEPTION 'PGMQ read lost payload or delivery count'; + END IF; + IF EXISTS (SELECT FROM pgmq.read('oliphaunt_queue', 30, 1)) THEN + RAISE EXCEPTION 'PGMQ visibility timeout did not hide the leased message'; + END IF; + IF NOT pgmq.archive('oliphaunt_queue', message.msg_id) THEN + RAISE EXCEPTION 'PGMQ archive failed'; + END IF; + IF (SELECT count(*) FROM pgmq.a_oliphaunt_queue) <> 1 THEN + RAISE EXCEPTION 'PGMQ archive lost the message'; + END IF; +END +$proof$; +-- oliphaunt-statement +SELECT pgmq.send('oliphaunt_queue', '{"payload":"delete"}'::jsonb); +-- oliphaunt-statement +DO $proof$ +DECLARE + message record; +BEGIN + SELECT * INTO STRICT message FROM pgmq.pop('oliphaunt_queue'); + IF message.message <> '{"payload":"delete"}'::jsonb THEN + RAISE EXCEPTION 'PGMQ pop returned the wrong message'; + END IF; + IF EXISTS (SELECT FROM pgmq.read('oliphaunt_queue', 30, 1)) THEN + RAISE EXCEPTION 'PGMQ pop did not remove the message'; + END IF; +END +$proof$; +-- oliphaunt-statement +SELECT pgmq.create('oliphaunt_drop_queue'); +-- oliphaunt-statement +SELECT pgmq.drop_queue('oliphaunt_drop_queue'); +-- oliphaunt-statement +SELECT pgmq.send('oliphaunt_queue', '{"payload":"restart-and-restore"}'::jsonb); +-- oliphaunt-statement +-- oliphaunt-verify +DO $proof$ +BEGIN + IF (SELECT count(*) FROM pgmq.q_oliphaunt_queue) <> 1 OR + NOT EXISTS (SELECT FROM pgmq.q_oliphaunt_queue + WHERE message = '{"payload":"restart-and-restore"}'::jsonb) THEN + RAISE EXCEPTION 'PGMQ persistent queue message did not survive'; + END IF; + IF (SELECT count(*) FROM pgmq.a_oliphaunt_queue) <> 1 OR + NOT EXISTS (SELECT FROM pgmq.a_oliphaunt_queue + WHERE message = '{"payload":"persistent"}'::jsonb) THEN + RAISE EXCEPTION 'PGMQ archived message did not survive'; + END IF; +END +$proof$; diff --git a/src/wasix/runtime/tools/xtask/src/asset_pipeline.rs b/src/wasix/runtime/tools/xtask/src/asset_pipeline.rs index 3b1b105f8..90291e62e 100644 --- a/src/wasix/runtime/tools/xtask/src/asset_pipeline.rs +++ b/src/wasix/runtime/tools/xtask/src/asset_pipeline.rs @@ -1691,6 +1691,21 @@ fn stage_pgxs_style_extension( .join(control_file.file_name().unwrap_or_default()), )?; } + if sql_name == "pgmq" { + let sql_dir = build_dir.join("sql"); + let mut copied = false; + for entry in sorted_children(&sql_dir)? { + let Some(name) = entry.file_name().and_then(|name| name.to_str()) else { + continue; + }; + if entry.is_file() && name.starts_with("pgmq--") && name.ends_with(".sql") { + copy_file(&entry, &extension_sql_dir.join(name))?; + copied = true; + } + } + ensure!(copied, "PGMQ build has no versioned SQL files"); + return Ok(()); + } let mut copied_root_sql = copy_extension_sql_files(&build_dir, sql_name, &extension_sql_dir)?; if !copied_root_sql { copied_root_sql = copy_extension_sql_files(source, sql_name, &extension_sql_dir)?; @@ -2558,6 +2573,65 @@ fn extension_control_files_for_asset_manifest( mod tests { use super::*; + #[test] + fn pgmq_stages_generated_install_and_upgrade_sql_only() { + let root = temp_aot_manifest_path("pgmq-stage"); + let source = root.join("source"); + let build = root.join("build"); + let stage = root.join("stage"); + let sql = build.join("pgxs/pgmq/sql"); + fs::create_dir_all(&source).unwrap(); + fs::create_dir_all(&sql).unwrap(); + fs::write(source.join("pgmq.control"), "default_version = '1.13.0'\n").unwrap(); + for name in [ + "pgmq.sql", + "pgmq--1.13.0.sql", + "pgmq--1.12.0--1.13.0.sql", + "foreign.sql", + ] { + fs::write(sql.join(name), "-- SQL\n").unwrap(); + } + let extension = extension_catalog::ExtensionBuildSpec { + id: "pgmq".into(), + display_name: "PGMQ".into(), + sql_name: "pgmq".into(), + build_kind: "pgxs-sql-only".into(), + source_dir: source.to_string_lossy().into(), + contrib_dir: None, + module_file: None, + archive: "extensions/pgmq.tar.zst".into(), + control_file: None, + native_support_modules: vec![], + excluded_sql_extensions: vec![], + staging: None, + lifecycle: extension_catalog::ExtensionLifecycle { + create_extension: true, + create_schema: Some("pgmq".into()), + load_sql: vec![], + post_create_sql: vec![], + startup_config: vec![], + preload_required: false, + restart_required: false, + shared_memory_required: false, + }, + }; + stage_pgxs_style_extension(&build, &extension, &stage).unwrap(); + let files: Vec<_> = sorted_children(&stage.join("share/postgresql/extension")) + .unwrap() + .into_iter() + .map(|path| path.file_name().unwrap().to_string_lossy().into_owned()) + .collect(); + assert_eq!( + files, + [ + "pgmq--1.12.0--1.13.0.sql", + "pgmq--1.13.0.sql", + "pgmq.control" + ] + ); + fs::remove_dir_all(root).unwrap(); + } + fn manifest_extension_metadata( create_extension: bool, control_files: Vec<&str>, diff --git a/src/wasix/runtime/tools/xtask/src/extension_catalog.rs b/src/wasix/runtime/tools/xtask/src/extension_catalog.rs index d79407c61..4347779ea 100644 --- a/src/wasix/runtime/tools/xtask/src/extension_catalog.rs +++ b/src/wasix/runtime/tools/xtask/src/extension_catalog.rs @@ -54,7 +54,7 @@ fn build_specs_at( display_name: extension.display_name.clone(), sql_name: extension.sql_name.clone(), build_kind, - source_dir: extension_source_dir(extension), + source_dir: extension_source_dir_at(extension, repository_root)?, contrib_dir: (extension.source_kind == "postgres-contrib") .then(|| extension_contrib_dir_name(&extension.id)), module_file: extension.native_module_file.clone(), @@ -205,8 +205,41 @@ fn build_kind( } } -fn extension_source_dir(extension: &ExtensionCatalogEntry) -> String { - extension_source_dir_for(&extension.id, &extension.source_kind) +fn extension_source_dir_at( + extension: &ExtensionCatalogEntry, + repository_root: &Path, +) -> Result { + let root = extension_source_dir_for(&extension.id, &extension.source_kind); + let recipe = repository_root + .join(EXTERNAL_EXTENSION_RECIPE_ROOT) + .join(&extension.sql_name) + .join("recipe.toml"); + if !recipe.is_file() { + return Ok(root); + } + let text = fs::read_to_string(&recipe).with_context(|| format!("read {}", recipe.display()))?; + let recipe: toml::Value = toml::from_str(&text).context("parse extension recipe")?; + let Some(subdirectory) = recipe + .get("build") + .and_then(|value| value.get("source_subdirectory")) + else { + return Ok(root); + }; + let subdirectory = subdirectory + .as_str() + .context("PGXS source subdirectory must be a string")?; + ensure!( + subdirectory.split('/').all(|part| { + let mut bytes = part.bytes(); + bytes + .next() + .is_some_and(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'_' | b'-')) + && bytes + .all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'_' | b'-' | b'.')) + }), + "PGXS source subdirectory must stay within the pinned checkout" + ); + Ok(format!("{root}/{subdirectory}")) } fn extension_source_dir_for(id: &str, source_kind: &str) -> String { @@ -376,5 +409,11 @@ mod tests { .iter() .any(|module| module.name == "postgis_deps") ); + let pgmq = specs.iter().find(|spec| spec.id == "pgmq").unwrap(); + assert_eq!(pgmq.build_kind, "pgxs-sql-only"); + assert_eq!( + pgmq.source_dir, + "target/oliphaunt-sources/checkouts/pgmq/pgmq-extension" + ); } } diff --git a/src/wasix/sdks/rust/src/oliphaunt/generated_extensions.rs b/src/wasix/sdks/rust/src/oliphaunt/generated_extensions.rs index 04f2b30d4..b5f76c0dc 100644 --- a/src/wasix/sdks/rust/src/oliphaunt/generated_extensions.rs +++ b/src/wasix/sdks/rust/src/oliphaunt/generated_extensions.rs @@ -292,6 +292,16 @@ const DEFINITION_PGCRYPTO: Extension = Extension { package: None, }; +const DEFINITION_PGMQ: Extension = Extension { + sql_name: "pgmq", + native_support_modules: &[], + native_module_file: None, + aot_name: None, + dependencies: &[], + startup_config: &[], + package: None, +}; + const DEFINITION_PGTAP: Extension = Extension { sql_name: "pgtap", native_support_modules: &[], @@ -483,6 +493,9 @@ impl Extension { /// Select the `pgcrypto` artifact. pub const PGCRYPTO: Self = DEFINITION_PGCRYPTO; + /// Select the `pgmq` artifact. + + pub const PGMQ: Self = DEFINITION_PGMQ; /// Select the `pgtap` artifact. pub const PGTAP: Self = DEFINITION_PGTAP; @@ -545,6 +558,7 @@ impl Extension { Self::PG_VISIBILITY, Self::PG_WALINSPECT, Self::PGCRYPTO, + Self::PGMQ, Self::PGTAP, Self::POSTGIS, Self::SEG, @@ -619,6 +633,8 @@ pub(super) fn creates_database_object_for_test(extension: Extension) -> bool { "pgcrypto" => true, + "pgmq" => true, + "pgtap" => true, "postgis" => true, @@ -736,6 +752,11 @@ pub(super) fn activation_sql_for_test(extension: Extension) -> &'static [&'stati "pgcrypto" => &["CREATE EXTENSION IF NOT EXISTS \"pgcrypto\";"], + "pgmq" => &[ + "CREATE SCHEMA IF NOT EXISTS \"pgmq\";", + "CREATE EXTENSION IF NOT EXISTS \"pgmq\" WITH SCHEMA \"pgmq\";", + ], + "pgtap" => &["CREATE EXTENSION IF NOT EXISTS \"pgtap\" WITH SCHEMA \"pg_catalog\";"], "postgis" => &["CREATE EXTENSION IF NOT EXISTS \"postgis\";"], From 5db6fa9412a6fb65815300b395e21eabdcdc1bf7 Mon Sep 17 00:00:00 2001 From: Sid Jain Date: Mon, 19 Oct 2026 06:16:27 +0000 Subject: [PATCH 03/11] feat(extensions): add missing PostgreSQL contrib members --- .../src/generated/extension-smoke.ts | 78 +++- src/extensions/catalog/extensions.source.json | 185 ++++++++++ src/extensions/contrib/postgres18.toml | 46 +++ src/extensions/evidence/matrix.toml | 54 +++ src/extensions/generated/contrib-build.tsv | 6 + .../generated/docs/extension-evidence.json | 212 ++++++++++- .../generated/extensions.catalog.json | 223 ++++++++++++ .../generated/mobile/static-extensions.tsv | 6 + .../generated/mobile/static-registry.json | 42 +++ src/extensions/generated/sdk/extensions.json | 160 ++++++++- .../generated/wasix/extensions.json | 133 +++++++ src/extensions/tools/extension-model.test.mts | 15 + .../tools/extension-projections.mts | 2 +- .../runtime/bin/build-postgres18-linux.sh | 27 +- .../runtime/bin/build-postgres18-macos.sh | 27 +- .../rust-bindings/src/generated/extensions.rs | 108 ++++++ .../android/extension-legal-catalog.json | 338 +++++++++++++++++- .../oliphaunt/android/extensions.properties | 38 +- .../dev/oliphaunt/GeneratedExtensions.kt | 6 + .../dev/oliphaunt/OliphauntExtension.kt | 6 + .../react-native/src/generated/extensions.ts | 148 +++++++- .../OliphauntCore/OliphauntExtension.swift | 6 + .../sdks/ts/src/generated/extensions.ts | 142 +++++++- src/test-fixtures/extensions/autoinc.sql | 21 ++ .../extensions/insert_username.sql | 19 + src/test-fixtures/extensions/manifest.json | 6 + src/test-fixtures/extensions/moddatetime.sql | 19 + .../extensions/pg_logicalinspect.sql | 23 ++ .../extensions/pg_stat_statements.sql | 21 ++ src/test-fixtures/extensions/refint.sql | 39 ++ .../runtime/assets/generated/wasix-dl.exports | 33 ++ .../tools/xtask/src/extension_catalog.rs | 30 ++ .../src/oliphaunt/generated_extensions.rs | 114 ++++++ 33 files changed, 2313 insertions(+), 20 deletions(-) create mode 100644 src/test-fixtures/extensions/autoinc.sql create mode 100644 src/test-fixtures/extensions/insert_username.sql create mode 100644 src/test-fixtures/extensions/moddatetime.sql create mode 100644 src/test-fixtures/extensions/pg_logicalinspect.sql create mode 100644 src/test-fixtures/extensions/pg_stat_statements.sql create mode 100644 src/test-fixtures/extensions/refint.sql diff --git a/src/examples/native/react-native-expo/src/generated/extension-smoke.ts b/src/examples/native/react-native-expo/src/generated/extension-smoke.ts index 28e8718e9..2c9968259 100644 --- a/src/examples/native/react-native-expo/src/generated/extension-smoke.ts +++ b/src/examples/native/react-native-expo/src/generated/extension-smoke.ts @@ -7,7 +7,7 @@ export type GeneratedMobileExtensionProof = { readonly selectedExtensionDependencies: readonly string[]; }; -export const GENERATED_MOBILE_EXTENSION_METADATA_SHA256 = "f6982b4f5ace1f2b8478bbb794dece00d6379545e64bf65a28fa28b459210028" as const; +export const GENERATED_MOBILE_EXTENSION_METADATA_SHA256 = "b9b246ee0a810514f7ef1fc5966ae31d8e857e8fb146b4593baa04c32cf8fcbf" as const; export const GENERATED_MOBILE_EXTENSION_PLAN = [ { @@ -20,6 +20,11 @@ export const GENERATED_MOBILE_EXTENSION_PLAN = [ "createsExtension": false, "selectedExtensionDependencies": [] }, + { + "sqlName": "autoinc", + "createsExtension": true, + "selectedExtensionDependencies": [] + }, { "sqlName": "bloom", "createsExtension": true, @@ -77,6 +82,11 @@ export const GENERATED_MOBILE_EXTENSION_PLAN = [ "createsExtension": true, "selectedExtensionDependencies": [] }, + { + "sqlName": "insert_username", + "createsExtension": true, + "selectedExtensionDependencies": [] + }, { "sqlName": "intarray", "createsExtension": true, @@ -97,6 +107,11 @@ export const GENERATED_MOBILE_EXTENSION_PLAN = [ "createsExtension": true, "selectedExtensionDependencies": [] }, + { + "sqlName": "moddatetime", + "createsExtension": true, + "selectedExtensionDependencies": [] + }, { "sqlName": "pageinspect", "createsExtension": true, @@ -122,6 +137,16 @@ export const GENERATED_MOBILE_EXTENSION_PLAN = [ "createsExtension": true, "selectedExtensionDependencies": [] }, + { + "sqlName": "pg_logicalinspect", + "createsExtension": true, + "selectedExtensionDependencies": [] + }, + { + "sqlName": "pg_stat_statements", + "createsExtension": true, + "selectedExtensionDependencies": [] + }, { "sqlName": "pg_surgery", "createsExtension": true, @@ -172,6 +197,11 @@ export const GENERATED_MOBILE_EXTENSION_PLAN = [ "createsExtension": true, "selectedExtensionDependencies": [] }, + { + "sqlName": "refint", + "createsExtension": true, + "selectedExtensionDependencies": [] + }, { "sqlName": "seg", "createsExtension": true, @@ -223,6 +253,15 @@ export const GENERATED_MOBILE_EXTENSION_SMOKE = { "auto_explain": [ "EXPLAIN SELECT count(*) FROM pg_class;" ], + "autoinc": [ + "DROP TABLE IF EXISTS oliphaunt_autoinc;", + "DROP SEQUENCE IF EXISTS oliphaunt_autoinc_sequence;", + "CREATE SEQUENCE oliphaunt_autoinc_sequence START 11;", + "CREATE TABLE oliphaunt_autoinc (id integer, value text);", + "CREATE TRIGGER oliphaunt_autoinc_trigger BEFORE INSERT ON oliphaunt_autoinc\nFOR EACH ROW EXECUTE FUNCTION autoinc('id', 'oliphaunt_autoinc_sequence');", + "INSERT INTO oliphaunt_autoinc VALUES (NULL, 'generated'), (50, 'preserved');", + "-- oliphaunt-verify\nDO $oliphaunt$\nBEGIN\n IF (SELECT array_agg(id ORDER BY id) FROM oliphaunt_autoinc) IS DISTINCT FROM ARRAY[11, 50] THEN\n RAISE EXCEPTION 'autoinc did not generate a missing id and preserve an explicit id';\n END IF;\nEND\n$oliphaunt$;" + ], "bloom": [ "CREATE TEMP TABLE oliphaunt_bloom (id int, value int);", "CREATE INDEX oliphaunt_bloom_idx ON oliphaunt_bloom USING bloom (id, value);", @@ -272,6 +311,14 @@ export const GENERATED_MOBILE_EXTENSION_SMOKE = { "INSERT INTO oliphaunt_hstore VALUES ('a=>1,b=>2'::hstore);", "DO $$ DECLARE v text; BEGIN SELECT attrs -> 'b' INTO v FROM oliphaunt_hstore; IF v <> '2' THEN RAISE EXCEPTION 'hstore lookup failed: %', v; END IF; END $$;" ], + "insert_username": [ + "DROP TABLE IF EXISTS oliphaunt_insert_username;", + "CREATE TABLE oliphaunt_insert_username (id integer, username text, expected_username text);", + "CREATE TRIGGER oliphaunt_insert_username_trigger BEFORE INSERT OR UPDATE ON oliphaunt_insert_username\nFOR EACH ROW EXECUTE FUNCTION insert_username('username');", + "INSERT INTO oliphaunt_insert_username VALUES (1, 'untrusted', current_user);", + "UPDATE oliphaunt_insert_username SET username = 'still untrusted';", + "-- oliphaunt-verify\nDO $oliphaunt$\nBEGIN\n IF NOT EXISTS (SELECT FROM oliphaunt_insert_username WHERE username = expected_username) THEN\n RAISE EXCEPTION 'insert_username did not replace the caller-supplied username';\n END IF;\nEND\n$oliphaunt$;" + ], "intarray": [ "CREATE TEMP TABLE oliphaunt_intarray (tags int[]);", "INSERT INTO oliphaunt_intarray VALUES (ARRAY[1, 2, 5]), (ARRAY[3, 4]);", @@ -290,6 +337,14 @@ export const GENERATED_MOBILE_EXTENSION_SMOKE = { "INSERT INTO oliphaunt_ltree VALUES ('Top.Science.Astronomy'), ('Top.Collections.Pictures');", "DO $$ DECLARE n int; BEGIN SELECT count(*) INTO n FROM oliphaunt_ltree WHERE path <@ 'Top.Science'; IF n <> 1 THEN RAISE EXCEPTION 'ltree ancestor query failed: %', n; END IF; END $$;" ], + "moddatetime": [ + "DROP TABLE IF EXISTS oliphaunt_moddatetime;", + "CREATE TABLE oliphaunt_moddatetime (id integer, modified_at timestamptz);", + "CREATE TRIGGER oliphaunt_moddatetime_trigger BEFORE UPDATE ON oliphaunt_moddatetime\nFOR EACH ROW EXECUTE FUNCTION moddatetime('modified_at');", + "INSERT INTO oliphaunt_moddatetime VALUES (1, '2000-01-01 00:00:00+00');", + "UPDATE oliphaunt_moddatetime SET id = 2;", + "-- oliphaunt-verify\nDO $oliphaunt$\nBEGIN\n IF NOT EXISTS (SELECT FROM oliphaunt_moddatetime WHERE id = 2 AND modified_at > '2000-01-01 00:00:00+00') THEN\n RAISE EXCEPTION 'moddatetime did not update the modification timestamp';\n END IF;\nEND\n$oliphaunt$;" + ], "pageinspect": [ "CREATE TEMP TABLE oliphaunt_pageinspect (id int);", "INSERT INTO oliphaunt_pageinspect SELECT generate_series(1, 5);", @@ -319,6 +374,14 @@ export const GENERATED_MOBILE_EXTENSION_SMOKE = { "SELECT pgivm.restore_immv('oliphaunt_ivm_restored', $$ SELECT id, amount FROM oliphaunt_ivm_orders $$);", "-- oliphaunt-verify\nDO $$\nDECLARE n int; populated boolean;\nBEGIN\n SELECT count(*) INTO n FROM oliphaunt_ivm_summary;\n IF n <> 2 THEN RAISE EXCEPTION 'pg_ivm count failed: %', n; END IF;\n UPDATE oliphaunt_ivm_orders SET amount = 11 WHERE id = 1;\n SELECT amount INTO n FROM oliphaunt_ivm_summary WHERE id = 1;\n IF n IS DISTINCT FROM 11 THEN RAISE EXCEPTION 'pg_ivm maintenance failed: %', n; END IF;\n UPDATE oliphaunt_ivm_orders SET amount = 10 WHERE id = 1;\n SELECT ispopulated INTO populated FROM pgivm.pg_ivm_immv\n WHERE immvrelid = 'oliphaunt_ivm_restored'::regclass;\n IF populated IS DISTINCT FROM true THEN\n RAISE EXCEPTION 'pg_ivm restored relation lost populated state';\n END IF;\n -- Before 1.17 this refresh added duplicate maintenance triggers after restore.\n PERFORM pgivm.refresh_immv('oliphaunt_ivm_restored');\n INSERT INTO oliphaunt_ivm_orders VALUES (99, 30);\n SELECT count(*) INTO n FROM oliphaunt_ivm_restored WHERE id = 99;\n IF n <> 1 THEN RAISE EXCEPTION 'pg_ivm restored maintenance duplicated rows: %', n; END IF;\n DELETE FROM oliphaunt_ivm_orders WHERE id = 99;\nEND $$;" ], + "pg_logicalinspect": [ + "-- Exercise both entry points without requiring a logical replication slot.\n-- Invalid snapshot names must be rejected before any filesystem access.\n-- oliphaunt-verify\nDO $oliphaunt$\nBEGIN\n BEGIN\n PERFORM pg_get_logical_snapshot_meta('../invalid');\n RAISE EXCEPTION 'pg_logicalinspect accepted an invalid snapshot name';\n EXCEPTION WHEN internal_error THEN\n IF SQLERRM <> 'invalid snapshot file name \"../invalid\"' THEN\n RAISE;\n END IF;\n END;\n BEGIN\n PERFORM pg_get_logical_snapshot_info('../invalid');\n RAISE EXCEPTION 'pg_logicalinspect accepted an invalid snapshot name';\n EXCEPTION WHEN internal_error THEN\n IF SQLERRM <> 'invalid snapshot file name \"../invalid\"' THEN\n RAISE;\n END IF;\n END;\nEND\n$oliphaunt$;" + ], + "pg_stat_statements": [ + "-- Reset and collect fresh counters on creation, restart, and backup restore.\n-- This fails if the library was loaded after shared-memory startup.\n-- oliphaunt-verify\nSELECT pg_stat_statements_reset();", + "-- oliphaunt-verify\nSELECT sum(value) FROM generate_series(1, 3) AS oliphaunt_pgss_probe(value);", + "-- oliphaunt-verify\nDO $oliphaunt$\nBEGIN\n IF NOT EXISTS (\n SELECT FROM pg_stat_statements\n WHERE query LIKE 'SELECT sum(value) FROM generate_series%oliphaunt_pgss_probe%'\n AND dbid = (SELECT oid FROM pg_database WHERE datname = current_database())\n AND queryid <> 0 AND calls >= 1 AND rows = calls\n ) THEN\n RAISE EXCEPTION 'pg_stat_statements did not record a completed query';\n END IF;\nEND\n$oliphaunt$;" + ], "pg_surgery": [ "DO $$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_proc WHERE proname = 'heap_force_kill') THEN RAISE EXCEPTION 'pg_surgery function missing'; END IF; END $$;" ], @@ -378,6 +441,19 @@ export const GENERATED_MOBILE_EXTENSION_SMOKE = { "CREATE INDEX oliphaunt_postgis_points_gix ON oliphaunt_postgis_points USING GIST (geom);", "-- oliphaunt-verify\nDO $$\nDECLARE\n distance float8;\n srid int;\n area float8;\n polygons int;\n nearby int;\nBEGIN\n SELECT ST_Distance(ST_GeomFromText('POINT(0 0)'), ST_GeomFromText('POINT(3 4)')) INTO distance;\n IF distance <> 5 THEN\n RAISE EXCEPTION 'postgis geometry distance failed: %', distance;\n END IF;\n IF ST_AsText(ST_Buffer(ST_GeomFromText('POINT(0 0)'), 1, 'quad_segs=1')) IS NULL THEN\n RAISE EXCEPTION 'postgis buffer failed';\n END IF;\n IF NOT ST_Within(\n ST_GeomFromText('POINT(0.5 0.5)'),\n ST_GeomFromText('POLYGON((0 0,0 1,1 1,1 0,0 0))')\n ) THEN\n RAISE EXCEPTION 'postgis within failed';\n END IF;\n SELECT ST_SRID(ST_Transform(ST_SetSRID(ST_MakePoint(-71.060316, 48.432044), 4326), 3857)) INTO srid;\n IF srid <> 3857 THEN\n RAISE EXCEPTION 'postgis transform failed: %', srid;\n END IF;\n SELECT ST_Area(ST_Transform(ST_SetSRID(ST_MakePolygon(ST_GeomFromText('LINESTRING(-71.1776848522251 42.3902896512902,-71.1776843766797 42.3903701743239,-71.1775844305465 42.3903829478009,-71.1775825927231 42.3902893647987,-71.1776848522251 42.3902896512902)')), 4326), 26986)) INTO area;\n IF area <= 0 THEN\n RAISE EXCEPTION 'postgis projected area failed: %', area;\n END IF;\n SELECT ST_NumGeometries(ST_Polygonize(ARRAY[\n ST_GeomFromText('LINESTRING(0 0, 1 0)'),\n ST_GeomFromText('LINESTRING(1 0, 1 1)'),\n ST_GeomFromText('LINESTRING(1 1, 0 1)'),\n ST_GeomFromText('LINESTRING(0 1, 0 0)')\n ])) INTO polygons;\n IF polygons <> 1 THEN\n RAISE EXCEPTION 'postgis polygonize failed: %', polygons;\n END IF;\n SELECT count(*) INTO nearby\n FROM oliphaunt_postgis_points\n WHERE ST_DWithin(\n geom::geography,\n ST_SetSRID(ST_MakePoint(-71.060316, 48.432044), 4326)::geography,\n 200\n );\n IF nearby <> 2 THEN\n RAISE EXCEPTION 'postgis dwithin failed: %', nearby;\n END IF;\nEND $$;" ], + "refint": [ + "DROP TABLE IF EXISTS oliphaunt_refint_child;", + "DROP TABLE IF EXISTS oliphaunt_refint_parent;", + "CREATE TABLE oliphaunt_refint_parent (id integer PRIMARY KEY);", + "CREATE TABLE oliphaunt_refint_child (parent_id integer);", + "CREATE TRIGGER oliphaunt_refint_parent_trigger AFTER DELETE OR UPDATE ON oliphaunt_refint_parent\nFOR EACH ROW EXECUTE FUNCTION check_foreign_key(1, 'cascade', 'id', 'oliphaunt_refint_child', 'parent_id');", + "CREATE TRIGGER oliphaunt_refint_child_trigger AFTER INSERT OR UPDATE ON oliphaunt_refint_child\nFOR EACH ROW EXECUTE FUNCTION check_primary_key('parent_id', 'oliphaunt_refint_parent', 'id');", + "INSERT INTO oliphaunt_refint_parent VALUES (1), (2);", + "INSERT INTO oliphaunt_refint_child VALUES (1), (2);", + "DO $oliphaunt$\nBEGIN\n BEGIN\n INSERT INTO oliphaunt_refint_child VALUES (3);\n RAISE EXCEPTION 'refint accepted a missing parent';\n EXCEPTION WHEN triggered_action_exception THEN\n NULL;\n END;\nEND\n$oliphaunt$;", + "DELETE FROM oliphaunt_refint_parent WHERE id = 1;", + "-- oliphaunt-verify\nDO $oliphaunt$\nBEGIN\n IF (SELECT array_agg(parent_id) FROM oliphaunt_refint_child) IS DISTINCT FROM ARRAY[2] THEN\n RAISE EXCEPTION 'refint did not cascade deletion to the referencing row';\n END IF;\nEND\n$oliphaunt$;" + ], "seg": [ "DO $$ BEGIN IF '7(+-)1'::seg::text <> '6 .. 8' THEN RAISE EXCEPTION 'seg cast failed'; END IF; END $$;" ], diff --git a/src/extensions/catalog/extensions.source.json b/src/extensions/catalog/extensions.source.json index 8ea54d61c..9d4949362 100644 --- a/src/extensions/catalog/extensions.source.json +++ b/src/extensions/catalog/extensions.source.json @@ -65,6 +65,37 @@ "native-module-file": "auto_explain.so", "notes": [] }, + { + "id": "autoinc", + "sql-name": "autoinc", + "rust-constant": "AUTOINC", + "display-name": "autoinc", + "source-kind": "postgres-contrib", + "upstream-import-name": "autoinc", + "package-export": "./contrib/autoinc", + "tags": ["postgres extension", "postgres/contrib"], + "control-file": "src/third-party/postgres/contrib/spi/autoinc.control", + "control": { + "module-pathname": "$libdir/autoinc", + "requires": [], + "relocatable": "true" + }, + "dependencies": [], + "load-order": [], + "lifecycle": { + "create-extension": true, + "create-schema": "pg_catalog", + "load-sql": [], + "post-create-sql": [], + "startup-config": [], + "preload-required": false, + "restart-required": false, + "shared-memory-required": false + }, + "tests": ["src/test-fixtures/extensions/autoinc.sql"], + "native-module-file": "autoinc.so", + "notes": [] + }, { "id": "bloom", "sql-name": "bloom", @@ -427,6 +458,37 @@ "native-module-file": "hstore.so", "notes": [] }, + { + "id": "insert_username", + "sql-name": "insert_username", + "rust-constant": "INSERT_USERNAME", + "display-name": "insert_username", + "source-kind": "postgres-contrib", + "upstream-import-name": "insert_username", + "package-export": "./contrib/insert_username", + "tags": ["postgres extension", "postgres/contrib"], + "control-file": "src/third-party/postgres/contrib/spi/insert_username.control", + "control": { + "module-pathname": "$libdir/insert_username", + "requires": [], + "relocatable": "true" + }, + "dependencies": [], + "load-order": [], + "lifecycle": { + "create-extension": true, + "create-schema": "pg_catalog", + "load-sql": [], + "post-create-sql": [], + "startup-config": [], + "preload-required": false, + "restart-required": false, + "shared-memory-required": false + }, + "tests": ["src/test-fixtures/extensions/insert_username.sql"], + "native-module-file": "insert_username.so", + "notes": [] + }, { "id": "intarray", "sql-name": "intarray", @@ -555,6 +617,37 @@ "native-module-file": "ltree.so", "notes": [] }, + { + "id": "moddatetime", + "sql-name": "moddatetime", + "rust-constant": "MODDATETIME", + "display-name": "moddatetime", + "source-kind": "postgres-contrib", + "upstream-import-name": "moddatetime", + "package-export": "./contrib/moddatetime", + "tags": ["postgres extension", "postgres/contrib"], + "control-file": "src/third-party/postgres/contrib/spi/moddatetime.control", + "control": { + "module-pathname": "$libdir/moddatetime", + "requires": [], + "relocatable": "true" + }, + "dependencies": [], + "load-order": [], + "lifecycle": { + "create-extension": true, + "create-schema": "pg_catalog", + "load-sql": [], + "post-create-sql": [], + "startup-config": [], + "preload-required": false, + "restart-required": false, + "shared-memory-required": false + }, + "tests": ["src/test-fixtures/extensions/moddatetime.sql"], + "native-module-file": "moddatetime.so", + "notes": [] + }, { "id": "pageinspect", "sql-name": "pageinspect", @@ -722,6 +815,67 @@ "native-module-file": "pg_ivm.so", "notes": [] }, + { + "id": "pg_logicalinspect", + "sql-name": "pg_logicalinspect", + "rust-constant": "PG_LOGICALINSPECT", + "display-name": "pg_logicalinspect", + "source-kind": "postgres-contrib", + "upstream-import-name": "pg_logicalinspect", + "package-export": "./contrib/pg_logicalinspect", + "tags": ["postgres extension", "postgres/contrib"], + "control-file": "src/third-party/postgres/contrib/pg_logicalinspect/pg_logicalinspect.control", + "control": { + "module-pathname": "$libdir/pg_logicalinspect", + "requires": [], + "relocatable": "true" + }, + "dependencies": [], + "load-order": [], + "lifecycle": { + "create-extension": true, + "create-schema": "pg_catalog", + "load-sql": [], + "post-create-sql": [], + "startup-config": [], + "preload-required": false, + "restart-required": false, + "shared-memory-required": false + }, + "tests": ["src/test-fixtures/extensions/pg_logicalinspect.sql"], + "native-module-file": "pg_logicalinspect.so", + "notes": [] + }, + { + "id": "pg_stat_statements", + "sql-name": "pg_stat_statements", + "rust-constant": "PG_STAT_STATEMENTS", + "display-name": "pg_stat_statements", + "source-kind": "postgres-contrib", + "upstream-import-name": "pg_stat_statements", + "package-export": "./contrib/pg_stat_statements", + "tags": ["postgres extension", "postgres/contrib"], + "control-file": "src/third-party/postgres/contrib/pg_stat_statements/pg_stat_statements.control", + "control": { + "module-pathname": "$libdir/pg_stat_statements", + "requires": [], + "relocatable": "true" + }, + "dependencies": [], + "load-order": [], + "lifecycle": { + "create-extension": true, + "load-sql": [], + "post-create-sql": [], + "startup-config": ["shared_preload_libraries=pg_stat_statements"], + "preload-required": true, + "restart-required": true, + "shared-memory-required": true + }, + "tests": ["src/test-fixtures/extensions/pg_stat_statements.sql"], + "native-module-file": "pg_stat_statements.so", + "notes": [] + }, { "id": "pg_surgery", "sql-name": "pg_surgery", @@ -1043,6 +1197,37 @@ "native-module-file": "postgis-3.so", "notes": [] }, + { + "id": "refint", + "sql-name": "refint", + "rust-constant": "REFINT", + "display-name": "refint", + "source-kind": "postgres-contrib", + "upstream-import-name": "refint", + "package-export": "./contrib/refint", + "tags": ["postgres extension", "postgres/contrib"], + "control-file": "src/third-party/postgres/contrib/spi/refint.control", + "control": { + "module-pathname": "$libdir/refint", + "requires": [], + "relocatable": "true" + }, + "dependencies": [], + "load-order": [], + "lifecycle": { + "create-extension": true, + "create-schema": "pg_catalog", + "load-sql": [], + "post-create-sql": [], + "startup-config": [], + "preload-required": false, + "restart-required": false, + "shared-memory-required": false + }, + "tests": ["src/test-fixtures/extensions/refint.sql"], + "native-module-file": "refint.so", + "notes": [] + }, { "id": "seg", "sql-name": "seg", diff --git a/src/extensions/contrib/postgres18.toml b/src/extensions/contrib/postgres18.toml index b1a95d479..b3aeaa13b 100644 --- a/src/extensions/contrib/postgres18.toml +++ b/src/extensions/contrib/postgres18.toml @@ -16,6 +16,14 @@ sql-name = "auto_explain" contrib-dir = "auto_explain" module-file = "auto_explain.so" +[[extensions]] +id = "autoinc" +sql-name = "autoinc" +contrib-dir = "spi" +module-file = "autoinc.so" +default-version = "1.0" +mobile-static-source-files = ["autoinc.c"] + [[extensions]] id = "bloom" sql-name = "bloom" @@ -94,6 +102,14 @@ contrib-dir = "hstore" module-file = "hstore.so" default-version = "1.8" +[[extensions]] +id = "insert_username" +sql-name = "insert_username" +contrib-dir = "spi" +module-file = "insert_username.so" +default-version = "1.0" +mobile-static-source-files = ["insert_username.c"] + [[extensions]] id = "intarray" sql-name = "intarray" @@ -122,6 +138,14 @@ contrib-dir = "ltree" module-file = "ltree.so" default-version = "1.3" +[[extensions]] +id = "moddatetime" +sql-name = "moddatetime" +contrib-dir = "spi" +module-file = "moddatetime.so" +default-version = "1.0" +mobile-static-source-files = ["moddatetime.c"] + [[extensions]] id = "pageinspect" sql-name = "pageinspect" @@ -143,6 +167,20 @@ contrib-dir = "pg_freespacemap" module-file = "pg_freespacemap.so" default-version = "1.3" +[[extensions]] +id = "pg_logicalinspect" +sql-name = "pg_logicalinspect" +contrib-dir = "pg_logicalinspect" +module-file = "pg_logicalinspect.so" +default-version = "1.0" + +[[extensions]] +id = "pg_stat_statements" +sql-name = "pg_stat_statements" +contrib-dir = "pg_stat_statements" +module-file = "pg_stat_statements.so" +default-version = "1.12" + [[extensions]] id = "pg_surgery" sql-name = "pg_surgery" @@ -178,6 +216,14 @@ contrib-dir = "pgcrypto" module-file = "pgcrypto.so" default-version = "1.4" +[[extensions]] +id = "refint" +sql-name = "refint" +contrib-dir = "spi" +module-file = "refint.so" +default-version = "1.0" +mobile-static-source-files = ["refint.c"] + [[extensions]] id = "seg" sql-name = "seg" diff --git a/src/extensions/evidence/matrix.toml b/src/extensions/evidence/matrix.toml index 54c1db353..9f89ca689 100644 --- a/src/extensions/evidence/matrix.toml +++ b/src/extensions/evidence/matrix.toml @@ -62,6 +62,7 @@ source-digest-inputs = [ "src/test-fixtures/extensions/manifest.json", "src/test-fixtures/extensions/amcheck.sql", "src/test-fixtures/extensions/auto_explain.sql", + "src/test-fixtures/extensions/autoinc.sql", "src/test-fixtures/extensions/bloom.sql", "src/test-fixtures/extensions/btree_gin.sql", "src/test-fixtures/extensions/btree_gist.sql", @@ -73,15 +74,19 @@ source-digest-inputs = [ "src/test-fixtures/extensions/file_fdw.sql", "src/test-fixtures/extensions/fuzzystrmatch.sql", "src/test-fixtures/extensions/hstore.sql", + "src/test-fixtures/extensions/insert_username.sql", "src/test-fixtures/extensions/intarray.sql", "src/test-fixtures/extensions/isn.sql", "src/test-fixtures/extensions/lo.sql", "src/test-fixtures/extensions/ltree.sql", + "src/test-fixtures/extensions/moddatetime.sql", "src/test-fixtures/extensions/pageinspect.sql", "src/test-fixtures/extensions/pg_buffercache.sql", "src/test-fixtures/extensions/pg_freespacemap.sql", "src/test-fixtures/extensions/pg_hashids.sql", "src/test-fixtures/extensions/pg_ivm.sql", + "src/test-fixtures/extensions/pg_logicalinspect.sql", + "src/test-fixtures/extensions/pg_stat_statements.sql", "src/test-fixtures/extensions/pg_surgery.sql", "src/test-fixtures/extensions/pg_textsearch.sql", "src/test-fixtures/extensions/pg_trgm.sql", @@ -92,6 +97,7 @@ source-digest-inputs = [ "src/test-fixtures/extensions/pgmq.sql", "src/test-fixtures/extensions/pgtap.sql", "src/test-fixtures/extensions/postgis.sql", + "src/test-fixtures/extensions/refint.sql", "src/test-fixtures/extensions/seg.sql", "src/test-fixtures/extensions/tablefunc.sql", "src/test-fixtures/extensions/tcn.sql", @@ -118,6 +124,14 @@ platform-targets = ["portable"] runtime-modes = ["direct","server","restart","backup-restore","materialization"] evidence-required = ["wasix-full-lifecycle-v1"] +[[claims]] +extension = "autoinc" +postgres-major = 18 +artifact-family = "wasix-runtime" +platform-targets = ["portable"] +runtime-modes = ["direct","server","restart","backup-restore","materialization"] +evidence-required = ["wasix-full-lifecycle-v1"] + [[claims]] extension = "bloom" postgres-major = 18 @@ -206,6 +220,14 @@ platform-targets = ["portable"] runtime-modes = ["direct","server","restart","backup-restore","materialization"] evidence-required = ["wasix-full-lifecycle-v1"] +[[claims]] +extension = "insert_username" +postgres-major = 18 +artifact-family = "wasix-runtime" +platform-targets = ["portable"] +runtime-modes = ["direct","server","restart","backup-restore","materialization"] +evidence-required = ["wasix-full-lifecycle-v1"] + [[claims]] extension = "intarray" postgres-major = 18 @@ -238,6 +260,14 @@ platform-targets = ["portable"] runtime-modes = ["direct","server","restart","backup-restore","materialization"] evidence-required = ["wasix-full-lifecycle-v1"] +[[claims]] +extension = "moddatetime" +postgres-major = 18 +artifact-family = "wasix-runtime" +platform-targets = ["portable"] +runtime-modes = ["direct","server","restart","backup-restore","materialization"] +evidence-required = ["wasix-full-lifecycle-v1"] + [[claims]] extension = "pageinspect" postgres-major = 18 @@ -278,6 +308,22 @@ platform-targets = ["portable"] runtime-modes = ["direct","server","restart","backup-restore","materialization"] evidence-required = ["wasix-full-lifecycle-v1"] +[[claims]] +extension = "pg_logicalinspect" +postgres-major = 18 +artifact-family = "wasix-runtime" +platform-targets = ["portable"] +runtime-modes = ["direct","server","restart","backup-restore","materialization"] +evidence-required = ["wasix-full-lifecycle-v1"] + +[[claims]] +extension = "pg_stat_statements" +postgres-major = 18 +artifact-family = "wasix-runtime" +platform-targets = ["portable"] +runtime-modes = ["direct","server","restart","backup-restore","materialization"] +evidence-required = ["wasix-full-lifecycle-v1"] + [[claims]] extension = "pg_surgery" postgres-major = 18 @@ -358,6 +404,14 @@ platform-targets = ["portable"] runtime-modes = ["direct","server","restart","backup-restore","materialization"] evidence-required = ["wasix-full-lifecycle-v1"] +[[claims]] +extension = "refint" +postgres-major = 18 +artifact-family = "wasix-runtime" +platform-targets = ["portable"] +runtime-modes = ["direct","server","restart","backup-restore","materialization"] +evidence-required = ["wasix-full-lifecycle-v1"] + [[claims]] extension = "seg" postgres-major = 18 diff --git a/src/extensions/generated/contrib-build.tsv b/src/extensions/generated/contrib-build.tsv index 1aef0fed0..e8223bebd 100644 --- a/src/extensions/generated/contrib-build.tsv +++ b/src/extensions/generated/contrib-build.tsv @@ -1,6 +1,7 @@ # id sql_name contrib_dir module_file archive amcheck amcheck amcheck amcheck.so extensions/amcheck.tar.zst auto_explain auto_explain auto_explain auto_explain.so extensions/auto_explain.tar.zst +autoinc autoinc spi autoinc.so extensions/autoinc.tar.zst bloom bloom bloom bloom.so extensions/bloom.tar.zst btree_gin btree_gin btree_gin btree_gin.so extensions/btree_gin.tar.zst btree_gist btree_gist btree_gist btree_gist.so extensions/btree_gist.tar.zst @@ -12,18 +13,23 @@ earthdistance earthdistance earthdistance earthdistance.so extensions/earthdista file_fdw file_fdw file_fdw file_fdw.so extensions/file_fdw.tar.zst fuzzystrmatch fuzzystrmatch fuzzystrmatch fuzzystrmatch.so extensions/fuzzystrmatch.tar.zst hstore hstore hstore hstore.so extensions/hstore.tar.zst +insert_username insert_username spi insert_username.so extensions/insert_username.tar.zst intarray intarray intarray _int.so extensions/intarray.tar.zst isn isn isn isn.so extensions/isn.tar.zst lo lo lo lo.so extensions/lo.tar.zst ltree ltree ltree ltree.so extensions/ltree.tar.zst +moddatetime moddatetime spi moddatetime.so extensions/moddatetime.tar.zst pageinspect pageinspect pageinspect pageinspect.so extensions/pageinspect.tar.zst pg_buffercache pg_buffercache pg_buffercache pg_buffercache.so extensions/pg_buffercache.tar.zst pg_freespacemap pg_freespacemap pg_freespacemap pg_freespacemap.so extensions/pg_freespacemap.tar.zst +pg_logicalinspect pg_logicalinspect pg_logicalinspect pg_logicalinspect.so extensions/pg_logicalinspect.tar.zst +pg_stat_statements pg_stat_statements pg_stat_statements pg_stat_statements.so extensions/pg_stat_statements.tar.zst pg_surgery pg_surgery pg_surgery pg_surgery.so extensions/pg_surgery.tar.zst pg_trgm pg_trgm pg_trgm pg_trgm.so extensions/pg_trgm.tar.zst pg_visibility pg_visibility pg_visibility pg_visibility.so extensions/pg_visibility.tar.zst pg_walinspect pg_walinspect pg_walinspect pg_walinspect.so extensions/pg_walinspect.tar.zst pgcrypto pgcrypto pgcrypto pgcrypto.so extensions/pgcrypto.tar.zst +refint refint spi refint.so extensions/refint.tar.zst seg seg seg seg.so extensions/seg.tar.zst tablefunc tablefunc tablefunc tablefunc.so extensions/tablefunc.tar.zst tcn tcn tcn tcn.so extensions/tcn.tar.zst diff --git a/src/extensions/generated/docs/extension-evidence.json b/src/extensions/generated/docs/extension-evidence.json index bd202add9..6859ee32e 100644 --- a/src/extensions/generated/docs/extension-evidence.json +++ b/src/extensions/generated/docs/extension-evidence.json @@ -68,6 +68,40 @@ ], "sql-name": "auto_explain" }, + { + "artifact-family": "wasix-runtime", + "evidence-required": [ + "wasix-full-lifecycle-v1" + ], + "extension": "autoinc", + "latest-accepted-evidence": [], + "missing-current-evidence": [ + { + "artifact-family": "wasix-runtime", + "evidence-tier": "wasix-full-lifecycle-v1", + "platform-target": "portable", + "runtime-modes": [ + "direct", + "server", + "restart", + "backup-restore", + "materialization" + ] + } + ], + "platform-targets": [ + "portable" + ], + "postgres-major": 18, + "runtime-modes": [ + "direct", + "server", + "restart", + "backup-restore", + "materialization" + ], + "sql-name": "autoinc" + }, { "artifact-family": "wasix-runtime", "evidence-required": [ @@ -442,6 +476,40 @@ ], "sql-name": "hstore" }, + { + "artifact-family": "wasix-runtime", + "evidence-required": [ + "wasix-full-lifecycle-v1" + ], + "extension": "insert_username", + "latest-accepted-evidence": [], + "missing-current-evidence": [ + { + "artifact-family": "wasix-runtime", + "evidence-tier": "wasix-full-lifecycle-v1", + "platform-target": "portable", + "runtime-modes": [ + "direct", + "server", + "restart", + "backup-restore", + "materialization" + ] + } + ], + "platform-targets": [ + "portable" + ], + "postgres-major": 18, + "runtime-modes": [ + "direct", + "server", + "restart", + "backup-restore", + "materialization" + ], + "sql-name": "insert_username" + }, { "artifact-family": "wasix-runtime", "evidence-required": [ @@ -578,6 +646,40 @@ ], "sql-name": "ltree" }, + { + "artifact-family": "wasix-runtime", + "evidence-required": [ + "wasix-full-lifecycle-v1" + ], + "extension": "moddatetime", + "latest-accepted-evidence": [], + "missing-current-evidence": [ + { + "artifact-family": "wasix-runtime", + "evidence-tier": "wasix-full-lifecycle-v1", + "platform-target": "portable", + "runtime-modes": [ + "direct", + "server", + "restart", + "backup-restore", + "materialization" + ] + } + ], + "platform-targets": [ + "portable" + ], + "postgres-major": 18, + "runtime-modes": [ + "direct", + "server", + "restart", + "backup-restore", + "materialization" + ], + "sql-name": "moddatetime" + }, { "artifact-family": "wasix-runtime", "evidence-required": [ @@ -748,6 +850,74 @@ ], "sql-name": "pg_ivm" }, + { + "artifact-family": "wasix-runtime", + "evidence-required": [ + "wasix-full-lifecycle-v1" + ], + "extension": "pg_logicalinspect", + "latest-accepted-evidence": [], + "missing-current-evidence": [ + { + "artifact-family": "wasix-runtime", + "evidence-tier": "wasix-full-lifecycle-v1", + "platform-target": "portable", + "runtime-modes": [ + "direct", + "server", + "restart", + "backup-restore", + "materialization" + ] + } + ], + "platform-targets": [ + "portable" + ], + "postgres-major": 18, + "runtime-modes": [ + "direct", + "server", + "restart", + "backup-restore", + "materialization" + ], + "sql-name": "pg_logicalinspect" + }, + { + "artifact-family": "wasix-runtime", + "evidence-required": [ + "wasix-full-lifecycle-v1" + ], + "extension": "pg_stat_statements", + "latest-accepted-evidence": [], + "missing-current-evidence": [ + { + "artifact-family": "wasix-runtime", + "evidence-tier": "wasix-full-lifecycle-v1", + "platform-target": "portable", + "runtime-modes": [ + "direct", + "server", + "restart", + "backup-restore", + "materialization" + ] + } + ], + "platform-targets": [ + "portable" + ], + "postgres-major": 18, + "runtime-modes": [ + "direct", + "server", + "restart", + "backup-restore", + "materialization" + ], + "sql-name": "pg_stat_statements" + }, { "artifact-family": "wasix-runtime", "evidence-required": [ @@ -1088,6 +1258,40 @@ ], "sql-name": "postgis" }, + { + "artifact-family": "wasix-runtime", + "evidence-required": [ + "wasix-full-lifecycle-v1" + ], + "extension": "refint", + "latest-accepted-evidence": [], + "missing-current-evidence": [ + { + "artifact-family": "wasix-runtime", + "evidence-tier": "wasix-full-lifecycle-v1", + "platform-target": "portable", + "runtime-modes": [ + "direct", + "server", + "restart", + "backup-restore", + "materialization" + ] + } + ], + "platform-targets": [ + "portable" + ], + "postgres-major": 18, + "runtime-modes": [ + "direct", + "server", + "restart", + "backup-restore", + "materialization" + ], + "sql-name": "refint" + }, { "artifact-family": "wasix-runtime", "evidence-required": [ @@ -1380,7 +1584,7 @@ "collector": "src/extensions/tools/collect-wasix-evidence.sh", "kind": "exact-sha-ci" }, - "source-digest": "sha256:fc36c80f2b5f4b24e93e06f781b72d81fb14106de9f8588b32e45215d45e45f6", + "source-digest": "sha256:fb1ece0312ea77afc2f313191fb705a959389f8b8e1cb2ca9142a608d861cdf4", "source-digest-inputs": [ "src/third-party/postgres/source.toml", "src/extensions/catalog/extensions.source.json", @@ -1444,6 +1648,7 @@ "src/test-fixtures/extensions/manifest.json", "src/test-fixtures/extensions/amcheck.sql", "src/test-fixtures/extensions/auto_explain.sql", + "src/test-fixtures/extensions/autoinc.sql", "src/test-fixtures/extensions/bloom.sql", "src/test-fixtures/extensions/btree_gin.sql", "src/test-fixtures/extensions/btree_gist.sql", @@ -1455,15 +1660,19 @@ "src/test-fixtures/extensions/file_fdw.sql", "src/test-fixtures/extensions/fuzzystrmatch.sql", "src/test-fixtures/extensions/hstore.sql", + "src/test-fixtures/extensions/insert_username.sql", "src/test-fixtures/extensions/intarray.sql", "src/test-fixtures/extensions/isn.sql", "src/test-fixtures/extensions/lo.sql", "src/test-fixtures/extensions/ltree.sql", + "src/test-fixtures/extensions/moddatetime.sql", "src/test-fixtures/extensions/pageinspect.sql", "src/test-fixtures/extensions/pg_buffercache.sql", "src/test-fixtures/extensions/pg_freespacemap.sql", "src/test-fixtures/extensions/pg_hashids.sql", "src/test-fixtures/extensions/pg_ivm.sql", + "src/test-fixtures/extensions/pg_logicalinspect.sql", + "src/test-fixtures/extensions/pg_stat_statements.sql", "src/test-fixtures/extensions/pg_surgery.sql", "src/test-fixtures/extensions/pg_textsearch.sql", "src/test-fixtures/extensions/pg_trgm.sql", @@ -1474,6 +1683,7 @@ "src/test-fixtures/extensions/pgmq.sql", "src/test-fixtures/extensions/pgtap.sql", "src/test-fixtures/extensions/postgis.sql", + "src/test-fixtures/extensions/refint.sql", "src/test-fixtures/extensions/seg.sql", "src/test-fixtures/extensions/tablefunc.sql", "src/test-fixtures/extensions/tcn.sql", diff --git a/src/extensions/generated/extensions.catalog.json b/src/extensions/generated/extensions.catalog.json index ea61744ea..f242b2941 100644 --- a/src/extensions/generated/extensions.catalog.json +++ b/src/extensions/generated/extensions.catalog.json @@ -92,6 +92,43 @@ "native-module-file": "auto_explain.so", "notes": [] }, + { + "id": "autoinc", + "sql-name": "autoinc", + "rust-constant": "AUTOINC", + "display-name": "autoinc", + "source-kind": "postgres-contrib", + "upstream-import-name": "autoinc", + "package-export": "./contrib/autoinc", + "tags": [ + "postgres extension", + "postgres/contrib" + ], + "control-file": "src/third-party/postgres/contrib/spi/autoinc.control", + "control": { + "default-version": "1.0", + "module-pathname": "$libdir/autoinc", + "requires": [], + "relocatable": "true" + }, + "dependencies": [], + "load-order": [], + "lifecycle": { + "create-extension": true, + "create-schema": "pg_catalog", + "load-sql": [], + "post-create-sql": [], + "startup-config": [], + "preload-required": false, + "restart-required": false, + "shared-memory-required": false + }, + "tests": [ + "src/test-fixtures/extensions/autoinc.sql" + ], + "native-module-file": "autoinc.so", + "notes": [] + }, { "id": "bloom", "sql-name": "bloom", @@ -514,6 +551,43 @@ "native-module-file": "hstore.so", "notes": [] }, + { + "id": "insert_username", + "sql-name": "insert_username", + "rust-constant": "INSERT_USERNAME", + "display-name": "insert_username", + "source-kind": "postgres-contrib", + "upstream-import-name": "insert_username", + "package-export": "./contrib/insert_username", + "tags": [ + "postgres extension", + "postgres/contrib" + ], + "control-file": "src/third-party/postgres/contrib/spi/insert_username.control", + "control": { + "default-version": "1.0", + "module-pathname": "$libdir/insert_username", + "requires": [], + "relocatable": "true" + }, + "dependencies": [], + "load-order": [], + "lifecycle": { + "create-extension": true, + "create-schema": "pg_catalog", + "load-sql": [], + "post-create-sql": [], + "startup-config": [], + "preload-required": false, + "restart-required": false, + "shared-memory-required": false + }, + "tests": [ + "src/test-fixtures/extensions/insert_username.sql" + ], + "native-module-file": "insert_username.so", + "notes": [] + }, { "id": "intarray", "sql-name": "intarray", @@ -666,6 +740,43 @@ "native-module-file": "ltree.so", "notes": [] }, + { + "id": "moddatetime", + "sql-name": "moddatetime", + "rust-constant": "MODDATETIME", + "display-name": "moddatetime", + "source-kind": "postgres-contrib", + "upstream-import-name": "moddatetime", + "package-export": "./contrib/moddatetime", + "tags": [ + "postgres extension", + "postgres/contrib" + ], + "control-file": "src/third-party/postgres/contrib/spi/moddatetime.control", + "control": { + "default-version": "1.0", + "module-pathname": "$libdir/moddatetime", + "requires": [], + "relocatable": "true" + }, + "dependencies": [], + "load-order": [], + "lifecycle": { + "create-extension": true, + "create-schema": "pg_catalog", + "load-sql": [], + "post-create-sql": [], + "startup-config": [], + "preload-required": false, + "restart-required": false, + "shared-memory-required": false + }, + "tests": [ + "src/test-fixtures/extensions/moddatetime.sql" + ], + "native-module-file": "moddatetime.so", + "notes": [] + }, { "id": "pageinspect", "sql-name": "pageinspect", @@ -855,6 +966,81 @@ "native-module-file": "pg_ivm.so", "notes": [] }, + { + "id": "pg_logicalinspect", + "sql-name": "pg_logicalinspect", + "rust-constant": "PG_LOGICALINSPECT", + "display-name": "pg_logicalinspect", + "source-kind": "postgres-contrib", + "upstream-import-name": "pg_logicalinspect", + "package-export": "./contrib/pg_logicalinspect", + "tags": [ + "postgres extension", + "postgres/contrib" + ], + "control-file": "src/third-party/postgres/contrib/pg_logicalinspect/pg_logicalinspect.control", + "control": { + "default-version": "1.0", + "module-pathname": "$libdir/pg_logicalinspect", + "requires": [], + "relocatable": "true" + }, + "dependencies": [], + "load-order": [], + "lifecycle": { + "create-extension": true, + "create-schema": "pg_catalog", + "load-sql": [], + "post-create-sql": [], + "startup-config": [], + "preload-required": false, + "restart-required": false, + "shared-memory-required": false + }, + "tests": [ + "src/test-fixtures/extensions/pg_logicalinspect.sql" + ], + "native-module-file": "pg_logicalinspect.so", + "notes": [] + }, + { + "id": "pg_stat_statements", + "sql-name": "pg_stat_statements", + "rust-constant": "PG_STAT_STATEMENTS", + "display-name": "pg_stat_statements", + "source-kind": "postgres-contrib", + "upstream-import-name": "pg_stat_statements", + "package-export": "./contrib/pg_stat_statements", + "tags": [ + "postgres extension", + "postgres/contrib" + ], + "control-file": "src/third-party/postgres/contrib/pg_stat_statements/pg_stat_statements.control", + "control": { + "default-version": "1.12", + "module-pathname": "$libdir/pg_stat_statements", + "requires": [], + "relocatable": "true" + }, + "dependencies": [], + "load-order": [], + "lifecycle": { + "create-extension": true, + "load-sql": [], + "post-create-sql": [], + "startup-config": [ + "shared_preload_libraries=pg_stat_statements" + ], + "preload-required": true, + "restart-required": true, + "shared-memory-required": true + }, + "tests": [ + "src/test-fixtures/extensions/pg_stat_statements.sql" + ], + "native-module-file": "pg_stat_statements.so", + "notes": [] + }, { "id": "pg_surgery", "sql-name": "pg_surgery", @@ -1237,6 +1423,43 @@ "native-module-file": "postgis-3.so", "notes": [] }, + { + "id": "refint", + "sql-name": "refint", + "rust-constant": "REFINT", + "display-name": "refint", + "source-kind": "postgres-contrib", + "upstream-import-name": "refint", + "package-export": "./contrib/refint", + "tags": [ + "postgres extension", + "postgres/contrib" + ], + "control-file": "src/third-party/postgres/contrib/spi/refint.control", + "control": { + "default-version": "1.0", + "module-pathname": "$libdir/refint", + "requires": [], + "relocatable": "true" + }, + "dependencies": [], + "load-order": [], + "lifecycle": { + "create-extension": true, + "create-schema": "pg_catalog", + "load-sql": [], + "post-create-sql": [], + "startup-config": [], + "preload-required": false, + "restart-required": false, + "shared-memory-required": false + }, + "tests": [ + "src/test-fixtures/extensions/refint.sql" + ], + "native-module-file": "refint.so", + "notes": [] + }, { "id": "seg", "sql-name": "seg", diff --git a/src/extensions/generated/mobile/static-extensions.tsv b/src/extensions/generated/mobile/static-extensions.tsv index 976855795..e362da3e3 100644 --- a/src/extensions/generated/mobile/static-extensions.tsv +++ b/src/extensions/generated/mobile/static-extensions.tsv @@ -2,6 +2,7 @@ sql-name native-module-stem source-kind source-rel mobile-static-dependencies ios-static-dependencies android-static-dependencies include-dependencies include-dirs cflags hash-source-dependencies ios-hash-source-dependencies android-hash-source-dependencies hash-dirs source-files source-recursive-dirs amcheck amcheck contrib contrib/amcheck auto_explain auto_explain contrib contrib/auto_explain +autoinc autoinc contrib contrib/spi autoinc.c bloom bloom contrib contrib/bloom btree_gin btree_gin contrib contrib/btree_gin btree_gist btree_gist contrib contrib/btree_gist @@ -13,15 +14,19 @@ earthdistance earthdistance contrib contrib/earthdistance file_fdw file_fdw contrib contrib/file_fdw fuzzystrmatch fuzzystrmatch contrib contrib/fuzzystrmatch hstore hstore contrib contrib/hstore +insert_username insert_username contrib contrib/spi insert_username.c intarray _int contrib contrib/intarray isn isn contrib contrib/isn lo lo contrib contrib/lo ltree ltree contrib contrib/ltree +moddatetime moddatetime contrib contrib/spi moddatetime.c pageinspect pageinspect contrib contrib/pageinspect pg_buffercache pg_buffercache contrib contrib/pg_buffercache pg_freespacemap pg_freespacemap contrib contrib/pg_freespacemap pg_hashids pg_hashids external target/oliphaunt-sources/checkouts/pg_hashids pg_ivm pg_ivm external target/oliphaunt-sources/checkouts/pg_ivm createas.c,matview.c,pg_ivm.c,ruleutils.c,subselect.c +pg_logicalinspect pg_logicalinspect contrib contrib/pg_logicalinspect +pg_stat_statements pg_stat_statements contrib contrib/pg_stat_statements pg_surgery pg_surgery contrib contrib/pg_surgery pg_textsearch pg_textsearch external target/oliphaunt-sources/checkouts/pg_textsearch source:src -DPG_TEXTSEARCH_VERSION="0.6.1" src pg_trgm pg_trgm contrib contrib/pg_trgm @@ -30,6 +35,7 @@ pg_visibility pg_visibility contrib contrib/pg_visibility pg_walinspect pg_walinspect contrib contrib/pg_walinspect pgcrypto pgcrypto contrib contrib/pgcrypto openssl openssl openssl openssl openssl openssl openssl postgis postgis-3 external target/oliphaunt-sources/checkouts/postgis geos,geos-c,json-c,libcharset,libiconv,libxml2,proj,sqlite geos,geos-c,json-c,libxml2,proj,sqlite geos,geos-c,json-c,libcharset,libiconv,libxml2,proj,sqlite geos,json-c,libiconv,libxml2,proj,sqlite geos,json-c,libiconv,libxml2,proj,sqlite geos,json-c,libxml2,proj,sqlite geos,json-c,libiconv,libxml2,proj,sqlite +refint refint contrib contrib/spi refint.c seg seg contrib contrib/seg tablefunc tablefunc contrib contrib/tablefunc tcn tcn contrib contrib/tcn diff --git a/src/extensions/generated/mobile/static-registry.json b/src/extensions/generated/mobile/static-registry.json index 2a4cdcf26..57394a0e9 100644 --- a/src/extensions/generated/mobile/static-registry.json +++ b/src/extensions/generated/mobile/static-registry.json @@ -25,6 +25,13 @@ "sql-name": "auto_explain", "static-registry-required": true }, + { + "data-files": [], + "id": "autoinc", + "native-module-stem": "autoinc", + "sql-name": "autoinc", + "static-registry-required": true + }, { "data-files": [], "id": "bloom", @@ -104,6 +111,13 @@ "sql-name": "hstore", "static-registry-required": true }, + { + "data-files": [], + "id": "insert_username", + "native-module-stem": "insert_username", + "sql-name": "insert_username", + "static-registry-required": true + }, { "data-files": [], "id": "intarray", @@ -132,6 +146,13 @@ "sql-name": "ltree", "static-registry-required": true }, + { + "data-files": [], + "id": "moddatetime", + "native-module-stem": "moddatetime", + "sql-name": "moddatetime", + "static-registry-required": true + }, { "data-files": [], "id": "pageinspect", @@ -167,6 +188,20 @@ "sql-name": "pg_ivm", "static-registry-required": true }, + { + "data-files": [], + "id": "pg_logicalinspect", + "native-module-stem": "pg_logicalinspect", + "sql-name": "pg_logicalinspect", + "static-registry-required": true + }, + { + "data-files": [], + "id": "pg_stat_statements", + "native-module-stem": "pg_stat_statements", + "sql-name": "pg_stat_statements", + "static-registry-required": true + }, { "data-files": [], "id": "pg_surgery", @@ -233,6 +268,13 @@ "sql-name": "postgis", "static-registry-required": true }, + { + "data-files": [], + "id": "refint", + "native-module-stem": "refint", + "sql-name": "refint", + "static-registry-required": true + }, { "data-files": [], "id": "seg", diff --git a/src/extensions/generated/sdk/extensions.json b/src/extensions/generated/sdk/extensions.json index e017a3886..0f7805cbb 100644 --- a/src/extensions/generated/sdk/extensions.json +++ b/src/extensions/generated/sdk/extensions.json @@ -1,5 +1,5 @@ { - "extension-catalog-sha256": "f6982b4f5ace1f2b8478bbb794dece00d6379545e64bf65a28fa28b459210028", + "extension-catalog-sha256": "b9b246ee0a810514f7ef1fc5966ae31d8e857e8fb146b4593baa04c32cf8fcbf", "extensions": [ { "artifact-product": "oliphaunt-extension-contrib-pg18", @@ -53,6 +53,32 @@ "source-kind": "postgres-contrib", "sql-name": "auto_explain" }, + { + "artifact-product": "oliphaunt-extension-contrib-pg18", + "cargo-package": "oliphaunt-extension-contrib-pg18", + "creates-extension": true, + "data-files": [], + "dependencies": [], + "display-name": "autoinc", + "extension-sql-file-names": [], + "extension-sql-file-prefixes": [], + "id": "autoinc", + "maven-artifact": "oliphaunt-extension-contrib-pg18", + "maven-group": "dev.oliphaunt.extensions", + "native-component-requirements": [], + "native-components": [], + "native-module-stem": "autoinc", + "npm-package": "@oliphaunt/extension-contrib-pg18", + "postgres-major": 18, + "release-product": "liboliphaunt-native", + "runtime-bound": true, + "runtime-environment": [], + "runtime-share-data-files": [], + "selected-extension-dependencies": [], + "shared-preload-libraries": [], + "source-kind": "postgres-contrib", + "sql-name": "autoinc" + }, { "artifact-product": "oliphaunt-extension-contrib-pg18", "cargo-package": "oliphaunt-extension-contrib-pg18", @@ -347,6 +373,32 @@ "source-kind": "postgres-contrib", "sql-name": "hstore" }, + { + "artifact-product": "oliphaunt-extension-contrib-pg18", + "cargo-package": "oliphaunt-extension-contrib-pg18", + "creates-extension": true, + "data-files": [], + "dependencies": [], + "display-name": "insert_username", + "extension-sql-file-names": [], + "extension-sql-file-prefixes": [], + "id": "insert_username", + "maven-artifact": "oliphaunt-extension-contrib-pg18", + "maven-group": "dev.oliphaunt.extensions", + "native-component-requirements": [], + "native-components": [], + "native-module-stem": "insert_username", + "npm-package": "@oliphaunt/extension-contrib-pg18", + "postgres-major": 18, + "release-product": "liboliphaunt-native", + "runtime-bound": true, + "runtime-environment": [], + "runtime-share-data-files": [], + "selected-extension-dependencies": [], + "shared-preload-libraries": [], + "source-kind": "postgres-contrib", + "sql-name": "insert_username" + }, { "artifact-product": "oliphaunt-extension-contrib-pg18", "cargo-package": "oliphaunt-extension-contrib-pg18", @@ -451,6 +503,32 @@ "source-kind": "postgres-contrib", "sql-name": "ltree" }, + { + "artifact-product": "oliphaunt-extension-contrib-pg18", + "cargo-package": "oliphaunt-extension-contrib-pg18", + "creates-extension": true, + "data-files": [], + "dependencies": [], + "display-name": "moddatetime", + "extension-sql-file-names": [], + "extension-sql-file-prefixes": [], + "id": "moddatetime", + "maven-artifact": "oliphaunt-extension-contrib-pg18", + "maven-group": "dev.oliphaunt.extensions", + "native-component-requirements": [], + "native-components": [], + "native-module-stem": "moddatetime", + "npm-package": "@oliphaunt/extension-contrib-pg18", + "postgres-major": 18, + "release-product": "liboliphaunt-native", + "runtime-bound": true, + "runtime-environment": [], + "runtime-share-data-files": [], + "selected-extension-dependencies": [], + "shared-preload-libraries": [], + "source-kind": "postgres-contrib", + "sql-name": "moddatetime" + }, { "artifact-product": "oliphaunt-extension-contrib-pg18", "cargo-package": "oliphaunt-extension-contrib-pg18", @@ -581,6 +659,60 @@ "source-kind": "oliphaunt-other-extension", "sql-name": "pg_ivm" }, + { + "artifact-product": "oliphaunt-extension-contrib-pg18", + "cargo-package": "oliphaunt-extension-contrib-pg18", + "creates-extension": true, + "data-files": [], + "dependencies": [], + "display-name": "pg_logicalinspect", + "extension-sql-file-names": [], + "extension-sql-file-prefixes": [], + "id": "pg_logicalinspect", + "maven-artifact": "oliphaunt-extension-contrib-pg18", + "maven-group": "dev.oliphaunt.extensions", + "native-component-requirements": [], + "native-components": [], + "native-module-stem": "pg_logicalinspect", + "npm-package": "@oliphaunt/extension-contrib-pg18", + "postgres-major": 18, + "release-product": "liboliphaunt-native", + "runtime-bound": true, + "runtime-environment": [], + "runtime-share-data-files": [], + "selected-extension-dependencies": [], + "shared-preload-libraries": [], + "source-kind": "postgres-contrib", + "sql-name": "pg_logicalinspect" + }, + { + "artifact-product": "oliphaunt-extension-contrib-pg18", + "cargo-package": "oliphaunt-extension-contrib-pg18", + "creates-extension": true, + "data-files": [], + "dependencies": [], + "display-name": "pg_stat_statements", + "extension-sql-file-names": [], + "extension-sql-file-prefixes": [], + "id": "pg_stat_statements", + "maven-artifact": "oliphaunt-extension-contrib-pg18", + "maven-group": "dev.oliphaunt.extensions", + "native-component-requirements": [], + "native-components": [], + "native-module-stem": "pg_stat_statements", + "npm-package": "@oliphaunt/extension-contrib-pg18", + "postgres-major": 18, + "release-product": "liboliphaunt-native", + "runtime-bound": true, + "runtime-environment": [], + "runtime-share-data-files": [], + "selected-extension-dependencies": [], + "shared-preload-libraries": [ + "pg_stat_statements" + ], + "source-kind": "postgres-contrib", + "sql-name": "pg_stat_statements" + }, { "artifact-product": "oliphaunt-extension-contrib-pg18", "cargo-package": "oliphaunt-extension-contrib-pg18", @@ -1184,6 +1316,32 @@ "source-kind": "postgis", "sql-name": "postgis" }, + { + "artifact-product": "oliphaunt-extension-contrib-pg18", + "cargo-package": "oliphaunt-extension-contrib-pg18", + "creates-extension": true, + "data-files": [], + "dependencies": [], + "display-name": "refint", + "extension-sql-file-names": [], + "extension-sql-file-prefixes": [], + "id": "refint", + "maven-artifact": "oliphaunt-extension-contrib-pg18", + "maven-group": "dev.oliphaunt.extensions", + "native-component-requirements": [], + "native-components": [], + "native-module-stem": "refint", + "npm-package": "@oliphaunt/extension-contrib-pg18", + "postgres-major": 18, + "release-product": "liboliphaunt-native", + "runtime-bound": true, + "runtime-environment": [], + "runtime-share-data-files": [], + "selected-extension-dependencies": [], + "shared-preload-libraries": [], + "source-kind": "postgres-contrib", + "sql-name": "refint" + }, { "artifact-product": "oliphaunt-extension-contrib-pg18", "cargo-package": "oliphaunt-extension-contrib-pg18", diff --git a/src/extensions/generated/wasix/extensions.json b/src/extensions/generated/wasix/extensions.json index 5df6ca1aa..ccf5251f0 100644 --- a/src/extensions/generated/wasix/extensions.json +++ b/src/extensions/generated/wasix/extensions.json @@ -48,6 +48,28 @@ "native-support-modules": [], "sql-name": "auto_explain" }, + { + "archive": "extensions/autoinc.tar.zst", + "dependencies": [], + "id": "autoinc", + "lifecycle": { + "create-extension": true, + "create-schema": "pg_catalog", + "load-sql": [], + "post-create-sql": [], + "preload-required": false, + "restart-required": false, + "shared-memory-required": false, + "startup-config": [] + }, + "load-order": [], + "native-components": [], + "native-link-units": [], + "native-module-file": "autoinc.so", + "native-runtime-files": [], + "native-support-modules": [], + "sql-name": "autoinc" + }, { "archive": "extensions/bloom.tar.zst", "dependencies": [], @@ -292,6 +314,28 @@ "native-support-modules": [], "sql-name": "hstore" }, + { + "archive": "extensions/insert_username.tar.zst", + "dependencies": [], + "id": "insert_username", + "lifecycle": { + "create-extension": true, + "create-schema": "pg_catalog", + "load-sql": [], + "post-create-sql": [], + "preload-required": false, + "restart-required": false, + "shared-memory-required": false, + "startup-config": [] + }, + "load-order": [], + "native-components": [], + "native-link-units": [], + "native-module-file": "insert_username.so", + "native-runtime-files": [], + "native-support-modules": [], + "sql-name": "insert_username" + }, { "archive": "extensions/intarray.tar.zst", "dependencies": [], @@ -380,6 +424,28 @@ "native-support-modules": [], "sql-name": "ltree" }, + { + "archive": "extensions/moddatetime.tar.zst", + "dependencies": [], + "id": "moddatetime", + "lifecycle": { + "create-extension": true, + "create-schema": "pg_catalog", + "load-sql": [], + "post-create-sql": [], + "preload-required": false, + "restart-required": false, + "shared-memory-required": false, + "startup-config": [] + }, + "load-order": [], + "native-components": [], + "native-link-units": [], + "native-module-file": "moddatetime.so", + "native-runtime-files": [], + "native-support-modules": [], + "sql-name": "moddatetime" + }, { "archive": "extensions/pageinspect.tar.zst", "dependencies": [], @@ -490,6 +556,51 @@ "native-support-modules": [], "sql-name": "pg_ivm" }, + { + "archive": "extensions/pg_logicalinspect.tar.zst", + "dependencies": [], + "id": "pg_logicalinspect", + "lifecycle": { + "create-extension": true, + "create-schema": "pg_catalog", + "load-sql": [], + "post-create-sql": [], + "preload-required": false, + "restart-required": false, + "shared-memory-required": false, + "startup-config": [] + }, + "load-order": [], + "native-components": [], + "native-link-units": [], + "native-module-file": "pg_logicalinspect.so", + "native-runtime-files": [], + "native-support-modules": [], + "sql-name": "pg_logicalinspect" + }, + { + "archive": "extensions/pg_stat_statements.tar.zst", + "dependencies": [], + "id": "pg_stat_statements", + "lifecycle": { + "create-extension": true, + "load-sql": [], + "post-create-sql": [], + "preload-required": true, + "restart-required": true, + "shared-memory-required": true, + "startup-config": [ + "shared_preload_libraries=pg_stat_statements" + ] + }, + "load-order": [], + "native-components": [], + "native-link-units": [], + "native-module-file": "pg_stat_statements.so", + "native-runtime-files": [], + "native-support-modules": [], + "sql-name": "pg_stat_statements" + }, { "archive": "extensions/pg_surgery.tar.zst", "dependencies": [], @@ -745,6 +856,28 @@ ], "sql-name": "postgis" }, + { + "archive": "extensions/refint.tar.zst", + "dependencies": [], + "id": "refint", + "lifecycle": { + "create-extension": true, + "create-schema": "pg_catalog", + "load-sql": [], + "post-create-sql": [], + "preload-required": false, + "restart-required": false, + "shared-memory-required": false, + "startup-config": [] + }, + "load-order": [], + "native-components": [], + "native-link-units": [], + "native-module-file": "refint.so", + "native-runtime-files": [], + "native-support-modules": [], + "sql-name": "refint" + }, { "archive": "extensions/seg.tar.zst", "dependencies": [], diff --git a/src/extensions/tools/extension-model.test.mts b/src/extensions/tools/extension-model.test.mts index c05e267cb..20d97601e 100644 --- a/src/extensions/tools/extension-model.test.mts +++ b/src/extensions/tools/extension-model.test.mts @@ -164,3 +164,18 @@ test('extension projections retain dependency and runtime data while deriving mo assert(updated.includes('-DPG_TEXTSEARCH_VERSION="9.8.7"')); assert(!updated.includes('@EXTVERSION@')); }); + +test('SPI modules compile only their own C source in mobile static registries', () => { + const rows = readFileSync('src/extensions/generated/mobile/static-extensions.tsv', 'utf8') + .trimEnd() + .split('\n') + .slice(2) + .map((line) => line.split('\t')); + for (const name of ['autoinc', 'insert_username', 'moddatetime', 'refint']) { + const row = rows.find((fields) => fields[0] === name); + assert(row, `missing SPI module ${name}`); + assert.equal(row[3], 'contrib/spi'); + assert.equal(row[14], `${name}.c`); + assert(!row[15], 'SPI members must not also compile recursive source directories'); + } +}); diff --git a/src/extensions/tools/extension-projections.mts b/src/extensions/tools/extension-projections.mts index 750f2372f..f63313a5e 100644 --- a/src/extensions/tools/extension-projections.mts +++ b/src/extensions/tools/extension-projections.mts @@ -393,7 +393,7 @@ ${metadataRows.map((row) => ` public static let ${row.id.replace(/[-_]([a-z]) dependencies('sources', ['ios-xcframework']), dependencies('sources', ['android-arm64-v8a', 'android-x86_64']), list('hash_dirs', 'mobile-static-hash-dirs'), - list('source_files'), + list('source_files', 'mobile-static-source-files'), list('source_recursive_dirs'), ] .map((value) => (Array.isArray(value) ? value.join(',') : value)) diff --git a/src/native/runtime/bin/build-postgres18-linux.sh b/src/native/runtime/bin/build-postgres18-linux.sh index c94233510..226e0a949 100755 --- a/src/native/runtime/bin/build-postgres18-linux.sh +++ b/src/native/runtime/bin/build-postgres18-linux.sh @@ -106,18 +106,21 @@ contrib_extensions=( pageinspect pg_buffercache pg_freespacemap - pgcrypto - uuid-ossp + pg_logicalinspect + pg_stat_statements pg_surgery pg_trgm pg_visibility pg_walinspect + pgcrypto seg + spi tablefunc tcn tsm_system_rows tsm_system_time unaccent + uuid-ossp ) external_extensions=( @@ -133,6 +136,7 @@ external_extensions=( required_extension_controls=( amcheck + autoinc bloom btree_gin btree_gist @@ -144,25 +148,30 @@ required_extension_controls=( file_fdw fuzzystrmatch hstore + insert_username intarray isn lo ltree + moddatetime pageinspect pg_buffercache pg_freespacemap pg_hashids pg_ivm - pgcrypto - postgis + pg_logicalinspect + pg_stat_statements pg_surgery pg_textsearch pg_trgm pg_uuidv7 pg_visibility pg_walinspect + pgcrypto pgtap pgmq + postgis + refint seg tablefunc tcn @@ -177,6 +186,7 @@ required_extension_modules=( _int amcheck auto_explain + autoinc bloom btree_gin btree_gist @@ -188,22 +198,27 @@ required_extension_modules=( file_fdw fuzzystrmatch hstore + insert_username isn lo ltree + moddatetime pageinspect pg_buffercache pg_freespacemap pg_hashids pg_ivm - pgcrypto - postgis-3 + pg_logicalinspect + pg_stat_statements pg_surgery pg_textsearch pg_trgm pg_uuidv7 pg_visibility pg_walinspect + pgcrypto + postgis-3 + refint seg tablefunc tcn diff --git a/src/native/runtime/bin/build-postgres18-macos.sh b/src/native/runtime/bin/build-postgres18-macos.sh index a54414aa4..9bef8af3a 100755 --- a/src/native/runtime/bin/build-postgres18-macos.sh +++ b/src/native/runtime/bin/build-postgres18-macos.sh @@ -90,18 +90,21 @@ contrib_extensions=( pageinspect pg_buffercache pg_freespacemap - pgcrypto - uuid-ossp + pg_logicalinspect + pg_stat_statements pg_surgery pg_trgm pg_visibility pg_walinspect + pgcrypto seg + spi tablefunc tcn tsm_system_rows tsm_system_time unaccent + uuid-ossp ) external_extensions=( @@ -117,6 +120,7 @@ external_extensions=( required_extension_controls=( amcheck + autoinc bloom btree_gin btree_gist @@ -128,25 +132,30 @@ required_extension_controls=( file_fdw fuzzystrmatch hstore + insert_username intarray isn lo ltree + moddatetime pageinspect pg_buffercache pg_freespacemap pg_hashids pg_ivm - pgcrypto - postgis + pg_logicalinspect + pg_stat_statements pg_surgery pg_textsearch pg_trgm pg_uuidv7 pg_visibility pg_walinspect + pgcrypto pgtap pgmq + postgis + refint seg tablefunc tcn @@ -161,6 +170,7 @@ required_extension_modules=( _int amcheck auto_explain + autoinc bloom btree_gin btree_gist @@ -172,22 +182,27 @@ required_extension_modules=( file_fdw fuzzystrmatch hstore + insert_username isn lo ltree + moddatetime pageinspect pg_buffercache pg_freespacemap pg_hashids pg_ivm - pgcrypto - postgis-3 + pg_logicalinspect + pg_stat_statements pg_surgery pg_textsearch pg_trgm pg_uuidv7 pg_visibility pg_walinspect + pgcrypto + postgis-3 + refint seg tablefunc tcn diff --git a/src/native/rust-bindings/src/generated/extensions.rs b/src/native/rust-bindings/src/generated/extensions.rs index 3356f9cc8..2f42ce01a 100644 --- a/src/native/rust-bindings/src/generated/extensions.rs +++ b/src/native/rust-bindings/src/generated/extensions.rs @@ -16,6 +16,8 @@ enum ExtensionId { Amcheck, /// PostgreSQL `auto_explain`. AutoExplain, + /// PostgreSQL `autoinc`. + Autoinc, /// PostgreSQL `bloom`. Bloom, /// PostgreSQL `btree_gin`. @@ -38,6 +40,8 @@ enum ExtensionId { Fuzzystrmatch, /// PostgreSQL `hstore`. Hstore, + /// PostgreSQL `insert_username`. + InsertUsername, /// PostgreSQL `intarray`. Intarray, /// PostgreSQL `isn`. @@ -46,6 +50,8 @@ enum ExtensionId { Lo, /// PostgreSQL `ltree`. Ltree, + /// PostgreSQL `moddatetime`. + Moddatetime, /// PostgreSQL `pageinspect`. Pageinspect, /// PostgreSQL `pg_buffercache`. @@ -56,6 +62,10 @@ enum ExtensionId { PgHashids, /// PostgreSQL `pg_ivm`. PgIvm, + /// PostgreSQL `pg_logicalinspect`. + PgLogicalinspect, + /// PostgreSQL `pg_stat_statements`. + PgStatStatements, /// PostgreSQL `pg_surgery`. PgSurgery, /// PostgreSQL `pg_textsearch`. @@ -76,6 +86,8 @@ enum ExtensionId { Pgtap, /// PostgreSQL `postgis`. Postgis, + /// PostgreSQL `refint`. + Refint, /// PostgreSQL `seg`. Seg, /// PostgreSQL `tablefunc`. @@ -105,6 +117,11 @@ impl Extension { id: ExtensionId::AutoExplain, package: None, }; + /// Select the `autoinc` artifact. + pub const AUTOINC: Self = Self { + id: ExtensionId::Autoinc, + package: None, + }; /// Select the `bloom` artifact. pub const BLOOM: Self = Self { id: ExtensionId::Bloom, @@ -160,6 +177,11 @@ impl Extension { id: ExtensionId::Hstore, package: None, }; + /// Select the `insert_username` artifact. + pub const INSERT_USERNAME: Self = Self { + id: ExtensionId::InsertUsername, + package: None, + }; /// Select the `intarray` artifact. pub const INTARRAY: Self = Self { id: ExtensionId::Intarray, @@ -180,6 +202,11 @@ impl Extension { id: ExtensionId::Ltree, package: None, }; + /// Select the `moddatetime` artifact. + pub const MODDATETIME: Self = Self { + id: ExtensionId::Moddatetime, + package: None, + }; /// Select the `pageinspect` artifact. pub const PAGEINSPECT: Self = Self { id: ExtensionId::Pageinspect, @@ -205,6 +232,16 @@ impl Extension { id: ExtensionId::PgIvm, package: None, }; + /// Select the `pg_logicalinspect` artifact. + pub const PG_LOGICALINSPECT: Self = Self { + id: ExtensionId::PgLogicalinspect, + package: None, + }; + /// Select the `pg_stat_statements` artifact. + pub const PG_STAT_STATEMENTS: Self = Self { + id: ExtensionId::PgStatStatements, + package: None, + }; /// Select the `pg_surgery` artifact. pub const PG_SURGERY: Self = Self { id: ExtensionId::PgSurgery, @@ -255,6 +292,11 @@ impl Extension { id: ExtensionId::Postgis, package: None, }; + /// Select the `refint` artifact. + pub const REFINT: Self = Self { + id: ExtensionId::Refint, + package: None, + }; /// Select the `seg` artifact. pub const SEG: Self = Self { id: ExtensionId::Seg, @@ -300,6 +342,7 @@ impl Extension { pub const ALL: &'static [Self] = &[ Extension::AMCHECK, Extension::AUTO_EXPLAIN, + Extension::AUTOINC, Extension::BLOOM, Extension::BTREE_GIN, Extension::BTREE_GIST, @@ -311,15 +354,19 @@ impl Extension { Extension::FILE_FDW, Extension::FUZZYSTRMATCH, Extension::HSTORE, + Extension::INSERT_USERNAME, Extension::INTARRAY, Extension::ISN, Extension::LO, Extension::LTREE, + Extension::MODDATETIME, Extension::PAGEINSPECT, Extension::PG_BUFFERCACHE, Extension::PG_FREESPACEMAP, Extension::PG_HASHIDS, Extension::PG_IVM, + Extension::PG_LOGICALINSPECT, + Extension::PG_STAT_STATEMENTS, Extension::PG_SURGERY, Extension::PG_TEXTSEARCH, Extension::PG_TRGM, @@ -330,6 +377,7 @@ impl Extension { Extension::PGMQ, Extension::PGTAP, Extension::POSTGIS, + Extension::REFINT, Extension::SEG, Extension::TABLEFUNC, Extension::TCN, @@ -346,6 +394,7 @@ pub(super) const fn sql_name(extension: Extension) -> &'static str { match extension.id { ExtensionId::Amcheck => "amcheck", ExtensionId::AutoExplain => "auto_explain", + ExtensionId::Autoinc => "autoinc", ExtensionId::Bloom => "bloom", ExtensionId::BtreeGin => "btree_gin", ExtensionId::BtreeGist => "btree_gist", @@ -357,15 +406,19 @@ pub(super) const fn sql_name(extension: Extension) -> &'static str { ExtensionId::FileFdw => "file_fdw", ExtensionId::Fuzzystrmatch => "fuzzystrmatch", ExtensionId::Hstore => "hstore", + ExtensionId::InsertUsername => "insert_username", ExtensionId::Intarray => "intarray", ExtensionId::Isn => "isn", ExtensionId::Lo => "lo", ExtensionId::Ltree => "ltree", + ExtensionId::Moddatetime => "moddatetime", ExtensionId::Pageinspect => "pageinspect", ExtensionId::PgBuffercache => "pg_buffercache", ExtensionId::PgFreespacemap => "pg_freespacemap", ExtensionId::PgHashids => "pg_hashids", ExtensionId::PgIvm => "pg_ivm", + ExtensionId::PgLogicalinspect => "pg_logicalinspect", + ExtensionId::PgStatStatements => "pg_stat_statements", ExtensionId::PgSurgery => "pg_surgery", ExtensionId::PgTextsearch => "pg_textsearch", ExtensionId::PgTrgm => "pg_trgm", @@ -376,6 +429,7 @@ pub(super) const fn sql_name(extension: Extension) -> &'static str { ExtensionId::Pgmq => "pgmq", ExtensionId::Pgtap => "pgtap", ExtensionId::Postgis => "postgis", + ExtensionId::Refint => "refint", ExtensionId::Seg => "seg", ExtensionId::Tablefunc => "tablefunc", ExtensionId::Tcn => "tcn", @@ -392,6 +446,7 @@ pub(super) const fn artifact_product(extension: Extension) -> &'static str { match extension.id { ExtensionId::Amcheck => "oliphaunt-extension-contrib-pg18", ExtensionId::AutoExplain => "oliphaunt-extension-contrib-pg18", + ExtensionId::Autoinc => "oliphaunt-extension-contrib-pg18", ExtensionId::Bloom => "oliphaunt-extension-contrib-pg18", ExtensionId::BtreeGin => "oliphaunt-extension-contrib-pg18", ExtensionId::BtreeGist => "oliphaunt-extension-contrib-pg18", @@ -403,15 +458,19 @@ pub(super) const fn artifact_product(extension: Extension) -> &'static str { ExtensionId::FileFdw => "oliphaunt-extension-contrib-pg18", ExtensionId::Fuzzystrmatch => "oliphaunt-extension-contrib-pg18", ExtensionId::Hstore => "oliphaunt-extension-contrib-pg18", + ExtensionId::InsertUsername => "oliphaunt-extension-contrib-pg18", ExtensionId::Intarray => "oliphaunt-extension-contrib-pg18", ExtensionId::Isn => "oliphaunt-extension-contrib-pg18", ExtensionId::Lo => "oliphaunt-extension-contrib-pg18", ExtensionId::Ltree => "oliphaunt-extension-contrib-pg18", + ExtensionId::Moddatetime => "oliphaunt-extension-contrib-pg18", ExtensionId::Pageinspect => "oliphaunt-extension-contrib-pg18", ExtensionId::PgBuffercache => "oliphaunt-extension-contrib-pg18", ExtensionId::PgFreespacemap => "oliphaunt-extension-contrib-pg18", ExtensionId::PgHashids => "oliphaunt-extension-pg-hashids", ExtensionId::PgIvm => "oliphaunt-extension-pg-ivm", + ExtensionId::PgLogicalinspect => "oliphaunt-extension-contrib-pg18", + ExtensionId::PgStatStatements => "oliphaunt-extension-contrib-pg18", ExtensionId::PgSurgery => "oliphaunt-extension-contrib-pg18", ExtensionId::PgTextsearch => "oliphaunt-extension-pg-textsearch", ExtensionId::PgTrgm => "oliphaunt-extension-contrib-pg18", @@ -422,6 +481,7 @@ pub(super) const fn artifact_product(extension: Extension) -> &'static str { ExtensionId::Pgmq => "oliphaunt-extension-pgmq", ExtensionId::Pgtap => "oliphaunt-extension-pgtap", ExtensionId::Postgis => "oliphaunt-extension-postgis", + ExtensionId::Refint => "oliphaunt-extension-contrib-pg18", ExtensionId::Seg => "oliphaunt-extension-contrib-pg18", ExtensionId::Tablefunc => "oliphaunt-extension-contrib-pg18", ExtensionId::Tcn => "oliphaunt-extension-contrib-pg18", @@ -438,6 +498,7 @@ pub(super) const fn native_module_stem(extension: Extension) -> Option<&'static match extension.id { ExtensionId::Amcheck => Some("amcheck"), ExtensionId::AutoExplain => Some("auto_explain"), + ExtensionId::Autoinc => Some("autoinc"), ExtensionId::Bloom => Some("bloom"), ExtensionId::BtreeGin => Some("btree_gin"), ExtensionId::BtreeGist => Some("btree_gist"), @@ -449,15 +510,19 @@ pub(super) const fn native_module_stem(extension: Extension) -> Option<&'static ExtensionId::FileFdw => Some("file_fdw"), ExtensionId::Fuzzystrmatch => Some("fuzzystrmatch"), ExtensionId::Hstore => Some("hstore"), + ExtensionId::InsertUsername => Some("insert_username"), ExtensionId::Intarray => Some("_int"), ExtensionId::Isn => Some("isn"), ExtensionId::Lo => Some("lo"), ExtensionId::Ltree => Some("ltree"), + ExtensionId::Moddatetime => Some("moddatetime"), ExtensionId::Pageinspect => Some("pageinspect"), ExtensionId::PgBuffercache => Some("pg_buffercache"), ExtensionId::PgFreespacemap => Some("pg_freespacemap"), ExtensionId::PgHashids => Some("pg_hashids"), ExtensionId::PgIvm => Some("pg_ivm"), + ExtensionId::PgLogicalinspect => Some("pg_logicalinspect"), + ExtensionId::PgStatStatements => Some("pg_stat_statements"), ExtensionId::PgSurgery => Some("pg_surgery"), ExtensionId::PgTextsearch => Some("pg_textsearch"), ExtensionId::PgTrgm => Some("pg_trgm"), @@ -468,6 +533,7 @@ pub(super) const fn native_module_stem(extension: Extension) -> Option<&'static ExtensionId::Pgmq => None, ExtensionId::Pgtap => None, ExtensionId::Postgis => Some("postgis-3"), + ExtensionId::Refint => Some("refint"), ExtensionId::Seg => Some("seg"), ExtensionId::Tablefunc => Some("tablefunc"), ExtensionId::Tcn => Some("tcn"), @@ -484,6 +550,7 @@ pub(super) const fn creates_extension(extension: Extension) -> bool { match extension.id { ExtensionId::Amcheck => true, ExtensionId::AutoExplain => false, + ExtensionId::Autoinc => true, ExtensionId::Bloom => true, ExtensionId::BtreeGin => true, ExtensionId::BtreeGist => true, @@ -495,15 +562,19 @@ pub(super) const fn creates_extension(extension: Extension) -> bool { ExtensionId::FileFdw => true, ExtensionId::Fuzzystrmatch => true, ExtensionId::Hstore => true, + ExtensionId::InsertUsername => true, ExtensionId::Intarray => true, ExtensionId::Isn => true, ExtensionId::Lo => true, ExtensionId::Ltree => true, + ExtensionId::Moddatetime => true, ExtensionId::Pageinspect => true, ExtensionId::PgBuffercache => true, ExtensionId::PgFreespacemap => true, ExtensionId::PgHashids => true, ExtensionId::PgIvm => true, + ExtensionId::PgLogicalinspect => true, + ExtensionId::PgStatStatements => true, ExtensionId::PgSurgery => true, ExtensionId::PgTextsearch => true, ExtensionId::PgTrgm => true, @@ -514,6 +585,7 @@ pub(super) const fn creates_extension(extension: Extension) -> bool { ExtensionId::Pgmq => true, ExtensionId::Pgtap => true, ExtensionId::Postgis => true, + ExtensionId::Refint => true, ExtensionId::Seg => true, ExtensionId::Tablefunc => true, ExtensionId::Tcn => true, @@ -530,6 +602,7 @@ pub(super) const fn dependencies(extension: Extension) -> &'static [Extension] { match extension.id { ExtensionId::Amcheck => &[], ExtensionId::AutoExplain => &[], + ExtensionId::Autoinc => &[], ExtensionId::Bloom => &[], ExtensionId::BtreeGin => &[], ExtensionId::BtreeGist => &[], @@ -541,15 +614,19 @@ pub(super) const fn dependencies(extension: Extension) -> &'static [Extension] { ExtensionId::FileFdw => &[], ExtensionId::Fuzzystrmatch => &[], ExtensionId::Hstore => &[], + ExtensionId::InsertUsername => &[], ExtensionId::Intarray => &[], ExtensionId::Isn => &[], ExtensionId::Lo => &[], ExtensionId::Ltree => &[], + ExtensionId::Moddatetime => &[], ExtensionId::Pageinspect => &[], ExtensionId::PgBuffercache => &[], ExtensionId::PgFreespacemap => &[], ExtensionId::PgHashids => &[], ExtensionId::PgIvm => &[], + ExtensionId::PgLogicalinspect => &[], + ExtensionId::PgStatStatements => &[], ExtensionId::PgSurgery => &[], ExtensionId::PgTextsearch => &[], ExtensionId::PgTrgm => &[], @@ -560,6 +637,7 @@ pub(super) const fn dependencies(extension: Extension) -> &'static [Extension] { ExtensionId::Pgmq => &[], ExtensionId::Pgtap => &[], ExtensionId::Postgis => &[], + ExtensionId::Refint => &[], ExtensionId::Seg => &[], ExtensionId::Tablefunc => &[], ExtensionId::Tcn => &[], @@ -576,6 +654,7 @@ pub(super) const fn required_shared_preload_library(extension: Extension) -> Opt match extension.id { ExtensionId::Amcheck => None, ExtensionId::AutoExplain => None, + ExtensionId::Autoinc => None, ExtensionId::Bloom => None, ExtensionId::BtreeGin => None, ExtensionId::BtreeGist => None, @@ -587,15 +666,19 @@ pub(super) const fn required_shared_preload_library(extension: Extension) -> Opt ExtensionId::FileFdw => None, ExtensionId::Fuzzystrmatch => None, ExtensionId::Hstore => None, + ExtensionId::InsertUsername => None, ExtensionId::Intarray => None, ExtensionId::Isn => None, ExtensionId::Lo => None, ExtensionId::Ltree => None, + ExtensionId::Moddatetime => None, ExtensionId::Pageinspect => None, ExtensionId::PgBuffercache => None, ExtensionId::PgFreespacemap => None, ExtensionId::PgHashids => None, ExtensionId::PgIvm => None, + ExtensionId::PgLogicalinspect => None, + ExtensionId::PgStatStatements => Some("pg_stat_statements"), ExtensionId::PgSurgery => None, ExtensionId::PgTextsearch => Some("pg_textsearch"), ExtensionId::PgTrgm => None, @@ -606,6 +689,7 @@ pub(super) const fn required_shared_preload_library(extension: Extension) -> Opt ExtensionId::Pgmq => None, ExtensionId::Pgtap => None, ExtensionId::Postgis => None, + ExtensionId::Refint => None, ExtensionId::Seg => None, ExtensionId::Tablefunc => None, ExtensionId::Tcn => None, @@ -622,6 +706,7 @@ pub(super) const fn extension_data_files(extension: Extension) -> &'static [&'st match extension.id { ExtensionId::Amcheck => &[], ExtensionId::AutoExplain => &[], + ExtensionId::Autoinc => &[], ExtensionId::Bloom => &[], ExtensionId::BtreeGin => &[], ExtensionId::BtreeGist => &[], @@ -633,15 +718,19 @@ pub(super) const fn extension_data_files(extension: Extension) -> &'static [&'st ExtensionId::FileFdw => &[], ExtensionId::Fuzzystrmatch => &[], ExtensionId::Hstore => &[], + ExtensionId::InsertUsername => &[], ExtensionId::Intarray => &[], ExtensionId::Isn => &[], ExtensionId::Lo => &[], ExtensionId::Ltree => &[], + ExtensionId::Moddatetime => &[], ExtensionId::Pageinspect => &[], ExtensionId::PgBuffercache => &[], ExtensionId::PgFreespacemap => &[], ExtensionId::PgHashids => &[], ExtensionId::PgIvm => &[], + ExtensionId::PgLogicalinspect => &[], + ExtensionId::PgStatStatements => &[], ExtensionId::PgSurgery => &[], ExtensionId::PgTextsearch => &[], ExtensionId::PgTrgm => &[], @@ -662,6 +751,7 @@ pub(super) const fn extension_data_files(extension: Extension) -> &'static [&'st "contrib/postgis-3.6/uninstall_postgis.sql", "proj/proj.db", ], + ExtensionId::Refint => &[], ExtensionId::Seg => &[], ExtensionId::Tablefunc => &[], ExtensionId::Tcn => &[], @@ -678,6 +768,7 @@ pub(super) const fn extension_sql_file_prefixes(extension: Extension) -> &'stati match extension.id { ExtensionId::Amcheck => &[], ExtensionId::AutoExplain => &[], + ExtensionId::Autoinc => &[], ExtensionId::Bloom => &[], ExtensionId::BtreeGin => &[], ExtensionId::BtreeGist => &[], @@ -689,15 +780,19 @@ pub(super) const fn extension_sql_file_prefixes(extension: Extension) -> &'stati ExtensionId::FileFdw => &[], ExtensionId::Fuzzystrmatch => &[], ExtensionId::Hstore => &[], + ExtensionId::InsertUsername => &[], ExtensionId::Intarray => &[], ExtensionId::Isn => &[], ExtensionId::Lo => &[], ExtensionId::Ltree => &[], + ExtensionId::Moddatetime => &[], ExtensionId::Pageinspect => &[], ExtensionId::PgBuffercache => &[], ExtensionId::PgFreespacemap => &[], ExtensionId::PgHashids => &[], ExtensionId::PgIvm => &[], + ExtensionId::PgLogicalinspect => &[], + ExtensionId::PgStatStatements => &[], ExtensionId::PgSurgery => &[], ExtensionId::PgTextsearch => &[], ExtensionId::PgTrgm => &[], @@ -712,6 +807,7 @@ pub(super) const fn extension_sql_file_prefixes(extension: Extension) -> &'stati "postgis_proc_set_search_path", "rtpostgis", ], + ExtensionId::Refint => &[], ExtensionId::Seg => &[], ExtensionId::Tablefunc => &[], ExtensionId::Tcn => &[], @@ -728,6 +824,7 @@ pub(super) const fn extension_sql_file_names(extension: Extension) -> &'static [ match extension.id { ExtensionId::Amcheck => &[], ExtensionId::AutoExplain => &[], + ExtensionId::Autoinc => &[], ExtensionId::Bloom => &[], ExtensionId::BtreeGin => &[], ExtensionId::BtreeGist => &[], @@ -739,15 +836,19 @@ pub(super) const fn extension_sql_file_names(extension: Extension) -> &'static [ ExtensionId::FileFdw => &[], ExtensionId::Fuzzystrmatch => &[], ExtensionId::Hstore => &[], + ExtensionId::InsertUsername => &[], ExtensionId::Intarray => &[], ExtensionId::Isn => &[], ExtensionId::Lo => &[], ExtensionId::Ltree => &[], + ExtensionId::Moddatetime => &[], ExtensionId::Pageinspect => &[], ExtensionId::PgBuffercache => &[], ExtensionId::PgFreespacemap => &[], ExtensionId::PgHashids => &[], ExtensionId::PgIvm => &[], + ExtensionId::PgLogicalinspect => &[], + ExtensionId::PgStatStatements => &[], ExtensionId::PgSurgery => &[], ExtensionId::PgTextsearch => &[], ExtensionId::PgTrgm => &[], @@ -758,6 +859,7 @@ pub(super) const fn extension_sql_file_names(extension: Extension) -> &'static [ ExtensionId::Pgmq => &[], ExtensionId::Pgtap => &["uninstall_pgtap.sql"], ExtensionId::Postgis => &["uninstall_postgis.sql"], + ExtensionId::Refint => &[], ExtensionId::Seg => &[], ExtensionId::Tablefunc => &[], ExtensionId::Tcn => &[], @@ -776,6 +878,7 @@ pub(super) const fn runtime_environment( match extension.id { ExtensionId::Amcheck => &[], ExtensionId::AutoExplain => &[], + ExtensionId::Autoinc => &[], ExtensionId::Bloom => &[], ExtensionId::BtreeGin => &[], ExtensionId::BtreeGist => &[], @@ -787,15 +890,19 @@ pub(super) const fn runtime_environment( ExtensionId::FileFdw => &[], ExtensionId::Fuzzystrmatch => &[], ExtensionId::Hstore => &[], + ExtensionId::InsertUsername => &[], ExtensionId::Intarray => &[], ExtensionId::Isn => &[], ExtensionId::Lo => &[], ExtensionId::Ltree => &[], + ExtensionId::Moddatetime => &[], ExtensionId::Pageinspect => &[], ExtensionId::PgBuffercache => &[], ExtensionId::PgFreespacemap => &[], ExtensionId::PgHashids => &[], ExtensionId::PgIvm => &[], + ExtensionId::PgLogicalinspect => &[], + ExtensionId::PgStatStatements => &[], ExtensionId::PgSurgery => &[], ExtensionId::PgTextsearch => &[], ExtensionId::PgTrgm => &[], @@ -810,6 +917,7 @@ pub(super) const fn runtime_environment( relative_path: "share/postgresql/proj", required_file: "proj.db", }], + ExtensionId::Refint => &[], ExtensionId::Seg => &[], ExtensionId::Tablefunc => &[], ExtensionId::Tcn => &[], diff --git a/src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extension-legal-catalog.json b/src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extension-legal-catalog.json index 7509350d0..e4126dbe4 100644 --- a/src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extension-legal-catalog.json +++ b/src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extension-legal-catalog.json @@ -1,6 +1,6 @@ { "schema": "oliphaunt-android-extension-legal-catalog-v1", - "sourceCatalogSha256": "f6982b4f5ace1f2b8478bbb794dece00d6379545e64bf65a28fa28b459210028", + "sourceCatalogSha256": "b9b246ee0a810514f7ef1fc5966ae31d8e857e8fb146b4593baa04c32cf8fcbf", "contracts": [ { "scope": "aggregate", @@ -886,6 +886,62 @@ } ] }, + { + "scope": "leaf", + "identity": "autoinc", + "product": "oliphaunt-extension-contrib-pg18", + "target": "android-arm64-v8a", + "profile": "contrib-native", + "licenseFiles": [], + "members": [ + { + "path": "LICENSE", + "bytes": 1085, + "sha256": "6f8300e2f43c5a012d6f914fe5affa9090b97b0be39ddf3846f01b905edd8c10", + "mode": "0644" + }, + { + "path": "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT", + "bytes": 1198, + "sha256": "3d6af92ff8a4c2cdf69afb1cf44edea727922f5cd0cf8b5f72b11cdecac8fdfd", + "mode": "0644" + }, + { + "path": "THIRD_PARTY_NOTICES.md", + "bytes": 821, + "sha256": "20fd67487d1a631ba959cf7ec3fdbaf4977997ed624c0188dcb3c8870eded830", + "mode": "0644" + } + ] + }, + { + "scope": "leaf", + "identity": "autoinc", + "product": "oliphaunt-extension-contrib-pg18", + "target": "android-x86_64", + "profile": "contrib-native", + "licenseFiles": [], + "members": [ + { + "path": "LICENSE", + "bytes": 1085, + "sha256": "6f8300e2f43c5a012d6f914fe5affa9090b97b0be39ddf3846f01b905edd8c10", + "mode": "0644" + }, + { + "path": "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT", + "bytes": 1198, + "sha256": "3d6af92ff8a4c2cdf69afb1cf44edea727922f5cd0cf8b5f72b11cdecac8fdfd", + "mode": "0644" + }, + { + "path": "THIRD_PARTY_NOTICES.md", + "bytes": 821, + "sha256": "20fd67487d1a631ba959cf7ec3fdbaf4977997ed624c0188dcb3c8870eded830", + "mode": "0644" + } + ] + }, { "scope": "leaf", "identity": "bloom", @@ -1502,6 +1558,62 @@ } ] }, + { + "scope": "leaf", + "identity": "insert_username", + "product": "oliphaunt-extension-contrib-pg18", + "target": "android-arm64-v8a", + "profile": "contrib-native", + "licenseFiles": [], + "members": [ + { + "path": "LICENSE", + "bytes": 1085, + "sha256": "6f8300e2f43c5a012d6f914fe5affa9090b97b0be39ddf3846f01b905edd8c10", + "mode": "0644" + }, + { + "path": "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT", + "bytes": 1198, + "sha256": "3d6af92ff8a4c2cdf69afb1cf44edea727922f5cd0cf8b5f72b11cdecac8fdfd", + "mode": "0644" + }, + { + "path": "THIRD_PARTY_NOTICES.md", + "bytes": 821, + "sha256": "20fd67487d1a631ba959cf7ec3fdbaf4977997ed624c0188dcb3c8870eded830", + "mode": "0644" + } + ] + }, + { + "scope": "leaf", + "identity": "insert_username", + "product": "oliphaunt-extension-contrib-pg18", + "target": "android-x86_64", + "profile": "contrib-native", + "licenseFiles": [], + "members": [ + { + "path": "LICENSE", + "bytes": 1085, + "sha256": "6f8300e2f43c5a012d6f914fe5affa9090b97b0be39ddf3846f01b905edd8c10", + "mode": "0644" + }, + { + "path": "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT", + "bytes": 1198, + "sha256": "3d6af92ff8a4c2cdf69afb1cf44edea727922f5cd0cf8b5f72b11cdecac8fdfd", + "mode": "0644" + }, + { + "path": "THIRD_PARTY_NOTICES.md", + "bytes": 821, + "sha256": "20fd67487d1a631ba959cf7ec3fdbaf4977997ed624c0188dcb3c8870eded830", + "mode": "0644" + } + ] + }, { "scope": "leaf", "identity": "intarray", @@ -1726,6 +1838,62 @@ } ] }, + { + "scope": "leaf", + "identity": "moddatetime", + "product": "oliphaunt-extension-contrib-pg18", + "target": "android-arm64-v8a", + "profile": "contrib-native", + "licenseFiles": [], + "members": [ + { + "path": "LICENSE", + "bytes": 1085, + "sha256": "6f8300e2f43c5a012d6f914fe5affa9090b97b0be39ddf3846f01b905edd8c10", + "mode": "0644" + }, + { + "path": "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT", + "bytes": 1198, + "sha256": "3d6af92ff8a4c2cdf69afb1cf44edea727922f5cd0cf8b5f72b11cdecac8fdfd", + "mode": "0644" + }, + { + "path": "THIRD_PARTY_NOTICES.md", + "bytes": 821, + "sha256": "20fd67487d1a631ba959cf7ec3fdbaf4977997ed624c0188dcb3c8870eded830", + "mode": "0644" + } + ] + }, + { + "scope": "leaf", + "identity": "moddatetime", + "product": "oliphaunt-extension-contrib-pg18", + "target": "android-x86_64", + "profile": "contrib-native", + "licenseFiles": [], + "members": [ + { + "path": "LICENSE", + "bytes": 1085, + "sha256": "6f8300e2f43c5a012d6f914fe5affa9090b97b0be39ddf3846f01b905edd8c10", + "mode": "0644" + }, + { + "path": "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT", + "bytes": 1198, + "sha256": "3d6af92ff8a4c2cdf69afb1cf44edea727922f5cd0cf8b5f72b11cdecac8fdfd", + "mode": "0644" + }, + { + "path": "THIRD_PARTY_NOTICES.md", + "bytes": 821, + "sha256": "20fd67487d1a631ba959cf7ec3fdbaf4977997ed624c0188dcb3c8870eded830", + "mode": "0644" + } + ] + }, { "scope": "leaf", "identity": "pageinspect", @@ -2014,6 +2182,118 @@ } ] }, + { + "scope": "leaf", + "identity": "pg_logicalinspect", + "product": "oliphaunt-extension-contrib-pg18", + "target": "android-arm64-v8a", + "profile": "contrib-native", + "licenseFiles": [], + "members": [ + { + "path": "LICENSE", + "bytes": 1085, + "sha256": "6f8300e2f43c5a012d6f914fe5affa9090b97b0be39ddf3846f01b905edd8c10", + "mode": "0644" + }, + { + "path": "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT", + "bytes": 1198, + "sha256": "3d6af92ff8a4c2cdf69afb1cf44edea727922f5cd0cf8b5f72b11cdecac8fdfd", + "mode": "0644" + }, + { + "path": "THIRD_PARTY_NOTICES.md", + "bytes": 821, + "sha256": "20fd67487d1a631ba959cf7ec3fdbaf4977997ed624c0188dcb3c8870eded830", + "mode": "0644" + } + ] + }, + { + "scope": "leaf", + "identity": "pg_logicalinspect", + "product": "oliphaunt-extension-contrib-pg18", + "target": "android-x86_64", + "profile": "contrib-native", + "licenseFiles": [], + "members": [ + { + "path": "LICENSE", + "bytes": 1085, + "sha256": "6f8300e2f43c5a012d6f914fe5affa9090b97b0be39ddf3846f01b905edd8c10", + "mode": "0644" + }, + { + "path": "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT", + "bytes": 1198, + "sha256": "3d6af92ff8a4c2cdf69afb1cf44edea727922f5cd0cf8b5f72b11cdecac8fdfd", + "mode": "0644" + }, + { + "path": "THIRD_PARTY_NOTICES.md", + "bytes": 821, + "sha256": "20fd67487d1a631ba959cf7ec3fdbaf4977997ed624c0188dcb3c8870eded830", + "mode": "0644" + } + ] + }, + { + "scope": "leaf", + "identity": "pg_stat_statements", + "product": "oliphaunt-extension-contrib-pg18", + "target": "android-arm64-v8a", + "profile": "contrib-native", + "licenseFiles": [], + "members": [ + { + "path": "LICENSE", + "bytes": 1085, + "sha256": "6f8300e2f43c5a012d6f914fe5affa9090b97b0be39ddf3846f01b905edd8c10", + "mode": "0644" + }, + { + "path": "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT", + "bytes": 1198, + "sha256": "3d6af92ff8a4c2cdf69afb1cf44edea727922f5cd0cf8b5f72b11cdecac8fdfd", + "mode": "0644" + }, + { + "path": "THIRD_PARTY_NOTICES.md", + "bytes": 821, + "sha256": "20fd67487d1a631ba959cf7ec3fdbaf4977997ed624c0188dcb3c8870eded830", + "mode": "0644" + } + ] + }, + { + "scope": "leaf", + "identity": "pg_stat_statements", + "product": "oliphaunt-extension-contrib-pg18", + "target": "android-x86_64", + "profile": "contrib-native", + "licenseFiles": [], + "members": [ + { + "path": "LICENSE", + "bytes": 1085, + "sha256": "6f8300e2f43c5a012d6f914fe5affa9090b97b0be39ddf3846f01b905edd8c10", + "mode": "0644" + }, + { + "path": "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT", + "bytes": 1198, + "sha256": "3d6af92ff8a4c2cdf69afb1cf44edea727922f5cd0cf8b5f72b11cdecac8fdfd", + "mode": "0644" + }, + { + "path": "THIRD_PARTY_NOTICES.md", + "bytes": 821, + "sha256": "20fd67487d1a631ba959cf7ec3fdbaf4977997ed624c0188dcb3c8870eded830", + "mode": "0644" + } + ] + }, { "scope": "leaf", "identity": "pg_surgery", @@ -2830,6 +3110,62 @@ } ] }, + { + "scope": "leaf", + "identity": "refint", + "product": "oliphaunt-extension-contrib-pg18", + "target": "android-arm64-v8a", + "profile": "contrib-native", + "licenseFiles": [], + "members": [ + { + "path": "LICENSE", + "bytes": 1085, + "sha256": "6f8300e2f43c5a012d6f914fe5affa9090b97b0be39ddf3846f01b905edd8c10", + "mode": "0644" + }, + { + "path": "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT", + "bytes": 1198, + "sha256": "3d6af92ff8a4c2cdf69afb1cf44edea727922f5cd0cf8b5f72b11cdecac8fdfd", + "mode": "0644" + }, + { + "path": "THIRD_PARTY_NOTICES.md", + "bytes": 821, + "sha256": "20fd67487d1a631ba959cf7ec3fdbaf4977997ed624c0188dcb3c8870eded830", + "mode": "0644" + } + ] + }, + { + "scope": "leaf", + "identity": "refint", + "product": "oliphaunt-extension-contrib-pg18", + "target": "android-x86_64", + "profile": "contrib-native", + "licenseFiles": [], + "members": [ + { + "path": "LICENSE", + "bytes": 1085, + "sha256": "6f8300e2f43c5a012d6f914fe5affa9090b97b0be39ddf3846f01b905edd8c10", + "mode": "0644" + }, + { + "path": "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT", + "bytes": 1198, + "sha256": "3d6af92ff8a4c2cdf69afb1cf44edea727922f5cd0cf8b5f72b11cdecac8fdfd", + "mode": "0644" + }, + { + "path": "THIRD_PARTY_NOTICES.md", + "bytes": 821, + "sha256": "20fd67487d1a631ba959cf7ec3fdbaf4977997ed624c0188dcb3c8870eded830", + "mode": "0644" + } + ] + }, { "scope": "leaf", "identity": "seg", diff --git a/src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extensions.properties b/src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extensions.properties index 66ece44aa..5cea04152 100644 --- a/src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extensions.properties +++ b/src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extensions.properties @@ -1,7 +1,7 @@ # This file is generated by src/extensions/tools/check-extension-model.sh. # Do not edit by hand. schema=oliphaunt-android-extension-catalog-v2 -catalogSha256=f6982b4f5ace1f2b8478bbb794dece00d6379545e64bf65a28fa28b459210028 +catalogSha256=b9b246ee0a810514f7ef1fc5966ae31d8e857e8fb146b4593baa04c32cf8fcbf extension.amcheck.artifactProduct=oliphaunt-extension-contrib-pg18 extension.amcheck.releaseProduct=liboliphaunt-native extension.amcheck.mavenGroup=dev.oliphaunt.extensions @@ -14,6 +14,12 @@ extension.auto_explain.mavenGroup=dev.oliphaunt.extensions extension.auto_explain.mavenArtifact=oliphaunt-extension-contrib-pg18 extension.auto_explain.runtimeBound=true extension.auto_explain.dependencies= +extension.autoinc.artifactProduct=oliphaunt-extension-contrib-pg18 +extension.autoinc.releaseProduct=liboliphaunt-native +extension.autoinc.mavenGroup=dev.oliphaunt.extensions +extension.autoinc.mavenArtifact=oliphaunt-extension-contrib-pg18 +extension.autoinc.runtimeBound=true +extension.autoinc.dependencies= extension.bloom.artifactProduct=oliphaunt-extension-contrib-pg18 extension.bloom.releaseProduct=liboliphaunt-native extension.bloom.mavenGroup=dev.oliphaunt.extensions @@ -80,6 +86,12 @@ extension.hstore.mavenGroup=dev.oliphaunt.extensions extension.hstore.mavenArtifact=oliphaunt-extension-contrib-pg18 extension.hstore.runtimeBound=true extension.hstore.dependencies= +extension.insert_username.artifactProduct=oliphaunt-extension-contrib-pg18 +extension.insert_username.releaseProduct=liboliphaunt-native +extension.insert_username.mavenGroup=dev.oliphaunt.extensions +extension.insert_username.mavenArtifact=oliphaunt-extension-contrib-pg18 +extension.insert_username.runtimeBound=true +extension.insert_username.dependencies= extension.intarray.artifactProduct=oliphaunt-extension-contrib-pg18 extension.intarray.releaseProduct=liboliphaunt-native extension.intarray.mavenGroup=dev.oliphaunt.extensions @@ -104,6 +116,12 @@ extension.ltree.mavenGroup=dev.oliphaunt.extensions extension.ltree.mavenArtifact=oliphaunt-extension-contrib-pg18 extension.ltree.runtimeBound=true extension.ltree.dependencies= +extension.moddatetime.artifactProduct=oliphaunt-extension-contrib-pg18 +extension.moddatetime.releaseProduct=liboliphaunt-native +extension.moddatetime.mavenGroup=dev.oliphaunt.extensions +extension.moddatetime.mavenArtifact=oliphaunt-extension-contrib-pg18 +extension.moddatetime.runtimeBound=true +extension.moddatetime.dependencies= extension.pageinspect.artifactProduct=oliphaunt-extension-contrib-pg18 extension.pageinspect.releaseProduct=liboliphaunt-native extension.pageinspect.mavenGroup=dev.oliphaunt.extensions @@ -134,6 +152,18 @@ extension.pg_ivm.mavenGroup=dev.oliphaunt.extensions extension.pg_ivm.mavenArtifact=oliphaunt-extension-pg-ivm extension.pg_ivm.runtimeBound=false extension.pg_ivm.dependencies= +extension.pg_logicalinspect.artifactProduct=oliphaunt-extension-contrib-pg18 +extension.pg_logicalinspect.releaseProduct=liboliphaunt-native +extension.pg_logicalinspect.mavenGroup=dev.oliphaunt.extensions +extension.pg_logicalinspect.mavenArtifact=oliphaunt-extension-contrib-pg18 +extension.pg_logicalinspect.runtimeBound=true +extension.pg_logicalinspect.dependencies= +extension.pg_stat_statements.artifactProduct=oliphaunt-extension-contrib-pg18 +extension.pg_stat_statements.releaseProduct=liboliphaunt-native +extension.pg_stat_statements.mavenGroup=dev.oliphaunt.extensions +extension.pg_stat_statements.mavenArtifact=oliphaunt-extension-contrib-pg18 +extension.pg_stat_statements.runtimeBound=true +extension.pg_stat_statements.dependencies= extension.pg_surgery.artifactProduct=oliphaunt-extension-contrib-pg18 extension.pg_surgery.releaseProduct=liboliphaunt-native extension.pg_surgery.mavenGroup=dev.oliphaunt.extensions @@ -194,6 +224,12 @@ extension.postgis.mavenGroup=dev.oliphaunt.extensions extension.postgis.mavenArtifact=oliphaunt-extension-postgis extension.postgis.runtimeBound=false extension.postgis.dependencies= +extension.refint.artifactProduct=oliphaunt-extension-contrib-pg18 +extension.refint.releaseProduct=liboliphaunt-native +extension.refint.mavenGroup=dev.oliphaunt.extensions +extension.refint.mavenArtifact=oliphaunt-extension-contrib-pg18 +extension.refint.runtimeBound=true +extension.refint.dependencies= extension.seg.artifactProduct=oliphaunt-extension-contrib-pg18 extension.seg.releaseProduct=liboliphaunt-native extension.seg.mavenGroup=dev.oliphaunt.extensions diff --git a/src/native/sdks/kotlin/oliphaunt/src/commonMain/kotlin/dev/oliphaunt/GeneratedExtensions.kt b/src/native/sdks/kotlin/oliphaunt/src/commonMain/kotlin/dev/oliphaunt/GeneratedExtensions.kt index 2fbdbbfdb..0edce909c 100644 --- a/src/native/sdks/kotlin/oliphaunt/src/commonMain/kotlin/dev/oliphaunt/GeneratedExtensions.kt +++ b/src/native/sdks/kotlin/oliphaunt/src/commonMain/kotlin/dev/oliphaunt/GeneratedExtensions.kt @@ -11,6 +11,7 @@ internal data class GeneratedExtensionRuntimeContract( internal val generatedExtensionRuntimeContracts: Map = mapOf( "amcheck" to GeneratedExtensionRuntimeContract(createsExtension = true, nativeModuleStem = "amcheck"), "auto_explain" to GeneratedExtensionRuntimeContract(createsExtension = false, nativeModuleStem = "auto_explain"), + "autoinc" to GeneratedExtensionRuntimeContract(createsExtension = true, nativeModuleStem = "autoinc"), "bloom" to GeneratedExtensionRuntimeContract(createsExtension = true, nativeModuleStem = "bloom"), "btree_gin" to GeneratedExtensionRuntimeContract(createsExtension = true, nativeModuleStem = "btree_gin"), "btree_gist" to GeneratedExtensionRuntimeContract(createsExtension = true, nativeModuleStem = "btree_gist"), @@ -22,15 +23,19 @@ internal val generatedExtensionRuntimeContracts: Map '2000-01-01 00:00:00+00') THEN + RAISE EXCEPTION 'moddatetime did not update the modification timestamp'; + END IF; +END +$oliphaunt$; diff --git a/src/test-fixtures/extensions/pg_logicalinspect.sql b/src/test-fixtures/extensions/pg_logicalinspect.sql new file mode 100644 index 000000000..612e793bd --- /dev/null +++ b/src/test-fixtures/extensions/pg_logicalinspect.sql @@ -0,0 +1,23 @@ +-- Exercise both entry points without requiring a logical replication slot. +-- Invalid snapshot names must be rejected before any filesystem access. +-- oliphaunt-verify +DO $oliphaunt$ +BEGIN + BEGIN + PERFORM pg_get_logical_snapshot_meta('../invalid'); + RAISE EXCEPTION 'pg_logicalinspect accepted an invalid snapshot name'; + EXCEPTION WHEN internal_error THEN + IF SQLERRM <> 'invalid snapshot file name "../invalid"' THEN + RAISE; + END IF; + END; + BEGIN + PERFORM pg_get_logical_snapshot_info('../invalid'); + RAISE EXCEPTION 'pg_logicalinspect accepted an invalid snapshot name'; + EXCEPTION WHEN internal_error THEN + IF SQLERRM <> 'invalid snapshot file name "../invalid"' THEN + RAISE; + END IF; + END; +END +$oliphaunt$; diff --git a/src/test-fixtures/extensions/pg_stat_statements.sql b/src/test-fixtures/extensions/pg_stat_statements.sql new file mode 100644 index 000000000..b85346d43 --- /dev/null +++ b/src/test-fixtures/extensions/pg_stat_statements.sql @@ -0,0 +1,21 @@ +-- Reset and collect fresh counters on creation, restart, and backup restore. +-- This fails if the library was loaded after shared-memory startup. +-- oliphaunt-verify +SELECT pg_stat_statements_reset(); +-- oliphaunt-statement +-- oliphaunt-verify +SELECT sum(value) FROM generate_series(1, 3) AS oliphaunt_pgss_probe(value); +-- oliphaunt-statement +-- oliphaunt-verify +DO $oliphaunt$ +BEGIN + IF NOT EXISTS ( + SELECT FROM pg_stat_statements + WHERE query LIKE 'SELECT sum(value) FROM generate_series%oliphaunt_pgss_probe%' + AND dbid = (SELECT oid FROM pg_database WHERE datname = current_database()) + AND queryid <> 0 AND calls >= 1 AND rows = calls + ) THEN + RAISE EXCEPTION 'pg_stat_statements did not record a completed query'; + END IF; +END +$oliphaunt$; diff --git a/src/test-fixtures/extensions/refint.sql b/src/test-fixtures/extensions/refint.sql new file mode 100644 index 000000000..b21dc3717 --- /dev/null +++ b/src/test-fixtures/extensions/refint.sql @@ -0,0 +1,39 @@ +DROP TABLE IF EXISTS oliphaunt_refint_child; +-- oliphaunt-statement +DROP TABLE IF EXISTS oliphaunt_refint_parent; +-- oliphaunt-statement +CREATE TABLE oliphaunt_refint_parent (id integer PRIMARY KEY); +-- oliphaunt-statement +CREATE TABLE oliphaunt_refint_child (parent_id integer); +-- oliphaunt-statement +CREATE TRIGGER oliphaunt_refint_parent_trigger AFTER DELETE OR UPDATE ON oliphaunt_refint_parent +FOR EACH ROW EXECUTE FUNCTION check_foreign_key(1, 'cascade', 'id', 'oliphaunt_refint_child', 'parent_id'); +-- oliphaunt-statement +CREATE TRIGGER oliphaunt_refint_child_trigger AFTER INSERT OR UPDATE ON oliphaunt_refint_child +FOR EACH ROW EXECUTE FUNCTION check_primary_key('parent_id', 'oliphaunt_refint_parent', 'id'); +-- oliphaunt-statement +INSERT INTO oliphaunt_refint_parent VALUES (1), (2); +-- oliphaunt-statement +INSERT INTO oliphaunt_refint_child VALUES (1), (2); +-- oliphaunt-statement +DO $oliphaunt$ +BEGIN + BEGIN + INSERT INTO oliphaunt_refint_child VALUES (3); + RAISE EXCEPTION 'refint accepted a missing parent'; + EXCEPTION WHEN triggered_action_exception THEN + NULL; + END; +END +$oliphaunt$; +-- oliphaunt-statement +DELETE FROM oliphaunt_refint_parent WHERE id = 1; +-- oliphaunt-statement +-- oliphaunt-verify +DO $oliphaunt$ +BEGIN + IF (SELECT array_agg(parent_id) FROM oliphaunt_refint_child) IS DISTINCT FROM ARRAY[2] THEN + RAISE EXCEPTION 'refint did not cascade deletion to the referencing row'; + END IF; +END +$oliphaunt$; diff --git a/src/wasix/runtime/assets/generated/wasix-dl.exports b/src/wasix/runtime/assets/generated/wasix-dl.exports index 456df7e2b..4854fadff 100644 --- a/src/wasix/runtime/assets/generated/wasix-dl.exports +++ b/src/wasix/runtime/assets/generated/wasix-dl.exports @@ -1,6 +1,7 @@ AcquireRewriteLocks AggCheckCallContext AllocSetContextCreateInternal +AllocateFile ArrayGetIntegerTypmods ArrayGetNItems Async_Notify @@ -22,6 +23,7 @@ BufFileWrite BufferBlocks BufferDescriptors BufferGetBlockNumber +BufferUsageAccumDiff BuildIndexInfo BuildTupleFromCStrings CacheMemoryContext @@ -37,6 +39,8 @@ CheckFunctionValidatorAccess CheckIndexCompatible CheckTableNotInUse CheckXidAlive +CleanQuerytext +CloseTransientFile CommandCounterIncrement ConditionVariableBroadcast ConditionVariableCancelSleep @@ -83,6 +87,7 @@ DirectFunctionCall4Coll DirectFunctionCall5Coll EOH_flatten_into EOH_get_flat_size +EnableQueryId EncodeDateOnly EncodeDateTime EncodeSpecialDate @@ -126,6 +131,7 @@ FreeAccessStrategy FreeCachedExpression FreeExecutorState FreeExprContext +FreeFile FreeQueryDesc FunctionCall0Coll FunctionCall1Coll @@ -156,6 +162,7 @@ GetForeignServer GetForeignTable GetFreeIndexPage GetMemoryChunkContext +GetNamedLWLockTranche GetOldestNonRemovableTransactionId GetRecordedFreeSpace GetRunningTransactionData @@ -165,6 +172,7 @@ GetTopFullTransactionId GetTransactionSnapshot GetUserId GetUserIdAndSecContext +GetUserNameFromId GetXLogReplayRecPtr GinDataLeafPageGetItems HeapTupleGetUpdateXid @@ -182,6 +190,7 @@ Int64GetDatum InterruptPending InvalidObjectAddress IsTransactionState +IsUnderPostmaster IsValidJsonNumber ItemPointerCompare ItemPointerEquals @@ -222,6 +231,7 @@ MemoryContextSetParent MemoryContextStrdup MultiXactIdPrecedes MultiXactIdPrecedesOrEquals +MyDatabaseId MyProc NBuffers NameListToString @@ -231,6 +241,7 @@ NewRelationCreateToastTable NextCopyFrom OidFunctionCall1Coll OidOutputFunctionCall +OpenTransientFile OpernameGetOprid OutputFunctionCall PG_exception_stack @@ -285,6 +296,7 @@ ReleaseCurrentSubTransaction ReleaseSysCache RelnameGetRelid RequestAddinShmemSpace +RequestNamedLWLockTranche ResourceOwnerCreate ResourceOwnerDelete ResourceOwnerEnlarge @@ -307,6 +319,7 @@ SPI_cursor_open_with_paramlist SPI_cursor_parse_open SPI_datumTransfer SPI_exec +SPI_execp SPI_execute SPI_execute_extended SPI_execute_plan @@ -318,7 +331,9 @@ SPI_fnumber SPI_freeplan SPI_freetuptable SPI_getbinval +SPI_getrelname SPI_gettype +SPI_gettypeid SPI_getvalue SPI_keepplan SPI_modifytuple @@ -341,6 +356,8 @@ SPI_scroll_cursor_move SPI_tuptable ScanKeyInit ScanKeywordLookup +ScanKeywordTokens +ScanKeywords SearchPathMatchesCurrentEnvironment SearchSysCache1 SearchSysCache2 @@ -352,7 +369,9 @@ SetTuplestoreDestReceiverParams SetUserIdAndSecContext SharedFileSetAttach SharedFileSetInit +ShmemInitHash ShmemInitStruct +SnapBuildRestoreSnapshot SnapshotAnyData SplitIdentifierString SysCacheGetAttrNotNull @@ -380,6 +399,7 @@ UnregisterSnapshot UpdateActiveSnapshotCommandId WaitForParallelWorkersToAttach WaitForParallelWorkersToFinish +WalUsageAccumDiff WinGetCurrentPosition WinGetFuncArgCurrent WinGetFuncArgInPartition @@ -591,6 +611,7 @@ dshash_release_lock dshash_seq_init dshash_seq_next dshash_seq_term +durable_rename end_MultiFuncCall enlargeStringInfo enum_cmp @@ -685,6 +706,7 @@ free_object_addresses fseek fstat ftell +ftruncate function_parse_error_transpose fwrite gen_random_uuid @@ -763,16 +785,19 @@ hash_bytes hash_bytes_extended hash_create hash_destroy +hash_estimate_size hash_get_num_entries hash_search hash_seq_init hash_seq_search +hash_seq_term heap_deform_tuple heap_fetch heap_form_tuple heap_freetuple heap_getsysattr heap_modify_tuple +heap_modify_tuple_by_cols heap_reloptions heap_tuple_needs_eventual_freeze identify_opfamily_groups @@ -879,6 +904,7 @@ nanosleep network_cmp new_object_addresses nextafterf +nextval nocache_index_getattr nocachegetattr nodeToString @@ -914,6 +940,7 @@ oliphaunt_wasix_set_active oliphaunt_wasix_set_force_host_error_recovery oliphaunt_wasix_set_protocol_transport oliphaunt_wasix_start +on_shmem_exit op_hashjoinable op_mergejoinable open @@ -930,6 +957,8 @@ parser_errposition per_MultiFuncCall performMultipleDeletions pfree +pgBufferUsage +pgWalUsage pg_any_to_server pg_ascii_tolower pg_bindtextdomain @@ -1029,6 +1058,7 @@ pull_varattnos pull_varnos pull_vars_of_level pushJsonbValue +pwrite qsort qsort_arg query_tree_walker_impl @@ -1166,9 +1196,11 @@ timestamp_cmp timestamp_eq timestamp_ge timestamp_gt +timestamp_in timestamp_le timestamp_lt timestamp_mi +timestamptz_in timetz_cmp tm2timestamp to_hex32 @@ -1212,6 +1244,7 @@ type_is_collatable type_is_rowtype typeidType typenameTypeIdAndMod +unlink unpack_sql_state untransformRelOptions updateClosestMatch diff --git a/src/wasix/runtime/tools/xtask/src/extension_catalog.rs b/src/wasix/runtime/tools/xtask/src/extension_catalog.rs index 4347779ea..f5f17677b 100644 --- a/src/wasix/runtime/tools/xtask/src/extension_catalog.rs +++ b/src/wasix/runtime/tools/xtask/src/extension_catalog.rs @@ -260,6 +260,7 @@ fn extension_source_dir_for(id: &str, source_kind: &str) -> String { fn extension_contrib_dir_name(id: &str) -> String { match id { "uuid_ossp" => "uuid-ossp".to_owned(), + "autoinc" | "insert_username" | "moddatetime" | "refint" => "spi".to_owned(), other => other.to_owned(), } } @@ -416,4 +417,33 @@ mod tests { "target/oliphaunt-sources/checkouts/pgmq/pgmq-extension" ); } + + #[test] + fn contrib_build_paths_match_the_shared_postgres_inventory() { + let root = Path::new(env!("CARGO_MANIFEST_DIR")).join("../../../../.."); + let catalog: ExtensionCatalog = + serde_json::from_str(&fs::read_to_string(root.join(CATALOG_PATH)).unwrap()).unwrap(); + let inventory: toml::Value = toml::from_str( + &fs::read_to_string(root.join("src/extensions/contrib/postgres18.toml")).unwrap(), + ) + .unwrap(); + for spec in build_specs_at(&catalog, &root).unwrap() { + let Some(directory) = spec.contrib_dir else { + continue; + }; + let recipe = inventory["extensions"] + .as_array() + .unwrap() + .iter() + .find(|recipe| recipe["id"].as_str() == Some(spec.id.as_str())) + .unwrap(); + assert_eq!(Some(directory.as_str()), recipe["contrib-dir"].as_str()); + assert_eq!( + spec.source_dir, + format!("{POSTGRES_CONTRIB}/{directory}"), + "{} must stage its own SQL files from the canonical contrib directory", + spec.id + ); + } + } } diff --git a/src/wasix/sdks/rust/src/oliphaunt/generated_extensions.rs b/src/wasix/sdks/rust/src/oliphaunt/generated_extensions.rs index b5f76c0dc..f6a7da04b 100644 --- a/src/wasix/sdks/rust/src/oliphaunt/generated_extensions.rs +++ b/src/wasix/sdks/rust/src/oliphaunt/generated_extensions.rs @@ -22,6 +22,16 @@ const DEFINITION_AUTO_EXPLAIN: Extension = Extension { package: None, }; +const DEFINITION_AUTOINC: Extension = Extension { + sql_name: "autoinc", + native_support_modules: &[], + native_module_file: Some("autoinc.so"), + aot_name: Some("extension:autoinc"), + dependencies: &[], + startup_config: &[], + package: None, +}; + const DEFINITION_BLOOM: Extension = Extension { sql_name: "bloom", native_support_modules: &[], @@ -132,6 +142,16 @@ const DEFINITION_HSTORE: Extension = Extension { package: None, }; +const DEFINITION_INSERT_USERNAME: Extension = Extension { + sql_name: "insert_username", + native_support_modules: &[], + native_module_file: Some("insert_username.so"), + aot_name: Some("extension:insert_username"), + dependencies: &[], + startup_config: &[], + package: None, +}; + const DEFINITION_INTARRAY: Extension = Extension { sql_name: "intarray", native_support_modules: &[], @@ -172,6 +192,16 @@ const DEFINITION_LTREE: Extension = Extension { package: None, }; +const DEFINITION_MODDATETIME: Extension = Extension { + sql_name: "moddatetime", + native_support_modules: &[], + native_module_file: Some("moddatetime.so"), + aot_name: Some("extension:moddatetime"), + dependencies: &[], + startup_config: &[], + package: None, +}; + const DEFINITION_PAGEINSPECT: Extension = Extension { sql_name: "pageinspect", native_support_modules: &[], @@ -222,6 +252,26 @@ const DEFINITION_PG_IVM: Extension = Extension { package: None, }; +const DEFINITION_PG_LOGICALINSPECT: Extension = Extension { + sql_name: "pg_logicalinspect", + native_support_modules: &[], + native_module_file: Some("pg_logicalinspect.so"), + aot_name: Some("extension:pg_logicalinspect"), + dependencies: &[], + startup_config: &[], + package: None, +}; + +const DEFINITION_PG_STAT_STATEMENTS: Extension = Extension { + sql_name: "pg_stat_statements", + native_support_modules: &[], + native_module_file: Some("pg_stat_statements.so"), + aot_name: Some("extension:pg_stat_statements"), + dependencies: &[], + startup_config: &["shared_preload_libraries=pg_stat_statements"], + package: None, +}; + const DEFINITION_PG_SURGERY: Extension = Extension { sql_name: "pg_surgery", native_support_modules: &[], @@ -325,6 +375,16 @@ const DEFINITION_POSTGIS: Extension = Extension { package: None, }; +const DEFINITION_REFINT: Extension = Extension { + sql_name: "refint", + native_support_modules: &[], + native_module_file: Some("refint.so"), + aot_name: Some("extension:refint"), + dependencies: &[], + startup_config: &[], + package: None, +}; + const DEFINITION_SEG: Extension = Extension { sql_name: "seg", native_support_modules: &[], @@ -412,6 +472,9 @@ impl Extension { /// Select the `auto_explain` artifact. pub const AUTO_EXPLAIN: Self = DEFINITION_AUTO_EXPLAIN; + /// Select the `autoinc` artifact. + + pub const AUTOINC: Self = DEFINITION_AUTOINC; /// Select the `bloom` artifact. pub const BLOOM: Self = DEFINITION_BLOOM; @@ -445,6 +508,9 @@ impl Extension { /// Select the `hstore` artifact. pub const HSTORE: Self = DEFINITION_HSTORE; + /// Select the `insert_username` artifact. + + pub const INSERT_USERNAME: Self = DEFINITION_INSERT_USERNAME; /// Select the `intarray` artifact. pub const INTARRAY: Self = DEFINITION_INTARRAY; @@ -457,6 +523,9 @@ impl Extension { /// Select the `ltree` artifact. pub const LTREE: Self = DEFINITION_LTREE; + /// Select the `moddatetime` artifact. + + pub const MODDATETIME: Self = DEFINITION_MODDATETIME; /// Select the `pageinspect` artifact. pub const PAGEINSPECT: Self = DEFINITION_PAGEINSPECT; @@ -472,6 +541,12 @@ impl Extension { /// Select the `pg_ivm` artifact. pub const PG_IVM: Self = DEFINITION_PG_IVM; + /// Select the `pg_logicalinspect` artifact. + + pub const PG_LOGICALINSPECT: Self = DEFINITION_PG_LOGICALINSPECT; + /// Select the `pg_stat_statements` artifact. + + pub const PG_STAT_STATEMENTS: Self = DEFINITION_PG_STAT_STATEMENTS; /// Select the `pg_surgery` artifact. pub const PG_SURGERY: Self = DEFINITION_PG_SURGERY; @@ -502,6 +577,9 @@ impl Extension { /// Select the `postgis` artifact. pub const POSTGIS: Self = DEFINITION_POSTGIS; + /// Select the `refint` artifact. + + pub const REFINT: Self = DEFINITION_REFINT; /// Select the `seg` artifact. pub const SEG: Self = DEFINITION_SEG; @@ -531,6 +609,7 @@ impl Extension { pub const ALL: &'static [Self] = &[ Self::AMCHECK, Self::AUTO_EXPLAIN, + Self::AUTOINC, Self::BLOOM, Self::BTREE_GIN, Self::BTREE_GIST, @@ -542,15 +621,19 @@ impl Extension { Self::FILE_FDW, Self::FUZZYSTRMATCH, Self::HSTORE, + Self::INSERT_USERNAME, Self::INTARRAY, Self::ISN, Self::LO, Self::LTREE, + Self::MODDATETIME, Self::PAGEINSPECT, Self::PG_BUFFERCACHE, Self::PG_FREESPACEMAP, Self::PG_HASHIDS, Self::PG_IVM, + Self::PG_LOGICALINSPECT, + Self::PG_STAT_STATEMENTS, Self::PG_SURGERY, Self::PG_TEXTSEARCH, Self::PG_TRGM, @@ -561,6 +644,7 @@ impl Extension { Self::PGMQ, Self::PGTAP, Self::POSTGIS, + Self::REFINT, Self::SEG, Self::TABLEFUNC, Self::TCN, @@ -579,6 +663,8 @@ pub(super) fn creates_database_object_for_test(extension: Extension) -> bool { "auto_explain" => false, + "autoinc" => true, + "bloom" => true, "btree_gin" => true, @@ -601,6 +687,8 @@ pub(super) fn creates_database_object_for_test(extension: Extension) -> bool { "hstore" => true, + "insert_username" => true, + "intarray" => true, "isn" => true, @@ -609,6 +697,8 @@ pub(super) fn creates_database_object_for_test(extension: Extension) -> bool { "ltree" => true, + "moddatetime" => true, + "pageinspect" => true, "pg_buffercache" => true, @@ -619,6 +709,10 @@ pub(super) fn creates_database_object_for_test(extension: Extension) -> bool { "pg_ivm" => true, + "pg_logicalinspect" => true, + + "pg_stat_statements" => true, + "pg_surgery" => true, "pg_textsearch" => true, @@ -639,6 +733,8 @@ pub(super) fn creates_database_object_for_test(extension: Extension) -> bool { "postgis" => true, + "refint" => true, + "seg" => true, "tablefunc" => true, @@ -670,6 +766,8 @@ pub(super) fn activation_sql_for_test(extension: Extension) -> &'static [&'stati "SET auto_explain.log_level = 'NOTICE';", ], + "autoinc" => &["CREATE EXTENSION IF NOT EXISTS \"autoinc\" WITH SCHEMA \"pg_catalog\";"], + "bloom" => &["CREATE EXTENSION IF NOT EXISTS \"bloom\" WITH SCHEMA \"pg_catalog\";"], "btree_gin" => { @@ -702,6 +800,10 @@ pub(super) fn activation_sql_for_test(extension: Extension) -> &'static [&'stati "hstore" => &["CREATE EXTENSION IF NOT EXISTS \"hstore\" WITH SCHEMA \"pg_catalog\";"], + "insert_username" => { + &["CREATE EXTENSION IF NOT EXISTS \"insert_username\" WITH SCHEMA \"pg_catalog\";"] + } + "intarray" => &["CREATE EXTENSION IF NOT EXISTS \"intarray\" WITH SCHEMA \"pg_catalog\";"], "isn" => &["CREATE EXTENSION IF NOT EXISTS \"isn\" WITH SCHEMA \"pg_catalog\";"], @@ -710,6 +812,10 @@ pub(super) fn activation_sql_for_test(extension: Extension) -> &'static [&'stati "ltree" => &["CREATE EXTENSION IF NOT EXISTS \"ltree\" WITH SCHEMA \"pg_catalog\";"], + "moddatetime" => { + &["CREATE EXTENSION IF NOT EXISTS \"moddatetime\" WITH SCHEMA \"pg_catalog\";"] + } + "pageinspect" => { &["CREATE EXTENSION IF NOT EXISTS \"pageinspect\" WITH SCHEMA \"pg_catalog\";"] } @@ -728,6 +834,12 @@ pub(super) fn activation_sql_for_test(extension: Extension) -> &'static [&'stati "pg_ivm" => &["CREATE EXTENSION IF NOT EXISTS \"pg_ivm\" WITH SCHEMA \"pg_catalog\";"], + "pg_logicalinspect" => { + &["CREATE EXTENSION IF NOT EXISTS \"pg_logicalinspect\" WITH SCHEMA \"pg_catalog\";"] + } + + "pg_stat_statements" => &["CREATE EXTENSION IF NOT EXISTS \"pg_stat_statements\";"], + "pg_surgery" => { &["CREATE EXTENSION IF NOT EXISTS \"pg_surgery\" WITH SCHEMA \"pg_catalog\";"] } @@ -761,6 +873,8 @@ pub(super) fn activation_sql_for_test(extension: Extension) -> &'static [&'stati "postgis" => &["CREATE EXTENSION IF NOT EXISTS \"postgis\";"], + "refint" => &["CREATE EXTENSION IF NOT EXISTS \"refint\" WITH SCHEMA \"pg_catalog\";"], + "seg" => &["CREATE EXTENSION IF NOT EXISTS \"seg\" WITH SCHEMA \"pg_catalog\";"], "tablefunc" => { From 40fc06604b8ba06c449c92ac1bf00efb51791c0e Mon Sep 17 00:00:00 2001 From: Sid Jain Date: Mon, 19 Oct 2026 06:21:18 +0000 Subject: [PATCH 04/11] feat(extensions): add SQL-only pg_partman 5.5.0 --- .release-please-manifest.json | 1 + release-please-config.json | 7 + .../src/generated/extension-smoke.ts | 19 ++- .../native/tools/build-windows-extensions.sh | 1 + .../tools/windows-extension-sources.mts | 26 ++++ .../tools/windows-extension-sources.test.mts | 35 ++++- src/extensions/catalog/extensions.source.json | 32 +++++ src/extensions/evidence/matrix.toml | 15 +++ .../external/pg_partman/CHANGELOG.md | 0 src/extensions/external/pg_partman/VERSION | 1 + src/extensions/external/pg_partman/moon.yml | 19 +++ .../external/pg_partman/recipe.toml | 30 +++++ .../external/pg_partman/release.toml | 55 ++++++++ .../external/pg_partman/source.toml | 9 ++ .../targets/native-static-registry.toml | 12 ++ .../external/pg_partman/targets/native.toml | 5 + .../external/pg_partman/targets/wasix.toml | 5 + .../pg_partman/upstream-license-data.json | 30 +++++ .../generated/docs/extension-evidence.json | 43 +++++- .../generated/extensions.catalog.json | 41 ++++++ src/extensions/generated/pgxs-build.tsv | 1 + src/extensions/generated/sdk/extensions.json | 30 ++++- .../generated/wasix/extensions.json | 24 ++++ .../tools/extension-projections.mts | 6 +- .../runtime/bin/build-postgres18-linux.sh | 5 + .../runtime/bin/build-postgres18-macos.sh | 5 + .../rust-bindings/src/generated/extensions.rs | 18 +++ .../android/extension-legal-catalog.json | 122 +++++++++++++++++- .../oliphaunt/android/extensions.properties | 8 +- .../dev/oliphaunt/GeneratedExtensions.kt | 1 + .../dev/oliphaunt/OliphauntExtension.kt | 1 + .../react-native/src/generated/extensions.ts | 28 +++- .../OliphauntCore/OliphauntExtension.swift | 1 + .../sdks/ts/src/generated/extensions.ts | 27 +++- src/test-fixtures/extensions/manifest.json | 1 + src/test-fixtures/extensions/pg_partman.sql | 44 +++++++ .../assets/build/docker_pgxs_extensions.sh | 2 +- .../build/docker_pgxs_extensions.test.sh | 76 +++++++++++ src/wasix/runtime/crates/assets/Cargo.toml | 1 + .../runtime/crates/assets/build-support.rs | 7 + src/wasix/runtime/moon.yml | 7 +- .../runtime/tools/xtask/src/asset_pipeline.rs | 84 ++++++++++++ src/wasix/sdks/rust/Cargo.toml | 1 + .../src/oliphaunt/generated_extensions.rs | 21 +++ 44 files changed, 896 insertions(+), 11 deletions(-) create mode 100644 src/extensions/external/pg_partman/CHANGELOG.md create mode 100644 src/extensions/external/pg_partman/VERSION create mode 100644 src/extensions/external/pg_partman/moon.yml create mode 100644 src/extensions/external/pg_partman/recipe.toml create mode 100644 src/extensions/external/pg_partman/release.toml create mode 100644 src/extensions/external/pg_partman/source.toml create mode 100644 src/extensions/external/pg_partman/targets/native-static-registry.toml create mode 100644 src/extensions/external/pg_partman/targets/native.toml create mode 100644 src/extensions/external/pg_partman/targets/wasix.toml create mode 100644 src/extensions/external/pg_partman/upstream-license-data.json create mode 100644 src/test-fixtures/extensions/pg_partman.sql create mode 100644 src/wasix/runtime/assets/build/docker_pgxs_extensions.test.sh diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 8a63fe375..a00fc7297 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -10,6 +10,7 @@ "src/native/sdks/ts": "0.3.1", "src/extensions/external/pg_hashids": "0.3.2", "src/extensions/external/pg_ivm": "0.3.2", + "src/extensions/external/pg_partman": "0.0.0", "src/extensions/external/pg_textsearch": "0.3.2", "src/extensions/external/pg_uuidv7": "0.3.2", "src/extensions/external/pgmq": "0.0.0", diff --git a/release-please-config.json b/release-please-config.json index 06dbd73e6..fd384c59b 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -245,6 +245,13 @@ "version-file": "VERSION", "changelog-path": "CHANGELOG.md" }, + "src/extensions/external/pg_partman": { + "release-type": "simple", + "component": "oliphaunt-extension-pg-partman", + "package-name": "oliphaunt-extension-pg-partman", + "version-file": "VERSION", + "changelog-path": "CHANGELOG.md" + }, "src/extensions/external/pg_textsearch": { "release-type": "simple", "component": "oliphaunt-extension-pg-textsearch", diff --git a/src/examples/native/react-native-expo/src/generated/extension-smoke.ts b/src/examples/native/react-native-expo/src/generated/extension-smoke.ts index 2c9968259..c8d68e705 100644 --- a/src/examples/native/react-native-expo/src/generated/extension-smoke.ts +++ b/src/examples/native/react-native-expo/src/generated/extension-smoke.ts @@ -7,7 +7,7 @@ export type GeneratedMobileExtensionProof = { readonly selectedExtensionDependencies: readonly string[]; }; -export const GENERATED_MOBILE_EXTENSION_METADATA_SHA256 = "b9b246ee0a810514f7ef1fc5966ae31d8e857e8fb146b4593baa04c32cf8fcbf" as const; +export const GENERATED_MOBILE_EXTENSION_METADATA_SHA256 = "72b4266b1468babd53f59bbcf23d62520f5fb5454d35a07d4f482e0504868ac7" as const; export const GENERATED_MOBILE_EXTENSION_PLAN = [ { @@ -142,6 +142,11 @@ export const GENERATED_MOBILE_EXTENSION_PLAN = [ "createsExtension": true, "selectedExtensionDependencies": [] }, + { + "sqlName": "pg_partman", + "createsExtension": true, + "selectedExtensionDependencies": [] + }, { "sqlName": "pg_stat_statements", "createsExtension": true, @@ -377,6 +382,18 @@ export const GENERATED_MOBILE_EXTENSION_SMOKE = { "pg_logicalinspect": [ "-- Exercise both entry points without requiring a logical replication slot.\n-- Invalid snapshot names must be rejected before any filesystem access.\n-- oliphaunt-verify\nDO $oliphaunt$\nBEGIN\n BEGIN\n PERFORM pg_get_logical_snapshot_meta('../invalid');\n RAISE EXCEPTION 'pg_logicalinspect accepted an invalid snapshot name';\n EXCEPTION WHEN internal_error THEN\n IF SQLERRM <> 'invalid snapshot file name \"../invalid\"' THEN\n RAISE;\n END IF;\n END;\n BEGIN\n PERFORM pg_get_logical_snapshot_info('../invalid');\n RAISE EXCEPTION 'pg_logicalinspect accepted an invalid snapshot name';\n EXCEPTION WHEN internal_error THEN\n IF SQLERRM <> 'invalid snapshot file name \"../invalid\"' THEN\n RAISE;\n END IF;\n END;\nEND\n$oliphaunt$;" ], + "pg_partman": [ + "SELECT set_config('search_path', quote_ident(n.nspname) || ', public', false)\nFROM pg_extension e JOIN pg_namespace n ON n.oid = e.extnamespace\nWHERE e.extname = 'pg_partman';", + "CREATE TABLE public.oliphaunt_partman_events (id bigint NOT NULL, payload text)\nPARTITION BY RANGE (id);", + "SELECT create_parent('public.oliphaunt_partman_events', 'id', '10',\n p_premake := 2, p_start_partition := '0', p_jobmon := false);", + "INSERT INTO public.oliphaunt_partman_events VALUES (1, 'old'), (25, 'retained');", + "SELECT run_maintenance('public.oliphaunt_partman_events', p_jobmon := false);", + "DO $$\nBEGIN\n IF to_regclass('public.oliphaunt_partman_events_p40') IS NULL THEN\n RAISE EXCEPTION 'pg_partman did not premake partitions beyond the highest ID';\n END IF;\nEND $$;", + "UPDATE part_config SET retention = '10', retention_keep_table = false\nWHERE parent_table = 'public.oliphaunt_partman_events';", + "SELECT run_maintenance('public.oliphaunt_partman_events', p_jobmon := false);", + "-- oliphaunt-verify\nSELECT set_config('search_path', quote_ident(n.nspname) || ', public', false)\nFROM pg_extension e JOIN pg_namespace n ON n.oid = e.extnamespace\nWHERE e.extname = 'pg_partman';", + "DO $$\nBEGIN\n IF to_regclass('public.oliphaunt_partman_events_p0') IS NOT NULL THEN\n RAISE EXCEPTION 'pg_partman did not remove the expired ID partition';\n END IF;\n IF (SELECT count(*) FROM public.oliphaunt_partman_events) <> 1\n OR NOT EXISTS (SELECT FROM public.oliphaunt_partman_events WHERE id = 25 AND payload = 'retained') THEN\n RAISE EXCEPTION 'pg_partman retention removed or changed the retained row';\n END IF;\n IF NOT EXISTS (SELECT FROM part_config WHERE parent_table = 'public.oliphaunt_partman_events') THEN\n RAISE EXCEPTION 'pg_partman configuration did not survive';\n END IF;\nEND $$;" + ], "pg_stat_statements": [ "-- Reset and collect fresh counters on creation, restart, and backup restore.\n-- This fails if the library was loaded after shared-memory startup.\n-- oliphaunt-verify\nSELECT pg_stat_statements_reset();", "-- oliphaunt-verify\nSELECT sum(value) FROM generate_series(1, 3) AS oliphaunt_pgss_probe(value);", diff --git a/src/extensions/artifacts/native/tools/build-windows-extensions.sh b/src/extensions/artifacts/native/tools/build-windows-extensions.sh index 6c5d025ca..9f3d8c7bf 100644 --- a/src/extensions/artifacts/native/tools/build-windows-extensions.sh +++ b/src/extensions/artifacts/native/tools/build-windows-extensions.sh @@ -156,4 +156,5 @@ windows_extension_install_pgtap() { windows_extension_install() { windows_extension_install_pgtap if selected pgmq; then windows_extension_generate pgmq-install; fi + if selected pg_partman; then windows_extension_generate pg_partman-install; fi } diff --git a/src/extensions/artifacts/native/tools/windows-extension-sources.mts b/src/extensions/artifacts/native/tools/windows-extension-sources.mts index 61ed72fc4..c95fd3188 100644 --- a/src/extensions/artifacts/native/tools/windows-extension-sources.mts +++ b/src/extensions/artifacts/native/tools/windows-extension-sources.mts @@ -642,6 +642,29 @@ export function installPgmq(config: Config) { ); } +export function installPartman(config: Config) { + const source = path.join(config.repo, 'target/oliphaunt-sources/checkouts/pg_partman'); + const destination = path.join(config.install, 'share/postgresql/extension'); + // Match the pinned Makefile's wildcard groups: types and tables precede functions. + const inputs = ['types', 'tables', 'functions', 'procedures'].flatMap((group) => { + const directory = path.join(source, 'sql', group); + const names = glob(directory, '*.sql'); + assert(names.length > 0, `pg_partman SQL group is empty: ${group}`); + return names.map((name) => read(path.join(directory, name))); + }); + write( + path.join(destination, `pg_partman--${version(source, 'pg_partman')}.sql`), + inputs.join(''), + ); + copyFileSync( + path.join(source, 'pg_partman.control'), + path.join(destination, 'pg_partman.control'), + ); + for (const name of glob(path.join(source, 'updates'), 'pg_partman--*--*.sql')) { + copyFileSync(path.join(source, 'updates', name), path.join(destination, name)); + } +} + if (import.meta.main) { const phase = process.argv[2]; const { values } = parseArgs({ @@ -686,6 +709,9 @@ if (import.meta.main) { case 'postgis-sql-unpackaged': postgisSql(config, phase); break; + case 'pg_partman-install': + installPartman(config); + break; case 'pgtap': pgtap(config); break; diff --git a/src/extensions/artifacts/native/tools/windows-extension-sources.test.mts b/src/extensions/artifacts/native/tools/windows-extension-sources.test.mts index dd291a901..22f85335b 100644 --- a/src/extensions/artifacts/native/tools/windows-extension-sources.test.mts +++ b/src/extensions/artifacts/native/tools/windows-extension-sources.test.mts @@ -3,7 +3,7 @@ import assert from 'node:assert/strict'; import { mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; import { tmpdir } from 'node:os'; import path from 'node:path'; -import { installPgmq, patchTextsearch } from './windows-extension-sources.mts'; +import { installPartman, installPgmq, patchTextsearch } from './windows-extension-sources.mts'; test('PGMQ SQL packaging includes the current installation and upgrades, without unrelated files', () => { const root = mkdtempSync(path.join(tmpdir(), 'pgmq-windows-')); @@ -31,6 +31,39 @@ test('PGMQ SQL packaging includes the current installation and upgrades, without } }); + +test('SQL-only pg_partman stages ordered install SQL and upgrades without workers or tools', () => { + const root = mkdtempSync(path.join(tmpdir(), 'partman-windows-')); + try { + const source = path.join(root, 'target/oliphaunt-sources/checkouts/pg_partman'); + for (const group of ['types', 'tables', 'functions', 'procedures']) { + mkdirSync(path.join(source, 'sql', group), { recursive: true }); + writeFileSync(path.join(source, 'sql', group, 'b.sql'), `${group}-b\n`); + writeFileSync(path.join(source, 'sql', group, 'a.sql'), `${group}-a\n`); + } + mkdirSync(path.join(source, 'updates')); + writeFileSync(path.join(source, 'updates', 'pg_partman--5.4.0--5.5.0.sql'), 'upgrade\n'); + writeFileSync(path.join(source, 'updates', 'foreign.sql'), 'excluded\n'); + writeFileSync(path.join(source, 'pg_partman.control'), "default_version = '5.5.0'\n"); + const install = path.join(root, 'install'); + installPartman({ repo: root, work: root, postgres: root, install }); + const destination = path.join(install, 'share/postgresql/extension'); + assert.equal( + readFileSync(path.join(destination, 'pg_partman--5.5.0.sql'), 'utf8'), + ['types', 'tables', 'functions', 'procedures'] + .map((group) => `${group}-a\n${group}-b\n`) + .join(''), + ); + assert.deepEqual([...new Bun.Glob('**/*').scanSync({ cwd: install, onlyFiles: true })].sort(), [ + 'share/postgresql/extension/pg_partman--5.4.0--5.5.0.sql', + 'share/postgresql/extension/pg_partman--5.5.0.sql', + 'share/postgresql/extension/pg_partman.control', + ]); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + test('Windows packing applies to each exact textsearch struct, including V3 predecessors', () => { const root = mkdtempSync(path.join(tmpdir(), 'textsearch-windows-')); const structs = [ diff --git a/src/extensions/catalog/extensions.source.json b/src/extensions/catalog/extensions.source.json index 9d4949362..c1f0ffdc9 100644 --- a/src/extensions/catalog/extensions.source.json +++ b/src/extensions/catalog/extensions.source.json @@ -876,6 +876,38 @@ "native-module-file": "pg_stat_statements.so", "notes": [] }, + { + "id": "pg_partman", + "sql-name": "pg_partman", + "rust-constant": "PG_PARTMAN", + "display-name": "pg_partman", + "source-kind": "oliphaunt-other-extension", + "upstream-import-name": "pg_partman", + "package-export": "./pg_partman", + "tags": ["postgres extension"], + "control-file": "target/oliphaunt-sources/checkouts/pg_partman/pg_partman.control", + "control": { + "requires": ["plpgsql"], + "relocatable": "false", + "superuser": "false" + }, + "dependencies": ["plpgsql"], + "load-order": [], + "lifecycle": { + "create-extension": true, + "create-schema": "partman", + "load-sql": [], + "post-create-sql": [], + "startup-config": [], + "preload-required": false, + "restart-required": false, + "shared-memory-required": false + }, + "tests": ["src/test-fixtures/extensions/pg_partman.sql"], + "notes": [ + "SQL-only build without pg_partman_bgw or Python utilities. Applications invoke maintenance explicitly." + ] + }, { "id": "pg_surgery", "sql-name": "pg_surgery", diff --git a/src/extensions/evidence/matrix.toml b/src/extensions/evidence/matrix.toml index 9f89ca689..3e0911399 100644 --- a/src/extensions/evidence/matrix.toml +++ b/src/extensions/evidence/matrix.toml @@ -10,6 +10,7 @@ source-digest-inputs = [ "src/database-resources/icu/source.toml", "src/extensions/external/pg_hashids/source.toml", "src/extensions/external/pg_ivm/source.toml", + "src/extensions/external/pg_partman/source.toml", "src/extensions/external/pg_textsearch/source.toml", "src/extensions/external/pg_uuidv7/source.toml", "src/extensions/external/pgmq/source.toml", @@ -29,6 +30,11 @@ source-digest-inputs = [ "src/extensions/external/pg_hashids/upstream-license-data.json", "src/extensions/external/pg_ivm/targets/native-static-registry.toml", "src/extensions/external/pg_ivm/upstream-license-data.json", + "src/extensions/external/pg_partman/recipe.toml", + "src/extensions/external/pg_partman/targets/native-static-registry.toml", + "src/extensions/external/pg_partman/targets/native.toml", + "src/extensions/external/pg_partman/targets/wasix.toml", + "src/extensions/external/pg_partman/upstream-license-data.json", "src/extensions/external/pg_textsearch/recipe.toml", "src/extensions/external/pg_textsearch/targets/native-static-registry.toml", "src/extensions/external/pg_textsearch/upstream-license-data.json", @@ -86,6 +92,7 @@ source-digest-inputs = [ "src/test-fixtures/extensions/pg_hashids.sql", "src/test-fixtures/extensions/pg_ivm.sql", "src/test-fixtures/extensions/pg_logicalinspect.sql", + "src/test-fixtures/extensions/pg_partman.sql", "src/test-fixtures/extensions/pg_stat_statements.sql", "src/test-fixtures/extensions/pg_surgery.sql", "src/test-fixtures/extensions/pg_textsearch.sql", @@ -316,6 +323,14 @@ platform-targets = ["portable"] runtime-modes = ["direct","server","restart","backup-restore","materialization"] evidence-required = ["wasix-full-lifecycle-v1"] +[[claims]] +extension = "pg_partman" +postgres-major = 18 +artifact-family = "wasix-runtime" +platform-targets = ["portable"] +runtime-modes = ["direct","server","restart","backup-restore","materialization"] +evidence-required = ["wasix-full-lifecycle-v1"] + [[claims]] extension = "pg_stat_statements" postgres-major = 18 diff --git a/src/extensions/external/pg_partman/CHANGELOG.md b/src/extensions/external/pg_partman/CHANGELOG.md new file mode 100644 index 000000000..e69de29bb diff --git a/src/extensions/external/pg_partman/VERSION b/src/extensions/external/pg_partman/VERSION new file mode 100644 index 000000000..77d6f4ca2 --- /dev/null +++ b/src/extensions/external/pg_partman/VERSION @@ -0,0 +1 @@ +0.0.0 diff --git a/src/extensions/external/pg_partman/moon.yml b/src/extensions/external/pg_partman/moon.yml new file mode 100644 index 000000000..d141faa96 --- /dev/null +++ b/src/extensions/external/pg_partman/moon.yml @@ -0,0 +1,19 @@ +$schema: "https://moonrepo.dev/schemas/project.json" + +id: "oliphaunt-extension-pg-partman" +language: "unknown" +layer: "library" +stack: "systems" +tags: ["extensions", "external", "release-product"] +dependsOn: + - id: "extension-runtime-contract" + scope: "build" + - id: "liboliphaunt-native" + scope: "build" + - id: "liboliphaunt-wasix" + scope: "build" + +project: + release: + component: "oliphaunt-extension-pg-partman" + packagePath: "src/extensions/external/pg_partman" diff --git a/src/extensions/external/pg_partman/recipe.toml b/src/extensions/external/pg_partman/recipe.toml new file mode 100644 index 000000000..3b4d6ce8b --- /dev/null +++ b/src/extensions/external/pg_partman/recipe.toml @@ -0,0 +1,30 @@ +schema = "oliphaunt-extension-recipe-v1" +sql_name = "pg_partman" +display_name = "pg_partman" +kind = "external-simple-pgxs" +license = "PostgreSQL" +source = "pg_partman" +postgres_majors = [18] + +[lifecycle] +creates_extension = true +requires = ["plpgsql"] +implicit_sql_dependencies = [] +load_sql = [] +post_create_sql = [] +shared_preload_libraries = [] +restart_required = false +background_workers = false +shared_memory = false +session_load_required = false +needs_superuser = false +trusted = false + +[artifacts] +control_files = ["share/postgresql/extension/pg_partman.control"] +sql_globs = ["share/postgresql/extension/pg_partman--*.sql"] +native_modules = [] +native_dependency_modules = [] +data_files = [] +headers = [] +licenses = [] diff --git a/src/extensions/external/pg_partman/release.toml b/src/extensions/external/pg_partman/release.toml new file mode 100644 index 000000000..466c156ec --- /dev/null +++ b/src/extensions/external/pg_partman/release.toml @@ -0,0 +1,55 @@ +id = "oliphaunt-extension-pg-partman" +owner = "@oliphaunt/extensions" +kind = "exact-extension-artifact" +shared_source_paths = ["src/extensions/artifacts/packages/tools/package-extension-cargo-facades.mts", "src/extensions/artifacts/packages/tools/package-extension-release-carriers.mts", "src/native/sdks/swift/tools/ios-carrier-manifest.mts", "src/wasix/runtime/tools/package_liboliphaunt_wasix_cargo_artifacts.mts", "tools/packaging/build-maven-artifact-manifest.mts", "tools/packaging/maven-artifact-staging.mts"] +publish_targets = [ + "github-release-assets", + "npm", + "maven-central", + "crates-io", +] +registry_packages = [ + "crates:oliphaunt-extension-pg-partman", + "crates:oliphaunt-extension-pg-partman-linux-arm64-gnu", + "crates:oliphaunt-extension-pg-partman-linux-x64-gnu", + "crates:oliphaunt-extension-pg-partman-macos-arm64", + "crates:oliphaunt-extension-pg-partman-wasix", + "crates:oliphaunt-extension-pg-partman-windows-x64-msvc", + "npm:@oliphaunt/extension-pg-partman", + "npm:@oliphaunt/extension-pg-partman-linux-arm64-gnu", + "npm:@oliphaunt/extension-pg-partman-linux-x64-gnu", + "npm:@oliphaunt/extension-pg-partman-macos-arm64", + "npm:@oliphaunt/extension-pg-partman-wasix", + "npm:@oliphaunt/extension-pg-partman-windows-x64-msvc", + "maven:dev.oliphaunt.extensions:oliphaunt-extension-pg-partman-android-arm64-v8a", + "maven:dev.oliphaunt.extensions:oliphaunt-extension-pg-partman-android-x86_64", +] +release_artifacts = ["exact-extension-artifacts"] +extension_sql_name = "pg_partman" + +[extension] +sql_name = "pg_partman" +class = "external" +versioning = "upstream-bound" + +[extension.source] +path = "src/extensions/external/pg_partman/source.toml" + +[extension.compatibility] +postgres_major = "18" +extension_runtime_contract = "src/extensions/contracts/contract.toml" +native_runtime_product = "liboliphaunt-native" +native_runtime_version = "0.3.3" +wasix_runtime_product = "liboliphaunt-wasix" +wasix_runtime_version = "0.3.2" +[compatibility_versions.oliphaunt-extension-pg-partman-liboliphaunt-native] +public_support = true +source_product = "liboliphaunt-native" +path = "src/extensions/external/pg_partman/release.toml" +parser = "toml:extension.compatibility.native_runtime_version" + +[compatibility_versions.oliphaunt-extension-pg-partman-liboliphaunt-wasix] +public_support = true +source_product = "liboliphaunt-wasix" +path = "src/extensions/external/pg_partman/release.toml" +parser = "toml:extension.compatibility.wasix_runtime_version" diff --git a/src/extensions/external/pg_partman/source.toml b/src/extensions/external/pg_partman/source.toml new file mode 100644 index 000000000..0b691c7c0 --- /dev/null +++ b/src/extensions/external/pg_partman/source.toml @@ -0,0 +1,9 @@ +name = "pg_partman" +url = "https://github.com/pgpartman/pg_partman.git" +branch = "pinned" +commit = "f7e83b9c441c7e97066d815bbe14e02a9dc5ff94" + +[extension-control] +sql-name = "pg_partman" +source-path = "pg_partman.control" +default-version = "5.5.0" diff --git a/src/extensions/external/pg_partman/targets/native-static-registry.toml b/src/extensions/external/pg_partman/targets/native-static-registry.toml new file mode 100644 index 000000000..095968283 --- /dev/null +++ b/src/extensions/external/pg_partman/targets/native-static-registry.toml @@ -0,0 +1,12 @@ +schema = "oliphaunt-extension-target-v1" +artifact_family = "sql-only" +build_kind = "pgxs-sql-only" +platform_targets = [ + "macos-arm64", + "ios-arm64", + "ios-simulator-arm64", + "android-arm64-v8a", + "android-x86_64", +] +module_files = [] +data_files = [] diff --git a/src/extensions/external/pg_partman/targets/native.toml b/src/extensions/external/pg_partman/targets/native.toml new file mode 100644 index 000000000..e693c7978 --- /dev/null +++ b/src/extensions/external/pg_partman/targets/native.toml @@ -0,0 +1,5 @@ +schema = "oliphaunt-extension-target-v1" +artifact_family = "sql-only" +build_kind = "pgxs-sql-only" +module_files = [] +data_files = [] diff --git a/src/extensions/external/pg_partman/targets/wasix.toml b/src/extensions/external/pg_partman/targets/wasix.toml new file mode 100644 index 000000000..e693c7978 --- /dev/null +++ b/src/extensions/external/pg_partman/targets/wasix.toml @@ -0,0 +1,5 @@ +schema = "oliphaunt-extension-target-v1" +artifact_family = "sql-only" +build_kind = "pgxs-sql-only" +module_files = [] +data_files = [] diff --git a/src/extensions/external/pg_partman/upstream-license-data.json b/src/extensions/external/pg_partman/upstream-license-data.json new file mode 100644 index 000000000..a06f79f4b --- /dev/null +++ b/src/extensions/external/pg_partman/upstream-license-data.json @@ -0,0 +1,30 @@ +{ + "schema": "oliphaunt-extension-upstream-license-data-v1", + "sources": [ + { + "id": "pg_partman", + "manifest": "src/extensions/external/pg_partman/source.toml", + "kind": "git", + "url": "https://github.com/pgpartman/pg_partman.git", + "branch": "pinned", + "commit": "f7e83b9c441c7e97066d815bbe14e02a9dc5ff94" + } + ], + "extension": { + "sql_name": "pg_partman", + "files": [ + { + "source": "pg_partman", + "path": "LICENSE.txt", + "destination": "share/licenses/pg_partman/LICENSE.txt", + "role": "license", + "spdx": "PostgreSQL", + "license_url": "https://github.com/pgpartman/pg_partman/blob/f7e83b9c441c7e97066d815bbe14e02a9dc5ff94/LICENSE.txt", + "sha256": "657cd7bde17fc758e47824280a7ccb9bc7d44067e3f3790c2ef4b07e8a04223a" + } + ] + }, + "blobs": { + "657cd7bde17fc758e47824280a7ccb9bc7d44067e3f3790c2ef4b07e8a04223a": "TElDRU5TRSBBTkQgQ09QWVJJR0hUCi0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKUEcgUGFydGl0aW9uIE1hbmFnZXIgKHBnX3BhcnRtYW4pIGlzIHJlbGVhc2VkIHVuZGVyIHRoZSBQb3N0Z3JlU1FMIExpY2Vuc2UsIGEgbGliZXJhbCBPcGVuIFNvdXJjZSBsaWNlbnNlLCBzaW1pbGFyIHRvIHRoZSBCU0Qgb3IgTUlUIGxpY2Vuc2VzLgoKQ29weXJpZ2h0IChjKSAyMDI1LTIwMjYgU25vd2ZsYWtlLCBJbmMuCkNvcHlyaWdodCAoYykgMjAxOC0yMDI1IENydW5jaHkgRGF0YSBTb2x1dGlvbnMsIEluYy4KQ29weXJpZ2h0IChjKSAyMDE3IE9tbmlUSSwgSW5jLgoKUGVybWlzc2lvbiB0byB1c2UsIGNvcHksIG1vZGlmeSwgYW5kIGRpc3RyaWJ1dGUgdGhpcyBzb2Z0d2FyZSBhbmQgaXRzIGRvY3VtZW50YXRpb24gZm9yIGFueSBwdXJwb3NlLCB3aXRob3V0IGZlZSwgYW5kIHdpdGhvdXQgYSB3cml0dGVuIGFncmVlbWVudCBpcyBoZXJlYnkgZ3JhbnRlZCwgcHJvdmlkZWQgdGhhdCB0aGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQgdGhpcyBwYXJhZ3JhcGggYW5kIHRoZSBmb2xsb3dpbmcgdHdvIHBhcmFncmFwaHMgYXBwZWFyIGluIGFsbCBjb3BpZXMuCgpJTiBOTyBFVkVOVCBTSEFMTCBUSEUgQVVUSE9SIEJFIExJQUJMRSBUTyBBTlkgUEFSVFkgRk9SIERJUkVDVCwgSU5ESVJFQ1QsIFNQRUNJQUwsIElOQ0lERU5UQUwsIE9SIENPTlNFUVVFTlRJQUwgREFNQUdFUywgSU5DTFVESU5HIExPU1QgUFJPRklUUywgQVJJU0lORyBPVVQgT0YgVEhFIFVTRSBPRiBUSElTIFNPRlRXQVJFIEFORCBJVFMgRE9DVU1FTlRBVElPTiwgRVZFTiBJRiBUSEUgQVVUSE9SIEhBUyBCRUVOIEFEVklTRUQgT0YgVEhFIFBPU1NJQklMSVRZIE9GIFNVQ0ggREFNQUdFLgoKVEhFIEFVVEhPUiBTUEVDSUZJQ0FMTFkgRElTQ0xBSU1TIEFOWSBXQVJSQU5USUVTLCBJTkNMVURJTkcsIEJVVCBOT1QgTElNSVRFRCBUTywgVEhFIElNUExJRUQgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFkgQU5EIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBUSEUgU09GVFdBUkUgUFJPVklERUQgSEVSRVVOREVSIElTIE9OIEFOICJBUyBJUyIgQkFTSVMsIEFORCBUSEUgQVVUSE9SIEhBUyBOTyBPQkxJR0FUSU9OUyBUTyBQUk9WSURFIE1BSU5URU5BTkNFLCBTVVBQT1JULCBVUERBVEVTLCBFTkhBTkNFTUVOVFMsIE9SIE1PRElGSUNBVElPTlMuCg==" + } +} diff --git a/src/extensions/generated/docs/extension-evidence.json b/src/extensions/generated/docs/extension-evidence.json index 6859ee32e..eceb29525 100644 --- a/src/extensions/generated/docs/extension-evidence.json +++ b/src/extensions/generated/docs/extension-evidence.json @@ -884,6 +884,40 @@ ], "sql-name": "pg_logicalinspect" }, + { + "artifact-family": "wasix-runtime", + "evidence-required": [ + "wasix-full-lifecycle-v1" + ], + "extension": "pg_partman", + "latest-accepted-evidence": [], + "missing-current-evidence": [ + { + "artifact-family": "wasix-runtime", + "evidence-tier": "wasix-full-lifecycle-v1", + "platform-target": "portable", + "runtime-modes": [ + "direct", + "server", + "restart", + "backup-restore", + "materialization" + ] + } + ], + "platform-targets": [ + "portable" + ], + "postgres-major": 18, + "runtime-modes": [ + "direct", + "server", + "restart", + "backup-restore", + "materialization" + ], + "sql-name": "pg_partman" + }, { "artifact-family": "wasix-runtime", "evidence-required": [ @@ -1584,7 +1618,7 @@ "collector": "src/extensions/tools/collect-wasix-evidence.sh", "kind": "exact-sha-ci" }, - "source-digest": "sha256:fb1ece0312ea77afc2f313191fb705a959389f8b8e1cb2ca9142a608d861cdf4", + "source-digest": "sha256:5519c1a61255d31585b62a63fd3cf7450aad6fae54553f544631c55e131e8335", "source-digest-inputs": [ "src/third-party/postgres/source.toml", "src/extensions/catalog/extensions.source.json", @@ -1596,6 +1630,7 @@ "src/database-resources/icu/source.toml", "src/extensions/external/pg_hashids/source.toml", "src/extensions/external/pg_ivm/source.toml", + "src/extensions/external/pg_partman/source.toml", "src/extensions/external/pg_textsearch/source.toml", "src/extensions/external/pg_uuidv7/source.toml", "src/extensions/external/pgmq/source.toml", @@ -1615,6 +1650,11 @@ "src/extensions/external/pg_hashids/upstream-license-data.json", "src/extensions/external/pg_ivm/targets/native-static-registry.toml", "src/extensions/external/pg_ivm/upstream-license-data.json", + "src/extensions/external/pg_partman/recipe.toml", + "src/extensions/external/pg_partman/targets/native-static-registry.toml", + "src/extensions/external/pg_partman/targets/native.toml", + "src/extensions/external/pg_partman/targets/wasix.toml", + "src/extensions/external/pg_partman/upstream-license-data.json", "src/extensions/external/pg_textsearch/recipe.toml", "src/extensions/external/pg_textsearch/targets/native-static-registry.toml", "src/extensions/external/pg_textsearch/upstream-license-data.json", @@ -1672,6 +1712,7 @@ "src/test-fixtures/extensions/pg_hashids.sql", "src/test-fixtures/extensions/pg_ivm.sql", "src/test-fixtures/extensions/pg_logicalinspect.sql", + "src/test-fixtures/extensions/pg_partman.sql", "src/test-fixtures/extensions/pg_stat_statements.sql", "src/test-fixtures/extensions/pg_surgery.sql", "src/test-fixtures/extensions/pg_textsearch.sql", diff --git a/src/extensions/generated/extensions.catalog.json b/src/extensions/generated/extensions.catalog.json index f242b2941..d57d22162 100644 --- a/src/extensions/generated/extensions.catalog.json +++ b/src/extensions/generated/extensions.catalog.json @@ -1003,6 +1003,47 @@ "native-module-file": "pg_logicalinspect.so", "notes": [] }, + { + "id": "pg_partman", + "sql-name": "pg_partman", + "rust-constant": "PG_PARTMAN", + "display-name": "pg_partman", + "source-kind": "oliphaunt-other-extension", + "upstream-import-name": "pg_partman", + "package-export": "./pg_partman", + "tags": [ + "postgres extension" + ], + "control-file": "target/oliphaunt-sources/checkouts/pg_partman/pg_partman.control", + "control": { + "default-version": "5.5.0", + "requires": [ + "plpgsql" + ], + "relocatable": "false", + "superuser": "false" + }, + "dependencies": [ + "plpgsql" + ], + "load-order": [], + "lifecycle": { + "create-extension": true, + "create-schema": "partman", + "load-sql": [], + "post-create-sql": [], + "startup-config": [], + "preload-required": false, + "restart-required": false, + "shared-memory-required": false + }, + "tests": [ + "src/test-fixtures/extensions/pg_partman.sql" + ], + "notes": [ + "SQL-only build without pg_partman_bgw or Python utilities. Applications invoke maintenance explicitly." + ] + }, { "id": "pg_stat_statements", "sql-name": "pg_stat_statements", diff --git a/src/extensions/generated/pgxs-build.tsv b/src/extensions/generated/pgxs-build.tsv index ac77a68d6..692b1e275 100644 --- a/src/extensions/generated/pgxs-build.tsv +++ b/src/extensions/generated/pgxs-build.tsv @@ -1,6 +1,7 @@ # id sql_name source_dir module_file archive make_args pg_hashids pg_hashids target/oliphaunt-sources/checkouts/pg_hashids pg_hashids.so extensions/pg_hashids.tar.zst - pg_ivm pg_ivm target/oliphaunt-sources/checkouts/pg_ivm pg_ivm.so extensions/pg_ivm.tar.zst - +pg_partman pg_partman target/oliphaunt-sources/checkouts/pg_partman - extensions/pg_partman.tar.zst NO_BGW=1 SCRIPTS= DOCS= pg_textsearch pg_textsearch target/oliphaunt-sources/checkouts/pg_textsearch pg_textsearch.so extensions/pg_textsearch.tar.zst - pg_uuidv7 pg_uuidv7 target/oliphaunt-sources/checkouts/pg_uuidv7 pg_uuidv7.so extensions/pg_uuidv7.tar.zst - pgmq pgmq target/oliphaunt-sources/checkouts/pgmq/pgmq-extension - extensions/pgmq.tar.zst - diff --git a/src/extensions/generated/sdk/extensions.json b/src/extensions/generated/sdk/extensions.json index 0f7805cbb..95a57b1d5 100644 --- a/src/extensions/generated/sdk/extensions.json +++ b/src/extensions/generated/sdk/extensions.json @@ -1,5 +1,5 @@ { - "extension-catalog-sha256": "b9b246ee0a810514f7ef1fc5966ae31d8e857e8fb146b4593baa04c32cf8fcbf", + "extension-catalog-sha256": "72b4266b1468babd53f59bbcf23d62520f5fb5454d35a07d4f482e0504868ac7", "extensions": [ { "artifact-product": "oliphaunt-extension-contrib-pg18", @@ -685,6 +685,34 @@ "source-kind": "postgres-contrib", "sql-name": "pg_logicalinspect" }, + { + "artifact-product": "oliphaunt-extension-pg-partman", + "cargo-package": "oliphaunt-extension-pg-partman", + "creates-extension": true, + "data-files": [], + "dependencies": [ + "plpgsql" + ], + "display-name": "pg_partman", + "extension-sql-file-names": [], + "extension-sql-file-prefixes": [], + "id": "pg_partman", + "maven-artifact": "oliphaunt-extension-pg-partman", + "maven-group": "dev.oliphaunt.extensions", + "native-component-requirements": [], + "native-components": [], + "native-module-stem": null, + "npm-package": "@oliphaunt/extension-pg-partman", + "postgres-major": 18, + "release-product": "oliphaunt-extension-pg-partman", + "runtime-bound": false, + "runtime-environment": [], + "runtime-share-data-files": [], + "selected-extension-dependencies": [], + "shared-preload-libraries": [], + "source-kind": "oliphaunt-other-extension", + "sql-name": "pg_partman" + }, { "artifact-product": "oliphaunt-extension-contrib-pg18", "cargo-package": "oliphaunt-extension-contrib-pg18", diff --git a/src/extensions/generated/wasix/extensions.json b/src/extensions/generated/wasix/extensions.json index ccf5251f0..c9d416e26 100644 --- a/src/extensions/generated/wasix/extensions.json +++ b/src/extensions/generated/wasix/extensions.json @@ -578,6 +578,30 @@ "native-support-modules": [], "sql-name": "pg_logicalinspect" }, + { + "archive": "extensions/pg_partman.tar.zst", + "dependencies": [ + "plpgsql" + ], + "id": "pg_partman", + "lifecycle": { + "create-extension": true, + "create-schema": "partman", + "load-sql": [], + "post-create-sql": [], + "preload-required": false, + "restart-required": false, + "shared-memory-required": false, + "startup-config": [] + }, + "load-order": [], + "native-components": [], + "native-link-units": [], + "native-module-file": null, + "native-runtime-files": [], + "native-support-modules": [], + "sql-name": "pg_partman" + }, { "archive": "extensions/pg_stat_statements.tar.zst", "dependencies": [], diff --git a/src/extensions/tools/extension-projections.mts b/src/extensions/tools/extension-projections.mts index f63313a5e..bd7b6b015 100644 --- a/src/extensions/tools/extension-projections.mts +++ b/src/extensions/tools/extension-projections.mts @@ -647,7 +647,11 @@ export function catalogProjections(catalog: Row): Map { pgxsSourceDirectory(source.name, recipe.build?.source_subdirectory), row['native-module-file'] ?? '-', archive, - row.id === 'age' ? 'SIZEOF_DATUM=4' : '-', + row.id === 'age' + ? 'SIZEOF_DATUM=4' + : row.id === 'pg_partman' + ? 'NO_BGW=1 SCRIPTS= DOCS=' + : '-', ].join('\t'), ); } else assert.equal(row['source-kind'], 'postgis', 'unsupported extension build kind'); diff --git a/src/native/runtime/bin/build-postgres18-linux.sh b/src/native/runtime/bin/build-postgres18-linux.sh index 226e0a949..74f64a600 100755 --- a/src/native/runtime/bin/build-postgres18-linux.sh +++ b/src/native/runtime/bin/build-postgres18-linux.sh @@ -127,6 +127,7 @@ external_extensions=( pg_ivm pg_hashids pg_uuidv7 + pg_partman pgtap pgmq pgvector @@ -168,6 +169,7 @@ required_extension_controls=( pg_visibility pg_walinspect pgcrypto + pg_partman pgtap pgmq postgis @@ -1126,6 +1128,9 @@ pgxs_extension_link_args() { local be_dllibs="$2" [ -z "$be_dllibs" ] || printf '%s\n' "PG_LDFLAGS=$be_dllibs" case "$extension" in + pg_partman) + printf '%s\n' "NO_BGW=1" "SCRIPTS=" "DOCS=" + ;; pg_textsearch|pgvector|vector) printf '%s\n' "SHLIB_LINK=-lm" ;; diff --git a/src/native/runtime/bin/build-postgres18-macos.sh b/src/native/runtime/bin/build-postgres18-macos.sh index 9bef8af3a..052624985 100755 --- a/src/native/runtime/bin/build-postgres18-macos.sh +++ b/src/native/runtime/bin/build-postgres18-macos.sh @@ -111,6 +111,7 @@ external_extensions=( pg_ivm pg_hashids pg_uuidv7 + pg_partman pgtap pgmq pgvector @@ -152,6 +153,7 @@ required_extension_controls=( pg_visibility pg_walinspect pgcrypto + pg_partman pgtap pgmq postgis @@ -1938,6 +1940,9 @@ pgxs_extension_link_args() { local link_flags="$3" local be_dllibs="$link_flags" case "$extension" in + pg_partman) + printf '%s\n' "NO_BGW=1" "SCRIPTS=" "DOCS=" + ;; pg_textsearch|pgvector|vector) if [ -n "$be_dllibs" ]; then be_dllibs="$be_dllibs -lm" diff --git a/src/native/rust-bindings/src/generated/extensions.rs b/src/native/rust-bindings/src/generated/extensions.rs index 2f42ce01a..786fa383c 100644 --- a/src/native/rust-bindings/src/generated/extensions.rs +++ b/src/native/rust-bindings/src/generated/extensions.rs @@ -64,6 +64,8 @@ enum ExtensionId { PgIvm, /// PostgreSQL `pg_logicalinspect`. PgLogicalinspect, + /// PostgreSQL `pg_partman`. + PgPartman, /// PostgreSQL `pg_stat_statements`. PgStatStatements, /// PostgreSQL `pg_surgery`. @@ -237,6 +239,11 @@ impl Extension { id: ExtensionId::PgLogicalinspect, package: None, }; + /// Select the `pg_partman` artifact. + pub const PG_PARTMAN: Self = Self { + id: ExtensionId::PgPartman, + package: None, + }; /// Select the `pg_stat_statements` artifact. pub const PG_STAT_STATEMENTS: Self = Self { id: ExtensionId::PgStatStatements, @@ -366,6 +373,7 @@ impl Extension { Extension::PG_HASHIDS, Extension::PG_IVM, Extension::PG_LOGICALINSPECT, + Extension::PG_PARTMAN, Extension::PG_STAT_STATEMENTS, Extension::PG_SURGERY, Extension::PG_TEXTSEARCH, @@ -418,6 +426,7 @@ pub(super) const fn sql_name(extension: Extension) -> &'static str { ExtensionId::PgHashids => "pg_hashids", ExtensionId::PgIvm => "pg_ivm", ExtensionId::PgLogicalinspect => "pg_logicalinspect", + ExtensionId::PgPartman => "pg_partman", ExtensionId::PgStatStatements => "pg_stat_statements", ExtensionId::PgSurgery => "pg_surgery", ExtensionId::PgTextsearch => "pg_textsearch", @@ -470,6 +479,7 @@ pub(super) const fn artifact_product(extension: Extension) -> &'static str { ExtensionId::PgHashids => "oliphaunt-extension-pg-hashids", ExtensionId::PgIvm => "oliphaunt-extension-pg-ivm", ExtensionId::PgLogicalinspect => "oliphaunt-extension-contrib-pg18", + ExtensionId::PgPartman => "oliphaunt-extension-pg-partman", ExtensionId::PgStatStatements => "oliphaunt-extension-contrib-pg18", ExtensionId::PgSurgery => "oliphaunt-extension-contrib-pg18", ExtensionId::PgTextsearch => "oliphaunt-extension-pg-textsearch", @@ -522,6 +532,7 @@ pub(super) const fn native_module_stem(extension: Extension) -> Option<&'static ExtensionId::PgHashids => Some("pg_hashids"), ExtensionId::PgIvm => Some("pg_ivm"), ExtensionId::PgLogicalinspect => Some("pg_logicalinspect"), + ExtensionId::PgPartman => None, ExtensionId::PgStatStatements => Some("pg_stat_statements"), ExtensionId::PgSurgery => Some("pg_surgery"), ExtensionId::PgTextsearch => Some("pg_textsearch"), @@ -574,6 +585,7 @@ pub(super) const fn creates_extension(extension: Extension) -> bool { ExtensionId::PgHashids => true, ExtensionId::PgIvm => true, ExtensionId::PgLogicalinspect => true, + ExtensionId::PgPartman => true, ExtensionId::PgStatStatements => true, ExtensionId::PgSurgery => true, ExtensionId::PgTextsearch => true, @@ -626,6 +638,7 @@ pub(super) const fn dependencies(extension: Extension) -> &'static [Extension] { ExtensionId::PgHashids => &[], ExtensionId::PgIvm => &[], ExtensionId::PgLogicalinspect => &[], + ExtensionId::PgPartman => &[], ExtensionId::PgStatStatements => &[], ExtensionId::PgSurgery => &[], ExtensionId::PgTextsearch => &[], @@ -678,6 +691,7 @@ pub(super) const fn required_shared_preload_library(extension: Extension) -> Opt ExtensionId::PgHashids => None, ExtensionId::PgIvm => None, ExtensionId::PgLogicalinspect => None, + ExtensionId::PgPartman => None, ExtensionId::PgStatStatements => Some("pg_stat_statements"), ExtensionId::PgSurgery => None, ExtensionId::PgTextsearch => Some("pg_textsearch"), @@ -730,6 +744,7 @@ pub(super) const fn extension_data_files(extension: Extension) -> &'static [&'st ExtensionId::PgHashids => &[], ExtensionId::PgIvm => &[], ExtensionId::PgLogicalinspect => &[], + ExtensionId::PgPartman => &[], ExtensionId::PgStatStatements => &[], ExtensionId::PgSurgery => &[], ExtensionId::PgTextsearch => &[], @@ -792,6 +807,7 @@ pub(super) const fn extension_sql_file_prefixes(extension: Extension) -> &'stati ExtensionId::PgHashids => &[], ExtensionId::PgIvm => &[], ExtensionId::PgLogicalinspect => &[], + ExtensionId::PgPartman => &[], ExtensionId::PgStatStatements => &[], ExtensionId::PgSurgery => &[], ExtensionId::PgTextsearch => &[], @@ -848,6 +864,7 @@ pub(super) const fn extension_sql_file_names(extension: Extension) -> &'static [ ExtensionId::PgHashids => &[], ExtensionId::PgIvm => &[], ExtensionId::PgLogicalinspect => &[], + ExtensionId::PgPartman => &[], ExtensionId::PgStatStatements => &[], ExtensionId::PgSurgery => &[], ExtensionId::PgTextsearch => &[], @@ -902,6 +919,7 @@ pub(super) const fn runtime_environment( ExtensionId::PgHashids => &[], ExtensionId::PgIvm => &[], ExtensionId::PgLogicalinspect => &[], + ExtensionId::PgPartman => &[], ExtensionId::PgStatStatements => &[], ExtensionId::PgSurgery => &[], ExtensionId::PgTextsearch => &[], diff --git a/src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extension-legal-catalog.json b/src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extension-legal-catalog.json index e4126dbe4..1c7004246 100644 --- a/src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extension-legal-catalog.json +++ b/src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extension-legal-catalog.json @@ -1,6 +1,6 @@ { "schema": "oliphaunt-android-extension-legal-catalog-v1", - "sourceCatalogSha256": "b9b246ee0a810514f7ef1fc5966ae31d8e857e8fb146b4593baa04c32cf8fcbf", + "sourceCatalogSha256": "72b4266b1468babd53f59bbcf23d62520f5fb5454d35a07d4f482e0504868ac7", "contracts": [ { "scope": "aggregate", @@ -190,6 +190,66 @@ } ] }, + { + "scope": "aggregate", + "identity": "oliphaunt-extension-pg-partman", + "product": "oliphaunt-extension-pg-partman", + "target": "android-arm64-v8a", + "profile": "external-native", + "licenseFiles": [ + "share/licenses/pg_partman/LICENSE.txt" + ], + "members": [ + { + "path": "LICENSE", + "bytes": 1085, + "sha256": "6f8300e2f43c5a012d6f914fe5affa9090b97b0be39ddf3846f01b905edd8c10", + "mode": "0644" + }, + { + "path": "THIRD_PARTY_NOTICES.md", + "bytes": 821, + "sha256": "20fd67487d1a631ba959cf7ec3fdbaf4977997ed624c0188dcb3c8870eded830", + "mode": "0644" + }, + { + "path": "share/licenses/pg_partman/LICENSE.txt", + "bytes": 1201, + "sha256": "657cd7bde17fc758e47824280a7ccb9bc7d44067e3f3790c2ef4b07e8a04223a", + "mode": "0644" + } + ] + }, + { + "scope": "aggregate", + "identity": "oliphaunt-extension-pg-partman", + "product": "oliphaunt-extension-pg-partman", + "target": "android-x86_64", + "profile": "external-native", + "licenseFiles": [ + "share/licenses/pg_partman/LICENSE.txt" + ], + "members": [ + { + "path": "LICENSE", + "bytes": 1085, + "sha256": "6f8300e2f43c5a012d6f914fe5affa9090b97b0be39ddf3846f01b905edd8c10", + "mode": "0644" + }, + { + "path": "THIRD_PARTY_NOTICES.md", + "bytes": 821, + "sha256": "20fd67487d1a631ba959cf7ec3fdbaf4977997ed624c0188dcb3c8870eded830", + "mode": "0644" + }, + { + "path": "share/licenses/pg_partman/LICENSE.txt", + "bytes": 1201, + "sha256": "657cd7bde17fc758e47824280a7ccb9bc7d44067e3f3790c2ef4b07e8a04223a", + "mode": "0644" + } + ] + }, { "scope": "aggregate", "identity": "oliphaunt-extension-pg-textsearch", @@ -2238,6 +2298,66 @@ } ] }, + { + "scope": "leaf", + "identity": "pg_partman", + "product": "oliphaunt-extension-pg-partman", + "target": "android-arm64-v8a", + "profile": "external-native", + "licenseFiles": [ + "share/licenses/pg_partman/LICENSE.txt" + ], + "members": [ + { + "path": "LICENSE", + "bytes": 1085, + "sha256": "6f8300e2f43c5a012d6f914fe5affa9090b97b0be39ddf3846f01b905edd8c10", + "mode": "0644" + }, + { + "path": "THIRD_PARTY_NOTICES.md", + "bytes": 821, + "sha256": "20fd67487d1a631ba959cf7ec3fdbaf4977997ed624c0188dcb3c8870eded830", + "mode": "0644" + }, + { + "path": "files/share/licenses/pg_partman/LICENSE.txt", + "bytes": 1201, + "sha256": "657cd7bde17fc758e47824280a7ccb9bc7d44067e3f3790c2ef4b07e8a04223a", + "mode": "0644" + } + ] + }, + { + "scope": "leaf", + "identity": "pg_partman", + "product": "oliphaunt-extension-pg-partman", + "target": "android-x86_64", + "profile": "external-native", + "licenseFiles": [ + "share/licenses/pg_partman/LICENSE.txt" + ], + "members": [ + { + "path": "LICENSE", + "bytes": 1085, + "sha256": "6f8300e2f43c5a012d6f914fe5affa9090b97b0be39ddf3846f01b905edd8c10", + "mode": "0644" + }, + { + "path": "THIRD_PARTY_NOTICES.md", + "bytes": 821, + "sha256": "20fd67487d1a631ba959cf7ec3fdbaf4977997ed624c0188dcb3c8870eded830", + "mode": "0644" + }, + { + "path": "files/share/licenses/pg_partman/LICENSE.txt", + "bytes": 1201, + "sha256": "657cd7bde17fc758e47824280a7ccb9bc7d44067e3f3790c2ef4b07e8a04223a", + "mode": "0644" + } + ] + }, { "scope": "leaf", "identity": "pg_stat_statements", diff --git a/src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extensions.properties b/src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extensions.properties index 5cea04152..57693d1a0 100644 --- a/src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extensions.properties +++ b/src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extensions.properties @@ -1,7 +1,7 @@ # This file is generated by src/extensions/tools/check-extension-model.sh. # Do not edit by hand. schema=oliphaunt-android-extension-catalog-v2 -catalogSha256=b9b246ee0a810514f7ef1fc5966ae31d8e857e8fb146b4593baa04c32cf8fcbf +catalogSha256=72b4266b1468babd53f59bbcf23d62520f5fb5454d35a07d4f482e0504868ac7 extension.amcheck.artifactProduct=oliphaunt-extension-contrib-pg18 extension.amcheck.releaseProduct=liboliphaunt-native extension.amcheck.mavenGroup=dev.oliphaunt.extensions @@ -158,6 +158,12 @@ extension.pg_logicalinspect.mavenGroup=dev.oliphaunt.extensions extension.pg_logicalinspect.mavenArtifact=oliphaunt-extension-contrib-pg18 extension.pg_logicalinspect.runtimeBound=true extension.pg_logicalinspect.dependencies= +extension.pg_partman.artifactProduct=oliphaunt-extension-pg-partman +extension.pg_partman.releaseProduct=oliphaunt-extension-pg-partman +extension.pg_partman.mavenGroup=dev.oliphaunt.extensions +extension.pg_partman.mavenArtifact=oliphaunt-extension-pg-partman +extension.pg_partman.runtimeBound=false +extension.pg_partman.dependencies= extension.pg_stat_statements.artifactProduct=oliphaunt-extension-contrib-pg18 extension.pg_stat_statements.releaseProduct=liboliphaunt-native extension.pg_stat_statements.mavenGroup=dev.oliphaunt.extensions diff --git a/src/native/sdks/kotlin/oliphaunt/src/commonMain/kotlin/dev/oliphaunt/GeneratedExtensions.kt b/src/native/sdks/kotlin/oliphaunt/src/commonMain/kotlin/dev/oliphaunt/GeneratedExtensions.kt index 0edce909c..638ce6c52 100644 --- a/src/native/sdks/kotlin/oliphaunt/src/commonMain/kotlin/dev/oliphaunt/GeneratedExtensions.kt +++ b/src/native/sdks/kotlin/oliphaunt/src/commonMain/kotlin/dev/oliphaunt/GeneratedExtensions.kt @@ -35,6 +35,7 @@ internal val generatedExtensionRuntimeContracts: Map 1 + OR NOT EXISTS (SELECT FROM public.oliphaunt_partman_events WHERE id = 25 AND payload = 'retained') THEN + RAISE EXCEPTION 'pg_partman retention removed or changed the retained row'; + END IF; + IF NOT EXISTS (SELECT FROM part_config WHERE parent_table = 'public.oliphaunt_partman_events') THEN + RAISE EXCEPTION 'pg_partman configuration did not survive'; + END IF; +END $$; diff --git a/src/wasix/runtime/assets/build/docker_pgxs_extensions.sh b/src/wasix/runtime/assets/build/docker_pgxs_extensions.sh index 110799144..d68383391 100755 --- a/src/wasix/runtime/assets/build/docker_pgxs_extensions.sh +++ b/src/wasix/runtime/assets/build/docker_pgxs_extensions.sh @@ -92,7 +92,7 @@ fi ln -sf "$PGSRC/src/makefiles/pgxs.mk" "$BUILD_DIR/src/makefiles/pgxs.mk" ln -sf "$PGSRC/src/Makefile.shlib" "$BUILD_DIR/src/Makefile.shlib" - while IFS=$'\''\t'\'' read -r id sql_name source_dir module_file archive stable make_args; do + while IFS=$'\''\t'\'' read -r id sql_name source_dir module_file archive make_args; do case "$id" in ""|"#"*) continue ;; esac test -n "$sql_name" test -n "$source_dir" diff --git a/src/wasix/runtime/assets/build/docker_pgxs_extensions.test.sh b/src/wasix/runtime/assets/build/docker_pgxs_extensions.test.sh new file mode 100644 index 000000000..a35d09ba4 --- /dev/null +++ b/src/wasix/runtime/assets/build/docker_pgxs_extensions.test.sh @@ -0,0 +1,76 @@ +#!/usr/bin/env bash +set -euo pipefail + +script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +repo_root="$(git -C "$script_dir" rev-parse --show-toplevel)" +fixture="$(mktemp -d)" +trap 'rm -rf "$fixture"' EXIT +export OLIPHAUNT_PGXS_TEST_ROOT="$fixture" +build_scripts="$fixture/src/wasix/runtime/assets/build" +mkdir -p "$build_scripts" "$fixture/bin" "$fixture/build/src/backend" "$fixture/postgres/src/makefiles" +touch "$fixture/build/config.status" "$fixture/build/src/backend/oliphaunt" +printf 'test\n' > "$fixture/build/.oliphaunt-wasix-build-profile" +sha256sum "$fixture/build/config.status" > "$fixture/build/.oliphaunt-wasix-bridge-sha256" +cat > "$build_scripts/profile_flags.sh" <<'SH' +oliphaunt_wasix_apply_wasix_profile() { :; } +oliphaunt_wasix_wasix_profile_signature() { echo test; } +SH +cat > "$build_scripts/source_lane.sh" <<'SH' +oliphaunt_wasix_check_source_markers() { :; } +oliphaunt_wasix_verify_side_module_sjlj() { :; } +SH +touch "$build_scripts/docker_wasix_env.sh" +printf '#!/usr/bin/env bash\necho\n' > "$build_scripts/pg_config_wasix.sh" +chmod +x "$build_scripts/pg_config_wasix.sh" + +# Run the actual Docker payload locally with harmless source/build fixtures. +# Only the container mount path and prerequisite toolchain are substituted. +cat > "$fixture/bin/docker" <<'SH' +#!/usr/bin/env bash +set -euo pipefail +if [[ "$1" == image ]]; then exit 0; fi +while [[ "$1" != bash ]]; do + if [[ "$1" == -e ]]; then export "$2"; shift; fi + shift +done +payload="${3//\/work\//$OLIPHAUNT_PGXS_TEST_ROOT/}" +cd "$OLIPHAUNT_PGXS_TEST_ROOT" +exec bash -c "$payload" +SH +chmod +x "$fixture/bin/docker" + +# Use the generated SQL-only row, plus a compiled extension with one make arg. +awk -F '\t' '$1 == "pg_partman"' "$repo_root/src/extensions/generated/pgxs-build.tsv" > "$fixture/plan.tsv" +test -s "$fixture/plan.tsv" +printf 'age\tage\tfixture-age\tage.so\textensions/age.tar.zst\tSIZEOF_DATUM=4\n' >> "$fixture/plan.tsv" +partman_source="$(cut -f3 "$fixture/plan.tsv" | head -1)" +mkdir -p "$fixture/$partman_source" "$fixture/fixture-age" +cat > "$fixture/$partman_source/Makefile" <<'MAKE' +SCRIPTS = unwanted-tools +DOCS = unwanted-docs +all: + @test "$(NO_BGW)" = 1 + @test -z "$(SCRIPTS)" + @test -z "$(DOCS)" + @touch flags-verified +clean: + @true +MAKE +cat > "$fixture/fixture-age/Makefile" <<'MAKE' +all: + @test "$(SIZEOF_DATUM)" = 4 + @touch age.so flags-verified +clean: + @true +MAKE + +DOCKER="$fixture/bin/docker" \ + JOBS=2 OLIPHAUNT_WASM_SKIP_IMAGE_BUILD=1 \ + CONTAINER_PGSRC="$fixture/postgres" \ + CONTAINER_BUILD_DIR="$fixture/build" \ + CONTAINER_ROOT="$build_scripts" \ + CONTAINER_PLAN="$fixture/plan.tsv" \ + bash "$script_dir/docker_pgxs_extensions.sh" +test -f "$fixture/build/pgxs/pg_partman/flags-verified" +test -f "$fixture/build/pgxs/age/flags-verified" +echo 'WASIX PGXS generated plan passes each make argument to the actual build' diff --git a/src/wasix/runtime/crates/assets/Cargo.toml b/src/wasix/runtime/crates/assets/Cargo.toml index c91d03aa8..06ecd5da8 100644 --- a/src/wasix/runtime/crates/assets/Cargo.toml +++ b/src/wasix/runtime/crates/assets/Cargo.toml @@ -46,6 +46,7 @@ extension-pg-buffercache = [] extension-pg-freespacemap = [] extension-pg-hashids = [] extension-pg-ivm = [] +extension-pg-partman = [] extension-pg-surgery = [] extension-pg-textsearch = [] extension-pg-trgm = [] diff --git a/src/wasix/runtime/crates/assets/build-support.rs b/src/wasix/runtime/crates/assets/build-support.rs index e26af1d7b..337df4a00 100644 --- a/src/wasix/runtime/crates/assets/build-support.rs +++ b/src/wasix/runtime/crates/assets/build-support.rs @@ -331,6 +331,13 @@ const EXTENSION_PACKAGES: &[ExtensionPackage] = &[ sql_name: "pg_ivm", crate_ident: "oliphaunt_extension_pg_ivm", }, + ExtensionPackage { + feature: "extension-pg-partman", + env: "CARGO_FEATURE_EXTENSION_PG_PARTMAN", + product: "oliphaunt-extension-pg-partman", + sql_name: "pg_partman", + crate_ident: "oliphaunt_extension_pg_partman", + }, ExtensionPackage { feature: "extension-pg-textsearch", env: "CARGO_FEATURE_EXTENSION_PG_TEXTSEARCH", diff --git a/src/wasix/runtime/moon.yml b/src/wasix/runtime/moon.yml index e06430673..22388653a 100644 --- a/src/wasix/runtime/moon.yml +++ b/src/wasix/runtime/moon.yml @@ -107,10 +107,15 @@ tasks: tags: - quality - unit - script: "set -e\nbash src/wasix/runtime/tools/check-shim-abi.sh\nbash src/wasix/runtime/assets/build/docker/install-pinned-apt-packages.test.sh\nbash src/wasix/runtime/assets/build/docker/install-pinned-wasixcc.test.sh\n" + script: "set -e\nbash src/wasix/runtime/tools/check-shim-abi.sh\nbash src/wasix/runtime/assets/build/docker/install-pinned-apt-packages.test.sh\nbash src/wasix/runtime/assets/build/docker/install-pinned-wasixcc.test.sh\nbash src/wasix/runtime/assets/build/docker_pgxs_extensions.test.sh\n" inputs: - /tools/dev/acquisition.sh - assets/build/docker/**/* + - assets/build/docker_pgxs_extensions.sh + - assets/build/docker_pgxs_extensions.test.sh + - assets/build/wasix_third_party.sh + - assets/build/source_lane.sh + - /src/extensions/generated/pgxs-build.tsv - assets/build/wasix_shim/**/* - tools/check-shim-abi.sh options: diff --git a/src/wasix/runtime/tools/xtask/src/asset_pipeline.rs b/src/wasix/runtime/tools/xtask/src/asset_pipeline.rs index 90291e62e..62c188848 100644 --- a/src/wasix/runtime/tools/xtask/src/asset_pipeline.rs +++ b/src/wasix/runtime/tools/xtask/src/asset_pipeline.rs @@ -1706,6 +1706,16 @@ fn stage_pgxs_style_extension( ensure!(copied, "PGMQ build has no versioned SQL files"); return Ok(()); } + if sql_name == "pg_partman" { + // sql/ also contains source fragments: only ship the assembled install + // script and versioned updates, never the unexpanded @extschema@ pieces. + ensure!( + copy_extension_sql_files(&build_dir.join("sql"), sql_name, &extension_sql_dir)?, + "pg_partman generated install SQL is missing" + ); + copy_extension_sql_files(&source.join("updates"), sql_name, &extension_sql_dir)?; + return Ok(()); + } let mut copied_root_sql = copy_extension_sql_files(&build_dir, sql_name, &extension_sql_dir)?; if !copied_root_sql { copied_root_sql = copy_extension_sql_files(source, sql_name, &extension_sql_dir)?; @@ -2632,6 +2642,80 @@ mod tests { fs::remove_dir_all(root).unwrap(); } + #[test] + fn partman_staging_keeps_install_and_upgrade_sql_without_source_fragments() { + let root = temp_aot_manifest_path("partman-stage"); + let source = root.join("source"); + let build = root.join("build"); + let stage = root.join("stage"); + let built_sql = build.join("pgxs/pg_partman/sql"); + fs::create_dir_all(built_sql.join("functions")).unwrap(); + fs::create_dir_all(source.join("updates")).unwrap(); + fs::write( + source.join("pg_partman.control"), + "default_version = '5.5.0'\n", + ) + .unwrap(); + fs::write(built_sql.join("pg_partman--5.5.0.sql"), "install\n").unwrap(); + fs::write( + built_sql.join("functions/raw.sql"), + "@extschema@ fragment\n", + ) + .unwrap(); + fs::write( + source.join("updates/pg_partman--5.4.0--5.5.0.sql"), + "upgrade\n", + ) + .unwrap(); + fs::write(source.join("updates/unrelated.sql"), "excluded\n").unwrap(); + let extension = extension_catalog::ExtensionBuildSpec { + id: "pg_partman".to_owned(), + display_name: "pg_partman".to_owned(), + sql_name: "pg_partman".to_owned(), + build_kind: "pgxs-sql-only".to_owned(), + source_dir: source.to_string_lossy().into_owned(), + contrib_dir: None, + module_file: None, + archive: "extensions/pg_partman.tar.zst".to_owned(), + control_file: None, + native_support_modules: Vec::new(), + excluded_sql_extensions: Vec::new(), + staging: None, + lifecycle: extension_catalog::ExtensionLifecycle { + create_extension: true, + create_schema: Some("partman".to_owned()), + load_sql: Vec::new(), + post_create_sql: Vec::new(), + startup_config: Vec::new(), + preload_required: false, + restart_required: false, + shared_memory_required: false, + }, + }; + stage_pgxs_style_extension(&build, &extension, &stage).unwrap(); + let names = sorted_files(&stage) + .unwrap() + .into_iter() + .map(|file| { + file.strip_prefix(&stage) + .unwrap() + .to_string_lossy() + .replace('\\', "/") + }) + .collect::>(); + assert_eq!( + names, + vec![ + "share/postgresql/extension/pg_partman--5.4.0--5.5.0.sql", + "share/postgresql/extension/pg_partman--5.5.0.sql", + "share/postgresql/extension/pg_partman.control", + ] + ); + fs::remove_file(built_sql.join("pg_partman--5.5.0.sql")).unwrap(); + assert!(stage_pgxs_style_extension(&build, &extension, &root.join("missing")).is_err()); + fs::remove_dir_all(root).unwrap(); + } + fn manifest_extension_metadata( create_extension: bool, control_files: Vec<&str>, diff --git a/src/wasix/sdks/rust/Cargo.toml b/src/wasix/sdks/rust/Cargo.toml index a47f56288..9b0cc3426 100644 --- a/src/wasix/sdks/rust/Cargo.toml +++ b/src/wasix/sdks/rust/Cargo.toml @@ -62,6 +62,7 @@ extension-pg-buffercache = ["extensions", "liboliphaunt-wasix-portable/extension extension-pg-freespacemap = ["extensions", "liboliphaunt-wasix-portable/extension-pg-freespacemap"] extension-pg-hashids = ["extensions", "liboliphaunt-wasix-portable/extension-pg-hashids"] extension-pg-ivm = ["extensions", "liboliphaunt-wasix-portable/extension-pg-ivm"] +extension-pg-partman = ["extensions", "liboliphaunt-wasix-portable/extension-pg-partman"] extension-pg-surgery = ["extensions", "liboliphaunt-wasix-portable/extension-pg-surgery"] extension-pg-textsearch = ["extensions", "liboliphaunt-wasix-portable/extension-pg-textsearch"] extension-pg-trgm = ["extensions", "liboliphaunt-wasix-portable/extension-pg-trgm"] diff --git a/src/wasix/sdks/rust/src/oliphaunt/generated_extensions.rs b/src/wasix/sdks/rust/src/oliphaunt/generated_extensions.rs index f6a7da04b..323b548cd 100644 --- a/src/wasix/sdks/rust/src/oliphaunt/generated_extensions.rs +++ b/src/wasix/sdks/rust/src/oliphaunt/generated_extensions.rs @@ -262,6 +262,16 @@ const DEFINITION_PG_LOGICALINSPECT: Extension = Extension { package: None, }; +const DEFINITION_PG_PARTMAN: Extension = Extension { + sql_name: "pg_partman", + native_support_modules: &[], + native_module_file: None, + aot_name: None, + dependencies: &[], + startup_config: &[], + package: None, +}; + const DEFINITION_PG_STAT_STATEMENTS: Extension = Extension { sql_name: "pg_stat_statements", native_support_modules: &[], @@ -544,6 +554,9 @@ impl Extension { /// Select the `pg_logicalinspect` artifact. pub const PG_LOGICALINSPECT: Self = DEFINITION_PG_LOGICALINSPECT; + /// Select the `pg_partman` artifact. + + pub const PG_PARTMAN: Self = DEFINITION_PG_PARTMAN; /// Select the `pg_stat_statements` artifact. pub const PG_STAT_STATEMENTS: Self = DEFINITION_PG_STAT_STATEMENTS; @@ -633,6 +646,7 @@ impl Extension { Self::PG_HASHIDS, Self::PG_IVM, Self::PG_LOGICALINSPECT, + Self::PG_PARTMAN, Self::PG_STAT_STATEMENTS, Self::PG_SURGERY, Self::PG_TEXTSEARCH, @@ -711,6 +725,8 @@ pub(super) fn creates_database_object_for_test(extension: Extension) -> bool { "pg_logicalinspect" => true, + "pg_partman" => true, + "pg_stat_statements" => true, "pg_surgery" => true, @@ -838,6 +854,11 @@ pub(super) fn activation_sql_for_test(extension: Extension) -> &'static [&'stati &["CREATE EXTENSION IF NOT EXISTS \"pg_logicalinspect\" WITH SCHEMA \"pg_catalog\";"] } + "pg_partman" => &[ + "CREATE SCHEMA IF NOT EXISTS \"partman\";", + "CREATE EXTENSION IF NOT EXISTS \"pg_partman\" WITH SCHEMA \"partman\";", + ], + "pg_stat_statements" => &["CREATE EXTENSION IF NOT EXISTS \"pg_stat_statements\";"], "pg_surgery" => { From a9a2971b38a5be8c4c030c119f831a109c126300 Mon Sep 17 00:00:00 2001 From: Sid Jain Date: Mon, 19 Oct 2026 06:29:54 +0000 Subject: [PATCH 05/11] fix(wasix): register PGMQ artifact features --- src/wasix/runtime/crates/assets/Cargo.toml | 1 + src/wasix/runtime/crates/assets/build-support.rs | 7 +++++++ src/wasix/sdks/rust/Cargo.toml | 1 + 3 files changed, 9 insertions(+) diff --git a/src/wasix/runtime/crates/assets/Cargo.toml b/src/wasix/runtime/crates/assets/Cargo.toml index 06ecd5da8..6860938b7 100644 --- a/src/wasix/runtime/crates/assets/Cargo.toml +++ b/src/wasix/runtime/crates/assets/Cargo.toml @@ -54,6 +54,7 @@ extension-pg-uuidv7 = [] extension-pg-visibility = [] extension-pg-walinspect = [] extension-pgcrypto = [] +extension-pgmq = [] extension-pgtap = [] extension-postgis = [] extension-seg = [] diff --git a/src/wasix/runtime/crates/assets/build-support.rs b/src/wasix/runtime/crates/assets/build-support.rs index 337df4a00..032fdcffb 100644 --- a/src/wasix/runtime/crates/assets/build-support.rs +++ b/src/wasix/runtime/crates/assets/build-support.rs @@ -331,6 +331,13 @@ const EXTENSION_PACKAGES: &[ExtensionPackage] = &[ sql_name: "pg_ivm", crate_ident: "oliphaunt_extension_pg_ivm", }, + ExtensionPackage { + feature: "extension-pgmq", + env: "CARGO_FEATURE_EXTENSION_PGMQ", + product: "oliphaunt-extension-pgmq", + sql_name: "pgmq", + crate_ident: "oliphaunt_extension_pgmq", + }, ExtensionPackage { feature: "extension-pg-partman", env: "CARGO_FEATURE_EXTENSION_PG_PARTMAN", diff --git a/src/wasix/sdks/rust/Cargo.toml b/src/wasix/sdks/rust/Cargo.toml index 9b0cc3426..2fefc700f 100644 --- a/src/wasix/sdks/rust/Cargo.toml +++ b/src/wasix/sdks/rust/Cargo.toml @@ -70,6 +70,7 @@ extension-pg-uuidv7 = ["extensions", "liboliphaunt-wasix-portable/extension-pg-u extension-pg-visibility = ["extensions", "liboliphaunt-wasix-portable/extension-pg-visibility"] extension-pg-walinspect = ["extensions", "liboliphaunt-wasix-portable/extension-pg-walinspect"] extension-pgcrypto = ["extensions", "liboliphaunt-wasix-portable/extension-pgcrypto"] +extension-pgmq = ["extensions", "liboliphaunt-wasix-portable/extension-pgmq"] extension-pgtap = ["extensions", "liboliphaunt-wasix-portable/extension-pgtap"] extension-postgis = ["extensions", "liboliphaunt-wasix-portable/extension-postgis"] extension-seg = ["extensions", "liboliphaunt-wasix-portable/extension-seg"] From 977488cdf0bbc08b096a182d10714c71eb1d1e33 Mon Sep 17 00:00:00 2001 From: Sid Jain Date: Mon, 19 Oct 2026 06:28:11 +0000 Subject: [PATCH 06/11] feat(extensions): add contrib hooks and complete WASIX features --- .../src/generated/extension-smoke.ts | 20 ++- src/extensions/catalog/extensions.source.json | 50 ++++++++ src/extensions/contrib/postgres18.toml | 12 ++ src/extensions/evidence/matrix.toml | 18 +++ src/extensions/generated/contrib-build.tsv | 2 + .../generated/docs/extension-evidence.json | 72 ++++++++++- .../generated/extensions.catalog.json | 64 ++++++++++ .../generated/mobile/static-extensions.tsv | 2 + .../generated/mobile/static-registry.json | 14 +++ src/extensions/generated/sdk/extensions.json | 54 ++++++++- .../generated/wasix/extensions.json | 46 +++++++ .../runtime/bin/build-postgres18-linux.sh | 6 +- .../runtime/bin/build-postgres18-macos.sh | 6 +- .../rust-bindings/src/generated/extensions.rs | 36 ++++++ .../android/extension-legal-catalog.json | 114 +++++++++++++++++- .../oliphaunt/android/extensions.properties | 14 ++- .../dev/oliphaunt/GeneratedExtensions.kt | 2 + .../dev/oliphaunt/OliphauntExtension.kt | 2 + .../react-native/src/generated/extensions.ts | 50 +++++++- .../OliphauntCore/OliphauntExtension.swift | 2 + .../sdks/ts/src/generated/extensions.ts | 48 +++++++- src/test-fixtures/extensions/manifest.json | 2 + .../extensions/passwordcheck.sql | 20 +++ .../extensions/pg_overexplain.sql | 17 +++ .../runtime/assets/generated/wasix-dl.exports | 17 +++ src/wasix/runtime/crates/assets/Cargo.toml | 8 ++ .../runtime/crates/assets/build-support.rs | 56 +++++++++ ...iboliphaunt-wasix-cargo-artifacts.test.mts | 32 ++++- src/wasix/runtime/tools/test-packaging.sh | 10 +- .../tools/wasix-extension-features.test.mts | 30 ++++- src/wasix/sdks/rust/Cargo.toml | 8 ++ .../src/oliphaunt/generated_extensions.rs | 36 ++++++ 32 files changed, 851 insertions(+), 19 deletions(-) create mode 100644 src/test-fixtures/extensions/passwordcheck.sql create mode 100644 src/test-fixtures/extensions/pg_overexplain.sql diff --git a/src/examples/native/react-native-expo/src/generated/extension-smoke.ts b/src/examples/native/react-native-expo/src/generated/extension-smoke.ts index c8d68e705..be22d03f2 100644 --- a/src/examples/native/react-native-expo/src/generated/extension-smoke.ts +++ b/src/examples/native/react-native-expo/src/generated/extension-smoke.ts @@ -7,7 +7,7 @@ export type GeneratedMobileExtensionProof = { readonly selectedExtensionDependencies: readonly string[]; }; -export const GENERATED_MOBILE_EXTENSION_METADATA_SHA256 = "72b4266b1468babd53f59bbcf23d62520f5fb5454d35a07d4f482e0504868ac7" as const; +export const GENERATED_MOBILE_EXTENSION_METADATA_SHA256 = "2f9c13406ab3ce4f8f4f9fb419aeb8ad899e5bde59228215024933dad44c46fe" as const; export const GENERATED_MOBILE_EXTENSION_PLAN = [ { @@ -117,6 +117,11 @@ export const GENERATED_MOBILE_EXTENSION_PLAN = [ "createsExtension": true, "selectedExtensionDependencies": [] }, + { + "sqlName": "passwordcheck", + "createsExtension": false, + "selectedExtensionDependencies": [] + }, { "sqlName": "pg_buffercache", "createsExtension": true, @@ -142,6 +147,11 @@ export const GENERATED_MOBILE_EXTENSION_PLAN = [ "createsExtension": true, "selectedExtensionDependencies": [] }, + { + "sqlName": "pg_overexplain", + "createsExtension": false, + "selectedExtensionDependencies": [] + }, { "sqlName": "pg_partman", "createsExtension": true, @@ -355,6 +365,10 @@ export const GENERATED_MOBILE_EXTENSION_SMOKE = { "INSERT INTO oliphaunt_pageinspect SELECT generate_series(1, 5);", "SELECT * FROM page_header(get_raw_page('oliphaunt_pageinspect', 0));" ], + "passwordcheck": [ + "-- oliphaunt-verify\nLOAD 'passwordcheck';", + "-- oliphaunt-verify\nDO $oliphaunt$\nBEGIN\n CREATE ROLE oliphaunt_passwordcheck_probe;\n BEGIN\n ALTER ROLE oliphaunt_passwordcheck_probe PASSWORD 'short';\n RAISE EXCEPTION 'passwordcheck accepted a short password';\n EXCEPTION WHEN invalid_parameter_value THEN\n IF SQLERRM <> 'password is too short' THEN\n RAISE;\n END IF;\n END;\n ALTER ROLE oliphaunt_passwordcheck_probe PASSWORD 'a_nice_long_password';\n DROP ROLE oliphaunt_passwordcheck_probe;\nEND\n$oliphaunt$;" + ], "pg_buffercache": [ "SELECT * FROM pg_buffercache_summary();", "SELECT * FROM pg_buffercache_usage_counts();" @@ -382,6 +396,10 @@ export const GENERATED_MOBILE_EXTENSION_SMOKE = { "pg_logicalinspect": [ "-- Exercise both entry points without requiring a logical replication slot.\n-- Invalid snapshot names must be rejected before any filesystem access.\n-- oliphaunt-verify\nDO $oliphaunt$\nBEGIN\n BEGIN\n PERFORM pg_get_logical_snapshot_meta('../invalid');\n RAISE EXCEPTION 'pg_logicalinspect accepted an invalid snapshot name';\n EXCEPTION WHEN internal_error THEN\n IF SQLERRM <> 'invalid snapshot file name \"../invalid\"' THEN\n RAISE;\n END IF;\n END;\n BEGIN\n PERFORM pg_get_logical_snapshot_info('../invalid');\n RAISE EXCEPTION 'pg_logicalinspect accepted an invalid snapshot name';\n EXCEPTION WHEN internal_error THEN\n IF SQLERRM <> 'invalid snapshot file name \"../invalid\"' THEN\n RAISE;\n END IF;\n END;\nEND\n$oliphaunt$;" ], + "pg_overexplain": [ + "-- oliphaunt-verify\nLOAD 'pg_overexplain';", + "-- oliphaunt-verify\nDO $oliphaunt$\nDECLARE\n document jsonb;\nBEGIN\n EXECUTE 'EXPLAIN (DEBUG, RANGE_TABLE, FORMAT JSON, COSTS OFF) SELECT oid FROM pg_class WHERE relname = ''pg_class'''\n INTO document;\n IF (document->0->'Plan' ? 'Plan Node ID') IS DISTINCT FROM true\n OR COALESCE(jsonb_array_length(document->0->'Range Table'), 0) < 1 THEN\n RAISE EXCEPTION 'pg_overexplain did not include plan IDs and the range table: %', document;\n END IF;\nEND\n$oliphaunt$;" + ], "pg_partman": [ "SELECT set_config('search_path', quote_ident(n.nspname) || ', public', false)\nFROM pg_extension e JOIN pg_namespace n ON n.oid = e.extnamespace\nWHERE e.extname = 'pg_partman';", "CREATE TABLE public.oliphaunt_partman_events (id bigint NOT NULL, payload text)\nPARTITION BY RANGE (id);", diff --git a/src/extensions/catalog/extensions.source.json b/src/extensions/catalog/extensions.source.json index c1f0ffdc9..9506717d5 100644 --- a/src/extensions/catalog/extensions.source.json +++ b/src/extensions/catalog/extensions.source.json @@ -682,6 +682,32 @@ "native-module-file": "pageinspect.so", "notes": [] }, + { + "id": "passwordcheck", + "sql-name": "passwordcheck", + "rust-constant": "PASSWORDCHECK", + "display-name": "passwordcheck", + "source-kind": "postgres-contrib", + "upstream-import-name": "passwordcheck", + "package-export": "./contrib/passwordcheck", + "tags": ["postgres extension", "postgres/contrib"], + "dependencies": [], + "load-order": [], + "lifecycle": { + "create-extension": false, + "load-sql": ["LOAD 'passwordcheck';"], + "post-create-sql": [], + "startup-config": [], + "preload-required": false, + "restart-required": false, + "shared-memory-required": false + }, + "tests": ["src/test-fixtures/extensions/passwordcheck.sql"], + "native-module-file": "passwordcheck.so", + "notes": [ + "LOAD enables password checks for the current session. Use shared_preload_libraries to enforce checks across postmaster sessions." + ] + }, { "id": "pg_buffercache", "sql-name": "pg_buffercache", @@ -846,6 +872,30 @@ "native-module-file": "pg_logicalinspect.so", "notes": [] }, + { + "id": "pg_overexplain", + "sql-name": "pg_overexplain", + "rust-constant": "PG_OVEREXPLAIN", + "display-name": "pg_overexplain", + "source-kind": "postgres-contrib", + "upstream-import-name": "pg_overexplain", + "package-export": "./contrib/pg_overexplain", + "tags": ["postgres extension", "postgres/contrib"], + "dependencies": [], + "load-order": [], + "lifecycle": { + "create-extension": false, + "load-sql": ["LOAD 'pg_overexplain';"], + "post-create-sql": [], + "startup-config": [], + "preload-required": false, + "restart-required": false, + "shared-memory-required": false + }, + "tests": ["src/test-fixtures/extensions/pg_overexplain.sql"], + "native-module-file": "pg_overexplain.so", + "notes": [] + }, { "id": "pg_stat_statements", "sql-name": "pg_stat_statements", diff --git a/src/extensions/contrib/postgres18.toml b/src/extensions/contrib/postgres18.toml index b3aeaa13b..c0493bb2d 100644 --- a/src/extensions/contrib/postgres18.toml +++ b/src/extensions/contrib/postgres18.toml @@ -153,6 +153,12 @@ contrib-dir = "pageinspect" module-file = "pageinspect.so" default-version = "1.13" +[[extensions]] +id = "passwordcheck" +sql-name = "passwordcheck" +contrib-dir = "passwordcheck" +module-file = "passwordcheck.so" + [[extensions]] id = "pg_buffercache" sql-name = "pg_buffercache" @@ -174,6 +180,12 @@ contrib-dir = "pg_logicalinspect" module-file = "pg_logicalinspect.so" default-version = "1.0" +[[extensions]] +id = "pg_overexplain" +sql-name = "pg_overexplain" +contrib-dir = "pg_overexplain" +module-file = "pg_overexplain.so" + [[extensions]] id = "pg_stat_statements" sql-name = "pg_stat_statements" diff --git a/src/extensions/evidence/matrix.toml b/src/extensions/evidence/matrix.toml index 3e0911399..8b28b2dc8 100644 --- a/src/extensions/evidence/matrix.toml +++ b/src/extensions/evidence/matrix.toml @@ -87,11 +87,13 @@ source-digest-inputs = [ "src/test-fixtures/extensions/ltree.sql", "src/test-fixtures/extensions/moddatetime.sql", "src/test-fixtures/extensions/pageinspect.sql", + "src/test-fixtures/extensions/passwordcheck.sql", "src/test-fixtures/extensions/pg_buffercache.sql", "src/test-fixtures/extensions/pg_freespacemap.sql", "src/test-fixtures/extensions/pg_hashids.sql", "src/test-fixtures/extensions/pg_ivm.sql", "src/test-fixtures/extensions/pg_logicalinspect.sql", + "src/test-fixtures/extensions/pg_overexplain.sql", "src/test-fixtures/extensions/pg_partman.sql", "src/test-fixtures/extensions/pg_stat_statements.sql", "src/test-fixtures/extensions/pg_surgery.sql", @@ -283,6 +285,14 @@ platform-targets = ["portable"] runtime-modes = ["direct","server","restart","backup-restore","materialization"] evidence-required = ["wasix-full-lifecycle-v1"] +[[claims]] +extension = "passwordcheck" +postgres-major = 18 +artifact-family = "wasix-runtime" +platform-targets = ["portable"] +runtime-modes = ["direct","server","restart","backup-restore","materialization"] +evidence-required = ["wasix-full-lifecycle-v1"] + [[claims]] extension = "pg_buffercache" postgres-major = 18 @@ -323,6 +333,14 @@ platform-targets = ["portable"] runtime-modes = ["direct","server","restart","backup-restore","materialization"] evidence-required = ["wasix-full-lifecycle-v1"] +[[claims]] +extension = "pg_overexplain" +postgres-major = 18 +artifact-family = "wasix-runtime" +platform-targets = ["portable"] +runtime-modes = ["direct","server","restart","backup-restore","materialization"] +evidence-required = ["wasix-full-lifecycle-v1"] + [[claims]] extension = "pg_partman" postgres-major = 18 diff --git a/src/extensions/generated/contrib-build.tsv b/src/extensions/generated/contrib-build.tsv index e8223bebd..a8c3aa55e 100644 --- a/src/extensions/generated/contrib-build.tsv +++ b/src/extensions/generated/contrib-build.tsv @@ -20,9 +20,11 @@ lo lo lo lo.so extensions/lo.tar.zst ltree ltree ltree ltree.so extensions/ltree.tar.zst moddatetime moddatetime spi moddatetime.so extensions/moddatetime.tar.zst pageinspect pageinspect pageinspect pageinspect.so extensions/pageinspect.tar.zst +passwordcheck passwordcheck passwordcheck passwordcheck.so extensions/passwordcheck.tar.zst pg_buffercache pg_buffercache pg_buffercache pg_buffercache.so extensions/pg_buffercache.tar.zst pg_freespacemap pg_freespacemap pg_freespacemap pg_freespacemap.so extensions/pg_freespacemap.tar.zst pg_logicalinspect pg_logicalinspect pg_logicalinspect pg_logicalinspect.so extensions/pg_logicalinspect.tar.zst +pg_overexplain pg_overexplain pg_overexplain pg_overexplain.so extensions/pg_overexplain.tar.zst pg_stat_statements pg_stat_statements pg_stat_statements pg_stat_statements.so extensions/pg_stat_statements.tar.zst pg_surgery pg_surgery pg_surgery pg_surgery.so extensions/pg_surgery.tar.zst pg_trgm pg_trgm pg_trgm pg_trgm.so extensions/pg_trgm.tar.zst diff --git a/src/extensions/generated/docs/extension-evidence.json b/src/extensions/generated/docs/extension-evidence.json index eceb29525..547ac251a 100644 --- a/src/extensions/generated/docs/extension-evidence.json +++ b/src/extensions/generated/docs/extension-evidence.json @@ -714,6 +714,40 @@ ], "sql-name": "pageinspect" }, + { + "artifact-family": "wasix-runtime", + "evidence-required": [ + "wasix-full-lifecycle-v1" + ], + "extension": "passwordcheck", + "latest-accepted-evidence": [], + "missing-current-evidence": [ + { + "artifact-family": "wasix-runtime", + "evidence-tier": "wasix-full-lifecycle-v1", + "platform-target": "portable", + "runtime-modes": [ + "direct", + "server", + "restart", + "backup-restore", + "materialization" + ] + } + ], + "platform-targets": [ + "portable" + ], + "postgres-major": 18, + "runtime-modes": [ + "direct", + "server", + "restart", + "backup-restore", + "materialization" + ], + "sql-name": "passwordcheck" + }, { "artifact-family": "wasix-runtime", "evidence-required": [ @@ -884,6 +918,40 @@ ], "sql-name": "pg_logicalinspect" }, + { + "artifact-family": "wasix-runtime", + "evidence-required": [ + "wasix-full-lifecycle-v1" + ], + "extension": "pg_overexplain", + "latest-accepted-evidence": [], + "missing-current-evidence": [ + { + "artifact-family": "wasix-runtime", + "evidence-tier": "wasix-full-lifecycle-v1", + "platform-target": "portable", + "runtime-modes": [ + "direct", + "server", + "restart", + "backup-restore", + "materialization" + ] + } + ], + "platform-targets": [ + "portable" + ], + "postgres-major": 18, + "runtime-modes": [ + "direct", + "server", + "restart", + "backup-restore", + "materialization" + ], + "sql-name": "pg_overexplain" + }, { "artifact-family": "wasix-runtime", "evidence-required": [ @@ -1618,7 +1686,7 @@ "collector": "src/extensions/tools/collect-wasix-evidence.sh", "kind": "exact-sha-ci" }, - "source-digest": "sha256:5519c1a61255d31585b62a63fd3cf7450aad6fae54553f544631c55e131e8335", + "source-digest": "sha256:3ebd072c4dbba4aaf1a3cc73b8f299eb2e3e1df6a29e80a1dd6f670a5e9da106", "source-digest-inputs": [ "src/third-party/postgres/source.toml", "src/extensions/catalog/extensions.source.json", @@ -1707,11 +1775,13 @@ "src/test-fixtures/extensions/ltree.sql", "src/test-fixtures/extensions/moddatetime.sql", "src/test-fixtures/extensions/pageinspect.sql", + "src/test-fixtures/extensions/passwordcheck.sql", "src/test-fixtures/extensions/pg_buffercache.sql", "src/test-fixtures/extensions/pg_freespacemap.sql", "src/test-fixtures/extensions/pg_hashids.sql", "src/test-fixtures/extensions/pg_ivm.sql", "src/test-fixtures/extensions/pg_logicalinspect.sql", + "src/test-fixtures/extensions/pg_overexplain.sql", "src/test-fixtures/extensions/pg_partman.sql", "src/test-fixtures/extensions/pg_stat_statements.sql", "src/test-fixtures/extensions/pg_surgery.sql", diff --git a/src/extensions/generated/extensions.catalog.json b/src/extensions/generated/extensions.catalog.json index d57d22162..a6853fb51 100644 --- a/src/extensions/generated/extensions.catalog.json +++ b/src/extensions/generated/extensions.catalog.json @@ -815,6 +815,39 @@ "native-module-file": "pageinspect.so", "notes": [] }, + { + "id": "passwordcheck", + "sql-name": "passwordcheck", + "rust-constant": "PASSWORDCHECK", + "display-name": "passwordcheck", + "source-kind": "postgres-contrib", + "upstream-import-name": "passwordcheck", + "package-export": "./contrib/passwordcheck", + "tags": [ + "postgres extension", + "postgres/contrib" + ], + "dependencies": [], + "load-order": [], + "lifecycle": { + "create-extension": false, + "load-sql": [ + "LOAD 'passwordcheck';" + ], + "post-create-sql": [], + "startup-config": [], + "preload-required": false, + "restart-required": false, + "shared-memory-required": false + }, + "tests": [ + "src/test-fixtures/extensions/passwordcheck.sql" + ], + "native-module-file": "passwordcheck.so", + "notes": [ + "LOAD enables password checks for the current session. Use shared_preload_libraries to enforce checks across postmaster sessions." + ] + }, { "id": "pg_buffercache", "sql-name": "pg_buffercache", @@ -1003,6 +1036,37 @@ "native-module-file": "pg_logicalinspect.so", "notes": [] }, + { + "id": "pg_overexplain", + "sql-name": "pg_overexplain", + "rust-constant": "PG_OVEREXPLAIN", + "display-name": "pg_overexplain", + "source-kind": "postgres-contrib", + "upstream-import-name": "pg_overexplain", + "package-export": "./contrib/pg_overexplain", + "tags": [ + "postgres extension", + "postgres/contrib" + ], + "dependencies": [], + "load-order": [], + "lifecycle": { + "create-extension": false, + "load-sql": [ + "LOAD 'pg_overexplain';" + ], + "post-create-sql": [], + "startup-config": [], + "preload-required": false, + "restart-required": false, + "shared-memory-required": false + }, + "tests": [ + "src/test-fixtures/extensions/pg_overexplain.sql" + ], + "native-module-file": "pg_overexplain.so", + "notes": [] + }, { "id": "pg_partman", "sql-name": "pg_partman", diff --git a/src/extensions/generated/mobile/static-extensions.tsv b/src/extensions/generated/mobile/static-extensions.tsv index e362da3e3..af500aaaa 100644 --- a/src/extensions/generated/mobile/static-extensions.tsv +++ b/src/extensions/generated/mobile/static-extensions.tsv @@ -21,11 +21,13 @@ lo lo contrib contrib/lo ltree ltree contrib contrib/ltree moddatetime moddatetime contrib contrib/spi moddatetime.c pageinspect pageinspect contrib contrib/pageinspect +passwordcheck passwordcheck contrib contrib/passwordcheck pg_buffercache pg_buffercache contrib contrib/pg_buffercache pg_freespacemap pg_freespacemap contrib contrib/pg_freespacemap pg_hashids pg_hashids external target/oliphaunt-sources/checkouts/pg_hashids pg_ivm pg_ivm external target/oliphaunt-sources/checkouts/pg_ivm createas.c,matview.c,pg_ivm.c,ruleutils.c,subselect.c pg_logicalinspect pg_logicalinspect contrib contrib/pg_logicalinspect +pg_overexplain pg_overexplain contrib contrib/pg_overexplain pg_stat_statements pg_stat_statements contrib contrib/pg_stat_statements pg_surgery pg_surgery contrib contrib/pg_surgery pg_textsearch pg_textsearch external target/oliphaunt-sources/checkouts/pg_textsearch source:src -DPG_TEXTSEARCH_VERSION="0.6.1" src diff --git a/src/extensions/generated/mobile/static-registry.json b/src/extensions/generated/mobile/static-registry.json index 57394a0e9..6741a89bf 100644 --- a/src/extensions/generated/mobile/static-registry.json +++ b/src/extensions/generated/mobile/static-registry.json @@ -160,6 +160,13 @@ "sql-name": "pageinspect", "static-registry-required": true }, + { + "data-files": [], + "id": "passwordcheck", + "native-module-stem": "passwordcheck", + "sql-name": "passwordcheck", + "static-registry-required": true + }, { "data-files": [], "id": "pg_buffercache", @@ -195,6 +202,13 @@ "sql-name": "pg_logicalinspect", "static-registry-required": true }, + { + "data-files": [], + "id": "pg_overexplain", + "native-module-stem": "pg_overexplain", + "sql-name": "pg_overexplain", + "static-registry-required": true + }, { "data-files": [], "id": "pg_stat_statements", diff --git a/src/extensions/generated/sdk/extensions.json b/src/extensions/generated/sdk/extensions.json index 95a57b1d5..01b3e6f72 100644 --- a/src/extensions/generated/sdk/extensions.json +++ b/src/extensions/generated/sdk/extensions.json @@ -1,5 +1,5 @@ { - "extension-catalog-sha256": "72b4266b1468babd53f59bbcf23d62520f5fb5454d35a07d4f482e0504868ac7", + "extension-catalog-sha256": "2f9c13406ab3ce4f8f4f9fb419aeb8ad899e5bde59228215024933dad44c46fe", "extensions": [ { "artifact-product": "oliphaunt-extension-contrib-pg18", @@ -555,6 +555,32 @@ "source-kind": "postgres-contrib", "sql-name": "pageinspect" }, + { + "artifact-product": "oliphaunt-extension-contrib-pg18", + "cargo-package": "oliphaunt-extension-contrib-pg18", + "creates-extension": false, + "data-files": [], + "dependencies": [], + "display-name": "passwordcheck", + "extension-sql-file-names": [], + "extension-sql-file-prefixes": [], + "id": "passwordcheck", + "maven-artifact": "oliphaunt-extension-contrib-pg18", + "maven-group": "dev.oliphaunt.extensions", + "native-component-requirements": [], + "native-components": [], + "native-module-stem": "passwordcheck", + "npm-package": "@oliphaunt/extension-contrib-pg18", + "postgres-major": 18, + "release-product": "liboliphaunt-native", + "runtime-bound": true, + "runtime-environment": [], + "runtime-share-data-files": [], + "selected-extension-dependencies": [], + "shared-preload-libraries": [], + "source-kind": "postgres-contrib", + "sql-name": "passwordcheck" + }, { "artifact-product": "oliphaunt-extension-contrib-pg18", "cargo-package": "oliphaunt-extension-contrib-pg18", @@ -685,6 +711,32 @@ "source-kind": "postgres-contrib", "sql-name": "pg_logicalinspect" }, + { + "artifact-product": "oliphaunt-extension-contrib-pg18", + "cargo-package": "oliphaunt-extension-contrib-pg18", + "creates-extension": false, + "data-files": [], + "dependencies": [], + "display-name": "pg_overexplain", + "extension-sql-file-names": [], + "extension-sql-file-prefixes": [], + "id": "pg_overexplain", + "maven-artifact": "oliphaunt-extension-contrib-pg18", + "maven-group": "dev.oliphaunt.extensions", + "native-component-requirements": [], + "native-components": [], + "native-module-stem": "pg_overexplain", + "npm-package": "@oliphaunt/extension-contrib-pg18", + "postgres-major": 18, + "release-product": "liboliphaunt-native", + "runtime-bound": true, + "runtime-environment": [], + "runtime-share-data-files": [], + "selected-extension-dependencies": [], + "shared-preload-libraries": [], + "source-kind": "postgres-contrib", + "sql-name": "pg_overexplain" + }, { "artifact-product": "oliphaunt-extension-pg-partman", "cargo-package": "oliphaunt-extension-pg-partman", diff --git a/src/extensions/generated/wasix/extensions.json b/src/extensions/generated/wasix/extensions.json index c9d416e26..952b99967 100644 --- a/src/extensions/generated/wasix/extensions.json +++ b/src/extensions/generated/wasix/extensions.json @@ -468,6 +468,29 @@ "native-support-modules": [], "sql-name": "pageinspect" }, + { + "archive": "extensions/passwordcheck.tar.zst", + "dependencies": [], + "id": "passwordcheck", + "lifecycle": { + "create-extension": false, + "load-sql": [ + "LOAD 'passwordcheck';" + ], + "post-create-sql": [], + "preload-required": false, + "restart-required": false, + "shared-memory-required": false, + "startup-config": [] + }, + "load-order": [], + "native-components": [], + "native-link-units": [], + "native-module-file": "passwordcheck.so", + "native-runtime-files": [], + "native-support-modules": [], + "sql-name": "passwordcheck" + }, { "archive": "extensions/pg_buffercache.tar.zst", "dependencies": [], @@ -578,6 +601,29 @@ "native-support-modules": [], "sql-name": "pg_logicalinspect" }, + { + "archive": "extensions/pg_overexplain.tar.zst", + "dependencies": [], + "id": "pg_overexplain", + "lifecycle": { + "create-extension": false, + "load-sql": [ + "LOAD 'pg_overexplain';" + ], + "post-create-sql": [], + "preload-required": false, + "restart-required": false, + "shared-memory-required": false, + "startup-config": [] + }, + "load-order": [], + "native-components": [], + "native-link-units": [], + "native-module-file": "pg_overexplain.so", + "native-runtime-files": [], + "native-support-modules": [], + "sql-name": "pg_overexplain" + }, { "archive": "extensions/pg_partman.tar.zst", "dependencies": [ diff --git a/src/native/runtime/bin/build-postgres18-linux.sh b/src/native/runtime/bin/build-postgres18-linux.sh index 74f64a600..efd354a88 100755 --- a/src/native/runtime/bin/build-postgres18-linux.sh +++ b/src/native/runtime/bin/build-postgres18-linux.sh @@ -104,9 +104,11 @@ contrib_extensions=( lo ltree pageinspect + passwordcheck pg_buffercache pg_freespacemap pg_logicalinspect + pg_overexplain pg_stat_statements pg_surgery pg_trgm @@ -206,11 +208,13 @@ required_extension_modules=( ltree moddatetime pageinspect + passwordcheck pg_buffercache pg_freespacemap pg_hashids pg_ivm pg_logicalinspect + pg_overexplain pg_stat_statements pg_surgery pg_textsearch @@ -246,7 +250,7 @@ native_extensions_include_postgis() { native_extension_has_control_artifacts() { case "$1" in - auto_explain) return 1 ;; + auto_explain|passwordcheck|pg_overexplain) return 1 ;; *) return 0 ;; esac } diff --git a/src/native/runtime/bin/build-postgres18-macos.sh b/src/native/runtime/bin/build-postgres18-macos.sh index 052624985..bd051ed16 100755 --- a/src/native/runtime/bin/build-postgres18-macos.sh +++ b/src/native/runtime/bin/build-postgres18-macos.sh @@ -88,9 +88,11 @@ contrib_extensions=( lo ltree pageinspect + passwordcheck pg_buffercache pg_freespacemap pg_logicalinspect + pg_overexplain pg_stat_statements pg_surgery pg_trgm @@ -190,11 +192,13 @@ required_extension_modules=( ltree moddatetime pageinspect + passwordcheck pg_buffercache pg_freespacemap pg_hashids pg_ivm pg_logicalinspect + pg_overexplain pg_stat_statements pg_surgery pg_textsearch @@ -230,7 +234,7 @@ native_extensions_include_postgis() { native_extension_has_control_artifacts() { case "$1" in - auto_explain) return 1 ;; + auto_explain|passwordcheck|pg_overexplain) return 1 ;; *) return 0 ;; esac } diff --git a/src/native/rust-bindings/src/generated/extensions.rs b/src/native/rust-bindings/src/generated/extensions.rs index 786fa383c..16ec08fd9 100644 --- a/src/native/rust-bindings/src/generated/extensions.rs +++ b/src/native/rust-bindings/src/generated/extensions.rs @@ -54,6 +54,8 @@ enum ExtensionId { Moddatetime, /// PostgreSQL `pageinspect`. Pageinspect, + /// PostgreSQL `passwordcheck`. + Passwordcheck, /// PostgreSQL `pg_buffercache`. PgBuffercache, /// PostgreSQL `pg_freespacemap`. @@ -64,6 +66,8 @@ enum ExtensionId { PgIvm, /// PostgreSQL `pg_logicalinspect`. PgLogicalinspect, + /// PostgreSQL `pg_overexplain`. + PgOverexplain, /// PostgreSQL `pg_partman`. PgPartman, /// PostgreSQL `pg_stat_statements`. @@ -214,6 +218,11 @@ impl Extension { id: ExtensionId::Pageinspect, package: None, }; + /// Select the `passwordcheck` artifact. + pub const PASSWORDCHECK: Self = Self { + id: ExtensionId::Passwordcheck, + package: None, + }; /// Select the `pg_buffercache` artifact. pub const PG_BUFFERCACHE: Self = Self { id: ExtensionId::PgBuffercache, @@ -239,6 +248,11 @@ impl Extension { id: ExtensionId::PgLogicalinspect, package: None, }; + /// Select the `pg_overexplain` artifact. + pub const PG_OVEREXPLAIN: Self = Self { + id: ExtensionId::PgOverexplain, + package: None, + }; /// Select the `pg_partman` artifact. pub const PG_PARTMAN: Self = Self { id: ExtensionId::PgPartman, @@ -368,11 +382,13 @@ impl Extension { Extension::LTREE, Extension::MODDATETIME, Extension::PAGEINSPECT, + Extension::PASSWORDCHECK, Extension::PG_BUFFERCACHE, Extension::PG_FREESPACEMAP, Extension::PG_HASHIDS, Extension::PG_IVM, Extension::PG_LOGICALINSPECT, + Extension::PG_OVEREXPLAIN, Extension::PG_PARTMAN, Extension::PG_STAT_STATEMENTS, Extension::PG_SURGERY, @@ -421,11 +437,13 @@ pub(super) const fn sql_name(extension: Extension) -> &'static str { ExtensionId::Ltree => "ltree", ExtensionId::Moddatetime => "moddatetime", ExtensionId::Pageinspect => "pageinspect", + ExtensionId::Passwordcheck => "passwordcheck", ExtensionId::PgBuffercache => "pg_buffercache", ExtensionId::PgFreespacemap => "pg_freespacemap", ExtensionId::PgHashids => "pg_hashids", ExtensionId::PgIvm => "pg_ivm", ExtensionId::PgLogicalinspect => "pg_logicalinspect", + ExtensionId::PgOverexplain => "pg_overexplain", ExtensionId::PgPartman => "pg_partman", ExtensionId::PgStatStatements => "pg_stat_statements", ExtensionId::PgSurgery => "pg_surgery", @@ -474,11 +492,13 @@ pub(super) const fn artifact_product(extension: Extension) -> &'static str { ExtensionId::Ltree => "oliphaunt-extension-contrib-pg18", ExtensionId::Moddatetime => "oliphaunt-extension-contrib-pg18", ExtensionId::Pageinspect => "oliphaunt-extension-contrib-pg18", + ExtensionId::Passwordcheck => "oliphaunt-extension-contrib-pg18", ExtensionId::PgBuffercache => "oliphaunt-extension-contrib-pg18", ExtensionId::PgFreespacemap => "oliphaunt-extension-contrib-pg18", ExtensionId::PgHashids => "oliphaunt-extension-pg-hashids", ExtensionId::PgIvm => "oliphaunt-extension-pg-ivm", ExtensionId::PgLogicalinspect => "oliphaunt-extension-contrib-pg18", + ExtensionId::PgOverexplain => "oliphaunt-extension-contrib-pg18", ExtensionId::PgPartman => "oliphaunt-extension-pg-partman", ExtensionId::PgStatStatements => "oliphaunt-extension-contrib-pg18", ExtensionId::PgSurgery => "oliphaunt-extension-contrib-pg18", @@ -527,11 +547,13 @@ pub(super) const fn native_module_stem(extension: Extension) -> Option<&'static ExtensionId::Ltree => Some("ltree"), ExtensionId::Moddatetime => Some("moddatetime"), ExtensionId::Pageinspect => Some("pageinspect"), + ExtensionId::Passwordcheck => Some("passwordcheck"), ExtensionId::PgBuffercache => Some("pg_buffercache"), ExtensionId::PgFreespacemap => Some("pg_freespacemap"), ExtensionId::PgHashids => Some("pg_hashids"), ExtensionId::PgIvm => Some("pg_ivm"), ExtensionId::PgLogicalinspect => Some("pg_logicalinspect"), + ExtensionId::PgOverexplain => Some("pg_overexplain"), ExtensionId::PgPartman => None, ExtensionId::PgStatStatements => Some("pg_stat_statements"), ExtensionId::PgSurgery => Some("pg_surgery"), @@ -580,11 +602,13 @@ pub(super) const fn creates_extension(extension: Extension) -> bool { ExtensionId::Ltree => true, ExtensionId::Moddatetime => true, ExtensionId::Pageinspect => true, + ExtensionId::Passwordcheck => false, ExtensionId::PgBuffercache => true, ExtensionId::PgFreespacemap => true, ExtensionId::PgHashids => true, ExtensionId::PgIvm => true, ExtensionId::PgLogicalinspect => true, + ExtensionId::PgOverexplain => false, ExtensionId::PgPartman => true, ExtensionId::PgStatStatements => true, ExtensionId::PgSurgery => true, @@ -633,11 +657,13 @@ pub(super) const fn dependencies(extension: Extension) -> &'static [Extension] { ExtensionId::Ltree => &[], ExtensionId::Moddatetime => &[], ExtensionId::Pageinspect => &[], + ExtensionId::Passwordcheck => &[], ExtensionId::PgBuffercache => &[], ExtensionId::PgFreespacemap => &[], ExtensionId::PgHashids => &[], ExtensionId::PgIvm => &[], ExtensionId::PgLogicalinspect => &[], + ExtensionId::PgOverexplain => &[], ExtensionId::PgPartman => &[], ExtensionId::PgStatStatements => &[], ExtensionId::PgSurgery => &[], @@ -686,11 +712,13 @@ pub(super) const fn required_shared_preload_library(extension: Extension) -> Opt ExtensionId::Ltree => None, ExtensionId::Moddatetime => None, ExtensionId::Pageinspect => None, + ExtensionId::Passwordcheck => None, ExtensionId::PgBuffercache => None, ExtensionId::PgFreespacemap => None, ExtensionId::PgHashids => None, ExtensionId::PgIvm => None, ExtensionId::PgLogicalinspect => None, + ExtensionId::PgOverexplain => None, ExtensionId::PgPartman => None, ExtensionId::PgStatStatements => Some("pg_stat_statements"), ExtensionId::PgSurgery => None, @@ -739,11 +767,13 @@ pub(super) const fn extension_data_files(extension: Extension) -> &'static [&'st ExtensionId::Ltree => &[], ExtensionId::Moddatetime => &[], ExtensionId::Pageinspect => &[], + ExtensionId::Passwordcheck => &[], ExtensionId::PgBuffercache => &[], ExtensionId::PgFreespacemap => &[], ExtensionId::PgHashids => &[], ExtensionId::PgIvm => &[], ExtensionId::PgLogicalinspect => &[], + ExtensionId::PgOverexplain => &[], ExtensionId::PgPartman => &[], ExtensionId::PgStatStatements => &[], ExtensionId::PgSurgery => &[], @@ -802,11 +832,13 @@ pub(super) const fn extension_sql_file_prefixes(extension: Extension) -> &'stati ExtensionId::Ltree => &[], ExtensionId::Moddatetime => &[], ExtensionId::Pageinspect => &[], + ExtensionId::Passwordcheck => &[], ExtensionId::PgBuffercache => &[], ExtensionId::PgFreespacemap => &[], ExtensionId::PgHashids => &[], ExtensionId::PgIvm => &[], ExtensionId::PgLogicalinspect => &[], + ExtensionId::PgOverexplain => &[], ExtensionId::PgPartman => &[], ExtensionId::PgStatStatements => &[], ExtensionId::PgSurgery => &[], @@ -859,11 +891,13 @@ pub(super) const fn extension_sql_file_names(extension: Extension) -> &'static [ ExtensionId::Ltree => &[], ExtensionId::Moddatetime => &[], ExtensionId::Pageinspect => &[], + ExtensionId::Passwordcheck => &[], ExtensionId::PgBuffercache => &[], ExtensionId::PgFreespacemap => &[], ExtensionId::PgHashids => &[], ExtensionId::PgIvm => &[], ExtensionId::PgLogicalinspect => &[], + ExtensionId::PgOverexplain => &[], ExtensionId::PgPartman => &[], ExtensionId::PgStatStatements => &[], ExtensionId::PgSurgery => &[], @@ -914,11 +948,13 @@ pub(super) const fn runtime_environment( ExtensionId::Ltree => &[], ExtensionId::Moddatetime => &[], ExtensionId::Pageinspect => &[], + ExtensionId::Passwordcheck => &[], ExtensionId::PgBuffercache => &[], ExtensionId::PgFreespacemap => &[], ExtensionId::PgHashids => &[], ExtensionId::PgIvm => &[], ExtensionId::PgLogicalinspect => &[], + ExtensionId::PgOverexplain => &[], ExtensionId::PgPartman => &[], ExtensionId::PgStatStatements => &[], ExtensionId::PgSurgery => &[], diff --git a/src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extension-legal-catalog.json b/src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extension-legal-catalog.json index 1c7004246..27fb8778c 100644 --- a/src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extension-legal-catalog.json +++ b/src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extension-legal-catalog.json @@ -1,6 +1,6 @@ { "schema": "oliphaunt-android-extension-legal-catalog-v1", - "sourceCatalogSha256": "72b4266b1468babd53f59bbcf23d62520f5fb5454d35a07d4f482e0504868ac7", + "sourceCatalogSha256": "2f9c13406ab3ce4f8f4f9fb419aeb8ad899e5bde59228215024933dad44c46fe", "contracts": [ { "scope": "aggregate", @@ -2010,6 +2010,62 @@ } ] }, + { + "scope": "leaf", + "identity": "passwordcheck", + "product": "oliphaunt-extension-contrib-pg18", + "target": "android-arm64-v8a", + "profile": "contrib-native", + "licenseFiles": [], + "members": [ + { + "path": "LICENSE", + "bytes": 1085, + "sha256": "6f8300e2f43c5a012d6f914fe5affa9090b97b0be39ddf3846f01b905edd8c10", + "mode": "0644" + }, + { + "path": "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT", + "bytes": 1198, + "sha256": "3d6af92ff8a4c2cdf69afb1cf44edea727922f5cd0cf8b5f72b11cdecac8fdfd", + "mode": "0644" + }, + { + "path": "THIRD_PARTY_NOTICES.md", + "bytes": 821, + "sha256": "20fd67487d1a631ba959cf7ec3fdbaf4977997ed624c0188dcb3c8870eded830", + "mode": "0644" + } + ] + }, + { + "scope": "leaf", + "identity": "passwordcheck", + "product": "oliphaunt-extension-contrib-pg18", + "target": "android-x86_64", + "profile": "contrib-native", + "licenseFiles": [], + "members": [ + { + "path": "LICENSE", + "bytes": 1085, + "sha256": "6f8300e2f43c5a012d6f914fe5affa9090b97b0be39ddf3846f01b905edd8c10", + "mode": "0644" + }, + { + "path": "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT", + "bytes": 1198, + "sha256": "3d6af92ff8a4c2cdf69afb1cf44edea727922f5cd0cf8b5f72b11cdecac8fdfd", + "mode": "0644" + }, + { + "path": "THIRD_PARTY_NOTICES.md", + "bytes": 821, + "sha256": "20fd67487d1a631ba959cf7ec3fdbaf4977997ed624c0188dcb3c8870eded830", + "mode": "0644" + } + ] + }, { "scope": "leaf", "identity": "pg_buffercache", @@ -2298,6 +2354,62 @@ } ] }, + { + "scope": "leaf", + "identity": "pg_overexplain", + "product": "oliphaunt-extension-contrib-pg18", + "target": "android-arm64-v8a", + "profile": "contrib-native", + "licenseFiles": [], + "members": [ + { + "path": "LICENSE", + "bytes": 1085, + "sha256": "6f8300e2f43c5a012d6f914fe5affa9090b97b0be39ddf3846f01b905edd8c10", + "mode": "0644" + }, + { + "path": "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT", + "bytes": 1198, + "sha256": "3d6af92ff8a4c2cdf69afb1cf44edea727922f5cd0cf8b5f72b11cdecac8fdfd", + "mode": "0644" + }, + { + "path": "THIRD_PARTY_NOTICES.md", + "bytes": 821, + "sha256": "20fd67487d1a631ba959cf7ec3fdbaf4977997ed624c0188dcb3c8870eded830", + "mode": "0644" + } + ] + }, + { + "scope": "leaf", + "identity": "pg_overexplain", + "product": "oliphaunt-extension-contrib-pg18", + "target": "android-x86_64", + "profile": "contrib-native", + "licenseFiles": [], + "members": [ + { + "path": "LICENSE", + "bytes": 1085, + "sha256": "6f8300e2f43c5a012d6f914fe5affa9090b97b0be39ddf3846f01b905edd8c10", + "mode": "0644" + }, + { + "path": "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT", + "bytes": 1198, + "sha256": "3d6af92ff8a4c2cdf69afb1cf44edea727922f5cd0cf8b5f72b11cdecac8fdfd", + "mode": "0644" + }, + { + "path": "THIRD_PARTY_NOTICES.md", + "bytes": 821, + "sha256": "20fd67487d1a631ba959cf7ec3fdbaf4977997ed624c0188dcb3c8870eded830", + "mode": "0644" + } + ] + }, { "scope": "leaf", "identity": "pg_partman", diff --git a/src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extensions.properties b/src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extensions.properties index 57693d1a0..cbcb220d0 100644 --- a/src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extensions.properties +++ b/src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extensions.properties @@ -1,7 +1,7 @@ # This file is generated by src/extensions/tools/check-extension-model.sh. # Do not edit by hand. schema=oliphaunt-android-extension-catalog-v2 -catalogSha256=72b4266b1468babd53f59bbcf23d62520f5fb5454d35a07d4f482e0504868ac7 +catalogSha256=2f9c13406ab3ce4f8f4f9fb419aeb8ad899e5bde59228215024933dad44c46fe extension.amcheck.artifactProduct=oliphaunt-extension-contrib-pg18 extension.amcheck.releaseProduct=liboliphaunt-native extension.amcheck.mavenGroup=dev.oliphaunt.extensions @@ -128,6 +128,12 @@ extension.pageinspect.mavenGroup=dev.oliphaunt.extensions extension.pageinspect.mavenArtifact=oliphaunt-extension-contrib-pg18 extension.pageinspect.runtimeBound=true extension.pageinspect.dependencies= +extension.passwordcheck.artifactProduct=oliphaunt-extension-contrib-pg18 +extension.passwordcheck.releaseProduct=liboliphaunt-native +extension.passwordcheck.mavenGroup=dev.oliphaunt.extensions +extension.passwordcheck.mavenArtifact=oliphaunt-extension-contrib-pg18 +extension.passwordcheck.runtimeBound=true +extension.passwordcheck.dependencies= extension.pg_buffercache.artifactProduct=oliphaunt-extension-contrib-pg18 extension.pg_buffercache.releaseProduct=liboliphaunt-native extension.pg_buffercache.mavenGroup=dev.oliphaunt.extensions @@ -158,6 +164,12 @@ extension.pg_logicalinspect.mavenGroup=dev.oliphaunt.extensions extension.pg_logicalinspect.mavenArtifact=oliphaunt-extension-contrib-pg18 extension.pg_logicalinspect.runtimeBound=true extension.pg_logicalinspect.dependencies= +extension.pg_overexplain.artifactProduct=oliphaunt-extension-contrib-pg18 +extension.pg_overexplain.releaseProduct=liboliphaunt-native +extension.pg_overexplain.mavenGroup=dev.oliphaunt.extensions +extension.pg_overexplain.mavenArtifact=oliphaunt-extension-contrib-pg18 +extension.pg_overexplain.runtimeBound=true +extension.pg_overexplain.dependencies= extension.pg_partman.artifactProduct=oliphaunt-extension-pg-partman extension.pg_partman.releaseProduct=oliphaunt-extension-pg-partman extension.pg_partman.mavenGroup=dev.oliphaunt.extensions diff --git a/src/native/sdks/kotlin/oliphaunt/src/commonMain/kotlin/dev/oliphaunt/GeneratedExtensions.kt b/src/native/sdks/kotlin/oliphaunt/src/commonMain/kotlin/dev/oliphaunt/GeneratedExtensions.kt index 638ce6c52..022d153fd 100644 --- a/src/native/sdks/kotlin/oliphaunt/src/commonMain/kotlin/dev/oliphaunt/GeneratedExtensions.kt +++ b/src/native/sdks/kotlin/oliphaunt/src/commonMain/kotlin/dev/oliphaunt/GeneratedExtensions.kt @@ -30,11 +30,13 @@ internal val generatedExtensionRuntimeContracts: Map 'password is too short' THEN + RAISE; + END IF; + END; + ALTER ROLE oliphaunt_passwordcheck_probe PASSWORD 'a_nice_long_password'; + DROP ROLE oliphaunt_passwordcheck_probe; +END +$oliphaunt$; diff --git a/src/test-fixtures/extensions/pg_overexplain.sql b/src/test-fixtures/extensions/pg_overexplain.sql new file mode 100644 index 000000000..a3b17b19b --- /dev/null +++ b/src/test-fixtures/extensions/pg_overexplain.sql @@ -0,0 +1,17 @@ +-- oliphaunt-verify +LOAD 'pg_overexplain'; + +-- oliphaunt-statement +-- oliphaunt-verify +DO $oliphaunt$ +DECLARE + document jsonb; +BEGIN + EXECUTE 'EXPLAIN (DEBUG, RANGE_TABLE, FORMAT JSON, COSTS OFF) SELECT oid FROM pg_class WHERE relname = ''pg_class''' + INTO document; + IF (document->0->'Plan' ? 'Plan Node ID') IS DISTINCT FROM true + OR COALESCE(jsonb_array_length(document->0->'Range Table'), 0) < 1 THEN + RAISE EXCEPTION 'pg_overexplain did not include plan IDs and the range table: %', document; + END IF; +END +$oliphaunt$; diff --git a/src/wasix/runtime/assets/generated/wasix-dl.exports b/src/wasix/runtime/assets/generated/wasix-dl.exports index 4854fadff..c5cafb3c8 100644 --- a/src/wasix/runtime/assets/generated/wasix-dl.exports +++ b/src/wasix/runtime/assets/generated/wasix-dl.exports @@ -113,12 +113,18 @@ ExecutorStart ExecutorStart_hook ExitParallelMode ExplainBeginOutput +ExplainCloseGroup ExplainEndOutput +ExplainIndentText +ExplainOpenGroup ExplainPrintJITSummary ExplainPrintPlan ExplainPrintTriggers +ExplainPropertyBool +ExplainPropertyFloat ExplainPropertyInteger ExplainPropertyText +ExplainPropertyUInteger ExplainQueryParameters ExplainQueryText ExprEvalPushStep @@ -155,12 +161,15 @@ GetDatabaseEncodingName GetDefaultCharSignedness GetDefaultOpClass GetErrorContextStack +GetExplainExtensionId +GetExplainExtensionState GetFlushRecPtr GetForeignColumnOptions GetForeignDataWrapper GetForeignServer GetForeignTable GetFreeIndexPage +GetLockmodeName GetMemoryChunkContext GetNamedLWLockTranche GetOldestNonRemovableTransactionId @@ -278,6 +287,7 @@ ReadNextMultiXactId RecentXmin RecordFreeIndexPage RecoveryInProgress +RegisterExtensionExplainOption RegisterSnapshot RegisterSubXactCallback RegisterXactCallback @@ -365,6 +375,7 @@ SearchSysCache3 SearchSysCacheAttName SearchSysCacheList SetConfigOption +SetExplainExtensionState SetTuplestoreDestReceiverParams SetUserIdAndSecContext SharedFileSetAttach @@ -538,6 +549,7 @@ check_amop_signature check_amoptsproc_signature check_amproc_signature check_function_bodies +check_password_hook check_stack_depth clamp_row_est clauselist_selectivity @@ -653,6 +665,8 @@ expanded_record_lookup_field expanded_record_set_field_internal expanded_record_set_fields expanded_record_set_tuple +explain_per_node_hook +explain_per_plan_hook exprCollation exprLocation exprType @@ -738,12 +752,14 @@ get_func_support get_function_sibling_type get_mergejoin_opfamilies get_namespace_name +get_namespace_name_or_temp get_namespace_oid get_opcode get_opfamily_member get_opfamily_name get_primary_key_attnos get_rel_name +get_rel_namespace get_rel_relkind get_rel_type_id get_relids_in_jointree @@ -1032,6 +1048,7 @@ pgstat_count_heap_insert pgstat_count_truncate pgstat_progress_update_param pgstat_report_activity +plain_crypt_verify plan_create_index_workers planner_hook pnstrdup diff --git a/src/wasix/runtime/crates/assets/Cargo.toml b/src/wasix/runtime/crates/assets/Cargo.toml index 6860938b7..d26cb2bfe 100644 --- a/src/wasix/runtime/crates/assets/Cargo.toml +++ b/src/wasix/runtime/crates/assets/Cargo.toml @@ -26,6 +26,7 @@ include = [ [features] extension-amcheck = [] extension-auto-explain = [] +extension-autoinc = [] extension-bloom = [] extension-btree-gin = [] extension-btree-gist = [] @@ -37,15 +38,21 @@ extension-earthdistance = ["extension-cube"] extension-file-fdw = [] extension-fuzzystrmatch = [] extension-hstore = [] +extension-insert-username = [] extension-intarray = [] extension-isn = [] extension-lo = [] extension-ltree = [] +extension-moddatetime = [] extension-pageinspect = [] +extension-passwordcheck = [] extension-pg-buffercache = [] extension-pg-freespacemap = [] extension-pg-hashids = [] extension-pg-ivm = [] +extension-pg-logicalinspect = [] +extension-pg-overexplain = [] +extension-pg-stat-statements = [] extension-pg-partman = [] extension-pg-surgery = [] extension-pg-textsearch = [] @@ -57,6 +64,7 @@ extension-pgcrypto = [] extension-pgmq = [] extension-pgtap = [] extension-postgis = [] +extension-refint = [] extension-seg = [] extension-tablefunc = [] extension-tcn = [] diff --git a/src/wasix/runtime/crates/assets/build-support.rs b/src/wasix/runtime/crates/assets/build-support.rs index 032fdcffb..aa732cde3 100644 --- a/src/wasix/runtime/crates/assets/build-support.rs +++ b/src/wasix/runtime/crates/assets/build-support.rs @@ -107,6 +107,13 @@ const EXTENSION_PACKAGES: &[ExtensionPackage] = &[ sql_name: "auto_explain", crate_ident: "oliphaunt_extension_contrib_pg18", }, + ExtensionPackage { + feature: "extension-autoinc", + env: "CARGO_FEATURE_EXTENSION_AUTOINC", + product: "oliphaunt-extension-contrib-pg18", + sql_name: "autoinc", + crate_ident: "oliphaunt_extension_contrib_pg18", + }, ExtensionPackage { feature: "extension-bloom", env: "CARGO_FEATURE_EXTENSION_BLOOM", @@ -184,6 +191,13 @@ const EXTENSION_PACKAGES: &[ExtensionPackage] = &[ sql_name: "hstore", crate_ident: "oliphaunt_extension_contrib_pg18", }, + ExtensionPackage { + feature: "extension-insert-username", + env: "CARGO_FEATURE_EXTENSION_INSERT_USERNAME", + product: "oliphaunt-extension-contrib-pg18", + sql_name: "insert_username", + crate_ident: "oliphaunt_extension_contrib_pg18", + }, ExtensionPackage { feature: "extension-intarray", env: "CARGO_FEATURE_EXTENSION_INTARRAY", @@ -212,6 +226,13 @@ const EXTENSION_PACKAGES: &[ExtensionPackage] = &[ sql_name: "ltree", crate_ident: "oliphaunt_extension_contrib_pg18", }, + ExtensionPackage { + feature: "extension-moddatetime", + env: "CARGO_FEATURE_EXTENSION_MODDATETIME", + product: "oliphaunt-extension-contrib-pg18", + sql_name: "moddatetime", + crate_ident: "oliphaunt_extension_contrib_pg18", + }, ExtensionPackage { feature: "extension-pageinspect", env: "CARGO_FEATURE_EXTENSION_PAGEINSPECT", @@ -219,6 +240,13 @@ const EXTENSION_PACKAGES: &[ExtensionPackage] = &[ sql_name: "pageinspect", crate_ident: "oliphaunt_extension_contrib_pg18", }, + ExtensionPackage { + feature: "extension-passwordcheck", + env: "CARGO_FEATURE_EXTENSION_PASSWORDCHECK", + product: "oliphaunt-extension-contrib-pg18", + sql_name: "passwordcheck", + crate_ident: "oliphaunt_extension_contrib_pg18", + }, ExtensionPackage { feature: "extension-pg-buffercache", env: "CARGO_FEATURE_EXTENSION_PG_BUFFERCACHE", @@ -233,6 +261,27 @@ const EXTENSION_PACKAGES: &[ExtensionPackage] = &[ sql_name: "pg_freespacemap", crate_ident: "oliphaunt_extension_contrib_pg18", }, + ExtensionPackage { + feature: "extension-pg-logicalinspect", + env: "CARGO_FEATURE_EXTENSION_PG_LOGICALINSPECT", + product: "oliphaunt-extension-contrib-pg18", + sql_name: "pg_logicalinspect", + crate_ident: "oliphaunt_extension_contrib_pg18", + }, + ExtensionPackage { + feature: "extension-pg-overexplain", + env: "CARGO_FEATURE_EXTENSION_PG_OVEREXPLAIN", + product: "oliphaunt-extension-contrib-pg18", + sql_name: "pg_overexplain", + crate_ident: "oliphaunt_extension_contrib_pg18", + }, + ExtensionPackage { + feature: "extension-pg-stat-statements", + env: "CARGO_FEATURE_EXTENSION_PG_STAT_STATEMENTS", + product: "oliphaunt-extension-contrib-pg18", + sql_name: "pg_stat_statements", + crate_ident: "oliphaunt_extension_contrib_pg18", + }, ExtensionPackage { feature: "extension-pg-surgery", env: "CARGO_FEATURE_EXTENSION_PG_SURGERY", @@ -268,6 +317,13 @@ const EXTENSION_PACKAGES: &[ExtensionPackage] = &[ sql_name: "pgcrypto", crate_ident: "oliphaunt_extension_contrib_pg18", }, + ExtensionPackage { + feature: "extension-refint", + env: "CARGO_FEATURE_EXTENSION_REFINT", + product: "oliphaunt-extension-contrib-pg18", + sql_name: "refint", + crate_ident: "oliphaunt_extension_contrib_pg18", + }, ExtensionPackage { feature: "extension-seg", env: "CARGO_FEATURE_EXTENSION_SEG", diff --git a/src/wasix/runtime/tools/package-liboliphaunt-wasix-cargo-artifacts.test.mts b/src/wasix/runtime/tools/package-liboliphaunt-wasix-cargo-artifacts.test.mts index 1f5b6e0b3..ef19ee11c 100644 --- a/src/wasix/runtime/tools/package-liboliphaunt-wasix-cargo-artifacts.test.mts +++ b/src/wasix/runtime/tools/package-liboliphaunt-wasix-cargo-artifacts.test.mts @@ -17,10 +17,10 @@ import { createDeterministicTar } from '../../../../tools/packaging/cargo-source import { canonicalGzipSync } from '../../../../tools/packaging/portable-archive.mts'; import { stageReleaseNotices } from '../../../../tools/packaging/release-notices.mts'; import { + exactExtensionProducts, extensionReleaseProduct, extensionReleaseVersion, extensionSqlNames, - exactExtensionProducts, } from '../../../../tools/release/release-artifact-targets.mts'; import { extractArchiveMemberToFile, @@ -218,6 +218,36 @@ function aggregateFixture(root, { nestedOwner = false } = {}) { } describe('aggregate WASIX Cargo artifact packaging', () => { + test('source consumers select every catalog member through the asset build script', () => { + const manifest = JSON.parse( + readFileSync(path.join(ROOT, 'src/extensions/generated/wasix/extensions.json'), 'utf8'), + ); + const sqlNames = manifest.extensions.map((extension) => extension['sql-name']).sort(); + const features = sqlNames.map((sqlName) => `extension-${sqlName.replaceAll('_', '-')}`); + const app = path.join(scratch, 'all-members', 'app'); + mkdirSync(path.join(app, 'src'), { recursive: true }); + writeFileSync( + path.join(app, 'Cargo.toml'), + `[package] +name = "wasix-all-members-proof" +version = "0.0.0" +edition = "2024" +[dependencies] +liboliphaunt-wasix-portable = { path = ${JSON.stringify(path.join(ROOT, 'src/wasix/runtime/crates/assets'))}, features = ${JSON.stringify(features)} } +[workspace] +`, + ); + writeFileSync( + path.join(app, 'src/main.rs'), + `fn main() { + let mut selected = liboliphaunt_wasix_portable::SELECTED_EXTENSION_SQL_NAMES.to_vec(); + selected.sort_unstable(); + assert_eq!(selected, ${JSON.stringify(sqlNames)}); +} +`, + ); + }); + test('runtime source builds use every external extension product version independently of the runtime', () => { const root = path.join(scratch, 'independent-extension'); const host = supportedRustcHostTriple(); diff --git a/src/wasix/runtime/tools/test-packaging.sh b/src/wasix/runtime/tools/test-packaging.sh index 719d33b2e..907d723ca 100644 --- a/src/wasix/runtime/tools/test-packaging.sh +++ b/src/wasix/runtime/tools/test-packaging.sh @@ -18,15 +18,19 @@ if bun "$contract" unsupported > /dev/null 2>&1; then fi bash tools/dev/bun.sh test ./src/wasix/runtime/tools node src/wasix/runtime/tools/wasix-runtime-npm.test-consumer.mts -for scenario in nested-owner aggregate independent-extension; do +for scenario in all-members nested-owner aggregate independent-extension; do root="$OLIPHAUNT_WASIX_PACKAGING_TEST_ROOT/$scenario" # Keep registry dependencies at the qualified workspace versions; this # disposable consumer only changes local carrier paths and feature selection. cp Cargo.lock "$root/app/Cargo.lock" cargo fetch --manifest-path "$root/app/Cargo.toml" + if [[ "$scenario" == all-members ]]; then + artifact_env=(-u OLIPHAUNT_WASIX_EXTENSION_ARTIFACT_ROOT) + else + artifact_env=("OLIPHAUNT_WASIX_EXTENSION_ARTIFACT_ROOT=$root") + fi CARGO_TARGET_DIR="$OLIPHAUNT_WASIX_PACKAGING_TEST_ROOT/cargo-target" \ - OLIPHAUNT_WASIX_EXTENSION_ARTIFACT_ROOT="$root" \ - cargo run --locked --offline --manifest-path "$root/app/Cargo.toml" + env "${artifact_env[@]}" cargo run --locked --offline --manifest-path "$root/app/Cargo.toml" done root="$OLIPHAUNT_WASIX_PACKAGING_TEST_ROOT/independent-extension" manifest="$root/oliphaunt-extension-pg-hashids/extension-artifacts.json" diff --git a/src/wasix/runtime/tools/wasix-extension-features.test.mts b/src/wasix/runtime/tools/wasix-extension-features.test.mts index bbc87c1a2..d0df88aaa 100644 --- a/src/wasix/runtime/tools/wasix-extension-features.test.mts +++ b/src/wasix/runtime/tools/wasix-extension-features.test.mts @@ -9,21 +9,39 @@ import { extensionFeatures, fullEvidenceFeatures } from './wasix-extension-featu const ROOT = path.resolve(import.meta.dirname, '../../../..'); -test('the live WASIX public surface includes the PostGIS product', () => { +test('every catalog extension has matching Rust asset and SDK features', () => { const manifest = JSON.parse( readFileSync(path.join(ROOT, 'src/extensions/generated/wasix/extensions.json'), 'utf8'), ); - assert.equal( - manifest.extensions.some((row) => row['sql-name'] === 'postgis'), - true, - ); + const expected = extensionFeatures(manifest); for (const relative of [ 'src/wasix/runtime/crates/assets/Cargo.toml', 'src/wasix/sdks/rust/Cargo.toml', ]) { const cargo = Bun.TOML.parse(readFileSync(path.join(ROOT, relative), 'utf8')); - assert.equal(Object.hasOwn(cargo.features ?? {}, 'extension-postgis'), true, relative); + assert.deepEqual( + Object.keys(cargo.features ?? {}) + .filter((feature) => feature.startsWith('extension-')) + .sort(), + expected, + relative, + ); + for (const extension of manifest.extensions) { + const feature = `extension-${extension['sql-name'].replaceAll('_', '-')}`; + // plpgsql ships in the core runtime rather than an extension carrier. + const dependencies = extension.dependencies + .filter((sqlName) => sqlName !== 'plpgsql') + .map((sqlName) => `extension-${sqlName.replaceAll('_', '-')}`); + const forwarding = relative.includes('/sdks/') + ? ['extensions', `liboliphaunt-wasix-portable/${feature}`] + : []; + assert.deepEqual( + cargo.features[feature].toSorted(), + [...dependencies, ...forwarding].sort(), + feature, + ); + } } }); diff --git a/src/wasix/sdks/rust/Cargo.toml b/src/wasix/sdks/rust/Cargo.toml index 2fefc700f..e39b9223e 100644 --- a/src/wasix/sdks/rust/Cargo.toml +++ b/src/wasix/sdks/rust/Cargo.toml @@ -38,6 +38,7 @@ tools = [ ] extension-amcheck = ["extensions", "liboliphaunt-wasix-portable/extension-amcheck"] extension-auto-explain = ["extensions", "liboliphaunt-wasix-portable/extension-auto-explain"] +extension-autoinc = ["extensions", "liboliphaunt-wasix-portable/extension-autoinc"] extension-bloom = ["extensions", "liboliphaunt-wasix-portable/extension-bloom"] extension-btree-gin = ["extensions", "liboliphaunt-wasix-portable/extension-btree-gin"] extension-btree-gist = ["extensions", "liboliphaunt-wasix-portable/extension-btree-gist"] @@ -53,15 +54,21 @@ extension-earthdistance = [ extension-file-fdw = ["extensions", "liboliphaunt-wasix-portable/extension-file-fdw"] extension-fuzzystrmatch = ["extensions", "liboliphaunt-wasix-portable/extension-fuzzystrmatch"] extension-hstore = ["extensions", "liboliphaunt-wasix-portable/extension-hstore"] +extension-insert-username = ["extensions", "liboliphaunt-wasix-portable/extension-insert-username"] extension-intarray = ["extensions", "liboliphaunt-wasix-portable/extension-intarray"] extension-isn = ["extensions", "liboliphaunt-wasix-portable/extension-isn"] extension-lo = ["extensions", "liboliphaunt-wasix-portable/extension-lo"] extension-ltree = ["extensions", "liboliphaunt-wasix-portable/extension-ltree"] +extension-moddatetime = ["extensions", "liboliphaunt-wasix-portable/extension-moddatetime"] extension-pageinspect = ["extensions", "liboliphaunt-wasix-portable/extension-pageinspect"] +extension-passwordcheck = ["extensions", "liboliphaunt-wasix-portable/extension-passwordcheck"] extension-pg-buffercache = ["extensions", "liboliphaunt-wasix-portable/extension-pg-buffercache"] extension-pg-freespacemap = ["extensions", "liboliphaunt-wasix-portable/extension-pg-freespacemap"] extension-pg-hashids = ["extensions", "liboliphaunt-wasix-portable/extension-pg-hashids"] extension-pg-ivm = ["extensions", "liboliphaunt-wasix-portable/extension-pg-ivm"] +extension-pg-logicalinspect = ["extensions", "liboliphaunt-wasix-portable/extension-pg-logicalinspect"] +extension-pg-overexplain = ["extensions", "liboliphaunt-wasix-portable/extension-pg-overexplain"] +extension-pg-stat-statements = ["extensions", "liboliphaunt-wasix-portable/extension-pg-stat-statements"] extension-pg-partman = ["extensions", "liboliphaunt-wasix-portable/extension-pg-partman"] extension-pg-surgery = ["extensions", "liboliphaunt-wasix-portable/extension-pg-surgery"] extension-pg-textsearch = ["extensions", "liboliphaunt-wasix-portable/extension-pg-textsearch"] @@ -73,6 +80,7 @@ extension-pgcrypto = ["extensions", "liboliphaunt-wasix-portable/extension-pgcry extension-pgmq = ["extensions", "liboliphaunt-wasix-portable/extension-pgmq"] extension-pgtap = ["extensions", "liboliphaunt-wasix-portable/extension-pgtap"] extension-postgis = ["extensions", "liboliphaunt-wasix-portable/extension-postgis"] +extension-refint = ["extensions", "liboliphaunt-wasix-portable/extension-refint"] extension-seg = ["extensions", "liboliphaunt-wasix-portable/extension-seg"] extension-tablefunc = ["extensions", "liboliphaunt-wasix-portable/extension-tablefunc"] extension-tcn = ["extensions", "liboliphaunt-wasix-portable/extension-tcn"] diff --git a/src/wasix/sdks/rust/src/oliphaunt/generated_extensions.rs b/src/wasix/sdks/rust/src/oliphaunt/generated_extensions.rs index 323b548cd..b87e2d2fc 100644 --- a/src/wasix/sdks/rust/src/oliphaunt/generated_extensions.rs +++ b/src/wasix/sdks/rust/src/oliphaunt/generated_extensions.rs @@ -212,6 +212,16 @@ const DEFINITION_PAGEINSPECT: Extension = Extension { package: None, }; +const DEFINITION_PASSWORDCHECK: Extension = Extension { + sql_name: "passwordcheck", + native_support_modules: &[], + native_module_file: Some("passwordcheck.so"), + aot_name: Some("extension:passwordcheck"), + dependencies: &[], + startup_config: &[], + package: None, +}; + const DEFINITION_PG_BUFFERCACHE: Extension = Extension { sql_name: "pg_buffercache", native_support_modules: &[], @@ -262,6 +272,16 @@ const DEFINITION_PG_LOGICALINSPECT: Extension = Extension { package: None, }; +const DEFINITION_PG_OVEREXPLAIN: Extension = Extension { + sql_name: "pg_overexplain", + native_support_modules: &[], + native_module_file: Some("pg_overexplain.so"), + aot_name: Some("extension:pg_overexplain"), + dependencies: &[], + startup_config: &[], + package: None, +}; + const DEFINITION_PG_PARTMAN: Extension = Extension { sql_name: "pg_partman", native_support_modules: &[], @@ -539,6 +559,9 @@ impl Extension { /// Select the `pageinspect` artifact. pub const PAGEINSPECT: Self = DEFINITION_PAGEINSPECT; + /// Select the `passwordcheck` artifact. + + pub const PASSWORDCHECK: Self = DEFINITION_PASSWORDCHECK; /// Select the `pg_buffercache` artifact. pub const PG_BUFFERCACHE: Self = DEFINITION_PG_BUFFERCACHE; @@ -554,6 +577,9 @@ impl Extension { /// Select the `pg_logicalinspect` artifact. pub const PG_LOGICALINSPECT: Self = DEFINITION_PG_LOGICALINSPECT; + /// Select the `pg_overexplain` artifact. + + pub const PG_OVEREXPLAIN: Self = DEFINITION_PG_OVEREXPLAIN; /// Select the `pg_partman` artifact. pub const PG_PARTMAN: Self = DEFINITION_PG_PARTMAN; @@ -641,11 +667,13 @@ impl Extension { Self::LTREE, Self::MODDATETIME, Self::PAGEINSPECT, + Self::PASSWORDCHECK, Self::PG_BUFFERCACHE, Self::PG_FREESPACEMAP, Self::PG_HASHIDS, Self::PG_IVM, Self::PG_LOGICALINSPECT, + Self::PG_OVEREXPLAIN, Self::PG_PARTMAN, Self::PG_STAT_STATEMENTS, Self::PG_SURGERY, @@ -715,6 +743,8 @@ pub(super) fn creates_database_object_for_test(extension: Extension) -> bool { "pageinspect" => true, + "passwordcheck" => false, + "pg_buffercache" => true, "pg_freespacemap" => true, @@ -725,6 +755,8 @@ pub(super) fn creates_database_object_for_test(extension: Extension) -> bool { "pg_logicalinspect" => true, + "pg_overexplain" => false, + "pg_partman" => true, "pg_stat_statements" => true, @@ -836,6 +868,8 @@ pub(super) fn activation_sql_for_test(extension: Extension) -> &'static [&'stati &["CREATE EXTENSION IF NOT EXISTS \"pageinspect\" WITH SCHEMA \"pg_catalog\";"] } + "passwordcheck" => &["LOAD 'passwordcheck';"], + "pg_buffercache" => { &["CREATE EXTENSION IF NOT EXISTS \"pg_buffercache\" WITH SCHEMA \"pg_catalog\";"] } @@ -854,6 +888,8 @@ pub(super) fn activation_sql_for_test(extension: Extension) -> &'static [&'stati &["CREATE EXTENSION IF NOT EXISTS \"pg_logicalinspect\" WITH SCHEMA \"pg_catalog\";"] } + "pg_overexplain" => &["LOAD 'pg_overexplain';"], + "pg_partman" => &[ "CREATE SCHEMA IF NOT EXISTS \"partman\";", "CREATE EXTENSION IF NOT EXISTS \"pg_partman\" WITH SCHEMA \"partman\";", From ea7095d35d198d94b442f1d5acd7e83f9a554ecd Mon Sep 17 00:00:00 2001 From: Sid Jain Date: Mon, 19 Oct 2026 06:32:26 +0000 Subject: [PATCH 07/11] fix(wasix): invalidate compiler output on export changes --- src/wasix/runtime/moon.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/wasix/runtime/moon.yml b/src/wasix/runtime/moon.yml index 22388653a..a5fa1b311 100644 --- a/src/wasix/runtime/moon.yml +++ b/src/wasix/runtime/moon.yml @@ -181,8 +181,7 @@ tasks: - "!/src/third-party/postgres/testdata/**/*" - tools/build-compiler-output.sh - tools/extension-build-scripts.mts - - "!assets/generated" - - "!assets/generated/**" + - assets/generated/wasix-dl.exports - /src/wasix/sdks/rust/Cargo.toml - /src/wasix/runtime/tools/xtask/**/* - "@group(release-archive-contract)" From a063555794a059b7df1f7eeed0ab0db4520f8738 Mon Sep 17 00:00:00 2001 From: Sid Jain Date: Mon, 19 Oct 2026 09:21:21 +0000 Subject: [PATCH 08/11] fix(extensions): qualify catalog and release selection updates --- .../tools/windows-extension-sources.test.mts | 1 - .../tools/check-mobile-artifacts.test.mts | 8 ++- src/native/sdks/rust/tests/public_api.rs | 55 ++++++++++++++++++- tools/release/check-release-metadata.mts | 22 +++++--- .../prepare-release-candidate.test.mts | 20 ++----- .../release/release-dependency-plan.test.mts | 38 +++++++++++++ 6 files changed, 120 insertions(+), 24 deletions(-) diff --git a/src/extensions/artifacts/native/tools/windows-extension-sources.test.mts b/src/extensions/artifacts/native/tools/windows-extension-sources.test.mts index 22f85335b..327e2d05d 100644 --- a/src/extensions/artifacts/native/tools/windows-extension-sources.test.mts +++ b/src/extensions/artifacts/native/tools/windows-extension-sources.test.mts @@ -31,7 +31,6 @@ test('PGMQ SQL packaging includes the current installation and upgrades, without } }); - test('SQL-only pg_partman stages ordered install SQL and upgrades without workers or tools', () => { const root = mkdtempSync(path.join(tmpdir(), 'partman-windows-')); try { diff --git a/src/native/sdks/react-native/tools/check-mobile-artifacts.test.mts b/src/native/sdks/react-native/tools/check-mobile-artifacts.test.mts index 3d7d06ce3..f070402f0 100644 --- a/src/native/sdks/react-native/tools/check-mobile-artifacts.test.mts +++ b/src/native/sdks/react-native/tools/check-mobile-artifacts.test.mts @@ -53,12 +53,18 @@ test('matches CocoaPods iOS link inputs exactly for all generated extension iden REACT_NATIVE_METADATA.extensions.map((row) => [row['sql-name'], row['native-module-stem']]), ); assert.equal(bySqlName.get('intarray'), '_int'); + assert.equal(bySqlName.get('pg_partman'), null); + assert.equal(bySqlName.get('pgmq'), null); assert.equal(bySqlName.get('pgtap'), null); assert.equal(bySqlName.get('postgis'), 'postgis-3'); assert.equal(bySqlName.get('uuid-ossp'), 'uuid-ossp'); const expectedStems = [...bySqlName.values()].filter((stem) => stem !== null).sort(); - assert.equal(expectedStems.length, 38); + assert.equal(expectedStems.length, 46); + assert.deepEqual( + expectedStems, + MOBILE_STATIC_REGISTRY.modules.map((row) => row['native-module-stem']).sort(), + ); const evidence = iosCocoaPodsExtensionLinkEvidence({ expectedStems, inputText: expectedStems diff --git a/src/native/sdks/rust/tests/public_api.rs b/src/native/sdks/rust/tests/public_api.rs index 8a4a5c6a0..edd547674 100644 --- a/src/native/sdks/rust/tests/public_api.rs +++ b/src/native/sdks/rust/tests/public_api.rs @@ -408,7 +408,60 @@ fn extension_catalog_is_exact_and_sorted() { .map(|extension| extension.sql_name()) .collect::>(); assert!(names.windows(2).all(|pair| pair[0] < pair[1])); - assert_eq!(names.len(), 39); + assert_eq!( + names, + [ + "amcheck", + "auto_explain", + "autoinc", + "bloom", + "btree_gin", + "btree_gist", + "citext", + "cube", + "dict_int", + "dict_xsyn", + "earthdistance", + "file_fdw", + "fuzzystrmatch", + "hstore", + "insert_username", + "intarray", + "isn", + "lo", + "ltree", + "moddatetime", + "pageinspect", + "passwordcheck", + "pg_buffercache", + "pg_freespacemap", + "pg_hashids", + "pg_ivm", + "pg_logicalinspect", + "pg_overexplain", + "pg_partman", + "pg_stat_statements", + "pg_surgery", + "pg_textsearch", + "pg_trgm", + "pg_uuidv7", + "pg_visibility", + "pg_walinspect", + "pgcrypto", + "pgmq", + "pgtap", + "postgis", + "refint", + "seg", + "tablefunc", + "tcn", + "tsm_system_rows", + "tsm_system_time", + "unaccent", + "uuid-ossp", + "vector", + ] + ); for extension in Extension::ALL { assert_eq!( Extension::by_sql_name(extension.sql_name()), diff --git a/tools/release/check-release-metadata.mts b/tools/release/check-release-metadata.mts index b7c3d4939..36b7b3f46 100755 --- a/tools/release/check-release-metadata.mts +++ b/tools/release/check-release-metadata.mts @@ -300,11 +300,7 @@ function validateCompatibility(graph, { publication = false } = {}) { new Set(entries.map((entry) => entry.id)).size === entries.length, 'compatibility field ids must be globally unique', ); - const dependencyPlan = new Map( - (publication ? releaseDependencyPlan(graph.products, Object.keys(graph.products)) : []).map( - (entry) => [entry.id, entry.version], - ), - ); + let dependencyPlan = new Map(); let pendingRelease; let checkedPendingRelease = false; let pendingVersions = new Map(); @@ -349,6 +345,12 @@ function validateCompatibility(graph, { publication = false } = {}) { if (status.currentTagCommit === null) { pendingRelease = latestVerifiedReleaseCommit({ repo: ROOT }); pendingVersions = new Map(Object.entries(pendingRelease?.versions ?? {})); + dependencyPlan = new Map( + releaseDependencyPlan(graph.products, pendingVersions.keys()).map((entry) => [ + entry.id, + entry.version, + ]), + ); checkedPendingRelease = true; } } @@ -369,11 +371,17 @@ function validateCompatibility(graph, { publication = false } = {}) { // release. Once published, its immutable tag supplies this value. missingValue: value, }) - : dependencyPlan.get(entry.id); + : // A 0.0.0 product has no immutable release yet. An unrelated runtime + // release must preserve its declaration, just as candidate sync does. + pendingVersions.has(entry.product) + ? dependencyPlan.get(entry.id) + : value; const provenance = source.kind === 'tagged-sink' ? `immutable ${entry.product} tag ${source.tag}` - : `planned ${entry.sourceProduct} binding ${expected}`; + : pendingVersions.has(entry.product) + ? `planned ${entry.sourceProduct} binding ${expected}` + : `unreleased ${entry.product} declared requirement ${expected}`; requireCompatibilityVersionBinding( { id: entry.id, diff --git a/tools/release/prepare-release-candidate.test.mts b/tools/release/prepare-release-candidate.test.mts index e906ecfa3..5bfbbfbe3 100644 --- a/tools/release/prepare-release-candidate.test.mts +++ b/tools/release/prepare-release-candidate.test.mts @@ -406,13 +406,9 @@ for (const scenario of [ files: [`${native}/src/liboliphaunt.c`, 'src/extensions/external/vector/source.toml'], products: [ 'liboliphaunt-native', - 'oliphaunt-extension-vector', - 'oliphaunt-extension-pg-hashids', - 'oliphaunt-extension-pg-ivm', - 'oliphaunt-extension-pg-textsearch', - 'oliphaunt-extension-pg-uuidv7', - 'oliphaunt-extension-pgtap', - 'oliphaunt-extension-postgis', + ...Object.keys(graph.products).filter( + (id) => graph.products[id].extension?.class === 'external', + ), 'oliphaunt-js', 'oliphaunt-kotlin', 'oliphaunt-swift', @@ -466,13 +462,9 @@ for (const scenario of [ files: ['src/extensions/artifacts/packages/tools/package-extension-cargo-facades.mts'], products: [ 'liboliphaunt-native', - 'oliphaunt-extension-pg-hashids', - 'oliphaunt-extension-pg-ivm', - 'oliphaunt-extension-pg-textsearch', - 'oliphaunt-extension-pg-uuidv7', - 'oliphaunt-extension-pgtap', - 'oliphaunt-extension-postgis', - 'oliphaunt-extension-vector', + ...Object.keys(graph.products).filter( + (id) => graph.products[id].extension?.class === 'external', + ), 'oliphaunt-js', 'oliphaunt-kotlin', 'oliphaunt-swift', diff --git a/tools/release/release-dependency-plan.test.mts b/tools/release/release-dependency-plan.test.mts index c12b168f2..4613f7d63 100644 --- a/tools/release/release-dependency-plan.test.mts +++ b/tools/release/release-dependency-plan.test.mts @@ -1,4 +1,5 @@ import { expect, test } from 'bun:test'; +import { requireCompatibilityVersionBinding } from './compatibility-version-policy.mts'; import { releaseDependencyPlan, requirePublicSupportTransition, @@ -34,6 +35,43 @@ test('selected source consumers retain declarations while compiled payloads name ).toBe(true); }); +test('new SQL-only extensions retain declared hosts until their own release is selected', () => { + const runtime = 'liboliphaunt-wasix'; + for (const extension of ['pgmq', 'pg_partman']) { + const product = `oliphaunt-extension-${extension.replaceAll('_', '-')}`; + const products = { + [runtime]: { path: 'src/wasix/runtime', version: '0.3.3' }, + [product]: { + path: `src/extensions/external/${extension}`, + version: '0.0.0', + kind: 'exact-extension-artifact', + extension: { class: 'external' }, + }, + }; + const entry = { id: `${product}-host`, product, sourceProduct: runtime, publicSupport: true }; + const options = { entries: [entry], readValue: () => '0.3.2' }; + const [unchanged] = releaseDependencyPlan(products, [runtime], options); + expect(unchanged.version).toBe('0.3.2'); + expect(unchanged.binding).toBe('declared-requirement'); + + products[product].version = '0.1.0'; + const [selected] = releaseDependencyPlan(products, [runtime, product], options); + expect(selected.version).toBe('0.3.3'); + expect(selected.binding).toBe('compiled-input'); + const validate = (value) => + requireCompatibilityVersionBinding({ + id: entry.id, + value, + expected: selected.version, + sourceProduct: runtime, + sourceVersion: products[runtime].version, + provenance: `planned ${runtime} binding ${selected.version}`, + }); + expect(() => validate('0.3.2')).toThrow('must match planned'); + expect(() => validate('0.3.3')).not.toThrow(); + } +}); + test('support removal requires the configured pre-1.0 or stable breaking boundary', () => { const base = { product: 'extension', From d611d28ca6fd08016289c08aa198d2112e30cb24 Mon Sep 17 00:00:00 2001 From: Sid Jain Date: Mon, 19 Oct 2026 10:59:10 +0000 Subject: [PATCH 09/11] fix(extensions): repair WASIX builds and LOAD-only lifecycle checks --- .../react-native-expo/src/SmokeDashboard.tsx | 27 +----- .../react-native-expo/src/mobile-smoke.ts | 34 +++++-- .../tools/mobile-extension-proof.test.mts | 91 ++++++++++++++++++- .../generated/docs/extension-evidence.json | 2 +- src/extensions/generated/pgxs-build.tsv | 2 +- .../tools/extension-projections.mts | 6 +- .../sdks/rust/tests/native_extensions.rs | 21 ++++- src/wasix/pgwire-server/Cargo.toml | 10 ++ .../build/docker_pgxs_extensions.test.sh | 19 +++- .../runtime/assets/generated/wasix-dl.exports | 7 +- .../tools/wasix-extension-features.test.mts | 16 ++-- 11 files changed, 184 insertions(+), 51 deletions(-) diff --git a/src/examples/native/react-native-expo/src/SmokeDashboard.tsx b/src/examples/native/react-native-expo/src/SmokeDashboard.tsx index 234588110..55025402c 100644 --- a/src/examples/native/react-native-expo/src/SmokeDashboard.tsx +++ b/src/examples/native/react-native-expo/src/SmokeDashboard.tsx @@ -12,6 +12,7 @@ import { GENERATED_MOBILE_EXTENSION_SMOKE, } from './generated/extension-smoke'; import { + activationSqlForExtension, runMobileBindingProof, runMobileReleaseExtensionProof, runPostgresLifecycleResumeCheck, @@ -113,7 +114,7 @@ const packagedCatalogProfile = process.env.EXPO_PUBLIC_OLIPHAUNT_CATALOG_PROFILE const packagedCatalogProfileProbeSql = process.env.EXPO_PUBLIC_OLIPHAUNT_CATALOG_PROFILE_PROBE_SQL; const packagedCatalogProfileProbeExpected = process.env.EXPO_PUBLIC_OLIPHAUNT_CATALOG_PROFILE_PROBE_EXPECTED; -const packagedExtensions = process.env.EXPO_PUBLIC_OLIPHAUNT_EXTENSIONS; +const packagedExtensions: string | undefined = process.env.EXPO_PUBLIC_OLIPHAUNT_EXTENSIONS; let initialLaunchUrlPromise: Promise | undefined; function smokeGlobalState(): SmokeGlobalState { @@ -544,7 +545,9 @@ function mobileReleaseExtensionProofPlan() { selected.has(extension.sqlName), ); if (plan.length !== selected.size) { - const known = new Set(GENERATED_MOBILE_EXTENSION_PLAN.map((extension) => extension.sqlName)); + const known = new Set( + GENERATED_MOBILE_EXTENSION_PLAN.map((extension) => extension.sqlName), + ); const unknown = requested.filter((extension) => !known.has(extension)); throw new Error(`unknown packaged mobile extensions: ${unknown.join(',')}`); } @@ -565,26 +568,6 @@ function mobileReleaseExtensionProofPlan() { }); } -function activationSqlForExtension(extension: { - readonly sqlName: string; - readonly createsExtension: boolean; -}): readonly string[] { - if (extension.createsExtension) { - return [`CREATE EXTENSION "${extension.sqlName}"`]; - } - if (extension.sqlName === 'auto_explain') { - return [ - "LOAD 'auto_explain'", - "SET auto_explain.log_min_duration = '0'", - "SET auto_explain.log_analyze = 'true'", - "SET auto_explain.log_level = 'NOTICE'", - ]; - } - throw new Error( - `generated mobile extension ${extension.sqlName} does not create an extension and has no runtime proof`, - ); -} - function waitForBackgroundAndForeground( stage: (name: string, extra?: Record) => void, ): Promise<{ states: AppStateStatus[] }> { diff --git a/src/examples/native/react-native-expo/src/mobile-smoke.ts b/src/examples/native/react-native-expo/src/mobile-smoke.ts index e8b9e0b4e..56d015d22 100644 --- a/src/examples/native/react-native-expo/src/mobile-smoke.ts +++ b/src/examples/native/react-native-expo/src/mobile-smoke.ts @@ -236,6 +236,25 @@ async function provePgTextsearchEnglishSnowball(db: OliphauntDatabase): Promise< } } +export function activationSqlForExtension(extension: { + readonly sqlName: string; + readonly createsExtension: boolean; +}): readonly string[] { + if (extension.createsExtension) { + return [`CREATE EXTENSION "${extension.sqlName}"`]; + } + if (extension.sqlName === 'auto_explain') { + return [ + "LOAD 'auto_explain'", + "SET auto_explain.log_min_duration = '0'", + "SET auto_explain.log_analyze = 'true'", + "SET auto_explain.log_level = 'NOTICE'", + ]; + } + // Other LOAD-only modules are activated by their canonical smoke recipes. + return []; +} + export async function runMobileReleaseExtensionProof( db: OliphauntDatabase, plan: readonly MobileReleaseExtensionProof[], @@ -277,12 +296,15 @@ export async function runMobileReleaseExtensionProof( return `${extension.sqlName} ${version}; dependency closure ${extension.selectedExtensionDependencies.join(',') || 'none'}`; } - const configured = await scalar( - db, - "SELECT current_setting('auto_explain.log_min_duration')::text AS value", - ); - assertEqual(configured, '0', 'auto_explain load/configuration proof'); - return 'auto_explain loaded and configured in the installed app session'; + if (extension.sqlName === 'auto_explain') { + const configured = await scalar( + db, + "SELECT current_setting('auto_explain.log_min_duration')::text AS value", + ); + assertEqual(configured, '0', 'auto_explain load/configuration proof'); + return 'auto_explain loaded and configured in the installed app session'; + } + return `${extension.sqlName} canonical LOAD-only smoke proof completed in the installed app session`; }, onCheckStage, ); diff --git a/src/examples/native/react-native-expo/tools/mobile-extension-proof.test.mts b/src/examples/native/react-native-expo/tools/mobile-extension-proof.test.mts index 5a457d9e7..84c3112bb 100644 --- a/src/examples/native/react-native-expo/tools/mobile-extension-proof.test.mts +++ b/src/examples/native/react-native-expo/tools/mobile-extension-proof.test.mts @@ -1,5 +1,9 @@ import assert from 'node:assert/strict'; import { mock, test } from 'bun:test'; +import { + GENERATED_MOBILE_EXTENSION_PLAN, + GENERATED_MOBILE_EXTENSION_SMOKE, +} from '../src/generated/extension-smoke'; class FixturePostgresError extends Error {} @@ -10,7 +14,9 @@ mock.module('@oliphaunt/react-native', () => ({ }, })); -const { runMobileReleaseExtensionProof } = await import('../src/mobile-smoke.ts'); +const { activationSqlForExtension, runMobileReleaseExtensionProof } = await import( + '../src/mobile-smoke.ts' +); const { serializeExpoSmokePassReceipt } = await import('../src/smoke-pass-receipt.ts'); function queryResult(values) { @@ -53,7 +59,10 @@ test('the successful pg_textsearch producer supplies every semantic PASS fact', createsExtension: true, nativeModuleStem: 'pg_textsearch', selectedExtensionDependencies: [], - activationSql: ['CREATE EXTENSION pg_textsearch'], + activationSql: activationSqlForExtension({ + sqlName: 'pg_textsearch', + createsExtension: true, + }), smokeStatements: ['SELECT 1'], }, ]); @@ -62,7 +71,7 @@ test('the successful pg_textsearch producer supplies every semantic PASS fact', assert.equal(proof.extensionCatalogComplete, true); assert.equal(proof.pgTextsearchEnglishBm25, true); assert.deepEqual(executed, [ - 'CREATE EXTENSION pg_textsearch', + 'CREATE EXTENSION "pg_textsearch"', 'DROP TABLE IF EXISTS oliphaunt_mobile_pg_textsearch_english', 'CREATE TABLE oliphaunt_mobile_pg_textsearch_english (id bigint PRIMARY KEY, body text NOT NULL)', `INSERT INTO oliphaunt_mobile_pg_textsearch_english (id, body) VALUES @@ -102,3 +111,79 @@ test('the successful pg_textsearch producer supplies every semantic PASS fact', assert.equal(receipt.extensionCatalogComplete, true); assert.equal(receipt.pgTextsearchEnglishBm25, true); }); + +for (const sqlName of ['passwordcheck', 'pg_overexplain']) { + test(`${sqlName} proves its generated LOAD-only recipe without auto_explain`, async () => { + const extension = GENERATED_MOBILE_EXTENSION_PLAN.find((row) => row.sqlName === sqlName); + assert.ok(extension); + assert.equal(extension.createsExtension, false); + const smokeStatements = GENERATED_MOBILE_EXTENSION_SMOKE[sqlName]; + const queried = []; + const db = { + async execute(sql) { + throw new Error(`unexpected LOAD-only activation: ${sql}`); + }, + async query(sql) { + queried.push(sql); + if (smokeStatements.includes(sql)) return queryResult({}); + if (sql.includes('string_agg')) return queryResult({ value: '' }); + throw new Error(`unexpected LOAD-only query: ${sql}`); + }, + }; + const proof = await runMobileReleaseExtensionProof(db, [ + { + ...extension, + activationSql: activationSqlForExtension(extension), + smokeStatements, + }, + ]); + assert.deepEqual(queried.slice(0, -1), smokeStatements); + assert.deepEqual(proof.activatedExtensions, [sqlName]); + assert.equal(proof.extensionCatalogComplete, true); + assert.equal(proof.pgTextsearchEnglishBm25, false); + assert.equal(proof.checks[0].name, `extension activation: ${sqlName}`); + assert.equal( + proof.checks[0].detail, + `${sqlName} canonical LOAD-only smoke proof completed in the installed app session`, + ); + }); +} + +test('auto_explain still requires its configured logging duration', async () => { + const extension = GENERATED_MOBILE_EXTENSION_PLAN.find((row) => row.sqlName === 'auto_explain'); + assert.ok(extension); + const executed = []; + let logMinDuration = '0'; + const db = { + async execute(sql) { + executed.push(sql); + }, + async query(sql) { + if (GENERATED_MOBILE_EXTENSION_SMOKE.auto_explain.includes(sql)) return queryResult({}); + if (sql === "SELECT current_setting('auto_explain.log_min_duration')::text AS value") + return queryResult({ value: logMinDuration }); + if (sql.includes('string_agg')) return queryResult({ value: '' }); + throw new Error(`unexpected auto_explain query: ${sql}`); + }, + }; + const plan = [ + { + ...extension, + activationSql: activationSqlForExtension(extension), + smokeStatements: GENERATED_MOBILE_EXTENSION_SMOKE.auto_explain, + }, + ]; + const proof = await runMobileReleaseExtensionProof(db, plan); + assert.deepEqual(executed, [ + "LOAD 'auto_explain'", + "SET auto_explain.log_min_duration = '0'", + "SET auto_explain.log_analyze = 'true'", + "SET auto_explain.log_level = 'NOTICE'", + ]); + assert.equal(proof.extensionCatalogComplete, true); + logMinDuration = '-1'; + await assert.rejects( + () => runMobileReleaseExtensionProof(db, plan), + /auto_explain load\/configuration proof/, + ); +}); diff --git a/src/extensions/generated/docs/extension-evidence.json b/src/extensions/generated/docs/extension-evidence.json index 547ac251a..6602ae0ed 100644 --- a/src/extensions/generated/docs/extension-evidence.json +++ b/src/extensions/generated/docs/extension-evidence.json @@ -1686,7 +1686,7 @@ "collector": "src/extensions/tools/collect-wasix-evidence.sh", "kind": "exact-sha-ci" }, - "source-digest": "sha256:3ebd072c4dbba4aaf1a3cc73b8f299eb2e3e1df6a29e80a1dd6f670a5e9da106", + "source-digest": "sha256:adefd1b31d2e0587e279b640fa7f254e6f17eac6130d23b74a98ffe79dfe2d8f", "source-digest-inputs": [ "src/third-party/postgres/source.toml", "src/extensions/catalog/extensions.source.json", diff --git a/src/extensions/generated/pgxs-build.tsv b/src/extensions/generated/pgxs-build.tsv index 692b1e275..a9537f6af 100644 --- a/src/extensions/generated/pgxs-build.tsv +++ b/src/extensions/generated/pgxs-build.tsv @@ -6,4 +6,4 @@ pg_textsearch pg_textsearch target/oliphaunt-sources/checkouts/pg_textsearch pg_ pg_uuidv7 pg_uuidv7 target/oliphaunt-sources/checkouts/pg_uuidv7 pg_uuidv7.so extensions/pg_uuidv7.tar.zst - pgmq pgmq target/oliphaunt-sources/checkouts/pgmq/pgmq-extension - extensions/pgmq.tar.zst - pgtap pgtap target/oliphaunt-sources/checkouts/pgtap - extensions/pgtap.tar.zst - -vector vector target/oliphaunt-sources/checkouts/pgvector vector.so extensions/vector.tar.zst - +vector vector target/oliphaunt-sources/checkouts/pgvector vector.so extensions/vector.tar.zst OPTFLAGS=-mno-relaxed-simd diff --git a/src/extensions/tools/extension-projections.mts b/src/extensions/tools/extension-projections.mts index bd7b6b015..9818e5d36 100644 --- a/src/extensions/tools/extension-projections.mts +++ b/src/extensions/tools/extension-projections.mts @@ -651,7 +651,11 @@ export function catalogProjections(catalog: Row): Map { ? 'SIZEOF_DATUM=4' : row.id === 'pg_partman' ? 'NO_BGW=1 SCRIPTS= DOCS=' - : '-', + : row.id === 'vector' + ? // Upstream contracts floating-point operations; keep its SIMD within + // the pinned Wasmer runtime's supported, non-relaxed instruction set. + 'OPTFLAGS=-mno-relaxed-simd' + : '-', ].join('\t'), ); } else assert.equal(row['source-kind'], 'postgis', 'unsupported extension build kind'); diff --git a/src/native/sdks/rust/tests/native_extensions.rs b/src/native/sdks/rust/tests/native_extensions.rs index fba094efc..ba7b622d1 100644 --- a/src/native/sdks/rust/tests/native_extensions.rs +++ b/src/native/sdks/rust/tests/native_extensions.rs @@ -561,7 +561,7 @@ fn assert_repeated_create_extension_error_recovers( mode: TestMode, extension: Extension, ) -> Result<()> { - if extension == Extension::AUTO_EXPLAIN { + if !extension.creates_extension() { return Ok(()); } @@ -596,7 +596,7 @@ fn assert_repeated_create_extension_error_recovers( } fn assert_extension_visible(db: &TestDatabase, mode: TestMode, extension: Extension) -> Result<()> { - if extension != Extension::AUTO_EXPLAIN { + if extension.creates_extension() { let response = block_on(db.exec_protocol_raw(raw_query_message(&format!( "SELECT extname FROM pg_extension WHERE extname = '{}'", extension.sql_name() @@ -616,7 +616,7 @@ fn assert_extension_visible(db: &TestDatabase, mode: TestMode, extension: Extens } fn install_sql(extension: Extension) -> String { - if extension != Extension::AUTO_EXPLAIN { + if extension.creates_extension() { let sql_name = extension.sql_name().replace('"', "\"\""); format!("CREATE EXTENSION \"{sql_name}\" CASCADE") } else { @@ -625,6 +625,21 @@ fn install_sql(extension: Extension) -> String { } } +#[test] +fn native_extension_installation_respects_module_only_contracts() { + for (extension, expected) in [ + (Extension::AUTO_EXPLAIN, "LOAD 'auto_explain'"), + (Extension::PASSWORDCHECK, "LOAD 'passwordcheck'"), + (Extension::PG_OVEREXPLAIN, "LOAD 'pg_overexplain'"), + ( + Extension::PG_STAT_STATEMENTS, + "CREATE EXTENSION \"pg_stat_statements\" CASCADE", + ), + ] { + assert_eq!(install_sql(extension), expected); + } +} + fn run_extension_functional_smoke( db: &TestDatabase, mode: TestMode, diff --git a/src/wasix/pgwire-server/Cargo.toml b/src/wasix/pgwire-server/Cargo.toml index b2ea8b4b6..40e181ef1 100644 --- a/src/wasix/pgwire-server/Cargo.toml +++ b/src/wasix/pgwire-server/Cargo.toml @@ -18,6 +18,7 @@ icu = ["wasix", "oliphaunt-wasix/icu"] extension-amcheck = ["extensions", "oliphaunt-wasix/extension-amcheck"] extension-auto-explain = ["extensions", "oliphaunt-wasix/extension-auto-explain"] +extension-autoinc = ["extensions", "oliphaunt-wasix/extension-autoinc"] extension-bloom = ["extensions", "oliphaunt-wasix/extension-bloom"] extension-btree-gin = ["extensions", "oliphaunt-wasix/extension-btree-gin"] extension-btree-gist = ["extensions", "oliphaunt-wasix/extension-btree-gist"] @@ -29,15 +30,22 @@ extension-earthdistance = ["extensions", "oliphaunt-wasix/extension-earthdistanc extension-file-fdw = ["extensions", "oliphaunt-wasix/extension-file-fdw"] extension-fuzzystrmatch = ["extensions", "oliphaunt-wasix/extension-fuzzystrmatch"] extension-hstore = ["extensions", "oliphaunt-wasix/extension-hstore"] +extension-insert-username = ["extensions", "oliphaunt-wasix/extension-insert-username"] extension-intarray = ["extensions", "oliphaunt-wasix/extension-intarray"] extension-isn = ["extensions", "oliphaunt-wasix/extension-isn"] extension-lo = ["extensions", "oliphaunt-wasix/extension-lo"] extension-ltree = ["extensions", "oliphaunt-wasix/extension-ltree"] +extension-moddatetime = ["extensions", "oliphaunt-wasix/extension-moddatetime"] extension-pageinspect = ["extensions", "oliphaunt-wasix/extension-pageinspect"] +extension-passwordcheck = ["extensions", "oliphaunt-wasix/extension-passwordcheck"] extension-pg-buffercache = ["extensions", "oliphaunt-wasix/extension-pg-buffercache"] extension-pg-freespacemap = ["extensions", "oliphaunt-wasix/extension-pg-freespacemap"] extension-pg-hashids = ["extensions", "oliphaunt-wasix/extension-pg-hashids"] extension-pg-ivm = ["extensions", "oliphaunt-wasix/extension-pg-ivm"] +extension-pg-logicalinspect = ["extensions", "oliphaunt-wasix/extension-pg-logicalinspect"] +extension-pg-overexplain = ["extensions", "oliphaunt-wasix/extension-pg-overexplain"] +extension-pg-partman = ["extensions", "oliphaunt-wasix/extension-pg-partman"] +extension-pg-stat-statements = ["extensions", "oliphaunt-wasix/extension-pg-stat-statements"] extension-pg-surgery = ["extensions", "oliphaunt-wasix/extension-pg-surgery"] extension-pg-textsearch = ["extensions", "oliphaunt-wasix/extension-pg-textsearch"] extension-pg-trgm = ["extensions", "oliphaunt-wasix/extension-pg-trgm"] @@ -45,8 +53,10 @@ extension-pg-uuidv7 = ["extensions", "oliphaunt-wasix/extension-pg-uuidv7"] extension-pg-visibility = ["extensions", "oliphaunt-wasix/extension-pg-visibility"] extension-pg-walinspect = ["extensions", "oliphaunt-wasix/extension-pg-walinspect"] extension-pgcrypto = ["extensions", "oliphaunt-wasix/extension-pgcrypto"] +extension-pgmq = ["extensions", "oliphaunt-wasix/extension-pgmq"] extension-pgtap = ["extensions", "oliphaunt-wasix/extension-pgtap"] extension-postgis = ["extensions", "oliphaunt-wasix/extension-postgis"] +extension-refint = ["extensions", "oliphaunt-wasix/extension-refint"] extension-seg = ["extensions", "oliphaunt-wasix/extension-seg"] extension-tablefunc = ["extensions", "oliphaunt-wasix/extension-tablefunc"] extension-tcn = ["extensions", "oliphaunt-wasix/extension-tcn"] diff --git a/src/wasix/runtime/assets/build/docker_pgxs_extensions.test.sh b/src/wasix/runtime/assets/build/docker_pgxs_extensions.test.sh index a35d09ba4..290114552 100644 --- a/src/wasix/runtime/assets/build/docker_pgxs_extensions.test.sh +++ b/src/wasix/runtime/assets/build/docker_pgxs_extensions.test.sh @@ -39,12 +39,13 @@ exec bash -c "$payload" SH chmod +x "$fixture/bin/docker" -# Use the generated SQL-only row, plus a compiled extension with one make arg. -awk -F '\t' '$1 == "pg_partman"' "$repo_root/src/extensions/generated/pgxs-build.tsv" > "$fixture/plan.tsv" +# Use generated SQL-only and SIMD policy rows, plus a compiled extension with one make arg. +awk -F '\t' '$1 == "pg_partman" || $1 == "vector"' "$repo_root/src/extensions/generated/pgxs-build.tsv" > "$fixture/plan.tsv" test -s "$fixture/plan.tsv" printf 'age\tage\tfixture-age\tage.so\textensions/age.tar.zst\tSIZEOF_DATUM=4\n' >> "$fixture/plan.tsv" -partman_source="$(cut -f3 "$fixture/plan.tsv" | head -1)" -mkdir -p "$fixture/$partman_source" "$fixture/fixture-age" +partman_source="$(awk -F '\t' '$1 == "pg_partman" {print $3}' "$fixture/plan.tsv")" +vector_source="$(awk -F '\t' '$1 == "vector" {print $3}' "$fixture/plan.tsv")" +mkdir -p "$fixture/$partman_source" "$fixture/$vector_source" "$fixture/fixture-age" cat > "$fixture/$partman_source/Makefile" <<'MAKE' SCRIPTS = unwanted-tools DOCS = unwanted-docs @@ -56,6 +57,15 @@ all: clean: @true MAKE +cat > "$fixture/$vector_source/Makefile" <<'MAKE' +OPTFLAGS = -march=native +PG_CFLAGS += $(OPTFLAGS) -ffp-contract=fast +all: + @test "$(PG_CFLAGS)" = '-mno-relaxed-simd -ffp-contract=fast' + @touch vector.so flags-verified +clean: + @true +MAKE cat > "$fixture/fixture-age/Makefile" <<'MAKE' all: @test "$(SIZEOF_DATUM)" = 4 @@ -73,4 +83,5 @@ DOCKER="$fixture/bin/docker" \ bash "$script_dir/docker_pgxs_extensions.sh" test -f "$fixture/build/pgxs/pg_partman/flags-verified" test -f "$fixture/build/pgxs/age/flags-verified" +test -f "$fixture/build/pgxs/vector/flags-verified" echo 'WASIX PGXS generated plan passes each make argument to the actual build' diff --git a/src/wasix/runtime/assets/generated/wasix-dl.exports b/src/wasix/runtime/assets/generated/wasix-dl.exports index c5cafb3c8..c3b0ffbc6 100644 --- a/src/wasix/runtime/assets/generated/wasix-dl.exports +++ b/src/wasix/runtime/assets/generated/wasix-dl.exports @@ -50,7 +50,6 @@ ConditionVariableSignal ConditionVariableSleep ConditionVariableTimedSleep ConditionalLockBuffer -ConditionalLockRelationOid CopyErrorData CopyFromErrorCallback CopyIndexTuple @@ -278,6 +277,7 @@ PushCopiedSnapshot QueryCancelPending QueryRewrite RangeVarCallbackMaintainsTable +RangeVarCallbackOwnsRelation RangeVarGetRelidExtended ReThrowError ReadBuffer @@ -490,6 +490,7 @@ biteq bitge bitgt bitle +bitlength bitlt block_range_read_stream_cb bloom_add_element @@ -503,7 +504,6 @@ bms_del_member bms_del_members bms_equal bms_free -bms_int_members bms_is_member bms_is_subset bms_make_singleton @@ -851,7 +851,7 @@ lappend_oid list_concat list_concat_copy list_copy -list_delete_cell +list_delete_int list_delete_last list_delete_nth_cell list_free @@ -1011,7 +1011,6 @@ pg_numa_query_pages pg_number_of_ones pg_parse_query pg_plan_query -pg_popcount64 pg_popcount_optimized pg_printf pg_prng_double diff --git a/src/wasix/runtime/tools/wasix-extension-features.test.mts b/src/wasix/runtime/tools/wasix-extension-features.test.mts index d0df88aaa..448a5a05d 100644 --- a/src/wasix/runtime/tools/wasix-extension-features.test.mts +++ b/src/wasix/runtime/tools/wasix-extension-features.test.mts @@ -9,7 +9,7 @@ import { extensionFeatures, fullEvidenceFeatures } from './wasix-extension-featu const ROOT = path.resolve(import.meta.dirname, '../../../..'); -test('every catalog extension has matching Rust asset and SDK features', () => { +test('every catalog extension has matching Rust asset, SDK, and server features', () => { const manifest = JSON.parse( readFileSync(path.join(ROOT, 'src/extensions/generated/wasix/extensions.json'), 'utf8'), ); @@ -18,6 +18,7 @@ test('every catalog extension has matching Rust asset and SDK features', () => { for (const relative of [ 'src/wasix/runtime/crates/assets/Cargo.toml', 'src/wasix/sdks/rust/Cargo.toml', + 'src/wasix/pgwire-server/Cargo.toml', ]) { const cargo = Bun.TOML.parse(readFileSync(path.join(ROOT, relative), 'utf8')); assert.deepEqual( @@ -30,16 +31,19 @@ test('every catalog extension has matching Rust asset and SDK features', () => { for (const extension of manifest.extensions) { const feature = `extension-${extension['sql-name'].replaceAll('_', '-')}`; // plpgsql ships in the core runtime rather than an extension carrier. - const dependencies = extension.dependencies + const server = relative.includes('/pgwire-server/'); + const dependencies = (server ? [] : extension.dependencies) .filter((sqlName) => sqlName !== 'plpgsql') .map((sqlName) => `extension-${sqlName.replaceAll('_', '-')}`); - const forwarding = relative.includes('/sdks/') - ? ['extensions', `liboliphaunt-wasix-portable/${feature}`] - : []; + const forwarding = server + ? ['extensions', `oliphaunt-wasix/${feature}`] + : relative.includes('/sdks/') + ? ['extensions', `liboliphaunt-wasix-portable/${feature}`] + : []; assert.deepEqual( cargo.features[feature].toSorted(), [...dependencies, ...forwarding].sort(), - feature, + `${relative}: ${feature}`, ); } } From 0c2fcd7b666196474b444b85dd143308a97dc554 Mon Sep 17 00:00:00 2001 From: Sid Jain Date: Tue, 20 Oct 2026 05:29:33 +0000 Subject: [PATCH 10/11] fix(wasix): include all contrib extensions in Node-API releases --- src/wasix/node-addon/Cargo.toml | 18 ++++++++++++++ .../tools/wasix-extension-features.test.mts | 24 +++++++++++++++---- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/src/wasix/node-addon/Cargo.toml b/src/wasix/node-addon/Cargo.toml index f04684fb2..2b1cc6517 100644 --- a/src/wasix/node-addon/Cargo.toml +++ b/src/wasix/node-addon/Cargo.toml @@ -22,6 +22,7 @@ release = [ "tools", "extension-amcheck", "extension-auto-explain", + "extension-autoinc", "extension-bloom", "extension-btree-gin", "extension-btree-gist", @@ -33,18 +34,25 @@ release = [ "extension-file-fdw", "extension-fuzzystrmatch", "extension-hstore", + "extension-insert-username", "extension-intarray", "extension-isn", "extension-lo", "extension-ltree", + "extension-moddatetime", "extension-pageinspect", + "extension-passwordcheck", "extension-pg-buffercache", "extension-pg-freespacemap", + "extension-pg-logicalinspect", + "extension-pg-overexplain", + "extension-pg-stat-statements", "extension-pg-surgery", "extension-pg-trgm", "extension-pg-visibility", "extension-pg-walinspect", "extension-pgcrypto", + "extension-refint", "extension-seg", "extension-tablefunc", "extension-tcn", @@ -55,6 +63,7 @@ release = [ ] extension-amcheck = ["extensions", "oliphaunt-wasix/extension-amcheck"] extension-auto-explain = ["extensions", "oliphaunt-wasix/extension-auto-explain"] +extension-autoinc = ["extensions", "oliphaunt-wasix/extension-autoinc"] extension-bloom = ["extensions", "oliphaunt-wasix/extension-bloom"] extension-btree-gin = ["extensions", "oliphaunt-wasix/extension-btree-gin"] extension-btree-gist = ["extensions", "oliphaunt-wasix/extension-btree-gist"] @@ -66,15 +75,22 @@ extension-earthdistance = ["extensions", "oliphaunt-wasix/extension-earthdistanc extension-file-fdw = ["extensions", "oliphaunt-wasix/extension-file-fdw"] extension-fuzzystrmatch = ["extensions", "oliphaunt-wasix/extension-fuzzystrmatch"] extension-hstore = ["extensions", "oliphaunt-wasix/extension-hstore"] +extension-insert-username = ["extensions", "oliphaunt-wasix/extension-insert-username"] extension-intarray = ["extensions", "oliphaunt-wasix/extension-intarray"] extension-isn = ["extensions", "oliphaunt-wasix/extension-isn"] extension-lo = ["extensions", "oliphaunt-wasix/extension-lo"] extension-ltree = ["extensions", "oliphaunt-wasix/extension-ltree"] +extension-moddatetime = ["extensions", "oliphaunt-wasix/extension-moddatetime"] extension-pageinspect = ["extensions", "oliphaunt-wasix/extension-pageinspect"] +extension-passwordcheck = ["extensions", "oliphaunt-wasix/extension-passwordcheck"] extension-pg-buffercache = ["extensions", "oliphaunt-wasix/extension-pg-buffercache"] extension-pg-freespacemap = ["extensions", "oliphaunt-wasix/extension-pg-freespacemap"] extension-pg-hashids = ["extensions", "oliphaunt-wasix/extension-pg-hashids"] extension-pg-ivm = ["extensions", "oliphaunt-wasix/extension-pg-ivm"] +extension-pg-logicalinspect = ["extensions", "oliphaunt-wasix/extension-pg-logicalinspect"] +extension-pg-overexplain = ["extensions", "oliphaunt-wasix/extension-pg-overexplain"] +extension-pg-partman = ["extensions", "oliphaunt-wasix/extension-pg-partman"] +extension-pg-stat-statements = ["extensions", "oliphaunt-wasix/extension-pg-stat-statements"] extension-pg-surgery = ["extensions", "oliphaunt-wasix/extension-pg-surgery"] extension-pg-textsearch = ["extensions", "oliphaunt-wasix/extension-pg-textsearch"] extension-pg-trgm = ["extensions", "oliphaunt-wasix/extension-pg-trgm"] @@ -82,8 +98,10 @@ extension-pg-uuidv7 = ["extensions", "oliphaunt-wasix/extension-pg-uuidv7"] extension-pg-visibility = ["extensions", "oliphaunt-wasix/extension-pg-visibility"] extension-pg-walinspect = ["extensions", "oliphaunt-wasix/extension-pg-walinspect"] extension-pgcrypto = ["extensions", "oliphaunt-wasix/extension-pgcrypto"] +extension-pgmq = ["extensions", "oliphaunt-wasix/extension-pgmq"] extension-pgtap = ["extensions", "oliphaunt-wasix/extension-pgtap"] extension-postgis = ["extensions", "oliphaunt-wasix/extension-postgis"] +extension-refint = ["extensions", "oliphaunt-wasix/extension-refint"] extension-seg = ["extensions", "oliphaunt-wasix/extension-seg"] extension-tablefunc = ["extensions", "oliphaunt-wasix/extension-tablefunc"] extension-tcn = ["extensions", "oliphaunt-wasix/extension-tcn"] diff --git a/src/wasix/runtime/tools/wasix-extension-features.test.mts b/src/wasix/runtime/tools/wasix-extension-features.test.mts index 448a5a05d..188a3e067 100644 --- a/src/wasix/runtime/tools/wasix-extension-features.test.mts +++ b/src/wasix/runtime/tools/wasix-extension-features.test.mts @@ -9,7 +9,7 @@ import { extensionFeatures, fullEvidenceFeatures } from './wasix-extension-featu const ROOT = path.resolve(import.meta.dirname, '../../../..'); -test('every catalog extension has matching Rust asset, SDK, and server features', () => { +test('every catalog extension has matching Rust asset, SDK, server, and Node-API features', () => { const manifest = JSON.parse( readFileSync(path.join(ROOT, 'src/extensions/generated/wasix/extensions.json'), 'utf8'), ); @@ -19,6 +19,7 @@ test('every catalog extension has matching Rust asset, SDK, and server features' 'src/wasix/runtime/crates/assets/Cargo.toml', 'src/wasix/sdks/rust/Cargo.toml', 'src/wasix/pgwire-server/Cargo.toml', + 'src/wasix/node-addon/Cargo.toml', ]) { const cargo = Bun.TOML.parse(readFileSync(path.join(ROOT, relative), 'utf8')); assert.deepEqual( @@ -31,11 +32,11 @@ test('every catalog extension has matching Rust asset, SDK, and server features' for (const extension of manifest.extensions) { const feature = `extension-${extension['sql-name'].replaceAll('_', '-')}`; // plpgsql ships in the core runtime rather than an extension carrier. - const server = relative.includes('/pgwire-server/'); - const dependencies = (server ? [] : extension.dependencies) + const forwardsSdk = relative.includes('/pgwire-server/') || relative.includes('/node-addon/'); + const dependencies = (forwardsSdk ? [] : extension.dependencies) .filter((sqlName) => sqlName !== 'plpgsql') .map((sqlName) => `extension-${sqlName.replaceAll('_', '-')}`); - const forwarding = server + const forwarding = forwardsSdk ? ['extensions', `oliphaunt-wasix/${feature}`] : relative.includes('/sdks/') ? ['extensions', `liboliphaunt-wasix-portable/${feature}`] @@ -49,6 +50,21 @@ test('every catalog extension has matching Rust asset, SDK, and server features' } }); +test('the Node-API release embeds the complete contrib catalog', () => { + const catalog = JSON.parse( + readFileSync(path.join(ROOT, 'src/extensions/generated/extensions.catalog.json'), 'utf8'), + ); + const cargo = Bun.TOML.parse( + readFileSync(path.join(ROOT, 'src/wasix/node-addon/Cargo.toml'), 'utf8'), + ); + const contrib = extensionFeatures({ + extensions: catalog.extensions.filter( + (extension) => extension['source-kind'] === 'postgres-contrib', + ), + }); + assert.deepEqual(cargo.features.release.toSorted(), ['tools', ...contrib].sort()); +}); + test('full WASIX evidence enables every extension feature', () => { const manifest = { extensions: [{ 'sql-name': 'vector' }, { 'sql-name': 'pg_trgm' }], From fbd32667d7be3f6b87d6275342bec3984a151d51 Mon Sep 17 00:00:00 2001 From: Sid Jain Date: Tue, 20 Oct 2026 05:40:56 +0000 Subject: [PATCH 11/11] chore(ci): qualify merged extension upgrades Keep the qualification tip single-parent for the release metadata checker after integrating main.