diff --git a/sql/first_last_agg--0.1.4--0.1.5.sql b/sql/first_last_agg--0.1.4--0.1.5.sql index 82d135b..94be866 100644 --- a/sql/first_last_agg--0.1.4--0.1.5.sql +++ b/sql/first_last_agg--0.1.4--0.1.5.sql @@ -1,28 +1,51 @@ /* - * Make aggregate functions parallel safe, starting with PG10. + * Upgrade from 0.1.4 to 0.1.5: make aggregate functions parallel safe on + * supported server versions (PostgreSQL 12+). + * + * NOTE: upgrade limitations + * + * This upgrade requires PostgreSQL 12 or later. CREATE OR REPLACE AGGREGATE, + * which is needed to safely redefine aggregates that may have dependent + * objects, was introduced in PostgreSQL 12. Attempting this upgrade on an + * older version will raise an error; stay on 0.1.4 in that case. + * + * NOTE: parallel safety and sorted aggregates + * + * The primary use of first()/last() is with per-aggregate ORDER BY, such as + * "last(col ORDER BY sort_col)". + * As of PostgreSQL 18, PostgreSQL does not apply the Parallel Aggregate plan + * node to aggregates with ORDER BY or DISTINCT modifiers, so PARALLEL SAFE + + * COMBINEFUNC have no effect on query performance for that pattern. + * ref. https://www.postgresql.org/docs/18/parallel-plans.html#PARALLEL-AGGREGATION + * + * Parallel aggregation is currently only expected to apply outside of these + * cases. */ + DO $$ -DECLARE version_num integer; BEGIN - SELECT current_setting('server_version_num') INTO STRICT version_num; - IF version_num > 90600 THEN - EXECUTE $E$ ALTER FUNCTION last_sfunc(anyelement, anyelement) PARALLEL SAFE $E$; - EXECUTE $E$ ALTER FUNCTION first_sfunc(anyelement, anyelement) PARALLEL SAFE $E$; - - EXECUTE $E$ CREATE OR REPLACE AGGREGATE first(anyelement) ( - SFUNC = first_sfunc, - STYPE = anyelement, - COMBINEFUNC = first_sfunc, - parallel = SAFE - ); $E$; - - EXECUTE $E$ CREATE OR REPLACE AGGREGATE last(anyelement) ( - SFUNC = last_sfunc, - STYPE = anyelement, - COMBINEFUNC = last_sfunc, - parallel = SAFE - ); $E$; + IF current_setting('server_version_num')::integer < 120000 THEN + RAISE EXCEPTION + 'Upgrading first_last_agg to 0.1.5 requires PostgreSQL 12 or later ' + '(current version: %). Stay on version 0.1.4 or upgrade your PostgreSQL.', + current_setting('server_version'); END IF; END; $$; +ALTER FUNCTION last_sfunc(anyelement, anyelement) PARALLEL SAFE; +ALTER FUNCTION first_sfunc(anyelement, anyelement) PARALLEL SAFE; + +CREATE OR REPLACE AGGREGATE first(anyelement) ( + SFUNC = first_sfunc, + STYPE = anyelement, + COMBINEFUNC = first_sfunc, + PARALLEL = SAFE +); + +CREATE OR REPLACE AGGREGATE last(anyelement) ( + SFUNC = last_sfunc, + STYPE = anyelement, + COMBINEFUNC = last_sfunc, + PARALLEL = SAFE +); diff --git a/sql/first_last_agg--0.1.4--0.1.6.sql b/sql/first_last_agg--0.1.4--0.1.6.sql deleted file mode 100644 index 75a332e..0000000 --- a/sql/first_last_agg--0.1.4--0.1.6.sql +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Make aggregate functions parallel safe for supported server versions. - */ -DO $$ -DECLARE version_num integer; -BEGIN - SELECT current_setting('server_version_num') INTO STRICT version_num; - IF version_num > 90600 THEN - EXECUTE $E$ ALTER FUNCTION last_sfunc(anyelement, anyelement) PARALLEL SAFE $E$; - EXECUTE $E$ ALTER FUNCTION first_sfunc(anyelement, anyelement) PARALLEL SAFE $E$; - - EXECUTE $E$ DROP AGGREGATE IF EXISTS first(anyelement) $E$; - EXECUTE $E$ CREATE AGGREGATE first(anyelement) ( - SFUNC = first_sfunc, - STYPE = anyelement, - COMBINEFUNC = first_sfunc, - PARALLEL = SAFE - ) $E$; - - EXECUTE $E$ DROP AGGREGATE IF EXISTS last(anyelement) $E$; - EXECUTE $E$ CREATE AGGREGATE last(anyelement) ( - SFUNC = last_sfunc, - STYPE = anyelement, - COMBINEFUNC = last_sfunc, - PARALLEL = SAFE - ) $E$; - END IF; -END; -$$; diff --git a/sql/first_last_agg--0.1.5--0.1.4.sql b/sql/first_last_agg--0.1.5--0.1.4.sql index fe4578b..b75752e 100644 --- a/sql/first_last_agg--0.1.5--0.1.4.sql +++ b/sql/first_last_agg--0.1.5--0.1.4.sql @@ -1,24 +1,41 @@ /* - * Downgrade and create functions and aggregates without parallel safe. + * Downgrade from 0.1.5 to 0.1.4: remove parallel safety from aggregate + * functions. + * + * NOTE: downgrade limitations + * + * This downgrade requires PostgreSQL 12 or later, for the same reason as + * the upgrade: CREATE OR REPLACE AGGREGATE (needed to safely redefine + * aggregates with potential dependent objects) was introduced in PostgreSQL + * 12. + * Databases below PG 12 may have reached 0.1.5+ via a fresh installation + * or the old direct upgrade path (which used DROP+CREATE) if they had no + * dependency. Those databases cannot use this downgrade script. + * Since PG 10 and PG 11 are both EOL, no workaround is provided. If you face + * this problem, you will have to upgrade your PostgreSQL instance to at least + * PostgreSQL 12 in order to be able to downgrade the extension. */ + DO $$ -DECLARE version_num integer; BEGIN - SELECT current_setting('server_version_num') INTO STRICT version_num; - IF version_num > 90600 THEN - EXECUTE $E$ ALTER FUNCTION last_sfunc(anyelement, anyelement) PARALLEL UNSAFE $E$; - EXECUTE $E$ ALTER FUNCTION first_sfunc(anyelement, anyelement) PARALLEL UNSAFE $E$; - - EXECUTE $E$ CREATE OR REPLACE AGGREGATE first(anyelement) ( - SFUNC = first_sfunc, - STYPE = anyelement - ); $E$; - - EXECUTE $E$ CREATE OR REPLACE AGGREGATE last(anyelement) ( - SFUNC = last_sfunc, - STYPE = anyelement - ); $E$; + IF current_setting('server_version_num')::integer < 120000 THEN + RAISE EXCEPTION + 'Downgrading first_last_agg from 0.1.5 requires PostgreSQL 12 or later ' + '(current version: %).', + current_setting('server_version'); END IF; END; $$; +ALTER FUNCTION last_sfunc(anyelement, anyelement) PARALLEL UNSAFE; +ALTER FUNCTION first_sfunc(anyelement, anyelement) PARALLEL UNSAFE; + +CREATE OR REPLACE AGGREGATE first(anyelement) ( + SFUNC = first_sfunc, + STYPE = anyelement +); + +CREATE OR REPLACE AGGREGATE last(anyelement) ( + SFUNC = last_sfunc, + STYPE = anyelement +); diff --git a/sql/first_last_agg--0.1.5--0.1.6.sql b/sql/first_last_agg--0.1.5--0.1.6.sql index 4bea590..54978a8 100644 --- a/sql/first_last_agg--0.1.5--0.1.6.sql +++ b/sql/first_last_agg--0.1.5--0.1.6.sql @@ -1,4 +1,17 @@ /* - * Version 0.1.6 keeps the SQL object definitions from 0.1.5 unchanged. - * This release only adds a PostgreSQL 10-safe direct migration path from 0.1.4. + * No-op upgrade from 0.1.5 to 0.1.6. + * + * Version 0.1.6 introduces no changes to SQL object definitions. + * + * History of this upgrade path: + * - 0.1.4 defined the aggregates without parallel support. + * - 0.1.5 added PARALLEL SAFE + COMBINEFUNC, requiring PostgreSQL 12+. + * - 0.1.6 was originally intended to provide a PostgreSQL 10-safe direct: + * - migration path from 0.1.4 via DROP + CREATE with a dependency check + * - that approach has been superseded: 0.1.5+ now simply requires PG 12+ + * and uses CREATE OR REPLACE AGGREGATE + * - the SQL object definitions in 0.1.5 and 0.1.6 are therefore identical + * + * Databases already at 0.1.5 already have the parallel-safe definitions, so + * nothing needs to be done here. */ diff --git a/sql/first_last_agg--0.1.6--0.1.5.sql b/sql/first_last_agg--0.1.6--0.1.5.sql index 032ddac..4574ced 100644 --- a/sql/first_last_agg--0.1.6--0.1.5.sql +++ b/sql/first_last_agg--0.1.6--0.1.5.sql @@ -1,4 +1,7 @@ /* - * Version 0.1.6 keeps the SQL object definitions from 0.1.5 unchanged. - * This downgrade exists to preserve an explicit path between the tagged releases. + * No-op downgrade from 0.1.6 to 0.1.5. + * + * Version 0.1.6 and 0.1.5 have identical SQL object definitions, so there is + * nothing to revert. See first_last_agg--0.1.5--0.1.6.sql for the version + * history explaining why. */ diff --git a/sql/first_last_agg.sql b/sql/first_last_agg.sql index 3978568..b4c282e 100644 --- a/sql/first_last_agg.sql +++ b/sql/first_last_agg.sql @@ -20,6 +20,20 @@ CREATE AGGREGATE last(anyelement) ( STYPE = anyelement ); +/* + * NOTE: parallel safety and sorted aggregates + * + * The primary use of first()/last() is with per-aggregate ORDER BY, such as + * "last(col ORDER BY sort_col)". + * As of PostgreSQL 18, PostgreSQL does not apply the Parallel Aggregate plan + * node to aggregates with ORDER BY or DISTINCT modifiers, so PARALLEL SAFE + + * COMBINEFUNC have no effect on query performance for that pattern. + * ref. + * https://www.postgresql.org/docs/18/parallel-plans.html#PARALLEL-AGGREGATION + * + * So parallel aggregation is currently only expected to apply outside of these + * cases. + */ DO $$ DECLARE version_num integer; @@ -46,4 +60,4 @@ BEGIN ); $E$; END IF; END; -$$; \ No newline at end of file +$$;