mirror of
https://github.com/postgres/postgres.git
synced 2026-03-22 10:30:21 -04:00
Implementation of SQL property graph queries, according to SQL/PGQ standard (ISO/IEC 9075-16:2023). This adds: - GRAPH_TABLE table function for graph pattern matching - DDL commands CREATE/ALTER/DROP PROPERTY GRAPH - several new system catalogs and information schema views - psql \dG command - pg_get_propgraphdef() function for pg_dump and psql A property graph is a relation with a new relkind RELKIND_PROPGRAPH. It acts like a view in many ways. It is rewritten to a standard relational query in the rewriter. Access privileges act similar to a security invoker view. (The security definer variant is not currently implemented.) Starting documentation can be found in doc/src/sgml/ddl.sgml and doc/src/sgml/queries.sgml. Author: Peter Eisentraut <peter@eisentraut.org> Author: Ashutosh Bapat <ashutosh.bapat.oss@gmail.com> Reviewed-by: Junwang Zhao <zhjwpku@gmail.com> Reviewed-by: Ajay Pal <ajay.pal.k@gmail.com> Reviewed-by: Henson Choi <assam258@gmail.com> Discussion: https://www.postgresql.org/message-id/flat/a855795d-e697-4fa5-8698-d20122126567@eisentraut.org
133 lines
4.6 KiB
PL/PgSQL
133 lines
4.6 KiB
PL/PgSQL
-- These tests display internal details that would not be stable under
|
|
-- debug_parallel_query, so make sure that option is disabled.
|
|
SET debug_parallel_query = off;
|
|
|
|
-- Make sure that we don't print any JIT-related information, as that
|
|
-- would also make results unstable.
|
|
SET jit = off;
|
|
|
|
-- These options do not exist, so these queries should all fail.
|
|
EXPLAIN (DEBUFF) SELECT 1;
|
|
EXPLAIN (DEBUG) SELECT 1;
|
|
EXPLAIN (RANGE_TABLE) SELECT 1;
|
|
|
|
-- Load the module that creates the options.
|
|
LOAD 'pg_overexplain';
|
|
|
|
-- The first option still does not exist, but the others do.
|
|
EXPLAIN (DEBUFF) SELECT 1;
|
|
EXPLAIN (DEBUG) SELECT 1;
|
|
EXPLAIN (RANGE_TABLE) SELECT 1;
|
|
|
|
-- Create a partitioned table.
|
|
CREATE TABLE vegetables (id serial, name text, genus text)
|
|
PARTITION BY LIST (genus);
|
|
CREATE TABLE daucus PARTITION OF vegetables FOR VALUES IN ('daucus');
|
|
CREATE TABLE brassica PARTITION OF vegetables FOR VALUES IN ('brassica');
|
|
INSERT INTO vegetables (name, genus)
|
|
VALUES ('carrot', 'daucus'), ('bok choy', 'brassica'),
|
|
('brocooli', 'brassica'), ('cauliflower', 'brassica'),
|
|
('cabbage', 'brassica'), ('kohlrabi', 'brassica'),
|
|
('rutabaga', 'brassica'), ('turnip', 'brassica');
|
|
VACUUM ANALYZE vegetables;
|
|
|
|
-- We filter relation OIDs out of the test output in order to avoid
|
|
-- test instability. This is currently only needed for EXPLAIN (DEBUG), not
|
|
-- EXPLAIN (RANGE_TABLE). Also suppress actual row counts, which are not
|
|
-- stable (e.g. 1/8 is 0.12 on some buildfarm machines and 0.13 on others).
|
|
CREATE FUNCTION explain_filter(text) RETURNS SETOF text
|
|
LANGUAGE plpgsql AS
|
|
$$
|
|
DECLARE
|
|
ln text;
|
|
BEGIN
|
|
FOR ln IN EXECUTE $1
|
|
LOOP
|
|
ln := regexp_replace(ln, 'Relation OIDs:( \m\d+\M)+',
|
|
'Relation OIDs: NNN...', 'g');
|
|
ln := regexp_replace(ln, '<Relation-OIDs>( ?\m\d+\M)+</Relation-OIDs>',
|
|
'<Relation-OIDs>NNN...</Relation-OIDs>', 'g');
|
|
ln := regexp_replace(ln, 'actual rows=\d+\.\d+',
|
|
'actual rows=N.NN', 'g');
|
|
RETURN NEXT ln;
|
|
END LOOP;
|
|
END;
|
|
$$;
|
|
|
|
-- Test with both options together and an aggregate.
|
|
SELECT explain_filter($$
|
|
EXPLAIN (DEBUG, RANGE_TABLE, COSTS OFF)
|
|
SELECT genus, array_agg(name ORDER BY name) FROM vegetables GROUP BY genus
|
|
$$);
|
|
|
|
-- Test a different output format.
|
|
SELECT explain_filter($$
|
|
EXPLAIN (DEBUG, RANGE_TABLE, FORMAT XML, COSTS OFF)
|
|
SELECT genus, array_agg(name ORDER BY name) FROM vegetables GROUP BY genus
|
|
$$);
|
|
|
|
-- Test just the DEBUG option. Verify that it shows information about
|
|
-- disabled nodes, parallel safety, and the parallelModeNeeded flag.
|
|
SET enable_seqscan = false;
|
|
SET debug_parallel_query = true;
|
|
SELECT explain_filter($$
|
|
EXPLAIN (DEBUG, COSTS OFF)
|
|
SELECT genus, array_agg(name ORDER BY name) FROM vegetables GROUP BY genus
|
|
$$);
|
|
SET debug_parallel_query = false;
|
|
RESET enable_seqscan;
|
|
|
|
-- Test the DEBUG option with a non-SELECT query, and also verify that the
|
|
-- hasReturning flag is shown.
|
|
SELECT explain_filter($$
|
|
EXPLAIN (DEBUG, COSTS OFF)
|
|
INSERT INTO vegetables (name, genus)
|
|
VALUES ('Brotero''s carrot', 'brassica') RETURNING id
|
|
$$);
|
|
|
|
-- Create an index, and then attempt to force a nested loop with inner index
|
|
-- scan so that we can see parameter-related information. Also, let's try
|
|
-- actually running the query, but try to suppress potentially variable output.
|
|
CREATE INDEX ON vegetables (id);
|
|
ANALYZE vegetables;
|
|
SET enable_hashjoin = false;
|
|
SET enable_material = false;
|
|
SET enable_mergejoin = false;
|
|
SET enable_seqscan = false;
|
|
SELECT explain_filter($$
|
|
EXPLAIN (BUFFERS OFF, COSTS OFF, SUMMARY OFF, TIMING OFF, ANALYZE, DEBUG)
|
|
SELECT * FROM vegetables v1, vegetables v2 WHERE v1.id = v2.id;
|
|
$$);
|
|
RESET enable_hashjoin;
|
|
RESET enable_material;
|
|
RESET enable_mergejoin;
|
|
RESET enable_seqscan;
|
|
|
|
-- Test the RANGE_TABLE option with a case that allows partition pruning.
|
|
EXPLAIN (RANGE_TABLE, COSTS OFF)
|
|
SELECT * FROM vegetables WHERE genus = 'daucus';
|
|
|
|
-- Also test a case that involves a write.
|
|
EXPLAIN (RANGE_TABLE, COSTS OFF)
|
|
INSERT INTO vegetables (name, genus) VALUES ('broccoflower', 'brassica');
|
|
|
|
-- should show "Subplan: sub"
|
|
EXPLAIN (RANGE_TABLE, COSTS OFF)
|
|
SELECT * FROM vegetables v,
|
|
(SELECT * FROM vegetables WHERE genus = 'daucus' OFFSET 0) sub;
|
|
|
|
-- should show "Subplan: unnamed_subquery"
|
|
EXPLAIN (RANGE_TABLE, COSTS OFF)
|
|
SELECT * FROM vegetables v,
|
|
(SELECT * FROM vegetables WHERE genus = 'daucus' OFFSET 0);
|
|
|
|
-- Property graph test
|
|
CREATE PROPERTY GRAPH vegetables_graph
|
|
VERTEX TABLES
|
|
(
|
|
daucus KEY(name) DEFAULT LABEL LABEL vegetables,
|
|
brassica KEY(name) DEFAULT LABEL LABEL vegetables
|
|
);
|
|
|
|
EXPLAIN (RANGE_TABLE, COSTS OFF)
|
|
SELECT * FROM GRAPH_TABLE (vegetables_graph MATCH (v1 IS vegetables) WHERE v1.genus = 'daucus' COLUMNS (v1.name));
|