This section explains new features related to SQL statements.
3.2.1 NUMERIC data type
Negative numbers can now be specified for NUMERIC type scales. If a negative number is specified, it will be rounded to the specified digit. Also, the range of values that can be specified for the scale has been extended from -1,000 to 1,000.
Example 37Negative number for NUMERIC
postgres=> CREATE TABLE type1( c1 NUMERIC(5, -2) ) ;
CREATE TABLE
postgres=> INSERT INTO type1 VALUES (12345.678) ;
INSERT 0 1
postgres=> INSERT INTO type1 VALUES (1234567.89) ;
INSERT 0 1
postgres=> INSERT INTO type1 VALUES (12345678.901) ;
ERROR: numeric field overflow
DETAIL: A field with precision 5, scale -2 must round to an absolute value
less than 10^7.
postgres=> INSERT INTO type1 VALUES (-1234567.89) ;
INSERT 0 1
postgres=> SELECT * FROM type1 ;
c1
----------
12300
1234600
The syntax for tracking the version of a collation has been added to the ALTER DATABASE statement. Syntax
ALTERDATABASEdatabase_nameREFRESHCOLLATIONVERSION
Added a new function pg_database_collation_actual_version to get the collation version and a datcollversion column for the version in the pg_database view. If it detects that the collation version of the database is different from the operating system, a warning will be output when connecting to the corresponding database. Below is an example of migration from Red Hat Enterprise Linux 7.8 to Red Hat Enterprise Linux 8.6.
The SET ACCESS METHOD clause can now be specified in ALTER TABLE statements that change the access method for a table; the SET ACCESS METHOD clause can also be specified in ALTER MATERIALIZED VIEW statements.
PDF page 37
Syntax
ALTER TABLE table_name SET ACCESS METHOD method_name
ALTER MATERIALIZED VIEW view_name SET ACCESS METHOD method_name
Example 39Execute ALTER TABLE statement
postgres=> ALTER TABLE data1 SET ACCESS METHOD heap ;
ALTER TABLE
The following enhancements have been added to the COPY statement.
COPY TO statement
The format ’text’ and header ’true’ can now be used simultaneously in the COPY TO statement options. At the same time, the file_fdw extension can now enable headers in text format.
Example 40Text Format and Header
postgres=# CREATE EXTENSION file_fdw ;
CREATE EXTENSION
postgres=# CREATE SERVER textsvr FOREIGN DATA WRAPPER file_fdw ;
CREATE SERVER
postgres=# CREATE FOREIGN TABLE text1(c1 INT, c2 VARCHAR(10)) SERVER textsvr
OPTIONS (filename '/tmp/data.txt', format 'text', header 'true') ;
CREATE FOREIGN TABLE
postgres=# COPY data1 TO '/home/postgres/data1.txt' (FORMAT text, HEADER true) ;
COPY 100
postgres=# \! cat data1.txt
c1 c2
1 data1
…
PDF page 38
COPY FROM statement
The HEADER option can now be specified as ‘match’. When this option is specified, COPY FROM checks that the header row and column names match when the COPY FROM statement is executed. In the example below, the first row of the CSV file and the column names in the table are different, resulting in an error.
Example 41Header check
postgres=# \! cat /tmp/csvlog1.csv
c1,c3
1,data1
2,data2
3,data3
postgres=# COPY csvlog1 FROM '/tmp/csvlog1.csv' WITH
(format 'csv', header 'match') ;
ERROR: column name mismatch in header line field 2: got "c3", expected "c2"
CONTEXT: COPY csvlog1, line 1: "c1,c3"
3.2.5 CLUSTER
The CLUSTER statements can now be executed on partitioned tables.
Example 42Clustering of partition tables
postgres=> CREATE TABLE part1 (c1 INT PRIMARY KEY, c2 VARCHAR(10))
PARTITION BY LIST(c1) ;
CREATE TABLE
postgres=> CLUSTER part1 USING part1_pkey ;
CLUSTER
3.2.6 CREATE DATABASE
The following enhancements have been implemented for the CREATE DATABASE statement
ICU Locale
The CREATE DATABASE statement now includes a LOCALE_PROVIDER clause to specify the locale provider, an ICU_LOCALE clause to specify the ICU locale, and a COLLATION_VERSION clause to specify the collation version.
The STRATEGY clause has been added to the CREATE DATABASE statement to specify how the database should be created; specifying WAL_LOG in the STRATEGY clause will cause the new database to be copied from the template block by block, with information for each block output to WAL. This is an effective method when the template is small and is the default value. Specify FILE_COPY to perform the behavior of the previous version.
Column lists can now be specified in the ON DELETE SET NULL and SET DEFAULT clauses of foreign key definitions in CREATE TABLE and ALTER TABLE statements. In the previous version, it was not possible to specify columns. The confdelsetcols column has been added to the pg_constraint catalog.
PDF page 40
Example 46ON Specify DELETE SET NULL clause
postgres=> CREATE TABLE pktable1 (
tid INT,
id INT,
name1 VARCHAR(10), PRIMARY KEY (tid, id)) ;
CREATE TABLE
postgres=> CREATE TABLE fktable1 (
tid INT,
id INT,
fk_id_del_set_null INT,
fk_id_del_set_default INT DEFAULT 0,
FOREIGN KEY (tid, fk_id_del_set_null) REFERENCES pktable1
ON DELETE SET NULL (fk_id_del_set_null),
FOREIGN KEY (tid, fk_id_del_set_default) REFERENCES pktable1
ON DELETE SET DEFAULT (fk_id_del_set_default)
) ;
CREATE TABLE
3.2.8 CREATE UNIQUE INDEX
It is now possible to specify NULLS DISTINCT and NULLS NOT DISTINCT for the unique index attribute. Multiple null values can be stored in a unique index with the NULLS DISTINCT clause. If nothing is specified, the NULLS DISTINCT specification is the default. An index with the NULLS NOT DISTINCT clause cannot contain multiple null values. An indnullsnotdistinct column has been added to the pg_index catalog to indicate this attribute. Syntax
CREATE UNIQUE INDEX index_name ON … NULLS [NOT] DISTINCT
CONSTRAINT constraint_name NULLS [NOT] DISTINCT
PDF page 41
Example 47Create UNIQUE INDEX with NULLS DISTINCT clause
postgres=> CREATE TABLE data1(c1 INT, c2 INT, c3 VARCHAR(10)) ;
CREATE TABLE
postgres=> CREATE UNIQUE INDEX idx1_data1 ON data1(c1) NULLS DISTINCT ;
CREATE INDEX
postgres=> CREATE UNIQUE INDEX idx2_data1 ON data1(c2) NULLS NOT DISTINCT ;
CREATE INDEX
postgres=> INSERT INTO data1 VALUES (1, 1, 'data1') ;
INSERT 0 1
postgres=> INSERT INTO data1 VALUES (2, NULL, 'data2') ;
INSERT 0 1
postgres=> INSERT INTO data1 VALUES (NULL, 3, 'data3') ;
INSERT 0 1
postgres=> INSERT INTO data1 VALUES (NULL, NULL, 'data4') ;
ERROR: duplicate key value violates unique constraint "idx2_data1"
DETAIL: Key (c2)=(null) already exists.
postgres=> INSERT INTO data1 VALUES (NULL, 5, 'data5') ;
INSERT 0 1
postgres=> CREATE TABLE const1(c1 INT UNIQUE NULLS NOT DISTINCT, c2 INT) ;
CREATE TABLE
postgres=> ALTER TABLE const1 ADD CONSTRAINT uniq1 UNIQUE NULLS DISTINCT (c2) ;
ALTER TABLE
3.2.9 CREATE SEQUENCE
The UNLOGGED clause can now be specified in the CREATE SEQUENCE statement to suppress WAL output. The sequence created by the CREATE UNLOGGED SEQUENCE statement has the repersistence column in the pg_class catalog as ‘u’. The attributes of the sequence can be changed with the ALTER SEQUENCE SET LOGGED statement or the ALTER SEQUENCE SET UNLOGGED statement.
PDF page 42
Example 49Create UNLOGGED SEQUENCE
postgres=> CREATE UNLOGGED SEQUENCE seq1 ;
CREATE SEQUENCE
postgres=> \d seq1
Unlogged sequence "public.seq1"
Type | Start | Minimum | Maximum | Increment | Cycles? | Cache
--------+-------+---------+---------------------+-----------+---------+-------
bigint | 1 | 1 | 9223372036854775807 | 1 | no | 1
postgres=> SELECT relname, relpersistence FROM pg_class WHERE relname = 'seq1' ;
relname | relpersistence
---------+----------------
seq1 | u
(1 row)
postgres=> ALTER SEQUENCE seq1 SET LOGGED ;
ALTER SEQUENCE
If the instance crashes, UNLOGGED SEQUENCE will be reset to its default value.
3.2.10 CREATE VIEW
The security_invoker option has been added to the CREATE VIEW statement. By default, access to the table from which the view is based is enforced with the privileges of the view owner. When the security_invoker option is set to True for a view, access to the table is subject to the privileges of the user accessing the view. This option can also be specified in the ALTER VIEW statement. Syntax
CREATE VIEW view_name WITH (security_invoker = true|false) AS sql_clause
ALTER VIEW view_name SET (security_invoker = true|false)
ALTER VIEW view_name RESET (security_invoker)
Example 50Security_invoker option
postgres=> CREATE VIEW view1 WITH(security_invoker) AS SELECT * FROM data1 ;
CREATE VIEW
PDF page 43
3.2.11 EXPLAIN
I/O time for temporary files is now output when BUFFERS and VERBOSE are specified in JSON format.
Example 51Output of temporary file I/O time
postgres=# SET track_io_timing = on ;
SET
postgres=# EXPLAIN (ANALYZE, BUFFERS, VERBOSE, FORMAT JSON)
SELECT * FROM data1 ;
QUERY PLAN
----------------------------------------------------
[ +
…
"I/O Write Time": 0.000, +
"Temp I/O Read Time": 0.000, +
"Temp I/O Write Time": 0.000 +
}
…
3.2.12 GRANT
Roles can now be granted permission to change specific parameters through the ALTER SYSTEM statement. Syntax
GRANT {ALTER SYSTEM | SET} ON PARAMETER parameter_name TO role_spec
REVOKE {ALTER SYSTEM | SET} ON PARAMETER parameter_name FROM role_spec
PDF page 44
Example 52Execute GRANT ALTER SYSTEM statement
postgres=# GRANT ALTER SYSTEM ON PARAMETER log_statement TO demo ;
GRANT
postgres=# SELECT * FROM pg_parameter_acl ;
-[ RECORD 1 ]-----------------------------------
oid | 16385
parname | log_statement
paracl | {postgres=sA/postgres,demo=A/postgres}
postgres=# \connect postgres demo
You are now connected to database "postgres" as user "demo".
postgres=> ALTER SYSTEM SET log_statement = 'all' ;
ALTER SYSTEM
3.2.13 MERGE
The MERGE statement that simultaneously executes INSERT / DELETE / UPDATE statements on a table from a join condition is now supported. Tuples matching the join condition can be specified in the WHEN MATCHED clause to update (UPDATE) or delete (DELETE) or do nothing (DO NOTHING). Additional conditions may be specified. The behavior of tuples that do not match the condition is specified in the WHEN NOT MATCHED clause. Syntax
postgres=> MERGE INTO dst1 AS d USING src1 AS s ON d.c1 = s.c1
WHEN MATCHED THEN
UPDATE SET c2 = s.c2
WHEN NOT MATCHED THEN
INSERT VALUES (s.c1, s.c2) ;
MERGE 2
postgres=> MERGE INTO dst1 AS d USING src1 AS s ON d.c1 = s.c1
WHEN MATCHED AND s.c1 < 1000 THEN
DELETE
WHEN NOT MATCHED THEN
DO NOTHING ;
MERGE 2
postgres=> WITH data1 AS (
MERGE INTO dst1 USING src1 ON (true)
WHEN MATCHED THEN DELETE
) SELECT * FROM data1 ;
ERROR: MERGE not supported in WITH query
LINE 1: WITH data1 AS (
^
3.2.14 VACUUM
The execution log of the VACUUM VERBOSE statement has changed significantly. Average read rate, buffer usage, WAL output information, etc. have been added. Details on how pg_class.relfrozenxid and pg_class.relminmxid have progressed are also now reported.
PDF page 46
Example 55Execute VACUUM VERBOSE statement
postgres=> VACUUM VERBOSE data1 ;
INFO: vacuuming "postgres.public.data1"
INFO: finished vacuuming "postgres.public.data1": index scans: 1
pages: 0 removed, 5406 remain, 5406 scanned (100.00% of total)
tuples: 500000 removed, 500000 remain, 0 are dead but not yet removable
removable cutoff: 757, which was 0 XIDs old when operation ended
…
avg read rate: 0.000 MB/s, avg write rate: 0.068 MB/s
buffer usage: 18975 hits, 0 misses, 1 dirtied
WAL usage: 18953 records, 0 full page images, 4007392 bytes
system usage: CPU: user: 0.11 s, system: 0.00 s, elapsed: 0.11 s
INFO: vacuuming "postgres.pg_toast.pg_toast_32787"
…
3.2.15 Functions
The following functions have been added/extended.
MAX / MIN
MAX function and MIN function for xid8 type have been implemented.
Replication related functions
The following function to get replication information has been added. These functions can be executed by a user with the SUPERUSER attribute or the pg_monitor role.
Function name
Description
pg_ls_logicalmapdir
Returns information in the pg_logical/mappings directory
pg_ls_logicalsnapdir
Returns information in the pg_logical/snapshots directory
pg_ls_replslotdir
Returns information in the pg_replslot/SLOTNAMEdirectory
Table 15Added functions
PDF page 47
Example 56Get Logical Replication information
postgres=# SELECT pg_create_physical_replication_slot('slot1') ;
pg_create_physical_replication_slot
-------------------------------------
(slot1,)
(1 row)
postgres=# SELECT * FROM pg_ls_replslotdir('slot1') ;
name | size | modification
-------+------+------------------------
state | 200 | 2022-10-14 09:52:04+09
(1 row)
postgres=# SELECT * FROM pg_ls_logicalsnapdir() ;
name | size | modification
----------------+------+------------------------
0-3005558.snap | 128 | 2022-10-14 00:01:29+09
(1 row1)
postgres=# SELECT * FROM pg_ls_logicalmapdir() ;
name | size | modification
------+------+--------------
(0 rows)
Internally, it uses the READ_REPLICATION_SLOT command to read the replication slot
information.
Pg_log_backend_memory_contexts
The check for SUPERUSER permission has been removed, and it can now be used by general users by granting permission using the GRANT statement.
Regular expression functions
The regexp_count, regexp_instr, and regexp_substr have been added as functions that handle regular expressions. Parameters that can be specified have been added to the regexp_replace function.
PDF page 48
Function name
Description
regexp_count
Returns the number of times the pattern is matched.
regexp_instr
Returns the location that matches the pattern.
regexp_like
Returns whether it matches the pattern.
regexp_replace
Replace the part that matches the pattern. Added start and flags options.
The starts_with function can now use BTREE indexes. At the same time, the ^@ operator will do the same.
Example 60Execution of the starts_with function
postgres=> EXPLAIN SELECT * FROM data1 WHERE c2 ^@ '999' ;
QUERY PLAN
------------------------------------------------------------------------------
Index Scan using idx2_data1 on data1 (cost=0.42..1337.98 rows=100 width=12)
Index Cond: ((c2 >= '999'::text) AND (c2 < '99:'::text))
Filter: (c2 ^@ '999'::text)
(3 rows)
postgres=> EXPLAIN SELECT * FROM data1 WHERE starts_with(c2, '999') ;
QUERY PLAN
------------------------------------------------------------------------------
Index Scan using idx2_data1 on data1 (cost=0.42..1337.98 rows=100 width=12)
Index Cond: ((c2 >= '999'::text) AND (c2 < '99:'::text))
Filter: starts_with(c2, '999'::text)
(3 rows)
Pg_settings_get_flags
Attribute information of GUC is returned as an array of text. If a non-existent GUC name is specified, NULL is returned.
PDF page 51
Example 61Execution of the pg_settings_get_flags function
The poly_distance function has been implemented. This function existed in previous versions, but when executed it returned an ERRCODE_FEATURE_NOT_SUPPORTED error.