This section explains new features related to SQL statements.
3.2.1 ALTER CURRENT_ROLE
The statements that can specify CURRENT_USER clause, such as the ALTER AGGREGATE, ALTER CONVERSION, and ALTER DATABASE statements, can now also specify a CURRENT_ROLE clause.
Example 35ALTER DATABASE statement
postgres=# ALTER DATABASE demodb OWNER TO CURRENT_ROLE ;
ALTER DATABASE
3.2.2 ALTER SUBSCRIPTION
The syntax for adding/removing publications for existing subscriptions has been added. Specify ADD PUBLICATION clause or DROP PUBLICATION clause in the ALTER SUBSCRIPTION statement. Syntax
CONCURRENTLY clause can now be specified in the ALTER TABLE DETACH PARTITION statement. If CONCURRENTLY is specified, it will be executed at a lower lock level to avoid blocking other sessions that may be accessing the partitioned table. In this mode, two transactions are used internally and cannot be executed within a transaction block. Also, it cannot be executed on a partitioned table that contains the default partition. If FINALIZE is specified, the previous DETACH CONCURRENTLY call that was canceled or interrupted is completed.
Visibility Map is now updated with the execution of COPY FREEZE statement.
Example 36Check visibility map after executing COPY FREEZE statement
postgres=# BEGIN ;
BEGIN
postgres=*# TRUNCATE TABLE visible1 ;
TRUNCATE TABLE
postgres=*# COPY visible1 FROM '/home/postgres/visible1.csv'
CSV FREEZE ;
COPY 3
postgres=*# COMMIT ;
COMMIT
postgres=# SELECT * FROM pg_visibility_map('visible1', 0) ;
all_visible | all_frozen
-------------+------------
t | t
(1 row)
3.2.5 CREATE INDEX
The INCLUDE clause can now be specified when creating SP-GiST indexes.
PDF page 40
Example 37INCLUDE clause with SP-GiST index creation
postgres=> CREATE INDEX idx1_gist1 ON gist1 USING spgist (c1)
INCLUDE (c2) ;
CREATE INDEX
postgres=> \d+ idx1_gist1
Index "public.idx1_gist1"
Column | Type | Key? | Definition | Storage | Stats target
--------+------+------+------------+----------+--------------
c1 | text | yes | c1 | extended |
c2 | text | no | c2 | extended |
spgist, for table "public.gist1"
3.2.6 CREATE PROCEDURE/FUNCTION
The following enhancements have been implemented for the CREATE PROCEDURE and CREATE FUNCTION statements.
OUT clause
It is now possible to specify the OUT clause as a parameter of PROCEDURE.
PDF page 41
Example 38CREATE PROCEDURE statement
postgres=> CREATE PROCEDURE sum_n_product(x int, y int, OUT sum
int, OUT prod int) AS $$
BEGIN
sum := x + y ;
prod := x * y ;
END $$ LANGUAGE plpgsql ;
CREATE PROCEDURE
postgres=> SELECT proargmodes FROM pg_proc WHERE
proname='sum_n_product' ;
proargmodes
-------------
{i,i,o,o}
(1 row)
postgres=> CALL sum_n_product(2, 4, NULL, NULL) ;
sum | prod
-----+------
6 | 8
(1 row)
LANGUAGE SQL
When the LANGUAGE SQL clause is specified in the CREATE FUNCTION statement and CREATE PROCEDURE statement, it is not necessary to enclose it in character literals, and SQL standard-compliant syntax is supported. The source for FUNCTION / PROCEDURE created with this syntax is stored in the prosqlbody column of the pg_proc catalog.
Example 39LANGUAGE SQL
postgres=> CREATE PROCEDURE insert_data1(id INTEGER, val TEXT)
LANGUAGE SQL
BEGIN ATOMIC
INSERT INTO data1 VALUES (id, val) ;
INSERT INTO data1 VALUES (id, val) ;
END ;
CREATE PROCEDURE
PDF page 42
FUNCTION and PROCEDURE created in the standard format are aware of the dependencies of the objects they are used on. For this reason, when the DROP TABLE CASCADE statement is executed, FUNCTION with dependencies will be dropped at the same time.
Example 40DROP TABLE CASCADE statement
postgres=> CREATE PROCEDURE insert_data1(id NUMERIC, val TEXT)
LANGUAGE SQL
BEGIN ATOMIC
INSERT INTO data1 VALUES (id, val);
END ;
CREATE PROCEDURE
postgres=> DROP TABLE data1 ;
ERROR: cannot drop table data1 because other objects depend on it
DETAIL: function insert_data1(numeric,text) depends on table
data1
HINT: Use DROP ... CASCADE to drop the dependent objects too.
postgres=> DROP TABLE data1 CASCADE ;
NOTICE: drop cascades to function insert_data1(numeric,text)
DROP TABLE
3.2.7 CREATE TABLE
It is now possible to specify different values of COLLATION for partition boundaries.
Example 41CREATE TABLE statement
postgres=> CREATE TABLE part_coll (c1 TEXT) PARTITION BY RANGE
(c1 COLLATE "POSIX") ;
CREATE TABLE
postgres=> CREATE TABLE part_coll_p1 PARTITION OF part_coll FOR
VALUES FROM ('a' collate "C") to ('g') ;
CREATE TABLE
3.2.8 CREATE TRIGGER
The OR REPLACE clause can now be specified in the CREATE TRIGGER statement.
PDF page 43
Example 42CREATE OR REPLACE TRIGGER statement
postgres=> CREATE OR REPLACE TRIGGER data1_trig1 AFTER INSERT
ON data1 FOR EACH ROW EXECUTE FUNCTION data1_ins_func1 () ;
CREATE TRIGGER
3.2.9 CREATE TYPE
SUBSCRIPT clause that specifies the MULTIRANGE_TYPE_NAME clause and generic subscript access for the function you specify more than one range type has been added to the CREATE TYPE statement. Syntax
It is now possible to specify the GRANTED BY clause for granting roles with GRANT and REVOKE statements in accordance with the SQL standard. The GRANTED BY clause can only specify the current role that executes the GRANT statement, so it behaves the same as in previous versions. Syntax
GRANT role_name [, …] TO role_specification
[ WITH ADMIN OPTION ] [ GRANTED BY role_specification ]
REVOKE [ ADMIN OPTION FOR ] role_name [, …] FROM role_specification
[ GRANTED BY role_specification ] [ CASCADE | RESTRICT ]
PDF page 44
Example 43GRANTED BY clause
postgres=> GRANT SELECT ON data1 TO user1 GRANTED BY CURRENT_USER ;
GRANT
postgres=> GRANT SELECT ON data1 TO user1 GRANTED BY postgres ;
ERROR: grantor must be current user
3.2.11 INSERT
The following enhancements have been implemented in the INSERT statement.
ON CONFLICT clause
It is now possible to qualify a table name for a column specification in the WHERE clause in the ON CONFLICT clause.
Example 44Table qualified with ON CONFLICT clause
postgres=> INSERT INTO data1 AS d1 VALUES (10, 'data1') ON CONFLICT
(c1) WHERE d1.c2 = 'data1' DO NOTHING ;
INSERT 0 1
GENERATED ALWAYS clause
It is now possible to specify multi-tuple DEFAULT clause when executing an INSERT statement on a table that has a column with a GENERATED ALWAYS clause.
Example 45Multiple tuple DEFAULT clause
postgres=> CREATE TABLE gen1(c1 INT PRIMARY KEY, c2 INT
GENERATED ALWAYS AS (c1+1) STORED) ;
CREATE TABLE
postgres=> INSERT INTO gen1 VALUES (100, DEFAULT),(200, DEFAULT) ;
INSERT 0 2
postgres=> SELECT * FROM gen1 ;
c1 | c2
-----+-----
100 | 101
200 | 201
(2 rows)
PDF page 45
3.2.12 REINDEX
The following enhancements have been implemented to the REINDEX statement.
Partitioned table
It is now possible to specify a partitioned table for the REINDEX statement.
Example 46Execute REINDEX statement on a partitioned table
postgres=> CREATE TABLE part1(c1 NUMERIC, c2 VARCHAR(10))
PARTITION BY RANGE (c1) ;
CREATE TABLE
postgres=> CREATE TABLE part1v1 PARTITION OF part1 FOR VALUES
FROM (0) TO (100000) ;
CREATE TABLE
postgres=> CREATE TABLE part1v2 PARTITION OF part1 FOR VALUES
FROM (100000) TO (200000) ;
CREATE TABLE
postgres=> CREATE INDEX idx1_part1 ON part1(c1) ;
CREATE INDEX
postgres=> REINDEX TABLE part1 ;
REINDEX
Specifying the tablespace
Tablespaces for indexes can now be specified in the optional TABLESPACE clause.
PDF page 46
Example 47Specifying the tablespace
postgres=> REINDEX (TABLESPACE ts1, VERBOSE) INDEX idx1_data1 ;
INFO: index "idx1_data1" was reindexed
DETAIL: CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s
REINDEX
postgres=> REINDEX (TABLESPACE ts1, VERBOSE) TABLE data1 ;
INFO: index "data1_pkey" was reindexed
DETAIL: CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s
INFO: index "idx1_data1" was reindexed
DETAIL: CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s
INFO: index "pg_toast_16385_index" was reindexed
DETAIL: CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s
REINDEX
3.2.13 VACUUM
The following enhancements have been implemented in VACUUM.
TOAST table
The PROCESS_TOAST option can now be specified in the VACUUM statement. This option performs VACUUM processing on the TOAST table. This parameter is enabled by default. To disable processing of the TOAST table, specify the PROCESS_TOAST FALSE option.
Example 48VACUUM (PROCESS_TOAST) statement
postgres=> VACUUM (PROCESS_TOAST FALSE, VERBOSE) data1 ;
INFO: vacuuming "public.data1"
INFO: "data1": found 0 removable, 37 nonremovable row versions in
1 out of 5406 pages
DETAIL: 0 dead row versions cannot be removed yet, oldest xmin:
518
There were 38 unused item identifiers.
Skipped 0 pages due to buffer pins, 0 frozen pages.
0 pages are entirely empty.
CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s.
VACUUM
PDF page 47
Failsafe Mechanism
If it determines that the table’s relfrozenxid or relminmxid is dangerously past, VACUUM bypasses non-freeze processing. The parameters vacuum_failsafe_age and vacuum_multixact_failsafe_age have been added as these thresholds.
Bypass index vacuum
Allow vacuum to skip index vacuuming when the number of removable index entries is insignificant. The vacuum parameter INDEX_CLEANUP has a new default of auto that enables this optimization.
The following enhancements have been implemented to the SELECT statement.
Support for reserved words
In PostgreSQL 14, AS clause is no longer required even when a reserved word is specified as an alias for a column in the SELECT statement. The number of reserved words that cannot be used for aliases has been significantly reduced.
Example 50No AS clause required
postgres=> SELECT loc analyze FROM dept ;
analyze
---------
(0 rows)
PDF page 48
GROUP BY DISTINCT
It is now possible to specify DISTINCT to eliminate duplicates in the GROUP BY clause. It is also possible to specify ALL to output all (the default behavior is ALL).
Example 51GROUP BY DISTINCT
postgres=> SELECT a, b, c FROM (VALUES (1, 2, 3),
(4, NULL, 6), (7, 8, 9)) AS t (a, b, c)
GROUP BY ALL ROLLUP(a, b), ROLLUP(a, c) ORDER BY a, b, c ;
a | b | c
---+---+---
1 | 2 | 3
1 | 2 |
…
| |
(25 rows)
postgres=> SELECT a, b, c FROM (VALUES (1, 2, 3),
(4, NULL, 6), (7, 8, 9)) AS t (a, b, c) GROUP BY
DISTINCT ROLLUP(a, b), ROLLUP(a, c) ORDER BY a, b, c ;
a | b | c
---+---+---
1 | 2 | 3
1 | 2 |
…
| |
(13 rows)
SEARCH clause / CYCLE clause
The SEARCH and CYCLE clauses defined in the SQL standard can now be specified in the WITH clause of recursive SQL statements. The CYCLE clause is used for closed circuit detection, and the SEARCH clause can be used to specify depth-first search (DEPTH FIRST) or breadth-first search (BREADTH FIRST).
PDF page 49
Example 52SEARCH clause (DEPTH FIRST)
postgres=> CREATE TABLE graph0(f INT, t INT, label TEXT) ;
CREATE TABLE
postgres=> INSERT INTO graph0 VALUES (1, 2, 'arc 1 -> 2'),
(1, 3, 'arc 1 -> 3'), (2, 3, 'arc 2 -> 3'),
(1, 4, 'arc 1 -> 4'), (4, 5, 'arc 4 -> 5') ;
INSERT 0 5
postgres=> WITH RECURSIVE search_graph(f, t, label) AS (
SELECT * FROM graph0 g
UNION ALL
SELECT g.* FROM graph0 g, search_graph sg WHERE
g.f = sg.t
) SEARCH DEPTH FIRST BY f, t SET seq
SELECT * FROM search_graph ORDER BY seq ;
f | t | label | seq
---+---+------------+-------------------
1 | 2 | arc 1 -> 2 | {"(1,2)"}
2 | 3 | arc 2 -> 3 | {"(1,2)","(2,3)"}
1 | 3 | arc 1 -> 3 | {"(1,3)"}
1 | 4 | arc 1 -> 4 | {"(1,4)"}
4 | 5 | arc 4 -> 5 | {"(1,4)","(4,5)"}
2 | 3 | arc 2 -> 3 | {"(2,3)"}
4 | 5 | arc 4 -> 5 | {"(4,5)"}
(7 rows)
PDF page 50
Example 53SEARCH clause (BREADTH FIRST)
postgres=> WITH RECURSIVE search_graph(f, t, label) AS (
SELECT * FROM graph0 g
UNION ALL
SELECT g.* FROM graph0 g, search_graph sg WHERE g.f = sg.t
) SEARCH BREADTH FIRST BY f, t SET seq
SELECT * FROM search_graph ORDER BY seq ;
f | t | label | seq
---+---+------------+---------
1 | 2 | arc 1 -> 2 | (0,1,2)
1 | 3 | arc 1 -> 3 | (0,1,3)
1 | 4 | arc 1 -> 4 | (0,1,4)
2 | 3 | arc 2 -> 3 | (0,2,3)
4 | 5 | arc 4 -> 5 | (0,4,5)
2 | 3 | arc 2 -> 3 | (1,2,3)
4 | 5 | arc 4 -> 5 | (1,4,5)
(7 rows)
PDF page 51
Example 54CYCLE clause
postgres=> CREATE TABLE graph1(f INT, t INT, label TEXT) ;
CREATE TABLE
postgres=> INSERT INTO graph1 VALUES
(1, 2, 'arc 1 -> 2'), (1, 3, 'arc 1 -> 3'),
(2, 3, 'arc 2 -> 3'),
(1, 4, 'arc 1 -> 4'), (4, 5, 'arc 4 -> 5'),
(5, 1, 'arc 5 -> 1') ;
INSERT 0 6
postgres=> WITH RECURSIVE search_graph(f, t, label) AS (
SELECT * FROM graph1 g
UNION ALL
SELECT g.* FROM graph1 g, search_graph sg
WHERE g.f = sg.t
) CYCLE f, t SET is_cycle TO TRUE DEFAULT FALSE USING PATH
SELECT * FROM search_graph ;
f | t | label | is_cycle | path
---+---+------------+----------+---------------------------------
1 | 2 | arc 1 -> 2 | f | {"(1,2)"}
1 | 3 | arc 1 -> 3 | f | {"(1,3)"}
2 | 3 | arc 2 -> 3 | f | {"(2,3)"}
1 | 4 | arc 1 -> 4 | f | {"(1,4)"}
…
5 | 1 | arc 5 -> 1 | t | {"(5,1)","(1,4)","(4,5)","(5,1)"}
2
|
3
|
arc
2
->
3
|
f
|
{"(1,4)","(4,5)","(5,1)","(1,2)","(2,3)"}
(25 rows)
USING AS clause
It is now possible to use aliases for columns specified in the JOIN USING clause. Aliases are also available in the SELECT clause for the columns specified in the JOIN. This is a feature defined in SQL:2016 feature F404 “Range variable for common column names”.
PDF page 52
Example 55JOIN USING AS clause
postgres=> SELECT d1.c1, x.c1, x.c2 FROM data1 d1 JOIN data2 d2
USING (c1, c2) AS x ;
3.2.15 TRUNCATE
TRUNCATE statements can now be executed in FOREIGN TABLE if supported by FOREIGN DATA WRAPPER. The postgres_fdw module now supports the TRUNCATE statement.
It is now possible to specify a negative value for the third parameter of the split_part function. If a negative value is specified, the part from the right side of the string specified in the first parameter can be cut off.
Returns the paused state of recovery. Returns “not paused” if no pause was requested, “pause requested” if pause was requested but recovery is not paused, and “paused” if recovery is paused. In PostgreSQL 14, recovery is now paused if the required parameter values are missing. Syntax
The pg_log_backend_memory_contexts function outputs the memory status of the process with the specified ID as a LOG level message.
PDF page 58
Syntax
bool PG_LOG_BACKEND_MEMORY_CONTEXTS(pid integer)
Example 69Pg_log_backend_memory_contexts function
postgres=# SELECT pg_log_backend_memory_contexts(pg_backend_pid()) ;
LOG: logging memory contexts of PID 67300
STATEMENT: SELECT pg_log_backend_memory_contexts(pg_backend_pid());
LOG: level: 0; TopMemoryContext: 68704 total in 5 blocks; 14416 free (10
chunks); 54288 used
…
Pg_terminate_backend
The pg_terminate_backend function now has a parameter to specify a timeout. The function will return true if the session exits within the timeout. Syntax
This function outputs the time stamp and replication origin for the transaction ID. There is a need to specify ‘on’ the track_commit_timestamp the execution of this function. Syntax
record PG_XACT_COMMITTED_TIMESTAMP_ORIGIN(xid xid, OUT timestamp
timestamp with time zone, OUT roident oid)
PDF page 59
Example 70Pg_xact_commit_timestamp_origin function
postgres=# SHOW track_commit_timestamp ;
track_commit_timestamp
------------------------
on
(1 row)
postgres=# SELECT * FROM
pg_xact_commit_timestamp_origin(txid_current()::text::xid) ;
timestamp | roident
-----------+---------
|
(1 row)
Pg_last_committed_xact
The function now outputs a roident column indicating the replication origin in the execution result. Syntax
Added pg_get_catalog_foreign_keys function to retrieve information about foreign keys defined in a system catalog. This function can be run by general users.
Pg_create_logical_replication_slot
The parameter twophase has been added to support two-phase commit.
PDF page 60
Example 72Pg_create_logical_replication_slot function
postgres=# \dfS pg_create_logical_replication_slot
List of functions
-[ RECORD 1 ]-------+-------------------------------------------------------
Schema | pg_catalog
Name | pg_create_logical_replication_slot
Result data type | record
Argument data types | slot_name name, plugin name, temporary boolean DEFAULT
false, twophase boolean DEFAULT false, OUT slot_name name, OUT lsn pg_lsn
Type | func