mirror of
https://github.com/postgres/postgres.git
synced 2026-03-22 02:20:53 -04:00
SQL Property Graph Queries (SQL/PGQ)
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
This commit is contained in:
parent
fd6ecbfa75
commit
2f094e7ac6
122 changed files with 14888 additions and 72 deletions
|
|
@ -612,3 +612,57 @@ SELECT * FROM vegetables v,
|
|||
Unprunable RTIs: 1 3 4 5 6
|
||||
(51 rows)
|
||||
|
||||
-- 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));
|
||||
QUERY PLAN
|
||||
----------------------------------------------
|
||||
Append
|
||||
Append RTIs: 1
|
||||
Child Append RTIs: none
|
||||
-> Seq Scan on daucus
|
||||
Filter: (genus = 'daucus'::text)
|
||||
Scan RTI: 4
|
||||
Elided Node Type: SubqueryScan
|
||||
Elided Node RTIs: 2
|
||||
-> Seq Scan on brassica
|
||||
Filter: (genus = 'daucus'::text)
|
||||
Scan RTI: 5
|
||||
Elided Node Type: SubqueryScan
|
||||
Elided Node RTIs: 3
|
||||
RTI 1 (subquery, inherited, in-from-clause):
|
||||
Eref: "graph_table" (name)
|
||||
Relation: vegetables_graph
|
||||
Relation Kind: property_graph
|
||||
Relation Lock Mode: AccessShareLock
|
||||
Permission Info Index: 1
|
||||
Lateral: true
|
||||
RTI 2 (subquery):
|
||||
Eref: unnamed_subquery (name)
|
||||
Lateral: true
|
||||
RTI 3 (subquery):
|
||||
Eref: unnamed_subquery (name)
|
||||
Lateral: true
|
||||
RTI 4 (relation):
|
||||
Subplan: unnamed_subquery
|
||||
Eref: daucus (id, name, genus)
|
||||
Relation: daucus
|
||||
Relation Kind: relation
|
||||
Relation Lock Mode: AccessShareLock
|
||||
Permission Info Index: 2
|
||||
RTI 5 (relation):
|
||||
Subplan: unnamed_subquery_1
|
||||
Eref: brassica (id, name, genus)
|
||||
Relation: brassica
|
||||
Relation Kind: relation
|
||||
Relation Lock Mode: AccessShareLock
|
||||
Permission Info Index: 3
|
||||
Unprunable RTIs: 1 4 5
|
||||
(41 rows)
|
||||
|
||||
|
|
|
|||
|
|
@ -505,6 +505,17 @@ overexplain_range_table(PlannedStmt *plannedstmt, ExplainState *es)
|
|||
case RTE_GROUP:
|
||||
kind = "group";
|
||||
break;
|
||||
case RTE_GRAPH_TABLE:
|
||||
|
||||
/*
|
||||
* We should not see RTE of this kind here since property
|
||||
* graph RTE gets converted to subquery RTE in
|
||||
* RewriteGraphTable(). In case we decide not to do the
|
||||
* conversion and leave RTEkind unchanged in future, print
|
||||
* correct name of RTE kind.
|
||||
*/
|
||||
kind = "graph_table";
|
||||
break;
|
||||
}
|
||||
|
||||
/* Begin group for this specific RTE */
|
||||
|
|
@ -618,6 +629,9 @@ overexplain_range_table(PlannedStmt *plannedstmt, ExplainState *es)
|
|||
case RELKIND_PARTITIONED_INDEX:
|
||||
relkind = "partitioned_index";
|
||||
break;
|
||||
case RELKIND_PROPGRAPH:
|
||||
relkind = "property_graph";
|
||||
break;
|
||||
case '\0':
|
||||
relkind = NULL;
|
||||
break;
|
||||
|
|
@ -740,6 +754,12 @@ overexplain_range_table(PlannedStmt *plannedstmt, ExplainState *es)
|
|||
ExplainPropertyFloat("ENR Tuples", NULL, rte->enrtuples, 0, es);
|
||||
}
|
||||
|
||||
/*
|
||||
* rewriteGraphTable() clears graph_pattern and graph_table_columns
|
||||
* fields, so skip them. No graph table specific fields are required
|
||||
* to be printed.
|
||||
*/
|
||||
|
||||
/*
|
||||
* add_rte_to_flat_rtable will clear groupexprs and securityQuals, so
|
||||
* skip that field. We have handled inFromCl above, so the only thing
|
||||
|
|
|
|||
|
|
@ -120,3 +120,14 @@ SELECT * FROM vegetables v,
|
|||
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));
|
||||
|
|
|
|||
|
|
@ -240,6 +240,31 @@
|
|||
<entry>functions and procedures</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><link linkend="catalog-pg-propgraph-element"><structname>pg_propgraph_element</structname></link></entry>
|
||||
<entry>property graph elements (vertices and edges)</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><link linkend="catalog-pg-propgraph-element-label"><structname>pg_propgraph_element_label</structname></link></entry>
|
||||
<entry>property graph links between elements and labels</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><link linkend="catalog-pg-propgraph-label"><structname>pg_propgraph_label</structname></link></entry>
|
||||
<entry>property graph labels</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><link linkend="catalog-pg-propgraph-label-property"><structname>pg_propgraph_label_property</structname></link></entry>
|
||||
<entry>property graph label-specific property definitions</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><link linkend="catalog-pg-propgraph-property"><structname>pg_propgraph_property</structname></link></entry>
|
||||
<entry>property graph properties</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><link linkend="catalog-pg-publication"><structname>pg_publication</structname></link></entry>
|
||||
<entry>publications for logical replication</entry>
|
||||
|
|
@ -2141,7 +2166,8 @@ SCRAM-SHA-256$<replaceable><iteration count></replaceable>:<replaceable>&l
|
|||
<literal>c</literal> = composite type,
|
||||
<literal>f</literal> = foreign table,
|
||||
<literal>p</literal> = partitioned table,
|
||||
<literal>I</literal> = partitioned index
|
||||
<literal>I</literal> = partitioned index,
|
||||
<literal>g</literal> = property graph
|
||||
</para></entry>
|
||||
</row>
|
||||
|
||||
|
|
@ -6308,6 +6334,498 @@ SCRAM-SHA-256$<replaceable><iteration count></replaceable>:<replaceable>&l
|
|||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="catalog-pg-propgraph-element">
|
||||
<title><structname>pg_propgraph_element</structname></title>
|
||||
|
||||
<indexterm zone="catalog-pg-propgraph-element">
|
||||
<primary>pg_propgraph_element</primary>
|
||||
</indexterm>
|
||||
|
||||
<para>
|
||||
The catalog <structname>pg_propgraph_element</structname> stores
|
||||
information about the vertices and edges of a property graph, collectively
|
||||
called the elements of the property graph.
|
||||
</para>
|
||||
|
||||
<table>
|
||||
<title><structname>pg_propgraph_element</structname> Columns</title>
|
||||
<tgroup cols="1">
|
||||
<thead>
|
||||
<row>
|
||||
<entry role="catalog_table_entry"><para role="column_definition">
|
||||
Column Type
|
||||
</para>
|
||||
<para>
|
||||
Description
|
||||
</para></entry>
|
||||
</row>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<row>
|
||||
<entry role="catalog_table_entry"><para role="column_definition">
|
||||
<structfield>oid</structfield> <type>oid</type>
|
||||
</para>
|
||||
<para>
|
||||
Row identifier
|
||||
</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry role="catalog_table_entry"><para role="column_definition">
|
||||
<structfield>pgepgid</structfield> <type>oid</type>
|
||||
(references <link linkend="catalog-pg-class"><structname>pg_class</structname></link>.<structfield>oid</structfield>)
|
||||
</para>
|
||||
<para>
|
||||
Reference to the property graph that this element belongs to
|
||||
</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry role="catalog_table_entry"><para role="column_definition">
|
||||
<structfield>pgerelid</structfield> <type>oid</type>
|
||||
(references <link linkend="catalog-pg-class"><structname>pg_class</structname></link>.<structfield>oid</structfield>)
|
||||
</para>
|
||||
<para>
|
||||
Reference to the table that contains the data for this property graph element
|
||||
</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry role="catalog_table_entry"><para role="column_definition">
|
||||
<structfield>pgealias</structfield> <type>name</type>
|
||||
</para>
|
||||
<para>
|
||||
The alias of the element. This is a unique identifier for the element
|
||||
within the graph. It is set when the property graph is defined and
|
||||
defaults to the name of the underlying element table.
|
||||
</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry role="catalog_table_entry"><para role="column_definition">
|
||||
<structfield>pgekind</structfield> <type>char</type>
|
||||
</para>
|
||||
<para>
|
||||
<literal>v</literal> for a vertex, <literal>e</literal> for an edge
|
||||
</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry role="catalog_table_entry"><para role="column_definition">
|
||||
<structfield>pgesrcvertexid</structfield> <type>oid</type>
|
||||
(references <link linkend="catalog-pg-propgraph-element"><structname>pg_propgraph_element</structname></link>.<structfield>oid</structfield>)
|
||||
</para>
|
||||
<para>
|
||||
For an edge, a link to the source vertex. (Zero for a vertex.)
|
||||
</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry role="catalog_table_entry"><para role="column_definition">
|
||||
<structfield>pgedestvertexid</structfield> <type>oid</type>
|
||||
(references <link linkend="catalog-pg-propgraph-element"><structname>pg_propgraph_element</structname></link>.<structfield>oid</structfield>)
|
||||
</para>
|
||||
<para>
|
||||
For an edge, a link to the destination vertex. (Zero for a vertex.)
|
||||
</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry role="catalog_table_entry"><para role="column_definition">
|
||||
<structfield>pgekey</structfield> <type>int2[]</type>
|
||||
(references <link linkend="catalog-pg-attribute"><structname>pg_attribute</structname></link>.<structfield>attnum</structfield>)
|
||||
</para>
|
||||
<para>
|
||||
An array of column numbers in the table referenced by
|
||||
<structname>pgerelid</structname> that defines the key to use for this
|
||||
element table. (This defaults to the primary key when the property
|
||||
graph is created.)
|
||||
</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry role="catalog_table_entry"><para role="column_definition">
|
||||
<structfield>pgesrckey</structfield> <type>int2[]</type>
|
||||
(references <link linkend="catalog-pg-attribute"><structname>pg_attribute</structname></link>.<structfield>attnum</structfield>)
|
||||
</para>
|
||||
<para>
|
||||
For an edge, an array of column numbers in the table referenced by
|
||||
<structname>pgerelid</structname> that defines the source key to use
|
||||
for this element table. (Null for a vertex.) The combination of
|
||||
<structfield>pgesrckey</structfield> and
|
||||
<structfield>pgesrcref</structfield> creates the link between the edge
|
||||
and the source vertex.
|
||||
</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry role="catalog_table_entry"><para role="column_definition">
|
||||
<structfield>pgesrcref</structfield> <type>int2[]</type>
|
||||
(references <link linkend="catalog-pg-attribute"><structname>pg_attribute</structname></link>.<structfield>attnum</structfield>)
|
||||
</para>
|
||||
<para>
|
||||
For an edge, an array of column numbers in the table reached via
|
||||
<structname>pgesrcvertexid</structname>. (Null for a vertex.) The
|
||||
combination of <structfield>pgesrckey</structfield> and
|
||||
<structfield>pgesrcref</structfield> creates the link between the edge
|
||||
and the source vertex.
|
||||
</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry role="catalog_table_entry"><para role="column_definition">
|
||||
<structfield>pgesrceqop</structfield> <type>oid[]</type>
|
||||
(references <link linkend="catalog-pg-operator"><structname>pg_operator</structname></link>.<structfield>oid</structfield>)
|
||||
</para>
|
||||
<para>
|
||||
For an edge, an array of equality operators for
|
||||
<structfield>pgesrcref</structfield> =
|
||||
<structfield>pgesrckey</structfield> comparison. (Null for a vertex.)
|
||||
</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry role="catalog_table_entry"><para role="column_definition">
|
||||
<structfield>pgedestkey</structfield> <type>int2[]</type>
|
||||
(references <link linkend="catalog-pg-attribute"><structname>pg_attribute</structname></link>.<structfield>attnum</structfield>)
|
||||
</para>
|
||||
<para>
|
||||
For an edge, an array of column numbers in the table referenced by
|
||||
<structname>pgerelid</structname> that defines the destination key to use
|
||||
for this element table. (Null for a vertex.) The combination of
|
||||
<structfield>pgedestkey</structfield> and
|
||||
<structfield>pgedestref</structfield> creates the link between the edge
|
||||
and the destination vertex.
|
||||
</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry role="catalog_table_entry"><para role="column_definition">
|
||||
<structfield>pgedestref</structfield> <type>int2[]</type>
|
||||
(references <link linkend="catalog-pg-attribute"><structname>pg_attribute</structname></link>.<structfield>attnum</structfield>)
|
||||
</para>
|
||||
<para>
|
||||
For an edge, an array of column numbers in the table reached via
|
||||
<structname>pgedestvertexid</structname>. (Null for a vertex.) The
|
||||
combination of <structfield>pgedestkey</structfield> and
|
||||
<structfield>pgedestref</structfield> creates the link between the edge
|
||||
and the destination vertex.
|
||||
</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry role="catalog_table_entry"><para role="column_definition">
|
||||
<structfield>pgedesteqop</structfield> <type>oid[]</type>
|
||||
(references <link linkend="catalog-pg-operator"><structname>pg_operator</structname></link>.<structfield>oid</structfield>)
|
||||
</para>
|
||||
<para>
|
||||
For an edge, an array of equality operators for
|
||||
<structfield>pgedestref</structfield> =
|
||||
<structfield>pgedestkey</structfield> comparison. (Null for a vertex.)
|
||||
</para></entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="catalog-pg-propgraph-element-label">
|
||||
<title><structname>pg_propgraph_element_label</structname></title>
|
||||
|
||||
<indexterm zone="catalog-pg-propgraph-element-label">
|
||||
<primary>pg_propgraph_element_label</primary>
|
||||
</indexterm>
|
||||
|
||||
<para>
|
||||
The catalog <structname>pg_propgraph_element_label</structname> stores
|
||||
information about which labels apply to which elements.
|
||||
</para>
|
||||
|
||||
<table>
|
||||
<title><structname>pg_propgraph_element_label</structname> Columns</title>
|
||||
<tgroup cols="1">
|
||||
<thead>
|
||||
<row>
|
||||
<entry role="catalog_table_entry"><para role="column_definition">
|
||||
Column Type
|
||||
</para>
|
||||
<para>
|
||||
Description
|
||||
</para></entry>
|
||||
</row>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<row>
|
||||
<entry role="catalog_table_entry"><para role="column_definition">
|
||||
<structfield>oid</structfield> <type>oid</type>
|
||||
</para>
|
||||
<para>
|
||||
Row identifier
|
||||
</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry role="catalog_table_entry"><para role="column_definition">
|
||||
<structfield>pgellabelid</structfield> <type>oid</type>
|
||||
(references <link linkend="catalog-pg-propgraph-label"><structname>pg_propgraph_label</structname></link>.<structfield>oid</structfield>)
|
||||
</para>
|
||||
<para>
|
||||
Reference to the label
|
||||
</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry role="catalog_table_entry"><para role="column_definition">
|
||||
<structfield>pgelelid</structfield> <type>oid</type>
|
||||
(references <link linkend="catalog-pg-propgraph-element"><structname>pg_propgraph_element</structname></link>.<structfield>oid</structfield>)
|
||||
</para>
|
||||
<para>
|
||||
Reference to the element
|
||||
</para></entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="catalog-pg-propgraph-label">
|
||||
<title><structname>pg_propgraph_label</structname></title>
|
||||
|
||||
<indexterm zone="catalog-pg-propgraph-label">
|
||||
<primary>pg_propgraph_label</primary>
|
||||
</indexterm>
|
||||
|
||||
<para>
|
||||
The catalog <structname>pg_propgraph_label</structname> stores
|
||||
information about the labels in a property graph.
|
||||
</para>
|
||||
|
||||
<table>
|
||||
<title><structname>pg_propgraph_label</structname> Columns</title>
|
||||
<tgroup cols="1">
|
||||
<thead>
|
||||
<row>
|
||||
<entry role="catalog_table_entry"><para role="column_definition">
|
||||
Column Type
|
||||
</para>
|
||||
<para>
|
||||
Description
|
||||
</para></entry>
|
||||
</row>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<row>
|
||||
<entry role="catalog_table_entry"><para role="column_definition">
|
||||
<structfield>oid</structfield> <type>oid</type>
|
||||
</para>
|
||||
<para>
|
||||
Row identifier
|
||||
</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry role="catalog_table_entry"><para role="column_definition">
|
||||
<structfield>pglpgid</structfield> <type>oid</type>
|
||||
(references <link linkend="catalog-pg-class"><structname>pg_class</structname></link>.<structfield>oid</structfield>)
|
||||
</para>
|
||||
<para>
|
||||
Reference to the property graph that this label belongs to
|
||||
</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry role="catalog_table_entry"><para role="column_definition">
|
||||
<structfield>pgllabel</structfield> <type>name</type>
|
||||
</para>
|
||||
<para>
|
||||
The name of the label. This is unique among the labels in a graph.
|
||||
</para></entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="catalog-pg-propgraph-label-property">
|
||||
<title><structname>pg_propgraph_label_property</structname></title>
|
||||
|
||||
<indexterm zone="catalog-pg-propgraph-label-property">
|
||||
<primary>pg_propgraph_label_property</primary>
|
||||
</indexterm>
|
||||
|
||||
<para>
|
||||
The catalog <structname>pg_propgraph_label_property</structname> stores
|
||||
information about the properties in a property graph that are specific to a
|
||||
label. In particular, this stores the expression that defines the
|
||||
property.
|
||||
</para>
|
||||
|
||||
<table>
|
||||
<title><structname>pg_propgraph_label_property</structname> Columns</title>
|
||||
<tgroup cols="1">
|
||||
<thead>
|
||||
<row>
|
||||
<entry role="catalog_table_entry"><para role="column_definition">
|
||||
Column Type
|
||||
</para>
|
||||
<para>
|
||||
Description
|
||||
</para></entry>
|
||||
</row>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<row>
|
||||
<entry role="catalog_table_entry"><para role="column_definition">
|
||||
<structfield>oid</structfield> <type>oid</type>
|
||||
</para>
|
||||
<para>
|
||||
Row identifier
|
||||
</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry role="catalog_table_entry"><para role="column_definition">
|
||||
<structfield>plppropid</structfield> <type>oid</type>
|
||||
(references <link linkend="catalog-pg-propgraph-property"><structname>pg_propgraph_property</structname></link>.<structfield>oid</structfield>)
|
||||
</para>
|
||||
<para>
|
||||
Reference to the property
|
||||
</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry role="catalog_table_entry"><para role="column_definition">
|
||||
<structfield>plpellabelid</structfield> <type>oid</type>
|
||||
(references <link linkend="catalog-pg-propgraph-element-label"><structname>pg_propgraph_element_label</structname></link>.<structfield>oid</structfield>)
|
||||
</para>
|
||||
<para>
|
||||
Reference to the label (indirectly via
|
||||
<structname>pg_propgraph_element_label</structname>, which then links
|
||||
to <structname>pg_propgraph_label</structname>)
|
||||
</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry role="catalog_table_entry"><para role="column_definition">
|
||||
<structfield>plpexpr</structfield> <type>pg_node_tree</type>
|
||||
</para>
|
||||
<para>
|
||||
Expression tree (in <function>nodeToString()</function> representation)
|
||||
for the property's definition. The expression references the table
|
||||
reached via <structname>pg_propgraph_element_label</structname> and
|
||||
<structname>pg_propgraph_element</structname>.
|
||||
</para></entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="catalog-pg-propgraph-property">
|
||||
<title><structname>pg_propgraph_property</structname></title>
|
||||
|
||||
<indexterm zone="catalog-pg-propgraph-property">
|
||||
<primary>pg_propgraph_property</primary>
|
||||
</indexterm>
|
||||
|
||||
<para>
|
||||
The catalog <structname>pg_propgraph_property</structname> stores
|
||||
information about the properties in a property graph. This only stores
|
||||
information that applies to a property throughout the graph, independent of
|
||||
what label or element it is on. Additional information, including the
|
||||
actual expressions that define the properties are in the catalog <link
|
||||
linkend="catalog-pg-propgraph-label-property"><structname>pg_propgraph_label_property</structname></link>.
|
||||
</para>
|
||||
|
||||
<table>
|
||||
<title><structname>pg_propgraph_property</structname> Columns</title>
|
||||
<tgroup cols="1">
|
||||
<thead>
|
||||
<row>
|
||||
<entry role="catalog_table_entry"><para role="column_definition">
|
||||
Column Type
|
||||
</para>
|
||||
<para>
|
||||
Description
|
||||
</para></entry>
|
||||
</row>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<row>
|
||||
<entry role="catalog_table_entry"><para role="column_definition">
|
||||
<structfield>oid</structfield> <type>oid</type>
|
||||
</para>
|
||||
<para>
|
||||
Row identifier
|
||||
</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry role="catalog_table_entry"><para role="column_definition">
|
||||
<structfield>pgppgid</structfield> <type>oid</type>
|
||||
(references <link linkend="catalog-pg-class"><structname>pg_class</structname></link>.<structfield>oid</structfield>)
|
||||
</para>
|
||||
<para>
|
||||
Reference to the property graph that this property belongs to
|
||||
</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry role="catalog_table_entry"><para role="column_definition">
|
||||
<structfield>pgpname</structfield> <type>name</type>
|
||||
</para>
|
||||
<para>
|
||||
The name of the property. This is unique among the properties in a
|
||||
graph.
|
||||
</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry role="catalog_table_entry"><para role="column_definition">
|
||||
<structfield>pgptypid</structfield> <type>oid</type>
|
||||
(references <link linkend="catalog-pg-type"><structname>pg_type</structname></link>.<structfield>oid</structfield>)
|
||||
</para>
|
||||
<para>
|
||||
The data type of this property. (This is required to be fixed for a
|
||||
given property in a property graph, even if the property is defined
|
||||
multiple times in different elements and labels.)
|
||||
</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry role="catalog_table_entry"><para role="column_definition">
|
||||
<structfield>pgptypmod</structfield> <type>int4</type>
|
||||
</para>
|
||||
<para>
|
||||
<literal>typmod</literal> to be applied to the data type of this property.
|
||||
(This is required to be fixed for a given property in a property graph,
|
||||
even if the property is defined multiple times in different elements and
|
||||
labels.)
|
||||
</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry role="catalog_table_entry"><para role="column_definition">
|
||||
<structfield>pgpcollation</structfield> <type>oid</type>
|
||||
(references <link linkend="catalog-pg-collation"><structname>pg_collation</structname></link>.<structfield>oid</structfield>)
|
||||
</para>
|
||||
<para>
|
||||
The defined collation of this property, or zero if the property is not of
|
||||
a collatable data type. (This is required to be fixed for a given
|
||||
property in a property graph, even if the property is defined multiple
|
||||
times in different elements and labels.)
|
||||
</para></entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="catalog-pg-publication">
|
||||
<title><structname>pg_publication</structname></title>
|
||||
|
||||
|
|
|
|||
|
|
@ -2315,6 +2315,8 @@ REVOKE ALL ON accounts FROM PUBLIC;
|
|||
This privilege is also needed to reference existing column values in
|
||||
<command>UPDATE</command>, <command>DELETE</command>,
|
||||
or <command>MERGE</command>.
|
||||
For property graphs, this privilege allows the object to be referenced
|
||||
in a <literal>GRAPH_TABLE</literal> clause.
|
||||
For sequences, this privilege also allows use of the
|
||||
<function>currval</function> function.
|
||||
For large objects, this privilege allows the object to be read.
|
||||
|
|
@ -5693,6 +5695,242 @@ EXPLAIN SELECT count(*) FROM measurement WHERE logdate >= DATE '2008-01-01';
|
|||
</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="ddl-property-graphs">
|
||||
<title>Property Graphs</title>
|
||||
|
||||
<indexterm zone="ddl-property-graphs">
|
||||
<primary>property graph</primary>
|
||||
</indexterm>
|
||||
|
||||
<para>
|
||||
A property graph is a way to represent database contents, as an alternative
|
||||
to the usual (in SQL) approach of representing database contents using
|
||||
relational structures such as tables. A property graph can then be queried
|
||||
using graph pattern matching syntax, instead of join queries typical of
|
||||
relational databases. PostgreSQL implements SQL/PGQ<footnote><para>Here, PGQ
|
||||
stands for <quote>property graph query</quote>. In the jargon of graph
|
||||
databases, <quote>property graph</quote> is normally abbreviated as PG, which
|
||||
is clearly confusing for practioners of PostgreSQL, also usually abbreviated
|
||||
as PG.</para></footnote>, which is part of the SQL standard, where a property
|
||||
graph is defined as a kind of read-only view over relational tables. So the
|
||||
actual data is still in tables or table-like objects, but is exposed as a
|
||||
graph for graph querying operations. (This is in contrast to native graph
|
||||
databases, where the data is stored directly in a graph structure.)
|
||||
Underneath, both relational queries and graph queries use the same query
|
||||
planning and execution infrastructure, and in fact relational and graph
|
||||
queries can be combined and mixed in single queries.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
A graph is a set of vertices and edges. Each edge has two distinguishable
|
||||
associated vertices called the source and destination vertices. (So in
|
||||
this model, all edges are directed.) Vertices and edges together are
|
||||
called the elements of the graph. A property graph extends this well-known
|
||||
mathematical structure with a way to represent user data. In a property
|
||||
graph, each vertex or edge has one or more associated labels, and each
|
||||
label has zero or more properties. The labels are similar to table row
|
||||
types in that they define the kind of the contained data and its structure.
|
||||
The properties are similar to columns in that they contain the actual data.
|
||||
In fact, by default, a property graph definition exposes the underlying
|
||||
tables and columns as labels and properties, but more complicated
|
||||
definitions are possible.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Consider the following table definitions:
|
||||
<programlisting>
|
||||
CREATE TABLE products (
|
||||
product_no integer PRIMARY KEY,
|
||||
name varchar,
|
||||
price numeric
|
||||
);
|
||||
|
||||
CREATE TABLE customers (
|
||||
customer_id integer PRIMARY KEY,
|
||||
name varchar,
|
||||
address varchar
|
||||
);
|
||||
|
||||
CREATE TABLE orders (
|
||||
order_id integer PRIMARY KEY,
|
||||
ordered_when date
|
||||
);
|
||||
|
||||
CREATE TABLE order_items (
|
||||
order_items_id integer PRIMARY KEY,
|
||||
order_id integer REFERENCES orders (order_id),
|
||||
product_no integer REFERENCES products (product_no),
|
||||
quantity integer
|
||||
);
|
||||
|
||||
CREATE TABLE customer_orders (
|
||||
customer_orders_id integer PRIMARY KEY,
|
||||
customer_id integer REFERENCES customers (customer_id),
|
||||
order_id integer REFERENCES orders (order_id)
|
||||
);
|
||||
</programlisting>
|
||||
When mapping this to a graph, the first three tables would be the vertices
|
||||
and the last two tables would be the edges. The foreign-key definitions
|
||||
correspond to the fact that edges link two vertices. (Graph definitions
|
||||
work more naturally with many-to-many relationships, so this example is
|
||||
organized like that, even though one-to-many relationships might be used
|
||||
here in a pure relational approach.)
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Here is an example how a property graph could be defined on top of these
|
||||
tables:
|
||||
<programlisting>
|
||||
CREATE PROPERTY GRAPH myshop
|
||||
VERTEX TABLES (
|
||||
products,
|
||||
customers,
|
||||
orders
|
||||
)
|
||||
EDGE TABLES (
|
||||
order_items SOURCE orders DESTINATION products,
|
||||
customer_orders SOURCE customers DESTINATION orders
|
||||
);
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
This graph could then be queried like this:
|
||||
<programlisting>
|
||||
-- get list of customers active today
|
||||
SELECT customer_name FROM GRAPH_TABLE (myshop MATCH (c IS customers)-[IS customer_orders]->(o IS orders WHERE o.ordered_when = current_date) COLUMNS (c.name AS customer_name));
|
||||
</programlisting>
|
||||
corresponding approximately to this relational query:
|
||||
<programlisting>
|
||||
-- get list of customers active today
|
||||
SELECT customers.name FROM customers JOIN customer_orders USING (customer_id) JOIN orders USING (order_id) WHERE orders.ordered_when = current_date;
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The above definition requires that all tables have primary keys and that
|
||||
for each edge there is an appropriate foreign key. Otherwise, additional
|
||||
clauses have to be specified to identify the key columns. For example,
|
||||
this would be the fully verbose definition that does not rely on primary
|
||||
and foreign keys:
|
||||
<programlisting>
|
||||
CREATE PROPERTY GRAPH myshop
|
||||
VERTEX TABLES (
|
||||
products KEY (product_no),
|
||||
customers KEY (customer_id),
|
||||
orders KEY (order_id)
|
||||
)
|
||||
EDGE TABLES (
|
||||
order_items KEY (order_items_id)
|
||||
SOURCE KEY (order_id) REFERENCES orders (order_id)
|
||||
DESTINATION KEY (product_no) REFERENCES products (product_no),
|
||||
customer_orders KEY (customer_orders_id)
|
||||
SOURCE KEY (customer_id) REFERENCES customers (customer_id)
|
||||
DESTINATION KEY (order_id) REFERENCES orders (order_id)
|
||||
);
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
As mentioned above, by default, the names of the tables and columns are
|
||||
exposed as labels and properties, respectively. The clauses <literal>IS
|
||||
customer</literal>, <literal>IS order</literal>, etc. in the
|
||||
<literal>MATCH</literal> clause in fact refer to labels, not table names.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
One use of labels is to expose a table through a different name in the graph.
|
||||
For example, in graphs, vertices typically have singular nouns as labels and
|
||||
edges typically have verbs or phrases derived from verbs as labels, such as
|
||||
<quote>has</quote>, <quote>contains</quote>, or something specific like
|
||||
<quote>approved_by</quote>. We can introduce such labels into our example like
|
||||
this:
|
||||
<programlisting>
|
||||
CREATE PROPERTY GRAPH myshop
|
||||
VERTEX TABLES (
|
||||
products LABEL product,
|
||||
customers LABEL customer,
|
||||
orders LABEL "order"
|
||||
)
|
||||
EDGE TABLES (
|
||||
order_items SOURCE orders DESTINATION products LABEL contains,
|
||||
customer_orders SOURCE customers DESTINATION orders LABEL has_placed
|
||||
);
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
With this definition, we can write a query like this:
|
||||
<programlisting>
|
||||
SELECT customer_name FROM GRAPH_TABLE (myshop MATCH (c IS customer)-[IS has_placed]->(o IS "order" WHERE o.ordered_when = current_date) COLUMNS (c.name AS customer_name));
|
||||
</programlisting>
|
||||
With the new labels the <literal>MATCH</literal> clause is now more intuitive.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Notice that the label <literal>order</literal> is quoted. If we run above
|
||||
statements without adding quotes around <literal>order</literal>, we will get
|
||||
a syntax error since <literal>order</literal> is a keyword.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Another use is to apply the same label to multiple element tables. For
|
||||
example, consider this additional table:
|
||||
<programlisting>
|
||||
CREATE TABLE employees (
|
||||
employee_id integer PRIMARY KEY,
|
||||
employee_name varchar,
|
||||
...
|
||||
);
|
||||
</programlisting>
|
||||
and the following graph definition:
|
||||
<programlisting>
|
||||
CREATE PROPERTY GRAPH myshop
|
||||
VERTEX TABLES (
|
||||
products LABEL product,
|
||||
customers LABEL customer LABEL person PROPERTIES (name),
|
||||
orders LABEL order,
|
||||
employees LABEL employee LABEL person PROPERTIES (employee_name AS name)
|
||||
)
|
||||
EDGE TABLES (
|
||||
order_items SOURCE orders DESTINATION products LABEL contains,
|
||||
customer_orders SOURCE customers DESTINATION orders LABEL has
|
||||
);
|
||||
</programlisting>
|
||||
(In practice, there ought to be an edge linking the
|
||||
<literal>employees</literal> table to something, but it is allowed like
|
||||
this.) Then we can run a query like this (incomplete):
|
||||
<programlisting>
|
||||
SELECT ... FROM GRAPH_TABLE (myshop MATCH (IS person WHERE name = '...')-[]->... COLUMNS (...));
|
||||
</programlisting>
|
||||
This would automatically consider both the <literal>customers</literal> and
|
||||
the <literal>employees</literal> tables when looking for an edge with the
|
||||
<literal>person</literal> label.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
When more than one element table has the same label, it is required that
|
||||
the properties match in number, name, and type. In the example, we specify
|
||||
an explicit property list and in one case override the name of the column
|
||||
to achieve this.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Using more than one label associated with an element table and each label
|
||||
exposing a different set of properties, the same relational data, and the
|
||||
graph structure contained therein, can be exposed through multiple
|
||||
co-existing logical views, which can be queried using graph pattern matching
|
||||
constructs.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
For more details on the syntax for creating property graphs, see <link
|
||||
linkend="sql-create-property-graph"><command>CREATE PROPERTY
|
||||
GRAPH</command></link>. More details about the graph query syntax is in
|
||||
<xref linkend="queries-graph"/>.
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="ddl-others">
|
||||
<title>Other Database Objects</title>
|
||||
|
||||
|
|
|
|||
|
|
@ -70,10 +70,10 @@
|
|||
|
||||
<para>
|
||||
The <productname>PostgreSQL</productname> core covers parts 1, 2, 9,
|
||||
11, and 14. Part 3 is covered by the ODBC driver, and part 13 is
|
||||
11, 14, and 16. Part 3 is covered by the ODBC driver, and part 13 is
|
||||
covered by the PL/Java plug-in, but exact conformance is currently
|
||||
not being verified for these components. There are currently no
|
||||
implementations of parts 4, 10, 15, and 16
|
||||
implementations of parts 4, 10, and 15
|
||||
for <productname>PostgreSQL</productname>.
|
||||
</para>
|
||||
|
||||
|
|
|
|||
|
|
@ -1677,6 +1677,21 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
|
|||
</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry role="func_table_entry"><para role="func_signature">
|
||||
<indexterm>
|
||||
<primary>pg_get_propgraphdef</primary>
|
||||
</indexterm>
|
||||
<function>pg_get_propgraphdef</function> ( <parameter>propgraph</parameter> <type>oid</type> )
|
||||
<returnvalue>text</returnvalue>
|
||||
</para>
|
||||
<para>
|
||||
Reconstructs the creating command for a property graph.
|
||||
(This is a decompiled reconstruction, not the original text
|
||||
of the command.)
|
||||
</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry role="func_table_entry"><para role="func_signature">
|
||||
<indexterm>
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
27
doc/src/sgml/keywords/sql2023-16-nonreserved.txt
Normal file
27
doc/src/sgml/keywords/sql2023-16-nonreserved.txt
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
ACYCLIC
|
||||
BINDINGS
|
||||
BOUND
|
||||
DESTINATION
|
||||
DIFFERENT
|
||||
DIRECTED
|
||||
EDGE
|
||||
EDGES
|
||||
ELEMENTS
|
||||
LABEL
|
||||
LABELED
|
||||
NODE
|
||||
PATHS
|
||||
PROPERTIES
|
||||
PROPERTY
|
||||
PROPERTY_GRAPH_CATALOG
|
||||
PROPERTY_GRAPH_NAME
|
||||
PROPERTY_GRAPH_SCHEMA
|
||||
RELATIONSHIP
|
||||
RELATIONSHIPS
|
||||
SHORTEST
|
||||
SINGLETONS
|
||||
STEP
|
||||
TABLES
|
||||
TRAIL
|
||||
VERTEX
|
||||
WALK
|
||||
12
doc/src/sgml/keywords/sql2023-16-reserved.txt
Normal file
12
doc/src/sgml/keywords/sql2023-16-reserved.txt
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
ALL_DIFFERENT
|
||||
BINDING_COUNT
|
||||
ELEMENT_ID
|
||||
ELEMENT_NUMBER
|
||||
EXPORT
|
||||
GRAPH
|
||||
GRAPH_TABLE
|
||||
MATCHNUM
|
||||
PATH_LENGTH
|
||||
PATH_NAME
|
||||
PROPERTY_EXISTS
|
||||
SAME
|
||||
|
|
@ -863,6 +863,11 @@ ORDER BY p;
|
|||
to columns provided by preceding <literal>FROM</literal> items in any case.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
A <literal>GRAPH_TABLE</literal> <literal>FROM</literal> item can also
|
||||
always contain lateral references.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
A <literal>LATERAL</literal> item can appear at the top level in the
|
||||
<literal>FROM</literal> list, or within a <literal>JOIN</literal> tree. In the latter
|
||||
|
|
@ -2771,4 +2776,161 @@ SELECT * FROM t;
|
|||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="queries-graph">
|
||||
<title>Graph Queries</title>
|
||||
|
||||
<para>
|
||||
This section describes the sublanguage for querying property graphs,
|
||||
defined as described in <xref linkend="ddl-property-graphs"/>.
|
||||
</para>
|
||||
|
||||
<sect2 id="queries-graph-overview">
|
||||
<title>Overview</title>
|
||||
|
||||
<para>
|
||||
Consider this example from <xref linkend="ddl-property-graphs"/>:
|
||||
<programlisting>
|
||||
-- get list of customers active today
|
||||
SELECT customer_name FROM GRAPH_TABLE (myshop MATCH (c IS customers)-[IS customer_orders]->(o IS orders WHERE o.ordered_when = current_date) COLUMNS (c.name AS customer_name));
|
||||
</programlisting>
|
||||
The graph query part happens inside the <literal>GRAPH_TABLE</literal>
|
||||
construct. As far as the rest of the query is concerned, this acts like a
|
||||
table function in that it produces a computed table as output. Like other
|
||||
<literal>FROM</literal> clause elements, table alias and column alias
|
||||
names can be assigned to the result, and the result can be joined with
|
||||
other tables, subsequently filtered, and so on, for example:
|
||||
<programlisting>
|
||||
SELECT ... FROM GRAPH_TABLE (mygraph MATCH ... COLUMNS (...)) AS myresult (a, b, c) JOIN othertable USING (a) WHERE b > 0 ORDER BY c;
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The <literal>GRAPH_TABLE</literal> clause consists of the graph name,
|
||||
followed by the keyword <literal>MATCH</literal>, followed by a graph
|
||||
pattern expression (see below), followed by the keyword
|
||||
<literal>COLUMNS</literal> and a column list.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="queries-graph-patterns">
|
||||
<title>Graph Patterns</title>
|
||||
|
||||
<para>
|
||||
The core of the graph querying functionality is the graph pattern, which
|
||||
appears after the keyword <literal>MATCH</literal>. Formally, a graph
|
||||
pattern consists of one or more path patterns. A path is a sequence of
|
||||
graph elements, starting and ending with a vertex and alternating between
|
||||
vertices and edges. A path pattern is a syntactic expressions that
|
||||
matches paths.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
A path pattern thus matches a sequence of vertices and edges. The
|
||||
simplest possible path pattern is
|
||||
<programlisting>
|
||||
()
|
||||
</programlisting>
|
||||
which matches a single vertex. The next simplest pattern would be
|
||||
<programlisting>
|
||||
()-[]->()
|
||||
</programlisting>
|
||||
which matches a vertex followed by an edge followed by a vertex. The
|
||||
characters <literal>()</literal> are a vertex pattern and the characters
|
||||
<literal>-[]-></literal> are an edge pattern.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
These characters can also be separated by whitespace, for example:
|
||||
<programlisting>
|
||||
( ) - [ ] - > ( )
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
<tip>
|
||||
<para>
|
||||
A way to remember these symbols is that in visual representations of
|
||||
property graphs, vertices are usually circles (like
|
||||
<literal>()</literal>) and edges have rectangular labels (like
|
||||
<literal>[]</literal>).
|
||||
</para>
|
||||
</tip>
|
||||
|
||||
<para>
|
||||
The above patterns would match any vertex, or any two vertices connected
|
||||
by any edge, which isn't very interesting. Normally, we want to search
|
||||
for elements (vertices and edges) that have certain characteristics.
|
||||
These characteristics are written in between the parentheses or brackets.
|
||||
(This is also called an element pattern filler.) Typically, we would
|
||||
search for elements with a certain label. This is written by <literal>IS
|
||||
<replaceable>labelname</replaceable></literal>. For example, this would
|
||||
match all vertices with the label <literal>person</literal>:
|
||||
<programlisting>
|
||||
(IS person)
|
||||
</programlisting>
|
||||
The next
|
||||
example would match a vertex with the label <literal>person</literal>
|
||||
connected to a vertex with the label <literal>account</literal> connected
|
||||
by an edge with the label <literal>has</literal>.
|
||||
<programlisting>
|
||||
(IS person)-[IS has]->(IS account)
|
||||
</programlisting>
|
||||
Multiple labels can also be matched, using <quote>or</quote> semantics:
|
||||
<programlisting>
|
||||
(IS person)-[IS has]->(IS account|creditcard)
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Recall that edges are directed. The other direction is also possible in a
|
||||
path pattern, for example:
|
||||
<programlisting>
|
||||
(IS account)<-[IS has]-(IS person)
|
||||
</programlisting>
|
||||
It is also possible to match both directions:
|
||||
<programlisting>
|
||||
(IS person)-[IS is_friend_of]-(IS person)
|
||||
</programlisting>
|
||||
This has a meaning of <quote>or</quote>: An edge in either direction would
|
||||
match.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
In many cases, the edge patterns don't need a filler. (All the filtering
|
||||
then happens on the vertices.) For these cases, an abbreviated edge
|
||||
pattern syntax is available that omits the brackets, for example:
|
||||
<programlisting>
|
||||
(IS person)->(IS account)
|
||||
(IS account)<-(IS person)
|
||||
(IS person)-(IS person)
|
||||
</programlisting>
|
||||
As is often the case, abbreviated syntax can make expressions more compact
|
||||
but also sometimes harder to understand.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Furthermore, it is possible to define graph pattern variables in the path
|
||||
pattern expressions. These are bound to the matched elements and can be
|
||||
used to refer to the property values from those elements. The most
|
||||
important use is to use them in the <literal>COLUMNS</literal> clause to
|
||||
define the tabular result of the <literal>GRAPH_TABLE</literal> clause.
|
||||
For example (assuming appropriate definitions of the property graph as
|
||||
well as the underlying tables):
|
||||
<programlisting>
|
||||
GRAPH_TABLE (mygraph MATCH (p IS person)-[h IS has]->(a IS account)
|
||||
COLUMNS (p.name AS person_name, h.since AS has_account_since, a.num AS account_number)
|
||||
</programlisting>
|
||||
<literal>WHERE</literal> clauses can be used inside element patterns to
|
||||
filter matches:
|
||||
<programlisting>
|
||||
(IS person)-[IS has]->(a IS account WHERE a.type = 'savings')
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
<!-- TODO: multiple path patterns in a graph pattern (comma-separated) -->
|
||||
|
||||
<!-- TODO: quantifiers -->
|
||||
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
</chapter>
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ Complete list of usable sgml source files in this directory.
|
|||
<!ENTITY alterOperatorFamily SYSTEM "alter_opfamily.sgml">
|
||||
<!ENTITY alterPolicy SYSTEM "alter_policy.sgml">
|
||||
<!ENTITY alterProcedure SYSTEM "alter_procedure.sgml">
|
||||
<!ENTITY alterPropertyGraph SYSTEM "alter_property_graph.sgml">
|
||||
<!ENTITY alterPublication SYSTEM "alter_publication.sgml">
|
||||
<!ENTITY alterRole SYSTEM "alter_role.sgml">
|
||||
<!ENTITY alterRoutine SYSTEM "alter_routine.sgml">
|
||||
|
|
@ -79,6 +80,7 @@ Complete list of usable sgml source files in this directory.
|
|||
<!ENTITY createOperatorFamily SYSTEM "create_opfamily.sgml">
|
||||
<!ENTITY createPolicy SYSTEM "create_policy.sgml">
|
||||
<!ENTITY createProcedure SYSTEM "create_procedure.sgml">
|
||||
<!ENTITY createPropertyGraph SYSTEM "create_property_graph.sgml">
|
||||
<!ENTITY createPublication SYSTEM "create_publication.sgml">
|
||||
<!ENTITY createRole SYSTEM "create_role.sgml">
|
||||
<!ENTITY createRule SYSTEM "create_rule.sgml">
|
||||
|
|
@ -127,6 +129,7 @@ Complete list of usable sgml source files in this directory.
|
|||
<!ENTITY dropOwned SYSTEM "drop_owned.sgml">
|
||||
<!ENTITY dropPolicy SYSTEM "drop_policy.sgml">
|
||||
<!ENTITY dropProcedure SYSTEM "drop_procedure.sgml">
|
||||
<!ENTITY dropPropertyGraph SYSTEM "drop_property_graph.sgml">
|
||||
<!ENTITY dropPublication SYSTEM "drop_publication.sgml">
|
||||
<!ENTITY dropRole SYSTEM "drop_role.sgml">
|
||||
<!ENTITY dropRoutine SYSTEM "drop_routine.sgml">
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ ALTER EXTENSION <replaceable class="parameter">name</replaceable> DROP <replacea
|
|||
OPERATOR FAMILY <replaceable class="parameter">object_name</replaceable> USING <replaceable class="parameter">index_method</replaceable> |
|
||||
[ PROCEDURAL ] LANGUAGE <replaceable class="parameter">object_name</replaceable> |
|
||||
PROCEDURE <replaceable class="parameter">procedure_name</replaceable> [ ( [ [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">argname</replaceable> ] <replaceable class="parameter">argtype</replaceable> [, ...] ] ) ] |
|
||||
PROPERTY GRAPH <replaceable class="parameter">object_name</replaceable> |
|
||||
ROUTINE <replaceable class="parameter">routine_name</replaceable> [ ( [ [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">argname</replaceable> ] <replaceable class="parameter">argtype</replaceable> [, ...] ] ) ] |
|
||||
SCHEMA <replaceable class="parameter">object_name</replaceable> |
|
||||
SEQUENCE <replaceable class="parameter">object_name</replaceable> |
|
||||
|
|
@ -179,7 +180,7 @@ ALTER EXTENSION <replaceable class="parameter">name</replaceable> DROP <replacea
|
|||
The name of an object to be added to or removed from the extension.
|
||||
Names of tables,
|
||||
aggregates, domains, foreign tables, functions, operators,
|
||||
operator classes, operator families, procedures, routines, sequences, text search objects,
|
||||
operator classes, operator families, procedures, property graphs, routines, sequences, text search objects,
|
||||
types, and views can be schema-qualified.
|
||||
</para>
|
||||
</listitem>
|
||||
|
|
|
|||
299
doc/src/sgml/ref/alter_property_graph.sgml
Normal file
299
doc/src/sgml/ref/alter_property_graph.sgml
Normal file
|
|
@ -0,0 +1,299 @@
|
|||
<!--
|
||||
doc/src/sgml/ref/alter_property_graph.sgml
|
||||
PostgreSQL documentation
|
||||
-->
|
||||
|
||||
<refentry id="sql-alter-property-graph">
|
||||
<indexterm zone="sql-alter-property-graph">
|
||||
<primary>ALTER PROPERTY GRAPH</primary>
|
||||
</indexterm>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>ALTER PROPERTY GRAPH</refentrytitle>
|
||||
<manvolnum>7</manvolnum>
|
||||
<refmiscinfo>SQL - Language Statements</refmiscinfo>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>ALTER PROPERTY GRAPH</refname>
|
||||
<refpurpose>change the definition of an SQL-property graph</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<synopsis>
|
||||
ALTER PROPERTY GRAPH <replaceable class="parameter">name</replaceable> ADD
|
||||
[ {VERTEX|NODE} TABLES ( <replaceable class="parameter">vertex_table_definition</replaceable> [, ...] ) ]
|
||||
[ {EDGE|RELATIONSHIP} TABLES ( <replaceable class="parameter">edge_table_definition</replaceable> [, ...] ) ]
|
||||
|
||||
ALTER PROPERTY GRAPH <replaceable class="parameter">name</replaceable> DROP
|
||||
{VERTEX|NODE} TABLES ( <replaceable class="parameter">vertex_table_alias</replaceable> [, ...] ) [ CASCADE | RESTRICT ]
|
||||
|
||||
ALTER PROPERTY GRAPH <replaceable class="parameter">name</replaceable> DROP
|
||||
{EDGE|RELATIONSHIP} TABLES ( <replaceable class="parameter">edge_table_alias</replaceable> [, ...] ) [ CASCADE | RESTRICT ]
|
||||
|
||||
ALTER PROPERTY GRAPH <replaceable class="parameter">name</replaceable> ALTER
|
||||
{VERTEX|NODE|EDGE|RELATIONSHIP} TABLE <replaceable class="parameter">element_table_alias</replaceable>
|
||||
{ ADD LABEL <replaceable class="parameter">label_name</replaceable> [ NO PROPERTIES | PROPERTIES ALL COLUMNS | PROPERTIES ( { <replaceable class="parameter">expression</replaceable> [ AS <replaceable class="parameter">property_name</replaceable> ] } [, ...] ) ] } [ ... ]
|
||||
|
||||
ALTER PROPERTY GRAPH <replaceable class="parameter">name</replaceable> ALTER
|
||||
{VERTEX|NODE|EDGE|RELATIONSHIP} TABLE <replaceable class="parameter">element_table_alias</replaceable>
|
||||
DROP LABEL <replaceable class="parameter">label_name</replaceable> [ CASCADE | RESTRICT ]
|
||||
|
||||
ALTER PROPERTY GRAPH <replaceable class="parameter">name</replaceable> ALTER
|
||||
{VERTEX|NODE|EDGE|RELATIONSHIP} TABLE <replaceable class="parameter">element_table_alias</replaceable>
|
||||
ALTER LABEL <replaceable class="parameter">label_name</replaceable> ADD PROPERTIES ( { <replaceable class="parameter">expression</replaceable> [ AS <replaceable class="parameter">property_name</replaceable> ] } [, ...] )
|
||||
|
||||
ALTER PROPERTY GRAPH <replaceable class="parameter">name</replaceable> ALTER
|
||||
{VERTEX|NODE|EDGE|RELATIONSHIP} TABLE <replaceable class="parameter">element_table_alias</replaceable>
|
||||
ALTER LABEL <replaceable class="parameter">label_name</replaceable> DROP PROPERTIES ( <replaceable class="parameter">property_name</replaceable> [, ...] ) [ CASCADE | RESTRICT ]
|
||||
|
||||
ALTER PROPERTY GRAPH <replaceable class="parameter">name</replaceable> OWNER TO { <replaceable class="parameter">new_owner</replaceable> | CURRENT_USER | SESSION_USER }
|
||||
ALTER PROPERTY GRAPH <replaceable class="parameter">name</replaceable> RENAME TO <replaceable class="parameter">new_name</replaceable>
|
||||
ALTER PROPERTY GRAPH [ IF EXISTS ] <replaceable class="parameter">name</replaceable> SET SCHEMA <replaceable class="parameter">new_schema</replaceable>
|
||||
</synopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para>
|
||||
<command>ALTER PROPERTY GRAPH</command> changes the definition of an
|
||||
existing property graph. There are several subforms:
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><literal>ADD {VERTEX|NODE|EDGE|RELATIONSHIP} TABLES</literal></term>
|
||||
<listitem>
|
||||
<para>
|
||||
This form adds new vertex or edge tables to the property graph, using the
|
||||
same syntax as <link linkend="sql-create-property-graph"><command>CREATE
|
||||
PROPERTY GRAPH</command></link>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><literal>DROP {VERTEX|NODE|EDGE|RELATIONSHIP} TABLES</literal></term>
|
||||
<listitem>
|
||||
<para>
|
||||
This form removes vertex or edge tables from the property graph. (Only
|
||||
the association of the tables with the graph is removed. The tables
|
||||
themself are not dropped.)
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><literal>ALTER {VERTEX|NODE|EDGE|RELATIONSHIP} TABLE ... ADD LABEL</literal></term>
|
||||
<listitem>
|
||||
<para>
|
||||
This form adds a new label to an existing vertex or edge table, using
|
||||
the same syntax as <link
|
||||
linkend="sql-create-property-graph"><command>CREATE PROPERTY
|
||||
GRAPH</command></link>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><literal>ALTER {VERTEX|NODE|EDGE|RELATIONSHIP} TABLE ... DROP LABEL</literal></term>
|
||||
<listitem>
|
||||
<para>
|
||||
This form removes a label from an existing vertex or edge table.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><literal>ALTER {VERTEX|NODE|EDGE|RELATIONSHIP} TABLE ... ALTER LABEL ... ADD PROPERTIES</literal></term>
|
||||
<listitem>
|
||||
<para>
|
||||
This form adds new properties to an existing label on an existing
|
||||
vertex or edge table.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><literal>ALTER {VERTEX|NODE|EDGE|RELATIONSHIP} TABLE ... ALTER LABEL ... DROP PROPERTIES</literal></term>
|
||||
<listitem>
|
||||
<para>
|
||||
This form removes properties from an existing label on an existing
|
||||
vertex or edge table.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><literal>OWNER</literal></term>
|
||||
<listitem>
|
||||
<para>
|
||||
This form changes the owner of the property graph to the specified user.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><literal>RENAME</literal></term>
|
||||
<listitem>
|
||||
<para>
|
||||
This form changes the name of a property graph.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><literal>SET SCHEMA</literal></term>
|
||||
<listitem>
|
||||
<para>
|
||||
This form moves the property graph into another schema.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
You must own the property graph to use <command>ALTER PROPERTY
|
||||
GRAPH</command>. To change a property graph's schema, you must also have
|
||||
<literal>CREATE</literal> privilege on the new schema. To alter the owner,
|
||||
you must be able to <literal>SET ROLE</literal> to the new owning role, and
|
||||
that role must have <literal>CREATE</literal> privilege on the property
|
||||
graph's schema. (These restrictions enforce that altering the owner
|
||||
doesn't do anything you couldn't do by dropping and recreating the property
|
||||
graph. However, a superuser can alter ownership of any property graph
|
||||
anyway.)
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Parameters</title>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><replaceable class="parameter">name</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
The name (optionally schema-qualified) of a property graph to be altered.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><literal>IF EXISTS</literal></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Do not throw an error if the property graph does not exist. A notice is
|
||||
issued in this case.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><replaceable class="parameter">vertex_table_definition</replaceable></term>
|
||||
<term><replaceable class="parameter">edge_table_definition</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
See <link linkend="sql-create-property-graph"><command>CREATE PROPERTY
|
||||
GRAPH</command></link>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><replaceable class="parameter">vertex_table_alias</replaceable></term>
|
||||
<term><replaceable class="parameter">edge_table_alias</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
The alias of an existing vertex or edge table to operate on. (Note that
|
||||
the alias is potentially different from the name of the underlying
|
||||
table, if the vertex or edge table was created with <literal>AS
|
||||
<replaceable class="parameter">alias</replaceable></literal>.)
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><replaceable class="parameter">label_name</replaceable></term>
|
||||
<term><replaceable class="parameter">property_name</replaceable></term>
|
||||
<term><replaceable class="parameter">expression</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
See <link linkend="sql-create-property-graph"><command>CREATE PROPERTY
|
||||
GRAPH</command></link>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><replaceable class="parameter">new_owner</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
The user name of the new owner of the property graph.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><replaceable class="parameter">new_name</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
The new name for the property graph.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><replaceable class="parameter">new_schema</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
The new schema for the property graph.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Notes</title>
|
||||
|
||||
<para>
|
||||
The consistency checks on a property graph described at <xref
|
||||
linkend="sql-create-property-graph-notes"/> must be maintained by
|
||||
<command>ALTER PROPERTY GRAPH</command> operations. In some cases, it
|
||||
might be necessary to make multiple alterations in a single command to
|
||||
satisfy the checks.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Examples</title>
|
||||
|
||||
<para>
|
||||
<programlisting>
|
||||
ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (v2);
|
||||
|
||||
ALTER PROPERTY GRAPH g1 ALTER VERTEX TABLE v1 DROP LABEL foo;
|
||||
|
||||
ALTER PROPERTY GRAPH g1 RENAME TO g2;
|
||||
</programlisting></para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Compatibility</title>
|
||||
|
||||
<para>
|
||||
<command>ALTER PROPERTY GRAPH</command> conforms to ISO/IEC 9075-16
|
||||
(SQL/PGQ).
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>See Also</title>
|
||||
|
||||
<simplelist type="inline">
|
||||
<member><xref linkend="sql-create-property-graph"/></member>
|
||||
<member><xref linkend="sql-drop-property-graph"/></member>
|
||||
</simplelist>
|
||||
</refsect1>
|
||||
</refentry>
|
||||
|
|
@ -47,6 +47,7 @@ COMMENT ON
|
|||
POLICY <replaceable class="parameter">policy_name</replaceable> ON <replaceable class="parameter">table_name</replaceable> |
|
||||
[ PROCEDURAL ] LANGUAGE <replaceable class="parameter">object_name</replaceable> |
|
||||
PROCEDURE <replaceable class="parameter">procedure_name</replaceable> [ ( [ [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">argname</replaceable> ] <replaceable class="parameter">argtype</replaceable> [, ...] ] ) ] |
|
||||
PROPERTY GRAPH <replaceable class="parameter">object_name</replaceable>
|
||||
PUBLICATION <replaceable class="parameter">object_name</replaceable> |
|
||||
ROLE <replaceable class="parameter">object_name</replaceable> |
|
||||
ROUTINE <replaceable class="parameter">routine_name</replaceable> [ ( [ [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">argname</replaceable> ] <replaceable class="parameter">argtype</replaceable> [, ...] ] ) ] |
|
||||
|
|
|
|||
318
doc/src/sgml/ref/create_property_graph.sgml
Normal file
318
doc/src/sgml/ref/create_property_graph.sgml
Normal file
|
|
@ -0,0 +1,318 @@
|
|||
<!--
|
||||
doc/src/sgml/ref/create_property_graph.sgml
|
||||
PostgreSQL documentation
|
||||
-->
|
||||
|
||||
<refentry id="sql-create-property-graph">
|
||||
<indexterm zone="sql-create-property-graph">
|
||||
<primary>CREATE PROPERTY GRAPH</primary>
|
||||
</indexterm>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>CREATE PROPERTY GRAPH</refentrytitle>
|
||||
<manvolnum>7</manvolnum>
|
||||
<refmiscinfo>SQL - Language Statements</refmiscinfo>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>CREATE PROPERTY GRAPH</refname>
|
||||
<refpurpose>define an SQL-property graph</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<synopsis>
|
||||
CREATE [ TEMP | TEMPORARY ] PROPERTY GRAPH <replaceable class="parameter">name</replaceable>
|
||||
[ {VERTEX|NODE} TABLES ( <replaceable class="parameter">vertex_table_definition</replaceable> [, ...] ) ]
|
||||
[ {EDGE|RELATIONSHIP} TABLES ( <replaceable class="parameter">edge_table_definition</replaceable> [, ...] ) ]
|
||||
|
||||
<phrase>where <replaceable class="parameter">vertex_table_definition</replaceable> is:</phrase>
|
||||
|
||||
<replaceable class="parameter">vertex_table_name</replaceable> [ AS <replaceable class="parameter">alias</replaceable> ] [ KEY ( <replaceable class="parameter">column_name</replaceable> [, ...] ) ] [ <replaceable class="parameter">element_table_label_and_properties</replaceable> ]
|
||||
|
||||
<phrase>and <replaceable class="parameter">edge_table_definition</replaceable> is:</phrase>
|
||||
|
||||
<replaceable class="parameter">edge_table_name</replaceable> [ AS <replaceable class="parameter">alias</replaceable> ] [ KEY ( <replaceable class="parameter">column_name</replaceable> [, ...] ) ]
|
||||
SOURCE [ KEY ( <replaceable class="parameter">column_name</replaceable> [, ...] ) REFERENCES ] <replaceable class="parameter">source_table</replaceable> [ ( <replaceable class="parameter">column_name</replaceable> [, ...] ) ]
|
||||
DESTINATION [ KEY ( <replaceable class="parameter">column_name</replaceable> [, ...] ) REFERENCES ] <replaceable class="parameter">dest_table</replaceable> [ ( <replaceable class="parameter">column_name</replaceable> [, ...] ) ]
|
||||
[ <replaceable class="parameter">element_table_label_and_properties</replaceable> ]
|
||||
|
||||
<phrase>and <replaceable class="parameter">element_table_label_and_properties</replaceable> is either:</phrase>
|
||||
|
||||
NO PROPERTIES | PROPERTIES ALL COLUMNS | PROPERTIES ( { <replaceable class="parameter">expression</replaceable> [ AS <replaceable class="parameter">property_name</replaceable> ] } [, ...] )
|
||||
|
||||
<phrase>or:</phrase>
|
||||
|
||||
{ { LABEL <replaceable class="parameter">label_name</replaceable> | DEFAULT LABEL } [ NO PROPERTIES | PROPERTIES ALL COLUMNS | PROPERTIES ( { <replaceable class="parameter">expression</replaceable> [ AS <replaceable class="parameter">property_name</replaceable> ] } [, ...] ) ] } [...]
|
||||
</synopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para>
|
||||
<command>CREATE PROPERTY GRAPH</command> defines a property graph. A
|
||||
property graph consists of vertices and edges, together called elements,
|
||||
each with associated labels and properties, and can be queried using the
|
||||
<literal>GRAPH_TABLE</literal> clause of <xref linkend="sql-select"/> with
|
||||
a special path matching syntax. The data in the graph is stored in regular
|
||||
tables (or views, foreign tables, etc.). Each vertex or edge corresponds
|
||||
to a table. The property graph definition links these tables together into
|
||||
a graph structure that can be queried using graph query techniques.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<command>CREATE PROPERTY GRAPH</command> does not physically materialize a
|
||||
graph. It is thus similar to <command>CREATE VIEW</command> in that it
|
||||
records a structure that is used only when the defined object is queried.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
If a schema name is given (for example, <literal>CREATE PROPERTY GRAPH
|
||||
myschema.mygraph ...</literal>) then the property graph is created in the
|
||||
specified schema. Otherwise it is created in the current schema.
|
||||
Temporary property graphs exist in a special schema, so a schema name
|
||||
cannot be given when creating a temporary property graph. Property graphs
|
||||
share a namespace with tables and other relation types, so the name of the
|
||||
property graph must be distinct from the name of any other relation (table,
|
||||
sequence, index, view, materialized view, or foreign table) in the same
|
||||
schema.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Parameters</title>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><replaceable class="parameter">name</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
The name (optionally schema-qualified) of the new property graph.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><literal>VERTEX</literal>/<literal>NODE</literal></term>
|
||||
<term><literal>EDGE</literal>/<literal>RELATIONSHIP</literal></term>
|
||||
<listitem>
|
||||
<para>
|
||||
These keywords are synonyms, respectively.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><replaceable class="parameter">vertex_table_name</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
The name of a table that will contain vertices in the new property
|
||||
graph.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><replaceable class="parameter">edge_table_name</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
The name of a table that will contain edges in the new property graph.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><replaceable class="parameter">alias</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
A unique identifier for the vertex or edge table. This defaults to the
|
||||
name of the table. Aliases must be unique in a property graph
|
||||
definition (across all vertex table and edge table definitions).
|
||||
(Therefore, if a table is used more than once as a vertex or edge table,
|
||||
then an explicit alias must be specified for at least one of them to
|
||||
distinguish them.)
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><literal>KEY ( <replaceable class="parameter">column_name</replaceable> [, ...] )</literal></term>
|
||||
<listitem>
|
||||
<para>
|
||||
A set of columns that uniquely identifies a row in the vertex or edge
|
||||
table. Defaults to the primary key.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><replaceable class="parameter">source_table</replaceable></term>
|
||||
<term><replaceable class="parameter">dest_table</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
The vertex tables that the edge table is linked to. These refer to the
|
||||
aliases of the source and destination vertex tables respectively.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><literal>KEY ( <replaceable class="parameter">column_name</replaceable> [, ...] ) REFERENCES ... ( <replaceable class="parameter">column_name</replaceable> [, ...] )</literal></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Two sets of columns that connect the edge table and the source or
|
||||
destination vertex table, like in a foreign-key relationship. If a
|
||||
foreign-key constraint between the two tables exists, it is used by
|
||||
default.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><replaceable class="parameter">element_table_label_and_properties</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Defines the labels and properties for the element (vertex or edge)
|
||||
table. Each element has at least one label. By default, the label is
|
||||
the same as the element table alias. This can be specified explicitly
|
||||
as <literal>DEFAULT LABEL</literal>. Alternatively, one or more freely
|
||||
chosen label names can be specified. (Label names do not have to be
|
||||
unique across a property graph. It can be useful to assign the same
|
||||
label to different elements.) Each label has a list (possibly empty) of
|
||||
properties. By default, all columns of a table are automatically
|
||||
exposed as properties. This can be specified explicitly as
|
||||
<literal>PROPERTIES ALL COLUMNS</literal>. Alternatively, a list of
|
||||
expressions, which can refer to the columns of the underlying table, can
|
||||
be specified as properties. If the expressions are not a plain column
|
||||
reference, then an explicit property name must also be specified.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1 id="sql-create-property-graph-notes">
|
||||
<title>Notes</title>
|
||||
|
||||
<para>
|
||||
The following consistency checks must be satisfied by a property graph definition:
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
In a property graph, labels with the same name applied to different
|
||||
property graph elements must have the same number of properties and
|
||||
those properties must have the same names. For example, the following
|
||||
would be allowed:
|
||||
<programlisting>
|
||||
CREATE PROPERTY GRAPH g1
|
||||
VERTEX TABLES (
|
||||
v1 LABEL foo PROPERTIES (x, y),
|
||||
v2 LABEL foo PROPERTIES (x, y)
|
||||
) ...
|
||||
</programlisting>
|
||||
but this would not:
|
||||
<programlisting>
|
||||
CREATE PROPERTY GRAPH g1
|
||||
VERTEX TABLES (
|
||||
v1 LABEL foo PROPERTIES (x, y),
|
||||
v2 LABEL foo PROPERTIES (z)
|
||||
) ...
|
||||
</programlisting></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
In a property graph, all properties with the same name must have the
|
||||
same data type, independent of which label they are on. For example,
|
||||
this would be allowed:
|
||||
<programlisting>
|
||||
CREATE TABLE v1 (a int, b int);
|
||||
CREATE TABLE v2 (a int, b int);
|
||||
|
||||
CREATE PROPERTY GRAPH g1
|
||||
VERTEX TABLES (
|
||||
v1 LABEL foo PROPERTIES (a, b),
|
||||
v2 LABEL bar PROPERTIES (a, b)
|
||||
) ...
|
||||
</programlisting>
|
||||
but this would not:
|
||||
<programlisting>
|
||||
CREATE TABLE v1 (a int, b int);
|
||||
CREATE TABLE v2 (a int, b varchar);
|
||||
|
||||
CREATE PROPERTY GRAPH g1
|
||||
VERTEX TABLES (
|
||||
v1 LABEL foo PROPERTIES (a, b),
|
||||
v2 LABEL bar PROPERTIES (a, b)
|
||||
) ...
|
||||
</programlisting></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
For each property graph element, all properties with the same name must
|
||||
have the same expression for each label. For example, this would be
|
||||
allowed:
|
||||
<programlisting>
|
||||
CREATE PROPERTY GRAPH g1
|
||||
VERTEX TABLES (
|
||||
v1 LABEL foo PROPERTIES (a * 2 AS x) LABEL bar PROPERTIES (a * 2 AS x)
|
||||
) ...
|
||||
</programlisting>
|
||||
but this would not:
|
||||
<programlisting>
|
||||
CREATE PROPERTY GRAPH g1
|
||||
VERTEX TABLES (
|
||||
v1 LABEL foo PROPERTIES (a * 2 AS x) LABEL bar PROPERTIES (a * 10 AS x)
|
||||
) ...
|
||||
</programlisting></para>
|
||||
</listitem>
|
||||
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Property graphs are queried using the <literal>GRAPH_TABLE</literal> clause
|
||||
of <xref linkend="sql-select"/>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Access to the base relations underlying the <literal>GRAPH_TABLE</literal>
|
||||
clause is determined by the permissions of the user executing the query,
|
||||
rather than the property graph owner. Thus, the user of a property graph must
|
||||
have the relevant permissions on the property graph and base relations
|
||||
underlying the <literal>GRAPH_TABLE</literal> clause.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Examples</title>
|
||||
|
||||
<para>
|
||||
<programlisting>
|
||||
CREATE PROPERTY GRAPH g1
|
||||
VERTEX TABLES (v1, v2, v3)
|
||||
EDGE TABLES (e1 SOURCE v1 DESTINATION v2,
|
||||
e2 SOURCE v1 DESTINATION v3);
|
||||
</programlisting></para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Compatibility</title>
|
||||
|
||||
<para>
|
||||
<command>CREATE PROPERTY GRAPH</command> conforms to ISO/IEC 9075-16
|
||||
(SQL/PGQ).
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>See Also</title>
|
||||
|
||||
<simplelist type="inline">
|
||||
<member><xref linkend="sql-alter-property-graph"/></member>
|
||||
<member><xref linkend="sql-drop-property-graph"/></member>
|
||||
</simplelist>
|
||||
</refsect1>
|
||||
</refentry>
|
||||
111
doc/src/sgml/ref/drop_property_graph.sgml
Normal file
111
doc/src/sgml/ref/drop_property_graph.sgml
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
<!--
|
||||
doc/src/sgml/ref/drop_property_graph.sgml
|
||||
PostgreSQL documentation
|
||||
-->
|
||||
|
||||
<refentry id="sql-drop-property-graph">
|
||||
<indexterm zone="sql-drop-property-graph">
|
||||
<primary>DROP PROPERTY GRAPH</primary>
|
||||
</indexterm>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>DROP PROPERTY GRAPH</refentrytitle>
|
||||
<manvolnum>7</manvolnum>
|
||||
<refmiscinfo>SQL - Language Statements</refmiscinfo>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>DROP PROPERTY GRAPH</refname>
|
||||
<refpurpose>remove an SQL-property graph</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<synopsis>
|
||||
DROP PROPERTY GRAPH [ IF EXISTS ] <replaceable class="parameter">name</replaceable> [, ...] [ CASCADE | RESTRICT ]
|
||||
</synopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para>
|
||||
<command>DROP PROPERTY GRAPH</command> drops an existing property graph.
|
||||
To execute this command you must be the owner of the property graph.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Parameters</title>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><literal>IF EXISTS</literal></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Do not throw an error if the property graph does not exist. A notice is
|
||||
issued in this case.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><replaceable class="parameter">name</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
The name (optionally schema-qualified) of the property graph to remove.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><literal>CASCADE</literal></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Automatically drop objects that depend on the property graph, and in
|
||||
turn all objects that depend on those objects (see <xref
|
||||
linkend="ddl-depend"/>).
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><literal>RESTRICT</literal></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Refuse to drop the property graph if any objects depend on it. This is
|
||||
the default.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Examples</title>
|
||||
|
||||
<para>
|
||||
<programlisting>
|
||||
DROP PROPERTY GRAPH g1;
|
||||
</programlisting></para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Compatibility</title>
|
||||
|
||||
<para>
|
||||
<command>DROP PROPERTY GRAPH</command> conforms to ISO/IEC 9075-16
|
||||
(SQL/PGQ), except that the standard only allows one property graph to be
|
||||
dropped per command, and apart from the <literal>IF EXISTS</literal>
|
||||
option, which is a <productname>PostgreSQL</productname> extension.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>See Also</title>
|
||||
|
||||
<simplelist type="inline">
|
||||
<member><xref linkend="sql-create-property-graph"/></member>
|
||||
<member><xref linkend="sql-alter-property-graph"/></member>
|
||||
</simplelist>
|
||||
</refsect1>
|
||||
</refentry>
|
||||
|
|
@ -82,6 +82,11 @@ GRANT { { SET | ALTER SYSTEM } [, ... ] | ALL [ PRIVILEGES ] }
|
|||
TO <replaceable class="parameter">role_specification</replaceable> [, ...] [ WITH GRANT OPTION ]
|
||||
[ GRANTED BY <replaceable class="parameter">role_specification</replaceable> ]
|
||||
|
||||
GRANT { SELECT | ALL [ PRIVILEGES ] }
|
||||
ON PROPERTY GRAPH <replaceable>graph_name</replaceable> [, ...]
|
||||
TO <replaceable class="parameter">role_specification</replaceable> [, ...] [ WITH GRANT OPTION ]
|
||||
[ GRANTED BY <replaceable class="parameter">role_specification</replaceable> ]
|
||||
|
||||
GRANT { { CREATE | USAGE } [, ...] | ALL [ PRIVILEGES ] }
|
||||
ON SCHEMA <replaceable>schema_name</replaceable> [, ...]
|
||||
TO <replaceable class="parameter">role_specification</replaceable> [, ...] [ WITH GRANT OPTION ]
|
||||
|
|
@ -119,7 +124,7 @@ GRANT <replaceable class="parameter">role_name</replaceable> [, ...] TO <replace
|
|||
that grants privileges on a database object (table, column, view,
|
||||
foreign table, sequence, database, foreign-data wrapper, foreign server,
|
||||
function, procedure, procedural language, large object, configuration
|
||||
parameter, schema, tablespace, or type), and one that grants
|
||||
parameter, property graph, schema, tablespace, or type), and one that grants
|
||||
membership in a role. These variants are similar in many ways, but
|
||||
they are different enough to be described separately.
|
||||
</para>
|
||||
|
|
|
|||
|
|
@ -1293,7 +1293,7 @@ SELECT $1 \parse stmt1
|
|||
|
||||
<listitem>
|
||||
<para>
|
||||
For each relation (table, view, materialized view, index, sequence,
|
||||
For each relation (table, view, materialized view, index, property graph, sequence,
|
||||
or foreign table)
|
||||
or composite type matching the
|
||||
<replaceable class="parameter">pattern</replaceable>, show all
|
||||
|
|
@ -1333,9 +1333,9 @@ SELECT $1 \parse stmt1
|
|||
<para>
|
||||
If <command>\d</command> is used without a
|
||||
<replaceable class="parameter">pattern</replaceable> argument, it is
|
||||
equivalent to <command>\dtvmsE</command> which will show a list of
|
||||
all visible tables, views, materialized views, sequences and
|
||||
foreign tables.
|
||||
equivalent to <command>\dtvmsEG</command> which will show a list of
|
||||
all visible tables, views, materialized views, sequences,
|
||||
foreign tables, and property graphs.
|
||||
This is purely a convenience measure.
|
||||
</para>
|
||||
<para>
|
||||
|
|
@ -1643,6 +1643,7 @@ SELECT $1 \parse stmt1
|
|||
|
||||
<varlistentry id="app-psql-meta-command-de">
|
||||
<term><literal>\dE[Sx+] [ <link linkend="app-psql-patterns"><replaceable class="parameter">pattern</replaceable></link> ]</literal></term>
|
||||
<term><literal>\dG[Sx+] [ <link linkend="app-psql-patterns"><replaceable class="parameter">pattern</replaceable></link> ]</literal></term>
|
||||
<term><literal>\di[Sx+] [ <link linkend="app-psql-patterns"><replaceable class="parameter">pattern</replaceable></link> ]</literal></term>
|
||||
<term><literal>\dm[Sx+] [ <link linkend="app-psql-patterns"><replaceable class="parameter">pattern</replaceable></link> ]</literal></term>
|
||||
<term><literal>\ds[Sx+] [ <link linkend="app-psql-patterns"><replaceable class="parameter">pattern</replaceable></link> ]</literal></term>
|
||||
|
|
@ -1651,10 +1652,10 @@ SELECT $1 \parse stmt1
|
|||
|
||||
<listitem>
|
||||
<para>
|
||||
In this group of commands, the letters <literal>E</literal>,
|
||||
In this group of commands, the letters <literal>E</literal>, <literal>G</literal>,
|
||||
<literal>i</literal>, <literal>m</literal>, <literal>s</literal>,
|
||||
<literal>t</literal>, and <literal>v</literal>
|
||||
stand for foreign table, index, materialized view,
|
||||
stand for foreign table, index, property graph, materialized view,
|
||||
sequence, table, and view,
|
||||
respectively.
|
||||
You can specify any or all of
|
||||
|
|
|
|||
|
|
@ -104,6 +104,13 @@ REVOKE [ GRANT OPTION FOR ]
|
|||
[ GRANTED BY <replaceable class="parameter">role_specification</replaceable> ]
|
||||
[ CASCADE | RESTRICT ]
|
||||
|
||||
REVOKE [ GRANT OPTION FOR ]
|
||||
{ SELECT | ALL [ PRIVILEGES ] }
|
||||
ON PROPERTY GRAPH <replaceable>graph_name</replaceable> [, ...]
|
||||
FROM <replaceable class="parameter">role_specification</replaceable> [, ...]
|
||||
[ GRANTED BY <replaceable class="parameter">role_specification</replaceable> ]
|
||||
[ CASCADE | RESTRICT ]
|
||||
|
||||
REVOKE [ GRANT OPTION FOR ]
|
||||
{ { CREATE | USAGE } [, ...] | ALL [ PRIVILEGES ] }
|
||||
ON SCHEMA <replaceable>schema_name</replaceable> [, ...]
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ SECURITY LABEL [ FOR <replaceable class="parameter">provider</replaceable> ] ON
|
|||
MATERIALIZED VIEW <replaceable class="parameter">object_name</replaceable> |
|
||||
[ PROCEDURAL ] LANGUAGE <replaceable class="parameter">object_name</replaceable> |
|
||||
PROCEDURE <replaceable class="parameter">procedure_name</replaceable> [ ( [ [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">argname</replaceable> ] <replaceable class="parameter">argtype</replaceable> [, ...] ] ) ] |
|
||||
PROPERTY GRAPH <replaceable class="parameter">object_name</replaceable>
|
||||
PUBLICATION <replaceable class="parameter">object_name</replaceable> |
|
||||
ROLE <replaceable class="parameter">object_name</replaceable> |
|
||||
ROUTINE <replaceable class="parameter">routine_name</replaceable> [ ( [ [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">argname</replaceable> ] <replaceable class="parameter">argtype</replaceable> [, ...] ] ) ] |
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ SELECT [ ALL | DISTINCT [ ON ( <replaceable class="parameter">expression</replac
|
|||
[ LATERAL ] <replaceable class="parameter">function_name</replaceable> ( [ <replaceable class="parameter">argument</replaceable> [, ...] ] ) AS ( <replaceable class="parameter">column_definition</replaceable> [, ...] )
|
||||
[ LATERAL ] ROWS FROM( <replaceable class="parameter">function_name</replaceable> ( [ <replaceable class="parameter">argument</replaceable> [, ...] ] ) [ AS ( <replaceable class="parameter">column_definition</replaceable> [, ...] ) ] [, ...] )
|
||||
[ WITH ORDINALITY ] [ [ AS ] <replaceable class="parameter">alias</replaceable> [ ( <replaceable class="parameter">column_alias</replaceable> [, ...] ) ] ]
|
||||
GRAPH_TABLE ( <replaceable class="parameter">graph_name</replaceable> MATCH <replaceable class="parameter">graph_pattern</replaceable> COLUMNS ( { <replaceable class="parameter">expression</replaceable> [ AS <replaceable class="parameter">name</replaceable> ] } [, ...] ) ) [ [ AS ] <replaceable class="parameter">alias</replaceable> [ ( <replaceable class="parameter">column_alias</replaceable> [, ...] ) ] ]
|
||||
<replaceable class="parameter">from_item</replaceable> <replaceable class="parameter">join_type</replaceable> <replaceable class="parameter">from_item</replaceable> { ON <replaceable class="parameter">join_condition</replaceable> | USING ( <replaceable class="parameter">join_column</replaceable> [, ...] ) [ AS <replaceable class="parameter">join_using_alias</replaceable> ] }
|
||||
<replaceable class="parameter">from_item</replaceable> NATURAL <replaceable class="parameter">join_type</replaceable> <replaceable class="parameter">from_item</replaceable>
|
||||
<replaceable class="parameter">from_item</replaceable> CROSS JOIN <replaceable class="parameter">from_item</replaceable>
|
||||
|
|
@ -587,6 +588,48 @@ TABLE [ ONLY ] <replaceable class="parameter">table_name</replaceable> [ * ]
|
|||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><literal>GRAPH_TABLE ( <replaceable class="parameter">graph_name</replaceable> MATCH <replaceable class="parameter">graph_pattern</replaceable> COLUMNS ( { <replaceable class="parameter">expression</replaceable> [ AS <replaceable class="parameter">name</replaceable> ] } [, ...] ) )</literal></term>
|
||||
<listitem>
|
||||
<para>
|
||||
This clause produces output from matching the specifying graph pattern
|
||||
against a property graph. See <xref linkend="ddl-property-graphs"/>
|
||||
and <xref linkend="queries-graph"/> for more information.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<replaceable class="parameter">graph_name</replaceable> is the name
|
||||
(optionally schema-qualified) of an existing property graph (defined
|
||||
with <xref linkend="sql-create-property-graph"/>).
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<replaceable class="parameter">graph_pattern</replaceable> is a graph
|
||||
pattern in a special graph pattern sublanguage. See <xref
|
||||
linkend="queries-graph-patterns"/>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The <literal>COLUMNS</literal> clause defines the output columns of
|
||||
the <literal>GRAPH_TABLE</literal> clause. <replaceable
|
||||
class="parameter">expression</replaceable> is a scalar expression
|
||||
using the graph pattern variables defined in the <replaceable
|
||||
class="parameter">graph_pattern</replaceable>. The name of the output
|
||||
columns are specified using the <literal>AS</literal> clauses. If the
|
||||
expressions are simple property references, the property names are
|
||||
used as the output names, otherwise an explicit name must be
|
||||
specified.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Like for other <literal>FROM</literal> clause items, a table alias
|
||||
name and column alias names may follow the <literal>GRAPH_TABLE
|
||||
(...)</literal> clause. (A column alias list would be redundant with
|
||||
the <literal>COLUMNS</literal> clause.)
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><replaceable class="parameter">join_type</replaceable></term>
|
||||
<listitem>
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@
|
|||
&alterOperatorFamily;
|
||||
&alterPolicy;
|
||||
&alterProcedure;
|
||||
&alterPropertyGraph;
|
||||
&alterPublication;
|
||||
&alterRole;
|
||||
&alterRoutine;
|
||||
|
|
@ -107,6 +108,7 @@
|
|||
&createOperatorFamily;
|
||||
&createPolicy;
|
||||
&createProcedure;
|
||||
&createPropertyGraph;
|
||||
&createPublication;
|
||||
&createRole;
|
||||
&createRule;
|
||||
|
|
@ -155,6 +157,7 @@
|
|||
&dropOwned;
|
||||
&dropPolicy;
|
||||
&dropProcedure;
|
||||
&dropPropertyGraph;
|
||||
&dropPublication;
|
||||
&dropRole;
|
||||
&dropRoutine;
|
||||
|
|
|
|||
|
|
@ -290,6 +290,9 @@ restrict_and_check_grant(bool is_grant, AclMode avail_goptions, bool all_privs,
|
|||
case OBJECT_PARAMETER_ACL:
|
||||
whole_mask = ACL_ALL_RIGHTS_PARAMETER_ACL;
|
||||
break;
|
||||
case OBJECT_PROPGRAPH:
|
||||
whole_mask = ACL_ALL_RIGHTS_PROPGRAPH;
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "unrecognized object type: %d", objtype);
|
||||
/* not reached, but keep compiler quiet */
|
||||
|
|
@ -534,6 +537,10 @@ ExecuteGrantStmt(GrantStmt *stmt)
|
|||
all_privileges = ACL_ALL_RIGHTS_PARAMETER_ACL;
|
||||
errormsg = gettext_noop("invalid privilege type %s for parameter");
|
||||
break;
|
||||
case OBJECT_PROPGRAPH:
|
||||
all_privileges = ACL_ALL_RIGHTS_PROPGRAPH;
|
||||
errormsg = gettext_noop("invalid privilege type %s for property graph");
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "unrecognized GrantStmt.objtype: %d",
|
||||
(int) stmt->objtype);
|
||||
|
|
@ -604,6 +611,7 @@ ExecGrantStmt_oids(InternalGrant *istmt)
|
|||
{
|
||||
case OBJECT_TABLE:
|
||||
case OBJECT_SEQUENCE:
|
||||
case OBJECT_PROPGRAPH:
|
||||
ExecGrant_Relation(istmt);
|
||||
break;
|
||||
case OBJECT_DATABASE:
|
||||
|
|
@ -700,6 +708,7 @@ objectNamesToOids(ObjectType objtype, List *objnames, bool is_grant)
|
|||
|
||||
case OBJECT_TABLE:
|
||||
case OBJECT_SEQUENCE:
|
||||
case OBJECT_PROPGRAPH:
|
||||
|
||||
/*
|
||||
* Here, we don't use get_object_address(). It requires that the
|
||||
|
|
@ -817,6 +826,10 @@ objectsInSchemaToOids(ObjectType objtype, List *nspnames)
|
|||
objs = getRelationsInNamespace(namespaceId, RELKIND_SEQUENCE);
|
||||
objects = list_concat(objects, objs);
|
||||
break;
|
||||
case OBJECT_PROPGRAPH:
|
||||
objs = getRelationsInNamespace(namespaceId, RELKIND_PROPGRAPH);
|
||||
objects = list_concat(objects, objs);
|
||||
break;
|
||||
case OBJECT_FUNCTION:
|
||||
case OBJECT_PROCEDURE:
|
||||
case OBJECT_ROUTINE:
|
||||
|
|
@ -1022,6 +1035,10 @@ ExecAlterDefaultPrivilegesStmt(ParseState *pstate, AlterDefaultPrivilegesStmt *s
|
|||
all_privileges = ACL_ALL_RIGHTS_LARGEOBJECT;
|
||||
errormsg = gettext_noop("invalid privilege type %s for large object");
|
||||
break;
|
||||
case OBJECT_PROPGRAPH:
|
||||
all_privileges = ACL_ALL_RIGHTS_PROPGRAPH;
|
||||
errormsg = gettext_noop("invalid privilege type %s for property graph");
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "unrecognized GrantStmt.objtype: %d",
|
||||
(int) action->objtype);
|
||||
|
|
@ -1836,11 +1853,20 @@ ExecGrant_Relation(InternalGrant *istmt)
|
|||
errmsg("\"%s\" is not a sequence",
|
||||
NameStr(pg_class_tuple->relname))));
|
||||
|
||||
if (istmt->objtype == OBJECT_PROPGRAPH &&
|
||||
pg_class_tuple->relkind != RELKIND_PROPGRAPH)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
||||
errmsg("\"%s\" is not a property graph",
|
||||
NameStr(pg_class_tuple->relname))));
|
||||
|
||||
/* Adjust the default permissions based on object type */
|
||||
if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
|
||||
{
|
||||
if (pg_class_tuple->relkind == RELKIND_SEQUENCE)
|
||||
this_privileges = ACL_ALL_RIGHTS_SEQUENCE;
|
||||
else if (pg_class_tuple->relkind == RELKIND_PROPGRAPH)
|
||||
this_privileges = ACL_ALL_RIGHTS_PROPGRAPH;
|
||||
else
|
||||
this_privileges = ACL_ALL_RIGHTS_RELATION;
|
||||
}
|
||||
|
|
@ -1934,6 +1960,9 @@ ExecGrant_Relation(InternalGrant *istmt)
|
|||
case RELKIND_SEQUENCE:
|
||||
old_acl = acldefault(OBJECT_SEQUENCE, ownerId);
|
||||
break;
|
||||
case RELKIND_PROPGRAPH:
|
||||
old_acl = acldefault(OBJECT_PROPGRAPH, ownerId);
|
||||
break;
|
||||
default:
|
||||
old_acl = acldefault(OBJECT_TABLE, ownerId);
|
||||
break;
|
||||
|
|
@ -2731,6 +2760,9 @@ aclcheck_error(AclResult aclerr, ObjectType objtype,
|
|||
case OBJECT_PROCEDURE:
|
||||
msg = gettext_noop("permission denied for procedure %s");
|
||||
break;
|
||||
case OBJECT_PROPGRAPH:
|
||||
msg = gettext_noop("permission denied for property graph %s");
|
||||
break;
|
||||
case OBJECT_PUBLICATION:
|
||||
msg = gettext_noop("permission denied for publication %s");
|
||||
break;
|
||||
|
|
@ -2857,6 +2889,9 @@ aclcheck_error(AclResult aclerr, ObjectType objtype,
|
|||
case OBJECT_PROCEDURE:
|
||||
msg = gettext_noop("must be owner of procedure %s");
|
||||
break;
|
||||
case OBJECT_PROPGRAPH:
|
||||
msg = gettext_noop("must be owner of property graph %s");
|
||||
break;
|
||||
case OBJECT_PUBLICATION:
|
||||
msg = gettext_noop("must be owner of publication %s");
|
||||
break;
|
||||
|
|
@ -2993,6 +3028,7 @@ pg_aclmask(ObjectType objtype, Oid object_oid, AttrNumber attnum, Oid roleid,
|
|||
pg_attribute_aclmask(object_oid, attnum, roleid, mask, how);
|
||||
case OBJECT_TABLE:
|
||||
case OBJECT_SEQUENCE:
|
||||
case OBJECT_PROPGRAPH:
|
||||
return pg_class_aclmask(object_oid, roleid, mask, how);
|
||||
case OBJECT_DATABASE:
|
||||
return object_aclmask(DatabaseRelationId, object_oid, roleid, mask, how);
|
||||
|
|
|
|||
|
|
@ -51,6 +51,11 @@
|
|||
#include "catalog/pg_parameter_acl.h"
|
||||
#include "catalog/pg_policy.h"
|
||||
#include "catalog/pg_proc.h"
|
||||
#include "catalog/pg_propgraph_element.h"
|
||||
#include "catalog/pg_propgraph_element_label.h"
|
||||
#include "catalog/pg_propgraph_label.h"
|
||||
#include "catalog/pg_propgraph_label_property.h"
|
||||
#include "catalog/pg_propgraph_property.h"
|
||||
#include "catalog/pg_publication.h"
|
||||
#include "catalog/pg_publication_namespace.h"
|
||||
#include "catalog/pg_publication_rel.h"
|
||||
|
|
@ -1514,6 +1519,11 @@ doDeletion(const ObjectAddress *object, int flags)
|
|||
case AccessMethodRelationId:
|
||||
case AccessMethodOperatorRelationId:
|
||||
case AccessMethodProcedureRelationId:
|
||||
case PropgraphElementRelationId:
|
||||
case PropgraphElementLabelRelationId:
|
||||
case PropgraphLabelRelationId:
|
||||
case PropgraphLabelPropertyRelationId:
|
||||
case PropgraphPropertyRelationId:
|
||||
case NamespaceRelationId:
|
||||
case TSParserRelationId:
|
||||
case TSDictionaryRelationId:
|
||||
|
|
@ -2267,6 +2277,7 @@ find_expr_references_walker(Node *node,
|
|||
switch (rte->rtekind)
|
||||
{
|
||||
case RTE_RELATION:
|
||||
case RTE_GRAPH_TABLE:
|
||||
add_object_address(RelationRelationId, rte->relid, 0,
|
||||
context->addrs);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -3009,3 +3009,369 @@ CREATE VIEW user_mappings AS
|
|||
FROM _pg_user_mappings;
|
||||
|
||||
GRANT SELECT ON user_mappings TO PUBLIC;
|
||||
|
||||
|
||||
-- SQL/PGQ views; these use section numbers from part 16 of the standard.
|
||||
|
||||
/*
|
||||
* 15.2
|
||||
* PG_DEFINED_LABEL_SETS view
|
||||
*/
|
||||
|
||||
-- TODO
|
||||
|
||||
|
||||
/*
|
||||
* 15.3
|
||||
* PG_DEFINED_LABEL_SET_LABELS view
|
||||
*/
|
||||
|
||||
-- TODO
|
||||
|
||||
|
||||
/*
|
||||
* 15.4
|
||||
* PG_EDGE_DEFINED_LABEL_SETS view
|
||||
*/
|
||||
|
||||
-- TODO
|
||||
|
||||
|
||||
/*
|
||||
* 15.5
|
||||
* PG_EDGE_TABLE_COMPONENTS view
|
||||
*/
|
||||
|
||||
CREATE VIEW pg_edge_table_components AS
|
||||
SELECT CAST(current_database() AS sql_identifier) AS property_graph_catalog,
|
||||
CAST(npg.nspname AS sql_identifier) AS property_graph_schema,
|
||||
CAST(pg.relname AS sql_identifier) AS property_graph_name,
|
||||
CAST(eg.pgealias AS sql_identifier) AS edge_table_alias,
|
||||
CAST(v.pgealias AS sql_identifier) AS vertex_table_alias,
|
||||
CAST(CASE eg.end WHEN 'src' THEN 'SOURCE' WHEN 'dest' THEN 'DESTINATION' END AS character_data) AS edge_end,
|
||||
CAST(ae.attname AS sql_identifier) AS edge_table_column_name,
|
||||
CAST(av.attname AS sql_identifier) AS vertex_table_column_name,
|
||||
CAST((eg.egkey).n AS cardinal_number) AS ordinal_position
|
||||
FROM pg_namespace npg
|
||||
JOIN
|
||||
(SELECT * FROM pg_class WHERE relkind = 'g') AS pg
|
||||
ON npg.oid = pg.relnamespace
|
||||
JOIN
|
||||
(SELECT pgepgid, pgealias, pgerelid, 'src' AS end, pgesrcvertexid AS vertexid, _pg_expandarray(pgesrckey) AS egkey, _pg_expandarray(pgesrcref) AS egref FROM pg_propgraph_element WHERE pgekind = 'e'
|
||||
UNION ALL
|
||||
SELECT pgepgid, pgealias, pgerelid, 'dest' AS end, pgedestvertexid AS vertexid, _pg_expandarray(pgedestkey) AS egkey, _pg_expandarray(pgedestref) AS egref FROM pg_propgraph_element WHERE pgekind = 'e'
|
||||
) AS eg
|
||||
ON pg.oid = eg.pgepgid
|
||||
JOIN
|
||||
(SELECT * FROM pg_propgraph_element WHERE pgekind = 'v') AS v
|
||||
ON eg.vertexid = v.oid
|
||||
JOIN
|
||||
(SELECT * FROM pg_attribute WHERE NOT attisdropped) AS ae
|
||||
ON eg.pgerelid = ae.attrelid AND (eg.egkey).x = ae.attnum
|
||||
JOIN
|
||||
(SELECT * FROM pg_attribute WHERE NOT attisdropped) AS av
|
||||
ON v.pgerelid = av.attrelid AND (eg.egref).x = av.attnum
|
||||
WHERE NOT pg_is_other_temp_schema(npg.oid)
|
||||
AND (pg_has_role(pg.relowner, 'USAGE')
|
||||
OR has_table_privilege(pg.oid, 'SELECT'));
|
||||
|
||||
GRANT SELECT ON pg_edge_table_components TO PUBLIC;
|
||||
|
||||
|
||||
/*
|
||||
* 15.6
|
||||
* PG_EDGE_TRIPLETS view
|
||||
*/
|
||||
|
||||
-- TODO
|
||||
|
||||
|
||||
/*
|
||||
* 15.7
|
||||
* PG_ELEMENT_TABLE_KEY_COLUMNS view
|
||||
*/
|
||||
|
||||
CREATE VIEW pg_element_table_key_columns AS
|
||||
SELECT CAST(current_database() AS sql_identifier) AS property_graph_catalog,
|
||||
CAST(npg.nspname AS sql_identifier) AS property_graph_schema,
|
||||
CAST(pg.relname AS sql_identifier) AS property_graph_name,
|
||||
CAST(pgealias AS sql_identifier) AS element_table_alias,
|
||||
CAST(a.attname AS sql_identifier) AS column_name,
|
||||
CAST((el.ekey).n AS cardinal_number) AS ordinal_position
|
||||
FROM pg_namespace npg
|
||||
JOIN
|
||||
(SELECT * FROM pg_class WHERE relkind = 'g') AS pg
|
||||
ON npg.oid = pg.relnamespace
|
||||
JOIN
|
||||
(SELECT pgepgid, pgealias, pgerelid, _pg_expandarray(pgekey) AS ekey FROM pg_propgraph_element) AS el
|
||||
ON pg.oid = el.pgepgid
|
||||
JOIN
|
||||
(SELECT * FROM pg_attribute WHERE NOT attisdropped) AS a
|
||||
ON el.pgerelid = a.attrelid AND (el.ekey).x = a.attnum
|
||||
WHERE NOT pg_is_other_temp_schema(npg.oid)
|
||||
AND (pg_has_role(pg.relowner, 'USAGE')
|
||||
OR has_table_privilege(pg.oid, 'SELECT'));
|
||||
|
||||
GRANT SELECT ON pg_element_table_key_columns TO PUBLIC;
|
||||
|
||||
|
||||
/*
|
||||
* 15.8
|
||||
* PG_ELEMENT_TABLE_LABELS view
|
||||
*/
|
||||
|
||||
CREATE VIEW pg_element_table_labels AS
|
||||
SELECT CAST(current_database() AS sql_identifier) AS property_graph_catalog,
|
||||
CAST(npg.nspname AS sql_identifier) AS property_graph_schema,
|
||||
CAST(pg.relname AS sql_identifier) AS property_graph_name,
|
||||
CAST(e.pgealias AS sql_identifier) AS element_table_alias,
|
||||
CAST(l.pgllabel AS sql_identifier) AS label_name
|
||||
FROM pg_namespace npg, pg_class pg, pg_propgraph_element e, pg_propgraph_element_label el, pg_propgraph_label l
|
||||
WHERE pg.relnamespace = npg.oid
|
||||
AND e.pgepgid = pg.oid
|
||||
AND el.pgelelid = e.oid
|
||||
AND el.pgellabelid = l.oid
|
||||
AND pg.relkind = 'g'
|
||||
AND (NOT pg_is_other_temp_schema(npg.oid))
|
||||
AND (pg_has_role(pg.relowner, 'USAGE')
|
||||
OR has_table_privilege(pg.oid, 'SELECT'));
|
||||
|
||||
GRANT SELECT ON pg_element_table_labels TO PUBLIC;
|
||||
|
||||
|
||||
/*
|
||||
* 15.9
|
||||
* PG_ELEMENT_TABLE_PROPERTIES view
|
||||
*/
|
||||
|
||||
CREATE VIEW pg_element_table_properties AS
|
||||
SELECT DISTINCT
|
||||
CAST(current_database() AS sql_identifier) AS property_graph_catalog,
|
||||
CAST(npg.nspname AS sql_identifier) AS property_graph_schema,
|
||||
CAST(pg.relname AS sql_identifier) AS property_graph_name,
|
||||
CAST(e.pgealias AS sql_identifier) AS element_table_alias,
|
||||
CAST(pr.pgpname AS sql_identifier) AS property_name,
|
||||
CAST(pg_get_expr(plp.plpexpr, e.pgerelid) AS character_data) AS property_expression
|
||||
FROM pg_namespace npg, pg_class pg, pg_propgraph_element e, pg_propgraph_element_label el, pg_propgraph_label_property plp, pg_propgraph_property pr
|
||||
WHERE pg.relnamespace = npg.oid
|
||||
AND e.pgepgid = pg.oid
|
||||
AND el.pgelelid = e.oid
|
||||
AND plp.plpellabelid = el.oid
|
||||
AND pr.oid = plp.plppropid
|
||||
AND pg.relkind = 'g'
|
||||
AND (NOT pg_is_other_temp_schema(npg.oid))
|
||||
AND (pg_has_role(pg.relowner, 'USAGE')
|
||||
OR has_table_privilege(pg.oid, 'SELECT'));
|
||||
|
||||
GRANT SELECT ON pg_element_table_properties TO PUBLIC;
|
||||
|
||||
|
||||
/*
|
||||
* 15.10
|
||||
* PG_ELEMENT_TABLES view
|
||||
*/
|
||||
|
||||
CREATE VIEW pg_element_tables AS
|
||||
SELECT CAST(current_database() AS sql_identifier) AS property_graph_catalog,
|
||||
CAST(npg.nspname AS sql_identifier) AS property_graph_schema,
|
||||
CAST(pg.relname AS sql_identifier) AS property_graph_name,
|
||||
CAST(e.pgealias AS sql_identifier) AS element_table_alias,
|
||||
CAST(CASE e.pgekind WHEN 'e' THEN 'EDGE' WHEN 'v' THEN 'VERTEX' END AS character_data) AS element_table_kind,
|
||||
CAST(current_database() AS sql_identifier) AS table_catalog,
|
||||
CAST(nt.nspname AS sql_identifier) AS table_schema,
|
||||
CAST(t.relname AS sql_identifier) AS table_name,
|
||||
CAST(NULL AS character_data) AS element_table_definition
|
||||
FROM pg_namespace npg, pg_class pg, pg_propgraph_element e, pg_class t, pg_namespace nt
|
||||
WHERE pg.relnamespace = npg.oid
|
||||
AND e.pgepgid = pg.oid
|
||||
AND e.pgerelid = t.oid
|
||||
AND t.relnamespace = nt.oid
|
||||
AND pg.relkind = 'g'
|
||||
AND (NOT pg_is_other_temp_schema(npg.oid))
|
||||
AND (pg_has_role(pg.relowner, 'USAGE')
|
||||
OR has_table_privilege(pg.oid, 'SELECT'));
|
||||
|
||||
GRANT SELECT ON pg_element_tables TO PUBLIC;
|
||||
|
||||
|
||||
/*
|
||||
* 15.11
|
||||
* PG_LABEL_PROPERTIES view
|
||||
*/
|
||||
|
||||
CREATE VIEW pg_label_properties AS
|
||||
SELECT DISTINCT
|
||||
CAST(current_database() AS sql_identifier) AS property_graph_catalog,
|
||||
CAST(npg.nspname AS sql_identifier) AS property_graph_schema,
|
||||
CAST(pg.relname AS sql_identifier) AS property_graph_name,
|
||||
CAST(l.pgllabel AS sql_identifier) AS label_name,
|
||||
CAST(pr.pgpname AS sql_identifier) AS property_name
|
||||
FROM pg_namespace npg, pg_class pg, pg_propgraph_element e, pg_propgraph_label l, pg_propgraph_element_label el, pg_propgraph_label_property plp, pg_propgraph_property pr
|
||||
WHERE pg.relnamespace = npg.oid
|
||||
AND e.pgepgid = pg.oid
|
||||
AND el.pgelelid = e.oid
|
||||
AND plp.plpellabelid = el.oid
|
||||
AND pr.oid = plp.plppropid
|
||||
AND el.pgellabelid = l.oid
|
||||
AND pg.relkind = 'g'
|
||||
AND (NOT pg_is_other_temp_schema(npg.oid))
|
||||
AND (pg_has_role(pg.relowner, 'USAGE')
|
||||
OR has_table_privilege(pg.oid, 'SELECT'));
|
||||
|
||||
GRANT SELECT ON pg_label_properties TO PUBLIC;
|
||||
|
||||
|
||||
/*
|
||||
* 15.12
|
||||
* PG_LABELS view
|
||||
*/
|
||||
|
||||
CREATE VIEW pg_labels AS
|
||||
SELECT CAST(current_database() AS sql_identifier) AS property_graph_catalog,
|
||||
CAST(npg.nspname AS sql_identifier) AS property_graph_schema,
|
||||
CAST(pg.relname AS sql_identifier) AS property_graph_name,
|
||||
CAST(l.pgllabel AS sql_identifier) AS label_name
|
||||
FROM pg_namespace npg, pg_class pg, pg_propgraph_label l
|
||||
WHERE pg.relnamespace = npg.oid
|
||||
AND l.pglpgid = pg.oid
|
||||
AND pg.relkind = 'g'
|
||||
AND (NOT pg_is_other_temp_schema(npg.oid))
|
||||
AND (pg_has_role(pg.relowner, 'USAGE')
|
||||
OR has_table_privilege(pg.oid, 'SELECT'));
|
||||
|
||||
GRANT SELECT ON pg_labels TO PUBLIC;
|
||||
|
||||
|
||||
/*
|
||||
* 15.13
|
||||
* PG_PROPERTY_DATA_TYPES view
|
||||
*/
|
||||
|
||||
CREATE VIEW pg_property_data_types AS
|
||||
SELECT CAST(current_database() AS sql_identifier) AS property_graph_catalog,
|
||||
CAST(npg.nspname AS sql_identifier) AS property_graph_schema,
|
||||
CAST(pg.relname AS sql_identifier) AS property_graph_name,
|
||||
CAST(pgp.pgpname AS sql_identifier) AS property_name,
|
||||
|
||||
CAST(
|
||||
CASE WHEN t.typtype = 'd' THEN
|
||||
CASE WHEN bt.typelem <> 0 AND bt.typlen = -1 THEN 'ARRAY'
|
||||
WHEN nbt.nspname = 'pg_catalog' THEN format_type(t.typbasetype, null)
|
||||
ELSE 'USER-DEFINED' END
|
||||
ELSE
|
||||
CASE WHEN t.typelem <> 0 AND t.typlen = -1 THEN 'ARRAY'
|
||||
WHEN nt.nspname = 'pg_catalog' THEN format_type(pgp.pgptypid, null)
|
||||
ELSE 'USER-DEFINED' END
|
||||
END
|
||||
AS character_data)
|
||||
AS data_type,
|
||||
|
||||
CAST(null AS cardinal_number) AS character_maximum_length,
|
||||
CAST(null AS cardinal_number) AS character_octet_length,
|
||||
CAST(null AS sql_identifier) AS character_set_catalog,
|
||||
CAST(null AS sql_identifier) AS character_set_schema,
|
||||
CAST(null AS sql_identifier) AS character_set_name,
|
||||
CAST(current_database() AS sql_identifier) AS collation_catalog,
|
||||
CAST(nc.nspname AS sql_identifier) AS collation_schema,
|
||||
CAST(c.collname AS sql_identifier) AS collation_name,
|
||||
CAST(null AS cardinal_number) AS numeric_precision,
|
||||
CAST(null AS cardinal_number) AS numeric_precision_radix,
|
||||
CAST(null AS cardinal_number) AS numeric_scale,
|
||||
CAST(null AS cardinal_number) AS datetime_precision,
|
||||
CAST(null AS character_data) AS interval_type,
|
||||
CAST(null AS cardinal_number) AS interval_precision,
|
||||
|
||||
CAST(current_database() AS sql_identifier) AS user_defined_type_catalog,
|
||||
CAST(coalesce(nbt.nspname, nt.nspname) AS sql_identifier) AS user_defined_type_schema,
|
||||
CAST(coalesce(bt.typname, t.typname) AS sql_identifier) AS user_defined_type_name,
|
||||
|
||||
CAST(null AS sql_identifier) AS scope_catalog,
|
||||
CAST(null AS sql_identifier) AS scope_schema,
|
||||
CAST(null AS sql_identifier) AS scope_name,
|
||||
|
||||
CAST(null AS cardinal_number) AS maximum_cardinality,
|
||||
CAST(pgp.pgpname AS sql_identifier) AS dtd_identifier
|
||||
|
||||
FROM pg_propgraph_property pgp
|
||||
JOIN (pg_class pg JOIN pg_namespace npg ON (pg.relnamespace = npg.oid)) ON pgp.pgppgid = pg.oid
|
||||
JOIN (pg_type t JOIN pg_namespace nt ON (t.typnamespace = nt.oid)) ON pgp.pgptypid = t.oid
|
||||
LEFT JOIN (pg_type bt JOIN pg_namespace nbt ON (bt.typnamespace = nbt.oid))
|
||||
ON (t.typtype = 'd' AND t.typbasetype = bt.oid)
|
||||
LEFT JOIN (pg_collation c JOIN pg_namespace nc ON (c.collnamespace = nc.oid))
|
||||
ON pgp.pgpcollation = c.oid AND (nc.nspname, c.collname) <> ('pg_catalog', 'default')
|
||||
|
||||
WHERE pg.relkind = 'g'
|
||||
AND (NOT pg_is_other_temp_schema(npg.oid))
|
||||
AND (pg_has_role(pg.relowner, 'USAGE')
|
||||
OR has_table_privilege(pg.oid, 'SELECT'));
|
||||
|
||||
GRANT SELECT ON pg_property_data_types TO PUBLIC;
|
||||
|
||||
|
||||
/*
|
||||
* 15.14
|
||||
* PG_PROPERTY_GRAPH_PRIVILEGES view
|
||||
*/
|
||||
|
||||
CREATE VIEW pg_property_graph_privileges AS
|
||||
SELECT CAST(u_grantor.rolname AS sql_identifier) AS grantor,
|
||||
CAST(grantee.rolname AS sql_identifier) AS grantee,
|
||||
CAST(current_database() AS sql_identifier) AS property_graph_catalog,
|
||||
CAST(nc.nspname AS sql_identifier) AS property_graph_schema,
|
||||
CAST(c.relname AS sql_identifier) AS property_graph_name,
|
||||
CAST(c.prtype AS character_data) AS privilege_type,
|
||||
CAST(
|
||||
CASE WHEN
|
||||
-- object owner always has grant options
|
||||
pg_has_role(grantee.oid, c.relowner, 'USAGE')
|
||||
OR c.grantable
|
||||
THEN 'YES' ELSE 'NO' END AS yes_or_no) AS is_grantable
|
||||
|
||||
FROM (
|
||||
SELECT oid, relname, relnamespace, relkind, relowner, (aclexplode(coalesce(relacl, acldefault('r', relowner)))).* FROM pg_class
|
||||
) AS c (oid, relname, relnamespace, relkind, relowner, grantor, grantee, prtype, grantable),
|
||||
pg_namespace nc,
|
||||
pg_authid u_grantor,
|
||||
(
|
||||
SELECT oid, rolname FROM pg_authid
|
||||
UNION ALL
|
||||
SELECT 0::oid, 'PUBLIC'
|
||||
) AS grantee (oid, rolname)
|
||||
|
||||
WHERE c.relnamespace = nc.oid
|
||||
AND c.relkind IN ('g')
|
||||
AND c.grantee = grantee.oid
|
||||
AND c.grantor = u_grantor.oid
|
||||
AND c.prtype IN ('SELECT')
|
||||
AND (pg_has_role(u_grantor.oid, 'USAGE')
|
||||
OR pg_has_role(grantee.oid, 'USAGE')
|
||||
OR grantee.rolname = 'PUBLIC');
|
||||
|
||||
GRANT SELECT ON pg_property_graph_privileges TO PUBLIC;
|
||||
|
||||
|
||||
/*
|
||||
* 15.15
|
||||
* PG_VERTEX_DEFINED_LABEL_SETS view
|
||||
*/
|
||||
|
||||
-- TODO
|
||||
|
||||
|
||||
/*
|
||||
* 15.16
|
||||
* PROPERTY_GRAPHS view
|
||||
*/
|
||||
|
||||
CREATE VIEW property_graphs AS
|
||||
SELECT CAST(current_database() AS sql_identifier) AS property_graph_catalog,
|
||||
CAST(nc.nspname AS sql_identifier) AS property_graph_schema,
|
||||
CAST(c.relname AS sql_identifier) AS property_graph_name
|
||||
FROM pg_namespace nc, pg_class c
|
||||
WHERE c.relnamespace = nc.oid
|
||||
AND c.relkind = 'g'
|
||||
AND (NOT pg_is_other_temp_schema(nc.oid))
|
||||
AND (pg_has_role(c.relowner, 'USAGE')
|
||||
OR has_table_privilege(c.oid, 'SELECT'));
|
||||
|
||||
GRANT SELECT ON property_graphs TO PUBLIC;
|
||||
|
|
|
|||
|
|
@ -47,6 +47,11 @@
|
|||
#include "catalog/pg_parameter_acl.h"
|
||||
#include "catalog/pg_policy.h"
|
||||
#include "catalog/pg_proc.h"
|
||||
#include "catalog/pg_propgraph_element.h"
|
||||
#include "catalog/pg_propgraph_element_label.h"
|
||||
#include "catalog/pg_propgraph_label.h"
|
||||
#include "catalog/pg_propgraph_label_property.h"
|
||||
#include "catalog/pg_propgraph_property.h"
|
||||
#include "catalog/pg_publication.h"
|
||||
#include "catalog/pg_publication_namespace.h"
|
||||
#include "catalog/pg_publication_rel.h"
|
||||
|
|
@ -370,6 +375,76 @@ static const ObjectPropertyType ObjectProperty[] =
|
|||
OBJECT_OPFAMILY,
|
||||
true
|
||||
},
|
||||
{
|
||||
"property graph element",
|
||||
PropgraphElementRelationId,
|
||||
PropgraphElementObjectIndexId,
|
||||
PROPGRAPHELOID,
|
||||
PROPGRAPHELALIAS,
|
||||
Anum_pg_propgraph_element_oid,
|
||||
Anum_pg_propgraph_element_pgealias,
|
||||
InvalidAttrNumber,
|
||||
InvalidAttrNumber,
|
||||
InvalidAttrNumber,
|
||||
-1,
|
||||
false
|
||||
},
|
||||
{
|
||||
"property graph element label",
|
||||
PropgraphElementLabelRelationId,
|
||||
PropgraphElementLabelObjectIndexId,
|
||||
-1,
|
||||
-1,
|
||||
Anum_pg_propgraph_element_label_oid,
|
||||
InvalidAttrNumber,
|
||||
InvalidAttrNumber,
|
||||
InvalidAttrNumber,
|
||||
InvalidAttrNumber,
|
||||
-1,
|
||||
false
|
||||
},
|
||||
{
|
||||
"property graph label",
|
||||
PropgraphLabelRelationId,
|
||||
PropgraphLabelObjectIndexId,
|
||||
PROPGRAPHLABELOID,
|
||||
PROPGRAPHLABELNAME,
|
||||
Anum_pg_propgraph_label_oid,
|
||||
Anum_pg_propgraph_label_pgllabel,
|
||||
InvalidAttrNumber,
|
||||
InvalidAttrNumber,
|
||||
InvalidAttrNumber,
|
||||
-1,
|
||||
false
|
||||
},
|
||||
{
|
||||
"property graph label property",
|
||||
PropgraphLabelPropertyRelationId,
|
||||
PropgraphLabelPropertyObjectIndexId,
|
||||
-1,
|
||||
-1,
|
||||
Anum_pg_propgraph_label_property_oid,
|
||||
InvalidAttrNumber,
|
||||
InvalidAttrNumber,
|
||||
InvalidAttrNumber,
|
||||
InvalidAttrNumber,
|
||||
-1,
|
||||
false
|
||||
},
|
||||
{
|
||||
"property graph property",
|
||||
PropgraphPropertyRelationId,
|
||||
PropgraphPropertyObjectIndexId,
|
||||
-1,
|
||||
PROPGRAPHPROPNAME,
|
||||
Anum_pg_propgraph_property_oid,
|
||||
Anum_pg_propgraph_property_pgpname,
|
||||
InvalidAttrNumber,
|
||||
InvalidAttrNumber,
|
||||
InvalidAttrNumber,
|
||||
-1,
|
||||
false
|
||||
},
|
||||
{
|
||||
"role",
|
||||
AuthIdRelationId,
|
||||
|
|
@ -679,6 +754,9 @@ static const struct object_type_map
|
|||
{
|
||||
"foreign table", OBJECT_FOREIGN_TABLE
|
||||
},
|
||||
{
|
||||
"property graph", OBJECT_PROPGRAPH
|
||||
},
|
||||
{
|
||||
"table column", OBJECT_COLUMN
|
||||
},
|
||||
|
|
@ -814,6 +892,15 @@ static const struct object_type_map
|
|||
{
|
||||
"policy", OBJECT_POLICY
|
||||
},
|
||||
{
|
||||
"property graph element", -1
|
||||
},
|
||||
{
|
||||
"property graph label", -1
|
||||
},
|
||||
{
|
||||
"property graph property", -1
|
||||
},
|
||||
{
|
||||
"publication", OBJECT_PUBLICATION
|
||||
},
|
||||
|
|
@ -949,6 +1036,7 @@ get_object_address(ObjectType objtype, Node *object,
|
|||
case OBJECT_VIEW:
|
||||
case OBJECT_MATVIEW:
|
||||
case OBJECT_FOREIGN_TABLE:
|
||||
case OBJECT_PROPGRAPH:
|
||||
address =
|
||||
get_relation_by_qualified_name(objtype, castNode(List, object),
|
||||
&relation, lockmode,
|
||||
|
|
@ -1361,6 +1449,13 @@ get_relation_by_qualified_name(ObjectType objtype, List *object,
|
|||
errmsg("\"%s\" is not an index",
|
||||
RelationGetRelationName(relation))));
|
||||
break;
|
||||
case OBJECT_PROPGRAPH:
|
||||
if (relation->rd_rel->relkind != RELKIND_PROPGRAPH)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
||||
errmsg("\"%s\" is not a property graph",
|
||||
RelationGetRelationName(relation))));
|
||||
break;
|
||||
case OBJECT_SEQUENCE:
|
||||
if (relation->rd_rel->relkind != RELKIND_SEQUENCE)
|
||||
ereport(ERROR,
|
||||
|
|
@ -2280,6 +2375,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
|
|||
case OBJECT_MATVIEW:
|
||||
case OBJECT_INDEX:
|
||||
case OBJECT_FOREIGN_TABLE:
|
||||
case OBJECT_PROPGRAPH:
|
||||
case OBJECT_COLUMN:
|
||||
case OBJECT_ATTRIBUTE:
|
||||
case OBJECT_COLLATION:
|
||||
|
|
@ -2399,6 +2495,7 @@ check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address,
|
|||
case OBJECT_VIEW:
|
||||
case OBJECT_MATVIEW:
|
||||
case OBJECT_FOREIGN_TABLE:
|
||||
case OBJECT_PROPGRAPH:
|
||||
case OBJECT_COLUMN:
|
||||
case OBJECT_RULE:
|
||||
case OBJECT_TRIGGER:
|
||||
|
|
@ -3976,6 +4073,156 @@ getObjectDescription(const ObjectAddress *object, bool missing_ok)
|
|||
break;
|
||||
}
|
||||
|
||||
case PropgraphElementRelationId:
|
||||
{
|
||||
HeapTuple tup;
|
||||
Form_pg_propgraph_element pgeform;
|
||||
|
||||
tup = SearchSysCache1(PROPGRAPHELOID, ObjectIdGetDatum(object->objectId));
|
||||
if (!HeapTupleIsValid(tup))
|
||||
{
|
||||
if (!missing_ok)
|
||||
elog(ERROR, "cache lookup failed for property graph element %u",
|
||||
object->objectId);
|
||||
break;
|
||||
}
|
||||
|
||||
pgeform = (Form_pg_propgraph_element) GETSTRUCT(tup);
|
||||
|
||||
if (pgeform->pgekind == PGEKIND_VERTEX)
|
||||
/* translator: followed by, e.g., "property graph %s" */
|
||||
appendStringInfo(&buffer, _("vertex %s of "), NameStr(pgeform->pgealias));
|
||||
else if (pgeform->pgekind == PGEKIND_EDGE)
|
||||
/* translator: followed by, e.g., "property graph %s" */
|
||||
appendStringInfo(&buffer, _("edge %s of "), NameStr(pgeform->pgealias));
|
||||
else
|
||||
appendStringInfo(&buffer, "??? element %s of ", NameStr(pgeform->pgealias));
|
||||
getRelationDescription(&buffer, pgeform->pgepgid, false);
|
||||
|
||||
ReleaseSysCache(tup);
|
||||
break;
|
||||
}
|
||||
|
||||
case PropgraphElementLabelRelationId:
|
||||
{
|
||||
Relation rel;
|
||||
SysScanDesc scan;
|
||||
ScanKeyData key[1];
|
||||
HeapTuple tuple;
|
||||
Form_pg_propgraph_element_label pgelform;
|
||||
ObjectAddress oa;
|
||||
|
||||
rel = table_open(PropgraphElementLabelRelationId, AccessShareLock);
|
||||
ScanKeyInit(&key[0],
|
||||
Anum_pg_propgraph_element_label_oid,
|
||||
BTEqualStrategyNumber, F_OIDEQ,
|
||||
ObjectIdGetDatum(object->objectId));
|
||||
|
||||
scan = systable_beginscan(rel, PropgraphElementLabelObjectIndexId, true, NULL, 1, key);
|
||||
tuple = systable_getnext(scan);
|
||||
if (!HeapTupleIsValid(tuple))
|
||||
{
|
||||
if (!missing_ok)
|
||||
elog(ERROR, "could not find tuple for element label %u", object->objectId);
|
||||
|
||||
systable_endscan(scan);
|
||||
table_close(rel, AccessShareLock);
|
||||
break;
|
||||
}
|
||||
|
||||
pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tuple);
|
||||
|
||||
appendStringInfo(&buffer, _("label %s of "), get_propgraph_label_name(pgelform->pgellabelid));
|
||||
ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
|
||||
appendStringInfoString(&buffer, getObjectDescription(&oa, false));
|
||||
|
||||
systable_endscan(scan);
|
||||
table_close(rel, AccessShareLock);
|
||||
break;
|
||||
}
|
||||
|
||||
case PropgraphLabelRelationId:
|
||||
{
|
||||
HeapTuple tuple;
|
||||
Form_pg_propgraph_label pglform;
|
||||
|
||||
tuple = SearchSysCache1(PROPGRAPHLABELOID, object->objectId);
|
||||
if (!HeapTupleIsValid(tuple))
|
||||
{
|
||||
if (!missing_ok)
|
||||
elog(ERROR, "could not find tuple for label %u", object->objectId);
|
||||
break;
|
||||
}
|
||||
|
||||
pglform = (Form_pg_propgraph_label) GETSTRUCT(tuple);
|
||||
|
||||
/* translator: followed by, e.g., "property graph %s" */
|
||||
appendStringInfo(&buffer, _("label %s of "), NameStr(pglform->pgllabel));
|
||||
getRelationDescription(&buffer, pglform->pglpgid, false);
|
||||
ReleaseSysCache(tuple);
|
||||
break;
|
||||
}
|
||||
|
||||
case PropgraphLabelPropertyRelationId:
|
||||
{
|
||||
Relation rel;
|
||||
SysScanDesc scan;
|
||||
ScanKeyData key[1];
|
||||
HeapTuple tuple;
|
||||
Form_pg_propgraph_label_property plpform;
|
||||
ObjectAddress oa;
|
||||
|
||||
rel = table_open(PropgraphLabelPropertyRelationId, AccessShareLock);
|
||||
ScanKeyInit(&key[0],
|
||||
Anum_pg_propgraph_label_property_oid,
|
||||
BTEqualStrategyNumber, F_OIDEQ,
|
||||
ObjectIdGetDatum(object->objectId));
|
||||
|
||||
scan = systable_beginscan(rel, PropgraphLabelPropertyObjectIndexId, true, NULL, 1, key);
|
||||
tuple = systable_getnext(scan);
|
||||
if (!HeapTupleIsValid(tuple))
|
||||
{
|
||||
if (!missing_ok)
|
||||
elog(ERROR, "could not find tuple for label property %u", object->objectId);
|
||||
|
||||
systable_endscan(scan);
|
||||
table_close(rel, AccessShareLock);
|
||||
break;
|
||||
}
|
||||
|
||||
plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tuple);
|
||||
|
||||
appendStringInfo(&buffer, _("property %s of "), get_propgraph_property_name(plpform->plppropid));
|
||||
ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
|
||||
appendStringInfoString(&buffer, getObjectDescription(&oa, false));
|
||||
|
||||
systable_endscan(scan);
|
||||
table_close(rel, AccessShareLock);
|
||||
break;
|
||||
}
|
||||
|
||||
case PropgraphPropertyRelationId:
|
||||
{
|
||||
HeapTuple tuple;
|
||||
Form_pg_propgraph_property pgpform;
|
||||
|
||||
tuple = SearchSysCache1(PROPGRAPHPROPOID, object->objectId);
|
||||
if (!HeapTupleIsValid(tuple))
|
||||
{
|
||||
if (!missing_ok)
|
||||
elog(ERROR, "could not find tuple for property %u", object->objectId);
|
||||
break;
|
||||
}
|
||||
|
||||
pgpform = (Form_pg_propgraph_property) GETSTRUCT(tuple);
|
||||
|
||||
/* translator: followed by, e.g., "property graph %s" */
|
||||
appendStringInfo(&buffer, _("property %s of "), NameStr(pgpform->pgpname));
|
||||
getRelationDescription(&buffer, pgpform->pgppgid, false);
|
||||
ReleaseSysCache(tuple);
|
||||
break;
|
||||
}
|
||||
|
||||
case PublicationRelationId:
|
||||
{
|
||||
char *pubname = get_publication_name(object->objectId,
|
||||
|
|
@ -4161,6 +4408,10 @@ getRelationDescription(StringInfo buffer, Oid relid, bool missing_ok)
|
|||
appendStringInfo(buffer, _("foreign table %s"),
|
||||
relname);
|
||||
break;
|
||||
case RELKIND_PROPGRAPH:
|
||||
appendStringInfo(buffer, _("property graph %s"),
|
||||
relname);
|
||||
break;
|
||||
default:
|
||||
/* shouldn't get here */
|
||||
appendStringInfo(buffer, _("relation %s"),
|
||||
|
|
@ -4650,6 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
|
|||
appendStringInfoString(&buffer, "policy");
|
||||
break;
|
||||
|
||||
case PropgraphElementRelationId:
|
||||
appendStringInfoString(&buffer, "property graph element");
|
||||
break;
|
||||
|
||||
case PropgraphLabelRelationId:
|
||||
appendStringInfoString(&buffer, "property graph label");
|
||||
break;
|
||||
|
||||
case PropgraphPropertyRelationId:
|
||||
appendStringInfoString(&buffer, "property graph property");
|
||||
break;
|
||||
|
||||
case PublicationRelationId:
|
||||
appendStringInfoString(&buffer, "publication");
|
||||
break;
|
||||
|
|
@ -4731,6 +4994,9 @@ getRelationTypeDescription(StringInfo buffer, Oid relid, int32 objectSubId,
|
|||
case RELKIND_FOREIGN_TABLE:
|
||||
appendStringInfoString(buffer, "foreign table");
|
||||
break;
|
||||
case RELKIND_PROPGRAPH:
|
||||
appendStringInfoString(buffer, "property graph");
|
||||
break;
|
||||
default:
|
||||
/* shouldn't get here */
|
||||
appendStringInfoString(buffer, "relation");
|
||||
|
|
@ -5895,6 +6161,73 @@ getObjectIdentityParts(const ObjectAddress *object,
|
|||
break;
|
||||
}
|
||||
|
||||
case PropgraphElementRelationId:
|
||||
{
|
||||
HeapTuple tup;
|
||||
Form_pg_propgraph_element pge;
|
||||
|
||||
tup = SearchSysCache1(PROPGRAPHELOID, object->objectId);
|
||||
if (!HeapTupleIsValid(tup))
|
||||
{
|
||||
if (!missing_ok)
|
||||
elog(ERROR, "cache lookup failed for property graph element %u", object->objectId);
|
||||
break;
|
||||
}
|
||||
pge = (Form_pg_propgraph_element) GETSTRUCT(tup);
|
||||
appendStringInfo(&buffer, "%s of ", quote_identifier(NameStr(pge->pgealias)));
|
||||
|
||||
getRelationIdentity(&buffer, pge->pgepgid, objname, false);
|
||||
if (objname)
|
||||
*objname = lappend(*objname, pstrdup(NameStr(pge->pgealias)));
|
||||
|
||||
ReleaseSysCache(tup);
|
||||
break;
|
||||
}
|
||||
|
||||
case PropgraphLabelRelationId:
|
||||
{
|
||||
HeapTuple tup;
|
||||
Form_pg_propgraph_label pgl;
|
||||
|
||||
tup = SearchSysCache1(PROPGRAPHLABELOID, object->objectId);
|
||||
if (!HeapTupleIsValid(tup))
|
||||
{
|
||||
if (!missing_ok)
|
||||
elog(ERROR, "cache lookup failed for property graph label %u", object->objectId);
|
||||
break;
|
||||
}
|
||||
|
||||
pgl = (Form_pg_propgraph_label) GETSTRUCT(tup);
|
||||
appendStringInfo(&buffer, "%s of ", quote_identifier(NameStr(pgl->pgllabel)));
|
||||
getRelationIdentity(&buffer, pgl->pglpgid, objname, false);
|
||||
if (objname)
|
||||
*objname = lappend(*objname, pstrdup(NameStr(pgl->pgllabel)));
|
||||
ReleaseSysCache(tup);
|
||||
break;
|
||||
}
|
||||
|
||||
case PropgraphPropertyRelationId:
|
||||
{
|
||||
HeapTuple tup;
|
||||
Form_pg_propgraph_property pgp;
|
||||
|
||||
tup = SearchSysCache1(PROPGRAPHPROPOID, object->objectId);
|
||||
if (!HeapTupleIsValid(tup))
|
||||
{
|
||||
if (!missing_ok)
|
||||
elog(ERROR, "cache lookup failed for property graph property %u", object->objectId);
|
||||
break;
|
||||
}
|
||||
|
||||
pgp = (Form_pg_propgraph_property) GETSTRUCT(tup);
|
||||
appendStringInfo(&buffer, "%s of ", quote_identifier(NameStr(pgp->pgpname)));
|
||||
getRelationIdentity(&buffer, pgp->pgppgid, objname, false);
|
||||
if (objname)
|
||||
*objname = lappend(*objname, pstrdup(NameStr(pgp->pgpname)));
|
||||
ReleaseSysCache(tup);
|
||||
break;
|
||||
}
|
||||
|
||||
case PublicationRelationId:
|
||||
{
|
||||
char *pubname;
|
||||
|
|
@ -6201,6 +6534,8 @@ get_relkind_objtype(char relkind)
|
|||
return OBJECT_MATVIEW;
|
||||
case RELKIND_FOREIGN_TABLE:
|
||||
return OBJECT_FOREIGN_TABLE;
|
||||
case RELKIND_PROPGRAPH:
|
||||
return OBJECT_PROPGRAPH;
|
||||
case RELKIND_TOASTVALUE:
|
||||
return OBJECT_TABLE;
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -45,6 +45,8 @@ errdetail_relkind_not_supported(char relkind)
|
|||
return errdetail("This operation is not supported for partitioned tables.");
|
||||
case RELKIND_PARTITIONED_INDEX:
|
||||
return errdetail("This operation is not supported for partitioned indexes.");
|
||||
case RELKIND_PROPGRAPH:
|
||||
return errdetail("This operation is not supported for property graphs.");
|
||||
default:
|
||||
elog(ERROR, "unrecognized relkind: '%c'", relkind);
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -348,6 +348,106 @@ F866 FETCH FIRST clause: PERCENT option NO
|
|||
F867 FETCH FIRST clause: WITH TIES option YES
|
||||
F868 ORDER BY in grouped table YES
|
||||
F869 SQL implementation info population YES
|
||||
G000 Graph pattern YES SQL/PGQ required
|
||||
G001 Repeatable-elements match mode YES SQL/PGQ required
|
||||
G002 Different-edges match mode NO
|
||||
G003 Explicit REPEATABLE ELEMENTS keyword NO
|
||||
G004 Path variables NO
|
||||
G005 Path search prefix in a path pattern NO
|
||||
G006 Graph pattern KEEP clause: path mode prefix NO
|
||||
G007 Graph pattern KEEP clause: path search prefix NO
|
||||
G008 Graph pattern WHERE clause YES SQL/PGQ required
|
||||
G010 Explicit WALK keyword NO
|
||||
G011 Advanced path modes: TRAIL NO
|
||||
G012 Advanced path modes: SIMPLE NO
|
||||
G013 Advanced path modes: ACYCLIC NO
|
||||
G014 Explicit PATH/PATHS keywords NO
|
||||
G015 All path search: explicit ALL keyword NO
|
||||
G016 Any path search NO
|
||||
G017 All shortest path search NO
|
||||
G018 Any shortest path search NO
|
||||
G019 Counted shortest path search NO
|
||||
G020 Counted shortest group search NO
|
||||
G030 Path multiset alternation NO
|
||||
G031 Path multiset alternation: variable length path operands NO
|
||||
G032 Path pattern union NO
|
||||
G033 Path pattern union: variable length path operands NO
|
||||
G034 Path concatenation YES SQL/PGQ required
|
||||
G035 Quantified paths NO
|
||||
G036 Quantified edges NO
|
||||
G037 Questioned paths NO
|
||||
G038 Parenthesized path pattern expression NO
|
||||
G039 Simplified path pattern expression: full defaulting NO
|
||||
G040 Vertex pattern YES SQL/PGQ required
|
||||
G041 Non-local element pattern predicates NO
|
||||
G042 Basic full edge patterns YES SQL/PGQ required
|
||||
G043 Complete full edge patterns NO
|
||||
G044 Basic abbreviated edge patterns YES
|
||||
G045 Complete abbreviated edge patterns NO
|
||||
G046 Relaxed topological consistency: adjacent vertex patterns NO
|
||||
G047 Relaxed topological consistency: concise edge patterns NO
|
||||
G048 Parenthesized path pattern: subpath variable declaration NO
|
||||
G049 Parenthesized path pattern: path mode prefix NO
|
||||
G050 Parenthesized path pattern: WHERE clause NO
|
||||
G051 Parenthesized path pattern: non-local predicates NO
|
||||
G060 Bounded graph pattern quantifiers NO
|
||||
G061 Unbounded graph pattern quantifiers NO
|
||||
G070 Label expression: label disjunction YES SQL/PGQ required
|
||||
G071 Label expression: label conjunction NO
|
||||
G072 Label expression: label negation NO
|
||||
G073 Label expression: individual label name YES SQL/PGQ required
|
||||
G074 Label expression: wildcard label NO
|
||||
G075 Parenthesized label expression NO
|
||||
G080 Simplified path pattern expression: basic defaulting NO
|
||||
G081 Simplified path pattern expression: full overrides NO
|
||||
G082 Simplified path pattern expression: basic overrides NO
|
||||
G090 Property reference YES SQL/PGQ required
|
||||
G100 ELEMENT_ID function NO
|
||||
G110 IS DIRECTED predicate NO
|
||||
G111 IS LABELED predicate NO
|
||||
G112 IS SOURCE and IS DESTINATION predicate NO
|
||||
G113 ALL_DIFFERENT predicate NO
|
||||
G114 SAME predicate NO
|
||||
G115 PROPERTY_EXISTS predicate NO
|
||||
G120 Within-match aggregates NO
|
||||
G800 PATH_NAME function NO
|
||||
G801 ELEMENT_NUMBER function NO
|
||||
G802 PATH_LENGTH function NO
|
||||
G803 MATCHNUM function NO
|
||||
G810 IS BOUND predicate NO
|
||||
G811 IS BOUND predicate: AS option NO
|
||||
G820 BINDING_COUNT NO
|
||||
G830 Colon in 'is label' expression NO
|
||||
G840 Path-ordered aggregates NO
|
||||
G850 SQL/PGQ Information Schema views YES
|
||||
G860 GET DIAGNOSTICS enhancements for SQL-property graphs NO
|
||||
G900 GRAPH_TABLE YES SQL/PGQ required
|
||||
G901 GRAPH_TABLE: ONE ROW PER VERTEX NO
|
||||
G902 GRAPH_TABLE: ONE ROW PER STEP NO
|
||||
G903 GRAPH_TABLE: explicit ONE ROW PER MATCH keywords NO
|
||||
G904 All properties reference NO
|
||||
G905 GRAPH_TABLE: optional COLUMNS clause NO
|
||||
G906 GRAPH_TABLE: explicit EXPORT ALL NO
|
||||
G907 GRAPH_TABLE: EXPORT ALL EXCEPT NO
|
||||
G908 GRAPH_TABLE: EXPORT SINGLETONS list NO
|
||||
G909 GRAPH_TABLE: explicit EXPORT NO SINGLETONS NO
|
||||
G910 GRAPH_TABLE: 'in paths clause' NO
|
||||
G920 DDL-based SQL-property graphs YES SQL/PGQ required
|
||||
G921 Empty SQL-property graph YES
|
||||
G922 Views as element tables YES
|
||||
G923 In-line views as element tables NO
|
||||
G924 Explicit key clause for element tables YES SQL/PGQ required
|
||||
G925 Explicit label and properties clause for element tables YES SQL/PGQ required
|
||||
G926 More than one label for vertex tables YES
|
||||
G927 More than one label for edge tables YES
|
||||
G928 Value expressions as properties and renaming of properties YES
|
||||
G929 Labels and properties: EXCEPT list NO
|
||||
G940 Multi-sourced/destined edges YES
|
||||
G941 Implicit removal of incomplete edges YES
|
||||
G950 Alter property graph statement: ADD/DROP element table YES
|
||||
G960 Alter element table definition: ADD/DROP LABEL YES
|
||||
G970 Alter element table definition: ALTER LABEL YES
|
||||
G980 DROP PROPERTY GRAPH: CASCADE drop behavior YES
|
||||
R010 Row pattern recognition: FROM clause NO
|
||||
R020 Row pattern recognition: WINDOW clause NO
|
||||
R030 Row pattern recognition: full aggregate support NO
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ OBJS = \
|
|||
portalcmds.o \
|
||||
prepare.o \
|
||||
proclang.o \
|
||||
propgraphcmds.o \
|
||||
publicationcmds.o \
|
||||
schemacmds.o \
|
||||
seclabel.o \
|
||||
|
|
|
|||
|
|
@ -390,6 +390,7 @@ ExecRenameStmt(RenameStmt *stmt)
|
|||
case OBJECT_MATVIEW:
|
||||
case OBJECT_INDEX:
|
||||
case OBJECT_FOREIGN_TABLE:
|
||||
case OBJECT_PROPGRAPH:
|
||||
return RenameRelation(stmt);
|
||||
|
||||
case OBJECT_COLUMN:
|
||||
|
|
@ -543,6 +544,7 @@ ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt,
|
|||
case OBJECT_TABLE:
|
||||
case OBJECT_VIEW:
|
||||
case OBJECT_MATVIEW:
|
||||
case OBJECT_PROPGRAPH:
|
||||
address = AlterTableNamespace(stmt,
|
||||
oldSchemaAddr ? &oldNspOid : NULL);
|
||||
break;
|
||||
|
|
@ -876,6 +878,7 @@ ExecAlterOwnerStmt(AlterOwnerStmt *stmt)
|
|||
case OBJECT_OPCLASS:
|
||||
case OBJECT_OPFAMILY:
|
||||
case OBJECT_PROCEDURE:
|
||||
case OBJECT_PROPGRAPH:
|
||||
case OBJECT_ROUTINE:
|
||||
case OBJECT_STATISTIC_EXT:
|
||||
case OBJECT_TABLESPACE:
|
||||
|
|
@ -884,11 +887,26 @@ ExecAlterOwnerStmt(AlterOwnerStmt *stmt)
|
|||
{
|
||||
ObjectAddress address;
|
||||
|
||||
address = get_object_address(stmt->objectType,
|
||||
stmt->object,
|
||||
NULL,
|
||||
AccessExclusiveLock,
|
||||
false);
|
||||
if (stmt->relation)
|
||||
{
|
||||
Relation relation;
|
||||
|
||||
address = get_object_address_rv(stmt->objectType,
|
||||
stmt->relation,
|
||||
NIL,
|
||||
&relation,
|
||||
AccessExclusiveLock,
|
||||
false);
|
||||
relation_close(relation, NoLock);
|
||||
}
|
||||
else
|
||||
{
|
||||
address = get_object_address(stmt->objectType,
|
||||
stmt->object,
|
||||
NULL,
|
||||
AccessExclusiveLock,
|
||||
false);
|
||||
}
|
||||
|
||||
AlterObjectOwner_internal(address.classId, address.objectId,
|
||||
newowner);
|
||||
|
|
|
|||
|
|
@ -482,6 +482,7 @@ does_not_exist_skipping(ObjectType objtype, Node *object)
|
|||
case OBJECT_FOREIGN_TABLE:
|
||||
case OBJECT_INDEX:
|
||||
case OBJECT_MATVIEW:
|
||||
case OBJECT_PROPGRAPH:
|
||||
case OBJECT_ROLE:
|
||||
case OBJECT_SEQUENCE:
|
||||
case OBJECT_SUBSCRIPTION:
|
||||
|
|
|
|||
|
|
@ -2305,6 +2305,7 @@ stringify_grant_objtype(ObjectType objtype)
|
|||
case OBJECT_OPERATOR:
|
||||
case OBJECT_OPFAMILY:
|
||||
case OBJECT_POLICY:
|
||||
case OBJECT_PROPGRAPH:
|
||||
case OBJECT_PUBLICATION:
|
||||
case OBJECT_PUBLICATION_NAMESPACE:
|
||||
case OBJECT_PUBLICATION_REL:
|
||||
|
|
@ -2389,6 +2390,7 @@ stringify_adefprivs_objtype(ObjectType objtype)
|
|||
case OBJECT_OPFAMILY:
|
||||
case OBJECT_PARAMETER_ACL:
|
||||
case OBJECT_POLICY:
|
||||
case OBJECT_PROPGRAPH:
|
||||
case OBJECT_PUBLICATION:
|
||||
case OBJECT_PUBLICATION_NAMESPACE:
|
||||
case OBJECT_PUBLICATION_REL:
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ backend_sources += files(
|
|||
'portalcmds.c',
|
||||
'prepare.c',
|
||||
'proclang.c',
|
||||
'propgraphcmds.c',
|
||||
'publicationcmds.c',
|
||||
'schemacmds.c',
|
||||
'seclabel.c',
|
||||
|
|
|
|||
1882
src/backend/commands/propgraphcmds.c
Normal file
1882
src/backend/commands/propgraphcmds.c
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -80,6 +80,7 @@ SecLabelSupportsObjectType(ObjectType objtype)
|
|||
case OBJECT_OPFAMILY:
|
||||
case OBJECT_PARAMETER_ACL:
|
||||
case OBJECT_POLICY:
|
||||
case OBJECT_PROPGRAPH:
|
||||
case OBJECT_PUBLICATION_NAMESPACE:
|
||||
case OBJECT_PUBLICATION_REL:
|
||||
case OBJECT_RULE:
|
||||
|
|
|
|||
|
|
@ -308,6 +308,12 @@ static const struct dropmsgstrings dropmsgstringarray[] = {
|
|||
gettext_noop("index \"%s\" does not exist, skipping"),
|
||||
gettext_noop("\"%s\" is not an index"),
|
||||
gettext_noop("Use DROP INDEX to remove an index.")},
|
||||
{RELKIND_PROPGRAPH,
|
||||
ERRCODE_UNDEFINED_OBJECT,
|
||||
gettext_noop("property graph \"%s\" does not exist"),
|
||||
gettext_noop("property graph \"%s\" does not exist, skipping"),
|
||||
gettext_noop("\"%s\" is not a property graph"),
|
||||
gettext_noop("Use DROP PROPERTY GRAPH to remove a property graph.")},
|
||||
{'\0', 0, NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
|
|
@ -1550,7 +1556,7 @@ DropErrorMsgWrongType(const char *relname, char wrongkind, char rightkind)
|
|||
/*
|
||||
* RemoveRelations
|
||||
* Implements DROP TABLE, DROP INDEX, DROP SEQUENCE, DROP VIEW,
|
||||
* DROP MATERIALIZED VIEW, DROP FOREIGN TABLE
|
||||
* DROP MATERIALIZED VIEW, DROP FOREIGN TABLE, DROP PROPERTY GRAPH
|
||||
*/
|
||||
void
|
||||
RemoveRelations(DropStmt *drop)
|
||||
|
|
@ -1614,6 +1620,10 @@ RemoveRelations(DropStmt *drop)
|
|||
relkind = RELKIND_FOREIGN_TABLE;
|
||||
break;
|
||||
|
||||
case OBJECT_PROPGRAPH:
|
||||
relkind = RELKIND_PROPGRAPH;
|
||||
break;
|
||||
|
||||
default:
|
||||
elog(ERROR, "unrecognized drop object type: %d",
|
||||
(int) drop->removeType);
|
||||
|
|
@ -4219,7 +4229,7 @@ RenameConstraint(RenameStmt *stmt)
|
|||
}
|
||||
|
||||
/*
|
||||
* Execute ALTER TABLE/INDEX/SEQUENCE/VIEW/MATERIALIZED VIEW/FOREIGN TABLE
|
||||
* Execute ALTER TABLE/INDEX/SEQUENCE/VIEW/MATERIALIZED VIEW/FOREIGN TABLE/PROPERTY GRAPH
|
||||
* RENAME
|
||||
*/
|
||||
ObjectAddress
|
||||
|
|
@ -16329,6 +16339,7 @@ ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lock
|
|||
case RELKIND_MATVIEW:
|
||||
case RELKIND_FOREIGN_TABLE:
|
||||
case RELKIND_PARTITIONED_TABLE:
|
||||
case RELKIND_PROPGRAPH:
|
||||
/* ok to change owner */
|
||||
break;
|
||||
case RELKIND_INDEX:
|
||||
|
|
@ -19897,6 +19908,11 @@ RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid,
|
|||
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
||||
errmsg("\"%s\" is not a composite type", rv->relname)));
|
||||
|
||||
if (reltype == OBJECT_PROPGRAPH && relkind != RELKIND_PROPGRAPH)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
||||
errmsg("\"%s\" is not a property graph", rv->relname)));
|
||||
|
||||
if (reltype == OBJECT_INDEX && relkind != RELKIND_INDEX &&
|
||||
relkind != RELKIND_PARTITIONED_INDEX
|
||||
&& !IsA(stmt, RenameStmt))
|
||||
|
|
|
|||
|
|
@ -599,11 +599,11 @@ ExecCheckPermissions(List *rangeTable, List *rteperminfos,
|
|||
|
||||
/*
|
||||
* Only relation RTEs and subquery RTEs that were once relation
|
||||
* RTEs (views) have their perminfoindex set.
|
||||
* RTEs (views, property graphs) have their perminfoindex set.
|
||||
*/
|
||||
Assert(rte->rtekind == RTE_RELATION ||
|
||||
(rte->rtekind == RTE_SUBQUERY &&
|
||||
rte->relkind == RELKIND_VIEW));
|
||||
(rte->relkind == RELKIND_VIEW || rte->relkind == RELKIND_PROPGRAPH)));
|
||||
|
||||
(void) getRTEPermissionInfo(rteperminfos, rte);
|
||||
/* Many-to-one mapping not allowed */
|
||||
|
|
@ -1163,6 +1163,12 @@ CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation,
|
|||
break;
|
||||
}
|
||||
break;
|
||||
case RELKIND_PROPGRAPH:
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
||||
errmsg("cannot change property graph \"%s\"",
|
||||
RelationGetRelationName(resultRel))));
|
||||
break;
|
||||
default:
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
||||
|
|
@ -1227,6 +1233,13 @@ CheckValidRowMarkRel(Relation rel, RowMarkType markType)
|
|||
errmsg("cannot lock rows in foreign table \"%s\"",
|
||||
RelationGetRelationName(rel))));
|
||||
break;
|
||||
case RELKIND_PROPGRAPH:
|
||||
/* Should not get here; rewriter should have expanded the graph */
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
||||
errmsg_internal("cannot lock rows in property graph \"%s\"",
|
||||
RelationGetRelationName(rel))));
|
||||
break;
|
||||
default:
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
||||
|
|
|
|||
|
|
@ -284,6 +284,9 @@ exprType(const Node *expr)
|
|||
case T_PlaceHolderVar:
|
||||
type = exprType((Node *) ((const PlaceHolderVar *) expr)->phexpr);
|
||||
break;
|
||||
case T_GraphPropertyRef:
|
||||
type = ((const GraphPropertyRef *) expr)->typeId;
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr));
|
||||
type = InvalidOid; /* keep compiler quiet */
|
||||
|
|
@ -536,6 +539,8 @@ exprTypmod(const Node *expr)
|
|||
return exprTypmod((Node *) ((const ReturningExpr *) expr)->retexpr);
|
||||
case T_PlaceHolderVar:
|
||||
return exprTypmod((Node *) ((const PlaceHolderVar *) expr)->phexpr);
|
||||
case T_GraphPropertyRef:
|
||||
return ((const GraphPropertyRef *) expr)->typmod;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -1058,6 +1063,9 @@ exprCollation(const Node *expr)
|
|||
case T_PlaceHolderVar:
|
||||
coll = exprCollation((Node *) ((const PlaceHolderVar *) expr)->phexpr);
|
||||
break;
|
||||
case T_GraphPropertyRef:
|
||||
coll = ((const GraphPropertyRef *) expr)->collation;
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr));
|
||||
coll = InvalidOid; /* keep compiler quiet */
|
||||
|
|
@ -2127,6 +2135,7 @@ expression_tree_walker_impl(Node *node,
|
|||
case T_RangeTblRef:
|
||||
case T_SortGroupClause:
|
||||
case T_CTESearchClause:
|
||||
case T_GraphPropertyRef:
|
||||
case T_MergeSupportFunc:
|
||||
/* primitive node types with no expression subnodes */
|
||||
break;
|
||||
|
|
@ -2667,6 +2676,26 @@ expression_tree_walker_impl(Node *node,
|
|||
return true;
|
||||
}
|
||||
break;
|
||||
case T_GraphElementPattern:
|
||||
{
|
||||
GraphElementPattern *gep = (GraphElementPattern *) node;
|
||||
|
||||
if (WALK(gep->subexpr))
|
||||
return true;
|
||||
if (WALK(gep->whereClause))
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case T_GraphPattern:
|
||||
{
|
||||
GraphPattern *gp = (GraphPattern *) node;
|
||||
|
||||
if (LIST_WALK(gp->path_pattern_list))
|
||||
return true;
|
||||
if (WALK(gp->whereClause))
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "unrecognized node type: %d",
|
||||
(int) nodeTag(node));
|
||||
|
|
@ -2860,6 +2889,12 @@ range_table_entry_walker_impl(RangeTblEntry *rte,
|
|||
if (WALK(rte->values_lists))
|
||||
return true;
|
||||
break;
|
||||
case RTE_GRAPH_TABLE:
|
||||
if (WALK(rte->graph_pattern))
|
||||
return true;
|
||||
if (WALK(rte->graph_table_columns))
|
||||
return true;
|
||||
break;
|
||||
case RTE_CTE:
|
||||
case RTE_NAMEDTUPLESTORE:
|
||||
case RTE_RESULT:
|
||||
|
|
@ -3912,6 +3947,10 @@ range_table_mutator_impl(List *rtable,
|
|||
case RTE_VALUES:
|
||||
MUTATE(newrte->values_lists, rte->values_lists, List *);
|
||||
break;
|
||||
case RTE_GRAPH_TABLE:
|
||||
MUTATE(newrte->graph_pattern, rte->graph_pattern, GraphPattern *);
|
||||
MUTATE(newrte->graph_table_columns, rte->graph_table_columns, List *);
|
||||
break;
|
||||
case RTE_CTE:
|
||||
case RTE_NAMEDTUPLESTORE:
|
||||
case RTE_RESULT:
|
||||
|
|
@ -4546,6 +4585,18 @@ raw_expression_tree_walker_impl(Node *node,
|
|||
return true;
|
||||
}
|
||||
break;
|
||||
case T_RangeGraphTable:
|
||||
{
|
||||
RangeGraphTable *rgt = (RangeGraphTable *) node;
|
||||
|
||||
if (WALK(rgt->graph_pattern))
|
||||
return true;
|
||||
if (WALK(rgt->columns))
|
||||
return true;
|
||||
if (WALK(rgt->alias))
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case T_TypeName:
|
||||
{
|
||||
TypeName *tn = (TypeName *) node;
|
||||
|
|
@ -4704,6 +4755,26 @@ raw_expression_tree_walker_impl(Node *node,
|
|||
return true;
|
||||
}
|
||||
break;
|
||||
case T_GraphElementPattern:
|
||||
{
|
||||
GraphElementPattern *gep = (GraphElementPattern *) node;
|
||||
|
||||
if (WALK(gep->subexpr))
|
||||
return true;
|
||||
if (WALK(gep->whereClause))
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case T_GraphPattern:
|
||||
{
|
||||
GraphPattern *gp = (GraphPattern *) node;
|
||||
|
||||
if (WALK(gp->path_pattern_list))
|
||||
return true;
|
||||
if (WALK(gp->whereClause))
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "unrecognized node type: %d",
|
||||
(int) nodeTag(node));
|
||||
|
|
|
|||
|
|
@ -565,6 +565,15 @@ _outRangeTblEntry(StringInfo str, const RangeTblEntry *node)
|
|||
/* we re-use these RELATION fields, too: */
|
||||
WRITE_OID_FIELD(relid);
|
||||
break;
|
||||
case RTE_GRAPH_TABLE:
|
||||
WRITE_NODE_FIELD(graph_pattern);
|
||||
WRITE_NODE_FIELD(graph_table_columns);
|
||||
/* we re-use these RELATION fields, too: */
|
||||
WRITE_OID_FIELD(relid);
|
||||
WRITE_CHAR_FIELD(relkind);
|
||||
WRITE_INT_FIELD(rellockmode);
|
||||
WRITE_UINT_FIELD(perminfoindex);
|
||||
break;
|
||||
case RTE_RESULT:
|
||||
/* no extra fields */
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -304,6 +304,10 @@ print_rt(const List *rtable)
|
|||
printf("%d\t%s\t[group]",
|
||||
i, rte->eref->aliasname);
|
||||
break;
|
||||
case RTE_GRAPH_TABLE:
|
||||
printf("%d\t%s\t[graph table]",
|
||||
i, rte->eref->aliasname);
|
||||
break;
|
||||
default:
|
||||
printf("%d\t%s\t[unknown rtekind]",
|
||||
i, rte->eref->aliasname);
|
||||
|
|
|
|||
|
|
@ -423,6 +423,15 @@ _readRangeTblEntry(void)
|
|||
/* we re-use these RELATION fields, too: */
|
||||
READ_OID_FIELD(relid);
|
||||
break;
|
||||
case RTE_GRAPH_TABLE:
|
||||
READ_NODE_FIELD(graph_pattern);
|
||||
READ_NODE_FIELD(graph_table_columns);
|
||||
/* we re-use these RELATION fields, too: */
|
||||
READ_OID_FIELD(relid);
|
||||
READ_CHAR_FIELD(relkind);
|
||||
READ_INT_FIELD(rellockmode);
|
||||
READ_UINT_FIELD(perminfoindex);
|
||||
break;
|
||||
case RTE_RESULT:
|
||||
/* no extra fields */
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -787,6 +787,16 @@ set_rel_consider_parallel(PlannerInfo *root, RelOptInfo *rel,
|
|||
case RTE_RESULT:
|
||||
/* RESULT RTEs, in themselves, are no problem. */
|
||||
break;
|
||||
|
||||
case RTE_GRAPH_TABLE:
|
||||
|
||||
/*
|
||||
* Shouldn't happen since these are replaced by subquery RTEs when
|
||||
* rewriting queries.
|
||||
*/
|
||||
Assert(false);
|
||||
return;
|
||||
|
||||
case RTE_GROUP:
|
||||
/* Shouldn't happen; we're only considering baserels here. */
|
||||
Assert(false);
|
||||
|
|
|
|||
|
|
@ -1631,6 +1631,10 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte,
|
|||
case RTE_GROUP:
|
||||
/* these can't contain any lateral references */
|
||||
break;
|
||||
case RTE_GRAPH_TABLE:
|
||||
/* shouldn't happen here */
|
||||
Assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2696,6 +2700,10 @@ replace_vars_in_jointree(Node *jtnode,
|
|||
/* these shouldn't be marked LATERAL */
|
||||
Assert(false);
|
||||
break;
|
||||
case RTE_GRAPH_TABLE:
|
||||
/* shouldn't happen here */
|
||||
Assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ OBJS = \
|
|||
parse_enr.o \
|
||||
parse_expr.o \
|
||||
parse_func.o \
|
||||
parse_graphtable.o \
|
||||
parse_jsontable.o \
|
||||
parse_merge.o \
|
||||
parse_node.o \
|
||||
|
|
|
|||
|
|
@ -79,9 +79,6 @@ static Query *transformValuesClause(ParseState *pstate, SelectStmt *stmt);
|
|||
static Query *transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt);
|
||||
static Node *transformSetOperationTree(ParseState *pstate, SelectStmt *stmt,
|
||||
bool isTopLevel, List **targetlist);
|
||||
static void constructSetOpTargetlist(ParseState *pstate, SetOperationStmt *op,
|
||||
const List *ltargetlist, const List *rtargetlist,
|
||||
List **targetlist, const char *context, bool recursive);
|
||||
static void determineRecursiveColTypes(ParseState *pstate,
|
||||
Node *larg, List *nrtargetlist);
|
||||
static Query *transformReturnStmt(ParseState *pstate, ReturnStmt *stmt);
|
||||
|
|
@ -2271,7 +2268,7 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt,
|
|||
* given SetOperationStmt node. context is a string for error messages
|
||||
* ("UNION" etc.). recursive is true if it is a recursive union.
|
||||
*/
|
||||
static void
|
||||
void
|
||||
constructSetOpTargetlist(ParseState *pstate, SetOperationStmt *op,
|
||||
const List *ltargetlist, const List *rtargetlist,
|
||||
List **targetlist, const char *context, bool recursive)
|
||||
|
|
|
|||
|
|
@ -295,6 +295,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
|
|||
CreateSchemaStmt CreateSeqStmt CreateStmt CreateStatsStmt CreateTableSpaceStmt
|
||||
CreateFdwStmt CreateForeignServerStmt CreateForeignTableStmt
|
||||
CreateAssertionStmt CreateTransformStmt CreateTrigStmt CreateEventTrigStmt
|
||||
CreatePropGraphStmt AlterPropGraphStmt
|
||||
CreateUserStmt CreateUserMappingStmt CreateRoleStmt CreatePolicyStmt
|
||||
CreatedbStmt DeclareCursorStmt DefineStmt DeleteStmt DiscardStmt DoStmt
|
||||
DropOpClassStmt DropOpFamilyStmt DropStmt
|
||||
|
|
@ -685,6 +686,36 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
|
|||
json_object_constructor_null_clause_opt
|
||||
json_array_constructor_null_clause_opt
|
||||
|
||||
%type <list> vertex_tables_clause edge_tables_clause
|
||||
opt_vertex_tables_clause opt_edge_tables_clause
|
||||
vertex_table_list
|
||||
opt_graph_table_key_clause
|
||||
edge_table_list
|
||||
source_vertex_table destination_vertex_table
|
||||
opt_element_table_label_and_properties
|
||||
label_and_properties_list
|
||||
add_label_list
|
||||
%type <node> vertex_table_definition edge_table_definition
|
||||
%type <alias> opt_propgraph_table_alias
|
||||
%type <str> element_table_label_clause
|
||||
%type <node> label_and_properties element_table_properties
|
||||
add_label
|
||||
%type <ival> vertex_or_edge
|
||||
|
||||
%type <list> opt_graph_pattern_quantifier
|
||||
path_pattern_list
|
||||
path_pattern
|
||||
path_pattern_expression
|
||||
path_term
|
||||
%type <node> graph_pattern
|
||||
path_factor
|
||||
path_primary
|
||||
opt_is_label_expression
|
||||
label_expression
|
||||
label_disjunction
|
||||
label_term
|
||||
%type <str> opt_colid
|
||||
|
||||
/*
|
||||
* Non-keyword token types. These are hard-wired into the "flex" lexer.
|
||||
* They must be listed first so that their numeric codes do not depend on
|
||||
|
|
@ -727,18 +758,18 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
|
|||
CURRENT_TIME CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE
|
||||
|
||||
DATA_P DATABASE DAY_P DEALLOCATE DEC DECIMAL_P DECLARE DEFAULT DEFAULTS
|
||||
DEFERRABLE DEFERRED DEFINER DELETE_P DELIMITER DELIMITERS DEPENDS DEPTH DESC
|
||||
DEFERRABLE DEFERRED DEFINER DELETE_P DELIMITER DELIMITERS DEPENDS DEPTH DESC DESTINATION
|
||||
DETACH DICTIONARY DISABLE_P DISCARD DISTINCT DO DOCUMENT_P DOMAIN_P
|
||||
DOUBLE_P DROP
|
||||
|
||||
EACH ELSE EMPTY_P ENABLE_P ENCODING ENCRYPTED END_P ENFORCED ENUM_P ERROR_P
|
||||
ESCAPE EVENT EXCEPT EXCLUDE EXCLUDING EXCLUSIVE EXECUTE EXISTS EXPLAIN
|
||||
EXPRESSION EXTENSION EXTERNAL EXTRACT
|
||||
EACH EDGE ELSE EMPTY_P ENABLE_P ENCODING ENCRYPTED END_P ENFORCED ENUM_P
|
||||
ERROR_P ESCAPE EVENT EXCEPT EXCLUDE EXCLUDING EXCLUSIVE EXECUTE EXISTS
|
||||
EXPLAIN EXPRESSION EXTENSION EXTERNAL EXTRACT
|
||||
|
||||
FALSE_P FAMILY FETCH FILTER FINALIZE FIRST_P FLOAT_P FOLLOWING FOR
|
||||
FORCE FOREIGN FORMAT FORWARD FREEZE FROM FULL FUNCTION FUNCTIONS
|
||||
|
||||
GENERATED GLOBAL GRANT GRANTED GREATEST GROUP_P GROUPING GROUPS
|
||||
GENERATED GLOBAL GRANT GRANTED GRAPH GRAPH_TABLE GREATEST GROUP_P GROUPING GROUPS
|
||||
|
||||
HANDLER HAVING HEADER_P HOLD HOUR_P
|
||||
|
||||
|
|
@ -759,7 +790,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
|
|||
MAPPING MATCH MATCHED MATERIALIZED MAXVALUE MERGE MERGE_ACTION METHOD
|
||||
MINUTE_P MINVALUE MODE MONTH_P MOVE
|
||||
|
||||
NAME_P NAMES NATIONAL NATURAL NCHAR NESTED NEW NEXT NFC NFD NFKC NFKD NO
|
||||
NAME_P NAMES NATIONAL NATURAL NCHAR NESTED NEW NEXT NFC NFD NFKC NFKD NO NODE
|
||||
NONE NORMALIZE NORMALIZED
|
||||
NOT NOTHING NOTIFY NOTNULL NOWAIT NULL_P NULLIF
|
||||
NULLS_P NUMERIC
|
||||
|
|
@ -771,12 +802,12 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
|
|||
PARALLEL PARAMETER PARSER PARTIAL PARTITION PARTITIONS PASSING PASSWORD PATH
|
||||
PERIOD PLACING PLAN PLANS POLICY
|
||||
POSITION PRECEDING PRECISION PRESERVE PREPARE PREPARED PRIMARY
|
||||
PRIOR PRIVILEGES PROCEDURAL PROCEDURE PROCEDURES PROGRAM PUBLICATION
|
||||
PRIOR PRIVILEGES PROCEDURAL PROCEDURE PROCEDURES PROGRAM PROPERTIES PROPERTY PUBLICATION
|
||||
|
||||
QUOTE QUOTES
|
||||
|
||||
RANGE READ REAL REASSIGN RECURSIVE REF_P REFERENCES REFERENCING
|
||||
REFRESH REINDEX RELATIVE_P RELEASE RENAME REPACK REPEATABLE REPLACE REPLICA
|
||||
REFRESH REINDEX RELATIONSHIP RELATIVE_P RELEASE RENAME REPACK REPEATABLE REPLACE REPLICA
|
||||
RESET RESPECT_P RESTART RESTRICT RETURN RETURNING RETURNS REVOKE RIGHT ROLE ROLLBACK ROLLUP
|
||||
ROUTINE ROUTINES ROW ROWS RULE
|
||||
|
||||
|
|
@ -796,7 +827,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
|
|||
UNLISTEN UNLOGGED UNTIL UPDATE USER USING
|
||||
|
||||
VACUUM VALID VALIDATE VALIDATOR VALUE_P VALUES VARCHAR VARIADIC VARYING
|
||||
VERBOSE VERSION_P VIEW VIEWS VIRTUAL VOLATILE
|
||||
VERBOSE VERSION_P VERTEX VIEW VIEWS VIRTUAL VOLATILE
|
||||
|
||||
WAIT WHEN WHERE WHITESPACE_P WINDOW WITH WITHIN WITHOUT WORK WRAPPER WRITE
|
||||
|
||||
|
|
@ -894,7 +925,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
|
|||
%nonassoc UNBOUNDED NESTED /* ideally would have same precedence as IDENT */
|
||||
%nonassoc IDENT PARTITION RANGE ROWS GROUPS PRECEDING FOLLOWING CUBE ROLLUP
|
||||
SET KEYS OBJECT_P SCALAR VALUE_P WITH WITHOUT PATH
|
||||
%left Op OPERATOR /* multi-character ops and user-defined operators */
|
||||
%left Op OPERATOR RIGHT_ARROW '|' /* multi-character ops and user-defined operators */
|
||||
%left '+' '-'
|
||||
%left '*' '/' '%'
|
||||
%left '^'
|
||||
|
|
@ -1021,6 +1052,7 @@ stmt:
|
|||
| AlterOperatorStmt
|
||||
| AlterTypeStmt
|
||||
| AlterPolicyStmt
|
||||
| AlterPropGraphStmt
|
||||
| AlterSeqStmt
|
||||
| AlterSystemStmt
|
||||
| AlterTableStmt
|
||||
|
|
@ -1060,6 +1092,7 @@ stmt:
|
|||
| AlterOpFamilyStmt
|
||||
| CreatePolicyStmt
|
||||
| CreatePLangStmt
|
||||
| CreatePropGraphStmt
|
||||
| CreateSchemaStmt
|
||||
| CreateSeqStmt
|
||||
| CreateStmt
|
||||
|
|
@ -7202,6 +7235,7 @@ object_type_any_name:
|
|||
| MATERIALIZED VIEW { $$ = OBJECT_MATVIEW; }
|
||||
| INDEX { $$ = OBJECT_INDEX; }
|
||||
| FOREIGN TABLE { $$ = OBJECT_FOREIGN_TABLE; }
|
||||
| PROPERTY GRAPH { $$ = OBJECT_PROPGRAPH; }
|
||||
| COLLATION { $$ = OBJECT_COLLATION; }
|
||||
| CONVERSION_P { $$ = OBJECT_CONVERSION; }
|
||||
| STATISTICS { $$ = OBJECT_STATISTIC_EXT; }
|
||||
|
|
@ -8090,6 +8124,15 @@ privilege_target:
|
|||
n->objs = $2;
|
||||
$$ = n;
|
||||
}
|
||||
| PROPERTY GRAPH qualified_name_list
|
||||
{
|
||||
PrivTarget *n = palloc_object(PrivTarget);
|
||||
|
||||
n->targtype = ACL_TARGET_OBJECT;
|
||||
n->objtype = OBJECT_PROPGRAPH;
|
||||
n->objs = $3;
|
||||
$$ = n;
|
||||
}
|
||||
| SCHEMA name_list
|
||||
{
|
||||
PrivTarget *n = palloc_object(PrivTarget);
|
||||
|
|
@ -9419,6 +9462,370 @@ opt_if_exists: IF_P EXISTS { $$ = true; }
|
|||
;
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* CREATE PROPERTY GRAPH
|
||||
* ALTER PROPERTY GRAPH
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
CreatePropGraphStmt: CREATE OptTemp PROPERTY GRAPH qualified_name opt_vertex_tables_clause opt_edge_tables_clause
|
||||
{
|
||||
CreatePropGraphStmt *n = makeNode(CreatePropGraphStmt);
|
||||
|
||||
n->pgname = $5;
|
||||
n->pgname->relpersistence = $2;
|
||||
n->vertex_tables = $6;
|
||||
n->edge_tables = $7;
|
||||
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
;
|
||||
|
||||
opt_vertex_tables_clause:
|
||||
vertex_tables_clause { $$ = $1; }
|
||||
| /*EMPTY*/ { $$ = NIL; }
|
||||
;
|
||||
|
||||
vertex_tables_clause:
|
||||
vertex_synonym TABLES '(' vertex_table_list ')' { $$ = $4; }
|
||||
;
|
||||
|
||||
vertex_synonym: NODE | VERTEX
|
||||
;
|
||||
|
||||
vertex_table_list: vertex_table_definition { $$ = list_make1($1); }
|
||||
| vertex_table_list ',' vertex_table_definition { $$ = lappend($1, $3); }
|
||||
;
|
||||
|
||||
vertex_table_definition: qualified_name opt_propgraph_table_alias opt_graph_table_key_clause
|
||||
opt_element_table_label_and_properties
|
||||
{
|
||||
PropGraphVertex *n = makeNode(PropGraphVertex);
|
||||
|
||||
$1->alias = $2;
|
||||
n->vtable = $1;
|
||||
n->vkey = $3;
|
||||
n->labels = $4;
|
||||
n->location = @1;
|
||||
|
||||
$$ = (Node *) n;
|
||||
}
|
||||
;
|
||||
|
||||
opt_propgraph_table_alias:
|
||||
AS name
|
||||
{
|
||||
$$ = makeNode(Alias);
|
||||
$$->aliasname = $2;
|
||||
}
|
||||
| /*EMPTY*/ { $$ = NULL; }
|
||||
;
|
||||
|
||||
opt_graph_table_key_clause:
|
||||
KEY '(' columnList ')' { $$ = $3; }
|
||||
| /*EMPTY*/ { $$ = NIL; }
|
||||
;
|
||||
|
||||
opt_edge_tables_clause:
|
||||
edge_tables_clause { $$ = $1; }
|
||||
| /*EMPTY*/ { $$ = NIL; }
|
||||
;
|
||||
|
||||
edge_tables_clause:
|
||||
edge_synonym TABLES '(' edge_table_list ')' { $$ = $4; }
|
||||
;
|
||||
|
||||
edge_synonym: EDGE | RELATIONSHIP
|
||||
;
|
||||
|
||||
edge_table_list: edge_table_definition { $$ = list_make1($1); }
|
||||
| edge_table_list ',' edge_table_definition { $$ = lappend($1, $3); }
|
||||
;
|
||||
|
||||
edge_table_definition: qualified_name opt_propgraph_table_alias opt_graph_table_key_clause
|
||||
source_vertex_table destination_vertex_table opt_element_table_label_and_properties
|
||||
{
|
||||
PropGraphEdge *n = makeNode(PropGraphEdge);
|
||||
|
||||
$1->alias = $2;
|
||||
n->etable = $1;
|
||||
n->ekey = $3;
|
||||
n->esrckey = linitial($4);
|
||||
n->esrcvertex = lsecond($4);
|
||||
n->esrcvertexcols = lthird($4);
|
||||
n->edestkey = linitial($5);
|
||||
n->edestvertex = lsecond($5);
|
||||
n->edestvertexcols = lthird($5);
|
||||
n->labels = $6;
|
||||
n->location = @1;
|
||||
|
||||
$$ = (Node *) n;
|
||||
}
|
||||
;
|
||||
|
||||
source_vertex_table: SOURCE name
|
||||
{
|
||||
$$ = list_make3(NULL, $2, NULL);
|
||||
}
|
||||
| SOURCE KEY '(' columnList ')' REFERENCES name '(' columnList ')'
|
||||
{
|
||||
$$ = list_make3($4, $7, $9);
|
||||
}
|
||||
;
|
||||
|
||||
destination_vertex_table: DESTINATION name
|
||||
{
|
||||
$$ = list_make3(NULL, $2, NULL);
|
||||
}
|
||||
| DESTINATION KEY '(' columnList ')' REFERENCES name '(' columnList ')'
|
||||
{
|
||||
$$ = list_make3($4, $7, $9);
|
||||
}
|
||||
;
|
||||
|
||||
opt_element_table_label_and_properties:
|
||||
element_table_properties
|
||||
{
|
||||
PropGraphLabelAndProperties *lp = makeNode(PropGraphLabelAndProperties);
|
||||
|
||||
lp->properties = (PropGraphProperties *) $1;
|
||||
lp->location = @1;
|
||||
|
||||
$$ = list_make1(lp);
|
||||
}
|
||||
| label_and_properties_list
|
||||
{
|
||||
$$ = $1;
|
||||
}
|
||||
| /*EMPTY*/
|
||||
{
|
||||
PropGraphLabelAndProperties *lp = makeNode(PropGraphLabelAndProperties);
|
||||
PropGraphProperties *pr = makeNode(PropGraphProperties);
|
||||
|
||||
pr->all = true;
|
||||
pr->location = -1;
|
||||
lp->properties = pr;
|
||||
lp->location = -1;
|
||||
|
||||
$$ = list_make1(lp);
|
||||
}
|
||||
;
|
||||
|
||||
element_table_properties:
|
||||
NO PROPERTIES
|
||||
{
|
||||
PropGraphProperties *pr = makeNode(PropGraphProperties);
|
||||
|
||||
pr->properties = NIL;
|
||||
pr->location = @1;
|
||||
|
||||
$$ = (Node *) pr;
|
||||
}
|
||||
| PROPERTIES ALL COLUMNS
|
||||
/*
|
||||
* SQL standard also allows "PROPERTIES ARE ALL COLUMNS", but that
|
||||
* would require making ARE a keyword, which seems a bit much for
|
||||
* such a marginal use. Could be added later if needed.
|
||||
*/
|
||||
{
|
||||
PropGraphProperties *pr = makeNode(PropGraphProperties);
|
||||
|
||||
pr->all = true;
|
||||
pr->location = @1;
|
||||
|
||||
$$ = (Node *) pr;
|
||||
}
|
||||
| PROPERTIES '(' labeled_expr_list ')'
|
||||
{
|
||||
PropGraphProperties *pr = makeNode(PropGraphProperties);
|
||||
|
||||
pr->properties = $3;
|
||||
pr->location = @1;
|
||||
|
||||
$$ = (Node *) pr;
|
||||
}
|
||||
;
|
||||
|
||||
label_and_properties_list:
|
||||
label_and_properties
|
||||
{
|
||||
$$ = list_make1($1);
|
||||
}
|
||||
| label_and_properties_list label_and_properties
|
||||
{
|
||||
$$ = lappend($1, $2);
|
||||
}
|
||||
;
|
||||
|
||||
label_and_properties:
|
||||
element_table_label_clause
|
||||
{
|
||||
PropGraphLabelAndProperties *lp = makeNode(PropGraphLabelAndProperties);
|
||||
PropGraphProperties *pr = makeNode(PropGraphProperties);
|
||||
|
||||
pr->all = true;
|
||||
pr->location = -1;
|
||||
|
||||
lp->label = $1;
|
||||
lp->properties = pr;
|
||||
lp->location = @1;
|
||||
|
||||
$$ = (Node *) lp;
|
||||
}
|
||||
| element_table_label_clause element_table_properties
|
||||
{
|
||||
PropGraphLabelAndProperties *lp = makeNode(PropGraphLabelAndProperties);
|
||||
|
||||
lp->label = $1;
|
||||
lp->properties = (PropGraphProperties *) $2;
|
||||
lp->location = @1;
|
||||
|
||||
$$ = (Node *) lp;
|
||||
}
|
||||
;
|
||||
|
||||
element_table_label_clause:
|
||||
LABEL name
|
||||
{
|
||||
$$ = $2;
|
||||
}
|
||||
| DEFAULT LABEL
|
||||
{
|
||||
$$ = NULL;
|
||||
}
|
||||
;
|
||||
|
||||
AlterPropGraphStmt:
|
||||
ALTER PROPERTY GRAPH qualified_name ADD_P vertex_tables_clause
|
||||
{
|
||||
AlterPropGraphStmt *n = makeNode(AlterPropGraphStmt);
|
||||
|
||||
n->pgname = $4;
|
||||
n->add_vertex_tables = $6;
|
||||
|
||||
$$ = (Node *) n;
|
||||
}
|
||||
| ALTER PROPERTY GRAPH qualified_name ADD_P vertex_tables_clause ADD_P edge_tables_clause
|
||||
{
|
||||
AlterPropGraphStmt *n = makeNode(AlterPropGraphStmt);
|
||||
|
||||
n->pgname = $4;
|
||||
n->add_vertex_tables = $6;
|
||||
n->add_edge_tables = $8;
|
||||
|
||||
$$ = (Node *) n;
|
||||
}
|
||||
| ALTER PROPERTY GRAPH qualified_name ADD_P edge_tables_clause
|
||||
{
|
||||
AlterPropGraphStmt *n = makeNode(AlterPropGraphStmt);
|
||||
|
||||
n->pgname = $4;
|
||||
n->add_edge_tables = $6;
|
||||
|
||||
$$ = (Node *) n;
|
||||
}
|
||||
| ALTER PROPERTY GRAPH qualified_name DROP vertex_synonym TABLES '(' name_list ')' opt_drop_behavior
|
||||
{
|
||||
AlterPropGraphStmt *n = makeNode(AlterPropGraphStmt);
|
||||
|
||||
n->pgname = $4;
|
||||
n->drop_vertex_tables = $9;
|
||||
n->drop_behavior = $11;
|
||||
|
||||
$$ = (Node *) n;
|
||||
}
|
||||
| ALTER PROPERTY GRAPH qualified_name DROP edge_synonym TABLES '(' name_list ')' opt_drop_behavior
|
||||
{
|
||||
AlterPropGraphStmt *n = makeNode(AlterPropGraphStmt);
|
||||
|
||||
n->pgname = $4;
|
||||
n->drop_edge_tables = $9;
|
||||
n->drop_behavior = $11;
|
||||
|
||||
$$ = (Node *) n;
|
||||
}
|
||||
| ALTER PROPERTY GRAPH qualified_name ALTER vertex_or_edge TABLE name
|
||||
add_label_list
|
||||
{
|
||||
AlterPropGraphStmt *n = makeNode(AlterPropGraphStmt);
|
||||
|
||||
n->pgname = $4;
|
||||
n->element_kind = $6;
|
||||
n->element_alias = $8;
|
||||
n->add_labels = $9;
|
||||
|
||||
$$ = (Node *) n;
|
||||
}
|
||||
| ALTER PROPERTY GRAPH qualified_name ALTER vertex_or_edge TABLE name
|
||||
DROP LABEL name opt_drop_behavior
|
||||
{
|
||||
AlterPropGraphStmt *n = makeNode(AlterPropGraphStmt);
|
||||
|
||||
n->pgname = $4;
|
||||
n->element_kind = $6;
|
||||
n->element_alias = $8;
|
||||
n->drop_label = $11;
|
||||
n->drop_behavior = $12;
|
||||
|
||||
$$ = (Node *) n;
|
||||
}
|
||||
| ALTER PROPERTY GRAPH qualified_name ALTER vertex_or_edge TABLE name
|
||||
ALTER LABEL name ADD_P PROPERTIES '(' labeled_expr_list ')'
|
||||
{
|
||||
AlterPropGraphStmt *n = makeNode(AlterPropGraphStmt);
|
||||
PropGraphProperties *pr = makeNode(PropGraphProperties);
|
||||
|
||||
n->pgname = $4;
|
||||
n->element_kind = $6;
|
||||
n->element_alias = $8;
|
||||
n->alter_label = $11;
|
||||
|
||||
pr->properties = $15;
|
||||
pr->location = @13;
|
||||
n->add_properties = pr;
|
||||
|
||||
$$ = (Node *) n;
|
||||
}
|
||||
| ALTER PROPERTY GRAPH qualified_name ALTER vertex_or_edge TABLE name
|
||||
ALTER LABEL name DROP PROPERTIES '(' name_list ')' opt_drop_behavior
|
||||
{
|
||||
AlterPropGraphStmt *n = makeNode(AlterPropGraphStmt);
|
||||
|
||||
n->pgname = $4;
|
||||
n->element_kind = $6;
|
||||
n->element_alias = $8;
|
||||
n->alter_label = $11;
|
||||
n->drop_properties = $15;
|
||||
n->drop_behavior = $17;
|
||||
|
||||
$$ = (Node *) n;
|
||||
}
|
||||
;
|
||||
|
||||
vertex_or_edge:
|
||||
vertex_synonym { $$ = PROPGRAPH_ELEMENT_KIND_VERTEX; }
|
||||
| edge_synonym { $$ = PROPGRAPH_ELEMENT_KIND_EDGE; }
|
||||
;
|
||||
|
||||
add_label_list:
|
||||
add_label { $$ = list_make1($1); }
|
||||
| add_label_list add_label { $$ = lappend($1, $2); }
|
||||
;
|
||||
|
||||
add_label: ADD_P LABEL name element_table_properties
|
||||
{
|
||||
PropGraphLabelAndProperties *lp = makeNode(PropGraphLabelAndProperties);
|
||||
|
||||
lp->label = $3;
|
||||
lp->properties = (PropGraphProperties *) $4;
|
||||
lp->location = @1;
|
||||
|
||||
$$ = (Node *) lp;
|
||||
}
|
||||
;
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* CREATE TRANSFORM / DROP TRANSFORM
|
||||
|
|
@ -9715,6 +10122,16 @@ RenameStmt: ALTER AGGREGATE aggregate_with_argtypes RENAME TO name
|
|||
n->missing_ok = false;
|
||||
$$ = (Node *) n;
|
||||
}
|
||||
| ALTER PROPERTY GRAPH qualified_name RENAME TO name
|
||||
{
|
||||
RenameStmt *n = makeNode(RenameStmt);
|
||||
|
||||
n->renameType = OBJECT_PROPGRAPH;
|
||||
n->relation = $4;
|
||||
n->newname = $7;
|
||||
n->missing_ok = false;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| ALTER PUBLICATION name RENAME TO name
|
||||
{
|
||||
RenameStmt *n = makeNode(RenameStmt);
|
||||
|
|
@ -10340,6 +10757,26 @@ AlterObjectSchemaStmt:
|
|||
n->missing_ok = false;
|
||||
$$ = (Node *) n;
|
||||
}
|
||||
| ALTER PROPERTY GRAPH qualified_name SET SCHEMA name
|
||||
{
|
||||
AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
|
||||
|
||||
n->objectType = OBJECT_PROPGRAPH;
|
||||
n->relation = $4;
|
||||
n->newschema = $7;
|
||||
n->missing_ok = false;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| ALTER PROPERTY GRAPH IF_P EXISTS qualified_name SET SCHEMA name
|
||||
{
|
||||
AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
|
||||
|
||||
n->objectType = OBJECT_PROPGRAPH;
|
||||
n->relation = $6;
|
||||
n->newschema = $9;
|
||||
n->missing_ok = true;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| ALTER ROUTINE function_with_argtypes SET SCHEMA name
|
||||
{
|
||||
AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
|
||||
|
|
@ -10683,6 +11120,15 @@ AlterOwnerStmt: ALTER AGGREGATE aggregate_with_argtypes OWNER TO RoleSpec
|
|||
n->newowner = $6;
|
||||
$$ = (Node *) n;
|
||||
}
|
||||
| ALTER PROPERTY GRAPH qualified_name OWNER TO RoleSpec
|
||||
{
|
||||
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
|
||||
|
||||
n->objectType = OBJECT_PROPGRAPH;
|
||||
n->relation = $4;
|
||||
n->newowner = $7;
|
||||
$$ = (Node *) n;
|
||||
}
|
||||
| ALTER ROUTINE function_with_argtypes OWNER TO RoleSpec
|
||||
{
|
||||
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
|
||||
|
|
@ -13958,6 +14404,17 @@ table_ref: relation_expr opt_alias_clause
|
|||
n->alias = $3;
|
||||
$$ = (Node *) n;
|
||||
}
|
||||
| GRAPH_TABLE '(' qualified_name MATCH graph_pattern COLUMNS '(' labeled_expr_list ')' ')' opt_alias_clause
|
||||
{
|
||||
RangeGraphTable *n = makeNode(RangeGraphTable);
|
||||
|
||||
n->graph_name = $3;
|
||||
n->graph_pattern = castNode(GraphPattern, $5);
|
||||
n->columns = $8;
|
||||
n->alias = $11;
|
||||
n->location = @1;
|
||||
$$ = (Node *) n;
|
||||
}
|
||||
| select_with_parens opt_alias_clause
|
||||
{
|
||||
RangeSubselect *n = makeNode(RangeSubselect);
|
||||
|
|
@ -15309,6 +15766,10 @@ a_expr: c_expr { $$ = $1; }
|
|||
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, ">=", $1, $3, @2); }
|
||||
| a_expr NOT_EQUALS a_expr
|
||||
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "<>", $1, $3, @2); }
|
||||
| a_expr RIGHT_ARROW a_expr
|
||||
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "->", $1, $3, @2); }
|
||||
| a_expr '|' a_expr
|
||||
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "|", $1, $3, @2); }
|
||||
|
||||
| a_expr qual_Op a_expr %prec Op
|
||||
{ $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, $3, @2); }
|
||||
|
|
@ -15789,6 +16250,10 @@ b_expr: c_expr
|
|||
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, ">=", $1, $3, @2); }
|
||||
| b_expr NOT_EQUALS b_expr
|
||||
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "<>", $1, $3, @2); }
|
||||
| b_expr RIGHT_ARROW b_expr
|
||||
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "->", $1, $3, @2); }
|
||||
| b_expr '|' b_expr
|
||||
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "|", $1, $3, @2); }
|
||||
| b_expr qual_Op b_expr %prec Op
|
||||
{ $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, $3, @2); }
|
||||
| qual_Op b_expr %prec Op
|
||||
|
|
@ -16984,6 +17449,8 @@ MathOp: '+' { $$ = "+"; }
|
|||
| LESS_EQUALS { $$ = "<="; }
|
||||
| GREATER_EQUALS { $$ = ">="; }
|
||||
| NOT_EQUALS { $$ = "<>"; }
|
||||
| RIGHT_ARROW { $$ = "->"; }
|
||||
| '|' { $$ = "|"; }
|
||||
;
|
||||
|
||||
qual_Op: Op
|
||||
|
|
@ -17564,6 +18031,214 @@ json_array_aggregate_order_by_clause_opt:
|
|||
| /* EMPTY */ { $$ = NIL; }
|
||||
;
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* graph patterns
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
graph_pattern:
|
||||
path_pattern_list where_clause
|
||||
{
|
||||
GraphPattern *gp = makeNode(GraphPattern);
|
||||
|
||||
gp->path_pattern_list = $1;
|
||||
gp->whereClause = $2;
|
||||
$$ = (Node *) gp;
|
||||
}
|
||||
;
|
||||
|
||||
path_pattern_list:
|
||||
path_pattern { $$ = list_make1($1); }
|
||||
| path_pattern_list ',' path_pattern { $$ = lappend($1, $3); }
|
||||
;
|
||||
|
||||
path_pattern:
|
||||
path_pattern_expression { $$ = $1; }
|
||||
;
|
||||
|
||||
/*
|
||||
* path pattern expression
|
||||
*/
|
||||
|
||||
path_pattern_expression:
|
||||
path_term { $$ = $1; }
|
||||
/* | path_multiset_alternation */
|
||||
/* | path_pattern_union */
|
||||
;
|
||||
|
||||
path_term:
|
||||
path_factor { $$ = list_make1($1); }
|
||||
| path_term path_factor { $$ = lappend($1, $2); }
|
||||
;
|
||||
|
||||
path_factor:
|
||||
path_primary opt_graph_pattern_quantifier
|
||||
{
|
||||
GraphElementPattern *gep = (GraphElementPattern *) $1;
|
||||
|
||||
gep->quantifier = $2;
|
||||
|
||||
$$ = (Node *) gep;
|
||||
}
|
||||
;
|
||||
|
||||
path_primary:
|
||||
'(' opt_colid opt_is_label_expression where_clause ')'
|
||||
{
|
||||
GraphElementPattern *gep = makeNode(GraphElementPattern);
|
||||
|
||||
gep->kind = VERTEX_PATTERN;
|
||||
gep->variable = $2;
|
||||
gep->labelexpr = $3;
|
||||
gep->whereClause = $4;
|
||||
gep->location = @1;
|
||||
|
||||
$$ = (Node *) gep;
|
||||
}
|
||||
/* full edge pointing left: <-[ xxx ]- */
|
||||
| '<' '-' '[' opt_colid opt_is_label_expression where_clause ']' '-'
|
||||
{
|
||||
GraphElementPattern *gep = makeNode(GraphElementPattern);
|
||||
|
||||
gep->kind = EDGE_PATTERN_LEFT;
|
||||
gep->variable = $4;
|
||||
gep->labelexpr = $5;
|
||||
gep->whereClause = $6;
|
||||
gep->location = @1;
|
||||
|
||||
$$ = (Node *) gep;
|
||||
}
|
||||
/* full edge pointing right: -[ xxx ]-> */
|
||||
| '-' '[' opt_colid opt_is_label_expression where_clause ']' '-' '>'
|
||||
{
|
||||
GraphElementPattern *gep = makeNode(GraphElementPattern);
|
||||
|
||||
gep->kind = EDGE_PATTERN_RIGHT;
|
||||
gep->variable = $3;
|
||||
gep->labelexpr = $4;
|
||||
gep->whereClause = $5;
|
||||
gep->location = @1;
|
||||
|
||||
$$ = (Node *) gep;
|
||||
}
|
||||
| '-' '[' opt_colid opt_is_label_expression where_clause ']' RIGHT_ARROW
|
||||
{
|
||||
GraphElementPattern *gep = makeNode(GraphElementPattern);
|
||||
|
||||
gep->kind = EDGE_PATTERN_RIGHT;
|
||||
gep->variable = $3;
|
||||
gep->labelexpr = $4;
|
||||
gep->whereClause = $5;
|
||||
gep->location = @1;
|
||||
|
||||
$$ = (Node *) gep;
|
||||
}
|
||||
/* full edge any direction: -[ xxx ]- */
|
||||
| '-' '[' opt_colid opt_is_label_expression where_clause ']' '-'
|
||||
{
|
||||
GraphElementPattern *gep = makeNode(GraphElementPattern);
|
||||
|
||||
gep->kind = EDGE_PATTERN_ANY;
|
||||
gep->variable = $3;
|
||||
gep->labelexpr = $4;
|
||||
gep->whereClause = $5;
|
||||
gep->location = @1;
|
||||
|
||||
$$ = (Node *) gep;
|
||||
}
|
||||
/* abbreviated edge patterns */
|
||||
| '<' '-'
|
||||
{
|
||||
GraphElementPattern *gep = makeNode(GraphElementPattern);
|
||||
|
||||
gep->kind = EDGE_PATTERN_LEFT;
|
||||
gep->location = @1;
|
||||
|
||||
$$ = (Node *) gep;
|
||||
}
|
||||
| '-' '>'
|
||||
{
|
||||
GraphElementPattern *gep = makeNode(GraphElementPattern);
|
||||
|
||||
gep->kind = EDGE_PATTERN_RIGHT;
|
||||
gep->location = @1;
|
||||
|
||||
$$ = (Node *) gep;
|
||||
}
|
||||
| RIGHT_ARROW
|
||||
{
|
||||
GraphElementPattern *gep = makeNode(GraphElementPattern);
|
||||
|
||||
gep->kind = EDGE_PATTERN_RIGHT;
|
||||
gep->location = @1;
|
||||
|
||||
$$ = (Node *) gep;
|
||||
}
|
||||
| '-'
|
||||
{
|
||||
GraphElementPattern *gep = makeNode(GraphElementPattern);
|
||||
|
||||
gep->kind = EDGE_PATTERN_ANY;
|
||||
gep->location = @1;
|
||||
|
||||
$$ = (Node *) gep;
|
||||
}
|
||||
| '(' path_pattern_expression where_clause ')'
|
||||
{
|
||||
GraphElementPattern *gep = makeNode(GraphElementPattern);
|
||||
|
||||
gep->kind = PAREN_EXPR;
|
||||
gep->subexpr = $2;
|
||||
gep->whereClause = $3;
|
||||
gep->location = @1;
|
||||
|
||||
$$ = (Node *) gep;
|
||||
}
|
||||
;
|
||||
|
||||
opt_colid:
|
||||
ColId { $$ = $1; }
|
||||
| /*EMPTY*/ { $$ = NULL; }
|
||||
;
|
||||
|
||||
opt_is_label_expression:
|
||||
IS label_expression { $$ = $2; }
|
||||
| /*EMPTY*/ { $$ = NULL; }
|
||||
;
|
||||
|
||||
/*
|
||||
* graph pattern quantifier
|
||||
*/
|
||||
|
||||
opt_graph_pattern_quantifier:
|
||||
'{' Iconst '}' { $$ = list_make2_int($2, $2); }
|
||||
| '{' ',' Iconst '}' { $$ = list_make2_int(0, $3); }
|
||||
| '{' Iconst ',' Iconst '}' { $$ = list_make2_int($2, $4); }
|
||||
| /*EMPTY*/ { $$ = NULL; }
|
||||
;
|
||||
|
||||
/*
|
||||
* label expression
|
||||
*/
|
||||
|
||||
label_expression:
|
||||
label_term
|
||||
| label_disjunction
|
||||
;
|
||||
|
||||
label_disjunction:
|
||||
label_expression '|' label_term
|
||||
{ $$ = makeOrExpr($1, $3, @2); }
|
||||
;
|
||||
|
||||
label_term:
|
||||
name
|
||||
{ $$ = makeColumnRef($1, NIL, @1, yyscanner); }
|
||||
;
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* target list for SELECT
|
||||
|
|
@ -18085,6 +18760,7 @@ unreserved_keyword:
|
|||
| DELIMITERS
|
||||
| DEPENDS
|
||||
| DEPTH
|
||||
| DESTINATION
|
||||
| DETACH
|
||||
| DICTIONARY
|
||||
| DISABLE_P
|
||||
|
|
@ -18094,6 +18770,7 @@ unreserved_keyword:
|
|||
| DOUBLE_P
|
||||
| DROP
|
||||
| EACH
|
||||
| EDGE
|
||||
| EMPTY_P
|
||||
| ENABLE_P
|
||||
| ENCODING
|
||||
|
|
@ -18124,6 +18801,7 @@ unreserved_keyword:
|
|||
| GENERATED
|
||||
| GLOBAL
|
||||
| GRANTED
|
||||
| GRAPH
|
||||
| GROUPS
|
||||
| HANDLER
|
||||
| HEADER_P
|
||||
|
|
@ -18190,6 +18868,7 @@ unreserved_keyword:
|
|||
| NFKC
|
||||
| NFKD
|
||||
| NO
|
||||
| NODE
|
||||
| NORMALIZED
|
||||
| NOTHING
|
||||
| NOTIFY
|
||||
|
|
@ -18234,6 +18913,8 @@ unreserved_keyword:
|
|||
| PROCEDURE
|
||||
| PROCEDURES
|
||||
| PROGRAM
|
||||
| PROPERTIES
|
||||
| PROPERTY
|
||||
| PUBLICATION
|
||||
| QUOTE
|
||||
| QUOTES
|
||||
|
|
@ -18245,6 +18926,7 @@ unreserved_keyword:
|
|||
| REFERENCING
|
||||
| REFRESH
|
||||
| REINDEX
|
||||
| RELATIONSHIP
|
||||
| RELATIVE_P
|
||||
| RELEASE
|
||||
| RENAME
|
||||
|
|
@ -18337,6 +19019,7 @@ unreserved_keyword:
|
|||
| VALUE_P
|
||||
| VARYING
|
||||
| VERSION_P
|
||||
| VERTEX
|
||||
| VIEW
|
||||
| VIEWS
|
||||
| VIRTUAL
|
||||
|
|
@ -18377,6 +19060,7 @@ col_name_keyword:
|
|||
| EXISTS
|
||||
| EXTRACT
|
||||
| FLOAT_P
|
||||
| GRAPH_TABLE
|
||||
| GREATEST
|
||||
| GROUPING
|
||||
| INOUT
|
||||
|
|
@ -18668,6 +19352,7 @@ bare_label_keyword:
|
|||
| DEPENDS
|
||||
| DEPTH
|
||||
| DESC
|
||||
| DESTINATION
|
||||
| DETACH
|
||||
| DICTIONARY
|
||||
| DISABLE_P
|
||||
|
|
@ -18679,6 +19364,7 @@ bare_label_keyword:
|
|||
| DOUBLE_P
|
||||
| DROP
|
||||
| EACH
|
||||
| EDGE
|
||||
| ELSE
|
||||
| EMPTY_P
|
||||
| ENABLE_P
|
||||
|
|
@ -18717,6 +19403,8 @@ bare_label_keyword:
|
|||
| GENERATED
|
||||
| GLOBAL
|
||||
| GRANTED
|
||||
| GRAPH
|
||||
| GRAPH_TABLE
|
||||
| GREATEST
|
||||
| GROUPING
|
||||
| GROUPS
|
||||
|
|
@ -18813,6 +19501,7 @@ bare_label_keyword:
|
|||
| NFKC
|
||||
| NFKD
|
||||
| NO
|
||||
| NODE
|
||||
| NONE
|
||||
| NORMALIZE
|
||||
| NORMALIZED
|
||||
|
|
@ -18870,6 +19559,8 @@ bare_label_keyword:
|
|||
| PROCEDURE
|
||||
| PROCEDURES
|
||||
| PROGRAM
|
||||
| PROPERTIES
|
||||
| PROPERTY
|
||||
| PUBLICATION
|
||||
| QUOTE
|
||||
| QUOTES
|
||||
|
|
@ -18883,6 +19574,7 @@ bare_label_keyword:
|
|||
| REFERENCING
|
||||
| REFRESH
|
||||
| REINDEX
|
||||
| RELATIONSHIP
|
||||
| RELATIVE_P
|
||||
| RELEASE
|
||||
| RENAME
|
||||
|
|
@ -18999,6 +19691,7 @@ bare_label_keyword:
|
|||
| VARIADIC
|
||||
| VERBOSE
|
||||
| VERSION_P
|
||||
| VERTEX
|
||||
| VIEW
|
||||
| VIEWS
|
||||
| VIRTUAL
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ backend_sources += files(
|
|||
'parse_enr.c',
|
||||
'parse_expr.c',
|
||||
'parse_func.c',
|
||||
'parse_graphtable.c',
|
||||
'parse_jsontable.c',
|
||||
'parse_merge.c',
|
||||
'parse_node.c',
|
||||
|
|
|
|||
|
|
@ -585,6 +585,14 @@ check_agglevels_and_constraints(ParseState *pstate, Node *expr)
|
|||
errkind = true;
|
||||
break;
|
||||
|
||||
case EXPR_KIND_PROPGRAPH_PROPERTY:
|
||||
if (isAgg)
|
||||
err = _("aggregate functions are not allowed in property definition expressions");
|
||||
else
|
||||
err = _("grouping operations are not allowed in property definition expressions");
|
||||
|
||||
break;
|
||||
|
||||
/*
|
||||
* There is intentionally no default: case here, so that the
|
||||
* compiler will warn if we add a new ParseExprKind without
|
||||
|
|
@ -1024,6 +1032,9 @@ transformWindowFuncCall(ParseState *pstate, WindowFunc *wfunc,
|
|||
case EXPR_KIND_CYCLE_MARK:
|
||||
errkind = true;
|
||||
break;
|
||||
case EXPR_KIND_PROPGRAPH_PROPERTY:
|
||||
err = _("window functions are not allowed in property definition expressions");
|
||||
break;
|
||||
|
||||
/*
|
||||
* There is intentionally no default: case here, so that the
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include "access/htup_details.h"
|
||||
#include "access/nbtree.h"
|
||||
#include "access/relation.h"
|
||||
#include "access/table.h"
|
||||
#include "access/tsmapi.h"
|
||||
#include "catalog/catalog.h"
|
||||
|
|
@ -35,6 +36,7 @@
|
|||
#include "parser/parse_collate.h"
|
||||
#include "parser/parse_expr.h"
|
||||
#include "parser/parse_func.h"
|
||||
#include "parser/parse_graphtable.h"
|
||||
#include "parser/parse_oper.h"
|
||||
#include "parser/parse_relation.h"
|
||||
#include "parser/parse_target.h"
|
||||
|
|
@ -65,6 +67,8 @@ static ParseNamespaceItem *transformRangeFunction(ParseState *pstate,
|
|||
RangeFunction *r);
|
||||
static ParseNamespaceItem *transformRangeTableFunc(ParseState *pstate,
|
||||
RangeTableFunc *rtf);
|
||||
static ParseNamespaceItem *transformRangeGraphTable(ParseState *pstate,
|
||||
RangeGraphTable *rgt);
|
||||
static TableSampleClause *transformRangeTableSample(ParseState *pstate,
|
||||
RangeTableSample *rts);
|
||||
static ParseNamespaceItem *getNSItemForSpecialRelationTypes(ParseState *pstate,
|
||||
|
|
@ -898,6 +902,126 @@ transformRangeTableFunc(ParseState *pstate, RangeTableFunc *rtf)
|
|||
tf, rtf->alias, is_lateral, true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Similar to parserOpenTable() but for property graphs.
|
||||
*/
|
||||
static Relation
|
||||
parserOpenPropGraph(ParseState *pstate, const RangeVar *relation, LOCKMODE lockmode)
|
||||
{
|
||||
Relation rel;
|
||||
ParseCallbackState pcbstate;
|
||||
|
||||
setup_parser_errposition_callback(&pcbstate, pstate, relation->location);
|
||||
|
||||
rel = relation_openrv(relation, lockmode);
|
||||
|
||||
/*
|
||||
* In parserOpenTable(), the relkind check is done inside table_openrv*.
|
||||
* We do it here since we don't have anything like propgraph_open.
|
||||
*/
|
||||
if (rel->rd_rel->relkind != RELKIND_PROPGRAPH)
|
||||
ereport(ERROR,
|
||||
errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
||||
errmsg("\"%s\" is not a property graph",
|
||||
RelationGetRelationName(rel)));
|
||||
|
||||
cancel_parser_errposition_callback(&pcbstate);
|
||||
return rel;
|
||||
}
|
||||
|
||||
/*
|
||||
* transformRangeGraphTable -- transform a GRAPH_TABLE clause
|
||||
*/
|
||||
static ParseNamespaceItem *
|
||||
transformRangeGraphTable(ParseState *pstate, RangeGraphTable *rgt)
|
||||
{
|
||||
Relation rel;
|
||||
Oid graphid;
|
||||
GraphTableParseState *gpstate = palloc0_object(GraphTableParseState);
|
||||
Node *gp;
|
||||
List *columns = NIL;
|
||||
List *colnames = NIL;
|
||||
ListCell *lc;
|
||||
int resno = 0;
|
||||
bool saved_hasSublinks;
|
||||
|
||||
rel = parserOpenPropGraph(pstate, rgt->graph_name, AccessShareLock);
|
||||
|
||||
graphid = RelationGetRelid(rel);
|
||||
|
||||
gpstate->graphid = graphid;
|
||||
|
||||
/*
|
||||
* The syntax does not allow nested GRAPH_TABLE and this function
|
||||
* prohibits subquery within GRAPH_TABLE. There should be only one
|
||||
* GRAPH_TABLE being transformed at a time.
|
||||
*/
|
||||
Assert(!pstate->p_graph_table_pstate);
|
||||
pstate->p_graph_table_pstate = gpstate;
|
||||
|
||||
Assert(!pstate->p_lateral_active);
|
||||
pstate->p_lateral_active = true;
|
||||
|
||||
saved_hasSublinks = pstate->p_hasSubLinks;
|
||||
pstate->p_hasSubLinks = false;
|
||||
|
||||
gp = transformGraphPattern(pstate, rgt->graph_pattern);
|
||||
|
||||
/*
|
||||
* Construct a targetlist representing the COLUMNS specified in the
|
||||
* GRAPH_TABLE. This uses previously constructed list of element pattern
|
||||
* variables in the GraphTableParseState.
|
||||
*/
|
||||
foreach(lc, rgt->columns)
|
||||
{
|
||||
ResTarget *rt = lfirst_node(ResTarget, lc);
|
||||
Node *colexpr;
|
||||
TargetEntry *te;
|
||||
char *colname;
|
||||
|
||||
colexpr = transformExpr(pstate, rt->val, EXPR_KIND_SELECT_TARGET);
|
||||
|
||||
if (rt->name)
|
||||
colname = rt->name;
|
||||
else
|
||||
{
|
||||
if (IsA(colexpr, GraphPropertyRef))
|
||||
colname = get_propgraph_property_name(castNode(GraphPropertyRef, colexpr)->propid);
|
||||
else
|
||||
{
|
||||
ereport(ERROR,
|
||||
errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("complex graph table column must specify an explicit column name"),
|
||||
parser_errposition(pstate, rt->location));
|
||||
colname = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
colnames = lappend(colnames, makeString(colname));
|
||||
|
||||
te = makeTargetEntry((Expr *) colexpr, ++resno, colname, false);
|
||||
columns = lappend(columns, te);
|
||||
}
|
||||
|
||||
table_close(rel, NoLock);
|
||||
|
||||
pstate->p_graph_table_pstate = NULL;
|
||||
pstate->p_lateral_active = false;
|
||||
|
||||
/*
|
||||
* If we support subqueries within GRAPH_TABLE, those need to be
|
||||
* propagated to the queries resulting from rewriting graph table RTE. We
|
||||
* don't do that right now, hence prohibit it for now.
|
||||
*/
|
||||
if (pstate->p_hasSubLinks)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("subqueries within GRAPH_TABLE reference are not supported")));
|
||||
pstate->p_hasSubLinks = saved_hasSublinks;
|
||||
|
||||
return addRangeTableEntryForGraphTable(pstate, graphid, castNode(GraphPattern, gp), columns, colnames, rgt->alias, false, true);
|
||||
}
|
||||
|
||||
/*
|
||||
* transformRangeTableSample --- transform a TABLESAMPLE clause
|
||||
*
|
||||
|
|
@ -1121,6 +1245,18 @@ transformFromClauseItem(ParseState *pstate, Node *n,
|
|||
rtr->rtindex = nsitem->p_rtindex;
|
||||
return (Node *) rtr;
|
||||
}
|
||||
else if (IsA(n, RangeGraphTable))
|
||||
{
|
||||
RangeTblRef *rtr;
|
||||
ParseNamespaceItem *nsitem;
|
||||
|
||||
nsitem = transformRangeGraphTable(pstate, (RangeGraphTable *) n);
|
||||
*top_nsitem = nsitem;
|
||||
*namespace = list_make1(nsitem);
|
||||
rtr = makeNode(RangeTblRef);
|
||||
rtr->rtindex = nsitem->p_rtindex;
|
||||
return (Node *) rtr;
|
||||
}
|
||||
else if (IsA(n, RangeTableSample))
|
||||
{
|
||||
/* TABLESAMPLE clause (wrapping some other valid FROM node) */
|
||||
|
|
|
|||
|
|
@ -546,6 +546,7 @@ assign_collations_walker(Node *node, assign_collations_context *context)
|
|||
case T_CaseTestExpr:
|
||||
case T_SetToDefault:
|
||||
case T_CurrentOfExpr:
|
||||
case T_GraphPropertyRef:
|
||||
|
||||
/*
|
||||
* General case for childless expression nodes. These should
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#include "parser/parse_collate.h"
|
||||
#include "parser/parse_expr.h"
|
||||
#include "parser/parse_func.h"
|
||||
#include "parser/parse_graphtable.h"
|
||||
#include "parser/parse_oper.h"
|
||||
#include "parser/parse_relation.h"
|
||||
#include "parser/parse_target.h"
|
||||
|
|
@ -577,6 +578,7 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
|
|||
case EXPR_KIND_COPY_WHERE:
|
||||
case EXPR_KIND_GENERATED_COLUMN:
|
||||
case EXPR_KIND_CYCLE_MARK:
|
||||
case EXPR_KIND_PROPGRAPH_PROPERTY:
|
||||
/* okay */
|
||||
break;
|
||||
|
||||
|
|
@ -824,6 +826,10 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
|
|||
break;
|
||||
}
|
||||
|
||||
/* Try it as a graph table property reference. */
|
||||
if (node == NULL)
|
||||
node = transformGraphTablePropertyRef(pstate, cref);
|
||||
|
||||
/*
|
||||
* Now give the PostParseColumnRefHook, if any, a chance. We pass the
|
||||
* translation-so-far so that it can throw an error if it wishes in the
|
||||
|
|
@ -1871,6 +1877,9 @@ transformSubLink(ParseState *pstate, SubLink *sublink)
|
|||
case EXPR_KIND_GENERATED_COLUMN:
|
||||
err = _("cannot use subquery in column generation expression");
|
||||
break;
|
||||
case EXPR_KIND_PROPGRAPH_PROPERTY:
|
||||
err = _("cannot use subquery in property definition expression");
|
||||
break;
|
||||
|
||||
/*
|
||||
* There is intentionally no default: case here, so that the
|
||||
|
|
@ -3230,6 +3239,8 @@ ParseExprKindName(ParseExprKind exprKind)
|
|||
return "GENERATED AS";
|
||||
case EXPR_KIND_CYCLE_MARK:
|
||||
return "CYCLE";
|
||||
case EXPR_KIND_PROPGRAPH_PROPERTY:
|
||||
return "property definition expression";
|
||||
|
||||
/*
|
||||
* There is intentionally no default: case here, so that the
|
||||
|
|
|
|||
|
|
@ -2783,6 +2783,9 @@ check_srf_call_placement(ParseState *pstate, Node *last_srf, int location)
|
|||
case EXPR_KIND_CYCLE_MARK:
|
||||
errkind = true;
|
||||
break;
|
||||
case EXPR_KIND_PROPGRAPH_PROPERTY:
|
||||
err = _("set-returning functions are not allowed in property definition expressions");
|
||||
break;
|
||||
|
||||
/*
|
||||
* There is intentionally no default: case here, so that the
|
||||
|
|
|
|||
309
src/backend/parser/parse_graphtable.c
Normal file
309
src/backend/parser/parse_graphtable.c
Normal file
|
|
@ -0,0 +1,309 @@
|
|||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* parse_graphtable.c
|
||||
* parsing of GRAPH_TABLE
|
||||
*
|
||||
* Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* src/backend/parser/parse_graphtable.c
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "postgres.h"
|
||||
|
||||
#include "access/genam.h"
|
||||
#include "access/htup_details.h"
|
||||
#include "access/table.h"
|
||||
#include "catalog/pg_propgraph_label.h"
|
||||
#include "catalog/pg_propgraph_property.h"
|
||||
#include "miscadmin.h"
|
||||
#include "nodes/makefuncs.h"
|
||||
#include "parser/parse_collate.h"
|
||||
#include "parser/parse_expr.h"
|
||||
#include "parser/parse_graphtable.h"
|
||||
#include "parser/parse_node.h"
|
||||
#include "utils/fmgroids.h"
|
||||
#include "utils/lsyscache.h"
|
||||
#include "utils/relcache.h"
|
||||
#include "utils/syscache.h"
|
||||
|
||||
|
||||
/*
|
||||
* Return human-readable name of the type of graph element pattern in
|
||||
* GRAPH_TABLE clause, usually for error message purpose.
|
||||
*/
|
||||
static const char *
|
||||
get_gep_kind_name(GraphElementPatternKind gepkind)
|
||||
{
|
||||
switch (gepkind)
|
||||
{
|
||||
case VERTEX_PATTERN:
|
||||
return "vertex";
|
||||
case EDGE_PATTERN_LEFT:
|
||||
return "edge pointing left";
|
||||
case EDGE_PATTERN_RIGHT:
|
||||
return "edge pointing right";
|
||||
case EDGE_PATTERN_ANY:
|
||||
return "edge pointing any direction";
|
||||
case PAREN_EXPR:
|
||||
return "nested path pattern";
|
||||
}
|
||||
|
||||
/*
|
||||
* When a GraphElementPattern is constructed by the parser, it will set a
|
||||
* value from the GraphElementPatternKind enum. But we may get here if the
|
||||
* GraphElementPatternKind value stored in a catalog is corrupted.
|
||||
*/
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
/*
|
||||
* Transform a property reference.
|
||||
*
|
||||
* A property reference is parsed as a ColumnRef of the form:
|
||||
* <variable>.<property>. If <variable> is one of the variables bound to an
|
||||
* element pattern in the graph pattern and <property> can be resolved as a
|
||||
* property of the property graph, then we return a GraphPropertyRef node
|
||||
* representing the property reference. If the <variable> exists in the graph
|
||||
* pattern but <property> does not exist in the property graph, we raise an
|
||||
* error. However, if <variable> does not exist in the graph pattern, we return
|
||||
* NULL to let the caller handle it as some other kind of ColumnRef. The
|
||||
* variables bound to the element patterns in the graph pattern are expected to
|
||||
* be collected in the GraphTableParseState.
|
||||
*/
|
||||
Node *
|
||||
transformGraphTablePropertyRef(ParseState *pstate, ColumnRef *cref)
|
||||
{
|
||||
GraphTableParseState *gpstate = pstate->p_graph_table_pstate;
|
||||
|
||||
if (!gpstate)
|
||||
return NULL;
|
||||
|
||||
if (list_length(cref->fields) == 2)
|
||||
{
|
||||
Node *field1 = linitial(cref->fields);
|
||||
Node *field2 = lsecond(cref->fields);
|
||||
char *elvarname;
|
||||
char *propname;
|
||||
|
||||
if (IsA(field1, A_Star) || IsA(field2, A_Star))
|
||||
{
|
||||
if (pstate->p_expr_kind == EXPR_KIND_SELECT_TARGET)
|
||||
ereport(ERROR,
|
||||
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("\"*\" is not supported here"),
|
||||
parser_errposition(pstate, cref->location));
|
||||
else
|
||||
ereport(ERROR,
|
||||
errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("\"*\" not allowed here"),
|
||||
parser_errposition(pstate, cref->location));
|
||||
}
|
||||
|
||||
elvarname = strVal(field1);
|
||||
propname = strVal(field2);
|
||||
|
||||
if (list_member(gpstate->variables, field1))
|
||||
{
|
||||
GraphPropertyRef *gpr = makeNode(GraphPropertyRef);
|
||||
HeapTuple pgptup;
|
||||
Form_pg_propgraph_property pgpform;
|
||||
|
||||
pgptup = SearchSysCache2(PROPGRAPHPROPNAME, ObjectIdGetDatum(gpstate->graphid), CStringGetDatum(propname));
|
||||
if (!HeapTupleIsValid(pgptup))
|
||||
ereport(ERROR,
|
||||
errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("property \"%s\" does not exist", propname));
|
||||
pgpform = (Form_pg_propgraph_property) GETSTRUCT(pgptup);
|
||||
|
||||
gpr->location = cref->location;
|
||||
gpr->elvarname = elvarname;
|
||||
gpr->propid = pgpform->oid;
|
||||
gpr->typeId = pgpform->pgptypid;
|
||||
gpr->typmod = pgpform->pgptypmod;
|
||||
gpr->collation = pgpform->pgpcollation;
|
||||
|
||||
ReleaseSysCache(pgptup);
|
||||
|
||||
return (Node *) gpr;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Transform a label expression.
|
||||
*
|
||||
* A label expression is parsed as either a ColumnRef with a single field or a
|
||||
* label expression like label disjunction. The single field in the ColumnRef is
|
||||
* treated as a label name and transformed to a GraphLabelRef node. The label
|
||||
* expression is recursively transformed into an expression tree containg
|
||||
* GraphLabelRef nodes corresponding to the names of the labels appearing in the
|
||||
* expression. If any label name cannot be resolved to a label in the property
|
||||
* graph, an error is raised.
|
||||
*/
|
||||
static Node *
|
||||
transformLabelExpr(GraphTableParseState *gpstate, Node *labelexpr)
|
||||
{
|
||||
Node *result;
|
||||
|
||||
if (labelexpr == NULL)
|
||||
return NULL;
|
||||
|
||||
check_stack_depth();
|
||||
|
||||
switch (nodeTag(labelexpr))
|
||||
{
|
||||
case T_ColumnRef:
|
||||
{
|
||||
ColumnRef *cref = (ColumnRef *) labelexpr;
|
||||
const char *labelname;
|
||||
Oid labelid;
|
||||
GraphLabelRef *lref;
|
||||
|
||||
Assert(list_length(cref->fields) == 1);
|
||||
labelname = strVal(linitial(cref->fields));
|
||||
|
||||
labelid = GetSysCacheOid2(PROPGRAPHLABELNAME, Anum_pg_propgraph_label_oid, ObjectIdGetDatum(gpstate->graphid), CStringGetDatum(labelname));
|
||||
if (!labelid)
|
||||
ereport(ERROR,
|
||||
errcode(ERRCODE_UNDEFINED_OBJECT),
|
||||
errmsg("label \"%s\" does not exist in property graph \"%s\"", labelname, get_rel_name(gpstate->graphid)));
|
||||
|
||||
lref = makeNode(GraphLabelRef);
|
||||
lref->labelid = labelid;
|
||||
lref->location = cref->location;
|
||||
|
||||
result = (Node *) lref;
|
||||
break;
|
||||
}
|
||||
|
||||
case T_BoolExpr:
|
||||
{
|
||||
BoolExpr *be = (BoolExpr *) labelexpr;
|
||||
ListCell *lc;
|
||||
List *args = NIL;
|
||||
|
||||
foreach(lc, be->args)
|
||||
{
|
||||
Node *arg = (Node *) lfirst(lc);
|
||||
|
||||
arg = transformLabelExpr(gpstate, arg);
|
||||
args = lappend(args, arg);
|
||||
}
|
||||
|
||||
result = (Node *) makeBoolExpr(be->boolop, args, be->location);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
/* should not reach here */
|
||||
elog(ERROR, "unsupported label expression node: %d", (int) nodeTag(labelexpr));
|
||||
result = NULL; /* keep compiler quiet */
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Transform a GraphElementPattern.
|
||||
*
|
||||
* Transform the label expression and the where clause in the element pattern
|
||||
* given by GraphElementPattern. The variable name in the GraphElementPattern is
|
||||
* added to the list of variables in the GraphTableParseState which is used to
|
||||
* resolve property references in this element pattern or elsewhere in the
|
||||
* GRAPH_TABLE.
|
||||
*/
|
||||
static Node *
|
||||
transformGraphElementPattern(ParseState *pstate, GraphElementPattern *gep)
|
||||
{
|
||||
GraphTableParseState *gpstate = pstate->p_graph_table_pstate;
|
||||
|
||||
if (gep->kind != VERTEX_PATTERN && !IS_EDGE_PATTERN(gep->kind))
|
||||
ereport(ERROR,
|
||||
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("unsupported element pattern kind: \"%s\"", get_gep_kind_name(gep->kind)));
|
||||
|
||||
if (gep->quantifier)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("element pattern quantifier is not supported")));
|
||||
|
||||
if (gep->variable)
|
||||
gpstate->variables = lappend(gpstate->variables, makeString(pstrdup(gep->variable)));
|
||||
|
||||
gep->labelexpr = transformLabelExpr(gpstate, gep->labelexpr);
|
||||
|
||||
gep->whereClause = transformExpr(pstate, gep->whereClause, EXPR_KIND_WHERE);
|
||||
assign_expr_collations(pstate, gep->whereClause);
|
||||
|
||||
return (Node *) gep;
|
||||
}
|
||||
|
||||
/*
|
||||
* Transform a path term (list of GraphElementPattern's).
|
||||
*/
|
||||
static Node *
|
||||
transformPathTerm(ParseState *pstate, List *path_term)
|
||||
{
|
||||
List *result = NIL;
|
||||
|
||||
foreach_node(GraphElementPattern, gep, path_term)
|
||||
result = lappend(result,
|
||||
transformGraphElementPattern(pstate, gep));
|
||||
|
||||
return (Node *) result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Transform a path pattern list (list of path terms).
|
||||
*/
|
||||
static Node *
|
||||
transformPathPatternList(ParseState *pstate, List *path_pattern)
|
||||
{
|
||||
List *result = NIL;
|
||||
|
||||
/* Grammar doesn't allow empty path pattern list */
|
||||
Assert(list_length(path_pattern) > 0);
|
||||
|
||||
/*
|
||||
* We do not support multiple path patterns in one GRAPH_TABLE clause
|
||||
* right now. But we may do so in future.
|
||||
*/
|
||||
if (list_length(path_pattern) != 1)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("multiple path patterns in one GRAPH_TABLE clause not supported")));
|
||||
|
||||
foreach_node(List, path_term, path_pattern)
|
||||
result = lappend(result, transformPathTerm(pstate, path_term));
|
||||
|
||||
return (Node *) result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Transform a GraphPattern.
|
||||
*
|
||||
* A GraphPattern consists of a list of one or more path patterns and an
|
||||
* optional where clause. Transform them. We use the previously constructure
|
||||
* list of variables in the GraphTableParseState to resolve property references
|
||||
* in the WHERE clause.
|
||||
*/
|
||||
Node *
|
||||
transformGraphPattern(ParseState *pstate, GraphPattern *graph_pattern)
|
||||
{
|
||||
List *path_pattern_list = castNode(List,
|
||||
transformPathPatternList(pstate, graph_pattern->path_pattern_list));
|
||||
|
||||
graph_pattern->path_pattern_list = path_pattern_list;
|
||||
graph_pattern->whereClause = transformExpr(pstate, graph_pattern->whereClause, EXPR_KIND_WHERE);
|
||||
assign_expr_collations(pstate, graph_pattern->whereClause);
|
||||
|
||||
return (Node *) graph_pattern;
|
||||
}
|
||||
|
|
@ -2131,6 +2131,99 @@ addRangeTableEntryForTableFunc(ParseState *pstate,
|
|||
rte->colcollations);
|
||||
}
|
||||
|
||||
ParseNamespaceItem *
|
||||
addRangeTableEntryForGraphTable(ParseState *pstate,
|
||||
Oid graphid,
|
||||
GraphPattern *graph_pattern,
|
||||
List *columns,
|
||||
List *colnames,
|
||||
Alias *alias,
|
||||
bool lateral,
|
||||
bool inFromCl)
|
||||
{
|
||||
RangeTblEntry *rte = makeNode(RangeTblEntry);
|
||||
char *refname = alias ? alias->aliasname : pstrdup("graph_table");
|
||||
Alias *eref;
|
||||
int numaliases;
|
||||
int varattno;
|
||||
ListCell *lc;
|
||||
List *coltypes = NIL;
|
||||
List *coltypmods = NIL;
|
||||
List *colcollations = NIL;
|
||||
RTEPermissionInfo *perminfo;
|
||||
ParseNamespaceItem *nsitem;
|
||||
|
||||
Assert(pstate != NULL);
|
||||
|
||||
rte->rtekind = RTE_GRAPH_TABLE;
|
||||
rte->relid = graphid;
|
||||
rte->relkind = RELKIND_PROPGRAPH;
|
||||
rte->graph_pattern = graph_pattern;
|
||||
rte->graph_table_columns = columns;
|
||||
rte->alias = alias;
|
||||
rte->rellockmode = AccessShareLock;
|
||||
|
||||
eref = alias ? copyObject(alias) : makeAlias(refname, NIL);
|
||||
|
||||
if (!eref->colnames)
|
||||
eref->colnames = colnames;
|
||||
|
||||
numaliases = list_length(eref->colnames);
|
||||
|
||||
/* fill in any unspecified alias columns */
|
||||
varattno = 0;
|
||||
foreach(lc, colnames)
|
||||
{
|
||||
varattno++;
|
||||
if (varattno > numaliases)
|
||||
eref->colnames = lappend(eref->colnames, lfirst(lc));
|
||||
}
|
||||
if (varattno < numaliases)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
|
||||
errmsg("GRAPH_TABLE \"%s\" has %d columns available but %d columns specified",
|
||||
refname, varattno, numaliases)));
|
||||
|
||||
rte->eref = eref;
|
||||
|
||||
foreach(lc, columns)
|
||||
{
|
||||
TargetEntry *te = lfirst_node(TargetEntry, lc);
|
||||
Node *colexpr = (Node *) te->expr;
|
||||
|
||||
coltypes = lappend_oid(coltypes, exprType(colexpr));
|
||||
coltypmods = lappend_int(coltypmods, exprTypmod(colexpr));
|
||||
colcollations = lappend_oid(colcollations, exprCollation(colexpr));
|
||||
}
|
||||
|
||||
/*
|
||||
* Set flags and access permissions.
|
||||
*/
|
||||
rte->lateral = lateral;
|
||||
rte->inFromCl = inFromCl;
|
||||
|
||||
perminfo = addRTEPermissionInfo(&pstate->p_rteperminfos, rte);
|
||||
perminfo->requiredPerms = ACL_SELECT;
|
||||
|
||||
/*
|
||||
* Add completed RTE to pstate's range table list, so that we know its
|
||||
* index. But we don't add it to the join list --- caller must do that if
|
||||
* appropriate.
|
||||
*/
|
||||
pstate->p_rtable = lappend(pstate->p_rtable, rte);
|
||||
|
||||
/*
|
||||
* Build a ParseNamespaceItem, but don't add it to the pstate's namespace
|
||||
* list --- caller must do that if appropriate.
|
||||
*/
|
||||
nsitem = buildNSItemFromLists(rte, list_length(pstate->p_rtable),
|
||||
coltypes, coltypmods, colcollations);
|
||||
|
||||
nsitem->p_perminfo = perminfo;
|
||||
|
||||
return nsitem;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add an entry for a VALUES list to the pstate's range table (p_rtable).
|
||||
* Then, construct and return a ParseNamespaceItem for the new RTE.
|
||||
|
|
@ -3029,6 +3122,7 @@ expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up,
|
|||
case RTE_VALUES:
|
||||
case RTE_CTE:
|
||||
case RTE_NAMEDTUPLESTORE:
|
||||
case RTE_GRAPH_TABLE:
|
||||
{
|
||||
/* Tablefunc, Values, CTE, or ENR RTE */
|
||||
ListCell *aliasp_item = list_head(rte->eref->colnames);
|
||||
|
|
@ -3413,10 +3507,11 @@ get_rte_attribute_is_dropped(RangeTblEntry *rte, AttrNumber attnum)
|
|||
case RTE_VALUES:
|
||||
case RTE_CTE:
|
||||
case RTE_GROUP:
|
||||
case RTE_GRAPH_TABLE:
|
||||
|
||||
/*
|
||||
* Subselect, Table Functions, Values, CTE, GROUP RTEs never have
|
||||
* dropped columns
|
||||
* Subselect, Table Functions, Values, CTE, GROUP RTEs, Property
|
||||
* graph references never have dropped columns
|
||||
*/
|
||||
result = false;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -359,6 +359,10 @@ markTargetListOrigin(ParseState *pstate, TargetEntry *tle,
|
|||
tle->resorigtbl = rte->relid;
|
||||
tle->resorigcol = attnum;
|
||||
break;
|
||||
case RTE_GRAPH_TABLE:
|
||||
tle->resorigtbl = rte->relid;
|
||||
tle->resorigcol = InvalidAttrNumber;
|
||||
break;
|
||||
case RTE_SUBQUERY:
|
||||
/* Subselect-in-FROM: copy up from the subselect */
|
||||
if (attnum != InvalidAttrNumber)
|
||||
|
|
@ -1584,6 +1588,7 @@ expandRecordVariable(ParseState *pstate, Var *var, int levelsup)
|
|||
case RTE_RELATION:
|
||||
case RTE_VALUES:
|
||||
case RTE_NAMEDTUPLESTORE:
|
||||
case RTE_GRAPH_TABLE:
|
||||
case RTE_RESULT:
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -348,6 +348,8 @@ less_equals "<="
|
|||
greater_equals ">="
|
||||
less_greater "<>"
|
||||
not_equals "!="
|
||||
/* Note there is no need for left_arrow, since "<-" is not a single operator. */
|
||||
right_arrow "->"
|
||||
|
||||
/*
|
||||
* "self" is the set of chars that should be returned as single-character
|
||||
|
|
@ -359,7 +361,7 @@ not_equals "!="
|
|||
* If you change either set, adjust the character lists appearing in the
|
||||
* rule for "operator"!
|
||||
*/
|
||||
self [,()\[\].;\:\+\-\*\/\%\^\<\>\=]
|
||||
self [,()\[\].;\:\|\+\-\*\/\%\^\<\>\=]
|
||||
op_chars [\~\!\@\#\^\&\|\`\?\+\-\*\/\%\<\>\=]
|
||||
operator {op_chars}+
|
||||
|
||||
|
|
@ -853,6 +855,11 @@ other .
|
|||
return NOT_EQUALS;
|
||||
}
|
||||
|
||||
{right_arrow} {
|
||||
SET_YYLLOC();
|
||||
return RIGHT_ARROW;
|
||||
}
|
||||
|
||||
{self} {
|
||||
SET_YYLLOC();
|
||||
return yytext[0];
|
||||
|
|
@ -930,7 +937,7 @@ other .
|
|||
* that the "self" rule would have.
|
||||
*/
|
||||
if (nchars == 1 &&
|
||||
strchr(",()[].;:+-*/%^<>=", yytext[0]))
|
||||
strchr(",()[].;:|+-*/%^<>=", yytext[0]))
|
||||
return yytext[0];
|
||||
/*
|
||||
* Likewise, if what we have left is two chars, and
|
||||
|
|
@ -950,6 +957,8 @@ other .
|
|||
return NOT_EQUALS;
|
||||
if (yytext[0] == '!' && yytext[1] == '=')
|
||||
return NOT_EQUALS;
|
||||
if (yytext[0] == '-' && yytext[1] == '>')
|
||||
return RIGHT_ARROW;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ include $(top_builddir)/src/Makefile.global
|
|||
|
||||
OBJS = \
|
||||
rewriteDefine.o \
|
||||
rewriteGraphTable.o \
|
||||
rewriteHandler.o \
|
||||
rewriteManip.o \
|
||||
rewriteRemove.o \
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
backend_sources += files(
|
||||
'rewriteDefine.c',
|
||||
'rewriteGraphTable.c',
|
||||
'rewriteHandler.c',
|
||||
'rewriteManip.c',
|
||||
'rewriteRemove.c',
|
||||
|
|
|
|||
1318
src/backend/rewrite/rewriteGraphTable.c
Normal file
1318
src/backend/rewrite/rewriteGraphTable.c
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -36,6 +36,7 @@
|
|||
#include "parser/parse_relation.h"
|
||||
#include "parser/parsetree.h"
|
||||
#include "rewrite/rewriteDefine.h"
|
||||
#include "rewrite/rewriteGraphTable.h"
|
||||
#include "rewrite/rewriteHandler.h"
|
||||
#include "rewrite/rewriteManip.h"
|
||||
#include "rewrite/rewriteSearchCycle.h"
|
||||
|
|
@ -173,6 +174,7 @@ AcquireRewriteLocks(Query *parsetree,
|
|||
switch (rte->rtekind)
|
||||
{
|
||||
case RTE_RELATION:
|
||||
case RTE_GRAPH_TABLE:
|
||||
|
||||
/*
|
||||
* Grab the appropriate lock type for the relation, and do not
|
||||
|
|
@ -2045,6 +2047,16 @@ fireRIRrules(Query *parsetree, List *activeRIRs)
|
|||
|
||||
rte = rt_fetch(rt_index, parsetree->rtable);
|
||||
|
||||
/*
|
||||
* Convert GRAPH_TABLE clause into a subquery using relational
|
||||
* operators. (This will change the rtekind to subquery, so it must
|
||||
* be done before the subquery handling below.)
|
||||
*/
|
||||
if (rte->rtekind == RTE_GRAPH_TABLE)
|
||||
{
|
||||
parsetree = rewriteGraphTable(parsetree, rt_index);
|
||||
}
|
||||
|
||||
/*
|
||||
* A subquery RTE can't have associated rules, so there's nothing to
|
||||
* do to this level of the query, but we must recurse into the
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@
|
|||
#include "commands/portalcmds.h"
|
||||
#include "commands/prepare.h"
|
||||
#include "commands/proclang.h"
|
||||
#include "commands/propgraphcmds.h"
|
||||
#include "commands/publicationcmds.h"
|
||||
#include "commands/schemacmds.h"
|
||||
#include "commands/seclabel.h"
|
||||
|
|
@ -149,6 +150,7 @@ ClassifyUtilityCommandAsReadOnly(Node *parsetree)
|
|||
case T_AlterOperatorStmt:
|
||||
case T_AlterOwnerStmt:
|
||||
case T_AlterPolicyStmt:
|
||||
case T_AlterPropGraphStmt:
|
||||
case T_AlterPublicationStmt:
|
||||
case T_AlterRoleSetStmt:
|
||||
case T_AlterRoleStmt:
|
||||
|
|
@ -179,6 +181,7 @@ ClassifyUtilityCommandAsReadOnly(Node *parsetree)
|
|||
case T_CreateOpFamilyStmt:
|
||||
case T_CreatePLangStmt:
|
||||
case T_CreatePolicyStmt:
|
||||
case T_CreatePropGraphStmt:
|
||||
case T_CreatePublicationStmt:
|
||||
case T_CreateRangeStmt:
|
||||
case T_CreateRoleStmt:
|
||||
|
|
@ -1739,6 +1742,14 @@ ProcessUtilitySlow(ParseState *pstate,
|
|||
commandCollected = true;
|
||||
break;
|
||||
|
||||
case T_CreatePropGraphStmt:
|
||||
address = CreatePropGraph(pstate, (CreatePropGraphStmt *) parsetree);
|
||||
break;
|
||||
|
||||
case T_AlterPropGraphStmt:
|
||||
address = AlterPropGraph(pstate, (AlterPropGraphStmt *) parsetree);
|
||||
break;
|
||||
|
||||
case T_CreateTransformStmt:
|
||||
address = CreateTransform((CreateTransformStmt *) parsetree);
|
||||
break;
|
||||
|
|
@ -2008,6 +2019,7 @@ ExecDropStmt(DropStmt *stmt, bool isTopLevel)
|
|||
case OBJECT_VIEW:
|
||||
case OBJECT_MATVIEW:
|
||||
case OBJECT_FOREIGN_TABLE:
|
||||
case OBJECT_PROPGRAPH:
|
||||
RemoveRelations(stmt);
|
||||
break;
|
||||
default:
|
||||
|
|
@ -2290,6 +2302,9 @@ AlterObjectTypeCommandTag(ObjectType objtype)
|
|||
case OBJECT_PROCEDURE:
|
||||
tag = CMDTAG_ALTER_PROCEDURE;
|
||||
break;
|
||||
case OBJECT_PROPGRAPH:
|
||||
tag = CMDTAG_ALTER_PROPERTY_GRAPH;
|
||||
break;
|
||||
case OBJECT_ROLE:
|
||||
tag = CMDTAG_ALTER_ROLE;
|
||||
break;
|
||||
|
|
@ -2566,6 +2581,9 @@ CreateCommandTag(Node *parsetree)
|
|||
case OBJECT_INDEX:
|
||||
tag = CMDTAG_DROP_INDEX;
|
||||
break;
|
||||
case OBJECT_PROPGRAPH:
|
||||
tag = CMDTAG_DROP_PROPERTY_GRAPH;
|
||||
break;
|
||||
case OBJECT_TYPE:
|
||||
tag = CMDTAG_DROP_TYPE;
|
||||
break;
|
||||
|
|
@ -2950,6 +2968,14 @@ CreateCommandTag(Node *parsetree)
|
|||
}
|
||||
break;
|
||||
|
||||
case T_CreatePropGraphStmt:
|
||||
tag = CMDTAG_CREATE_PROPERTY_GRAPH;
|
||||
break;
|
||||
|
||||
case T_AlterPropGraphStmt:
|
||||
tag = CMDTAG_ALTER_PROPERTY_GRAPH;
|
||||
break;
|
||||
|
||||
case T_CreateTransformStmt:
|
||||
tag = CMDTAG_CREATE_TRANSFORM;
|
||||
break;
|
||||
|
|
@ -3651,6 +3677,14 @@ GetCommandLogLevel(Node *parsetree)
|
|||
lev = LOGSTMT_DDL;
|
||||
break;
|
||||
|
||||
case T_CreatePropGraphStmt:
|
||||
lev = LOGSTMT_DDL;
|
||||
break;
|
||||
|
||||
case T_AlterPropGraphStmt:
|
||||
lev = LOGSTMT_DDL;
|
||||
break;
|
||||
|
||||
case T_CreateTransformStmt:
|
||||
lev = LOGSTMT_DDL;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -890,6 +890,10 @@ acldefault(ObjectType objtype, Oid ownerId)
|
|||
world_default = ACL_NO_RIGHTS;
|
||||
owner_default = ACL_ALL_RIGHTS_PARAMETER_ACL;
|
||||
break;
|
||||
case OBJECT_PROPGRAPH:
|
||||
world_default = ACL_NO_RIGHTS;
|
||||
owner_default = ACL_ALL_RIGHTS_PROPGRAPH;
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "unrecognized object type: %d", (int) objtype);
|
||||
world_default = ACL_NO_RIGHTS; /* keep compiler quiet */
|
||||
|
|
|
|||
|
|
@ -34,6 +34,11 @@
|
|||
#include "catalog/pg_operator.h"
|
||||
#include "catalog/pg_partitioned_table.h"
|
||||
#include "catalog/pg_proc.h"
|
||||
#include "catalog/pg_propgraph_element.h"
|
||||
#include "catalog/pg_propgraph_element_label.h"
|
||||
#include "catalog/pg_propgraph_label.h"
|
||||
#include "catalog/pg_propgraph_label_property.h"
|
||||
#include "catalog/pg_propgraph_property.h"
|
||||
#include "catalog/pg_statistic_ext.h"
|
||||
#include "catalog/pg_trigger.h"
|
||||
#include "catalog/pg_type.h"
|
||||
|
|
@ -361,6 +366,9 @@ static char *pg_get_indexdef_worker(Oid indexrelid, int colno,
|
|||
bool attrsOnly, bool keysOnly,
|
||||
bool showTblSpc, bool inherits,
|
||||
int prettyFlags, bool missing_ok);
|
||||
static void make_propgraphdef_elements(StringInfo buf, Oid pgrelid, char pgekind);
|
||||
static void make_propgraphdef_labels(StringInfo buf, Oid elid, const char *elalias, Oid elrelid);
|
||||
static void make_propgraphdef_properties(StringInfo buf, Oid ellabelid, Oid elrelid);
|
||||
static char *pg_get_statisticsobj_worker(Oid statextid, bool columns_only,
|
||||
bool missing_ok);
|
||||
static char *pg_get_partkeydef_worker(Oid relid, int prettyFlags,
|
||||
|
|
@ -1601,6 +1609,325 @@ pg_get_querydef(Query *query, bool pretty)
|
|||
return buf.data;
|
||||
}
|
||||
|
||||
/*
|
||||
* pg_get_propgraphdef - get the definition of a property graph
|
||||
*/
|
||||
Datum
|
||||
pg_get_propgraphdef(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Oid pgrelid = PG_GETARG_OID(0);
|
||||
StringInfoData buf;
|
||||
HeapTuple classtup;
|
||||
Form_pg_class classform;
|
||||
char *name;
|
||||
char *nsp;
|
||||
|
||||
initStringInfo(&buf);
|
||||
|
||||
classtup = SearchSysCache1(RELOID, ObjectIdGetDatum(pgrelid));
|
||||
if (!HeapTupleIsValid(classtup))
|
||||
PG_RETURN_NULL();
|
||||
|
||||
classform = (Form_pg_class) GETSTRUCT(classtup);
|
||||
name = NameStr(classform->relname);
|
||||
|
||||
if (classform->relkind != RELKIND_PROPGRAPH)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
||||
errmsg("\"%s\" is not a property graph", name)));
|
||||
|
||||
nsp = get_namespace_name(classform->relnamespace);
|
||||
|
||||
appendStringInfo(&buf, "CREATE PROPERTY GRAPH %s",
|
||||
quote_qualified_identifier(nsp, name));
|
||||
|
||||
ReleaseSysCache(classtup);
|
||||
|
||||
make_propgraphdef_elements(&buf, pgrelid, PGEKIND_VERTEX);
|
||||
make_propgraphdef_elements(&buf, pgrelid, PGEKIND_EDGE);
|
||||
|
||||
PG_RETURN_TEXT_P(string_to_text(buf.data));
|
||||
}
|
||||
|
||||
/*
|
||||
* Generates a VERTEX TABLES (...) or EDGE TABLES (...) clause. Pass in the
|
||||
* property graph relation OID and the element kind (vertex or edge). Result
|
||||
* is appended to buf.
|
||||
*/
|
||||
static void
|
||||
make_propgraphdef_elements(StringInfo buf, Oid pgrelid, char pgekind)
|
||||
{
|
||||
Relation pgerel;
|
||||
ScanKeyData scankey[1];
|
||||
SysScanDesc scan;
|
||||
bool first;
|
||||
HeapTuple tup;
|
||||
|
||||
pgerel = table_open(PropgraphElementRelationId, AccessShareLock);
|
||||
|
||||
ScanKeyInit(&scankey[0],
|
||||
Anum_pg_propgraph_element_pgepgid,
|
||||
BTEqualStrategyNumber, F_OIDEQ,
|
||||
ObjectIdGetDatum(pgrelid));
|
||||
|
||||
scan = systable_beginscan(pgerel, PropgraphElementAliasIndexId, true, NULL, 1, scankey);
|
||||
|
||||
first = true;
|
||||
while ((tup = systable_getnext(scan)))
|
||||
{
|
||||
Form_pg_propgraph_element pgeform = (Form_pg_propgraph_element) GETSTRUCT(tup);
|
||||
char *relname;
|
||||
Datum datum;
|
||||
bool isnull;
|
||||
|
||||
if (pgeform->pgekind != pgekind)
|
||||
continue;
|
||||
|
||||
if (first)
|
||||
{
|
||||
appendStringInfo(buf, "\n %s TABLES (\n", pgekind == PGEKIND_VERTEX ? "VERTEX" : "EDGE");
|
||||
first = false;
|
||||
}
|
||||
else
|
||||
appendStringInfo(buf, ",\n");
|
||||
|
||||
relname = get_rel_name(pgeform->pgerelid);
|
||||
if (relname && strcmp(relname, NameStr(pgeform->pgealias)) == 0)
|
||||
appendStringInfo(buf, " %s",
|
||||
generate_relation_name(pgeform->pgerelid, NIL));
|
||||
else
|
||||
appendStringInfo(buf, " %s AS %s",
|
||||
generate_relation_name(pgeform->pgerelid, NIL),
|
||||
quote_identifier(NameStr(pgeform->pgealias)));
|
||||
|
||||
datum = heap_getattr(tup, Anum_pg_propgraph_element_pgekey, RelationGetDescr(pgerel), &isnull);
|
||||
if (!isnull)
|
||||
{
|
||||
appendStringInfoString(buf, " KEY (");
|
||||
decompile_column_index_array(datum, pgeform->pgerelid, false, buf);
|
||||
appendStringInfoString(buf, ")");
|
||||
}
|
||||
else
|
||||
elog(ERROR, "null pgekey for element %u", pgeform->oid);
|
||||
|
||||
if (pgekind == PGEKIND_EDGE)
|
||||
{
|
||||
Datum srckey;
|
||||
Datum srcref;
|
||||
Datum destkey;
|
||||
Datum destref;
|
||||
HeapTuple tup2;
|
||||
Form_pg_propgraph_element pgeform2;
|
||||
|
||||
datum = heap_getattr(tup, Anum_pg_propgraph_element_pgesrckey, RelationGetDescr(pgerel), &isnull);
|
||||
srckey = isnull ? 0 : datum;
|
||||
datum = heap_getattr(tup, Anum_pg_propgraph_element_pgesrcref, RelationGetDescr(pgerel), &isnull);
|
||||
srcref = isnull ? 0 : datum;
|
||||
datum = heap_getattr(tup, Anum_pg_propgraph_element_pgedestkey, RelationGetDescr(pgerel), &isnull);
|
||||
destkey = isnull ? 0 : datum;
|
||||
datum = heap_getattr(tup, Anum_pg_propgraph_element_pgedestref, RelationGetDescr(pgerel), &isnull);
|
||||
destref = isnull ? 0 : datum;
|
||||
|
||||
appendStringInfoString(buf, " SOURCE");
|
||||
tup2 = SearchSysCache1(PROPGRAPHELOID, ObjectIdGetDatum(pgeform->pgesrcvertexid));
|
||||
if (!tup2)
|
||||
elog(ERROR, "cache lookup failed for property graph element %u", pgeform->pgesrcvertexid);
|
||||
pgeform2 = (Form_pg_propgraph_element) GETSTRUCT(tup2);
|
||||
if (srckey)
|
||||
{
|
||||
appendStringInfoString(buf, " KEY (");
|
||||
decompile_column_index_array(srckey, pgeform->pgerelid, false, buf);
|
||||
appendStringInfo(buf, ") REFERENCES %s (", quote_identifier(NameStr(pgeform2->pgealias)));
|
||||
decompile_column_index_array(srcref, pgeform2->pgerelid, false, buf);
|
||||
appendStringInfoString(buf, ")");
|
||||
}
|
||||
else
|
||||
appendStringInfo(buf, " %s ", quote_identifier(NameStr(pgeform2->pgealias)));
|
||||
ReleaseSysCache(tup2);
|
||||
|
||||
appendStringInfoString(buf, " DESTINATION");
|
||||
tup2 = SearchSysCache1(PROPGRAPHELOID, ObjectIdGetDatum(pgeform->pgedestvertexid));
|
||||
if (!tup2)
|
||||
elog(ERROR, "cache lookup failed for property graph element %u", pgeform->pgedestvertexid);
|
||||
pgeform2 = (Form_pg_propgraph_element) GETSTRUCT(tup2);
|
||||
if (destkey)
|
||||
{
|
||||
appendStringInfoString(buf, " KEY (");
|
||||
decompile_column_index_array(destkey, pgeform->pgerelid, false, buf);
|
||||
appendStringInfo(buf, ") REFERENCES %s (", quote_identifier(NameStr(pgeform2->pgealias)));
|
||||
decompile_column_index_array(destref, pgeform2->pgerelid, false, buf);
|
||||
appendStringInfoString(buf, ")");
|
||||
}
|
||||
else
|
||||
appendStringInfo(buf, " %s", quote_identifier(NameStr(pgeform2->pgealias)));
|
||||
ReleaseSysCache(tup2);
|
||||
}
|
||||
|
||||
make_propgraphdef_labels(buf, pgeform->oid, NameStr(pgeform->pgealias), pgeform->pgerelid);
|
||||
}
|
||||
if (!first)
|
||||
appendStringInfo(buf, "\n )");
|
||||
|
||||
systable_endscan(scan);
|
||||
table_close(pgerel, AccessShareLock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Generates label and properties list. Pass in the element OID, the element
|
||||
* alias, and the graph relation OID. Result is appended to buf.
|
||||
*/
|
||||
static void
|
||||
make_propgraphdef_labels(StringInfo buf, Oid elid, const char *elalias, Oid elrelid)
|
||||
{
|
||||
Relation pglrel;
|
||||
ScanKeyData scankey[1];
|
||||
SysScanDesc scan;
|
||||
int count;
|
||||
HeapTuple tup;
|
||||
|
||||
pglrel = table_open(PropgraphElementLabelRelationId, AccessShareLock);
|
||||
|
||||
ScanKeyInit(&scankey[0],
|
||||
Anum_pg_propgraph_element_label_pgelelid,
|
||||
BTEqualStrategyNumber, F_OIDEQ,
|
||||
ObjectIdGetDatum(elid));
|
||||
|
||||
count = 0;
|
||||
scan = systable_beginscan(pglrel, PropgraphElementLabelElementLabelIndexId, true, NULL, 1, scankey);
|
||||
while ((tup = systable_getnext(scan)))
|
||||
{
|
||||
count++;
|
||||
}
|
||||
systable_endscan(scan);
|
||||
|
||||
scan = systable_beginscan(pglrel, PropgraphElementLabelElementLabelIndexId, true, NULL, 1, scankey);
|
||||
|
||||
while ((tup = systable_getnext(scan)))
|
||||
{
|
||||
Form_pg_propgraph_element_label pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
|
||||
const char *labelname;
|
||||
|
||||
labelname = get_propgraph_label_name(pgelform->pgellabelid);
|
||||
|
||||
if (strcmp(labelname, elalias) == 0)
|
||||
{
|
||||
/* If the default label is the only label, don't print anything. */
|
||||
if (count != 1)
|
||||
appendStringInfo(buf, " DEFAULT LABEL");
|
||||
}
|
||||
else
|
||||
appendStringInfo(buf, " LABEL %s", quote_identifier(labelname));
|
||||
|
||||
make_propgraphdef_properties(buf, pgelform->oid, elrelid);
|
||||
}
|
||||
|
||||
systable_endscan(scan);
|
||||
|
||||
table_close(pglrel, AccessShareLock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper function for make_propgraphdef_properties(): Sort (propname, expr)
|
||||
* pairs by name.
|
||||
*/
|
||||
static int
|
||||
propdata_by_name_cmp(const ListCell *a, const ListCell *b)
|
||||
{
|
||||
List *la = lfirst_node(List, a);
|
||||
List *lb = lfirst_node(List, b);
|
||||
char *pna = strVal(linitial(la));
|
||||
char *pnb = strVal(linitial(lb));
|
||||
|
||||
return strcmp(pna, pnb);
|
||||
}
|
||||
|
||||
/*
|
||||
* Generates element table properties clause (PROPERTIES (...) or NO
|
||||
* PROPERTIES). Pass in label OID and element table OID. Result is appended
|
||||
* to buf.
|
||||
*/
|
||||
static void
|
||||
make_propgraphdef_properties(StringInfo buf, Oid ellabelid, Oid elrelid)
|
||||
{
|
||||
Relation plprel;
|
||||
ScanKeyData scankey[1];
|
||||
SysScanDesc scan;
|
||||
HeapTuple tup;
|
||||
List *outlist = NIL;
|
||||
|
||||
plprel = table_open(PropgraphLabelPropertyRelationId, AccessShareLock);
|
||||
|
||||
ScanKeyInit(&scankey[0],
|
||||
Anum_pg_propgraph_label_property_plpellabelid,
|
||||
BTEqualStrategyNumber, F_OIDEQ,
|
||||
ObjectIdGetDatum(ellabelid));
|
||||
|
||||
/*
|
||||
* We want to output the properties in a deterministic order. So we first
|
||||
* read all the data, then sort, then print it.
|
||||
*/
|
||||
scan = systable_beginscan(plprel, PropgraphLabelPropertyLabelPropIndexId, true, NULL, 1, scankey);
|
||||
|
||||
while ((tup = systable_getnext(scan)))
|
||||
{
|
||||
Form_pg_propgraph_label_property plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
|
||||
Datum exprDatum;
|
||||
bool isnull;
|
||||
char *tmp;
|
||||
Node *expr;
|
||||
char *propname;
|
||||
|
||||
exprDatum = heap_getattr(tup, Anum_pg_propgraph_label_property_plpexpr, RelationGetDescr(plprel), &isnull);
|
||||
Assert(!isnull);
|
||||
tmp = TextDatumGetCString(exprDatum);
|
||||
expr = stringToNode(tmp);
|
||||
pfree(tmp);
|
||||
|
||||
propname = get_propgraph_property_name(plpform->plppropid);
|
||||
|
||||
outlist = lappend(outlist, list_make2(makeString(propname), expr));
|
||||
}
|
||||
|
||||
systable_endscan(scan);
|
||||
table_close(plprel, AccessShareLock);
|
||||
|
||||
list_sort(outlist, propdata_by_name_cmp);
|
||||
|
||||
if (outlist)
|
||||
{
|
||||
List *context;
|
||||
ListCell *lc;
|
||||
bool first = true;
|
||||
|
||||
context = deparse_context_for(get_relation_name(elrelid), elrelid);
|
||||
|
||||
appendStringInfo(buf, " PROPERTIES (");
|
||||
|
||||
foreach(lc, outlist)
|
||||
{
|
||||
List *data = lfirst_node(List, lc);
|
||||
char *propname = strVal(linitial(data));
|
||||
Node *expr = lsecond(data);
|
||||
|
||||
if (first)
|
||||
first = false;
|
||||
else
|
||||
appendStringInfo(buf, ", ");
|
||||
|
||||
if (IsA(expr, Var) && strcmp(propname, get_attname(elrelid, castNode(Var, expr)->varattno, false)) == 0)
|
||||
appendStringInfo(buf, "%s", quote_identifier(propname));
|
||||
else
|
||||
appendStringInfo(buf, "%s AS %s",
|
||||
deparse_expression_pretty(expr, context, false, false, 0, 0),
|
||||
quote_identifier(propname));
|
||||
}
|
||||
|
||||
appendStringInfo(buf, ")");
|
||||
}
|
||||
else
|
||||
appendStringInfo(buf, " NO PROPERTIES");
|
||||
}
|
||||
|
||||
/*
|
||||
* pg_get_statisticsobjdef
|
||||
* Get the definition of an extended statistics object
|
||||
|
|
@ -7610,6 +7937,171 @@ get_utility_query_def(Query *query, deparse_context *context)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Parse back a graph label expression
|
||||
*/
|
||||
static void
|
||||
get_graph_label_expr(Node *label_expr, deparse_context *context)
|
||||
{
|
||||
StringInfo buf = context->buf;
|
||||
|
||||
check_stack_depth();
|
||||
|
||||
switch (nodeTag(label_expr))
|
||||
{
|
||||
case T_GraphLabelRef:
|
||||
{
|
||||
GraphLabelRef *lref = (GraphLabelRef *) label_expr;
|
||||
|
||||
appendStringInfoString(buf, quote_identifier(get_propgraph_label_name(lref->labelid)));
|
||||
break;
|
||||
}
|
||||
|
||||
case T_BoolExpr:
|
||||
{
|
||||
BoolExpr *be = (BoolExpr *) label_expr;
|
||||
ListCell *lc;
|
||||
bool first = true;
|
||||
|
||||
Assert(be->boolop == OR_EXPR);
|
||||
|
||||
foreach(lc, be->args)
|
||||
{
|
||||
if (!first)
|
||||
{
|
||||
if (be->boolop == OR_EXPR)
|
||||
appendStringInfoString(buf, "|");
|
||||
}
|
||||
else
|
||||
first = false;
|
||||
get_graph_label_expr(lfirst(lc), context);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(label_expr));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse back a path pattern expression
|
||||
*/
|
||||
static void
|
||||
get_path_pattern_expr_def(List *path_pattern_expr, deparse_context *context)
|
||||
{
|
||||
StringInfo buf = context->buf;
|
||||
ListCell *lc;
|
||||
|
||||
foreach(lc, path_pattern_expr)
|
||||
{
|
||||
GraphElementPattern *gep = lfirst_node(GraphElementPattern, lc);
|
||||
const char *sep = "";
|
||||
|
||||
switch (gep->kind)
|
||||
{
|
||||
case VERTEX_PATTERN:
|
||||
appendStringInfoString(buf, "(");
|
||||
break;
|
||||
case EDGE_PATTERN_LEFT:
|
||||
appendStringInfoString(buf, "<-[");
|
||||
break;
|
||||
case EDGE_PATTERN_RIGHT:
|
||||
case EDGE_PATTERN_ANY:
|
||||
appendStringInfoString(buf, "-[");
|
||||
break;
|
||||
case PAREN_EXPR:
|
||||
appendStringInfoString(buf, "(");
|
||||
break;
|
||||
}
|
||||
|
||||
if (gep->variable)
|
||||
{
|
||||
appendStringInfoString(buf, quote_identifier(gep->variable));
|
||||
sep = " ";
|
||||
}
|
||||
|
||||
if (gep->labelexpr)
|
||||
{
|
||||
appendStringInfoString(buf, sep);
|
||||
appendStringInfoString(buf, "IS ");
|
||||
get_graph_label_expr(gep->labelexpr, context);
|
||||
sep = " ";
|
||||
}
|
||||
|
||||
if (gep->subexpr)
|
||||
{
|
||||
appendStringInfoString(buf, sep);
|
||||
get_path_pattern_expr_def(gep->subexpr, context);
|
||||
sep = " ";
|
||||
}
|
||||
|
||||
if (gep->whereClause)
|
||||
{
|
||||
appendStringInfoString(buf, sep);
|
||||
appendStringInfoString(buf, "WHERE ");
|
||||
get_rule_expr(gep->whereClause, context, false);
|
||||
}
|
||||
|
||||
switch (gep->kind)
|
||||
{
|
||||
case VERTEX_PATTERN:
|
||||
appendStringInfoString(buf, ")");
|
||||
break;
|
||||
case EDGE_PATTERN_LEFT:
|
||||
case EDGE_PATTERN_ANY:
|
||||
appendStringInfoString(buf, "]-");
|
||||
break;
|
||||
case EDGE_PATTERN_RIGHT:
|
||||
appendStringInfoString(buf, "]->");
|
||||
break;
|
||||
case PAREN_EXPR:
|
||||
appendStringInfoString(buf, ")");
|
||||
break;
|
||||
}
|
||||
|
||||
if (gep->quantifier)
|
||||
{
|
||||
int lower = linitial_int(gep->quantifier);
|
||||
int upper = lsecond_int(gep->quantifier);
|
||||
|
||||
appendStringInfo(buf, "{%d,%d}", lower, upper);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse back a graph pattern
|
||||
*/
|
||||
static void
|
||||
get_graph_pattern_def(GraphPattern *graph_pattern, deparse_context *context)
|
||||
{
|
||||
StringInfo buf = context->buf;
|
||||
ListCell *lc;
|
||||
bool first = true;
|
||||
|
||||
foreach(lc, graph_pattern->path_pattern_list)
|
||||
{
|
||||
List *path_pattern_expr = lfirst_node(List, lc);
|
||||
|
||||
if (!first)
|
||||
appendStringInfoString(buf, ", ");
|
||||
else
|
||||
first = false;
|
||||
|
||||
get_path_pattern_expr_def(path_pattern_expr, context);
|
||||
}
|
||||
|
||||
if (graph_pattern->whereClause)
|
||||
{
|
||||
appendStringInfoString(buf, "WHERE ");
|
||||
get_rule_expr(graph_pattern->whereClause, context, false);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Display a Var appropriately.
|
||||
*
|
||||
|
|
@ -8220,6 +8712,7 @@ get_name_for_var_field(Var *var, int fieldno,
|
|||
case RTE_RELATION:
|
||||
case RTE_VALUES:
|
||||
case RTE_NAMEDTUPLESTORE:
|
||||
case RTE_GRAPH_TABLE:
|
||||
case RTE_RESULT:
|
||||
|
||||
/*
|
||||
|
|
@ -10664,6 +11157,14 @@ get_rule_expr(Node *node, deparse_context *context,
|
|||
get_tablefunc((TableFunc *) node, context, showimplicit);
|
||||
break;
|
||||
|
||||
case T_GraphPropertyRef:
|
||||
{
|
||||
GraphPropertyRef *gpr = (GraphPropertyRef *) node;
|
||||
|
||||
appendStringInfo(buf, "%s.%s", quote_identifier(gpr->elvarname), quote_identifier(get_propgraph_property_name(gpr->propid)));
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
|
||||
break;
|
||||
|
|
@ -12546,6 +13047,36 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
|
|||
case RTE_TABLEFUNC:
|
||||
get_tablefunc(rte->tablefunc, context, true);
|
||||
break;
|
||||
case RTE_GRAPH_TABLE:
|
||||
appendStringInfoString(buf, "GRAPH_TABLE (");
|
||||
appendStringInfoString(buf, generate_relation_name(rte->relid, context->namespaces));
|
||||
appendStringInfoString(buf, " MATCH ");
|
||||
get_graph_pattern_def(rte->graph_pattern, context);
|
||||
appendStringInfoString(buf, " COLUMNS (");
|
||||
{
|
||||
ListCell *lc;
|
||||
bool first = true;
|
||||
|
||||
foreach(lc, rte->graph_table_columns)
|
||||
{
|
||||
TargetEntry *te = lfirst_node(TargetEntry, lc);
|
||||
deparse_context context = {0};
|
||||
|
||||
if (!first)
|
||||
appendStringInfoString(buf, ", ");
|
||||
else
|
||||
first = false;
|
||||
|
||||
context.buf = buf;
|
||||
|
||||
get_rule_expr((Node *) te->expr, &context, false);
|
||||
appendStringInfoString(buf, " AS ");
|
||||
appendStringInfoString(buf, quote_identifier(te->resname));
|
||||
}
|
||||
}
|
||||
appendStringInfoString(buf, ")");
|
||||
appendStringInfoString(buf, ")");
|
||||
break;
|
||||
case RTE_VALUES:
|
||||
/* Values list RTE */
|
||||
appendStringInfoChar(buf, '(');
|
||||
|
|
|
|||
38
src/backend/utils/cache/lsyscache.c
vendored
38
src/backend/utils/cache/lsyscache.c
vendored
|
|
@ -34,6 +34,8 @@
|
|||
#include "catalog/pg_opfamily.h"
|
||||
#include "catalog/pg_operator.h"
|
||||
#include "catalog/pg_proc.h"
|
||||
#include "catalog/pg_propgraph_label.h"
|
||||
#include "catalog/pg_propgraph_property.h"
|
||||
#include "catalog/pg_publication.h"
|
||||
#include "catalog/pg_range.h"
|
||||
#include "catalog/pg_statistic.h"
|
||||
|
|
@ -3934,3 +3936,39 @@ get_subscription_name(Oid subid, bool missing_ok)
|
|||
|
||||
return subname;
|
||||
}
|
||||
|
||||
char *
|
||||
get_propgraph_label_name(Oid labeloid)
|
||||
{
|
||||
HeapTuple tuple;
|
||||
char *labelname;
|
||||
|
||||
tuple = SearchSysCache1(PROPGRAPHLABELOID, labeloid);
|
||||
if (!tuple)
|
||||
{
|
||||
elog(ERROR, "cache lookup failed for label %u", labeloid);
|
||||
return NULL;
|
||||
}
|
||||
labelname = pstrdup(NameStr(((Form_pg_propgraph_label) GETSTRUCT(tuple))->pgllabel));
|
||||
ReleaseSysCache(tuple);
|
||||
|
||||
return labelname;
|
||||
}
|
||||
|
||||
char *
|
||||
get_propgraph_property_name(Oid propoid)
|
||||
{
|
||||
HeapTuple tuple;
|
||||
char *propname;
|
||||
|
||||
tuple = SearchSysCache1(PROPGRAPHPROPOID, propoid);
|
||||
if (!tuple)
|
||||
{
|
||||
elog(ERROR, "cache lookup failed for property %u", propoid);
|
||||
return NULL;
|
||||
}
|
||||
propname = pstrdup(NameStr(((Form_pg_propgraph_property) GETSTRUCT(tuple))->pgpname));
|
||||
ReleaseSysCache(tuple);
|
||||
|
||||
return propname;
|
||||
}
|
||||
|
|
|
|||
6
src/backend/utils/cache/plancache.c
vendored
6
src/backend/utils/cache/plancache.c
vendored
|
|
@ -2014,7 +2014,11 @@ ScanQueryForLocks(Query *parsetree, bool acquire)
|
|||
break;
|
||||
|
||||
case RTE_SUBQUERY:
|
||||
/* If this was a view, must lock/unlock the view */
|
||||
|
||||
/*
|
||||
* If this was a view or a property graph, must lock/unlock
|
||||
* it.
|
||||
*/
|
||||
if (OidIsValid(rte->relid))
|
||||
{
|
||||
if (acquire)
|
||||
|
|
|
|||
|
|
@ -497,7 +497,8 @@ flagInhAttrs(Archive *fout, DumpOptions *dopt, TableInfo *tblinfo, int numTables
|
|||
/* Some kinds never have parents */
|
||||
if (tbinfo->relkind == RELKIND_SEQUENCE ||
|
||||
tbinfo->relkind == RELKIND_VIEW ||
|
||||
tbinfo->relkind == RELKIND_MATVIEW)
|
||||
tbinfo->relkind == RELKIND_MATVIEW ||
|
||||
tbinfo->relkind == RELKIND_PROPGRAPH)
|
||||
continue;
|
||||
|
||||
/* Don't bother computing anything for non-target tables, either */
|
||||
|
|
|
|||
|
|
@ -510,6 +510,9 @@ do { \
|
|||
/* UPDATE */
|
||||
CONVERT_PRIV('w', "UPDATE");
|
||||
}
|
||||
else if (strcmp(type, "PROPERTY GRAPH") == 0 ||
|
||||
strcmp(type, "PROPERTY GRAPHS") == 0)
|
||||
CONVERT_PRIV('r', "SELECT");
|
||||
else if (strcmp(type, "FUNCTION") == 0 ||
|
||||
strcmp(type, "FUNCTIONS") == 0)
|
||||
CONVERT_PRIV('X', "EXECUTE");
|
||||
|
|
|
|||
|
|
@ -3853,6 +3853,7 @@ _getObjectDescription(PQExpBuffer buf, const TocEntry *te)
|
|||
strcmp(type, "DOMAIN") == 0 ||
|
||||
strcmp(type, "FOREIGN TABLE") == 0 ||
|
||||
strcmp(type, "MATERIALIZED VIEW") == 0 ||
|
||||
strcmp(type, "PROPERTY GRAPH") == 0 ||
|
||||
strcmp(type, "SEQUENCE") == 0 ||
|
||||
strcmp(type, "STATISTICS") == 0 ||
|
||||
strcmp(type, "TABLE") == 0 ||
|
||||
|
|
|
|||
|
|
@ -1851,10 +1851,10 @@ expand_table_name_patterns(Archive *fout,
|
|||
"\n LEFT JOIN pg_catalog.pg_namespace n"
|
||||
"\n ON n.oid OPERATOR(pg_catalog.=) c.relnamespace"
|
||||
"\nWHERE c.relkind OPERATOR(pg_catalog.=) ANY"
|
||||
"\n (array['%c', '%c', '%c', '%c', '%c', '%c'])\n",
|
||||
"\n (array['%c', '%c', '%c', '%c', '%c', '%c', '%c'])\n",
|
||||
RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW,
|
||||
RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE,
|
||||
RELKIND_PARTITIONED_TABLE);
|
||||
RELKIND_PARTITIONED_TABLE, RELKIND_PROPGRAPH);
|
||||
initPQExpBuffer(&dbbuf);
|
||||
processSQLNamePattern(GetConnection(fout), query, cell->val, true,
|
||||
false, "n.nspname", "c.relname", NULL,
|
||||
|
|
@ -3034,6 +3034,9 @@ makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo)
|
|||
if (tbinfo->dataObj != NULL)
|
||||
return;
|
||||
|
||||
/* Skip property graphs (no data to dump) */
|
||||
if (tbinfo->relkind == RELKIND_PROPGRAPH)
|
||||
return;
|
||||
/* Skip VIEWs (no data to dump) */
|
||||
if (tbinfo->relkind == RELKIND_VIEW)
|
||||
return;
|
||||
|
|
@ -7484,7 +7487,8 @@ getTables(Archive *fout, int *numTables)
|
|||
CppAsString2(RELKIND_COMPOSITE_TYPE) ", "
|
||||
CppAsString2(RELKIND_MATVIEW) ", "
|
||||
CppAsString2(RELKIND_FOREIGN_TABLE) ", "
|
||||
CppAsString2(RELKIND_PARTITIONED_TABLE) ")\n"
|
||||
CppAsString2(RELKIND_PARTITIONED_TABLE) ", "
|
||||
CppAsString2(RELKIND_PROPGRAPH) ")\n"
|
||||
"ORDER BY c.oid");
|
||||
|
||||
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
|
||||
|
|
@ -16987,8 +16991,20 @@ dumpTable(Archive *fout, const TableInfo *tbinfo)
|
|||
namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
|
||||
if (tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
|
||||
{
|
||||
const char *objtype =
|
||||
(tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" : "TABLE";
|
||||
const char *objtype;
|
||||
|
||||
switch (tbinfo->relkind)
|
||||
{
|
||||
case RELKIND_SEQUENCE:
|
||||
objtype = "SEQUENCE";
|
||||
break;
|
||||
case RELKIND_PROPGRAPH:
|
||||
objtype = "PROPERTY GRAPH";
|
||||
break;
|
||||
default:
|
||||
objtype = "TABLE";
|
||||
break;
|
||||
}
|
||||
|
||||
tableAclDumpId =
|
||||
dumpACL(fout, tbinfo->dobj.dumpId, InvalidDumpId,
|
||||
|
|
@ -17234,8 +17250,6 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
|
|||
|
||||
reltypename = "VIEW";
|
||||
|
||||
appendPQExpBuffer(delq, "DROP VIEW %s;\n", qualrelname);
|
||||
|
||||
if (dopt->binary_upgrade)
|
||||
binary_upgrade_set_pg_class_oids(fout, q,
|
||||
tbinfo->dobj.catId.oid);
|
||||
|
|
@ -17261,6 +17275,47 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
|
|||
appendPQExpBuffer(q, "\n WITH %s CHECK OPTION", tbinfo->checkoption);
|
||||
appendPQExpBufferStr(q, ";\n");
|
||||
}
|
||||
else if (tbinfo->relkind == RELKIND_PROPGRAPH)
|
||||
{
|
||||
PQExpBuffer query = createPQExpBuffer();
|
||||
PGresult *res;
|
||||
int len;
|
||||
|
||||
reltypename = "PROPERTY GRAPH";
|
||||
|
||||
if (dopt->binary_upgrade)
|
||||
binary_upgrade_set_pg_class_oids(fout, q,
|
||||
tbinfo->dobj.catId.oid);
|
||||
|
||||
appendPQExpBuffer(query,
|
||||
"SELECT pg_catalog.pg_get_propgraphdef('%u'::pg_catalog.oid) AS pgdef",
|
||||
tbinfo->dobj.catId.oid);
|
||||
|
||||
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
|
||||
|
||||
if (PQntuples(res) != 1)
|
||||
{
|
||||
if (PQntuples(res) < 1)
|
||||
pg_fatal("query to obtain definition of property graph \"%s\" returned no data",
|
||||
tbinfo->dobj.name);
|
||||
else
|
||||
pg_fatal("query to obtain definition of property graph \"%s\" returned more than one definition",
|
||||
tbinfo->dobj.name);
|
||||
}
|
||||
|
||||
len = PQgetlength(res, 0, 0);
|
||||
|
||||
if (len == 0)
|
||||
pg_fatal("definition of property graph \"%s\" appears to be empty (length zero)",
|
||||
tbinfo->dobj.name);
|
||||
|
||||
appendPQExpBufferStr(q, PQgetvalue(res, 0, 0));
|
||||
|
||||
PQclear(res);
|
||||
destroyPQExpBuffer(query);
|
||||
|
||||
appendPQExpBufferStr(q, ";\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
char *partkeydef = NULL;
|
||||
|
|
@ -17336,8 +17391,6 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
|
|||
numParents = tbinfo->numParents;
|
||||
parents = tbinfo->parents;
|
||||
|
||||
appendPQExpBuffer(delq, "DROP %s %s;\n", reltypename, qualrelname);
|
||||
|
||||
if (dopt->binary_upgrade)
|
||||
binary_upgrade_set_pg_class_oids(fout, q,
|
||||
tbinfo->dobj.catId.oid);
|
||||
|
|
@ -18081,6 +18134,8 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
|
|||
appendPQExpBuffer(q, "\nALTER TABLE ONLY %s FORCE ROW LEVEL SECURITY;\n",
|
||||
qualrelname);
|
||||
|
||||
appendPQExpBuffer(delq, "DROP %s %s;\n", reltypename, qualrelname);
|
||||
|
||||
if (dopt->binary_upgrade)
|
||||
binary_upgrade_extension_member(q, &tbinfo->dobj,
|
||||
reltypename, qrelname,
|
||||
|
|
@ -20414,6 +20469,16 @@ getDependencies(Archive *fout)
|
|||
"classid = 'pg_amproc'::regclass AND objid = p.oid "
|
||||
"AND NOT (refclassid = 'pg_opfamily'::regclass AND amprocfamily = refobjid)\n");
|
||||
|
||||
/*
|
||||
* Translate dependencies of pg_propgraph_element entries into
|
||||
* dependencies of their parent pg_class entry.
|
||||
*/
|
||||
appendPQExpBufferStr(query, "UNION ALL\n"
|
||||
"SELECT 'pg_class'::regclass AS classid, pgepgid AS objid, refclassid, refobjid, deptype "
|
||||
"FROM pg_depend d, pg_propgraph_element pge "
|
||||
"WHERE deptype NOT IN ('p', 'e', 'i') AND "
|
||||
"classid = 'pg_propgraph_element'::regclass AND objid = pge.oid\n");
|
||||
|
||||
/* Sort the output for efficiency below */
|
||||
appendPQExpBufferStr(query, "ORDER BY 1,2");
|
||||
|
||||
|
|
|
|||
|
|
@ -3131,6 +3131,18 @@ my %tests = (
|
|||
},
|
||||
},
|
||||
|
||||
'CREATE PROPERTY GRAPH propgraph' => {
|
||||
create_order => 20,
|
||||
create_sql => 'CREATE PROPERTY GRAPH dump_test.propgraph;',
|
||||
regexp => qr/^
|
||||
\QCREATE PROPERTY GRAPH dump_test.propgraph\E;
|
||||
/xm,
|
||||
like =>
|
||||
{ %full_runs, %dump_test_schema_runs, section_pre_data => 1, },
|
||||
unlike =>
|
||||
{ exclude_dump_test_schema => 1, only_dump_measurement => 1, },
|
||||
},
|
||||
|
||||
'CREATE PUBLICATION pub1' => {
|
||||
create_order => 50,
|
||||
create_sql => 'CREATE PUBLICATION pub1;',
|
||||
|
|
@ -4508,6 +4520,22 @@ my %tests = (
|
|||
},
|
||||
},
|
||||
|
||||
'GRANT SELECT ON PROPERTY GRAPH propgraph' => {
|
||||
create_order => 21,
|
||||
create_sql =>
|
||||
'GRANT SELECT ON PROPERTY GRAPH dump_test.propgraph TO regress_dump_test_role;',
|
||||
regexp => qr/^
|
||||
\QGRANT ALL ON PROPERTY GRAPH dump_test.propgraph TO regress_dump_test_role;\E
|
||||
/xm,
|
||||
like =>
|
||||
{ %full_runs, %dump_test_schema_runs, section_pre_data => 1, },
|
||||
unlike => {
|
||||
exclude_dump_test_schema => 1,
|
||||
no_privs => 1,
|
||||
only_dump_measurement => 1,
|
||||
},
|
||||
},
|
||||
|
||||
'GRANT EXECUTE ON FUNCTION pg_sleep() TO regress_dump_test_role' => {
|
||||
create_order => 16,
|
||||
create_sql => 'GRANT EXECUTE ON FUNCTION pg_sleep(float8)
|
||||
|
|
|
|||
|
|
@ -1056,7 +1056,7 @@ exec_command_d(PsqlScanState scan_state, bool active_branch, const char *cmd)
|
|||
success = describeTableDetails(pattern, show_verbose, show_system);
|
||||
else
|
||||
/* standard listing of interesting things */
|
||||
success = listTables("tvmsE", NULL, show_verbose, show_system);
|
||||
success = listTables("tvmsEG", NULL, show_verbose, show_system);
|
||||
break;
|
||||
case 'A':
|
||||
{
|
||||
|
|
@ -1190,6 +1190,7 @@ exec_command_d(PsqlScanState scan_state, bool active_branch, const char *cmd)
|
|||
case 'i':
|
||||
case 's':
|
||||
case 'E':
|
||||
case 'G':
|
||||
success = listTables(&cmd[1], pattern, show_verbose, show_system);
|
||||
break;
|
||||
case 'r':
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include "catalog/pg_constraint_d.h"
|
||||
#include "catalog/pg_default_acl_d.h"
|
||||
#include "catalog/pg_proc_d.h"
|
||||
#include "catalog/pg_propgraph_element_d.h"
|
||||
#include "catalog/pg_publication_d.h"
|
||||
#include "catalog/pg_statistic_ext_d.h"
|
||||
#include "catalog/pg_subscription_d.h"
|
||||
|
|
@ -1068,6 +1069,7 @@ permissionsList(const char *pattern, bool showSystem)
|
|||
" WHEN " CppAsString2(RELKIND_MATVIEW) " THEN '%s'"
|
||||
" WHEN " CppAsString2(RELKIND_SEQUENCE) " THEN '%s'"
|
||||
" WHEN " CppAsString2(RELKIND_FOREIGN_TABLE) " THEN '%s'"
|
||||
" WHEN " CppAsString2(RELKIND_PROPGRAPH) " THEN '%s'"
|
||||
" WHEN " CppAsString2(RELKIND_PARTITIONED_TABLE) " THEN '%s'"
|
||||
" END as \"%s\",\n"
|
||||
" ",
|
||||
|
|
@ -1078,6 +1080,7 @@ permissionsList(const char *pattern, bool showSystem)
|
|||
gettext_noop("materialized view"),
|
||||
gettext_noop("sequence"),
|
||||
gettext_noop("foreign table"),
|
||||
gettext_noop("property graph"),
|
||||
gettext_noop("partitioned table"),
|
||||
gettext_noop("Type"));
|
||||
|
||||
|
|
@ -1169,6 +1172,7 @@ permissionsList(const char *pattern, bool showSystem)
|
|||
CppAsString2(RELKIND_MATVIEW) ","
|
||||
CppAsString2(RELKIND_SEQUENCE) ","
|
||||
CppAsString2(RELKIND_FOREIGN_TABLE) ","
|
||||
CppAsString2(RELKIND_PROPGRAPH) ","
|
||||
CppAsString2(RELKIND_PARTITIONED_TABLE) ")\n");
|
||||
|
||||
if (!showSystem && !pattern)
|
||||
|
|
@ -1909,6 +1913,78 @@ describeOneTableDetails(const char *schemaname,
|
|||
goto error_return; /* not an error, just return early */
|
||||
}
|
||||
|
||||
/*
|
||||
* If it's a property graph, deal with it here separately.
|
||||
*/
|
||||
if (tableinfo.relkind == RELKIND_PROPGRAPH)
|
||||
{
|
||||
printQueryOpt myopt = pset.popt;
|
||||
char *footers[3] = {NULL, NULL, NULL};
|
||||
|
||||
printfPQExpBuffer(&buf,
|
||||
"SELECT e.pgealias AS \"%s\","
|
||||
"\n pg_catalog.quote_ident(n.nspname) || '.' ||"
|
||||
"\n pg_catalog.quote_ident(c.relname) AS \"%s\","
|
||||
"\n case e.pgekind when " CppAsString2(PGEKIND_VERTEX) " then 'vertex'"
|
||||
"\n when " CppAsString2(PGEKIND_EDGE) " then 'edge' end AS \"%s\","
|
||||
"\n s.pgealias as \"%s\","
|
||||
"\n d.pgealias as \"%s\""
|
||||
"\n FROM pg_propgraph_element e"
|
||||
"\n INNER JOIN pg_class c ON c.oid = e.pgerelid"
|
||||
"\n INNER JOIN pg_namespace n ON c.relnamespace = n.oid"
|
||||
"\n LEFT JOIN pg_propgraph_element s ON e.pgesrcvertexid = s.oid"
|
||||
"\n LEFT JOIN pg_propgraph_element d ON e.pgedestvertexid = d.oid"
|
||||
"\n WHERE e.pgepgid = '%s'"
|
||||
"\n ORDER BY e.pgealias",
|
||||
gettext_noop("Element Alias"),
|
||||
gettext_noop("Element Table"),
|
||||
gettext_noop("Element Kind"),
|
||||
gettext_noop("Source Vertex Alias"),
|
||||
gettext_noop("Destination Vertex Alias"),
|
||||
oid);
|
||||
|
||||
res = PSQLexec(buf.data);
|
||||
if (!res)
|
||||
goto error_return;
|
||||
|
||||
printfPQExpBuffer(&title, _("Property Graph \"%s.%s\""),
|
||||
schemaname, relationname);
|
||||
|
||||
/* Add property graph definition in verbose mode */
|
||||
if (verbose)
|
||||
{
|
||||
PGresult *result;
|
||||
|
||||
printfPQExpBuffer(&buf,
|
||||
"SELECT pg_catalog.pg_get_propgraphdef('%s'::pg_catalog.oid);",
|
||||
oid);
|
||||
result = PSQLexec(buf.data);
|
||||
|
||||
if (result)
|
||||
{
|
||||
if (PQntuples(result) > 0)
|
||||
{
|
||||
footers[0] = pg_strdup(_("Property graph definition:"));
|
||||
footers[1] = pg_strdup(PQgetvalue(result, 0, 0));
|
||||
}
|
||||
PQclear(result);
|
||||
}
|
||||
}
|
||||
|
||||
myopt.footers = footers;
|
||||
myopt.topt.default_footer = false;
|
||||
myopt.title = title.data;
|
||||
myopt.translate_header = true;
|
||||
|
||||
printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
|
||||
|
||||
free(footers[0]);
|
||||
free(footers[1]);
|
||||
|
||||
retval = true;
|
||||
goto error_return; /* not an error, just return early */
|
||||
}
|
||||
|
||||
/* Identify whether we should print collation, nullable, default vals */
|
||||
if (tableinfo.relkind == RELKIND_RELATION ||
|
||||
tableinfo.relkind == RELKIND_VIEW ||
|
||||
|
|
@ -4093,6 +4169,7 @@ describeRoleGrants(const char *pattern, bool showSystem)
|
|||
* m - materialized views
|
||||
* s - sequences
|
||||
* E - foreign table (Note: different from 'f', the relkind value)
|
||||
* G - property graphs
|
||||
* (any order of the above is fine)
|
||||
*/
|
||||
bool
|
||||
|
|
@ -4104,6 +4181,7 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys
|
|||
bool showMatViews = strchr(tabtypes, 'm') != NULL;
|
||||
bool showSeq = strchr(tabtypes, 's') != NULL;
|
||||
bool showForeign = strchr(tabtypes, 'E') != NULL;
|
||||
bool showPropGraphs = strchr(tabtypes, 'G') != NULL;
|
||||
|
||||
int ntypes;
|
||||
PQExpBufferData buf;
|
||||
|
|
@ -4114,10 +4192,10 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys
|
|||
|
||||
/* Count the number of explicitly-requested relation types */
|
||||
ntypes = showTables + showIndexes + showViews + showMatViews +
|
||||
showSeq + showForeign;
|
||||
/* If none, we default to \dtvmsE (but see also command.c) */
|
||||
showSeq + showForeign + showPropGraphs;
|
||||
/* If none, we default to \dtvmsEG (but see also command.c) */
|
||||
if (ntypes == 0)
|
||||
showTables = showViews = showMatViews = showSeq = showForeign = true;
|
||||
showTables = showViews = showMatViews = showSeq = showForeign = showPropGraphs = true;
|
||||
|
||||
initPQExpBuffer(&buf);
|
||||
|
||||
|
|
@ -4134,6 +4212,7 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys
|
|||
" WHEN " CppAsString2(RELKIND_FOREIGN_TABLE) " THEN '%s'"
|
||||
" WHEN " CppAsString2(RELKIND_PARTITIONED_TABLE) " THEN '%s'"
|
||||
" WHEN " CppAsString2(RELKIND_PARTITIONED_INDEX) " THEN '%s'"
|
||||
" WHEN " CppAsString2(RELKIND_PROPGRAPH) " THEN '%s'"
|
||||
" END as \"%s\",\n"
|
||||
" pg_catalog.pg_get_userbyid(c.relowner) as \"%s\"",
|
||||
gettext_noop("Schema"),
|
||||
|
|
@ -4147,6 +4226,7 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys
|
|||
gettext_noop("foreign table"),
|
||||
gettext_noop("partitioned table"),
|
||||
gettext_noop("partitioned index"),
|
||||
gettext_noop("property graph"),
|
||||
gettext_noop("Type"),
|
||||
gettext_noop("Owner"));
|
||||
cols_so_far = 4;
|
||||
|
|
@ -4234,6 +4314,8 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys
|
|||
appendPQExpBufferStr(&buf, "'s',"); /* was RELKIND_SPECIAL */
|
||||
if (showForeign)
|
||||
appendPQExpBufferStr(&buf, CppAsString2(RELKIND_FOREIGN_TABLE) ",");
|
||||
if (showPropGraphs)
|
||||
appendPQExpBufferStr(&buf, CppAsString2(RELKIND_PROPGRAPH) ",");
|
||||
|
||||
appendPQExpBufferStr(&buf, "''"); /* dummy */
|
||||
appendPQExpBufferStr(&buf, ")\n");
|
||||
|
|
@ -4289,6 +4371,9 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys
|
|||
else if (showForeign)
|
||||
pg_log_error("Did not find any foreign tables named \"%s\".",
|
||||
pattern);
|
||||
else if (showPropGraphs)
|
||||
pg_log_error("Did not find any property graphs named \"%s\".",
|
||||
pattern);
|
||||
else /* should not get here */
|
||||
pg_log_error_internal("Did not find any ??? named \"%s\".",
|
||||
pattern);
|
||||
|
|
@ -4309,6 +4394,8 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys
|
|||
pg_log_error("Did not find any sequences.");
|
||||
else if (showForeign)
|
||||
pg_log_error("Did not find any foreign tables.");
|
||||
else if (showPropGraphs)
|
||||
pg_log_error("Did not find any property graphs.");
|
||||
else /* should not get here */
|
||||
pg_log_error_internal("Did not find any ??? relations.");
|
||||
}
|
||||
|
|
@ -4323,6 +4410,7 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys
|
|||
(showMatViews) ? _("List of materialized views") :
|
||||
(showSeq) ? _("List of sequences") :
|
||||
(showForeign) ? _("List of foreign tables") :
|
||||
(showPropGraphs) ? _("List of property graphs") :
|
||||
"List of ???"; /* should not get here */
|
||||
myopt.translate_header = true;
|
||||
myopt.translate_columns = translate_columns;
|
||||
|
|
|
|||
|
|
@ -219,8 +219,8 @@ slashUsage(unsigned short int pager)
|
|||
|
||||
HELP0("Informational\n");
|
||||
HELP0(" (options: S = show system objects, x = expanded mode, + = additional detail)\n");
|
||||
HELP0(" \\d[Sx+] list tables, views, and sequences\n");
|
||||
HELP0(" \\d[S+] NAME describe table, view, sequence, or index\n");
|
||||
HELP0(" \\d[Sx+] list tables, views, sequences, and property graphs\n");
|
||||
HELP0(" \\d[S+] NAME describe table, view, sequence, index, or property graph\n");
|
||||
HELP0(" \\da[Sx] [PATTERN] list aggregates\n");
|
||||
HELP0(" \\dA[x+] [PATTERN] list access methods\n");
|
||||
HELP0(" \\dAc[x+] [AMPTRN [TYPEPTRN]] list operator classes\n");
|
||||
|
|
@ -246,6 +246,7 @@ slashUsage(unsigned short int pager)
|
|||
HELP0(" \\dFp[x+] [PATTERN] list text search parsers\n");
|
||||
HELP0(" \\dFt[x+] [PATTERN] list text search templates\n");
|
||||
HELP0(" \\dg[Sx+] [PATTERN] list roles\n");
|
||||
HELP0(" \\dG[Sx+] [PATTERN] list property graphs\n");
|
||||
HELP0(" \\di[Sx+] [PATTERN] list indexes\n");
|
||||
HELP0(" \\dl[x+] list large objects, same as \\lo_list\n");
|
||||
HELP0(" \\dL[Sx+] [PATTERN] list procedural languages\n");
|
||||
|
|
|
|||
|
|
@ -815,6 +815,14 @@ static const SchemaQuery Query_for_list_of_partitioned_indexes = {
|
|||
.result = "c.relname",
|
||||
};
|
||||
|
||||
static const SchemaQuery Query_for_list_of_propgraphs = {
|
||||
.catname = "pg_catalog.pg_class c",
|
||||
.selcondition = "c.relkind IN (" CppAsString2(RELKIND_PROPGRAPH) ")",
|
||||
.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
|
||||
.namespace = "c.relnamespace",
|
||||
.result = "pg_catalog.quote_ident(c.relname)",
|
||||
};
|
||||
|
||||
|
||||
/* All relations */
|
||||
static const SchemaQuery Query_for_list_of_relations = {
|
||||
|
|
@ -1336,6 +1344,7 @@ static const pgsql_thing_t words_after_create[] = {
|
|||
{"PARSER", NULL, NULL, &Query_for_list_of_ts_parsers, NULL, THING_NO_SHOW},
|
||||
{"POLICY", NULL, NULL, NULL},
|
||||
{"PROCEDURE", NULL, NULL, Query_for_list_of_procedures},
|
||||
{"PROPERTY GRAPH", NULL, NULL, &Query_for_list_of_propgraphs},
|
||||
{"PUBLICATION", NULL, Query_for_list_of_publications},
|
||||
{"ROLE", Query_for_list_of_roles},
|
||||
{"ROUTINE", NULL, NULL, &Query_for_list_of_routines, NULL, THING_NO_CREATE},
|
||||
|
|
@ -2739,6 +2748,20 @@ match_previous_words(int pattern_id,
|
|||
else if (Matches("ALTER", "POLICY", MatchAny, "ON", MatchAny, "WITH", "CHECK"))
|
||||
COMPLETE_WITH("(");
|
||||
|
||||
/* ALTER PROPERTY GRAPH */
|
||||
else if (Matches("ALTER", "PROPERTY", "GRAPH"))
|
||||
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_propgraphs);
|
||||
else if (Matches("ALTER", "PROPERTY", "GRAPH", MatchAny))
|
||||
COMPLETE_WITH("ADD", "ALTER", "DROP", "OWNER TO", "RENAME TO", "SET SCHEMA");
|
||||
else if (Matches("ALTER", "PROPERTY", "GRAPH", MatchAny, "ADD|ALTER|DROP"))
|
||||
COMPLETE_WITH("VERTEX", "EDGE");
|
||||
else if (Matches("ALTER", "PROPERTY", "GRAPH", MatchAny, "ADD|DROP", "VERTEX|EDGE"))
|
||||
COMPLETE_WITH("TABLES");
|
||||
else if (HeadMatches("ALTER", "PROPERTY", "GRAPH", MatchAny, "ADD") && TailMatches("EDGE"))
|
||||
COMPLETE_WITH("TABLES");
|
||||
else if (Matches("ALTER", "PROPERTY", "GRAPH", MatchAny, "ALTER", "VERTEX|EDGE"))
|
||||
COMPLETE_WITH("TABLE");
|
||||
|
||||
/* ALTER RULE <name>, add ON */
|
||||
else if (Matches("ALTER", "RULE", MatchAny))
|
||||
COMPLETE_WITH("ON");
|
||||
|
|
@ -3275,7 +3298,7 @@ match_previous_words(int pattern_id,
|
|||
"FOREIGN DATA WRAPPER", "FOREIGN TABLE",
|
||||
"FUNCTION", "INDEX", "LANGUAGE", "LARGE OBJECT",
|
||||
"MATERIALIZED VIEW", "OPERATOR", "POLICY",
|
||||
"PROCEDURE", "PROCEDURAL LANGUAGE", "PUBLICATION", "ROLE",
|
||||
"PROCEDURE", "PROCEDURAL LANGUAGE", "PROPERTY GRAPH", "PUBLICATION", "ROLE",
|
||||
"ROUTINE", "RULE", "SCHEMA", "SEQUENCE", "SERVER",
|
||||
"STATISTICS", "SUBSCRIPTION", "TABLE",
|
||||
"TABLESPACE", "TEXT SEARCH", "TRANSFORM FOR",
|
||||
|
|
@ -3313,6 +3336,8 @@ match_previous_words(int pattern_id,
|
|||
}
|
||||
else if (Matches("COMMENT", "ON", "PROCEDURAL", "LANGUAGE"))
|
||||
COMPLETE_WITH_QUERY(Query_for_list_of_languages);
|
||||
else if (Matches("COMMENT", "ON", "PROPERTY", "GRAPH"))
|
||||
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_propgraphs);
|
||||
else if (Matches("COMMENT", "ON", "RULE", MatchAny))
|
||||
COMPLETE_WITH("ON");
|
||||
else if (Matches("COMMENT", "ON", "RULE", MatchAny, "ON"))
|
||||
|
|
@ -3672,6 +3697,25 @@ match_previous_words(int pattern_id,
|
|||
else if (Matches("CREATE", "POLICY", MatchAny, "ON", MatchAny, "AS", MatchAny, "USING"))
|
||||
COMPLETE_WITH("(");
|
||||
|
||||
/* CREATE PROPERTY GRAPH */
|
||||
else if (Matches("CREATE", "PROPERTY"))
|
||||
COMPLETE_WITH("GRAPH");
|
||||
else if (Matches("CREATE", "PROPERTY", "GRAPH", MatchAny))
|
||||
COMPLETE_WITH("VERTEX");
|
||||
else if (Matches("CREATE", "PROPERTY", "GRAPH", MatchAny, "VERTEX|NODE"))
|
||||
COMPLETE_WITH("TABLES");
|
||||
else if (Matches("CREATE", "PROPERTY", "GRAPH", MatchAny, "VERTEX|NODE", "TABLES"))
|
||||
COMPLETE_WITH("(");
|
||||
else if (Matches("CREATE", "PROPERTY", "GRAPH", MatchAny, "VERTEX|NODE", "TABLES", "("))
|
||||
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
|
||||
else if (Matches("CREATE", "PROPERTY", "GRAPH", MatchAny, "VERTEX|NODE", "TABLES", "(*)"))
|
||||
COMPLETE_WITH("EDGE");
|
||||
else if (HeadMatches("CREATE", "PROPERTY", "GRAPH") && TailMatches("EDGE|RELATIONSHIP"))
|
||||
COMPLETE_WITH("TABLES");
|
||||
else if (HeadMatches("CREATE", "PROPERTY", "GRAPH") && TailMatches("EDGE|RELATIONSHIP", "TABLES"))
|
||||
COMPLETE_WITH("(");
|
||||
else if (HeadMatches("CREATE", "PROPERTY", "GRAPH") && TailMatches("EDGE|RELATIONSHIP", "TABLES", "("))
|
||||
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
|
||||
|
||||
/* CREATE PUBLICATION */
|
||||
else if (Matches("CREATE", "PUBLICATION", MatchAny))
|
||||
|
|
@ -4403,6 +4447,12 @@ match_previous_words(int pattern_id,
|
|||
else if (Matches("DROP", "POLICY", MatchAny, "ON", MatchAny))
|
||||
COMPLETE_WITH("CASCADE", "RESTRICT");
|
||||
|
||||
/* DROP PROPERTY GRAPH */
|
||||
else if (Matches("DROP", "PROPERTY"))
|
||||
COMPLETE_WITH("GRAPH");
|
||||
else if (Matches("DROP", "PROPERTY", "GRAPH"))
|
||||
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_propgraphs);
|
||||
|
||||
/* DROP RULE */
|
||||
else if (Matches("DROP", "RULE", MatchAny))
|
||||
COMPLETE_WITH("ON");
|
||||
|
|
@ -4647,6 +4697,7 @@ match_previous_words(int pattern_id,
|
|||
"LARGE OBJECT",
|
||||
"PARAMETER",
|
||||
"PROCEDURE",
|
||||
"PROPERTY GRAPH",
|
||||
"ROUTINE",
|
||||
"SCHEMA",
|
||||
"SEQUENCE",
|
||||
|
|
@ -4805,6 +4856,14 @@ match_previous_words(int pattern_id,
|
|||
COMPLETE_WITH("FROM");
|
||||
}
|
||||
|
||||
/* GRAPH_TABLE */
|
||||
else if (TailMatches("GRAPH_TABLE"))
|
||||
COMPLETE_WITH("(");
|
||||
else if (TailMatches("GRAPH_TABLE", "("))
|
||||
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_propgraphs);
|
||||
else if (TailMatches("GRAPH_TABLE", "(", MatchAny))
|
||||
COMPLETE_WITH("MATCH");
|
||||
|
||||
/* GROUP BY */
|
||||
else if (TailMatches("FROM", MatchAny, "GROUP"))
|
||||
COMPLETE_WITH("BY");
|
||||
|
|
@ -5170,8 +5229,10 @@ match_previous_words(int pattern_id,
|
|||
COMPLETE_WITH("TABLE", "COLUMN", "AGGREGATE", "DATABASE", "DOMAIN",
|
||||
"EVENT TRIGGER", "FOREIGN TABLE", "FUNCTION",
|
||||
"LARGE OBJECT", "MATERIALIZED VIEW", "LANGUAGE",
|
||||
"PUBLICATION", "PROCEDURE", "ROLE", "ROUTINE", "SCHEMA",
|
||||
"PROPERTY GRAPH", "PUBLICATION", "PROCEDURE", "ROLE", "ROUTINE", "SCHEMA",
|
||||
"SEQUENCE", "SUBSCRIPTION", "TABLESPACE", "TYPE", "VIEW");
|
||||
else if (Matches("SECURITY", "LABEL", "ON", "PROPERTY", "GRAPH"))
|
||||
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_propgraphs);
|
||||
else if (Matches("SECURITY", "LABEL", "ON", MatchAny, MatchAny))
|
||||
COMPLETE_WITH("IS");
|
||||
|
||||
|
|
@ -5652,6 +5713,8 @@ match_previous_words(int pattern_id,
|
|||
COMPLETE_WITH("OBJECT");
|
||||
else if (TailMatches("CREATE|ALTER|DROP", "MATERIALIZED"))
|
||||
COMPLETE_WITH("VIEW");
|
||||
else if (TailMatches("CREATE|ALTER|DROP", "PROPERTY"))
|
||||
COMPLETE_WITH("GRAPH");
|
||||
else if (TailMatches("CREATE|ALTER|DROP", "TEXT"))
|
||||
COMPLETE_WITH("SEARCH");
|
||||
else if (TailMatches("CREATE|ALTER|DROP", "USER"))
|
||||
|
|
|
|||
|
|
@ -293,6 +293,8 @@ less_equals "<="
|
|||
greater_equals ">="
|
||||
less_greater "<>"
|
||||
not_equals "!="
|
||||
/* Note there is no need for left_arrow, since "<-" is not a single operator. */
|
||||
right_arrow "->"
|
||||
|
||||
/*
|
||||
* "self" is the set of chars that should be returned as single-character
|
||||
|
|
@ -304,7 +306,7 @@ not_equals "!="
|
|||
* If you change either set, adjust the character lists appearing in the
|
||||
* rule for "operator"!
|
||||
*/
|
||||
self [,()\[\].;\:\+\-\*\/\%\^\<\>\=]
|
||||
self [,()\[\].;\:\|\+\-\*\/\%\^\<\>\=]
|
||||
op_chars [\~\!\@\#\^\&\|\`\?\+\-\*\/\%\<\>\=]
|
||||
operator {op_chars}+
|
||||
|
||||
|
|
@ -652,6 +654,10 @@ other .
|
|||
ECHO;
|
||||
}
|
||||
|
||||
{right_arrow} {
|
||||
ECHO;
|
||||
}
|
||||
|
||||
/*
|
||||
* These rules are specific to psql --- they implement parenthesis
|
||||
* counting and detection of command-ending semicolon. These must
|
||||
|
|
|
|||
|
|
@ -81,7 +81,12 @@ CATALOG_HEADERS := \
|
|||
pg_publication_namespace.h \
|
||||
pg_publication_rel.h \
|
||||
pg_subscription.h \
|
||||
pg_subscription_rel.h
|
||||
pg_subscription_rel.h \
|
||||
pg_propgraph_element.h \
|
||||
pg_propgraph_element_label.h \
|
||||
pg_propgraph_label.h \
|
||||
pg_propgraph_label_property.h \
|
||||
pg_propgraph_property.h
|
||||
|
||||
GENERATED_HEADERS := $(CATALOG_HEADERS:%.h=%_d.h)
|
||||
|
||||
|
|
|
|||
|
|
@ -57,6 +57,6 @@
|
|||
*/
|
||||
|
||||
/* yyyymmddN */
|
||||
#define CATALOG_VERSION_NO 202603161
|
||||
#define CATALOG_VERSION_NO 202603162
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -69,6 +69,11 @@ catalog_headers = [
|
|||
'pg_publication_rel.h',
|
||||
'pg_subscription.h',
|
||||
'pg_subscription_rel.h',
|
||||
'pg_propgraph_element.h',
|
||||
'pg_propgraph_element_label.h',
|
||||
'pg_propgraph_label.h',
|
||||
'pg_propgraph_label_property.h',
|
||||
'pg_propgraph_property.h',
|
||||
]
|
||||
|
||||
# The .dat files we need can just be listed alphabetically.
|
||||
|
|
|
|||
|
|
@ -178,6 +178,7 @@ MAKE_SYSCACHE(RELNAMENSP, pg_class_relname_nsp_index, 128);
|
|||
#define RELKIND_FOREIGN_TABLE 'f' /* foreign table */
|
||||
#define RELKIND_PARTITIONED_TABLE 'p' /* partitioned table */
|
||||
#define RELKIND_PARTITIONED_INDEX 'I' /* partitioned index */
|
||||
#define RELKIND_PROPGRAPH 'g' /* property graph */
|
||||
|
||||
#define RELPERSISTENCE_PERMANENT 'p' /* regular table */
|
||||
#define RELPERSISTENCE_UNLOGGED 'u' /* unlogged permanent table */
|
||||
|
|
|
|||
|
|
@ -3965,6 +3965,9 @@
|
|||
proargtypes => 'oid oid', prosrc => 'oidge' },
|
||||
|
||||
# System-view support functions
|
||||
{ oid => '8302', descr => 'source text of a property graph',
|
||||
proname => 'pg_get_propgraphdef', provolatile => 's', prorettype => 'text',
|
||||
proargtypes => 'oid', prosrc => 'pg_get_propgraphdef' },
|
||||
{ oid => '1573', descr => 'source text of a rule',
|
||||
proname => 'pg_get_ruledef', provolatile => 's', prorettype => 'text',
|
||||
proargtypes => 'oid', prosrc => 'pg_get_ruledef' },
|
||||
|
|
|
|||
118
src/include/catalog/pg_propgraph_element.h
Normal file
118
src/include/catalog/pg_propgraph_element.h
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* pg_propgraph_element.h
|
||||
* definition of the "property graph elements" system catalog (pg_propgraph_element)
|
||||
*
|
||||
* Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* src/include/catalog/pg_propgraph_element.h
|
||||
*
|
||||
* NOTES
|
||||
* The Catalog.pm module reads this file and derives schema
|
||||
* information.
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef PG_PROPGRAPH_ELEMENT_H
|
||||
#define PG_PROPGRAPH_ELEMENT_H
|
||||
|
||||
#include "catalog/genbki.h"
|
||||
#include "catalog/pg_propgraph_element_d.h"
|
||||
|
||||
/* ----------------
|
||||
* pg_propgraph_element definition. cpp turns this into
|
||||
* typedef struct FormData_pg_propgraph_element
|
||||
* ----------------
|
||||
*/
|
||||
BEGIN_CATALOG_STRUCT
|
||||
|
||||
CATALOG(pg_propgraph_element,8299,PropgraphElementRelationId)
|
||||
{
|
||||
Oid oid;
|
||||
|
||||
/* OID of the property graph relation */
|
||||
Oid pgepgid BKI_LOOKUP(pg_class);
|
||||
|
||||
/* OID of the element table */
|
||||
Oid pgerelid BKI_LOOKUP(pg_class);
|
||||
|
||||
/* element alias */
|
||||
NameData pgealias;
|
||||
|
||||
/* vertex or edge? -- see PGEKIND_* below */
|
||||
char pgekind;
|
||||
|
||||
/* for edges: source vertex */
|
||||
Oid pgesrcvertexid BKI_LOOKUP_OPT(pg_propgraph_element);
|
||||
|
||||
/* for edges: destination vertex */
|
||||
Oid pgedestvertexid BKI_LOOKUP_OPT(pg_propgraph_element);
|
||||
|
||||
#ifdef CATALOG_VARLEN /* variable-length fields start here */
|
||||
/* element key (column numbers in pgerelid relation) */
|
||||
int16 pgekey[1] BKI_FORCE_NOT_NULL;
|
||||
|
||||
/*
|
||||
* for edges: source vertex key (column numbers in pgerelid relation)
|
||||
*/
|
||||
int16 pgesrckey[1];
|
||||
|
||||
/*
|
||||
* for edges: source vertex table referenced columns (column numbers in
|
||||
* relation reached via pgesrcvertexid)
|
||||
*/
|
||||
int16 pgesrcref[1];
|
||||
|
||||
/*
|
||||
* for edges: Oids of the equality operators for comparing source keys
|
||||
*/
|
||||
Oid pgesrceqop[1];
|
||||
|
||||
/*
|
||||
* for edges: destination vertex key (column numbers in pgerelid relation)
|
||||
*/
|
||||
int16 pgedestkey[1];
|
||||
|
||||
/*
|
||||
* for edges: destination vertex table referenced columns (column numbers
|
||||
* in relation reached via pgedestvertexid)
|
||||
*/
|
||||
int16 pgedestref[1];
|
||||
|
||||
/*
|
||||
* for edges: Oids of the equality operators for comparing destination
|
||||
* keys
|
||||
*/
|
||||
Oid pgedesteqop[1];
|
||||
#endif
|
||||
} FormData_pg_propgraph_element;
|
||||
|
||||
END_CATALOG_STRUCT
|
||||
|
||||
/* ----------------
|
||||
* Form_pg_propgraph_element corresponds to a pointer to a tuple with
|
||||
* the format of pg_propgraph_element relation.
|
||||
* ----------------
|
||||
*/
|
||||
typedef FormData_pg_propgraph_element *Form_pg_propgraph_element;
|
||||
|
||||
DECLARE_TOAST(pg_propgraph_element, 8315, 8316);
|
||||
|
||||
DECLARE_UNIQUE_INDEX_PKEY(pg_propgraph_element_oid_index, 8300, PropgraphElementObjectIndexId, pg_propgraph_element, btree(oid oid_ops));
|
||||
DECLARE_UNIQUE_INDEX(pg_propgraph_element_alias_index, 8301, PropgraphElementAliasIndexId, pg_propgraph_element, btree(pgepgid oid_ops, pgealias name_ops));
|
||||
|
||||
MAKE_SYSCACHE(PROPGRAPHELOID, pg_propgraph_element_oid_index, 128);
|
||||
MAKE_SYSCACHE(PROPGRAPHELALIAS, pg_propgraph_element_alias_index, 128);
|
||||
|
||||
#ifdef EXPOSE_TO_CLIENT_CODE
|
||||
|
||||
/*
|
||||
* Symbolic values for pgekind column
|
||||
*/
|
||||
#define PGEKIND_VERTEX 'v'
|
||||
#define PGEKIND_EDGE 'e'
|
||||
|
||||
#endif /* EXPOSE_TO_CLIENT_CODE */
|
||||
|
||||
#endif /* PG_PROPGRAPH_ELEMENT_H */
|
||||
55
src/include/catalog/pg_propgraph_element_label.h
Normal file
55
src/include/catalog/pg_propgraph_element_label.h
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* pg_propgraph_element_label.h
|
||||
*
|
||||
* Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* src/include/catalog/pg_propgraph_element_label.h
|
||||
*
|
||||
* NOTES
|
||||
* The Catalog.pm module reads this file and derives schema
|
||||
* information.
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef PG_PROPGRAPH_ELEMENT_LABEL_H
|
||||
#define PG_PROPGRAPH_ELEMENT_LABEL_H
|
||||
|
||||
#include "catalog/genbki.h"
|
||||
#include "catalog/pg_propgraph_element_label_d.h"
|
||||
|
||||
/* ----------------
|
||||
* pg_propgraph_element_label definition. cpp turns this into
|
||||
* typedef struct FormData_pg_propgraph_element_label
|
||||
* ----------------
|
||||
*/
|
||||
BEGIN_CATALOG_STRUCT
|
||||
|
||||
CATALOG(pg_propgraph_element_label,8305,PropgraphElementLabelRelationId)
|
||||
{
|
||||
Oid oid;
|
||||
|
||||
/* OID of the label */
|
||||
Oid pgellabelid BKI_LOOKUP(pg_propgraph_label);
|
||||
|
||||
/* OID of the property graph element */
|
||||
Oid pgelelid BKI_LOOKUP(pg_propgraph_element);
|
||||
} FormData_pg_propgraph_element_label;
|
||||
|
||||
END_CATALOG_STRUCT
|
||||
|
||||
/* ----------------
|
||||
* Form_pg_propgraph_element_label corresponds to a pointer to a tuple with
|
||||
* the format of pg_propgraph_element_label relation.
|
||||
* ----------------
|
||||
*/
|
||||
typedef FormData_pg_propgraph_element_label *Form_pg_propgraph_element_label;
|
||||
|
||||
DECLARE_UNIQUE_INDEX_PKEY(pg_propgraph_element_label_oid_index, 8312, PropgraphElementLabelObjectIndexId, pg_propgraph_element_label, btree(oid oid_ops));
|
||||
DECLARE_UNIQUE_INDEX(pg_propgraph_element_label_element_label_index, 8313, PropgraphElementLabelElementLabelIndexId, pg_propgraph_element_label, btree(pgelelid oid_ops, pgellabelid oid_ops));
|
||||
DECLARE_INDEX(pg_propgraph_element_label_label_index, 8317, PropgraphElementLabelLabelIndexId, pg_propgraph_element_label, btree(pgellabelid oid_ops));
|
||||
|
||||
MAKE_SYSCACHE(PROPGRAPHELEMENTLABELELEMENTLABEL, pg_propgraph_element_label_element_label_index, 128);
|
||||
|
||||
#endif /* PG_PROPGRAPH_ELEMENT_LABEL_H */
|
||||
55
src/include/catalog/pg_propgraph_label.h
Normal file
55
src/include/catalog/pg_propgraph_label.h
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* pg_propgraph_label.h
|
||||
*
|
||||
* Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* src/include/catalog/pg_propgraph_label.h
|
||||
*
|
||||
* NOTES
|
||||
* The Catalog.pm module reads this file and derives schema
|
||||
* information.
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef PG_PROPGRAPH_LABEL_H
|
||||
#define PG_PROPGRAPH_LABEL_H
|
||||
|
||||
#include "catalog/genbki.h"
|
||||
#include "catalog/pg_propgraph_label_d.h"
|
||||
|
||||
/* ----------------
|
||||
* pg_propgraph_label definition. cpp turns this into
|
||||
* typedef struct FormData_pg_propgraph_label
|
||||
* ----------------
|
||||
*/
|
||||
BEGIN_CATALOG_STRUCT
|
||||
|
||||
CATALOG(pg_propgraph_label,8303,PropgraphLabelRelationId)
|
||||
{
|
||||
Oid oid;
|
||||
|
||||
/* OID of the property graph relation */
|
||||
Oid pglpgid BKI_LOOKUP(pg_class);
|
||||
|
||||
/* label name */
|
||||
NameData pgllabel;
|
||||
} FormData_pg_propgraph_label;
|
||||
|
||||
END_CATALOG_STRUCT
|
||||
|
||||
/* ----------------
|
||||
* Form_pg_propgraph_label corresponds to a pointer to a tuple with
|
||||
* the format of pg_propgraph_label relation.
|
||||
* ----------------
|
||||
*/
|
||||
typedef FormData_pg_propgraph_label *Form_pg_propgraph_label;
|
||||
|
||||
DECLARE_UNIQUE_INDEX_PKEY(pg_propgraph_label_oid_index, 8304, PropgraphLabelObjectIndexId, pg_propgraph_label, btree(oid oid_ops));
|
||||
DECLARE_UNIQUE_INDEX(pg_propgraph_label_graph_name_index, 8314, PropgraphLabelGraphNameIndexId, pg_propgraph_label, btree(pglpgid oid_ops, pgllabel name_ops));
|
||||
|
||||
MAKE_SYSCACHE(PROPGRAPHLABELOID, pg_propgraph_label_oid_index, 128);
|
||||
MAKE_SYSCACHE(PROPGRAPHLABELNAME, pg_propgraph_label_graph_name_index, 128);
|
||||
|
||||
#endif /* PG_PROPGRAPH_LABEL_H */
|
||||
63
src/include/catalog/pg_propgraph_label_property.h
Normal file
63
src/include/catalog/pg_propgraph_label_property.h
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* pg_propgraph_label_property.h
|
||||
*
|
||||
* Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* src/include/catalog/pg_propgraph_label_property.h
|
||||
*
|
||||
* NOTES
|
||||
* The Catalog.pm module reads this file and derives schema
|
||||
* information.
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef PG_PROPGRAPH_LABEL_PROPERTY_H
|
||||
#define PG_PROPGRAPH_LABEL_PROPERTY_H
|
||||
|
||||
#include "catalog/genbki.h"
|
||||
#include "catalog/pg_propgraph_label_property_d.h"
|
||||
|
||||
/* ----------------
|
||||
* pg_propgraph_label_property definition. cpp turns this into
|
||||
* typedef struct FormData_pg_propgraph_label_property
|
||||
* ----------------
|
||||
*/
|
||||
BEGIN_CATALOG_STRUCT
|
||||
|
||||
CATALOG(pg_propgraph_label_property,8318,PropgraphLabelPropertyRelationId)
|
||||
{
|
||||
Oid oid;
|
||||
|
||||
/* OID of the property */
|
||||
Oid plppropid BKI_LOOKUP(pg_propgraph_property);
|
||||
|
||||
/* OID of the element label */
|
||||
Oid plpellabelid BKI_LOOKUP(pg_propgraph_element_label);
|
||||
|
||||
#ifdef CATALOG_VARLEN /* variable-length fields start here */
|
||||
|
||||
/* property expression */
|
||||
pg_node_tree plpexpr BKI_FORCE_NOT_NULL;
|
||||
|
||||
#endif
|
||||
} FormData_pg_propgraph_label_property;
|
||||
|
||||
END_CATALOG_STRUCT
|
||||
|
||||
/* ----------------
|
||||
* Form_pg_propgraph_label_property corresponds to a pointer to a tuple with
|
||||
* the format of pg_propgraph_label_property relation.
|
||||
* ----------------
|
||||
*/
|
||||
typedef FormData_pg_propgraph_label_property *Form_pg_propgraph_label_property;
|
||||
|
||||
DECLARE_TOAST(pg_propgraph_label_property, 8319, 8320);
|
||||
|
||||
DECLARE_UNIQUE_INDEX_PKEY(pg_propgraph_label_property_oid_index, 8328, PropgraphLabelPropertyObjectIndexId, pg_propgraph_label_property, btree(oid oid_ops));
|
||||
DECLARE_UNIQUE_INDEX(pg_propgraph_label_property_label_prop_index, 8329, PropgraphLabelPropertyLabelPropIndexId, pg_propgraph_label_property, btree(plpellabelid oid_ops, plppropid oid_ops));
|
||||
|
||||
MAKE_SYSCACHE(PROPGRAPHLABELPROP, pg_propgraph_label_property_label_prop_index, 128);
|
||||
|
||||
#endif /* PG_PROPGRAPH_LABEL_PROPERTY_H */
|
||||
64
src/include/catalog/pg_propgraph_property.h
Normal file
64
src/include/catalog/pg_propgraph_property.h
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* pg_propgraph_property.h
|
||||
*
|
||||
* Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* src/include/catalog/pg_propgraph_property.h
|
||||
*
|
||||
* NOTES
|
||||
* The Catalog.pm module reads this file and derives schema
|
||||
* information.
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef PG_PROPGRAPH_PROPERTY_H
|
||||
#define PG_PROPGRAPH_PROPERTY_H
|
||||
|
||||
#include "catalog/genbki.h"
|
||||
#include "catalog/pg_propgraph_property_d.h"
|
||||
|
||||
/* ----------------
|
||||
* pg_propgraph_property definition. cpp turns this into
|
||||
* typedef struct FormData_pg_propgraph_property
|
||||
* ----------------
|
||||
*/
|
||||
BEGIN_CATALOG_STRUCT
|
||||
|
||||
CATALOG(pg_propgraph_property,8306,PropgraphPropertyRelationId)
|
||||
{
|
||||
Oid oid;
|
||||
|
||||
/* OID of the property graph relation */
|
||||
Oid pgppgid BKI_LOOKUP(pg_class);
|
||||
|
||||
/* property name */
|
||||
NameData pgpname;
|
||||
|
||||
/* data type of the property */
|
||||
Oid pgptypid BKI_LOOKUP_OPT(pg_type);
|
||||
|
||||
/* typemod of the property */
|
||||
int32 pgptypmod;
|
||||
|
||||
/* collation of the property */
|
||||
Oid pgpcollation BKI_LOOKUP_OPT(pg_collation);
|
||||
} FormData_pg_propgraph_property;
|
||||
|
||||
END_CATALOG_STRUCT
|
||||
|
||||
/* ----------------
|
||||
* Form_pg_propgraph_property corresponds to a pointer to a tuple with
|
||||
* the format of pg_propgraph_property relation.
|
||||
* ----------------
|
||||
*/
|
||||
typedef FormData_pg_propgraph_property *Form_pg_propgraph_property;
|
||||
|
||||
DECLARE_UNIQUE_INDEX_PKEY(pg_propgraph_property_oid_index, 8307, PropgraphPropertyObjectIndexId, pg_propgraph_property, btree(oid oid_ops));
|
||||
DECLARE_UNIQUE_INDEX(pg_propgraph_property_name_index, 8308, PropgraphPropertyNameIndexId, pg_propgraph_property, btree(pgppgid oid_ops, pgpname name_ops));
|
||||
|
||||
MAKE_SYSCACHE(PROPGRAPHPROPOID, pg_propgraph_property_oid_index, 128);
|
||||
MAKE_SYSCACHE(PROPGRAPHPROPNAME, pg_propgraph_property_name_index, 128);
|
||||
|
||||
#endif /* PG_PROPGRAPH_PROPERTY_H */
|
||||
23
src/include/commands/propgraphcmds.h
Normal file
23
src/include/commands/propgraphcmds.h
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* propgraphcmds.h
|
||||
* prototypes for propgraphcmds.c.
|
||||
*
|
||||
* Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* src/include/commands/propgraphcmds.h
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef PROPGRAPHCMDS_H
|
||||
#define PROPGRAPHCMDS_H
|
||||
|
||||
#include "catalog/objectaddress.h"
|
||||
#include "parser/parse_node.h"
|
||||
|
||||
extern ObjectAddress CreatePropGraph(ParseState *pstate, const CreatePropGraphStmt *stmt);
|
||||
extern ObjectAddress AlterPropGraph(ParseState *pstate, const AlterPropGraphStmt *stmt);
|
||||
|
||||
#endif /* PROPGRAPHCMDS_H */
|
||||
|
|
@ -710,6 +710,19 @@ typedef struct RangeTableFuncCol
|
|||
ParseLoc location; /* token location, or -1 if unknown */
|
||||
} RangeTableFuncCol;
|
||||
|
||||
/*
|
||||
* RangeGraphTable - raw form of GRAPH_TABLE clause
|
||||
*/
|
||||
typedef struct RangeGraphTable
|
||||
{
|
||||
NodeTag type;
|
||||
RangeVar *graph_name;
|
||||
struct GraphPattern *graph_pattern;
|
||||
List *columns;
|
||||
Alias *alias; /* table alias & optional column aliases */
|
||||
ParseLoc location; /* token location, or -1 if unknown */
|
||||
} RangeGraphTable;
|
||||
|
||||
/*
|
||||
* RangeTableSample - TABLESAMPLE appearing in a raw FROM clause
|
||||
*
|
||||
|
|
@ -1003,6 +1016,42 @@ typedef struct PartitionCmd
|
|||
bool concurrent;
|
||||
} PartitionCmd;
|
||||
|
||||
/*
|
||||
* Nodes for graph pattern
|
||||
*/
|
||||
|
||||
typedef struct GraphPattern
|
||||
{
|
||||
NodeTag type;
|
||||
List *path_pattern_list;
|
||||
Node *whereClause;
|
||||
} GraphPattern;
|
||||
|
||||
typedef enum GraphElementPatternKind
|
||||
{
|
||||
VERTEX_PATTERN,
|
||||
EDGE_PATTERN_LEFT,
|
||||
EDGE_PATTERN_RIGHT,
|
||||
EDGE_PATTERN_ANY,
|
||||
PAREN_EXPR,
|
||||
} GraphElementPatternKind;
|
||||
|
||||
#define IS_EDGE_PATTERN(kind) ((kind) == EDGE_PATTERN_ANY || \
|
||||
(kind) == EDGE_PATTERN_RIGHT || \
|
||||
(kind) == EDGE_PATTERN_LEFT)
|
||||
|
||||
typedef struct GraphElementPattern
|
||||
{
|
||||
NodeTag type;
|
||||
GraphElementPatternKind kind;
|
||||
const char *variable;
|
||||
Node *labelexpr;
|
||||
List *subexpr;
|
||||
Node *whereClause;
|
||||
List *quantifier;
|
||||
ParseLoc location;
|
||||
} GraphElementPattern;
|
||||
|
||||
/****************************************************************************
|
||||
* Nodes for a Query tree
|
||||
****************************************************************************/
|
||||
|
|
@ -1075,6 +1124,7 @@ typedef enum RTEKind
|
|||
RTE_VALUES, /* VALUES (<exprlist>), (<exprlist>), ... */
|
||||
RTE_CTE, /* common table expr (WITH list element) */
|
||||
RTE_NAMEDTUPLESTORE, /* tuplestore, e.g. for AFTER triggers */
|
||||
RTE_GRAPH_TABLE, /* GRAPH_TABLE clause */
|
||||
RTE_RESULT, /* RTE represents an empty FROM clause; such
|
||||
* RTEs are added by the planner, they're not
|
||||
* present during parsing or rewriting */
|
||||
|
|
@ -1241,6 +1291,12 @@ typedef struct RangeTblEntry
|
|||
*/
|
||||
TableFunc *tablefunc;
|
||||
|
||||
/*
|
||||
* Fields valid for a graph table RTE (else NULL):
|
||||
*/
|
||||
GraphPattern *graph_pattern;
|
||||
List *graph_table_columns;
|
||||
|
||||
/*
|
||||
* Fields valid for a values RTE (else NIL):
|
||||
*/
|
||||
|
|
@ -2381,6 +2437,7 @@ typedef enum ObjectType
|
|||
OBJECT_PARAMETER_ACL,
|
||||
OBJECT_POLICY,
|
||||
OBJECT_PROCEDURE,
|
||||
OBJECT_PROPGRAPH,
|
||||
OBJECT_PUBLICATION,
|
||||
OBJECT_PUBLICATION_NAMESPACE,
|
||||
OBJECT_PUBLICATION_REL,
|
||||
|
|
@ -4186,6 +4243,88 @@ typedef struct CreateCastStmt
|
|||
bool inout;
|
||||
} CreateCastStmt;
|
||||
|
||||
/* ----------------------
|
||||
* CREATE PROPERTY GRAPH Statement
|
||||
* ----------------------
|
||||
*/
|
||||
typedef struct CreatePropGraphStmt
|
||||
{
|
||||
NodeTag type;
|
||||
RangeVar *pgname;
|
||||
List *vertex_tables;
|
||||
List *edge_tables;
|
||||
} CreatePropGraphStmt;
|
||||
|
||||
typedef struct PropGraphVertex
|
||||
{
|
||||
NodeTag type;
|
||||
RangeVar *vtable;
|
||||
List *vkey;
|
||||
List *labels;
|
||||
ParseLoc location;
|
||||
} PropGraphVertex;
|
||||
|
||||
typedef struct PropGraphEdge
|
||||
{
|
||||
NodeTag type;
|
||||
RangeVar *etable;
|
||||
List *ekey;
|
||||
List *esrckey;
|
||||
char *esrcvertex;
|
||||
List *esrcvertexcols;
|
||||
List *edestkey;
|
||||
char *edestvertex;
|
||||
List *edestvertexcols;
|
||||
List *labels;
|
||||
ParseLoc location;
|
||||
} PropGraphEdge;
|
||||
|
||||
typedef struct PropGraphLabelAndProperties
|
||||
{
|
||||
NodeTag type;
|
||||
const char *label;
|
||||
struct PropGraphProperties *properties;
|
||||
ParseLoc location;
|
||||
} PropGraphLabelAndProperties;
|
||||
|
||||
typedef struct PropGraphProperties
|
||||
{
|
||||
NodeTag type;
|
||||
List *properties;
|
||||
bool all;
|
||||
ParseLoc location;
|
||||
} PropGraphProperties;
|
||||
|
||||
/* ----------------------
|
||||
* ALTER PROPERTY GRAPH Statement
|
||||
* ----------------------
|
||||
*/
|
||||
|
||||
typedef enum AlterPropGraphElementKind
|
||||
{
|
||||
PROPGRAPH_ELEMENT_KIND_VERTEX = 1,
|
||||
PROPGRAPH_ELEMENT_KIND_EDGE = 2,
|
||||
} AlterPropGraphElementKind;
|
||||
|
||||
typedef struct AlterPropGraphStmt
|
||||
{
|
||||
NodeTag type;
|
||||
RangeVar *pgname;
|
||||
bool missing_ok;
|
||||
List *add_vertex_tables;
|
||||
List *add_edge_tables;
|
||||
List *drop_vertex_tables;
|
||||
List *drop_edge_tables;
|
||||
DropBehavior drop_behavior;
|
||||
AlterPropGraphElementKind element_kind;
|
||||
const char *element_alias;
|
||||
List *add_labels;
|
||||
const char *drop_label;
|
||||
const char *alter_label;
|
||||
PropGraphProperties *add_properties;
|
||||
List *drop_properties;
|
||||
} AlterPropGraphStmt;
|
||||
|
||||
/* ----------------------
|
||||
* CREATE TRANSFORM Statement
|
||||
* ----------------------
|
||||
|
|
|
|||
|
|
@ -2178,6 +2178,30 @@ typedef struct ReturningExpr
|
|||
Expr *retexpr; /* expression to be returned */
|
||||
} ReturningExpr;
|
||||
|
||||
/*
|
||||
* GraphLabelRef - label reference in label expression inside GRAPH_TABLE clause
|
||||
*/
|
||||
typedef struct GraphLabelRef
|
||||
{
|
||||
NodeTag type;
|
||||
Oid labelid;
|
||||
ParseLoc location;
|
||||
} GraphLabelRef;
|
||||
|
||||
/*
|
||||
* GraphPropertyRef - property reference inside GRAPH_TABLE clause
|
||||
*/
|
||||
typedef struct GraphPropertyRef
|
||||
{
|
||||
Expr xpr;
|
||||
const char *elvarname;
|
||||
Oid propid;
|
||||
Oid typeId;
|
||||
int32 typmod;
|
||||
Oid collation;
|
||||
ParseLoc location;
|
||||
} GraphPropertyRef;
|
||||
|
||||
/*--------------------
|
||||
* TargetEntry -
|
||||
* a target entry (used in query target lists)
|
||||
|
|
|
|||
|
|
@ -64,5 +64,8 @@ extern List *BuildOnConflictExcludedTargetlist(Relation targetrel,
|
|||
Index exclRelIndex);
|
||||
|
||||
extern SortGroupClause *makeSortGroupClauseForSetOp(Oid rescoltype, bool require_hash);
|
||||
extern void constructSetOpTargetlist(ParseState *pstate, SetOperationStmt *op,
|
||||
const List *ltargetlist, const List *rtargetlist,
|
||||
List **targetlist, const char *context, bool recursive);
|
||||
|
||||
#endif /* ANALYZE_H */
|
||||
|
|
|
|||
|
|
@ -136,6 +136,7 @@ PG_KEYWORD("delimiters", DELIMITERS, UNRESERVED_KEYWORD, BARE_LABEL)
|
|||
PG_KEYWORD("depends", DEPENDS, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||
PG_KEYWORD("depth", DEPTH, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||
PG_KEYWORD("desc", DESC, RESERVED_KEYWORD, BARE_LABEL)
|
||||
PG_KEYWORD("destination", DESTINATION, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||
PG_KEYWORD("detach", DETACH, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||
PG_KEYWORD("dictionary", DICTIONARY, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||
PG_KEYWORD("disable", DISABLE_P, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||
|
|
@ -147,6 +148,7 @@ PG_KEYWORD("domain", DOMAIN_P, UNRESERVED_KEYWORD, BARE_LABEL)
|
|||
PG_KEYWORD("double", DOUBLE_P, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||
PG_KEYWORD("drop", DROP, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||
PG_KEYWORD("each", EACH, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||
PG_KEYWORD("edge", EDGE, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||
PG_KEYWORD("else", ELSE, RESERVED_KEYWORD, BARE_LABEL)
|
||||
PG_KEYWORD("empty", EMPTY_P, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||
PG_KEYWORD("enable", ENABLE_P, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||
|
|
@ -191,6 +193,8 @@ PG_KEYWORD("generated", GENERATED, UNRESERVED_KEYWORD, BARE_LABEL)
|
|||
PG_KEYWORD("global", GLOBAL, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||
PG_KEYWORD("grant", GRANT, RESERVED_KEYWORD, AS_LABEL)
|
||||
PG_KEYWORD("granted", GRANTED, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||
PG_KEYWORD("graph", GRAPH, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||
PG_KEYWORD("graph_table", GRAPH_TABLE, COL_NAME_KEYWORD, BARE_LABEL)
|
||||
PG_KEYWORD("greatest", GREATEST, COL_NAME_KEYWORD, BARE_LABEL)
|
||||
PG_KEYWORD("group", GROUP_P, RESERVED_KEYWORD, AS_LABEL)
|
||||
PG_KEYWORD("grouping", GROUPING, COL_NAME_KEYWORD, BARE_LABEL)
|
||||
|
|
@ -297,6 +301,7 @@ PG_KEYWORD("nfd", NFD, UNRESERVED_KEYWORD, BARE_LABEL)
|
|||
PG_KEYWORD("nfkc", NFKC, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||
PG_KEYWORD("nfkd", NFKD, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||
PG_KEYWORD("no", NO, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||
PG_KEYWORD("node", NODE, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||
PG_KEYWORD("none", NONE, COL_NAME_KEYWORD, BARE_LABEL)
|
||||
PG_KEYWORD("normalize", NORMALIZE, COL_NAME_KEYWORD, BARE_LABEL)
|
||||
PG_KEYWORD("normalized", NORMALIZED, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||
|
|
@ -361,6 +366,8 @@ PG_KEYWORD("procedural", PROCEDURAL, UNRESERVED_KEYWORD, BARE_LABEL)
|
|||
PG_KEYWORD("procedure", PROCEDURE, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||
PG_KEYWORD("procedures", PROCEDURES, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||
PG_KEYWORD("program", PROGRAM, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||
PG_KEYWORD("properties", PROPERTIES, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||
PG_KEYWORD("property", PROPERTY, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||
PG_KEYWORD("publication", PUBLICATION, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||
PG_KEYWORD("quote", QUOTE, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||
PG_KEYWORD("quotes", QUOTES, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||
|
|
@ -374,6 +381,7 @@ PG_KEYWORD("references", REFERENCES, RESERVED_KEYWORD, BARE_LABEL)
|
|||
PG_KEYWORD("referencing", REFERENCING, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||
PG_KEYWORD("refresh", REFRESH, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||
PG_KEYWORD("reindex", REINDEX, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||
PG_KEYWORD("relationship", RELATIONSHIP, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||
PG_KEYWORD("relative", RELATIVE_P, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||
PG_KEYWORD("release", RELEASE, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||
PG_KEYWORD("rename", RENAME, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||
|
|
@ -496,6 +504,7 @@ PG_KEYWORD("variadic", VARIADIC, RESERVED_KEYWORD, BARE_LABEL)
|
|||
PG_KEYWORD("varying", VARYING, UNRESERVED_KEYWORD, AS_LABEL)
|
||||
PG_KEYWORD("verbose", VERBOSE, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL)
|
||||
PG_KEYWORD("version", VERSION_P, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||
PG_KEYWORD("vertex", VERTEX, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||
PG_KEYWORD("view", VIEW, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||
PG_KEYWORD("views", VIEWS, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||
PG_KEYWORD("virtual", VIRTUAL, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||
|
|
|
|||
24
src/include/parser/parse_graphtable.h
Normal file
24
src/include/parser/parse_graphtable.h
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* parse_graphtable.h
|
||||
* parsing of GRAPH_TABLE
|
||||
*
|
||||
*
|
||||
* Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* src/include/parser/parse_graphtable.h
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef PARSE_GRAPHTABLE_H
|
||||
#define PARSE_GRAPHTABLE_H
|
||||
|
||||
#include "nodes/pg_list.h"
|
||||
#include "parser/parse_node.h"
|
||||
|
||||
extern Node *transformGraphTablePropertyRef(ParseState *pstate, ColumnRef *cref);
|
||||
|
||||
extern Node *transformGraphPattern(ParseState *pstate, GraphPattern *graph_pattern);
|
||||
|
||||
#endif /* PARSE_GRAPHTABLE_H */
|
||||
|
|
@ -82,6 +82,7 @@ typedef enum ParseExprKind
|
|||
EXPR_KIND_COPY_WHERE, /* WHERE condition in COPY FROM */
|
||||
EXPR_KIND_GENERATED_COLUMN, /* generation expression for a column */
|
||||
EXPR_KIND_CYCLE_MARK, /* cycle mark value */
|
||||
EXPR_KIND_PROPGRAPH_PROPERTY, /* derived property expression */
|
||||
} ParseExprKind;
|
||||
|
||||
|
||||
|
|
@ -95,6 +96,21 @@ typedef Node *(*CoerceParamHook) (ParseState *pstate, Param *param,
|
|||
Oid targetTypeId, int32 targetTypeMod,
|
||||
int location);
|
||||
|
||||
/*
|
||||
* Namespace for the GRAPH_TABLE reference being transformed.
|
||||
*
|
||||
* Labels, properties and variables used in the GRAPH_TABLE form the namespace.
|
||||
* The names of the labels and properties used in GRAPH_TABLE are looked up using
|
||||
* the OID of the property graph. Variables are collected in a list as graph
|
||||
* patterns are transformed. This namespace is used to resolve label and property
|
||||
* references in the GRAPH_TABLE.
|
||||
*/
|
||||
typedef struct GraphTableParseState
|
||||
{
|
||||
Oid graphid; /* OID of the graph being referenced */
|
||||
List *variables; /* list of element pattern variables in
|
||||
* GRAPH_TABLE */
|
||||
} GraphTableParseState;
|
||||
|
||||
/*
|
||||
* State information used during parse analysis
|
||||
|
|
@ -174,6 +190,9 @@ typedef Node *(*CoerceParamHook) (ParseState *pstate, Param *param,
|
|||
* p_resolve_unknowns: resolve unknown-type SELECT output columns as type TEXT
|
||||
* (this is true by default).
|
||||
*
|
||||
* p_graph_table_pstate: Namespace for the GRAPH_TABLE reference being
|
||||
* transformed, if any.
|
||||
*
|
||||
* p_hasAggs, p_hasWindowFuncs, etc: true if we've found any of the indicated
|
||||
* constructs in the query.
|
||||
*
|
||||
|
|
@ -216,6 +235,8 @@ struct ParseState
|
|||
* type text */
|
||||
|
||||
QueryEnvironment *p_queryEnv; /* curr env, incl refs to enclosing env */
|
||||
GraphTableParseState *p_graph_table_pstate; /* Current graph table
|
||||
* namespace, if any */
|
||||
|
||||
/* Flags telling about things found in the query: */
|
||||
bool p_hasAggs;
|
||||
|
|
|
|||
|
|
@ -82,6 +82,14 @@ extern ParseNamespaceItem *addRangeTableEntryForTableFunc(ParseState *pstate,
|
|||
Alias *alias,
|
||||
bool lateral,
|
||||
bool inFromCl);
|
||||
extern ParseNamespaceItem *addRangeTableEntryForGraphTable(ParseState *pstate,
|
||||
Oid graphid,
|
||||
GraphPattern *graph_pattern,
|
||||
List *columns,
|
||||
List *colnames,
|
||||
Alias *alias,
|
||||
bool lateral,
|
||||
bool inFromCl);
|
||||
extern ParseNamespaceItem *addRangeTableEntryForJoin(ParseState *pstate,
|
||||
List *colnames,
|
||||
ParseNamespaceColumn *nscolumns,
|
||||
|
|
|
|||
21
src/include/rewrite/rewriteGraphTable.h
Normal file
21
src/include/rewrite/rewriteGraphTable.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* rewriteGraphTable.h
|
||||
* Support for rewriting GRAPH_TABLE clauses.
|
||||
*
|
||||
*
|
||||
* Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* src/include/rewrite/rewriteGraphTable.h
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef REWRITEGRAPHTABLE_H
|
||||
#define REWRITEGRAPHTABLE_H
|
||||
|
||||
#include "nodes/parsenodes.h"
|
||||
|
||||
extern Query *rewriteGraphTable(Query *parsetree, int rt_index);
|
||||
|
||||
#endif /* REWRITEGRAPHTABLE_H */
|
||||
|
|
@ -48,6 +48,7 @@ PG_CMDTAG(CMDTAG_ALTER_OPERATOR_CLASS, "ALTER OPERATOR CLASS", true, false, fals
|
|||
PG_CMDTAG(CMDTAG_ALTER_OPERATOR_FAMILY, "ALTER OPERATOR FAMILY", true, false, false)
|
||||
PG_CMDTAG(CMDTAG_ALTER_POLICY, "ALTER POLICY", true, false, false)
|
||||
PG_CMDTAG(CMDTAG_ALTER_PROCEDURE, "ALTER PROCEDURE", true, false, false)
|
||||
PG_CMDTAG(CMDTAG_ALTER_PROPERTY_GRAPH, "ALTER PROPERTY GRAPH", true, false, false)
|
||||
PG_CMDTAG(CMDTAG_ALTER_PUBLICATION, "ALTER PUBLICATION", true, false, false)
|
||||
PG_CMDTAG(CMDTAG_ALTER_ROLE, "ALTER ROLE", false, false, false)
|
||||
PG_CMDTAG(CMDTAG_ALTER_ROUTINE, "ALTER ROUTINE", true, false, false)
|
||||
|
|
@ -103,6 +104,7 @@ PG_CMDTAG(CMDTAG_CREATE_OPERATOR_CLASS, "CREATE OPERATOR CLASS", true, false, fa
|
|||
PG_CMDTAG(CMDTAG_CREATE_OPERATOR_FAMILY, "CREATE OPERATOR FAMILY", true, false, false)
|
||||
PG_CMDTAG(CMDTAG_CREATE_POLICY, "CREATE POLICY", true, false, false)
|
||||
PG_CMDTAG(CMDTAG_CREATE_PROCEDURE, "CREATE PROCEDURE", true, false, false)
|
||||
PG_CMDTAG(CMDTAG_CREATE_PROPERTY_GRAPH, "CREATE PROPERTY GRAPH", true, false, false)
|
||||
PG_CMDTAG(CMDTAG_CREATE_PUBLICATION, "CREATE PUBLICATION", true, false, false)
|
||||
PG_CMDTAG(CMDTAG_CREATE_ROLE, "CREATE ROLE", false, false, false)
|
||||
PG_CMDTAG(CMDTAG_CREATE_ROUTINE, "CREATE ROUTINE", true, false, false)
|
||||
|
|
@ -156,6 +158,7 @@ PG_CMDTAG(CMDTAG_DROP_OPERATOR_FAMILY, "DROP OPERATOR FAMILY", true, false, fals
|
|||
PG_CMDTAG(CMDTAG_DROP_OWNED, "DROP OWNED", true, false, false)
|
||||
PG_CMDTAG(CMDTAG_DROP_POLICY, "DROP POLICY", true, false, false)
|
||||
PG_CMDTAG(CMDTAG_DROP_PROCEDURE, "DROP PROCEDURE", true, false, false)
|
||||
PG_CMDTAG(CMDTAG_DROP_PROPERTY_GRAPH, "DROP PROPERTY GRAPH", true, false, false)
|
||||
PG_CMDTAG(CMDTAG_DROP_PUBLICATION, "DROP PUBLICATION", true, false, false)
|
||||
PG_CMDTAG(CMDTAG_DROP_ROLE, "DROP ROLE", false, false, false)
|
||||
PG_CMDTAG(CMDTAG_DROP_ROUTINE, "DROP ROUTINE", true, false, false)
|
||||
|
|
|
|||
|
|
@ -166,6 +166,7 @@ typedef struct ArrayType Acl;
|
|||
#define ACL_ALL_RIGHTS_LANGUAGE (ACL_USAGE)
|
||||
#define ACL_ALL_RIGHTS_LARGEOBJECT (ACL_SELECT|ACL_UPDATE)
|
||||
#define ACL_ALL_RIGHTS_PARAMETER_ACL (ACL_SET|ACL_ALTER_SYSTEM)
|
||||
#define ACL_ALL_RIGHTS_PROPGRAPH (ACL_SELECT)
|
||||
#define ACL_ALL_RIGHTS_SCHEMA (ACL_USAGE|ACL_CREATE)
|
||||
#define ACL_ALL_RIGHTS_TABLESPACE (ACL_CREATE)
|
||||
#define ACL_ALL_RIGHTS_TYPE (ACL_USAGE)
|
||||
|
|
|
|||
|
|
@ -213,6 +213,9 @@ extern char *get_publication_name(Oid pubid, bool missing_ok);
|
|||
extern Oid get_subscription_oid(const char *subname, bool missing_ok);
|
||||
extern char *get_subscription_name(Oid subid, bool missing_ok);
|
||||
|
||||
extern char *get_propgraph_label_name(Oid labeloid);
|
||||
extern char *get_propgraph_property_name(Oid propoid);
|
||||
|
||||
#define type_is_array(typid) (get_element_type(typid) != InvalidOid)
|
||||
/* type_is_array_domain accepts both plain arrays and domains over arrays */
|
||||
#define type_is_array_domain(typid) (get_base_element_type(typid) != InvalidOid)
|
||||
|
|
|
|||
|
|
@ -335,6 +335,8 @@ less_equals "<="
|
|||
greater_equals ">="
|
||||
less_greater "<>"
|
||||
not_equals "!="
|
||||
/* Note there is no need for left_arrow, since "<-" is not a single operator. */
|
||||
right_arrow "->"
|
||||
|
||||
/*
|
||||
* "self" is the set of chars that should be returned as single-character
|
||||
|
|
@ -346,7 +348,7 @@ not_equals "!="
|
|||
* If you change either set, adjust the character lists appearing in the
|
||||
* rule for "operator"!
|
||||
*/
|
||||
self [,()\[\].;\:\+\-\*\/\%\^\<\>\=]
|
||||
self [,()\[\].;\:\|\+\-\*\/\%\^\<\>\=]
|
||||
op_chars [\~\!\@\#\^\&\|\`\?\+\-\*\/\%\<\>\=]
|
||||
operator {op_chars}+
|
||||
|
||||
|
|
@ -854,6 +856,10 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+
|
|||
return NOT_EQUALS;
|
||||
}
|
||||
|
||||
{right_arrow} {
|
||||
return RIGHT_ARROW;
|
||||
}
|
||||
|
||||
{informix_special} {
|
||||
/* are we simulating Informix? */
|
||||
if (INFORMIX_MODE)
|
||||
|
|
@ -947,7 +953,7 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+
|
|||
* that the "self" rule would have.
|
||||
*/
|
||||
if (nchars == 1 &&
|
||||
strchr(",()[].;:+-*/%^<>=", yytext[0]))
|
||||
strchr(",()[].;:|+-*/%^<>=", yytext[0]))
|
||||
return yytext[0];
|
||||
|
||||
/*
|
||||
|
|
@ -968,6 +974,8 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+
|
|||
return NOT_EQUALS;
|
||||
if (yytext[0] == '!' && yytext[1] == '=')
|
||||
return NOT_EQUALS;
|
||||
if (yytext[0] == '-' && yytext[1] == '>')
|
||||
return RIGHT_ARROW;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ test: sql/quote
|
|||
test: sql/show
|
||||
test: sql/sqljson
|
||||
test: sql/sqljson_jsontable
|
||||
test: sql/sqlpgq
|
||||
test: sql/insupd
|
||||
test: sql/parser
|
||||
test: sql/prepareas
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue