From fcd58b6486c85d07f26c7e0eedf8a9e86d22d281 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lemuel=20Roberto=20Bonif=C3=A1cio?= Date: Wed, 30 Sep 2026 13:36:41 -0300 Subject: [PATCH 1/2] Ship transaction-free bundles by default Every sql/ script opened and committed its own transactions, so a release bundle carried dozens of top-level BEGIN;/COMMIT; pairs. That made the bundle impossible to embed where someone else already owns the transaction: a migration tool runs each migration inside one, and the bundle's first COMMIT; ended it halfway through, leaving the rest to run in autocommit. pg_tle hit the same wall, which is why pgtle-wrap.sh stripped those lines with grep before wrapping. The sources now carry no transaction control, and the plain artifacts are what the sources say. The caller picks the boundary: psql -1, a migration's transaction, or CREATE EXTENSION. For a bare psql -f that should still be all or nothing, every artifact gets a -tx twin holding exactly one BEGIN; and one COMMIT; around the whole bundle, rather than one pair per script section. Nothing in the scripts depended on a commit between sections: the all-in bundle installs inside a single transaction and a rollback leaves no cel schema behind. The release smoke job now proves exactly that for each plain artifact, and build-release.sh, which CI runs, refuses a BEGIN; or COMMIT; line that finds its way back into sql/. --- .github/workflows/ci.yml | 6 +++ .github/workflows/release.yml | 69 ++++++++++++++++++++++------------ README.md | 5 ++- docs/INSTALL.md | 30 +++++++++++++-- scripts/build-release.sh | 40 +++++++++++++++----- scripts/pgtle-wrap.sh | 15 +++++--- sql/000_install.sql | 10 ++--- sql/010_registry.sql | 4 -- sql/020_values.sql | 12 ------ sql/030_parse.sql | 24 ------------ sql/040_check.sql | 12 ------ sql/050_eval.sql | 4 -- sql/060_stdlib.sql | 12 ------ sql/070_wkt.sql | 8 ---- sql/100_ext_comprehensions.sql | 4 -- sql/110_ext_optionals.sql | 8 ---- sql/120_ext_strings.sql | 8 ---- sql/130_ext_math.sql | 4 -- sql/140_ext_lists.sql | 4 -- sql/150_ext_encoders.sql | 4 -- sql/160_ext_bindings.sql | 4 -- sql/170_ext_network.sql | 4 -- 22 files changed, 128 insertions(+), 163 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7fe7222..c4609d7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -45,6 +45,12 @@ jobs: # than reaching the suite as a mysterious test failure. - run: docker compose up -d --wait + # Instant, and it refuses a sql/ script that opens or closes a + # transaction -- the property the plain release artifacts + # depend on. + - name: Build release artifacts + run: ./scripts/build-release.sh + - name: Check formatting run: | unformatted=$(gofmt -l .) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9b7e75d..e485df8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,12 +18,14 @@ permissions: # between jobs -- fewer moving parts, and nothing to pin. jobs: - # The plain-scripts channel: the artifact is the initdb script - # for the same pinned image compose uses, and readiness is - # cel.version() answering. The all-in bundle and the core-only - # file are the two shapes that could break independently; each - # extension file is a verbatim copy of a sql/ script CI already - # installs. + # The plain-scripts channel, both shapes of the all-in bundle and + # the core-only file. A plain artifact must run inside a + # transaction it does not own: installed between BEGIN and + # ROLLBACK it has to leave no cel schema behind -- one stray + # COMMIT; would keep it -- and installed with --single-transaction + # it has to answer cel.version(). A -tx artifact installs with a + # bare psql -f. Each extension file is a verbatim copy of a sql/ + # script CI already installs. smoke: if: >- github.repository == 'emfga/cel4postgres' && @@ -45,29 +47,48 @@ jobs: sql/000_install.sql) image=$(sed -n 's/^ *image: \(postgres:[^ ]*\)$/\1/p' \ compose.yaml) - init=/docker-entrypoint-initdb.d/install.sql - for artifact in \ - "cel4postgres--$version.sql" \ - "cel4postgres-core--$version.sql" - do - echo "== $artifact" - docker run -d --rm --name relcheck \ - -e POSTGRES_DB=cel -e POSTGRES_USER=cel \ - -e POSTGRES_PASSWORD=pw \ - -v "$PWD/dist/$artifact:$init:ro" \ - "$image" >/dev/null - got= - for _ in $(seq 60); do - got=$(docker exec relcheck psql -U cel -d cel -tAc \ - 'SELECT cel.version()' 2>/dev/null) && break - sleep 2 - done - docker rm -f relcheck >/dev/null + docker run -d --rm --name relcheck \ + -e POSTGRES_DB=cel -e POSTGRES_USER=cel \ + -e POSTGRES_PASSWORD=pw \ + -v "$PWD/dist:/dist:ro" \ + "$image" >/dev/null + # -h 127.0.0.1: over the socket, pg_isready can reach + # initdb's temporary server; only the final one listens + # on TCP. + for _ in $(seq 60); do + docker exec relcheck pg_isready -h 127.0.0.1 \ + -U cel -d cel -q 2>/dev/null && break + sleep 2 + done + sql() { + docker exec -e PGOPTIONS='-c client_min_messages=warning' \ + relcheck psql -h 127.0.0.1 -U cel -d cel \ + -v ON_ERROR_STOP=1 -q "$@" + } + check() { + got=$(sql -tAc 'SELECT cel.version()') if [ "$got" != "$version" ]; then echo "expected $version, got '$got'" >&2 exit 1 fi + sql -c 'DROP SCHEMA cel CASCADE' + } + for name in cel4postgres cel4postgres-core; do + plain="/dist/$name--$version.sql" + echo "== $plain" + sql -c 'BEGIN' -f "$plain" -c 'ROLLBACK' + left=$(sql -tAc "SELECT to_regnamespace('cel')") + if [ -n "$left" ]; then + echo "$plain committed on its own" >&2 + exit 1 + fi + sql --single-transaction -f "$plain" + check + echo "== /dist/$name-tx--$version.sql" + sql -f "/dist/$name-tx--$version.sql" + check done + docker rm -f relcheck >/dev/null # The flagship channel: the same dist/ files, wrapped by # scripts/pgtle-wrap.sh into pgtle.install_extension, installed diff --git a/README.md b/README.md index 33e4170..7cc57c0 100644 --- a/README.md +++ b/README.md @@ -143,10 +143,13 @@ numeric prefix. Nothing about them is specific to the compose setup: ```bash for f in sql/*.sql; do - psql -v ON_ERROR_STOP=1 -f "$f" "$YOUR_DATABASE_URL" + psql -v ON_ERROR_STOP=1 -1 -f "$f" "$YOUR_DATABASE_URL" done ``` +The scripts open no transaction of their own; `-1` makes each file +all or nothing. + It needs a role that may create the `cel` schema. It does not need superuser. [docs/INSTALL.md](docs/INSTALL.md) is the full guide: release artifacts and their checksums, self-hosted and AWS diff --git a/docs/INSTALL.md b/docs/INSTALL.md index 9d30e13..86c28f1 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -24,8 +24,15 @@ Download from the [releases page][releases]: | `cel4postgres--.sql` | everything: core + all extensions | | `cel4postgres-core--.sql` | core only (`cel.evaluate`, standard library, well-known types) | | `cel4postgres-ext_--.sql` | one extension library | +| `cel4postgres…-tx--.sql` | the same file, between one `BEGIN;` and one `COMMIT;` | | `SHA256SUMS` | checksums for all of the above | +The plain files contain no transaction control, so they run inside +a transaction someone else opens: psql's `--single-transaction`, a +migration tool's, or pg_tle's `CREATE EXTENSION`. Each `-tx` twin +opens and commits exactly one transaction of its own, for a bare +`psql -f` that should still be all or nothing. + Verify downloads before running them: ```bash @@ -48,10 +55,14 @@ Run the artifact as a role that may create the `cel` schema — the database owner is enough; superuser is not needed: ```bash -psql -v ON_ERROR_STOP=1 "$DATABASE_URL" \ +psql -v ON_ERROR_STOP=1 --single-transaction "$DATABASE_URL" \ -f cel4postgres--.sql ``` +or, equivalently, `psql -v ON_ERROR_STOP=1 -f +cel4postgres-tx--.sql`. Either way a failure leaves the +database as it was. + Then verify: ```sql @@ -92,8 +103,9 @@ One-time instance setup (this part needs a reboot; see the Then register and install cel4postgres. The artifact is wrapped into a `pgtle.install_extension` call by a script from this -repository (it strips top-level transaction statements, which are -not allowed inside `CREATE EXTENSION`): +repository. Wrap the plain files, not the `-tx` ones: transaction +control is not allowed inside `CREATE EXTENSION`, and the script +refuses a file that contains it. ```bash ./scripts/pgtle-wrap.sh cel4postgres \ @@ -115,6 +127,18 @@ DROP EXTENSION cel4postgres; SELECT pgtle.uninstall_extension('cel4postgres'); ``` +## Inside a migration tool + +Migration tools (Flyway, Liquibase, Kysely, Alembic, Rails, …) +usually run each migration inside a transaction they own. Embed the +plain `cel4postgres--.sql` as the body of one migration and +execute it as a single multi-statement string, without bind +parameters — the file is many statements with `$$`-quoted function +bodies, which PostgreSQL accepts only over the simple query +protocol. The whole install then commits or rolls back with the +migration. Do not embed a `-tx` file: its `COMMIT;` would end the +tool's transaction halfway through. + ## Access control The installing role owns everything and is the only one that can diff --git a/scripts/build-release.sh b/scripts/build-release.sh index d744a30..ef8f115 100755 --- a/scripts/build-release.sh +++ b/scripts/build-release.sh @@ -7,11 +7,17 @@ # # Three granularities, per the distribution decision: an all-in # bundle, a core-only file (000-070), and one file per extension -# library (100-170). Plain concatenation is safe because every -# sql/ script opens and closes its own transactions. Install with -# ON_ERROR_STOP so a failure stops between them: +# library (100-170). # -# psql -v ON_ERROR_STOP=1 -f cel4postgres--.sql +# Each comes in two shapes. The plain file carries no transaction +# control, so it runs inside whatever transaction the caller already +# holds -- a migration tool's, pg_tle's CREATE EXTENSION, or psql's +# --single-transaction: +# +# psql -v ON_ERROR_STOP=1 -1 -f cel4postgres--.sql +# +# The -tx file is the same bundle between exactly one BEGIN; and one +# COMMIT;, for a plain `psql -f` that should still be all or nothing. set -eu @@ -27,31 +33,47 @@ case $version in ;; esac +# The sources carry no transaction control; that is what lets the +# plain artifacts run inside a caller's transaction. A BEGIN; or +# COMMIT; line reappearing in sql/ would silently commit that +# transaction halfway, so refuse to build rather than ship it. +if grep -n -x -e 'BEGIN;' -e 'COMMIT;' sql/*.sql; then + echo "sql/ must not open or close transactions" >&2 + exit 1 +fi + rm -rf dist mkdir -p dist # Concatenate the named files, each behind a banner naming its # source, so an error line in a bundle is traceable to a script. +# Writes --.sql and its -tx--.sql +# twin. bundle() { - out=$1 + name=$1 shift for f in "$@"; do printf -- '-- ---- %s ----\n\n' "$f" cat "$f" printf '\n' - done >"dist/$out" + done >"dist/$name--$version.sql" + { + printf 'BEGIN;\n\n' + cat "dist/$name--$version.sql" + printf 'COMMIT;\n' + } >"dist/$name-tx--$version.sql" } core=$(ls sql/0[0-9][0-9]_*.sql) exts=$(ls sql/1[0-9][0-9]_*.sql) # shellcheck disable=SC2086 -bundle "cel4postgres--$version.sql" $core $exts +bundle cel4postgres $core $exts # shellcheck disable=SC2086 -bundle "cel4postgres-core--$version.sql" $core +bundle cel4postgres-core $core for f in $exts; do name=$(basename "$f" .sql | sed 's/^[0-9]*_//') - bundle "cel4postgres-$name--$version.sql" "$f" + bundle "cel4postgres-$name" "$f" done (cd dist && sha256sum -- *.sql >SHA256SUMS) diff --git a/scripts/pgtle-wrap.sh b/scripts/pgtle-wrap.sh index 7bf0125..05694df 100755 --- a/scripts/pgtle-wrap.sh +++ b/scripts/pgtle-wrap.sh @@ -6,10 +6,9 @@ # # pgtle-wrap.sh ... > out.sql # -# The artifacts run unchanged except for one transformation: their -# top-level BEGIN;/COMMIT; lines are dropped, because a pg_tle -# script executes inside CREATE EXTENSION's own transaction, where -# transaction control is not allowed. +# The artifacts run unchanged. Pass the plain ones, never a -tx +# twin: a pg_tle script executes inside CREATE EXTENSION's own +# transaction, where transaction control is not allowed. set -eu @@ -21,7 +20,13 @@ tag='_cel_pgtle_' tmp=$(mktemp) trap 'rm -f "$tmp"' EXIT -cat -- "$@" | grep -v -x -e 'BEGIN;' -e 'COMMIT;' >"$tmp" +cat -- "$@" >"$tmp" + +if grep -q -x -e 'BEGIN;' -e 'COMMIT;' "$tmp"; then + echo "input controls transactions; pass the plain artifacts," \ + "not the -tx ones" >&2 + exit 1 +fi # The bundle becomes one dollar-quoted literal; the quoting breaks # if its tag ever appears in the content, so refuse instead of diff --git a/sql/000_install.sql b/sql/000_install.sql index a656fab..80aecfd 100644 --- a/sql/000_install.sql +++ b/sql/000_install.sql @@ -4,11 +4,13 @@ -- the cel schema. Nothing here requires superuser, a filesystem, or -- a server restart: see CLAUDE.md, "Installation and privileges". -- --- Run with: psql -v ON_ERROR_STOP=1 -f sql/000_install.sql +-- Run with: psql -v ON_ERROR_STOP=1 -1 -f sql/000_install.sql -- followed by the other sql/ scripts in numbered order (or use a -- release artifact, which bundles them already ordered). - -BEGIN; +-- +-- No script opens a transaction of its own. The caller decides: +-- psql -1 (--single-transaction) per file, a migration tool's +-- transaction around a whole bundle, or pg_tle's CREATE EXTENSION. CREATE SCHEMA IF NOT EXISTS cel; @@ -39,5 +41,3 @@ AS $$ ORDER BY applied_at DESC, version DESC LIMIT 1; $$; - -COMMIT; diff --git a/sql/010_registry.sql b/sql/010_registry.sql index 7394daa..3d091c4 100644 --- a/sql/010_registry.sql +++ b/sql/010_registry.sql @@ -6,8 +6,6 @@ -- core could reach anything the registry cannot describe, the -- registry would stop being the extension mechanism. -BEGIN; - -- Custom and well-known types: name resolution, construction, -- equality and conversion hooks. Every row visible in an env also -- implies an identifier of type type(T) under the type's name. @@ -182,5 +180,3 @@ INSERT INTO cel.env (name, flags) VALUES ('optionals', '{"optional_syntax": true}'), ('network', '{}') ON CONFLICT (name) DO NOTHING; - -COMMIT; diff --git a/sql/020_values.sql b/sql/020_values.sql index 7e7e56a..5b38e42 100644 --- a/sql/020_values.sql +++ b/sql/020_values.sql @@ -3,8 +3,6 @@ -- Run after 000_install.sql. Everything here is a pure function over -- tagged jsonb values or their scalar payloads; nothing reads a table. -BEGIN; - -- Renders a finite double the way CEL's string(double) must: cel-go -- delegates to Go's %g (common/types/double.go:141, pinned v0.32.0). -- Postgres's own float8 output is close but measurably different in @@ -128,10 +126,6 @@ BEGIN END; $$; -COMMIT; - -BEGIN; - -- Tagged-value primitives. The kind tag carries type identity; -- these helpers are the single place equality, ordering and payload -- access are defined, so every impl and the evaluator agree on them. @@ -465,10 +459,6 @@ BEGIN END; $$; -COMMIT; - -BEGIN; - -- Exact float8 -> numeric. The built-in cast goes through the -- shortest decimal text, which identifies the double uniquely but is -- NOT its exact binary value (36028797018963968::float8::numeric @@ -506,5 +496,3 @@ BEGIN * ('1e' || e)::numeric; END; $$; - -COMMIT; diff --git a/sql/030_parse.sql b/sql/030_parse.sql index e6e0ab5..9e18dcd 100644 --- a/sql/030_parse.sql +++ b/sql/030_parse.sql @@ -10,8 +10,6 @@ -- lexical rules follow it exactly, including the newline -- normalization applied to every literal form. -BEGIN; - -- Lexes one string or bytes literal. pos points at the opening quote -- (prefixes r/R/b/B already consumed by the caller). Returns the -- decoded value: text for strings, base64 text for bytes. ni is the @@ -428,10 +426,6 @@ BEGIN END; $$; -COMMIT; - -BEGIN; - -- Line/column (both 0-based line, 0-based col) for an offset, for -- parse error reporting. Conformance never string-matches parse -- errors; this exists for humans. @@ -620,10 +614,6 @@ BEGIN END; $$; -COMMIT; - -BEGIN; - -- Hex digits to numeric (uint64-sized values overflow bigint). CREATE OR REPLACE FUNCTION cel._p_hex(h text) RETURNS numeric @@ -772,10 +762,6 @@ BEGIN END; $$; -COMMIT; - -BEGIN; - -- The recursive grammar. Every function shares one signature: -- (tk, p, id, d, mac, fl) -> (node, np, nid, err, ep) -- tk: token array; p: cursor; id: last assigned node id; d: depth @@ -1347,10 +1333,6 @@ BEGIN END; $$; -COMMIT; - -BEGIN; - -- List literal: '[' consumed. Trailing comma allowed. '?e' elements -- (optionals extension) record their indices under "opt". CREATE OR REPLACE FUNCTION cel._p_list( @@ -1750,10 +1732,6 @@ BEGIN END; $$; -COMMIT; - -BEGIN; - -- Macro expanders. Each has the registry signature -- (target jsonb, args jsonb, next_id bigint) -- -> (expr jsonb, next_id bigint, err text) @@ -2178,5 +2156,3 @@ BEGIN 'macro_calls', fin.macro_calls)); END; $$; - -COMMIT; diff --git a/sql/040_check.sql b/sql/040_check.sql index 0cafdc1..03aeb6c 100644 --- a/sql/040_check.sql +++ b/sql/040_check.sql @@ -16,8 +16,6 @@ -- Errors fail fast: conformance asserts on check-failure existence, -- never on collecting several. -BEGIN; - -- Type formatting for error messages (checker/format.go, loosely). CREATE OR REPLACE FUNCTION cel._t_fmt(t jsonb) RETURNS text @@ -446,10 +444,6 @@ BEGIN END; $$; -COMMIT; - -BEGIN; - -- Fresh type variables and parameter instantiation. CREATE OR REPLACE FUNCTION cel._ck_collect_params(t jsonb) RETURNS text[] @@ -763,10 +757,6 @@ BEGIN END; $$; -COMMIT; - -BEGIN; - -- Literal kinds to checker types. CREATE OR REPLACE FUNCTION cel._ck_lit_type(v jsonb) RETURNS jsonb @@ -1347,5 +1337,3 @@ SET search_path = cel, pg_temp AS $$ SELECT cel.check(ast, env, NULL); $$; - -COMMIT; diff --git a/sql/050_eval.sql b/sql/050_eval.sql index 4146557..5cba410 100644 --- a/sql/050_eval.sql +++ b/sql/050_eval.sql @@ -10,8 +10,6 @@ -- the attribute machinery, everything else EXECUTEs the row's impl. -- No CASE on a function name anywhere -- day-one invariant 1. -BEGIN; - -- Signature match for runtime overload selection: does an evaluated -- argument satisfy a declared argument type? Parameterized and -- dynamic types erase to "match anything" at runtime; containers @@ -856,5 +854,3 @@ BEGIN RETURN cel.eval(ast, activation, env); END; $$; - -COMMIT; diff --git a/sql/060_stdlib.sql b/sql/060_stdlib.sql index 85d89f4..8e8715b 100644 --- a/sql/060_stdlib.sql +++ b/sql/060_stdlib.sql @@ -12,8 +12,6 @@ -- with the three non-finite sentinels, Go-style truncated division -- and remainder. -BEGIN; - -- Integer (int64) checked arithmetic. Postgres numeric is exact, so -- overflow is a range check, not a wraparound. @@ -576,10 +574,6 @@ AS $$ SELECT args[1]; $$; -COMMIT; - -BEGIN; - -- Overload rows. Ids are cel-go's exactly (common/overloads); the -- checker binds them and conformance's type_deduction output depends -- on them. The absorbed ids carry NULL impls -- the evaluator core @@ -802,10 +796,6 @@ INSERT INTO cel.env_item (env, kind, ref) SELECT 'standard', 'type', name FROM cel.type ON CONFLICT DO NOTHING; -COMMIT; - -BEGIN; - -- Part 2: type conversions and string functions. Conversion -- semantics are cel-go's exactly (common/types + overflow.go, -- measured): double-to-int excludes both 2^63 boundaries, string @@ -1281,5 +1271,3 @@ ON CONFLICT (id) DO UPDATE SET INSERT INTO cel.env_item (env, kind, ref) SELECT 'standard', 'overload', id FROM cel.overload ON CONFLICT DO NOTHING; - -COMMIT; diff --git a/sql/070_wkt.sql b/sql/070_wkt.sql index 5bf51c7..e598a7e 100644 --- a/sql/070_wkt.sql +++ b/sql/070_wkt.sql @@ -8,8 +8,6 @@ -- Semantics are cel-go v0.32.0's (common/types/timestamp.go, -- duration.go, overflow.go), confirmed by conformance runs. -BEGIN; - -- Range-checked constructors ------------------------------------------ -- Seconds range is year 0001..9999 (timestamp.go:54-56); outside it @@ -531,10 +529,6 @@ AS $$ trunc((args[1] ->> 'v')::numeric / 1000000) % 1000); $$; -COMMIT; - -BEGIN; - -- Construction impls --------------------------------------------------- -- Each receives the evaluated fields as a jsonb object of tagged -- values (050_eval.sql struct branch). Wrappers unwrap to their @@ -881,5 +875,3 @@ ON CONFLICT DO NOTHING; INSERT INTO cel.env_item (env, kind, ref) SELECT 'standard', 'overload', id FROM cel.overload ON CONFLICT DO NOTHING; - -COMMIT; diff --git a/sql/100_ext_comprehensions.sql b/sql/100_ext_comprehensions.sql index 15f193d..851c269 100644 --- a/sql/100_ext_comprehensions.sql +++ b/sql/100_ext_comprehensions.sql @@ -10,8 +10,6 @@ -- because initdb runs only the directory's top level; a -- subdirectory would silently not install. -BEGIN; - -- Extracts and validates the two iteration variables -- (ext/comprehensions.go extractIterVars). CREATE OR REPLACE FUNCTION cel._mx2_vars( @@ -355,5 +353,3 @@ INSERT INTO cel.env_item (env, kind, ref) VALUES ('two_var_comprehensions', 'overload', '@mapInsert_map_key_value'), ('two_var_comprehensions', 'overload', '@mapInsert_map_map') ON CONFLICT DO NOTHING; - -COMMIT; diff --git a/sql/110_ext_optionals.sql b/sql/110_ext_optionals.sql index 422167a..34a7763 100644 --- a/sql/110_ext_optionals.sql +++ b/sql/110_ext_optionals.sql @@ -11,8 +11,6 @@ -- (day-one invariant 3: extension types are registry rows over the -- opaque kind, never new core kinds). -BEGIN; - CREATE OR REPLACE FUNCTION cel._opt_of(v jsonb) RETURNS jsonb LANGUAGE sql @@ -153,10 +151,6 @@ INSERT INTO cel.env_item (env, kind, ref) VALUES ('optionals', 'overload', 'optional_hasValue') ON CONFLICT DO NOTHING; -COMMIT; - -BEGIN; - -- Part two: the optional-syntax operators, or/orValue, and the -- optMap/optFlatMap macros (cel/library.go optionals block, -- cel/library.go:430-560 at the pinned v0.32.0). @@ -493,5 +487,3 @@ INSERT INTO cel.env_item (env, kind, ref) VALUES ('optionals', 'macro', 'optMap/2/1'), ('optionals', 'macro', 'optFlatMap/2/1') ON CONFLICT DO NOTHING; - -COMMIT; diff --git a/sql/120_ext_strings.sql b/sql/120_ext_strings.sql index dafb054..4ad59e3 100644 --- a/sql/120_ext_strings.sql +++ b/sql/120_ext_strings.sql @@ -10,8 +10,6 @@ -- offset error instead of returning -1 -- the corpus and cel-java -- agree against cel-go v0.32.0 there. -BEGIN; - CREATE OR REPLACE FUNCTION cel._str_val(s text) RETURNS jsonb LANGUAGE sql @@ -351,10 +349,6 @@ BEGIN END; $$; -COMMIT; - -BEGIN; - -- string.format ------------------------------------------------------ -- Round-half-even of an exact numeric at scale p, returned as a @@ -795,5 +789,3 @@ WHERE id IN ( 'list_join', 'list_join_string', 'strings_quote', 'string_format') ON CONFLICT DO NOTHING; - -COMMIT; diff --git a/sql/130_ext_math.sql b/sql/130_ext_math.sql index 9fb3ac4..740a5ff 100644 --- a/sql/130_ext_math.sql +++ b/sql/130_ext_math.sql @@ -8,8 +8,6 @@ -- mod by exact powers of two) because Postgres bigint shifts take -- the count mod 64, and uint64 values do not fit bigint. -BEGIN; - CREATE OR REPLACE FUNCTION cel._math_ident(args jsonb[]) RETURNS jsonb LANGUAGE sql @@ -647,5 +645,3 @@ INSERT INTO cel.env_item (env, kind, ref) VALUES ('math', 'macro', 'least/-1/1'), ('math', 'macro', 'greatest/-1/1') ON CONFLICT DO NOTHING; - -COMMIT; diff --git a/sql/140_ext_lists.sql b/sql/140_ext_lists.sql index ecfb4a8..b3e0c5d 100644 --- a/sql/140_ext_lists.sql +++ b/sql/140_ext_lists.sql @@ -2,8 +2,6 @@ -- slice, flatten, sort, sortBy (macro over @sortByAssociatedKeys), -- lists.range, reverse, distinct. Registered under the 'lists' env. -BEGIN; - CREATE OR REPLACE FUNCTION cel._list_val(elems jsonb) RETURNS jsonb LANGUAGE sql @@ -408,5 +406,3 @@ ON CONFLICT DO NOTHING; INSERT INTO cel.env_item (env, kind, ref) VALUES ('lists', 'macro', 'sortBy/2/1') ON CONFLICT DO NOTHING; - -COMMIT; diff --git a/sql/150_ext_encoders.sql b/sql/150_ext_encoders.sql index be76866..0994608 100644 --- a/sql/150_ext_encoders.sql +++ b/sql/150_ext_encoders.sql @@ -2,8 +2,6 @@ -- v0.32.0): base64.encode / base64.decode. Registered under the -- 'encoders' env. -BEGIN; - -- Go accepts both padded and raw (unpadded) standard base64 -- (encoders.go:143-150); Postgres decode requires padding, so pad -- first. @@ -60,5 +58,3 @@ INSERT INTO cel.env_item (env, kind, ref) VALUES ('encoders', 'overload', 'base64_decode_string'), ('encoders', 'overload', 'base64_encode_bytes') ON CONFLICT DO NOTHING; - -COMMIT; diff --git a/sql/160_ext_bindings.sql b/sql/160_ext_bindings.sql index 74511db..05d07b2 100644 --- a/sql/160_ext_bindings.sql +++ b/sql/160_ext_bindings.sql @@ -3,8 +3,6 @@ -- bind-style comprehension (empty range, accumulator = the bound -- variable). Registered under the 'bindings' env. -BEGIN; - CREATE OR REPLACE FUNCTION cel._mx_cel_bind( target jsonb, args jsonb, next_id bigint, OUT expr jsonb, OUT next_id_out bigint, OUT err text @@ -62,5 +60,3 @@ ON CONFLICT (name, arity, member) DO UPDATE INSERT INTO cel.env_item (env, kind, ref) VALUES ('bindings', 'macro', 'bind/3/1') ON CONFLICT DO NOTHING; - -COMMIT; diff --git a/sql/170_ext_network.sql b/sql/170_ext_network.sql index 6774c36..66d57a8 100644 --- a/sql/170_ext_network.sql +++ b/sql/170_ext_network.sql @@ -13,8 +13,6 @@ -- zone suffixes, no IPv4-mapped IPv6, and a CIDR requires an -- explicit /bits. -BEGIN; - -- Strict address parse. Returns the canonical text or NULL when the -- input is not a valid address under netip.ParseAddr rules. CREATE OR REPLACE FUNCTION cel._net_parse_ip(s text) @@ -519,5 +517,3 @@ INSERT INTO cel.env_item (env, kind, ref) VALUES ('network', 'type', 'net.IP'), ('network', 'type', 'net.CIDR') ON CONFLICT DO NOTHING; - -COMMIT; From 431f21233bac47cb4b8ab5891982bebd4288f126 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lemuel=20Roberto=20Bonif=C3=A1cio?= Date: Wed, 30 Sep 2026 13:36:41 -0300 Subject: [PATCH 2/2] Number the next release 0.0.2 The artifact set changed shape: plain files lost their transaction control and -tx twins were added. A consumer pinning 0.0.1 must not receive files that behave differently under the same name. --- sql/000_install.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/000_install.sql b/sql/000_install.sql index 80aecfd..6392735 100644 --- a/sql/000_install.sql +++ b/sql/000_install.sql @@ -24,7 +24,7 @@ CREATE TABLE IF NOT EXISTS cel.schema_version ( ); INSERT INTO cel.schema_version (version) -VALUES ('0.0.1') +VALUES ('0.0.2') ON CONFLICT (version) DO NOTHING; -- The installed schema version. IMMUTABLE is deliberately wrong for