This section explains new features related to SQL statements.
3.2.1 ALTER TABLE
It is now possible to change the attributes of some system catalogs.
Example 26Alter system catalog
postgres=# SHOW allow_system_table_mods ;
allow_system_table_mods
-------------------------
on
(1 row)
postgres=# ALTER TABLE pg_attribute SET
(autovacuum_vacuum_scale_factor=0) ;
ALTER TABLE
3.2.2 ALTER TYPE ADD VALUE
The ALTER TYPE ADD VALUE statement is now available within a transaction block. However, the added value cannot be used in the transaction block.
Example 27ALTER TYPE ADD VALUE statement in the transaction block
postgres=> BEGIN ;
BEGIN
postgres=> ALTER TYPE t1 ADD VALUE 'v3' ;
ALTER TYPE
3.2.3 COMMIT/ROLLBACK AND CHAIN
It became possible to add CHAIN clause which start a new transaction right after committing or discarding (ROLLBACK) the transaction. Specify the AND CHAIN clause in the COMMIT statement or ROLLBACK statement. Specify “AND NO CHAIN” to explicitly deny the CHAIN clause. These statements can also be used in PROCEDUREs using PL/pgSQL.
PDF page 33
Example 28COMMIT AND CHAIN
postgres=> BEGIN ;
BEGIN
postgres=> INSERT INTO data1 VALUES (100, 'data1') ;
INSERT 0 1
postgres=> COMMIT AND CHAIN ;
COMMIT
postgres=> INSERT INTO data1 VALUES (200, 'data2') ;
INSERT 0 1
postgres=> ROLLBACK AND CHAIN ;
ROLLBACK
postgres=> INSERT INTO data1 VALUES (300, 'data3') ;
INSERT 0 1
postgres=> COMMIT ;
COMMIT
In transactions started with the CHAIN clause, attributes such as transaction isolation level are
maintained from the previous transaction.
PDF page 34
Example 29Transaction attribute
postgres=> SHOW transaction_isolation ;
transaction_isolation
-----------------------
read committed
(1 row)
postgres=> BEGIN ISOLATION LEVEL SERIALIZABLE ;
BEGIN
postgres=> COMMIT AND CHAIN ;
COMMIT
postgres=> SHOW transaction_isolation ;
transaction_isolation
-----------------------
serializable
(1 row)
postgres=> COMMIT ;
COMMIT
postgres=> SHOW transaction_isolation ;
transaction_isolation
-----------------------
read committed
(1 row)
3.2.4 COPY
The following enhancements have been made to the COPY statement.
COPY FROM statement
It has become possible to store only the table data that matches the conditions specified in the COPY FROM statement.
Example 30COPY FROM WHERE statement
postgres=# COPY data1 FROM '/home/postgres/data1.csv' CSV
DELIMITER ',' WHERE mod(c1, 2) = 0 ;
COPY 50000
PDF page 35
It can be executed similarly by \copy command of psql command.
Example 31\copy WHERE command
postgres=> \copy data1 FROM '/home/postgres/data1.csv' CSV
DELIMITER ',' WHERE mod(c1, 2) = 0 ;
COPY 50000
COPY FREEZE statement
Executing a COPY FREEZE statement on partitioned table results in an error. This specification also applies to PostgreSQL 11.2 and later.
Example 32COPY FREEZE statement on PostgreSQL 12
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 (100) ;
CREATE TABLE
postgres=> CREATE TABLE part1v2 PARTITION OF part1 FOR VALUES FROM
(100) TO (200) ;
CREATE TABLE
postgres=# COPY part1 FROM '/home/postgres/part1.csv' CSV FREEZE ;
ERROR: cannot perform FREEZE on a partitioned table
3.2.5 CREATE AGGREGATE
It is able to use the OR REPLACE clause in the CREATE AGGREGATE statement. Syntax
Covering indexes are now available for GiST indexes.
Example 33Covering index for GiST index
postgres=> CREATE TABLE data1(c1 INT, c2 box, c3 VARCHAR(10)) ;
CREATE TABLE
postgres=> CREATE INDEX idx1_data1 ON data1 USING gist (c2)
INCLUDE (c1) ;
CREATE INDEX
postgres=> \d data1
Table "public.data1"
Column | Type | Collation | Nullable | Default
--------+-----------------------+-----------+----------+---------
c1 | integer | | |
c2 | box | | |
c3 | character varying(10) | | |
Indexes:
"idx1_data1" gist (c2) INCLUDE (c1)
PDF page 37
GiST Index and VACUUM
Free pages are now reused by VACUUM.
WAL when creating GIN index
The amount of WAL output at indexing time has been significantly reduced.
3.2.8 CREATE STATISTICS
The mcv clause can be used in the CREATE STATISTICS statement. This value indicates Multivariate most-common values (MCV). It expands the regular MCV list and tracks the most frequent value combinations. The acquired statistics are stored in the stxmcv column of the pg_statistic_ext_data catalog.
The following enhancements have been made to the CREATE TABLE statement.
GENERATED column
The generated column is the column defined as the column based on calculation results to the table. At the time of column definition, specify GENERATED ALWAYS AS (calculation expression) STORED clause following data type.
In the above example, it is displayed that the c1 column is ‘AB’ (= 0x4142), the c2 column is ‘CD’ (= 0x4344), and the c3 column is ‘ABCD’ (= 0x41424344). Information on generated columns can be found by storing “s” in the attgenerated column added to the pg_attrdef catalog. In addition, information_schema column_column_usage table is newly added.
Example 38GENERATED column information
postgres=> SELECT * FROM information_schema.column_column_usage ;
table_catalog
|
table_schema
|
table_name
|
column_name
|
dependent_column
---------------+--------------+------------+-------------+-----------
------
postgres | public | gen1 | c1 | c3
postgres | public | gen1 | c2 | c3
(2 rows)
postgres=> SELECT attname, attgenerated FROM pg_attribute WHERE attname
IN ('c1', 'c2', 'c3') ;
attname | attgenerated
---------+--------------
c1 |
c2 |
c3 | s
(3 rows)
A generated column cannot be specified as a partitioning key. In addition, it is not possible to
define a generated column that depends on the other generated columns.
PDF page 40
Example 39Restriction of GENERATED column
postgres=> CREATE TABLE pgen1(c1 INT, c2 INT, c3 INT GENERATED
ALWAYS AS (c1 + c2) STORED) PARTITION BY RANGE(c3) ;
psql: ERROR: cannot use generated column in partition key
LINE 1: ...NERATED ALWAYS AS (c1 + c2) STORED) PARTITION BY
RANGE(c3) ;
^
DETAIL: Column "c3" is a generated column.
postgres=> CREATE TABLE gen2 (c1 INT, c2 INT GENERATED ALWAYS AS
(c1*2) STORED, c3 INT GENERATED ALWAYS AS (c2*2) STORED) ;
psql: ERROR: cannot use generated column "c2" in column generation
expression
LINE 1: ...AYS AS (c1*2) STORED, c3 INT GENERATED ALWAYS AS (c2*2)
STOR...
TABLESPACE clause of partition table definition
TABLESPACE clause is now enabled when creating the partition table. In previous versions, the TABLESPACE clause was ignored. Also, the value of the TABLESPACE clause of the partitioned table becomes the default tablespace at the time of partition creation.
PDF page 41
Example 40Partitioned Table Creation and TABLESPACE Clause
postgres=> CREATE TABLE part1(c1 NUMERIC, c2 VARCHAR(10))
PARTITION BY
LIST(c1) TABLESPACE ts1 ;
CREATE TABLE
postgres=> CREATE TABLE part1v1 PARTITION OF part1 FOR VALUES IN
(100) ;
CREATE TABLE
postgres=> \d part1
Partitioned table "public.part1"
Column | Type | Collation | Nullable | Default
--------+-----------------------+-----------+----------+---------
c1 | numeric | | |
c2 | character varying(10) | | |
Partition key: LIST (c1)
Number of partitions: 1 (Use \d+ to list them.)
Tablespace: "ts1"
postgres=> \d part1v1
Table "public.part1v1"
Column | Type | Collation | Nullable | Default
--------+-----------------------+-----------+----------+---------
c1 | numeric | | |
c2 | character varying(10) | | |
Partition of: part1 FOR VALUES IN ('100')
Tablespace: "ts1"
FOR VALUES clause of partition table
It is now possible to specify a formula or function instead of a literal in the FOR VALUES clause of a partition. The specified formula is executed only once when the CREATE TABLE statement is executed, and the calculated value is stored in the table definition.
PDF page 42
Example 41FOR VALUES clause of partition table
postgres=> CREATE TABLE part1v1 PARTITION OF part1 FOR VALUES IN
(power(2, 3)) ;
CREATE TABLE
postgres=> \d part1v1
Table "public.part1v1"
Column | Type | Collation | Nullable | Default
--------+-----------------------+-----------+----------+---------
c1 | numeric | | |
c2 | character varying(10) | | |
Partition of: part1 FOR VALUES IN ('8')
Tablespace: "ts1"
A foreign key reference to the partition table
The partition table can be referenced as a foreign key.
Example 42Refer to partition table as reference table
postgres=> CREATE TABLE fkey1(c1 INT PRIMARY KEY, c2
VARCHAR(10)) PARTITION BY RANGE(c1) ;
CREATE TABLE
postgres=> CREATE TABLE fkey1v1 PARTITION OF fkey1 FOR VALUES
FROM (0) TO (1000000) ;
CREATE TABLE
postgres=> CREATE TABLE fkey1v2 PARTITION OF fkey1 FOR VALUES
FROM (1000000) TO (2000000) ;
CREATE TABLE
postgres=> CREATE TABLE ref1(c1 INT REFERENCES fkey1(c1),
c2 VARCHAR(10)) ;
By specifying the VACUUM_INDEX_CLEANUP = OFF in WITH clause, it will be able to disable
PDF page 43
the VACUUM process for the index. The default value is ‘ON’, and VACUUM will be performed as before. Specify TOAST.VACUUM_INDEX_CLEANUP = OFF for the TOAST table.
VACUUM_TRUNCATE has been added to the attributes of the table. Determines whether the truncate empty block at the end of the table is released when performing VACUUM. The default value is ‘ON’, which truncate empty space as before. When it is specified as ‘OFF’, this operation is not performed.
PDF page 44
Example 44Truncate empty block at the end of the table
The SETTINGS ON option can now be specified in the EXPLAIN statement. This option outputs information on parameters related to the execution plan being changed from the default value.
Example 45EXPLAIN (SETTINGS ON)
postgres=> SET random_page_cost = 1.0 ;
SET
postgres=> EXPLAIN (SETTINGS ON) SELECT * FROM data1 WHERE c1=100 ;
QUERY PLAN
-----------------------------------------------------------------------
Index Scan using idx1_data1 on data1 (cost=0.29..2.31 rows=1 width=12)
Index Cond: (c1 = '100'::numeric)
Settings: random_page_cost = '1'
(3 rows)
PDF page 45
3.2.11 REINDEX CONCURRENTLY
The CONCURRENTLY option can now be added to the REINDEX statement. By reducing the lock range, application operation can be made to coexist with re-indexing. This feature is realized by temporarily creating a new index ({index_name}_ccnew) and replacing it with the old index.
Example 46REINDEX CONCURRENTLY statement
postgres=> REINDEX (VERBOSE) TABLE CONCURRENTLY data1 ;
psql: INFO: index "public.idx1_data1" was reindexed
psql: INFO: index "pg_toast.pg_toast_16385_index" was reindexed
psql: INFO: table "public.data1" was reindexed
DETAIL: CPU: user: 3.25 s, system: 0.69 s, elapsed: 13.27 s.
REINDEX
In accordance with the change of REINDEX statement, --concurrently option was also added to the
reindexdb command.
The following values can now be specified for the parameter plpgsql.extra_warnings: Both can output additional warnings or errors when the function is executed.
Strict_multi_assignment setting
A warning is output when the number of columns output by the SELECT INTO statement does not match the number of input variables. In the example below, two warnings occur in the function.
PDF page 46
Example 48strict_multi_assignment setting
postgres=> SET plpgsql.extra_warnings = 'strict_multi_assignment' ;
SET
postgres=> CREATE OR REPLACE FUNCTION strict1()
RETURNS void
LANGUAGE plpgsql
AS $$
DECLARE
x INTEGER ;
y INTEGER ;
BEGIN
SELECT 1 INTO x, y ;
SELECT 1, 2, 3 INTO x, y ;
END ;
$$ ;
CREATE FUNCTION
postgres=> SELECT strict1() ;
psql: WARNING: number of source and target fields in assignment do
not match
DETAIL: strict_multi_assignment check of extra_warnings is active.
HINT: Make sure the query returns the exact list of columns.
psql: WARNING: number of source and target fields in assignment do
not match
DETAIL: strict_multi_assignment check of extra_warnings is active.
HINT: Make sure the query returns the exact list of columns.
strict1
---------
(1 row)
Too_many_rows setting
An error is generated when multiple records are returned by the SELECT INTO statement, and execution of the procedure is stopped.
PDF page 47
Example 49too_many_rows setting
postgres=> SET plpgsql.extra_errors to 'too_many_rows' ;
SET
postgres=> DO $$
DECLARE x INTEGER ;
BEGIN
SELECT generate_series(1,2) INTO x ;
RAISE NOTICE 'test output' ;
END ;
$$ ;
psql: ERROR: query returned more than one row
HINT: Make sure the query returns a single row, or use LIMIT 1
CONTEXT: PL/pgSQL function inline_code_block line 4 at SQL
statement
3.2.13 VACUUM / ANALYZE
The following features have been added to the VACUUM and ANALYZE statements.
SKIP_LOCKED clause
When executing a VACUUM or ANALYZE statement on a locked table, it has been waiting for the lock to be released. In PostgreSQL 12, an option SKIP_LOCKED clause has been added to skip locked tables. When processing is skipped, a log of WARNING level (LOG level for automatic VACUUM) is output. SQLSTATEs are considered successful even if skipped.
Example 50Lock table
postgres=> BEGIN ;
BEGIN
postgres=> LOCK TABLE lock1 IN EXCLUSIVE MODE ;
LOCK TABLE
PDF page 48
Example 51Skip VACUUM for locked table
postgres=> VACUUM (SKIP_LOCKED) lock1 ;
psql: WARNING: skipping vacuum of "lock1" --- lock not available
VACUUM
postgres=> \echo :SQLSTATE
00000
Option specification syntax
In the VACUUM statement and ANALYZE statement, it is now possible to specify the action to be performed with TRUE/FALSE or ON/OFF.
Example 52Operation specification by ON/OFF
postgres=> VACUUM (VERBOSE OFF, FULL ON, ANALYZE ON) data1 ;
VACUUM
postgres=> VACUUM (VERBOSE TRUE, FULL TRUE, ANALYZE FALSE) data1 ;
psql: INFO: vacuuming "public.data1"
psql: INFO: "data1": found 0 removable, 1000000 nonremovable row
versions in 5406 pages
DETAIL: 0 dead row versions cannot be removed yet.
CPU: user: 0.23 s, system: 0.28 s, elapsed: 0.72 s.
VACUUM
Suppress VACUUM for index option
By specifying the OFF to INDEX_CLEANUP clause in VACUUM statement, it will be able to suppress the VACUUM process for the index. If this specification is omitted, the operation depends on the VACUUM_INDEX_CLEANUP attribute of the table.
PDF page 49
Example 53Suppress VACUUM for index
postgres=> VACUUM (VERBOSE ON, INDEX_CLEANUP OFF) data1 ;
INFO: vacuuming "public.data1"
INFO: "data1": found 10 removable, 1730 nonremovable row versions
in 10 out of 5406 pages
DETAIL: 0 dead row versions cannot be removed yet, oldest xmin:
593
There were 0 unused item identifiers.
Skipped 0 pages due to buffer pins, 5396 frozen pages.
0 pages are entirely empty.
CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s.
…
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
Suppression of free page truncation processing at the end of the table
The TRUNCATE clause has been added to the VACUUM statement. By specifying OFF for this attribute, it is possible to suppress free area deletion processing at the end of the table. If omitted, it depends on the VACUUM_TRUNCATE attribute of the table.
Example 54Suppress truncation processing
postgres=> VACUUM (VERBOSE ON, TRUNCATE OFF) data1 ;
INFO: vacuuming "public.data1"
INFO: scanned index "idx1_data1" to remove 10 row versions
DETAIL: CPU: user: 0.06 s, system: 0.00 s, elapsed: 0.08 s
INFO: "data1": removed 10 row versions in 10 pages
<<途中省略>>
There were 0 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 50
3.2.14 WITH SELECT
In the past, common table expressions (CTE) specified in the WITH clause were all MATERIALIZED. In PostgreSQL 12, the default behavior has been changed to NOT MATERIALIZED. In order to change these behaviors, it is possible to specify MATERIALIZED or NOT MATERIALIZED in the WITH clause. Specifying the NOT MATERIALIZED clause allows the specification of the WHERE clause to be pushed down into the WITH clause. In the example below, using the NOT MATERIALIZED clause shows that index search is selected and the cost is reduced.
Example 55WITH NOT MATERIALIZED
postgres=> EXPLAIN WITH s AS NOT MATERIALIZED (SELECT * FROM
data1) SELECT * FROM s WHERE c1=100 ;
QUERY PLAN
-----------------------------------------------------------------
--------
Index Scan using data1_pkey on data1 (cost=0.42..8.44 rows=1
width=12)
Index Cond: (c1 = '100'::numeric)
(2 rows)
Example 56WITH MATERIALIZED
postgres=> EXPLAIN WITH s AS MATERIALIZED (SELECT * FROM data1)
SELECT * FROM s WHERE c1=100 ;
QUERY PLAN
-----------------------------------------------------------------
------
CTE Scan on s (cost=15406.00..37906.00 rows=5000 width=70)
Filter: (c1 = '100'::numeric)
CTE s
-> Seq Scan on data1 (cost=0.00..15406.00 rows=1000000
width=12)
(4 rows)
3.2.15 Functions
The following functions have been added/enhanced.
PDF page 51
SQL/JSON
Some functions related to SQL / JSON proposed in SQL 2016 standard are provided.
Checks whether the JSON path returns any item for the specified JSON value.
jsonb_path_match
Returns JSON path predicate result for the specified JSON value. Only the first result item is taken into account.
jsonb_path_query
Gets all JSON items returned by JSON path for the specified JSON value.
jsonb_path_query_array
Gets all JSON items returned by JSON path for the specified JSON value and wraps result into an array.
jsonb_path_query_first
Gets the first JSON item returned by JSON path for the specified JSON value.
Table 16JSON/SQL functions
Pg_partition_tree
Pg_partition_tree is a function to display the tree structure of the partition table. It also supports hierarchical partition structure. Specify a partition table in the parameter. Specifying an object name other than a partition table or partition returns NULL.
PDF page 52
Example 58pg_partition_tree function
postgres=> SELECT * FROM pg_partition_tree('part1') ;
relid | parentrelid | isleaf | level
---------+-------------+--------+-------
part1 | | f | 0
part1v1 | part1 | t | 1
part1v2 | part1 | t | 1
(3 rows)
postgres=> SELECT pg_size_pretty(sum(pg_relation_size(relid))) AS
total FROM pg_partition_tree('part1') ;
total
-------
84 MB
(1 row)
Pg_partition_root
The pg_partition_root is a function that returns the top-level partition table name of a specified partition. In the following example, a sub partition is created and the pg_partition_root function is executed.
Example 59pg_partition_root function
postgres=> CREATE TABLE part1(c1 NUMERIC, c2 NUMERIC,
c3 VARCHAR(10)) PARTITION BY LIST(c1) ;
CREATE TABLE
postgres=> CREATE TABLE part1v1 PARTITION OF part1 FOR VALUES
IN (100) PARTITION BY LIST (c2) ;
CREATE TABLE
postgres=> CREATE TABLE part1v1v2 PARTITION OF part1v1 FOR
VALUES IN (200) ;
CREATE TABLE
postgres=> SELECT pg_partition_root('part1v1v2') ;
pg_partition_root
-------------------
part1
(1 row)
PDF page 53
Pg_partition_ancestors
The pg_partition_ancestors function prints the list towards the parent of the partition table that contains the specified partition.
Example 60pg_partition_ancestors function
postgres=> CREATE TABLE part1(c1 NUMERIC, c2 VARCHAR(10))
PARTITION BY LIST(c1) ;
CREATE TABLE
postgres=> CREATE TABLE part1v1 PARTITION OF part1 FOR VALUES
IN (100) ;
CREATE TABLE
postgres=> SELECT pg_partition_ancestors('part1v1') ;
pg_partition_ancestors
------------------------
part1v1
part1
(2 rows)
Pg_promote
This function promotes a standby instance to a primary instance. Previously, it was necessary to execute the pg_ctl promote command. Specify the parameter which determines whether to wait (default true) and the number of seconds to wait (default 60 seconds). This function returns false if processing fails or if the promotion is not completed within the waiting time, otherwise, it returns true.
Example 61pg_promote function
postgres=# SELECT pg_promote(true, 90) ;
pg_promote
------------
t
(1 row)
PDF page 54
Pg_ls_tmpdir
The pg_ls_tmpdir function has been added to return a list of file names where temporary data has been saved. Specify the OID of the TABLESPACE in the parameter. If omitted, it is assumed that pg_default is specified. This function requires the SUPERUSER privilege or the pg_monitor role.
The pg_ls_archive_statusdir function has been added to obtain the status of the archive file. This function searches the ${PGDATA}/pg_wal/archive_status directory and outputs the file name, size, and modification date. It does not output the actual information of archived WAL files. This function requires the SUPERUSER privilege or the pg_monitor role.
The function that performs a copy of an existing replication slot has been provided. The pg_copy_physical_replication_slot function and the pg_copy_logical_replication_slot function are provided according to the type of replication slot. To make a copy, it is necessary to replication slot is being used.