@@ -5,13 +5,18 @@ All notable changes to PL/Ruby are documented in this file.
55The format is based on [ Keep a Changelog] ( https://keepachangelog.com/en/1.1.0/ ) ,
66and the project aims to follow [ Semantic Versioning] ( https://semver.org/ ) .
77
8- ## [ Unreleased]
8+ ## [ 2.3.0] - 2026-07-05
9+
10+ Inline class definitions, the hstore transform, and transform coverage in
11+ every conversion context, including triggers. All plruby changes are in the
12+ shared library; ` ALTER EXTENSION plruby UPDATE ` completes the upgrade after
13+ installing the new binary.
914
1015### Added
1116
1217- ** Inline ` class ` /` module ` definitions in function bodies.** Bodies now
1318 compile to a top-level lambda (with a delegator method), where ` class ` is
14- legal — it was a SyntaxError anywhere inside the previous ` def ` -based
19+ legal; it was a SyntaxError anywhere inside the previous ` def ` -based
1520 compilation. Definitions register globally for the session, exactly like
1621 ` plruby_modules ` code, and work in functions, triggers, and ` DO ` blocks.
1722- ** Transforms reach nested contexts.** A ` TRANSFORM FOR TYPE ` declaration
@@ -22,50 +27,50 @@ and the project aims to follow [Semantic Versioning](https://semver.org/).
2227 ` return_next ` rows carry nested composite values.)
2328- ** Transforms in triggers.** A trigger function that declares
2429 ` TRANSFORM FOR TYPE ` receives transformed columns in ` $_TD['new'] ` /
25- ` $_TD['old'] ` and may put native Ruby data back via ` 'MODIFY' ` — going
30+ ` $_TD['old'] ` and may put native Ruby data back via ` 'MODIFY' ` , going
2631 beyond PL/Perl, whose transforms skip trigger data. Without the clause,
2732 triggers behave exactly as before.
28- - ** ` hstore_plruby ` ** — a companion extension (in ` hstore_plruby/ ` ) providing
33+ - ** ` hstore_plruby ` ** : a companion extension (in ` hstore_plruby/ ` ) providing
2934 ` TRANSFORM FOR TYPE hstore ` : opted-in functions receive hstore arguments as
3035 a Ruby ` Hash ` of String keys to String-or-` nil ` values and may return a
31- ` Hash ` into an hstore result (keys/values stringified, ` nil ` ↔ ` NULL ` ).
36+ ` Hash ` into an hstore result (keys/values stringified, ` nil ` maps to ` NULL ` in both directions ).
3237 Implemented against hstore's public SQL functions, so it needs no hstore
33- headers and works with the packaged hstore on PostgreSQL 11– 18.
38+ headers and works with the packaged hstore on PostgreSQL 11- 18.
3439
35- ## [ 2.2.0] — 2026-07-05
40+ ## [ 2.2.0] - 2026-07-05
3641
37- Native jsonb, modern Ruby, and CI. The ` jsonb_plruby ` companion extension
42+ Native jsonb, Ruby 3.3/3.4 support , and CI. The ` jsonb_plruby ` companion extension
3843exchanges jsonb with native Ruby data; RubyGems is enabled in the embedded
3944interpreter (restoring csv/bigdecimal/base64 on Ruby 3.4 and making
4045installed gems requirable); every push is now verified by GitHub Actions on
41- PostgreSQL 12– 18 and Ruby 3.2/3.3/3.4 (PG 11 verified out-of-band). All
46+ PostgreSQL 12- 18 and Ruby 3.2/3.3/3.4 (PG 11 verified out-of-band). All
4247plruby changes are in the shared library; ` ALTER EXTENSION plruby UPDATE `
4348completes the upgrade after installing the new binary.
4449
4550### Added
4651
47- - ** ` jsonb_plruby ` ** — a companion extension (in ` jsonb_plruby/ ` ) providing
52+ - ** ` jsonb_plruby ` ** : a companion extension (in ` jsonb_plruby/ ` ) providing
4853 ` TRANSFORM FOR TYPE jsonb ` : opted-in functions receive jsonb arguments as
4954 native Ruby data (` Hash ` /` Array ` /` String ` /` Integer ` /` Float ` /booleans/` nil ` )
5055 and return Ruby data into jsonb directly. Integers beyond ` Float ` precision
5156 and ` BigDecimal ` values serialize exactly.
52- - ** Structured ` pg_raise ` ** — `pg_raise(level, message, detail:, hint:,
57+ - ** Structured ` pg_raise ` ** : `pg_raise(level, message, detail:, hint:,
5358 sqlstate:)` maps the keywords onto the corresponding ` ereport` fields (like
5459 PL/pgSQL's ` RAISE ... USING ` ); a PL/Ruby caller that rescues the resulting
5560 error reads them back via ` PLRuby::Error#detail ` / ` #hint ` / ` #sqlstate ` .
56- - ** ` PLRuby::Error#detail ` / ` #hint ` ** — a caught database error now carries
61+ - ** ` PLRuby::Error#detail ` / ` #hint ` ** : a caught database error now carries
5762 its ` DETAIL ` and ` HINT ` alongside the SQLSTATE.
58- - ** Streaming ` spi_query_prepared ` ** — executes a prepared plan through a
63+ - ** Streaming ` spi_query_prepared ` ** : executes a prepared plan through a
5964 cursor (block form and ` PLRuby::Cursor ` handle form) instead of
6065 materializing; the plan stays reusable after the cursor closes. It was
6166 previously an alias of ` spi_exec_prepared ` .
62- - ** Regression suite 35 → 37 tests** (` replace ` : mid-session
67+ - ** Regression suite 35 to 37 tests** (` replace ` : mid-session
6368 ` CREATE OR REPLACE ` recompilation; extended ` misc ` /` sqlstate ` /` prepare ` ),
6469 plus the ` jsonb_plruby ` suite.
65- - ** CI (GitHub Actions)** — every push and pull request builds both
66- extensions and runs both suites on PostgreSQL 12– 18 (system Ruby 3.2) and
70+ - ** CI (GitHub Actions)** : every push and pull request builds both
71+ extensions and runs both suites on PostgreSQL 12- 18 (system Ruby 3.2) and
6772 on Ruby 3.3/3.4 (PostgreSQL 18).
68- - ** Ruby 3.3 and 3.4 support** — alternate expected files cover their
73+ - ** Ruby 3.3 and 3.4 support** : alternate expected files cover their
6974 changed ` NoMethodError ` /` Hash#inspect ` output; validation errors are
7075 reported as a single line (Ruby 3.4's parser quotes the generated wrapper
7176 source over many lines); the cookbook's token recipe encodes with
@@ -78,48 +83,48 @@ completes the upgrade after installing the new binary.
7883 arrived as the text-form String.
7984- ** RubyGems is enabled in the embedded interpreter** (was ` --disable-gems ` ):
8085 Ruby 3.4 ships ` csv ` , ` bigdecimal ` , and ` base64 ` as bundled gems, which
81- plain ` require ` cannot see without it — and installed gems become
86+ plain ` require ` cannot see without it, and installed gems become
8287 requirable as a side benefit. ` did_you_mean ` /` error_highlight ` are disabled
8388 so error messages stay deterministic. Verified on Ruby 3.2, 3.3, and 3.4
8489 (CI covers all three).
8590
86- ## [ 2.1.0] — 2026-07-05
91+ ## [ 2.1.0] - 2026-07-05
8792
8893Feature and hardening release: broader trigger and argument-mode coverage,
89- richer error objects, streaming SPI, a tested cookbook, and a regression
94+ error objects carrying SQLSTATE , streaming SPI, a tested cookbook, and a regression
9095suite grown to 35 tests verified on PostgreSQL 11 through 18. All changes
9196are in the shared library; ` ALTER EXTENSION plruby UPDATE ` completes the
9297upgrade after installing the new binary.
9398
9499### Added
95100
96- - ** Expanded regression suite** — 20 → 28 tests, verified on ** PostgreSQL 11,
101+ - ** Expanded regression suite** : 20 to 28 tests, verified on ** PostgreSQL 11,
97102 12, 13, 14, 16, and 18** with Ruby 3.2. New coverage: ` bytea ` conversion,
98103 special numeric/float values (` NaN ` , ` ±Infinity ` , integer overflow), nested
99104 and array-bearing composites, SPI DML status codes and NULL columns,
100105 DELETE-trigger ` $_TD['old'] ` handling, the error/` ensure ` model, prepared-plan
101106 reuse, standard-library ` require ` , ` $stdout ` /` $stderr ` redirection, quoting
102107 helpers, and ` plruby.start_proc ` .
103108
104- - ** Cursor streaming** — ` spi_query(sql) ` opens a portal and reads rows a batch
109+ - ** Cursor streaming** : ` spi_query(sql) ` opens a portal and reads rows a batch
105110 at a time, so large results stream without materializing. Block form
106- (` spi_query(sql) { |row| … } ` ), handle form (` spi_fetchrow ` /
111+ (` spi_query(sql) { |row| ... } ` ), handle form (` spi_fetchrow ` /
107112 ` spi_cursor_close ` ), and ` PLRuby::Cursor#each ` (Enumerable).
108- - ** Broader string encoding** — text is tagged with the Ruby encoding matching
109- the database encoding (LATIN* , WIN* , EUC* , SJIS, KOI8, Big5, GBK, … ), not just
113+ - ** Broader string encoding** : text is tagged with the Ruby encoding matching
114+ the database encoding (LATIN* , WIN* , EUC* , SJIS, KOI8, Big5, GBK, ... ), not just
110115 UTF-8; unmapped encodings fall back to ASCII-8BIT.
111- - ** ` PLRuby::Error#sqlstate ` ** — a caught PostgreSQL error now carries its
116+ - ** ` PLRuby::Error#sqlstate ` ** : a caught PostgreSQL error now carries its
112117 five-character ` SQLSTATE ` (e.g. ` 42P01 ` , ` 22012 ` ) on the Ruby exception; it
113118 is ` nil ` on a PL/Ruby error not backed by a database error.
114- - ** ` VARIADIC ` arguments** — the variadic tail arrives as a single Ruby
119+ - ** ` VARIADIC ` arguments** : the variadic tail arrives as a single Ruby
115120 ` Array ` argument (` VARIADIC "any" ` remains unsupported).
116- - ** ` INSTEAD OF ` triggers** on views — ` $_TD['when'] ` is ` INSTEAD OF ` , with
121+ - ** ` INSTEAD OF ` triggers** on views: ` $_TD['when'] ` is ` INSTEAD OF ` , with
117122 the same ` nil ` /` 'SKIP' ` /` 'MODIFY' ` return handling as BEFORE row triggers.
118- - ** Cookbook** — ` doc/cookbook.md ` , practical recipes built on Ruby's stdlib
123+ - ** Cookbook** : ` doc/cookbook.md ` , recipes built on Ruby's stdlib
119124 (JSON reshaping, HMAC/PBKDF2, audit trigger, CSV, Zlib-to-bytea, BigDecimal,
120125 slugify, ERB, streaming scans, batch commits); every recipe in the "tested"
121126 section runs verbatim in the regression suite (` cookbook ` test).
122- - ** Regression suite 28 → 35 tests** , adding ` datetime ` (date/time/timestamp/
127+ - ** Regression suite 28 to 35 tests** , adding ` datetime ` (date/time/timestamp/
123128 interval), ` jsonb ` , ` misc ` (uuid/inet/enum/domain), ` variadic ` , ` trigger2 `
124129 (INSTEAD OF, ` WHEN ` clauses, deferred constraint triggers, composite-column
125130 ` 'MODIFY' ` ), ` hostile ` (mid-SRF errors, cursor misuse, ~ 1MB TOAST values,
@@ -135,7 +140,7 @@ upgrade after installing the new binary.
135140 statement-level, return value ignored.
136141- ** ` spi_freeplan ` ** now invalidates the plan handle; reusing a freed plan
137142 raises a clear PL/Ruby error instead of silently failing.
138- - ** Trigger ` 'MODIFY' ` with composite columns** — the modified-tuple path is
143+ - ** Trigger ` 'MODIFY' ` with composite columns** : the modified-tuple path is
139144 now datum-based, so assigning a ` Hash ` to a composite-typed field of
140145 ` $_TD['new'] ` works (it previously failed with "malformed record literal").
141146- ** ` spi_fetchrow ` after ` spi_cursor_close ` ** now returns ` nil ` ; previously it
@@ -146,7 +151,7 @@ upgrade after installing the new binary.
146151- A function body compiles to a method, so a ` class ` /` module ` definition cannot
147152 appear inline in the body (use a ` plruby_modules ` module instead).
148153
149- ## [ 2.0.0] — 2026-07-01
154+ ## [ 2.0.0] - 2026-07-01
150155
151156The initial release of the modernized PL/Ruby: an MRI Ruby interpreter embedded
152157in PostgreSQL, packaged as a ` CREATE EXTENSION ` and offering the same feature
@@ -155,34 +160,34 @@ library, non-thread-safe embedding).
155160
156161### Added
157162
158- - ** Functions** with native Ruby argument and return types — ` Integer ` ,
163+ - ** Functions** with native Ruby argument and return types: ` Integer ` ,
159164 ` Float ` , ` true ` /` false ` , ` String ` , ` nil ` , nested ` Array ` (multidimensional
160165 PostgreSQL arrays), and composite/record types as ` Hash ` .
161- - ** Set-returning functions** — ` RETURNS SETOF ` and ` RETURNS TABLE(...) ` with
166+ - ** Set-returning functions** : ` RETURNS SETOF ` and ` RETURNS TABLE(...) ` with
162167 ` return_next ` (both explicit-value and no-argument forms, the latter reading
163168 the TABLE/OUT column locals from the running body's binding).
164- - ** Argument modes** — ` IN ` , ` OUT ` , ` INOUT ` , ` TABLE ` , and named parameters
169+ - ** Argument modes** : ` IN ` , ` OUT ` , ` INOUT ` , ` TABLE ` , and named parameters
165170 aliased as local variables.
166- - ** Trigger functions** — ` RETURNS trigger ` with the ` $_TD ` hash and
171+ - ** Trigger functions** : ` RETURNS trigger ` with the ` $_TD ` hash and
167172 ` nil ` /` 'SKIP' ` /` 'MODIFY' ` return semantics.
168- - ** Event trigger functions** — ` RETURNS event_trigger ` , with ` $_TD['event'] `
173+ - ** Event trigger functions** : ` RETURNS event_trigger ` , with ` $_TD['event'] `
169174 and ` $_TD['tag'] ` .
170- - ** Anonymous ` DO ` blocks** — ` DO $$ ... $$ LANGUAGE plruby ` .
171- - ** Database access (SPI)** — ` spi_exec ` , ` spi_fetch_row ` , ` spi_processed ` ,
175+ - ** Anonymous ` DO ` blocks** : ` DO $$ ... $$ LANGUAGE plruby ` .
176+ - ** Database access (SPI)** : ` spi_exec ` , ` spi_fetch_row ` , ` spi_processed ` ,
172177 ` spi_status ` , ` spi_rewind ` .
173- - ** Prepared statements** — ` spi_prepare ` , ` spi_exec_prepared ` ,
178+ - ** Prepared statements** : ` spi_prepare ` , ` spi_exec_prepared ` ,
174179 ` spi_query_prepared ` , and ` spi_freeplan ` .
175- - ** Transaction control** in procedures — ` spi_commit ` and ` spi_rollback ` .
176- - ** Explicit subtransactions** — ` subtransaction { ... } ` and
180+ - ** Transaction control** in procedures: ` spi_commit ` and ` spi_rollback ` .
181+ - ** Explicit subtransactions** : ` subtransaction { ... } ` and
177182 ` subtransaction(callable, ...) ` , rolling back and re-raising on any exception.
178- - ** Quoting helpers** — ` quote_literal ` , ` quote_nullable ` , ` quote_ident ` .
183+ - ** Quoting helpers** : ` quote_literal ` , ` quote_nullable ` , ` quote_ident ` .
179184- ** ` elog(level, message) ` ** supporting ` DEBUG ` /` LOG ` /` INFO ` /` NOTICE ` /` WARNING ` /` ERROR ` ,
180185 and the narrower ` pg_raise(level, message) ` .
181- - ** ` $_SHARED ` ** — a hash persisting across calls within a session; standard
186+ - ** ` $_SHARED ` ** : a hash persisting across calls within a session; standard
182187 output (` puts ` , ` print ` ) is forwarded to the server log.
183- - ** Session initialization** — module autoloading from a ` plruby_modules ` table
188+ - ** Session initialization** : module autoloading from a ` plruby_modules ` table
184189 and a ` plruby.start_proc ` configuration setting.
185- - ** UTF-8 string handling** — text from the database is tagged with the
190+ - ** UTF-8 string handling** : text from the database is tagged with the
186191 database encoding (UTF-8 when the database is UTF-8), so multibyte Ruby String
187192 operations (` length ` , ` reverse ` , regexp, ...) behave correctly.
188193- Packaging as a first-class extension (` CREATE EXTENSION plruby ` ) and a
0 commit comments