diff --git a/.gitignore b/.gitignore index 3a1e33d..2534df1 100644 --- a/.gitignore +++ b/.gitignore @@ -5,5 +5,7 @@ sql/first_last_agg--0.1.2.sql sql/first_last_agg--0.1.3.sql sql/first_last_agg--0.1.4.sql sql/first_last_agg--0.1.5.sql +sql/first_last_agg--0.1.6.sql +!sql/first_last_agg--0.1.4.sql src/first_last_agg.o src/first_last_agg.so diff --git a/META.json b/META.json index e249478..387915c 100644 --- a/META.json +++ b/META.json @@ -1,7 +1,7 @@ { "name": "first_last_agg", "abstract": "Provides first() and last() aggregate functions.", - "version": "0.1.5", + "version": "0.1.6", "maintainer" : [ "adjustgmbh" ], @@ -11,7 +11,7 @@ "first_last_agg": { "file": "sql/first_last_agg.sql", "docfile": "doc/first_last_agg.md", - "version": "0.1.5", + "version": "0.1.6", "abstract": "Provides first() and last() aggregate functions." } }, diff --git a/first_last_agg.control b/first_last_agg.control index e48b417..abc25d8 100644 --- a/first_last_agg.control +++ b/first_last_agg.control @@ -1,5 +1,5 @@ # first_last_agg extension comment = 'first() and last() aggregate functions' -default_version = '0.1.5' +default_version = '0.1.6' module_pathname = '$libdir/first_last_agg' relocatable = true 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 new file mode 100644 index 0000000..75a332e --- /dev/null +++ b/sql/first_last_agg--0.1.4--0.1.6.sql @@ -0,0 +1,29 @@ +/* + * 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.4.sql b/sql/first_last_agg--0.1.4.sql new file mode 100644 index 0000000..1fcf654 --- /dev/null +++ b/sql/first_last_agg--0.1.4.sql @@ -0,0 +1,21 @@ +CREATE OR REPLACE FUNCTION last_sfunc(anyelement, anyelement) +RETURNS anyelement +AS '$libdir/first_last_agg', 'last_sfunc' +LANGUAGE C IMMUTABLE STRICT; + +CREATE OR REPLACE FUNCTION first_sfunc(anyelement, anyelement) +RETURNS anyelement +AS '$libdir/first_last_agg', 'first_sfunc' +LANGUAGE C IMMUTABLE STRICT; + +DROP AGGREGATE IF EXISTS first(anyelement); +CREATE AGGREGATE first(anyelement) ( + SFUNC = first_sfunc, + STYPE = anyelement +); + +DROP AGGREGATE IF EXISTS last(anyelement); +CREATE 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 new file mode 100644 index 0000000..4bea590 --- /dev/null +++ b/sql/first_last_agg--0.1.5--0.1.6.sql @@ -0,0 +1,4 @@ +/* + * 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. + */ 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 new file mode 100644 index 0000000..032ddac --- /dev/null +++ b/sql/first_last_agg--0.1.6--0.1.5.sql @@ -0,0 +1,4 @@ +/* + * 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. + */ diff --git a/test/expected/migration.out b/test/expected/migration.out new file mode 100644 index 0000000..931d0ff --- /dev/null +++ b/test/expected/migration.out @@ -0,0 +1,58 @@ +BEGIN; +SET client_min_messages TO 'WARNING'; +CREATE EXTENSION first_last_agg VERSION '0.1.5'; +SELECT extversion +FROM pg_extension +WHERE extname = 'first_last_agg'; + extversion +------------ + 0.1.5 +(1 row) + +ALTER EXTENSION first_last_agg UPDATE TO '0.1.6'; +SELECT extversion +FROM pg_extension +WHERE extname = 'first_last_agg'; + extversion +------------ + 0.1.6 +(1 row) + +DROP EXTENSION first_last_agg; +CREATE EXTENSION first_last_agg VERSION '0.1.4'; +SELECT extversion +FROM pg_extension +WHERE extname = 'first_last_agg'; + extversion +------------ + 0.1.4 +(1 row) + +ALTER EXTENSION first_last_agg UPDATE TO '0.1.6'; +SELECT extversion +FROM pg_extension +WHERE extname = 'first_last_agg'; + extversion +------------ + 0.1.6 +(1 row) + +CREATE TEMPORARY TABLE migration_test ( + akey integer, + val1 integer, + val2 integer +); +INSERT INTO migration_test (akey, val1, val2) +VALUES (1, 2, 1), (1, 4, 2), (1, 3, 3), + (2, 2, 1), (2, NULL, 2), (2, 5, 3); +SELECT akey, first(val1 ORDER BY val2) AS first, last(val1 ORDER BY val2) AS last +FROM migration_test +GROUP BY akey +ORDER BY akey; + akey | first | last +------+-------+------ + 1 | 2 | 3 + 2 | 2 | 5 +(2 rows) + +ROLLBACK; diff --git a/test/sql/migration.sql b/test/sql/migration.sql new file mode 100644 index 0000000..3e64b1d --- /dev/null +++ b/test/sql/migration.sql @@ -0,0 +1,45 @@ +BEGIN; +SET client_min_messages TO 'WARNING'; + +CREATE EXTENSION first_last_agg VERSION '0.1.5'; + +SELECT extversion +FROM pg_extension +WHERE extname = 'first_last_agg'; + +ALTER EXTENSION first_last_agg UPDATE TO '0.1.6'; + +SELECT extversion +FROM pg_extension +WHERE extname = 'first_last_agg'; + +DROP EXTENSION first_last_agg; + +CREATE EXTENSION first_last_agg VERSION '0.1.4'; + +SELECT extversion +FROM pg_extension +WHERE extname = 'first_last_agg'; + +ALTER EXTENSION first_last_agg UPDATE TO '0.1.6'; + +SELECT extversion +FROM pg_extension +WHERE extname = 'first_last_agg'; + +CREATE TEMPORARY TABLE migration_test ( + akey integer, + val1 integer, + val2 integer +); + +INSERT INTO migration_test (akey, val1, val2) +VALUES (1, 2, 1), (1, 4, 2), (1, 3, 3), + (2, 2, 1), (2, NULL, 2), (2, 5, 3); + +SELECT akey, first(val1 ORDER BY val2) AS first, last(val1 ORDER BY val2) AS last +FROM migration_test +GROUP BY akey +ORDER BY akey; + +ROLLBACK;