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)
-
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 RTE kind unchanged in future, print
- * correct name of RTE kind.
- */
- kind = "graph_table";
- break;
}
/* Begin group for this specific RTE */
case RELKIND_PARTITIONED_INDEX:
relkind = "partitioned_index";
break;
- case RELKIND_PROPGRAPH:
- relkind = "property_graph";
- break;
case '\0':
relkind = NULL;
break;
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
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));
<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>
<literal>c</literal> = composite type,
<literal>f</literal> = foreign table,
<literal>p</literal> = partitioned table,
- <literal>I</literal> = partitioned index,
- <literal>g</literal> = property graph
+ <literal>I</literal> = partitioned index
</para></entry>
</row>
</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>
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.
<entry><literal>r</literal> (<quote>read</quote>)</entry>
<entry>
<literal>LARGE OBJECT</literal>,
- <literal>PROPERTY GRAPH</literal>,
<literal>SEQUENCE</literal>,
<literal>TABLE</literal> (and table-like objects),
table column
<entry>none</entry>
<entry><literal>\dconfig+</literal></entry>
</row>
- <row>
- <entry><literal>PROPERTY GRAPH</literal></entry>
- <entry><literal>r</literal></entry>
- <entry>none</entry>
- <entry><literal>\dp</literal></entry>
- </row>
<row>
<entry><literal>SCHEMA</literal></entry>
<entry><literal>UC</literal></entry>
</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 practitioners 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-createpropertygraph"><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>
<para>
The <productname>PostgreSQL</productname> core covers parts 1, 2, 9,
- 11, 14, and 16. Part 3 is covered by the ODBC driver, and part 13 is
+ 11, and 14. 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, and 15
+ implementations of parts 4, 10, 15, and 16
for <productname>PostgreSQL</productname>.
</para>
</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>
</table>
</sect1>
- <sect1 id="infoschema-pg-edge-table-components">
- <title><literal>pg_edge_table_components</literal></title>
-
- <para>
- The view <literal>pg_edge_table_components</literal> identifies which
- columns are part of the source or destination vertex keys, as well as their
- corresponding columns in the vertex tables being linked to, in the edge
- tables of property graphs defined in the current database. Only those
- property graphs are shown that the current user has access to (by way of
- being the owner or having some privilege).
- </para>
-
- <para>
- The source and destination vertex links of edge tables are specified in
- <command>CREATE PROPERTY GRAPH</command> and default to foreign keys in
- certain cases.
- </para>
-
- <table>
- <title><structname>pg_edge_table_components</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>property_graph_catalog</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Name of the database that contains the property graph (always the current database)
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>property_graph_schema</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Name of the schema that contains the property graph
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>property_graph_name</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Name of the property graph
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>edge_table_alias</structfield> <type>sql_identifier</type>
- </para>
- <para>
- The element table alias of the edge table being described
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>vertex_table_alias</structfield> <type>sql_identifier</type>
- </para>
- <para>
- The element table alias of the source or destination vertex table being linked to
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>edge_end</structfield> <type>character_data</type>
- </para>
- <para>
- Either <literal>SOURCE</literal> or <literal>DESTINATION</literal>;
- specifies which edge link is being described.
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>edge_table_column_name</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Name of the column that is part of the source or destination vertex key in this edge table
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>vertex_table_column_name</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Name of the column that is part of the key in the source or destination
- vertex table being linked to
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>ordinal_position</structfield> <type>cardinal_number</type>
- </para>
- <para>
- Ordinal position of the columns within the key (count starts at 1)
- </para></entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- </sect1>
-
- <sect1 id="infoschema-pg-element-table-key-columns">
- <title><literal>pg_element_table_key_columns</literal></title>
-
- <para>
- The view <literal>pg_element_table_key_columns</literal> identifies which
- columns are part of the keys of the element tables of property graphs defined
- in the current database. Only those property graphs are shown that the
- current user has access to (by way of being the owner or having some
- privilege).
- </para>
-
- <para>
- The key of an element table uniquely identifies the rows in it. It is
- either specified using the <literal>KEY</literal> clause in <command>CREATE
- PROPERTY GRAPH</command> or defaults to the primary key.
- </para>
-
- <table>
- <title><structname>pg_element_table_key_columns</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>property_graph_catalog</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Name of the database that contains the property graph (always the current database)
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>property_graph_schema</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Name of the schema that contains the property graph
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>property_graph_name</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Name of the property graph
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>element_table_alias</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Element table alias (unique identifier of an element table within a
- property graph)
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>column_name</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Name of the column that is part of the key
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>ordinal_position</structfield> <type>cardinal_number</type>
- </para>
- <para>
- Ordinal position of the column within the key (count starts at 1)
- </para></entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- </sect1>
-
- <sect1 id="infoschema-pg-element-table-labels">
- <title><literal>pg_element_table_labels</literal></title>
-
- <para>
- The view <literal>pg_element_table_labels</literal> shows which labels are
- defined on the element tables of property graphs defined in the current
- database. Only those property graphs are shown that the current user has
- access to (by way of being the owner or having some privilege).
- </para>
-
- <table>
- <title><structname>pg_element_table_labels</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>property_graph_catalog</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Name of the database that contains the property graph (always the current database)
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>property_graph_schema</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Name of the schema that contains the property graph
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>property_graph_name</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Name of the property graph
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>element_table_alias</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Element table alias (unique identifier of an element table within a
- property graph)
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>label_name</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Name of the label
- </para></entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- </sect1>
-
- <sect1 id="infoschema-pg-element-table-properties">
- <title><literal>pg_element_table_properties</literal></title>
-
- <para>
- The view <literal>pg_element_table_properties</literal> shows the definitions
- of the properties for the element tables of property graphs defined in the
- current database. Only those property graphs are shown that the current user
- has access to (by way of being the owner or having some privilege).
- </para>
-
- <table>
- <title><structname>pg_element_table_properties</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>property_graph_catalog</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Name of the database that contains the property graph (always the current database)
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>property_graph_schema</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Name of the schema that contains the property graph
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>property_graph_name</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Name of the property graph
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>element_table_alias</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Element table alias (unique identifier of an element table within a
- property graph)
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>property_name</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Name of the property
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>property_expression</structfield> <type>character_data</type>
- </para>
- <para>
- Expression of the property definition for this element table
- </para></entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- </sect1>
-
- <sect1 id="infoschema-pg-element-tables">
- <title><literal>pg_element_tables</literal></title>
-
- <para>
- The view <literal>pg_element_tables</literal> contains information about
- the element tables of property graphs defined in the current database.
- Only those property graphs are shown that the current user has access to
- (by way of being the owner or having some privilege).
- </para>
-
- <table>
- <title><structname>pg_element_tables</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>property_graph_catalog</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Name of the database that contains the property graph (always the current database)
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>property_graph_schema</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Name of the schema that contains the property graph
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>property_graph_name</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Name of the property graph
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>element_table_alias</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Element table alias (unique identifier of an element table within a
- property graph)
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>element_table_kind</structfield> <type>character_data</type>
- </para>
- <para>
- The kind of the element table: <literal>EDGE</literal> or <literal>VERTEX</literal>
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>table_catalog</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Name of the database that contains the referenced table (always the current database)
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>table_schema</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Name of the schema that contains the referenced table
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>table_name</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Name of the table being referenced by the element table definition
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>element_table_definition</structfield> <type>character_data</type>
- </para>
- <para>
- Applies to a feature not available in <productname>PostgreSQL</productname>
- </para></entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- </sect1>
-
- <sect1 id="infoschema-pg-label-properties">
- <title><literal>pg_label_properties</literal></title>
-
- <para>
- The view <literal>pg_label_properties</literal> shows which properties are
- defined on labels defined in property graphs defined in the current
- database. Only those property graphs are shown that the current user has
- access to (by way of being the owner or having some privilege).
- </para>
-
- <table>
- <title><structname>pg_label_properties</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>property_graph_catalog</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Name of the database that contains the property graph (always the current database)
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>property_graph_schema</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Name of the schema that contains the property graph
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>property_graph_name</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Name of the property graph
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>label_name</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Name of the label
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>property_name</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Name of the property
- </para></entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- </sect1>
-
- <sect1 id="infoschema-pg-labels">
- <title><literal>pg_labels</literal></title>
-
- <para>
- The view <literal>pg_labels</literal> contains all the labels defined in
- property graphs defined in the current database. Only those property
- graphs are shown that the current user has access to (by way of being the
- owner or having some privilege).
- </para>
-
- <table>
- <title><structname>pg_labels</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>property_graph_catalog</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Name of the database that contains the property graph (always the current database)
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>property_graph_schema</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Name of the schema that contains the property graph
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>property_graph_name</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Name of the property graph
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>label_name</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Name of the label
- </para></entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- </sect1>
-
- <sect1 id="infoschema-pg-property-data-types">
- <title><literal>pg_property_data_types</literal></title>
-
- <para>
- The view <literal>pg_property_data_types</literal> shows the data types of
- the properties in property graphs defined in the current database. Only
- those property graphs are shown that the current user has access to (by way
- of being the owner or having some privilege).
- </para>
-
- <table>
- <title><structname>pg_property_data_types</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>property_graph_catalog</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Name of the database that contains the property graph (always the current database)
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>property_graph_schema</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Name of the schema that contains the property graph
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>property_graph_name</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Name of the property graph
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>property_name</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Name of the property
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>data_type</structfield> <type>character_data</type>
- </para>
- <para>
- Data type of the property, if it is a built-in type, or
- <literal>ARRAY</literal> if it is some array (in that case, see the
- view <literal>element_types</literal>), else
- <literal>USER-DEFINED</literal> (in that case, the type is identified
- in <literal>attribute_udt_name</literal> and associated columns).
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>character_maximum_length</structfield> <type>cardinal_number</type>
- </para>
- <para>
- If <literal>data_type</literal> identifies a character or bit
- string type, the declared maximum length; null for all other
- data types or if no maximum length was declared.
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>character_octet_length</structfield> <type>cardinal_number</type>
- </para>
- <para>
- If <literal>data_type</literal> identifies a character type,
- the maximum possible length in octets (bytes) of a datum; null
- for all other data types. The maximum octet length depends on
- the declared character maximum length (see above) and the
- server encoding.
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>character_set_catalog</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Applies to a feature not available in <productname>PostgreSQL</productname>
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>character_set_schema</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Applies to a feature not available in <productname>PostgreSQL</productname>
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>character_set_name</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Applies to a feature not available in <productname>PostgreSQL</productname>
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>collation_catalog</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Name of the database containing the collation of the property (always
- the current database), null if default or the data type of the
- property is not collatable
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>collation_schema</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Name of the schema containing the collation of the property, null if
- default or the data type of the property is not collatable
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>collation_name</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Name of the collation of the property, null if default or the data type
- of the property is not collatable
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>numeric_precision</structfield> <type>cardinal_number</type>
- </para>
- <para>
- If <literal>data_type</literal> identifies a numeric type, this
- column contains the (declared or implicit) precision of the
- type for this attribute. The precision indicates the number of
- significant digits. It can be expressed in decimal (base 10)
- or binary (base 2) terms, as specified in the column
- <literal>numeric_precision_radix</literal>. For all other data
- types, this column is null.
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>numeric_precision_radix</structfield> <type>cardinal_number</type>
- </para>
- <para>
- If <literal>data_type</literal> identifies a numeric type, this
- column indicates in which base the values in the columns
- <literal>numeric_precision</literal> and
- <literal>numeric_scale</literal> are expressed. The value is
- either 2 or 10. For all other data types, this column is null.
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>numeric_scale</structfield> <type>cardinal_number</type>
- </para>
- <para>
- If <literal>data_type</literal> identifies an exact numeric
- type, this column contains the (declared or implicit) scale of
- the type for this attribute. The scale indicates the number of
- significant digits to the right of the decimal point. It can
- be expressed in decimal (base 10) or binary (base 2) terms, as
- specified in the column
- <literal>numeric_precision_radix</literal>. For all other data
- types, this column is null.
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>datetime_precision</structfield> <type>cardinal_number</type>
- </para>
- <para>
- If <literal>data_type</literal> identifies a date, time,
- timestamp, or interval type, this column contains the (declared
- or implicit) fractional seconds precision of the type for this
- attribute, that is, the number of decimal digits maintained
- following the decimal point in the seconds value. For all
- other data types, this column is null.
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>interval_type</structfield> <type>character_data</type>
- </para>
- <para>
- If <literal>data_type</literal> identifies an interval type,
- this column contains the specification which fields the
- intervals include for this attribute, e.g., <literal>YEAR TO
- MONTH</literal>, <literal>DAY TO SECOND</literal>, etc. If no
- field restrictions were specified (that is, the interval
- accepts all fields), and for all other data types, this field
- is null.
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>interval_precision</structfield> <type>cardinal_number</type>
- </para>
- <para>
- Applies to a feature not available
- in <productname>PostgreSQL</productname>
- (see <literal>datetime_precision</literal> for the fractional
- seconds precision of interval type properties)
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>user_defined_type_catalog</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Name of the database that the property data type is defined in
- (always the current database)
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>user_defined_type_schema</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Name of the schema that the property data type is defined in
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>user_defined_type_name</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Name of the property data type
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>scope_catalog</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Applies to a feature not available in <productname>PostgreSQL</productname>
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>scope_schema</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Applies to a feature not available in <productname>PostgreSQL</productname>
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>scope_name</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Applies to a feature not available in <productname>PostgreSQL</productname>
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>maximum_cardinality</structfield> <type>cardinal_number</type>
- </para>
- <para>
- Always null, because arrays always have unlimited maximum cardinality in <productname>PostgreSQL</productname>
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>dtd_identifier</structfield> <type>sql_identifier</type>
- </para>
- <para>
- An identifier of the data type descriptor of the property, unique
- among the data type descriptors pertaining to the property graph. This
- is mainly useful for joining with other instances of such
- identifiers. (The specific format of the identifier is not
- defined and not guaranteed to remain the same in future
- versions.)
- </para></entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- </sect1>
-
- <sect1 id="infoschema-pg-property-graph-privileges">
- <title><literal>pg_property_graph_privileges</literal></title>
-
- <para>
- The view <literal>pg_property_graph_privileges</literal> identifies all
- privileges granted on property graphs to a currently enabled role or by a
- currently enabled role. There is one row for each combination of property
- graph, grantor, and grantee.
- </para>
-
- <table>
- <title><structname>pg_property_graph_privileges</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>grantor</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Name of the role that granted the privilege
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>grantee</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Name of the role that the privilege was granted to
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>property_graph_catalog</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Name of the database that contains the property graph (always the current database)
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>property_graph_schema</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Name of the schema that contains the property graph
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>property_graph_name</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Name of the property graph
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>privilege_type</structfield> <type>character_data</type>
- </para>
- <para>
- Type of the privilege: <literal>SELECT</literal> is the only privilege
- type applicable to property graphs.
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>is_grantable</structfield> <type>yes_or_no</type>
- </para>
- <para>
- <literal>YES</literal> if the privilege is grantable, <literal>NO</literal> if not
- </para></entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- </sect1>
-
- <sect1 id="infoschema-property-graphs">
- <title><literal>property_graphs</literal></title>
-
- <para>
- The view <literal>property_graphs</literal> contains all property graphs
- defined in the current database. Only those property graphs are shown that
- the current user has access to (by way of being the owner or having some
- privilege).
- </para>
-
- <table>
- <title><structname>property_graphs</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>property_graph_catalog</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Name of the database that contains the property graph (always the current database)
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>property_graph_schema</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Name of the schema that contains the property graph
- </para></entry>
- </row>
-
- <row>
- <entry role="catalog_table_entry"><para role="column_definition">
- <structfield>property_graph_name</structfield> <type>sql_identifier</type>
- </para>
- <para>
- Name of the property graph
- </para></entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- </sect1>
-
<sect1 id="infoschema-referential-constraints">
<title><literal>referential_constraints</literal></title>
+++ /dev/null
-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
+++ /dev/null
-ALL_DIFFERENT
-BINDING_COUNT
-ELEMENT_ID
-ELEMENT_NUMBER
-EXPORT
-GRAPH
-GRAPH_TABLE
-MATCHNUM
-PATH_LENGTH
-PATH_NAME
-PROPERTY_EXISTS
-SAME
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
</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 expression 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>
<!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">
<!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">
<!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">
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> |
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, property graphs, routines, sequences, text search objects,
+ operator classes, operator families, procedures, routines, sequences, text search objects,
types, and views can be schema-qualified.
</para>
</listitem>
+++ /dev/null
-<!--
-doc/src/sgml/ref/alter_property_graph.sgml
-PostgreSQL documentation
--->
-
-<refentry id="sql-alterpropertygraph">
- <indexterm zone="sql-alterpropertygraph">
- <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-createpropertygraph"><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
- themselves 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-createpropertygraph"><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. The
- last label on an element table cannot be dropped; every vertex or edge
- table must have at least one label.
- </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-createpropertygraph"><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-createpropertygraph"><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-createpropertygraph-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-createpropertygraph"/></member>
- <member><xref linkend="sql-droppropertygraph"/></member>
- </simplelist>
- </refsect1>
-</refentry>
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> [, ...] ] ) ] |
+++ /dev/null
-<!--
-doc/src/sgml/ref/create_property_graph.sgml
-PostgreSQL documentation
--->
-
-<refentry id="sql-createpropertygraph">
- <indexterm zone="sql-createpropertygraph">
- <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 a new 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-createpropertygraph-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-alterpropertygraph"/></member>
- <member><xref linkend="sql-droppropertygraph"/></member>
- </simplelist>
- </refsect1>
-</refentry>
+++ /dev/null
-<!--
-doc/src/sgml/ref/drop_property_graph.sgml
-PostgreSQL documentation
--->
-
-<refentry id="sql-droppropertygraph">
- <indexterm zone="sql-droppropertygraph">
- <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-createpropertygraph"/></member>
- <member><xref linkend="sql-alterpropertygraph"/></member>
- </simplelist>
- </refsect1>
-</refentry>
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 ]
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, property graph, schema, tablespace, or type), and one that grants
+ parameter, 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>
<listitem>
<para>
- For each relation (table, view, materialized view, index, property graph, sequence,
+ For each relation (table, view, materialized view, index, sequence,
or foreign table)
or composite type matching the
<replaceable class="parameter">pattern</replaceable>, show all
<para>
If <command>\d</command> is used without a
<replaceable class="parameter">pattern</replaceable> argument, it is
- equivalent to <command>\dtvmsEG</command> which will show a list of
- all visible tables, views, materialized views, sequences,
- foreign tables, and property graphs.
+ equivalent to <command>\dtvmsE</command> which will show a list of
+ all visible tables, views, materialized views, sequences and
+ foreign tables.
This is purely a convenience measure.
</para>
<para>
<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>
<listitem>
<para>
- In this group of commands, the letters <literal>E</literal>, <literal>G</literal>,
+ In this group of commands, the letters <literal>E</literal>,
<literal>i</literal>, <literal>m</literal>, <literal>s</literal>,
<literal>t</literal>, and <literal>v</literal>
- stand for foreign table, index, property graph, materialized view,
+ stand for foreign table, index, materialized view,
sequence, table, and view,
respectively.
You can specify any or all of
[ 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> [, ...]
[ 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>
</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-createpropertygraph"/>).
- </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>
&alterOperatorFamily;
&alterPolicy;
&alterProcedure;
- &alterPropertyGraph;
&alterPublication;
&alterRole;
&alterRoutine;
&createOperatorFamily;
&createPolicy;
&createProcedure;
- &createPropertyGraph;
&createPublication;
&createRole;
&createRule;
&dropOwned;
&dropPolicy;
&dropProcedure;
- &dropPropertyGraph;
&dropPublication;
&dropRole;
&dropRoutine;
</para>
<itemizedlist>
- <listitem>
- <para>
- Support for
- <link linkend="ddl-property-graphs">property graph queries</link>
- (<acronym>SQL/PGQ</acronym>).
- </para>
- </listitem>
-
<listitem>
<para>
A new <link linkend="sql-repack"><command>REPACK</command></link> command
<title>Query Commands</title>
<itemizedlist>
-<!--
-Author: Peter Eisentraut <peter@eisentraut.org>
-2026-03-16 [2f094e7ac] SQL Property Graph Queries (SQL/PGQ)
-Author: Peter Eisentraut <peter@eisentraut.org>
-2026-03-31 [c5b3253b8] Property references are preferred over regular column re
-Author: Peter Eisentraut <peter@eisentraut.org>
-2026-03-31 [a0dd0702e] Fix cross variable references in graph pattern causing s
--->
-
-<listitem>
-<para>
-Add support for <acronym>SQL</acronym> Property Graph Queries (<acronym>SQL</acronym>/<acronym>PGQ</acronym>) (Peter Eisentraut, Ashutosh Bapat)
-<ulink url="&commit_baseurl;2f094e7ac">§</ulink>
-<ulink url="&commit_baseurl;c5b3253b8">§</ulink>
-<ulink url="&commit_baseurl;a0dd0702e">§</ulink>
-</para>
-
-<para>
-Internally these are processed like views so are written as standard relational queries.
-</para>
-</listitem>
-
<!--
Author: Peter Eisentraut <peter@eisentraut.org>
2026-04-01 [8e72d914c] Add UPDATE/DELETE FOR PORTION OF
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 */
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);
{
case OBJECT_TABLE:
case OBJECT_SEQUENCE:
- case OBJECT_PROPGRAPH:
ExecGrant_Relation(istmt);
break;
case OBJECT_DATABASE:
case OBJECT_TABLE:
case OBJECT_SEQUENCE:
- case OBJECT_PROPGRAPH:
/*
* Here, we don't use get_object_address(). It requires that the
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:
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);
}
/*
- * This processes all pg_class entries including sequences and property graphs.
+ * This processes both sequences and non-sequences.
*/
static void
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;
}
this_privileges &= (AclMode) ACL_ALL_RIGHTS_SEQUENCE;
}
}
- else if (pg_class_tuple->relkind == RELKIND_PROPGRAPH)
- {
- /*
- * Do not allow GRANT ... TABLE on property graph. We allowed
- * it on sequences for backward compatibility but there is no
- * reason to continue that further.
- */
- ereport(ERROR,
- errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("\"%s\" is a property graph", NameStr(pg_class_tuple->relname)),
- errhint("Use GRANT ... ON PROPERTY GRAPH instead."));
- }
else
{
if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_RELATION))
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;
case RELKIND_SEQUENCE:
objtype = OBJECT_SEQUENCE;
break;
- case RELKIND_PROPGRAPH:
- objtype = OBJECT_PROPGRAPH;
- break;
default:
objtype = OBJECT_TABLE;
break;
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;
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;
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);
case RELKIND_SEQUENCE:
acl = acldefault(OBJECT_SEQUENCE, ownerId);
break;
- case RELKIND_PROPGRAPH:
- acl = acldefault(OBJECT_PROPGRAPH, ownerId);
- break;
default:
acl = acldefault(OBJECT_TABLE, ownerId);
break;
#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"
case AccessMethodRelationId:
case AccessMethodOperatorRelationId:
case AccessMethodProcedureRelationId:
- case PropgraphElementRelationId:
- case PropgraphElementLabelRelationId:
- case PropgraphLabelRelationId:
- case PropgraphLabelPropertyRelationId:
- case PropgraphPropertyRelationId:
case NamespaceRelationId:
case TSParserRelationId:
case TSDictionaryRelationId:
add_object_address(TypeRelationId, rowexpr->row_typeid, 0,
context->addrs);
}
- else if (IsA(node, GraphLabelRef))
- {
- GraphLabelRef *glr = (GraphLabelRef *) node;
-
- /* GRAPH_TABLE label reference depends on the property graph label */
- add_object_address(PropgraphLabelRelationId, glr->labelid, 0,
- context->addrs);
- }
- else if (IsA(node, GraphPropertyRef))
- {
- GraphPropertyRef *gpr = (GraphPropertyRef *) node;
-
- /*
- * GRAPH_TABLE property reference depends on the property graph
- * property
- */
- add_object_address(PropgraphPropertyRelationId, gpr->propid, 0,
- context->addrs);
- }
else if (IsA(node, RowCompareExpr))
{
RowCompareExpr *rcexpr = (RowCompareExpr *) node;
switch (rte->rtekind)
{
case RTE_RELATION:
- case RTE_GRAPH_TABLE:
add_object_address(RelationRelationId, rte->relid, 0,
context->addrs);
break;
/*
* Decide whether to create a pg_type entry for the relation's rowtype.
* These types are made except where the use of a relation as such is an
- * implementation detail: toast tables, sequences, indexes, and property
- * graphs.
+ * implementation detail: toast tables, sequences and indexes.
*/
if (!(relkind == RELKIND_SEQUENCE ||
relkind == RELKIND_TOASTVALUE ||
relkind == RELKIND_INDEX ||
- relkind == RELKIND_PARTITIONED_INDEX ||
- relkind == RELKIND_PROPGRAPH))
+ relkind == RELKIND_PARTITIONED_INDEX))
{
Oid new_array_oid;
ObjectAddress new_type_addr;
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('g', 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;
#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"
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,
{
"foreign table", OBJECT_FOREIGN_TABLE
},
- {
- "property graph", OBJECT_PROPGRAPH
- },
{
"table column", OBJECT_COLUMN
},
{
"policy", OBJECT_POLICY
},
- {
- "property graph element", -1
- },
- {
- "property graph element label", -1
- },
- {
- "property graph label", -1
- },
- {
- "property graph label property", -1
- },
- {
- "property graph property", -1
- },
{
"publication", OBJECT_PUBLICATION
},
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,
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,
case OBJECT_MATVIEW:
case OBJECT_INDEX:
case OBJECT_FOREIGN_TABLE:
- case OBJECT_PROPGRAPH:
case OBJECT_COLUMN:
case OBJECT_ATTRIBUTE:
case OBJECT_COLLATION:
case OBJECT_VIEW:
case OBJECT_MATVIEW:
case OBJECT_FOREIGN_TABLE:
- case OBJECT_PROPGRAPH:
case OBJECT_COLUMN:
case OBJECT_RULE:
case OBJECT_TRIGGER:
break;
}
- case PropgraphElementRelationId:
- {
- HeapTuple tup;
- Form_pg_propgraph_element pgeform;
- StringInfoData rel;
-
- 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);
-
- initStringInfo(&rel);
- getRelationDescription(&rel, pgeform->pgepgid, false);
-
- if (pgeform->pgekind == PGEKIND_VERTEX)
- appendStringInfo(&buffer, _("vertex %s of %s"), NameStr(pgeform->pgealias), rel.data);
- else if (pgeform->pgekind == PGEKIND_EDGE)
- appendStringInfo(&buffer, _("edge %s of %s"), NameStr(pgeform->pgealias), rel.data);
- else
- appendStringInfo(&buffer, "??? element %s of %s", NameStr(pgeform->pgealias), rel.data);
-
- pfree(rel.data);
- ReleaseSysCache(tup);
- break;
- }
-
- case PropgraphElementLabelRelationId:
- {
- Relation rel;
- HeapTuple tuple;
- Form_pg_propgraph_element_label pgelform;
- ObjectAddress oa;
-
- rel = table_open(PropgraphElementLabelRelationId, AccessShareLock);
- tuple = get_catalog_object_by_oid(rel,
- Anum_pg_propgraph_element_label_oid,
- object->objectId);
- if (!HeapTupleIsValid(tuple))
- {
- if (!missing_ok)
- elog(ERROR, "could not find tuple for element label %u", object->objectId);
-
- table_close(rel, AccessShareLock);
- break;
- }
-
- pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tuple);
-
- ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
- appendStringInfo(&buffer, _("label %s of %s"),
- get_propgraph_label_name(pgelform->pgellabelid),
- getObjectDescription(&oa, false));
-
- table_close(rel, AccessShareLock);
- break;
- }
-
- case PropgraphLabelRelationId:
- {
- HeapTuple tuple;
- Form_pg_propgraph_label pglform;
- StringInfoData rel;
-
- tuple = SearchSysCache1(PROPGRAPHLABELOID, ObjectIdGetDatum(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);
-
- initStringInfo(&rel);
- getRelationDescription(&rel, pglform->pglpgid, false);
-
- appendStringInfo(&buffer, _("label %s of %s"), NameStr(pglform->pgllabel), rel.data);
-
- pfree(rel.data);
- ReleaseSysCache(tuple);
- break;
- }
-
- case PropgraphLabelPropertyRelationId:
- {
- Relation rel;
- HeapTuple tuple;
- Form_pg_propgraph_label_property plpform;
- ObjectAddress oa;
-
- rel = table_open(PropgraphLabelPropertyRelationId, AccessShareLock);
- tuple = get_catalog_object_by_oid(rel,
- Anum_pg_propgraph_label_property_oid,
- object->objectId);
- if (!HeapTupleIsValid(tuple))
- {
- if (!missing_ok)
- elog(ERROR, "could not find tuple for label property %u", object->objectId);
-
- table_close(rel, AccessShareLock);
- break;
- }
-
- plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tuple);
-
- ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
-
- appendStringInfo(&buffer, _("property %s of %s"),
- get_propgraph_property_name(plpform->plppropid),
- getObjectDescription(&oa, false));
-
- table_close(rel, AccessShareLock);
- break;
- }
-
- case PropgraphPropertyRelationId:
- {
- HeapTuple tuple;
- Form_pg_propgraph_property pgpform;
- StringInfoData rel;
-
- tuple = SearchSysCache1(PROPGRAPHPROPOID, ObjectIdGetDatum(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);
-
- initStringInfo(&rel);
- getRelationDescription(&rel, pgpform->pgppgid, false);
-
- appendStringInfo(&buffer, _("property %s of %s"), NameStr(pgpform->pgpname), rel.data);
-
- pfree(rel.data);
- ReleaseSysCache(tuple);
- break;
- }
-
case PublicationRelationId:
{
char *pubname = get_publication_name(object->objectId,
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"),
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 PropgraphElementLabelRelationId:
- appendStringInfoString(&buffer, "property graph element label");
- break;
-
- case PropgraphLabelPropertyRelationId:
- appendStringInfoString(&buffer, "property graph label property");
- break;
-
case PublicationRelationId:
appendStringInfoString(&buffer, "publication");
break;
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");
break;
}
- case PropgraphElementRelationId:
- {
- HeapTuple tup;
- Form_pg_propgraph_element pge;
-
- 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;
- }
- pge = (Form_pg_propgraph_element) GETSTRUCT(tup);
- appendStringInfo(&buffer, "%s of property graph ", 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, ObjectIdGetDatum(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 property graph ", 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, ObjectIdGetDatum(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 property graph ", quote_identifier(NameStr(pgp->pgpname)));
- getRelationIdentity(&buffer, pgp->pgppgid, objname, false);
- if (objname)
- *objname = lappend(*objname, pstrdup(NameStr(pgp->pgpname)));
- ReleaseSysCache(tup);
- break;
- }
-
- case PropgraphElementLabelRelationId:
- {
- Relation ellabelDesc;
- HeapTuple tup;
- Form_pg_propgraph_element_label pgelform;
- ObjectAddress oa;
- char *labelname;
-
- ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock);
- tup = get_catalog_object_by_oid(ellabelDesc,
- Anum_pg_propgraph_element_label_oid,
- object->objectId);
- if (!HeapTupleIsValid(tup))
- {
- if (!missing_ok)
- elog(ERROR, "could not find tuple for element label %u",
- object->objectId);
-
- table_close(ellabelDesc, AccessShareLock);
- break;
- }
-
- pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
-
- labelname = get_propgraph_label_name(pgelform->pgellabelid);
- appendStringInfo(&buffer, "%s of element ", quote_identifier(labelname));
- ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid);
- appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
- objargs, false));
- /* labelname is already pstrdup'ed. */
- if (objname)
- *objname = lappend(*objname, labelname);
-
- table_close(ellabelDesc, AccessShareLock);
- break;
- }
-
- case PropgraphLabelPropertyRelationId:
- {
- Relation lblpropDesc;
- HeapTuple tup;
- Form_pg_propgraph_label_property plpform;
- ObjectAddress oa;
- char *propname;
-
- lblpropDesc = table_open(PropgraphLabelPropertyRelationId,
- AccessShareLock);
- tup = get_catalog_object_by_oid(lblpropDesc,
- Anum_pg_propgraph_label_property_oid,
- object->objectId);
- if (!HeapTupleIsValid(tup))
- {
- if (!missing_ok)
- elog(ERROR, "could not find tuple for label property %u",
- object->objectId);
-
- table_close(lblpropDesc, AccessShareLock);
- break;
- }
-
- plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup);
-
- propname = get_propgraph_property_name(plpform->plppropid);
- appendStringInfo(&buffer, "%s of label ", quote_identifier(propname));
- ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid);
- appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname,
- objargs, false));
- /* propname is already pstrdup'ed. */
- if (objname)
- *objname = lappend(*objname, propname);
-
- table_close(lblpropDesc, AccessShareLock);
- break;
- }
-
case PublicationRelationId:
{
char *pubname;
return OBJECT_MATVIEW;
case RELKIND_FOREIGN_TABLE:
return OBJECT_FOREIGN_TABLE;
- case RELKIND_PROPGRAPH:
- return OBJECT_PROPGRAPH;
case RELKIND_TOASTVALUE:
return OBJECT_TABLE;
default:
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;
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
portalcmds.o \
prepare.o \
proclang.o \
- propgraphcmds.o \
publicationcmds.o \
repack.o \
repack_worker.o \
case OBJECT_MATVIEW:
case OBJECT_INDEX:
case OBJECT_FOREIGN_TABLE:
- case OBJECT_PROPGRAPH:
return RenameRelation(stmt);
case OBJECT_COLUMN:
case OBJECT_TABLE:
case OBJECT_VIEW:
case OBJECT_MATVIEW:
- case OBJECT_PROPGRAPH:
address = AlterTableNamespace(stmt,
oldSchemaAddr ? &oldNspOid : NULL);
break;
case OBJECT_OPCLASS:
case OBJECT_OPFAMILY:
case OBJECT_PROCEDURE:
- case OBJECT_PROPGRAPH:
case OBJECT_ROUTINE:
case OBJECT_STATISTIC_EXT:
case OBJECT_TABLESPACE:
{
ObjectAddress address;
- 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);
- }
+ address = get_object_address(stmt->objectType,
+ stmt->object,
+ NULL,
+ AccessExclusiveLock,
+ false);
AlterObjectOwner_internal(address.classId, address.objectId,
newowner);
case OBJECT_FOREIGN_TABLE:
case OBJECT_INDEX:
case OBJECT_MATVIEW:
- case OBJECT_PROPGRAPH:
case OBJECT_ROLE:
case OBJECT_SEQUENCE:
case OBJECT_SUBSCRIPTION:
return "PARAMETER";
case OBJECT_PROCEDURE:
return "PROCEDURE";
- case OBJECT_PROPGRAPH:
- return "PROPERTY GRAPH";
case OBJECT_ROUTINE:
return "ROUTINE";
case OBJECT_TABLESPACE:
case OBJECT_OPFAMILY:
case OBJECT_PARAMETER_ACL:
case OBJECT_POLICY:
- case OBJECT_PROPGRAPH:
case OBJECT_PUBLICATION:
case OBJECT_PUBLICATION_NAMESPACE:
case OBJECT_PUBLICATION_REL:
'portalcmds.c',
'prepare.c',
'proclang.c',
- 'propgraphcmds.c',
'publicationcmds.c',
'repack.c',
'repack_worker.c',
+++ /dev/null
-/*-------------------------------------------------------------------------
- *
- * propgraphcmds.c
- * property graph manipulation
- *
- * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- * src/backend/commands/propgraphcmds.c
- *
- *-------------------------------------------------------------------------
- */
-#include "postgres.h"
-
-#include "access/genam.h"
-#include "access/htup_details.h"
-#include "access/nbtree.h"
-#include "access/table.h"
-#include "access/xact.h"
-#include "catalog/catalog.h"
-#include "catalog/indexing.h"
-#include "catalog/namespace.h"
-#include "catalog/pg_class.h"
-#include "catalog/pg_collation_d.h"
-#include "catalog/pg_operator_d.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 "commands/defrem.h"
-#include "commands/propgraphcmds.h"
-#include "commands/tablecmds.h"
-#include "miscadmin.h"
-#include "nodes/nodeFuncs.h"
-#include "parser/parse_coerce.h"
-#include "parser/parse_collate.h"
-#include "parser/parse_oper.h"
-#include "parser/parse_relation.h"
-#include "parser/parse_target.h"
-#include "utils/acl.h"
-#include "utils/array.h"
-#include "utils/builtins.h"
-#include "utils/fmgroids.h"
-#include "utils/inval.h"
-#include "utils/lsyscache.h"
-#include "utils/rel.h"
-#include "utils/ruleutils.h"
-#include "utils/syscache.h"
-
-
-struct element_info
-{
- Oid elementid;
- char kind;
- Oid relid;
- char *aliasname;
- ArrayType *key;
-
- char *srcvertex;
- Oid srcvertexid;
- Oid srcrelid;
- ArrayType *srckey;
- ArrayType *srcref;
- ArrayType *srceqop;
-
- char *destvertex;
- Oid destvertexid;
- Oid destrelid;
- ArrayType *destkey;
- ArrayType *destref;
- ArrayType *desteqop;
-
- List *labels;
-};
-
-
-static ArrayType *propgraph_element_get_key(ParseState *pstate, const List *key_clause, Relation element_rel,
- const char *aliasname, int location);
-static void propgraph_edge_get_ref_keys(ParseState *pstate, const List *keycols, const List *refcols,
- Relation edge_rel, Relation ref_rel,
- const char *aliasname, int location, const char *type,
- ArrayType **outkey, ArrayType **outref, ArrayType **outeqop);
-static AttrNumber *array_from_column_list(ParseState *pstate, const List *colnames, int location, Relation element_rel);
-static ArrayType *array_from_attnums(int numattrs, const AttrNumber *attnums);
-static Oid insert_element_record(ObjectAddress pgaddress, struct element_info *einfo);
-static Oid insert_label_record(Oid graphid, Oid peoid, const char *label);
-static void insert_property_records(Oid graphid, Oid ellabeloid, Oid pgerelid, const PropGraphProperties *properties);
-static void insert_property_record(Oid graphid, Oid ellabeloid, Oid pgerelid, const char *propname, const Expr *expr);
-static void check_element_properties(Oid peoid);
-static void check_element_label_properties(Oid ellabeloid);
-static void check_all_labels_properties(Oid pgrelid);
-static Oid get_vertex_oid(ParseState *pstate, Oid pgrelid, const char *alias, int location);
-static Oid get_edge_oid(ParseState *pstate, Oid pgrelid, const char *alias, int location);
-static Oid get_element_relid(Oid peid);
-static List *get_graph_label_ids(Oid graphid);
-static List *get_label_element_label_ids(Oid labelid);
-static List *get_element_label_property_names(Oid ellabeloid);
-static List *get_graph_property_ids(Oid graphid);
-
-
-/*
- * CREATE PROPERTY GRAPH
- */
-ObjectAddress
-CreatePropGraph(ParseState *pstate, const CreatePropGraphStmt *stmt)
-{
- CreateStmt *cstmt = makeNode(CreateStmt);
- char components_persistence;
- ListCell *lc;
- ObjectAddress pgaddress;
- List *vertex_infos = NIL;
- List *edge_infos = NIL;
- List *element_aliases = NIL;
- List *element_oids = NIL;
-
- if (stmt->pgname->relpersistence == RELPERSISTENCE_UNLOGGED)
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("property graphs cannot be unlogged because they do not have storage")));
-
- components_persistence = RELPERSISTENCE_PERMANENT;
-
- foreach(lc, stmt->vertex_tables)
- {
- PropGraphVertex *vertex = lfirst_node(PropGraphVertex, lc);
- struct element_info *vinfo;
- Relation rel;
-
- vinfo = palloc0_object(struct element_info);
- vinfo->kind = PGEKIND_VERTEX;
-
- vinfo->relid = RangeVarGetRelidExtended(vertex->vtable, AccessShareLock, 0, RangeVarCallbackOwnsRelation, NULL);
-
- rel = table_open(vinfo->relid, NoLock);
-
- if (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
- components_persistence = RELPERSISTENCE_TEMP;
-
- if (vertex->vtable->alias)
- vinfo->aliasname = vertex->vtable->alias->aliasname;
- else
- vinfo->aliasname = vertex->vtable->relname;
-
- if (list_member(element_aliases, makeString(vinfo->aliasname)))
- ereport(ERROR,
- (errcode(ERRCODE_DUPLICATE_TABLE),
- errmsg("alias \"%s\" used more than once as element table", vinfo->aliasname),
- parser_errposition(pstate, vertex->location)));
-
- vinfo->key = propgraph_element_get_key(pstate, vertex->vkey, rel, vinfo->aliasname, vertex->location);
-
- vinfo->labels = vertex->labels;
-
- table_close(rel, NoLock);
-
- vertex_infos = lappend(vertex_infos, vinfo);
-
- element_aliases = lappend(element_aliases, makeString(vinfo->aliasname));
- }
-
- foreach(lc, stmt->edge_tables)
- {
- PropGraphEdge *edge = lfirst_node(PropGraphEdge, lc);
- struct element_info *einfo;
- Relation rel;
- ListCell *lc2;
- Oid srcrelid;
- Oid destrelid;
- Relation srcrel;
- Relation destrel;
-
- einfo = palloc0_object(struct element_info);
- einfo->kind = PGEKIND_EDGE;
-
- einfo->relid = RangeVarGetRelidExtended(edge->etable, AccessShareLock, 0, RangeVarCallbackOwnsRelation, NULL);
-
- rel = table_open(einfo->relid, NoLock);
-
- if (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
- components_persistence = RELPERSISTENCE_TEMP;
-
- if (edge->etable->alias)
- einfo->aliasname = edge->etable->alias->aliasname;
- else
- einfo->aliasname = edge->etable->relname;
-
- if (list_member(element_aliases, makeString(einfo->aliasname)))
- ereport(ERROR,
- (errcode(ERRCODE_DUPLICATE_TABLE),
- errmsg("alias \"%s\" used more than once as element table", einfo->aliasname),
- parser_errposition(pstate, edge->location)));
-
- einfo->key = propgraph_element_get_key(pstate, edge->ekey, rel, einfo->aliasname, edge->location);
-
- einfo->srcvertex = edge->esrcvertex;
- einfo->destvertex = edge->edestvertex;
-
- srcrelid = 0;
- destrelid = 0;
- foreach(lc2, vertex_infos)
- {
- struct element_info *vinfo = lfirst(lc2);
-
- if (strcmp(vinfo->aliasname, edge->esrcvertex) == 0)
- srcrelid = vinfo->relid;
-
- if (strcmp(vinfo->aliasname, edge->edestvertex) == 0)
- destrelid = vinfo->relid;
-
- if (srcrelid && destrelid)
- break;
- }
- if (!srcrelid)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
- errmsg("source vertex \"%s\" of edge \"%s\" does not exist",
- edge->esrcvertex, einfo->aliasname),
- parser_errposition(pstate, edge->location)));
- if (!destrelid)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
- errmsg("destination vertex \"%s\" of edge \"%s\" does not exist",
- edge->edestvertex, einfo->aliasname),
- parser_errposition(pstate, edge->location)));
-
- srcrel = table_open(srcrelid, NoLock);
- destrel = table_open(destrelid, NoLock);
-
- propgraph_edge_get_ref_keys(pstate, edge->esrckey, edge->esrcvertexcols, rel, srcrel,
- einfo->aliasname, edge->location, "SOURCE",
- &einfo->srckey, &einfo->srcref, &einfo->srceqop);
- propgraph_edge_get_ref_keys(pstate, edge->edestkey, edge->edestvertexcols, rel, destrel,
- einfo->aliasname, edge->location, "DESTINATION",
- &einfo->destkey, &einfo->destref, &einfo->desteqop);
-
- einfo->labels = edge->labels;
-
- table_close(destrel, NoLock);
- table_close(srcrel, NoLock);
-
- table_close(rel, NoLock);
-
- edge_infos = lappend(edge_infos, einfo);
-
- element_aliases = lappend(element_aliases, makeString(einfo->aliasname));
- }
-
- cstmt->relation = stmt->pgname;
- cstmt->oncommit = ONCOMMIT_NOOP;
-
- /*
- * Automatically make it temporary if any component tables are temporary
- * (see also DefineView()).
- */
- if (stmt->pgname->relpersistence == RELPERSISTENCE_PERMANENT
- && components_persistence == RELPERSISTENCE_TEMP)
- {
- cstmt->relation = copyObject(cstmt->relation);
- cstmt->relation->relpersistence = RELPERSISTENCE_TEMP;
- ereport(NOTICE,
- (errmsg("property graph \"%s\" will be temporary",
- stmt->pgname->relname)));
- }
-
- pgaddress = DefineRelation(cstmt, RELKIND_PROPGRAPH, InvalidOid, NULL, NULL);
-
- foreach(lc, vertex_infos)
- {
- struct element_info *vinfo = lfirst(lc);
- Oid peoid;
-
- peoid = insert_element_record(pgaddress, vinfo);
- element_oids = lappend_oid(element_oids, peoid);
- }
-
- foreach(lc, edge_infos)
- {
- struct element_info *einfo = lfirst(lc);
- Oid peoid;
- ListCell *lc2;
-
- /*
- * Look up the vertices again. Now the vertices have OIDs assigned,
- * which we need.
- */
- foreach(lc2, vertex_infos)
- {
- struct element_info *vinfo = lfirst(lc2);
-
- if (strcmp(vinfo->aliasname, einfo->srcvertex) == 0)
- {
- einfo->srcvertexid = vinfo->elementid;
- einfo->srcrelid = vinfo->relid;
- }
- if (strcmp(vinfo->aliasname, einfo->destvertex) == 0)
- {
- einfo->destvertexid = vinfo->elementid;
- einfo->destrelid = vinfo->relid;
- }
- if (einfo->srcvertexid && einfo->destvertexid)
- break;
- }
- Assert(einfo->srcvertexid);
- Assert(einfo->destvertexid);
- Assert(einfo->srcrelid);
- Assert(einfo->destrelid);
- peoid = insert_element_record(pgaddress, einfo);
- element_oids = lappend_oid(element_oids, peoid);
- }
-
- CommandCounterIncrement();
-
- foreach_oid(peoid, element_oids)
- check_element_properties(peoid);
- check_all_labels_properties(pgaddress.objectId);
-
- return pgaddress;
-}
-
-/*
- * Process the key clause specified for an element. If key_clause is non-NIL,
- * then it is a list of column names. Otherwise, the primary key of the
- * relation is used. The return value is an array of column numbers.
- */
-static ArrayType *
-propgraph_element_get_key(ParseState *pstate, const List *key_clause, Relation element_rel, const char *aliasname, int location)
-{
- ArrayType *a;
-
- if (key_clause == NIL)
- {
- Oid pkidx = RelationGetPrimaryKeyIndex(element_rel, false);
-
- if (!pkidx)
- ereport(ERROR,
- errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
- errmsg("no key specified and no suitable primary key exists for definition of element \"%s\"", aliasname),
- parser_errposition(pstate, location));
- else
- {
- Relation indexDesc;
-
- indexDesc = index_open(pkidx, AccessShareLock);
- a = array_from_attnums(IndexRelationGetNumberOfKeyAttributes(indexDesc),
- indexDesc->rd_index->indkey.values);
- index_close(indexDesc, NoLock);
- }
- }
- else
- {
- a = array_from_attnums(list_length(key_clause),
- array_from_column_list(pstate, key_clause, location, element_rel));
- }
-
- return a;
-}
-
-/*
- * Process the source or destination link of an edge.
- *
- * keycols and refcols are column names representing the local and referenced
- * (vertex) columns. If they are both NIL, a matching foreign key is looked
- * up.
- *
- * edge_rel and ref_rel are the local and referenced element tables.
- *
- * aliasname, location, and type are for error messages. type is either
- * "SOURCE" or "DESTINATION".
- *
- * The outputs are arrays of column numbers in outkey and outref.
- */
-static void
-propgraph_edge_get_ref_keys(ParseState *pstate, const List *keycols, const List *refcols,
- Relation edge_rel, Relation ref_rel,
- const char *aliasname, int location, const char *type,
- ArrayType **outkey, ArrayType **outref, ArrayType **outeqop)
-{
- int nkeys;
- AttrNumber *keyattnums;
- AttrNumber *refattnums;
- Oid *keyeqops;
- Datum *datums;
-
- Assert((keycols && refcols) || (!keycols && !refcols));
-
- if (keycols)
- {
- if (list_length(keycols) != list_length(refcols))
- ereport(ERROR,
- errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
- errmsg("mismatching number of columns in %s vertex definition of edge \"%s\"", type, aliasname),
- parser_errposition(pstate, location));
-
- nkeys = list_length(keycols);
- keyattnums = array_from_column_list(pstate, keycols, location, edge_rel);
- refattnums = array_from_column_list(pstate, refcols, location, ref_rel);
- keyeqops = palloc_array(Oid, nkeys);
-
- for (int i = 0; i < nkeys; i++)
- {
- Oid keytype;
- int32 keytypmod;
- Oid keycoll;
- Oid reftype;
- int32 reftypmod;
- Oid refcoll;
- Oid opc;
- Oid opf;
- StrategyNumber strategy;
-
- /*
- * Lookup equality operator to be used for edge and vertex key.
- * Vertex key is equivalent to primary key and edge key is similar
- * to foreign key since edge key references vertex key. Hence
- * vertex key is used as left operand and edge key is used as
- * right operand. The method used to find the equality operators
- * is similar to the method used to find equality operators for
- * FK/PK comparison in ATAddForeignKeyConstraint() except that
- * opclass of the vertex key type is used as a starting point.
- * Since we need only equality operators we use both BT and HASH
- * strategies.
- *
- * If the required operators do not exist, we can not construct
- * quals linking an edge to its adjacent vertices.
- */
- get_atttypetypmodcoll(RelationGetRelid(edge_rel), keyattnums[i], &keytype, &keytypmod, &keycoll);
- get_atttypetypmodcoll(RelationGetRelid(ref_rel), refattnums[i], &reftype, &reftypmod, &refcoll);
- keyeqops[i] = InvalidOid;
- strategy = BTEqualStrategyNumber;
- opc = GetDefaultOpClass(reftype, BTREE_AM_OID);
- if (!OidIsValid(opc))
- {
- opc = GetDefaultOpClass(reftype, HASH_AM_OID);
- strategy = HTEqualStrategyNumber;
- }
- if (OidIsValid(opc))
- {
- opf = get_opclass_family(opc);
- if (OidIsValid(opf))
- {
- keyeqops[i] = get_opfamily_member(opf, reftype, keytype, strategy);
- if (!OidIsValid(keyeqops[i]))
- {
- /* Last resort, implicit cast. */
- if (can_coerce_type(1, &keytype, &reftype, COERCION_IMPLICIT))
- keyeqops[i] = get_opfamily_member(opf, reftype, reftype, strategy);
- }
- }
- }
-
- if (!OidIsValid(keyeqops[i]))
- ereport(ERROR,
- errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("no equality operator exists for %s key comparison of edge \"%s\"",
- type, aliasname),
- parser_errposition(pstate, location));
-
- /*
- * If collations of key attribute and referenced attribute are
- * different, an edge may end up being adjacent to undesired
- * vertices. Prohibit such a case.
- *
- * PK/FK allows different collations as long as they are
- * deterministic for backward compatibility. But we can be a bit
- * stricter here and follow SQL standard.
- */
- if (keycoll != refcoll &&
- keycoll != DEFAULT_COLLATION_OID && refcoll != DEFAULT_COLLATION_OID &&
- OidIsValid(keycoll) && OidIsValid(refcoll))
- ereport(ERROR,
- errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("collation mismatch in %s key of edge \"%s\": %s vs. %s",
- type, aliasname,
- get_collation_name(keycoll), get_collation_name(refcoll)),
- parser_errposition(pstate, location));
- }
- }
- else
- {
- ForeignKeyCacheInfo *fk = NULL;
-
- foreach_node(ForeignKeyCacheInfo, tmp, RelationGetFKeyList(edge_rel))
- {
- if (tmp->confrelid == RelationGetRelid(ref_rel))
- {
- if (fk)
- ereport(ERROR,
- errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("more than one suitable foreign key exists for %s key of edge \"%s\"", type, aliasname),
- parser_errposition(pstate, location));
- fk = tmp;
- }
- }
-
- if (!fk)
- ereport(ERROR,
- errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("no %s key specified and no suitable foreign key exists for definition of edge \"%s\"", type, aliasname),
- parser_errposition(pstate, location));
-
- nkeys = fk->nkeys;
- keyattnums = fk->conkey;
- refattnums = fk->confkey;
- keyeqops = fk->conpfeqop;
- }
-
- *outkey = array_from_attnums(nkeys, keyattnums);
- *outref = array_from_attnums(nkeys, refattnums);
- datums = palloc_array(Datum, nkeys);
- for (int i = 0; i < nkeys; i++)
- datums[i] = ObjectIdGetDatum(keyeqops[i]);
- *outeqop = construct_array_builtin(datums, nkeys, OIDOID);
-}
-
-/*
- * Convert list of column names in the specified relation into an array of
- * column numbers.
- */
-static AttrNumber *
-array_from_column_list(ParseState *pstate, const List *colnames, int location, Relation element_rel)
-{
- int numattrs;
- AttrNumber *attnums;
- int i;
- ListCell *lc;
-
- numattrs = list_length(colnames);
- attnums = palloc_array(AttrNumber, numattrs);
-
- i = 0;
- foreach(lc, colnames)
- {
- char *colname = strVal(lfirst(lc));
- Oid relid = RelationGetRelid(element_rel);
- AttrNumber attnum;
-
- attnum = get_attnum(relid, colname);
- if (!attnum)
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_COLUMN),
- errmsg("column \"%s\" of relation \"%s\" does not exist",
- colname, get_rel_name(relid)),
- parser_errposition(pstate, location)));
- attnums[i++] = attnum;
- }
-
- for (int j = 0; j < numattrs; j++)
- {
- for (int k = j + 1; k < numattrs; k++)
- {
- if (attnums[j] == attnums[k])
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
- errmsg("graph key columns list must not contain duplicates"),
- parser_errposition(pstate, location)));
- }
- }
-
- return attnums;
-}
-
-static ArrayType *
-array_from_attnums(int numattrs, const AttrNumber *attnums)
-{
- Datum *attnumsd;
-
- attnumsd = palloc_array(Datum, numattrs);
-
- for (int i = 0; i < numattrs; i++)
- attnumsd[i] = Int16GetDatum(attnums[i]);
-
- return construct_array_builtin(attnumsd, numattrs, INT2OID);
-}
-
-static void
-array_of_attnums_to_objectaddrs(Oid relid, ArrayType *arr, ObjectAddresses *addrs)
-{
- Datum *attnumsd;
- int numattrs;
-
- deconstruct_array_builtin(arr, INT2OID, &attnumsd, NULL, &numattrs);
-
- for (int i = 0; i < numattrs; i++)
- {
- ObjectAddress referenced;
-
- ObjectAddressSubSet(referenced, RelationRelationId, relid, DatumGetInt16(attnumsd[i]));
- add_exact_object_address(&referenced, addrs);
- }
-}
-
-static void
-array_of_opers_to_objectaddrs(ArrayType *arr, ObjectAddresses *addrs)
-{
- Datum *opersd;
- int numopers;
-
- deconstruct_array_builtin(arr, OIDOID, &opersd, NULL, &numopers);
-
- for (int i = 0; i < numopers; i++)
- {
- ObjectAddress referenced;
-
- ObjectAddressSet(referenced, OperatorRelationId, DatumGetObjectId(opersd[i]));
- add_exact_object_address(&referenced, addrs);
- }
-}
-
-/*
- * Insert a record for an element into the pg_propgraph_element catalog. Also
- * inserts labels and properties into their respective catalogs.
- */
-static Oid
-insert_element_record(ObjectAddress pgaddress, struct element_info *einfo)
-{
- Oid graphid = pgaddress.objectId;
- Relation rel;
- NameData aliasname;
- Oid peoid;
- Datum values[Natts_pg_propgraph_element] = {0};
- bool nulls[Natts_pg_propgraph_element] = {0};
- HeapTuple tup;
- ObjectAddress myself;
- ObjectAddress referenced;
- ObjectAddresses *addrs;
-
- rel = table_open(PropgraphElementRelationId, RowExclusiveLock);
-
- peoid = GetNewOidWithIndex(rel, PropgraphElementObjectIndexId, Anum_pg_propgraph_element_oid);
- einfo->elementid = peoid;
- values[Anum_pg_propgraph_element_oid - 1] = ObjectIdGetDatum(peoid);
- values[Anum_pg_propgraph_element_pgepgid - 1] = ObjectIdGetDatum(graphid);
- values[Anum_pg_propgraph_element_pgerelid - 1] = ObjectIdGetDatum(einfo->relid);
- namestrcpy(&aliasname, einfo->aliasname);
- values[Anum_pg_propgraph_element_pgealias - 1] = NameGetDatum(&aliasname);
- values[Anum_pg_propgraph_element_pgekind - 1] = CharGetDatum(einfo->kind);
- values[Anum_pg_propgraph_element_pgesrcvertexid - 1] = ObjectIdGetDatum(einfo->srcvertexid);
- values[Anum_pg_propgraph_element_pgedestvertexid - 1] = ObjectIdGetDatum(einfo->destvertexid);
- values[Anum_pg_propgraph_element_pgekey - 1] = PointerGetDatum(einfo->key);
-
- if (einfo->srckey)
- values[Anum_pg_propgraph_element_pgesrckey - 1] = PointerGetDatum(einfo->srckey);
- else
- nulls[Anum_pg_propgraph_element_pgesrckey - 1] = true;
- if (einfo->srcref)
- values[Anum_pg_propgraph_element_pgesrcref - 1] = PointerGetDatum(einfo->srcref);
- else
- nulls[Anum_pg_propgraph_element_pgesrcref - 1] = true;
- if (einfo->srceqop)
- values[Anum_pg_propgraph_element_pgesrceqop - 1] = PointerGetDatum(einfo->srceqop);
- else
- nulls[Anum_pg_propgraph_element_pgesrceqop - 1] = true;
- if (einfo->destkey)
- values[Anum_pg_propgraph_element_pgedestkey - 1] = PointerGetDatum(einfo->destkey);
- else
- nulls[Anum_pg_propgraph_element_pgedestkey - 1] = true;
- if (einfo->destref)
- values[Anum_pg_propgraph_element_pgedestref - 1] = PointerGetDatum(einfo->destref);
- else
- nulls[Anum_pg_propgraph_element_pgedestref - 1] = true;
- if (einfo->desteqop)
- values[Anum_pg_propgraph_element_pgedesteqop - 1] = PointerGetDatum(einfo->desteqop);
- else
- nulls[Anum_pg_propgraph_element_pgedesteqop - 1] = true;
-
- tup = heap_form_tuple(RelationGetDescr(rel), values, nulls);
- CatalogTupleInsert(rel, tup);
- heap_freetuple(tup);
-
- ObjectAddressSet(myself, PropgraphElementRelationId, peoid);
-
- /* Add dependency on the property graph */
- recordDependencyOn(&myself, &pgaddress, DEPENDENCY_AUTO);
-
- addrs = new_object_addresses();
-
- /* Add dependency on the relation */
- ObjectAddressSet(referenced, RelationRelationId, einfo->relid);
- add_exact_object_address(&referenced, addrs);
- array_of_attnums_to_objectaddrs(einfo->relid, einfo->key, addrs);
-
- /*
- * Add dependencies on vertices and equality operators used for key
- * comparison.
- */
- if (einfo->srcvertexid)
- {
- ObjectAddressSet(referenced, PropgraphElementRelationId, einfo->srcvertexid);
- add_exact_object_address(&referenced, addrs);
- array_of_attnums_to_objectaddrs(einfo->relid, einfo->srckey, addrs);
- array_of_attnums_to_objectaddrs(einfo->srcrelid, einfo->srcref, addrs);
- array_of_opers_to_objectaddrs(einfo->srceqop, addrs);
- }
- if (einfo->destvertexid)
- {
- ObjectAddressSet(referenced, PropgraphElementRelationId, einfo->destvertexid);
- add_exact_object_address(&referenced, addrs);
- array_of_attnums_to_objectaddrs(einfo->relid, einfo->destkey, addrs);
- array_of_attnums_to_objectaddrs(einfo->destrelid, einfo->destref, addrs);
- array_of_opers_to_objectaddrs(einfo->desteqop, addrs);
- }
-
- record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
-
- table_close(rel, NoLock);
-
- if (einfo->labels)
- {
- ListCell *lc;
-
- foreach(lc, einfo->labels)
- {
- PropGraphLabelAndProperties *lp = lfirst_node(PropGraphLabelAndProperties, lc);
- Oid ellabeloid;
-
- if (lp->label)
- ellabeloid = insert_label_record(graphid, peoid, lp->label);
- else
- ellabeloid = insert_label_record(graphid, peoid, einfo->aliasname);
- insert_property_records(graphid, ellabeloid, einfo->relid, lp->properties);
-
- CommandCounterIncrement();
- }
- }
- else
- {
- Oid ellabeloid;
- PropGraphProperties *pr = makeNode(PropGraphProperties);
-
- pr->all = true;
- pr->location = -1;
-
- ellabeloid = insert_label_record(graphid, peoid, einfo->aliasname);
- insert_property_records(graphid, ellabeloid, einfo->relid, pr);
- }
-
- return peoid;
-}
-
-/*
- * Insert records for a label into the pg_propgraph_label and
- * pg_propgraph_element_label catalogs, and register dependencies.
- *
- * Returns the OID of the new pg_propgraph_element_label record.
- */
-static Oid
-insert_label_record(Oid graphid, Oid peoid, const char *label)
-{
- Oid labeloid;
- Oid ellabeloid;
-
- /*
- * Insert into pg_propgraph_label if not already existing.
- */
- labeloid = GetSysCacheOid2(PROPGRAPHLABELNAME, Anum_pg_propgraph_label_oid, ObjectIdGetDatum(graphid), CStringGetDatum(label));
- if (!labeloid)
- {
- Relation rel;
- Datum values[Natts_pg_propgraph_label] = {0};
- bool nulls[Natts_pg_propgraph_label] = {0};
- NameData labelname;
- HeapTuple tup;
- ObjectAddress myself;
- ObjectAddress referenced;
-
- rel = table_open(PropgraphLabelRelationId, RowExclusiveLock);
-
- labeloid = GetNewOidWithIndex(rel, PropgraphLabelObjectIndexId, Anum_pg_propgraph_label_oid);
- values[Anum_pg_propgraph_label_oid - 1] = ObjectIdGetDatum(labeloid);
- values[Anum_pg_propgraph_label_pglpgid - 1] = ObjectIdGetDatum(graphid);
- namestrcpy(&labelname, label);
- values[Anum_pg_propgraph_label_pgllabel - 1] = NameGetDatum(&labelname);
-
- tup = heap_form_tuple(RelationGetDescr(rel), values, nulls);
- CatalogTupleInsert(rel, tup);
- heap_freetuple(tup);
-
- ObjectAddressSet(myself, PropgraphLabelRelationId, labeloid);
-
- ObjectAddressSet(referenced, RelationRelationId, graphid);
- recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
-
- table_close(rel, NoLock);
- }
-
- /*
- * Insert into pg_propgraph_element_label
- */
- if (SearchSysCacheExists2(PROPGRAPHELEMENTLABELELEMENTLABEL,
- ObjectIdGetDatum(peoid),
- ObjectIdGetDatum(labeloid)))
- ereport(ERROR,
- errcode(ERRCODE_DUPLICATE_OBJECT),
- errmsg("label \"%s\" already exists", label));
- else
- {
- Relation rel;
- Datum values[Natts_pg_propgraph_element_label] = {0};
- bool nulls[Natts_pg_propgraph_element_label] = {0};
- HeapTuple tup;
- ObjectAddress myself;
- ObjectAddress referenced;
-
- rel = table_open(PropgraphElementLabelRelationId, RowExclusiveLock);
-
- ellabeloid = GetNewOidWithIndex(rel, PropgraphElementLabelObjectIndexId, Anum_pg_propgraph_element_label_oid);
- values[Anum_pg_propgraph_element_label_oid - 1] = ObjectIdGetDatum(ellabeloid);
- values[Anum_pg_propgraph_element_label_pgellabelid - 1] = ObjectIdGetDatum(labeloid);
- values[Anum_pg_propgraph_element_label_pgelelid - 1] = ObjectIdGetDatum(peoid);
-
- tup = heap_form_tuple(RelationGetDescr(rel), values, nulls);
- CatalogTupleInsert(rel, tup);
- heap_freetuple(tup);
-
- ObjectAddressSet(myself, PropgraphElementLabelRelationId, ellabeloid);
-
- ObjectAddressSet(referenced, PropgraphLabelRelationId, labeloid);
- recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
- ObjectAddressSet(referenced, PropgraphElementRelationId, peoid);
- recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
-
- table_close(rel, NoLock);
- }
-
- return ellabeloid;
-}
-
-/*
- * Insert records for properties into the pg_propgraph_property catalog.
- */
-static void
-insert_property_records(Oid graphid, Oid ellabeloid, Oid pgerelid, const PropGraphProperties *properties)
-{
- List *proplist = NIL;
- ParseState *pstate;
- ParseNamespaceItem *nsitem;
- List *tp;
- Relation rel;
- ListCell *lc;
-
- if (properties->all)
- {
- Relation attRelation;
- SysScanDesc scan;
- ScanKeyData key[1];
- HeapTuple attributeTuple;
-
- attRelation = table_open(AttributeRelationId, RowShareLock);
- ScanKeyInit(&key[0],
- Anum_pg_attribute_attrelid,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(pgerelid));
- scan = systable_beginscan(attRelation, AttributeRelidNumIndexId,
- true, NULL, 1, key);
- while (HeapTupleIsValid(attributeTuple = systable_getnext(scan)))
- {
- Form_pg_attribute att = (Form_pg_attribute) GETSTRUCT(attributeTuple);
- ColumnRef *cr;
- ResTarget *rt;
-
- if (att->attnum <= 0 || att->attisdropped)
- continue;
-
- cr = makeNode(ColumnRef);
- rt = makeNode(ResTarget);
-
- cr->fields = list_make1(makeString(pstrdup(NameStr(att->attname))));
- cr->location = -1;
-
- rt->name = pstrdup(NameStr(att->attname));
- rt->val = (Node *) cr;
- rt->location = -1;
-
- proplist = lappend(proplist, rt);
- }
- systable_endscan(scan);
- table_close(attRelation, RowShareLock);
- }
- else
- {
- proplist = properties->properties;
-
- foreach(lc, proplist)
- {
- ResTarget *rt = lfirst_node(ResTarget, lc);
-
- if (!rt->name && !IsA(rt->val, ColumnRef))
- ereport(ERROR,
- errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("property name required"),
- parser_errposition(NULL, rt->location));
- }
- }
-
- rel = table_open(pgerelid, AccessShareLock);
-
- pstate = make_parsestate(NULL);
- nsitem = addRangeTableEntryForRelation(pstate,
- rel,
- AccessShareLock,
- NULL,
- false,
- true);
- addNSItemToQuery(pstate, nsitem, true, true, true);
-
- table_close(rel, NoLock);
-
- tp = transformTargetList(pstate, proplist, EXPR_KIND_PROPGRAPH_PROPERTY);
- if (pstate->p_resolve_unknowns)
- resolveTargetListUnknowns(pstate, tp);
- assign_expr_collations(pstate, (Node *) tp);
-
- /*
- * When properties are derived from the table's attributes, names are
- * already unique. Reject duplicate property names within an explicit
- * PROPERTIES clause. Do this after transformTargetList() so that any
- * names derived by transformTargetList() are considered.
- */
- if (!properties->all)
- {
- List *seen = NIL;
-
- foreach_node(TargetEntry, te, tp)
- {
- String *name = makeString(te->resname);
-
- if (list_member(seen, name))
- ereport(ERROR,
- errcode(ERRCODE_DUPLICATE_OBJECT),
- errmsg("property \"%s\" specified more than once", te->resname));
- seen = lappend(seen, name);
- }
- }
-
- foreach_node(TargetEntry, te, tp)
- insert_property_record(graphid, ellabeloid, pgerelid, te->resname, te->expr);
-}
-
-/*
- * Insert records for a property into the pg_propgraph_property and
- * pg_propgraph_label_property catalogs, and register dependencies.
- */
-static void
-insert_property_record(Oid graphid, Oid ellabeloid, Oid pgerelid, const char *propname, const Expr *expr)
-{
- Oid propoid;
- Oid exprtypid = exprType((const Node *) expr);
- int32 exprtypmod = exprTypmod((const Node *) expr);
- Oid exprcollation = exprCollation((const Node *) expr);
-
- /*
- * Insert into pg_propgraph_property if not already existing.
- */
- propoid = GetSysCacheOid2(PROPGRAPHPROPNAME, Anum_pg_propgraph_property_oid, ObjectIdGetDatum(graphid), CStringGetDatum(propname));
- if (!OidIsValid(propoid))
- {
- Relation rel;
- NameData propnamedata;
- Datum values[Natts_pg_propgraph_property] = {0};
- bool nulls[Natts_pg_propgraph_property] = {0};
- HeapTuple tup;
- ObjectAddress myself;
- ObjectAddress referenced;
- AclResult aclresult;
-
- rel = table_open(PropgraphPropertyRelationId, RowExclusiveLock);
-
- propoid = GetNewOidWithIndex(rel, PropgraphPropertyObjectIndexId, Anum_pg_propgraph_property_oid);
- values[Anum_pg_propgraph_property_oid - 1] = ObjectIdGetDatum(propoid);
- values[Anum_pg_propgraph_property_pgppgid - 1] = ObjectIdGetDatum(graphid);
- namestrcpy(&propnamedata, propname);
- values[Anum_pg_propgraph_property_pgpname - 1] = NameGetDatum(&propnamedata);
- values[Anum_pg_propgraph_property_pgptypid - 1] = ObjectIdGetDatum(exprtypid);
- values[Anum_pg_propgraph_property_pgptypmod - 1] = Int32GetDatum(exprtypmod);
- values[Anum_pg_propgraph_property_pgpcollation - 1] = ObjectIdGetDatum(exprcollation);
-
- tup = heap_form_tuple(RelationGetDescr(rel), values, nulls);
- CatalogTupleInsert(rel, tup);
- heap_freetuple(tup);
-
- ObjectAddressSet(myself, PropgraphPropertyRelationId, propoid);
-
- ObjectAddressSet(referenced, RelationRelationId, graphid);
- recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
- aclresult = object_aclcheck(TypeRelationId, exprtypid, GetUserId(), ACL_USAGE);
- if (aclresult != ACLCHECK_OK)
- aclcheck_error_type(aclresult, exprtypid);
- ObjectAddressSet(referenced, TypeRelationId, exprtypid);
- recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
- if (OidIsValid(exprcollation) && exprcollation != DEFAULT_COLLATION_OID)
- {
- ObjectAddressSet(referenced, CollationRelationId, exprcollation);
- recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
- }
-
- table_close(rel, NoLock);
- }
- else
- {
- HeapTuple pgptup = SearchSysCache1(PROPGRAPHPROPOID, ObjectIdGetDatum(propoid));
- Form_pg_propgraph_property pgpform = (Form_pg_propgraph_property) GETSTRUCT(pgptup);
- Oid proptypid = pgpform->pgptypid;
- int32 proptypmod = pgpform->pgptypmod;
- Oid propcollation = pgpform->pgpcollation;
-
- ReleaseSysCache(pgptup);
-
- /*
- * Check that in the graph, all properties with the same name have the
- * same type (independent of which label they are on). (See SQL/PGQ
- * subclause "Consistency check of a tabular property graph
- * descriptor".)
- */
- if (proptypid != exprtypid || proptypmod != exprtypmod)
- {
- ereport(ERROR,
- errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("property \"%s\" data type mismatch: %s vs. %s",
- propname, format_type_with_typemod(proptypid, proptypmod), format_type_with_typemod(exprtypid, exprtypmod)),
- errdetail("In a property graph, a property of the same name has to have the same data type in each label."));
- }
-
- /* Similarly for collation */
- if (propcollation != exprcollation)
- {
- ereport(ERROR,
- errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("property \"%s\" collation mismatch: %s vs. %s",
- propname, get_collation_name(propcollation), get_collation_name(exprcollation)),
- errdetail("In a property graph, a property of the same name has to have the same collation in each label."));
- }
- }
-
- /*
- * Insert into pg_propgraph_label_property
- */
- if (SearchSysCacheExists2(PROPGRAPHLABELPROP, ObjectIdGetDatum(ellabeloid),
- ObjectIdGetDatum(propoid)))
- ereport(ERROR,
- errcode(ERRCODE_DUPLICATE_OBJECT),
- errmsg("property \"%s\" already exists", propname));
- else
- {
- Relation rel;
- Datum values[Natts_pg_propgraph_label_property] = {0};
- bool nulls[Natts_pg_propgraph_label_property] = {0};
- Oid plpoid;
- HeapTuple tup;
- ObjectAddress myself;
- ObjectAddress referenced;
-
- rel = table_open(PropgraphLabelPropertyRelationId, RowExclusiveLock);
-
- plpoid = GetNewOidWithIndex(rel, PropgraphLabelPropertyObjectIndexId, Anum_pg_propgraph_label_property_oid);
- values[Anum_pg_propgraph_label_property_oid - 1] = ObjectIdGetDatum(plpoid);
- values[Anum_pg_propgraph_label_property_plppropid - 1] = ObjectIdGetDatum(propoid);
- values[Anum_pg_propgraph_label_property_plpellabelid - 1] = ObjectIdGetDatum(ellabeloid);
- values[Anum_pg_propgraph_label_property_plpexpr - 1] = CStringGetTextDatum(nodeToString(expr));
-
- tup = heap_form_tuple(RelationGetDescr(rel), values, nulls);
- CatalogTupleInsert(rel, tup);
- heap_freetuple(tup);
-
- ObjectAddressSet(myself, PropgraphLabelPropertyRelationId, plpoid);
-
- ObjectAddressSet(referenced, PropgraphPropertyRelationId, propoid);
- recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
-
- ObjectAddressSet(referenced, PropgraphElementLabelRelationId, ellabeloid);
- recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
-
- CheckUsageOnTypesInSingleRelExpr((Node *) expr, pgerelid, GetUserId());
- recordDependencyOnSingleRelExpr(&myself, (Node *) copyObject(expr), pgerelid, DEPENDENCY_NORMAL, DEPENDENCY_NORMAL, false);
-
- table_close(rel, NoLock);
- }
-}
-
-/*
- * Check that for the given graph element, all properties with the same name
- * have the same expression for each label. (See SQL/PGQ subclause "Creation
- * of an element table descriptor".)
- *
- * We check this after all the catalog records are already inserted. This
- * makes it easier to share this code between CREATE PROPERTY GRAPH and ALTER
- * PROPERTY GRAPH. We pass in the element OID so that ALTER PROPERTY GRAPH
- * only has to check the element it has just operated on. CREATE PROPERTY
- * GRAPH checks all elements it has created.
- */
-static void
-check_element_properties(Oid peoid)
-{
- Relation rel1;
- ScanKeyData key1[1];
- SysScanDesc scan1;
- HeapTuple tuple1;
- List *propoids = NIL;
- List *propexprs = NIL;
-
- rel1 = table_open(PropgraphElementLabelRelationId, AccessShareLock);
- ScanKeyInit(&key1[0],
- Anum_pg_propgraph_element_label_pgelelid,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(peoid));
-
- scan1 = systable_beginscan(rel1, PropgraphElementLabelElementLabelIndexId, true, NULL, 1, key1);
- while (HeapTupleIsValid(tuple1 = systable_getnext(scan1)))
- {
- Form_pg_propgraph_element_label ellabel = (Form_pg_propgraph_element_label) GETSTRUCT(tuple1);
- Relation rel2;
- ScanKeyData key2[1];
- SysScanDesc scan2;
- HeapTuple tuple2;
-
- rel2 = table_open(PropgraphLabelPropertyRelationId, AccessShareLock);
- ScanKeyInit(&key2[0],
- Anum_pg_propgraph_label_property_plpellabelid,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(ellabel->oid));
-
- scan2 = systable_beginscan(rel2, PropgraphLabelPropertyLabelPropIndexId, true, NULL, 1, key2);
- while (HeapTupleIsValid(tuple2 = systable_getnext(scan2)))
- {
- Form_pg_propgraph_label_property lprop = (Form_pg_propgraph_label_property) GETSTRUCT(tuple2);
- Oid propoid;
- Datum datum;
- bool isnull;
- char *propexpr;
- ListCell *lc1,
- *lc2;
- bool found;
-
- propoid = lprop->plppropid;
- datum = heap_getattr(tuple2, Anum_pg_propgraph_label_property_plpexpr, RelationGetDescr(rel2), &isnull);
- Assert(!isnull);
- propexpr = TextDatumGetCString(datum);
-
- found = false;
- forboth(lc1, propoids, lc2, propexprs)
- {
- if (propoid == lfirst_oid(lc1))
- {
- Node *na,
- *nb;
-
- na = stringToNode(propexpr);
- nb = stringToNode(lfirst(lc2));
-
- found = true;
-
- if (!equal(na, nb))
- {
- HeapTuple tuple3;
- Form_pg_propgraph_element elform;
- List *dpcontext;
- char *dpa,
- *dpb;
-
- tuple3 = SearchSysCache1(PROPGRAPHELOID, ObjectIdGetDatum(peoid));
- if (!tuple3)
- elog(ERROR, "cache lookup failed for property graph element %u", peoid);
- elform = (Form_pg_propgraph_element) GETSTRUCT(tuple3);
- dpcontext = deparse_context_for(get_rel_name(elform->pgerelid), elform->pgerelid);
-
- dpa = deparse_expression(na, dpcontext, false, false);
- dpb = deparse_expression(nb, dpcontext, false, false);
-
- /*
- * show in sorted order to keep output independent of
- * index order
- */
- if (strcmp(dpa, dpb) > 0)
- {
- char *tmp;
-
- tmp = dpa;
- dpa = dpb;
- dpb = tmp;
- }
-
- ereport(ERROR,
- errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("element \"%s\" property \"%s\" expression mismatch: %s vs. %s",
- NameStr(elform->pgealias), get_propgraph_property_name(propoid), dpa, dpb),
- errdetail("In a property graph element, a property of the same name has to have the same expression in each label."));
-
- ReleaseSysCache(tuple3);
- }
-
- break;
- }
- }
-
- if (!found)
- {
- propoids = lappend_oid(propoids, propoid);
- propexprs = lappend(propexprs, propexpr);
- }
- }
- systable_endscan(scan2);
- table_close(rel2, AccessShareLock);
- }
-
- systable_endscan(scan1);
- table_close(rel1, AccessShareLock);
-}
-
-/*
- * Check that for the given element label, all labels of the same name in the
- * graph have the same number and names of properties (independent of which
- * element they are on). (See SQL/PGQ subclause "Consistency check of a
- * tabular property graph descriptor".)
- *
- * We check this after all the catalog records are already inserted. This
- * makes it easier to share this code between CREATE PROPERTY GRAPH and ALTER
- * PROPERTY GRAPH. We pass in the element label OID so that some variants of
- * ALTER PROPERTY GRAPH only have to check the element label it has just
- * operated on. CREATE PROPERTY GRAPH and other ALTER PROPERTY GRAPH variants
- * check all labels.
- */
-static void
-check_element_label_properties(Oid ellabeloid)
-{
- Relation rel;
- SysScanDesc scan;
- ScanKeyData key[1];
- HeapTuple tuple;
- Oid labelid = InvalidOid;
- Oid ref_ellabeloid = InvalidOid;
- List *myprops,
- *refprops;
- List *diff1,
- *diff2;
-
- rel = table_open(PropgraphElementLabelRelationId, AccessShareLock);
-
- /*
- * Get element label info
- */
- ScanKeyInit(&key[0],
- Anum_pg_propgraph_element_label_oid,
- BTEqualStrategyNumber,
- F_OIDEQ, ObjectIdGetDatum(ellabeloid));
- scan = systable_beginscan(rel, PropgraphElementLabelObjectIndexId, true, NULL, 1, key);
- if (HeapTupleIsValid(tuple = systable_getnext(scan)))
- {
- Form_pg_propgraph_element_label ellabel = (Form_pg_propgraph_element_label) GETSTRUCT(tuple);
-
- labelid = ellabel->pgellabelid;
- }
- systable_endscan(scan);
- if (!labelid)
- elog(ERROR, "element label %u not found", ellabeloid);
-
- /*
- * Find a reference element label to fetch label properties. The
- * reference element label has to have the same label OID as the one being
- * checked but a different element OID.
- */
- ScanKeyInit(&key[0],
- Anum_pg_propgraph_element_label_pgellabelid,
- BTEqualStrategyNumber,
- F_OIDEQ, ObjectIdGetDatum(labelid));
- scan = systable_beginscan(rel, PropgraphElementLabelLabelIndexId, true, NULL, 1, key);
- while (HeapTupleIsValid(tuple = systable_getnext(scan)))
- {
- Form_pg_propgraph_element_label otherellabel = (Form_pg_propgraph_element_label) GETSTRUCT(tuple);
-
- if (otherellabel->oid != ellabeloid)
- {
- ref_ellabeloid = otherellabel->oid;
- break;
- }
- }
- systable_endscan(scan);
-
- table_close(rel, AccessShareLock);
-
- /*
- * If there is no previous definition of this label, then we are done.
- */
- if (!ref_ellabeloid)
- return;
-
- /*
- * Now check number and names.
- *
- * XXX We could provide more detail in the error messages, but that would
- * probably only be useful for some ALTER commands, because otherwise it's
- * not really clear which label definition is the wrong one, and so you'd
- * have to construct a rather verbose report to be of any use. Let's keep
- * it simple for now.
- */
-
- myprops = get_element_label_property_names(ellabeloid);
- refprops = get_element_label_property_names(ref_ellabeloid);
-
- if (list_length(refprops) != list_length(myprops))
- ereport(ERROR,
- errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
- errmsg("mismatching number of properties in definition of label \"%s\"", get_propgraph_label_name(labelid)));
-
- diff1 = list_difference(myprops, refprops);
- diff2 = list_difference(refprops, myprops);
-
- if (diff1 || diff2)
- ereport(ERROR,
- errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
- errmsg("mismatching property names in definition of label \"%s\"", get_propgraph_label_name(labelid)));
-}
-
-/*
- * As above, but check all labels of a graph.
- */
-static void
-check_all_labels_properties(Oid pgrelid)
-{
- foreach_oid(labeloid, get_graph_label_ids(pgrelid))
- {
- foreach_oid(ellabeloid, get_label_element_label_ids(labeloid))
- {
- check_element_label_properties(ellabeloid);
- }
- }
-}
-
-/*
- * ALTER PROPERTY GRAPH
- */
-ObjectAddress
-AlterPropGraph(ParseState *pstate, const AlterPropGraphStmt *stmt)
-{
- Oid pgrelid;
- ListCell *lc;
- ObjectAddress pgaddress;
-
- /*
- * ShareRowExclusiveLock is required because this command runs some
- * graph-wide consistency checks that wouldn't work if more than one ALTER
- * PROPERTY GRAPH could operate on the same graph at once.
- */
- pgrelid = RangeVarGetRelidExtended(stmt->pgname,
- ShareRowExclusiveLock,
- stmt->missing_ok ? RVR_MISSING_OK : 0,
- RangeVarCallbackOwnsRelation,
- NULL);
- if (pgrelid == InvalidOid)
- {
- ereport(NOTICE,
- (errmsg("relation \"%s\" does not exist, skipping",
- stmt->pgname->relname)));
- return InvalidObjectAddress;
- }
-
- ObjectAddressSet(pgaddress, RelationRelationId, pgrelid);
-
- foreach(lc, stmt->add_vertex_tables)
- {
- PropGraphVertex *vertex = lfirst_node(PropGraphVertex, lc);
- struct element_info *vinfo;
- Relation rel;
- Oid peoid;
-
- vinfo = palloc0_object(struct element_info);
- vinfo->kind = PGEKIND_VERTEX;
-
- vinfo->relid = RangeVarGetRelidExtended(vertex->vtable, AccessShareLock, 0, RangeVarCallbackOwnsRelation, NULL);
-
- rel = table_open(vinfo->relid, NoLock);
-
- if (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP && get_rel_persistence(pgrelid) != RELPERSISTENCE_TEMP)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
- errmsg("cannot add temporary element table to non-temporary property graph"),
- errdetail("Table \"%s\" is a temporary table.", get_rel_name(vinfo->relid)),
- parser_errposition(pstate, vertex->vtable->location)));
-
- if (vertex->vtable->alias)
- vinfo->aliasname = vertex->vtable->alias->aliasname;
- else
- vinfo->aliasname = vertex->vtable->relname;
-
- vinfo->key = propgraph_element_get_key(pstate, vertex->vkey, rel, vinfo->aliasname, vertex->location);
-
- vinfo->labels = vertex->labels;
-
- table_close(rel, NoLock);
-
- if (SearchSysCacheExists2(PROPGRAPHELALIAS,
- ObjectIdGetDatum(pgrelid),
- CStringGetDatum(vinfo->aliasname)))
- ereport(ERROR,
- errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
- errmsg("alias \"%s\" already exists in property graph \"%s\"",
- vinfo->aliasname, stmt->pgname->relname),
- parser_errposition(pstate, vertex->vtable->location));
-
- peoid = insert_element_record(pgaddress, vinfo);
-
- CommandCounterIncrement();
- check_element_properties(peoid);
- check_all_labels_properties(pgrelid);
- }
-
- foreach(lc, stmt->add_edge_tables)
- {
- PropGraphEdge *edge = lfirst_node(PropGraphEdge, lc);
- struct element_info *einfo;
- Relation rel;
- Relation srcrel;
- Relation destrel;
- Oid peoid;
-
- einfo = palloc0_object(struct element_info);
- einfo->kind = PGEKIND_EDGE;
-
- einfo->relid = RangeVarGetRelidExtended(edge->etable, AccessShareLock, 0, RangeVarCallbackOwnsRelation, NULL);
-
- rel = table_open(einfo->relid, NoLock);
-
- if (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP && get_rel_persistence(pgrelid) != RELPERSISTENCE_TEMP)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
- errmsg("cannot add temporary element table to non-temporary property graph"),
- errdetail("Table \"%s\" is a temporary table.", get_rel_name(einfo->relid)),
- parser_errposition(pstate, edge->etable->location)));
-
- if (edge->etable->alias)
- einfo->aliasname = edge->etable->alias->aliasname;
- else
- einfo->aliasname = edge->etable->relname;
-
- einfo->key = propgraph_element_get_key(pstate, edge->ekey, rel, einfo->aliasname, edge->location);
-
- einfo->srcvertexid = get_vertex_oid(pstate, pgrelid, edge->esrcvertex, edge->location);
- einfo->destvertexid = get_vertex_oid(pstate, pgrelid, edge->edestvertex, edge->location);
-
- einfo->srcrelid = get_element_relid(einfo->srcvertexid);
- einfo->destrelid = get_element_relid(einfo->destvertexid);
-
- srcrel = table_open(einfo->srcrelid, AccessShareLock);
- destrel = table_open(einfo->destrelid, AccessShareLock);
-
- propgraph_edge_get_ref_keys(pstate, edge->esrckey, edge->esrcvertexcols, rel, srcrel,
- einfo->aliasname, edge->location, "SOURCE",
- &einfo->srckey, &einfo->srcref, &einfo->srceqop);
- propgraph_edge_get_ref_keys(pstate, edge->edestkey, edge->edestvertexcols, rel, destrel,
- einfo->aliasname, edge->location, "DESTINATION",
- &einfo->destkey, &einfo->destref, &einfo->desteqop);
-
- einfo->labels = edge->labels;
-
- table_close(destrel, NoLock);
- table_close(srcrel, NoLock);
-
- table_close(rel, NoLock);
-
- if (SearchSysCacheExists2(PROPGRAPHELALIAS,
- ObjectIdGetDatum(pgrelid),
- CStringGetDatum(einfo->aliasname)))
- ereport(ERROR,
- errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
- errmsg("alias \"%s\" already exists in property graph \"%s\"",
- einfo->aliasname, stmt->pgname->relname),
- parser_errposition(pstate, edge->etable->location));
-
- peoid = insert_element_record(pgaddress, einfo);
-
- CommandCounterIncrement();
- check_element_properties(peoid);
- check_all_labels_properties(pgrelid);
- }
-
- foreach(lc, stmt->drop_vertex_tables)
- {
- char *alias = strVal(lfirst(lc));
- Oid peoid;
- ObjectAddress obj;
-
- peoid = get_vertex_oid(pstate, pgrelid, alias, -1);
- ObjectAddressSet(obj, PropgraphElementRelationId, peoid);
- performDeletion(&obj, stmt->drop_behavior, 0);
- }
-
- foreach(lc, stmt->drop_edge_tables)
- {
- char *alias = strVal(lfirst(lc));
- Oid peoid;
- ObjectAddress obj;
-
- peoid = get_edge_oid(pstate, pgrelid, alias, -1);
- ObjectAddressSet(obj, PropgraphElementRelationId, peoid);
- performDeletion(&obj, stmt->drop_behavior, 0);
- }
-
- /* Remove any orphaned pg_propgraph_label entries */
- if (stmt->drop_vertex_tables || stmt->drop_edge_tables)
- {
- foreach_oid(labeloid, get_graph_label_ids(pgrelid))
- {
- if (!get_label_element_label_ids(labeloid))
- {
- ObjectAddress obj;
-
- ObjectAddressSet(obj, PropgraphLabelRelationId, labeloid);
- performDeletion(&obj, stmt->drop_behavior, 0);
- }
- }
- }
-
- foreach(lc, stmt->add_labels)
- {
- PropGraphLabelAndProperties *lp = lfirst_node(PropGraphLabelAndProperties, lc);
- Oid peoid;
- Oid pgerelid;
- Oid ellabeloid;
-
- Assert(lp->label);
-
- if (stmt->element_kind == PROPGRAPH_ELEMENT_KIND_VERTEX)
- peoid = get_vertex_oid(pstate, pgrelid, stmt->element_alias, -1);
- else
- peoid = get_edge_oid(pstate, pgrelid, stmt->element_alias, -1);
-
- pgerelid = get_element_relid(peoid);
-
- ellabeloid = insert_label_record(pgrelid, peoid, lp->label);
- insert_property_records(pgrelid, ellabeloid, pgerelid, lp->properties);
-
- CommandCounterIncrement();
- check_element_properties(peoid);
- check_element_label_properties(ellabeloid);
- }
-
- if (stmt->drop_label)
- {
- Oid peoid;
- Oid labeloid;
- Oid ellabeloid = InvalidOid;
- ObjectAddress obj;
- Relation ellabelrel;
- SysScanDesc ellabelscan;
- ScanKeyData ellabelkey[1];
- int nlabels;
- HeapTuple tuple;
-
- if (stmt->element_kind == PROPGRAPH_ELEMENT_KIND_VERTEX)
- peoid = get_vertex_oid(pstate, pgrelid, stmt->element_alias, -1);
- else
- peoid = get_edge_oid(pstate, pgrelid, stmt->element_alias, -1);
-
- labeloid = GetSysCacheOid2(PROPGRAPHLABELNAME,
- Anum_pg_propgraph_label_oid,
- ObjectIdGetDatum(pgrelid),
- CStringGetDatum(stmt->drop_label));
- if (!labeloid)
- ereport(ERROR,
- errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("property graph \"%s\" element \"%s\" has no label \"%s\"",
- get_rel_name(pgrelid), stmt->element_alias, stmt->drop_label),
- parser_errposition(pstate, -1));
-
- /*
- * Is the given label associated with the element? Is this the only
- * label associated with the element? Scan the
- * pg_propgraph_element_label table to find answers to these
- * questions. Stop scanning when we know both answers.
- */
- ellabelrel = table_open(PropgraphElementLabelRelationId, AccessShareLock);
- ScanKeyInit(&ellabelkey[0],
- Anum_pg_propgraph_element_label_pgelelid,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(peoid));
- ellabelscan = systable_beginscan(ellabelrel, PropgraphElementLabelElementLabelIndexId,
- true, NULL, 1, ellabelkey);
- nlabels = 0;
- while (HeapTupleIsValid(tuple = systable_getnext(ellabelscan)))
- {
- Form_pg_propgraph_element_label ellabelform = (Form_pg_propgraph_element_label) GETSTRUCT(tuple);
-
- nlabels++;
-
- if (ellabelform->pgellabelid == labeloid)
- ellabeloid = ellabelform->oid;
-
- if (nlabels > 1 && ellabeloid)
- break;
- }
- systable_endscan(ellabelscan);
- table_close(ellabelrel, AccessShareLock);
-
- if (!ellabeloid)
- ereport(ERROR,
- errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("property graph \"%s\" element \"%s\" has no label \"%s\"",
- get_rel_name(pgrelid), stmt->element_alias, stmt->drop_label),
- parser_errposition(pstate, -1));
-
- /*
- * Prevent dropping the last label from an element. Every element must
- * have at least one label associated with it.
- */
- if (nlabels == 1)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("cannot drop the last label from element \"%s\"",
- stmt->element_alias),
- errhint("Every element must have at least one label.")));
-
- ObjectAddressSet(obj, PropgraphElementLabelRelationId, ellabeloid);
- performDeletion(&obj, stmt->drop_behavior, 0);
-
- /* Remove any orphaned pg_propgraph_label entries */
- if (!get_label_element_label_ids(labeloid))
- {
- ObjectAddressSet(obj, PropgraphLabelRelationId, labeloid);
- performDeletion(&obj, stmt->drop_behavior, 0);
- }
- }
-
- if (stmt->add_properties)
- {
- Oid peoid;
- Oid pgerelid;
- Oid labeloid;
- Oid ellabeloid = InvalidOid;
-
- if (stmt->element_kind == PROPGRAPH_ELEMENT_KIND_VERTEX)
- peoid = get_vertex_oid(pstate, pgrelid, stmt->element_alias, -1);
- else
- peoid = get_edge_oid(pstate, pgrelid, stmt->element_alias, -1);
-
- labeloid = GetSysCacheOid2(PROPGRAPHLABELNAME,
- Anum_pg_propgraph_label_oid,
- ObjectIdGetDatum(pgrelid),
- CStringGetDatum(stmt->alter_label));
- if (labeloid)
- ellabeloid = GetSysCacheOid2(PROPGRAPHELEMENTLABELELEMENTLABEL,
- Anum_pg_propgraph_element_label_oid,
- ObjectIdGetDatum(peoid),
- ObjectIdGetDatum(labeloid));
- if (!ellabeloid)
- ereport(ERROR,
- errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("property graph \"%s\" element \"%s\" has no label \"%s\"",
- get_rel_name(pgrelid), stmt->element_alias, stmt->alter_label),
- parser_errposition(pstate, -1));
-
- pgerelid = get_element_relid(peoid);
-
- insert_property_records(pgrelid, ellabeloid, pgerelid, stmt->add_properties);
-
- CommandCounterIncrement();
- check_element_properties(peoid);
- check_element_label_properties(ellabeloid);
- }
-
- if (stmt->drop_properties)
- {
- Oid peoid;
- Oid labeloid;
- Oid ellabeloid = InvalidOid;
- ObjectAddress obj;
-
- if (stmt->element_kind == PROPGRAPH_ELEMENT_KIND_VERTEX)
- peoid = get_vertex_oid(pstate, pgrelid, stmt->element_alias, -1);
- else
- peoid = get_edge_oid(pstate, pgrelid, stmt->element_alias, -1);
-
- labeloid = GetSysCacheOid2(PROPGRAPHLABELNAME,
- Anum_pg_propgraph_label_oid,
- ObjectIdGetDatum(pgrelid),
- CStringGetDatum(stmt->alter_label));
- if (labeloid)
- ellabeloid = GetSysCacheOid2(PROPGRAPHELEMENTLABELELEMENTLABEL,
- Anum_pg_propgraph_element_label_oid,
- ObjectIdGetDatum(peoid),
- ObjectIdGetDatum(labeloid));
-
- if (!ellabeloid)
- ereport(ERROR,
- errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("property graph \"%s\" element \"%s\" has no label \"%s\"",
- get_rel_name(pgrelid), stmt->element_alias, stmt->alter_label),
- parser_errposition(pstate, -1));
-
- foreach(lc, stmt->drop_properties)
- {
- char *propname = strVal(lfirst(lc));
- Oid propoid;
- Oid plpoid = InvalidOid;
-
- propoid = GetSysCacheOid2(PROPGRAPHPROPNAME,
- Anum_pg_propgraph_property_oid,
- ObjectIdGetDatum(pgrelid),
- CStringGetDatum(propname));
- if (propoid)
- plpoid = GetSysCacheOid2(PROPGRAPHLABELPROP,
- Anum_pg_propgraph_label_property_oid,
- ObjectIdGetDatum(ellabeloid),
- ObjectIdGetDatum(propoid));
- if (!plpoid)
- ereport(ERROR,
- errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("property graph \"%s\" element \"%s\" label \"%s\" has no property \"%s\"",
- get_rel_name(pgrelid), stmt->element_alias, stmt->alter_label, propname),
- parser_errposition(pstate, -1));
-
- ObjectAddressSet(obj, PropgraphLabelPropertyRelationId, plpoid);
- performDeletion(&obj, stmt->drop_behavior, 0);
- }
-
- check_element_label_properties(ellabeloid);
- }
-
- /* Remove any orphaned pg_propgraph_property entries */
- if (stmt->drop_properties || stmt->drop_vertex_tables || stmt->drop_edge_tables || stmt->drop_label)
- {
- foreach_oid(propoid, get_graph_property_ids(pgrelid))
- {
- Relation rel;
- SysScanDesc scan;
- ScanKeyData key[1];
-
- rel = table_open(PropgraphLabelPropertyRelationId, RowShareLock);
- ScanKeyInit(&key[0],
- Anum_pg_propgraph_label_property_plppropid,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(propoid));
- /* XXX no suitable index */
- scan = systable_beginscan(rel, InvalidOid, true, NULL, 1, key);
- if (!systable_getnext(scan))
- {
- ObjectAddress obj;
-
- ObjectAddressSet(obj, PropgraphPropertyRelationId, propoid);
- performDeletion(&obj, stmt->drop_behavior, 0);
- }
-
- systable_endscan(scan);
- table_close(rel, RowShareLock);
- }
- }
-
- /*
- * Invalidate relcache entry of the property graph so that the queries in
- * the cached plans referencing the property graph will be rewritten
- * considering changes to the property graph.
- */
- CacheInvalidateRelcacheByRelid(pgrelid);
-
- return pgaddress;
-}
-
-/*
- * Get OID of vertex from graph OID and element alias. Element must be a
- * vertex, otherwise error.
- */
-static Oid
-get_vertex_oid(ParseState *pstate, Oid pgrelid, const char *alias, int location)
-{
- HeapTuple tuple;
- Oid peoid;
-
- tuple = SearchSysCache2(PROPGRAPHELALIAS, ObjectIdGetDatum(pgrelid), CStringGetDatum(alias));
- if (!tuple)
- ereport(ERROR,
- errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("property graph \"%s\" has no element with alias \"%s\"",
- get_rel_name(pgrelid), alias),
- parser_errposition(pstate, location));
-
- if (((Form_pg_propgraph_element) GETSTRUCT(tuple))->pgekind != PGEKIND_VERTEX)
- ereport(ERROR,
- errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("element \"%s\" of property graph \"%s\" is not a vertex",
- alias, get_rel_name(pgrelid)),
- parser_errposition(pstate, location));
-
- peoid = ((Form_pg_propgraph_element) GETSTRUCT(tuple))->oid;
-
- ReleaseSysCache(tuple);
-
- return peoid;
-}
-
-/*
- * Get OID of edge from graph OID and element alias. Element must be an edge,
- * otherwise error.
- */
-static Oid
-get_edge_oid(ParseState *pstate, Oid pgrelid, const char *alias, int location)
-{
- HeapTuple tuple;
- Oid peoid;
-
- tuple = SearchSysCache2(PROPGRAPHELALIAS, ObjectIdGetDatum(pgrelid), CStringGetDatum(alias));
- if (!tuple)
- ereport(ERROR,
- errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("property graph \"%s\" has no element with alias \"%s\"",
- get_rel_name(pgrelid), alias),
- parser_errposition(pstate, location));
-
- if (((Form_pg_propgraph_element) GETSTRUCT(tuple))->pgekind != PGEKIND_EDGE)
- ereport(ERROR,
- errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("element \"%s\" of property graph \"%s\" is not an edge",
- alias, get_rel_name(pgrelid)),
- parser_errposition(pstate, location));
-
- peoid = ((Form_pg_propgraph_element) GETSTRUCT(tuple))->oid;
-
- ReleaseSysCache(tuple);
-
- return peoid;
-}
-
-/*
- * Get the element table relation OID from the OID of the element.
- */
-static Oid
-get_element_relid(Oid peid)
-{
- HeapTuple tuple;
- Oid pgerelid;
-
- tuple = SearchSysCache1(PROPGRAPHELOID, ObjectIdGetDatum(peid));
- if (!tuple)
- elog(ERROR, "cache lookup failed for property graph element %u", peid);
-
- pgerelid = ((Form_pg_propgraph_element) GETSTRUCT(tuple))->pgerelid;
-
- ReleaseSysCache(tuple);
-
- return pgerelid;
-}
-
-/*
- * Get a list of all label OIDs of a graph.
- */
-static List *
-get_graph_label_ids(Oid graphid)
-{
- Relation rel;
- SysScanDesc scan;
- ScanKeyData key[1];
- HeapTuple tuple;
- List *result = NIL;
-
- rel = table_open(PropgraphLabelRelationId, AccessShareLock);
- ScanKeyInit(&key[0],
- Anum_pg_propgraph_label_pglpgid,
- BTEqualStrategyNumber,
- F_OIDEQ, ObjectIdGetDatum(graphid));
- scan = systable_beginscan(rel, PropgraphLabelGraphNameIndexId, true, NULL, 1, key);
- while (HeapTupleIsValid(tuple = systable_getnext(scan)))
- {
- result = lappend_oid(result, ((Form_pg_propgraph_label) GETSTRUCT(tuple))->oid);
- }
- systable_endscan(scan);
- table_close(rel, AccessShareLock);
-
- return result;
-}
-
-/*
- * Get a list of all element label OIDs for a label.
- */
-static List *
-get_label_element_label_ids(Oid labelid)
-{
- Relation rel;
- SysScanDesc scan;
- ScanKeyData key[1];
- HeapTuple tuple;
- List *result = NIL;
-
- rel = table_open(PropgraphElementLabelRelationId, AccessShareLock);
- ScanKeyInit(&key[0],
- Anum_pg_propgraph_element_label_pgellabelid,
- BTEqualStrategyNumber,
- F_OIDEQ, ObjectIdGetDatum(labelid));
- scan = systable_beginscan(rel, PropgraphElementLabelLabelIndexId, true, NULL, 1, key);
- while (HeapTupleIsValid(tuple = systable_getnext(scan)))
- {
- result = lappend_oid(result, ((Form_pg_propgraph_element_label) GETSTRUCT(tuple))->oid);
- }
- systable_endscan(scan);
- table_close(rel, AccessShareLock);
-
- return result;
-}
-
-/*
- * Get the names of properties associated with the given element label OID.
- *
- * The result is a list of String nodes (so we can use list functions to
- * detect differences).
- */
-static List *
-get_element_label_property_names(Oid ellabeloid)
-{
- Relation rel;
- SysScanDesc scan;
- ScanKeyData key[1];
- HeapTuple tuple;
- List *result = NIL;
-
- rel = table_open(PropgraphLabelPropertyRelationId, AccessShareLock);
-
- ScanKeyInit(&key[0],
- Anum_pg_propgraph_label_property_plpellabelid,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(ellabeloid));
-
- scan = systable_beginscan(rel, PropgraphLabelPropertyLabelPropIndexId, true, NULL, 1, key);
-
- while ((tuple = systable_getnext(scan)))
- {
- Form_pg_propgraph_label_property plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tuple);
-
- result = lappend(result, makeString(get_propgraph_property_name(plpform->plppropid)));
- }
-
- systable_endscan(scan);
- table_close(rel, AccessShareLock);
-
- return result;
-}
-
-/*
- * Get a list of all property OIDs of a graph.
- */
-static List *
-get_graph_property_ids(Oid graphid)
-{
- Relation rel;
- SysScanDesc scan;
- ScanKeyData key[1];
- HeapTuple tuple;
- List *result = NIL;
-
- rel = table_open(PropgraphPropertyRelationId, AccessShareLock);
- ScanKeyInit(&key[0],
- Anum_pg_propgraph_property_pgppgid,
- BTEqualStrategyNumber,
- F_OIDEQ, ObjectIdGetDatum(graphid));
- scan = systable_beginscan(rel, PropgraphPropertyNameIndexId, true, NULL, 1, key);
- while (HeapTupleIsValid(tuple = systable_getnext(scan)))
- {
- result = lappend_oid(result, ((Form_pg_propgraph_property) GETSTRUCT(tuple))->oid);
- }
- systable_endscan(scan);
- table_close(rel, AccessShareLock);
-
- return result;
-}
case OBJECT_OPFAMILY:
case OBJECT_PARAMETER_ACL:
case OBJECT_POLICY:
- case OBJECT_PROPGRAPH:
case OBJECT_PUBLICATION_NAMESPACE:
case OBJECT_PUBLICATION_REL:
case OBJECT_RULE:
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}
};
/*
* RemoveRelations
* Implements DROP TABLE, DROP INDEX, DROP SEQUENCE, DROP VIEW,
- * DROP MATERIALIZED VIEW, DROP FOREIGN TABLE, DROP PROPERTY GRAPH
+ * DROP MATERIALIZED VIEW, DROP FOREIGN TABLE
*/
void
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);
}
/*
- * Execute ALTER TABLE/INDEX/SEQUENCE/VIEW/MATERIALIZED VIEW/FOREIGN TABLE/PROPERTY GRAPH
+ * Execute ALTER TABLE/INDEX/SEQUENCE/VIEW/MATERIALIZED VIEW/FOREIGN TABLE
* RENAME
*/
ObjectAddress
case RELKIND_MATVIEW:
case RELKIND_FOREIGN_TABLE:
case RELKIND_PARTITIONED_TABLE:
- case RELKIND_PROPGRAPH:
/* ok to change owner */
break;
case RELKIND_INDEX:
(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))
/*
* Only relation RTEs and subquery RTEs that were once relation
- * RTEs (views, property graphs) have their perminfoindex set.
+ * RTEs (views) have their perminfoindex set.
*/
Assert(rte->rtekind == RTE_RELATION ||
(rte->rtekind == RTE_SUBQUERY &&
- (rte->relkind == RELKIND_VIEW || rte->relkind == RELKIND_PROPGRAPH)));
+ rte->relkind == RELKIND_VIEW));
(void) getRTEPermissionInfo(rteperminfos, rte);
/* Many-to-one mapping not allowed */
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),
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),
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 */
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;
}
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 */
case T_RangeTblRef:
case T_SortGroupClause:
case T_CTESearchClause:
- case T_GraphLabelRef:
- case T_GraphPropertyRef:
case T_MergeSupportFunc:
/* primitive node types with no expression subnodes */
break;
return true;
}
break;
- case T_GraphElementPattern:
- {
- GraphElementPattern *gep = (GraphElementPattern *) node;
-
- if (WALK(gep->labelexpr))
- return true;
- 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));
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:
case T_RangeTblRef:
case T_SortGroupClause:
case T_CTESearchClause:
- case T_GraphLabelRef:
- case T_GraphPropertyRef:
case T_MergeSupportFunc:
return copyObject(node);
case T_WithCheckOption:
return (Node *) newnode;
}
break;
- case T_GraphElementPattern:
- {
- GraphElementPattern *gep = (GraphElementPattern *) node;
- GraphElementPattern *newnode;
-
- FLATCOPY(newnode, gep, GraphElementPattern);
- MUTATE(newnode->labelexpr, gep->labelexpr, Node *);
- MUTATE(newnode->subexpr, gep->subexpr, List *);
- MUTATE(newnode->whereClause, gep->whereClause, Node *);
- newnode->quantifier = list_copy(gep->quantifier);
- return (Node *) newnode;
- }
- break;
- case T_GraphPattern:
- {
- GraphPattern *gp = (GraphPattern *) node;
- GraphPattern *newnode;
-
- FLATCOPY(newnode, gp, GraphPattern);
- MUTATE(newnode->path_pattern_list, gp->path_pattern_list, List *);
- MUTATE(newnode->whereClause, gp->whereClause, Node *);
- return (Node *) newnode;
- }
- break;
default:
elog(ERROR, "unrecognized node type: %d",
(int) nodeTag(node));
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:
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;
return true;
}
break;
- case T_GraphElementPattern:
- {
- GraphElementPattern *gep = (GraphElementPattern *) node;
-
- if (WALK(gep->labelexpr))
- return true;
- 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));
/* 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;
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);
/* 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;
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);
case RTE_GROUP:
/* these can't contain any lateral references */
break;
- case RTE_GRAPH_TABLE:
- /* shouldn't happen here */
- Assert(false);
- break;
}
}
}
/* these shouldn't be marked LATERAL */
Assert(false);
break;
- case RTE_GRAPH_TABLE:
- /* shouldn't happen here */
- Assert(false);
- break;
}
}
}
parse_enr.o \
parse_expr.o \
parse_func.o \
- parse_graphtable.o \
parse_jsontable.o \
parse_merge.o \
parse_node.o \
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);
* given SetOperationStmt node. context is a string for error messages
* ("UNION" etc.). recursive is true if it is a recursive union.
*/
-void
+static void
constructSetOpTargetlist(ParseState *pstate, SetOperationStmt *op,
const List *ltargetlist, const List *rtargetlist,
List **targetlist, const char *context, bool recursive)
LCS_asString(lc->strength)),
parser_errposition(pstate, thisrel->location)));
break;
- case RTE_GRAPH_TABLE:
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- /*------
- translator: %s is a SQL row locking clause such as FOR UPDATE */
- errmsg("%s cannot be applied to GRAPH_TABLE",
- LCS_asString(lc->strength)),
- parser_errposition(pstate, thisrel->location)));
- break;
/* Shouldn't be possible to see RTE_RESULT here */
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
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
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 DESTINATION
+ DEFERRABLE DEFERRED DEFINER DELETE_P DELIMITER DELIMITERS DEPENDS DEPTH DESC
DETACH DICTIONARY DISABLE_P DISCARD DISTINCT DO DOCUMENT_P DOMAIN_P
DOUBLE_P DROP
- 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
+ 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
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 GRAPH GRAPH_TABLE GREATEST GROUP_P GROUPING GROUPS
+ GENERATED GLOBAL GRANT GRANTED GREATEST GROUP_P GROUPING GROUPS
HANDLER HAVING HEADER_P HOLD HOUR_P
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 NODE
+ NAME_P NAMES NATIONAL NATURAL NCHAR NESTED NEW NEXT NFC NFD NFKC NFKD NO
NONE NORMALIZE NORMALIZED
NOT NOTHING NOTIFY NOTNULL NOWAIT NULL_P NULLIF
NULLS_P NUMERIC
PARALLEL PARAMETER PARSER PARTIAL PARTITION PASSING PASSWORD PATH
PERIOD PLACING PLAN PLANS POLICY PORTION
POSITION PRECEDING PRECISION PRESERVE PREPARE PREPARED PRIMARY
- PRIOR PRIVILEGES PROCEDURAL PROCEDURE PROCEDURES PROGRAM PROPERTIES PROPERTY PUBLICATION
+ PRIOR PRIVILEGES PROCEDURAL PROCEDURE PROCEDURES PROGRAM PUBLICATION
QUOTE QUOTES
RANGE READ REAL REASSIGN RECURSIVE REF_P REFERENCES REFERENCING
- REFRESH REINDEX RELATIONSHIP RELATIVE_P RELEASE RENAME REPACK REPEATABLE REPLACE REPLICA
+ REFRESH REINDEX 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
UNLISTEN UNLOGGED UNTIL UPDATE USER USING
VACUUM VALID VALIDATE VALIDATOR VALUE_P VALUES VARCHAR VARIADIC VARYING
- VERBOSE VERSION_P VERTEX VIEW VIEWS VIRTUAL VOLATILE
+ VERBOSE VERSION_P VIEW VIEWS VIRTUAL VOLATILE
WAIT WHEN WHERE WHITESPACE_P WINDOW WITH WITHIN WITHOUT WORK WRAPPER WRITE
%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 TO USING VALUE_P WITH WITHOUT PATH
-%left Op OPERATOR RIGHT_ARROW '|' /* multi-character ops and user-defined operators */
+%left Op OPERATOR /* multi-character ops and user-defined operators */
%left '+' '-'
%left '*' '/' '%'
%left '^'
| AlterOperatorStmt
| AlterTypeStmt
| AlterPolicyStmt
- | AlterPropGraphStmt
| AlterSeqStmt
| AlterSystemStmt
| AlterTableStmt
| AlterOpFamilyStmt
| CreatePolicyStmt
| CreatePLangStmt
- | CreatePropGraphStmt
| CreateSchemaStmt
| CreateSeqStmt
| CreateStmt
| 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; }
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);
;
-/*****************************************************************************
- *
- * 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
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);
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);
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);
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);
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, ">=", $1, $3, @2); }
| a_expr NOT_EQUALS a_expr
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "<>", $1, $3, @2); }
- | RIGHT_ARROW a_expr
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "->", NULL, $2, @1); }
- | '|' a_expr
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "|", NULL, $2, @1); }
- | 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); }
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, ">=", $1, $3, @2); }
| b_expr NOT_EQUALS b_expr
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "<>", $1, $3, @2); }
- | RIGHT_ARROW b_expr
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "->", NULL, $2, @1); }
- | '|' b_expr
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "|", NULL, $2, @1); }
- | 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
| LESS_EQUALS { $$ = "<="; }
| GREATER_EQUALS { $$ = ">="; }
| NOT_EQUALS { $$ = "<>"; }
- | RIGHT_ARROW { $$ = "->"; }
- | '|' { $$ = "|"; }
;
qual_Op: Op
| /* 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
| DELIMITERS
| DEPENDS
| DEPTH
- | DESTINATION
| DETACH
| DICTIONARY
| DISABLE_P
| DOUBLE_P
| DROP
| EACH
- | EDGE
| EMPTY_P
| ENABLE_P
| ENCODING
| GENERATED
| GLOBAL
| GRANTED
- | GRAPH
| GROUPS
| HANDLER
| HEADER_P
| NFKC
| NFKD
| NO
- | NODE
| NORMALIZED
| NOTHING
| NOTIFY
| PROCEDURE
| PROCEDURES
| PROGRAM
- | PROPERTIES
- | PROPERTY
| PUBLICATION
| QUOTE
| QUOTES
| REFERENCING
| REFRESH
| REINDEX
- | RELATIONSHIP
| RELATIVE_P
| RELEASE
| RENAME
| VALUE_P
| VARYING
| VERSION_P
- | VERTEX
| VIEW
| VIEWS
| VIRTUAL
| EXISTS
| EXTRACT
| FLOAT_P
- | GRAPH_TABLE
| GREATEST
| GROUPING
| INOUT
| DEPENDS
| DEPTH
| DESC
- | DESTINATION
| DETACH
| DICTIONARY
| DISABLE_P
| DOUBLE_P
| DROP
| EACH
- | EDGE
| ELSE
| EMPTY_P
| ENABLE_P
| GENERATED
| GLOBAL
| GRANTED
- | GRAPH
- | GRAPH_TABLE
| GREATEST
| GROUPING
| GROUPS
| NFKC
| NFKD
| NO
- | NODE
| NONE
| NORMALIZE
| NORMALIZED
| PROCEDURE
| PROCEDURES
| PROGRAM
- | PROPERTIES
- | PROPERTY
| PUBLICATION
| QUOTE
| QUOTES
| REFERENCING
| REFRESH
| REINDEX
- | RELATIONSHIP
| RELATIVE_P
| RELEASE
| RENAME
| VARIADIC
| VERBOSE
| VERSION_P
- | VERTEX
| VIEW
| VIEWS
| VIRTUAL
'parse_enr.c',
'parse_expr.c',
'parse_func.c',
- 'parse_graphtable.c',
'parse_jsontable.c',
'parse_merge.c',
'parse_node.c',
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
case EXPR_KIND_CYCLE_MARK:
errkind = true;
break;
- case EXPR_KIND_PROPGRAPH_PROPERTY:
- err = _("window functions are not allowed in property definition expressions");
- break;
case EXPR_KIND_FOR_PORTION:
err = _("window functions are not allowed in FOR PORTION OF expressions");
break;
#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"
#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"
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,
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;
- bool saved_hasAggs;
- bool saved_hasWindowFuncs;
- bool saved_hasTargetSRFs;
-
- 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;
-
- saved_hasAggs = pstate->p_hasAggs;
- pstate->p_hasAggs = false;
- saved_hasWindowFuncs = pstate->p_hasWindowFuncs;
- pstate->p_hasWindowFuncs = false;
- saved_hasTargetSRFs = pstate->p_hasTargetSRFs;
- pstate->p_hasTargetSRFs = 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);
- }
-
- /* resolve any still-unresolved output columns as being type text */
- if (pstate->p_resolve_unknowns)
- resolveTargetListUnknowns(pstate, columns);
-
- /*
- * Assign collations to column expressions now since
- * assign_query_collations() does not process rangetable entries.
- */
- assign_list_collations(pstate, columns);
-
- 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;
-
- /*
- * GRAPH_TABLE cannot yet evaluate aggregate, window, or set-returning
- * functions in its COLUMNS list, so prohibit them for now.
- */
- if (pstate->p_hasAggs)
- ereport(ERROR,
- errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("aggregate functions in GRAPH_TABLE COLUMNS are not supported"));
- if (pstate->p_hasWindowFuncs)
- ereport(ERROR,
- errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("window functions in GRAPH_TABLE COLUMNS are not supported"));
- if (pstate->p_hasTargetSRFs)
- ereport(ERROR,
- errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("set-returning functions in GRAPH_TABLE COLUMNS are not supported"));
- pstate->p_hasAggs = saved_hasAggs;
- pstate->p_hasWindowFuncs = saved_hasWindowFuncs;
- pstate->p_hasTargetSRFs = saved_hasTargetSRFs;
-
- return addRangeTableEntryForGraphTable(pstate, graphid, castNode(GraphPattern, gp), columns, colnames, rgt->alias, false, true);
-}
-
/*
* transformRangeTableSample --- transform a TABLESAMPLE clause
*
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) */
case T_CaseTestExpr:
case T_SetToDefault:
case T_CurrentOfExpr:
- case T_GraphPropertyRef:
/*
* General case for childless expression nodes. These should
#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"
case EXPR_KIND_COPY_WHERE:
case EXPR_KIND_GENERATED_COLUMN:
case EXPR_KIND_CYCLE_MARK:
- case EXPR_KIND_PROPGRAPH_PROPERTY:
/* okay */
break;
return node;
}
- /*
- * Element pattern variables in a GRAPH_TABLE clause form the innermost
- * namespace since we do not allow subqueries in GRAPH_TABLE patterns. Try
- * to resolve the column reference as a graph table property reference
- * before trying to resolve it as a regular column reference.
- */
- node = transformGraphTablePropertyRef(pstate, cref);
- if (node != NULL)
- return node;
-
/*----------
* The allowed syntaxes are:
*
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;
case EXPR_KIND_FOR_PORTION:
err = _("cannot use subquery in FOR PORTION OF expression");
break;
return "GENERATED AS";
case EXPR_KIND_CYCLE_MARK:
return "CYCLE";
- case EXPR_KIND_PROPGRAPH_PROPERTY:
- return "property definition expression";
case EXPR_KIND_FOR_PORTION:
return "FOR PORTION OF";
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;
case EXPR_KIND_FOR_PORTION:
err = _("set-returning functions are not allowed in FOR PORTION OF expressions");
break;
+++ /dev/null
-/*-------------------------------------------------------------------------
- *
- * 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_clause.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;
- HeapTuple pgptup;
- Form_pg_propgraph_property pgpform;
-
- /*
- * If we are transforming expression in an element pattern,
- * property references containing only that variable are allowed.
- */
- if (gpstate->cur_gep)
- {
- if (!gpstate->cur_gep->variable ||
- strcmp(elvarname, gpstate->cur_gep->variable) != 0)
- ereport(ERROR,
- errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("non-local element variable reference is not supported"),
- parser_errposition(pstate, cref->location));
- }
-
- gpr = makeNode(GraphPropertyRef);
- 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 containing
- * 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->quantifier)
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("element pattern quantifier is not supported")));
-
- Assert(!gpstate->cur_gep);
-
- gpstate->cur_gep = gep;
-
- gep->labelexpr = transformLabelExpr(gpstate, gep->labelexpr);
-
- gep->whereClause = transformWhereClause(pstate, gep->whereClause,
- EXPR_KIND_WHERE, "WHERE");
-
- /*
- * Assign collations here for the reason mentioned in the prologue of
- * transformGraphPattern().
- */
- assign_expr_collations(pstate, gep->whereClause);
-
- gpstate->cur_gep = NULL;
-
- return (Node *) gep;
-}
-
-/*
- * Transform a path term (list of GraphElementPattern's).
- */
-static Node *
-transformPathTerm(ParseState *pstate, List *path_term)
-{
- List *result = NIL;
- GraphElementPattern *prev_gep = NULL;
-
- foreach_node(GraphElementPattern, gep, path_term)
- {
- 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)),
- parser_errposition(pstate, gep->location)));
-
- if (IS_EDGE_PATTERN(gep->kind))
- {
- if (!prev_gep)
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("path pattern cannot start with an edge pattern"),
- parser_errposition(pstate, gep->location)));
- else if (prev_gep->kind != VERTEX_PATTERN)
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("edge pattern must be preceded by a vertex pattern"),
- parser_errposition(pstate, gep->location)));
- }
- else
- {
- if (prev_gep && !IS_EDGE_PATTERN(prev_gep->kind))
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("adjacent vertex patterns are not supported"),
- parser_errposition(pstate, gep->location)));
- }
-
- result = lappend(result,
- transformGraphElementPattern(pstate, gep));
- prev_gep = gep;
- }
-
- /* Path pattern should have at least one element pattern. */
- Assert(prev_gep);
-
- if (IS_EDGE_PATTERN(prev_gep->kind))
- {
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("path pattern cannot end with an edge pattern"),
- parser_errposition(pstate, prev_gep->location)));
- }
-
- return (Node *) result;
-}
-
-/*
- * Transform a path pattern list (list of path terms).
- */
-static Node *
-transformPathPatternList(ParseState *pstate, List *path_pattern)
-{
- List *result = NIL;
- GraphTableParseState *gpstate = pstate->p_graph_table_pstate;
-
- Assert(gpstate);
-
- /* 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")));
-
- /*
- * Collect all the variables in the path pattern into the
- * GraphTableParseState so that we can detect any non-local element
- * variable references. We need to do this before transforming the path
- * pattern so as to detect forward references to element variables in the
- * WHERE clause of an element pattern.
- */
- foreach_node(List, path_term, path_pattern)
- {
- foreach_node(GraphElementPattern, gep, path_term)
- {
- if (gep->variable)
- gpstate->variables = list_append_unique(gpstate->variables, makeString(pstrdup(gep->variable)));
- }
- }
-
- 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 constructed
- * list of variables in the GraphTableParseState to resolve property references
- * in the WHERE clause.
- *
- * Since most parts of the GraphPattern do not require collation assignment, we
- * assign collations to the required expressions as they are transformed. This
- * avoids the need to traverse the whole GraphPattern again and avoids exposing
- * it to assign_expr_collations().
- */
-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 = transformWhereClause(pstate, graph_pattern->whereClause,
- EXPR_KIND_WHERE, "WHERE");
- assign_expr_collations(pstate, graph_pattern->whereClause);
-
- return (Node *) graph_pattern;
-}
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.
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);
case RTE_VALUES:
case RTE_CTE:
case RTE_GROUP:
- case RTE_GRAPH_TABLE:
/*
- * Subselect, Table Functions, Values, CTE, GROUP RTEs, Property
- * graph references never have dropped columns
+ * Subselect, Table Functions, Values, CTE, GROUP RTEs never have
+ * dropped columns
*/
result = false;
break;
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)
case RTE_RELATION:
case RTE_VALUES:
case RTE_NAMEDTUPLESTORE:
- case RTE_GRAPH_TABLE:
case RTE_RESULT:
/*
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
* If you change either set, adjust the character lists appearing in the
* rule for "operator"!
*/
-self [,()\[\].;\:\|\+\-\*\/\%\^\<\>\=]
+self [,()\[\].;\:\+\-\*\/\%\^\<\>\=]
op_chars [\~\!\@\#\^\&\|\`\?\+\-\*\/\%\<\>\=]
operator {op_chars}+
return NOT_EQUALS;
}
-{right_arrow} {
- SET_YYLLOC();
- return RIGHT_ARROW;
- }
-
{self} {
SET_YYLLOC();
return yytext[0];
* 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
return NOT_EQUALS;
if (yytext[0] == '!' && yytext[1] == '=')
return NOT_EQUALS;
- if (yytext[0] == '-' && yytext[1] == '>')
- return RIGHT_ARROW;
}
}
OBJS = \
rewriteDefine.o \
- rewriteGraphTable.o \
rewriteHandler.o \
rewriteManip.o \
rewriteRemove.o \
backend_sources += files(
'rewriteDefine.c',
- 'rewriteGraphTable.c',
'rewriteHandler.c',
'rewriteManip.c',
'rewriteRemove.c',
+++ /dev/null
-/*-------------------------------------------------------------------------
- *
- * rewriteGraphTable.c
- * 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
- *
- * IDENTIFICATION
- * src/backend/rewrite/rewriteGraphTable.c
- *
- *-------------------------------------------------------------------------
- */
-#include "postgres.h"
-
-#include "access/genam.h"
-#include "access/sysattr.h"
-#include "access/table.h"
-#include "access/htup_details.h"
-#include "catalog/pg_operator.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 "miscadmin.h"
-#include "nodes/makefuncs.h"
-#include "nodes/nodeFuncs.h"
-#include "optimizer/optimizer.h"
-#include "parser/analyze.h"
-#include "parser/parse_collate.h"
-#include "parser/parse_func.h"
-#include "parser/parse_node.h"
-#include "parser/parse_oper.h"
-#include "parser/parse_relation.h"
-#include "parser/parsetree.h"
-#include "parser/parse_graphtable.h"
-#include "rewrite/rewriteGraphTable.h"
-#include "rewrite/rewriteHandler.h"
-#include "rewrite/rewriteManip.h"
-#include "utils/array.h"
-#include "utils/builtins.h"
-#include "utils/fmgroids.h"
-#include "utils/lsyscache.h"
-#include "utils/ruleutils.h"
-#include "utils/syscache.h"
-
-
-/*
- * Represents one path factor in a path.
- *
- * In a non-cyclic path, one path factor corresponds to one element pattern.
- *
- * In a cyclic path, one path factor corresponds to all the element patterns with
- * the same variable name.
- */
-struct path_factor
-{
- GraphElementPatternKind kind;
- const char *variable;
- Node *labelexpr;
- Node *whereClause;
- int factorpos; /* Position of this path factor in the list of
- * path factors representing a given path
- * pattern. */
- List *labeloids; /* OIDs of all the labels referenced in
- * labelexpr. */
- /* Links to adjacent vertex path factors if this is an edge path factor. */
- struct path_factor *src_pf;
- struct path_factor *dest_pf;
-};
-
-/*
- * Represents one property graph element (vertex or edge) in the path.
- *
- * Label expression in an element pattern resolves into a set of elements. We
- * create one path_element object for each of those elements.
- */
-struct path_element
-{
- /* Path factor from which this element is derived. */
- struct path_factor *path_factor;
- Oid elemoid;
- Oid reloid;
- /* Source and destination vertex elements for an edge element. */
- Oid srcvertexid;
- Oid destvertexid;
- /* Source and destination conditions for an edge element. */
- List *src_quals;
- List *dest_quals;
-};
-
-static Node *replace_property_refs(Oid propgraphid, Node *node, const List *mappings);
-static List *build_edge_vertex_link_quals(HeapTuple edgetup, int edgerti, int refrti, Oid refid, AttrNumber catalog_key_attnum, AttrNumber catalog_ref_attnum, AttrNumber catalog_eqop_attnum);
-static List *generate_queries_for_path_pattern(RangeTblEntry *rte, List *path_pattern);
-static Query *generate_query_for_graph_path(RangeTblEntry *rte, List *graph_path);
-static Node *generate_setop_from_pathqueries(List *pathqueries, List **rtable, List **targetlist);
-static List *generate_queries_for_path_pattern_recurse(RangeTblEntry *rte, List *pathqueries, List *cur_path, List *path_elem_lists, int elempos);
-static Query *generate_query_for_empty_path_pattern(RangeTblEntry *rte);
-static Query *generate_union_from_pathqueries(List **pathqueries);
-static List *get_path_elements_for_path_factor(Oid propgraphid, struct path_factor *pf);
-static bool is_property_associated_with_label(Oid labeloid, Oid propoid);
-static Node *get_element_property_expr(Oid elemoid, Oid propoid, int rtindex);
-
-/*
- * Convert GRAPH_TABLE clause into a subquery using relational
- * operators.
- */
-Query *
-rewriteGraphTable(Query *parsetree, int rt_index)
-{
- RangeTblEntry *rte;
- Query *graph_table_query;
- List *path_pattern;
- List *pathqueries = NIL;
-
- rte = rt_fetch(rt_index, parsetree->rtable);
-
- Assert(list_length(rte->graph_pattern->path_pattern_list) == 1);
-
- path_pattern = linitial(rte->graph_pattern->path_pattern_list);
- pathqueries = generate_queries_for_path_pattern(rte, path_pattern);
- graph_table_query = generate_union_from_pathqueries(&pathqueries);
-
- AcquireRewriteLocks(graph_table_query, true, false);
-
- rte->rtekind = RTE_SUBQUERY;
- rte->subquery = graph_table_query;
- rte->lateral = true;
-
- /*
- * Reset no longer applicable fields, to appease
- * WRITE_READ_PARSE_PLAN_TREES.
- */
- rte->graph_pattern = NULL;
- rte->graph_table_columns = NIL;
-
- return parsetree;
-}
-
-/*
- * Generate queries representing the given path pattern applied to the given
- * property graph.
- *
- * A path pattern consists of one or more element patterns. Each of the element
- * patterns may be satisfied by multiple elements. A path satisfying the given
- * path pattern consists of one element from each element pattern. There can be
- * as many paths as the number of combinations of the elements. A path pattern
- * in itself is a K-partite graph where K = number of element patterns in the
- * path pattern. The possible paths are computed by performing a DFS in this
- * graph. The DFS is implemented as recursion. Each of these paths is converted
- * into a query connecting all the elements in that path. Set of these queries is
- * returned.
- *
- * Between every two vertex elements in the path there is an edge element that
- * connects them. An edge connects two vertices identified by the source and
- * destination keys respectively. The connection between an edge and its
- * adjacent vertex is naturally computed as an equi-join between edge and vertex
- * table on their respective keys. Hence the query representing one path
- * consists of JOINs between edge and vertex tables.
- *
- * generate_queries_for_path_pattern() starts the recursion but actual work is
- * done by generate_queries_for_path_pattern_recurse().
- * generate_query_for_graph_path() constructs a query for a given path.
- *
- * A path pattern may end up producing no path if any of the element patterns
- * yields no elements or the edge patterns yield no edges connecting adjacent
- * vertex patterns. In such a case a dummy query which returns no result is
- * returned (generate_query_for_empty_path_pattern()).
- *
- * 'path_pattern' is given path pattern to be applied on the property graph in
- * the GRAPH_TABLE clause represented by given 'rte'.
- */
-static List *
-generate_queries_for_path_pattern(RangeTblEntry *rte, List *path_pattern)
-{
- List *pathqueries = NIL;
- List *path_elem_lists = NIL;
- int factorpos = 0;
- List *path_factors = NIL;
- struct path_factor *prev_pf = NULL;
-
- Assert(list_length(path_pattern) > 0);
-
- /*
- * Create a list of path factors representing the given path pattern
- * linking edge path factors to their adjacent vertex path factors.
- *
- * While doing that merge element patterns with the same variable name
- * into a single path_factor.
- */
- foreach_node(GraphElementPattern, gep, path_pattern)
- {
- struct path_factor *pf = NULL;
-
- /*
- * Unsupported conditions should have been caught by the parser
- * itself. We have corresponding Asserts here to document the
- * assumptions in this code.
- */
- Assert(gep->kind == VERTEX_PATTERN || IS_EDGE_PATTERN(gep->kind));
- Assert(!gep->quantifier);
-
- foreach_ptr(struct path_factor, other, path_factors)
- {
- if (gep->variable && other->variable &&
- strcmp(gep->variable, other->variable) == 0)
- {
- if (other->kind != gep->kind)
- ereport(ERROR,
- (errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("element patterns with same variable name \"%s\" but different element pattern types",
- gep->variable)));
-
- /*
- * If both the element patterns have label expressions, they
- * need to be conjuncted, which is not supported right now.
- *
- * However, an empty label expression means all labels.
- * Conjunction of any label expression with all labels is the
- * expression itself. Hence if only one of the two element
- * patterns has a label expression use that expression.
- */
- if (!other->labelexpr)
- other->labelexpr = gep->labelexpr;
- else if (gep->labelexpr && !equal(other->labelexpr, gep->labelexpr))
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("element patterns with same variable name \"%s\" but different label expressions are not supported",
- gep->variable)));
-
- /*
- * If two element patterns have the same variable name, they
- * represent the same set of graph elements and hence are
- * constrained by conditions from both the element patterns.
- */
- if (!other->whereClause)
- other->whereClause = gep->whereClause;
- else if (gep->whereClause)
- other->whereClause = (Node *) makeBoolExpr(AND_EXPR,
- list_make2(other->whereClause, gep->whereClause),
- -1);
- pf = other;
- break;
- }
- }
-
- if (!pf)
- {
- pf = palloc0_object(struct path_factor);
- pf->factorpos = factorpos++;
- pf->kind = gep->kind;
- pf->labelexpr = gep->labelexpr;
- pf->variable = gep->variable;
- pf->whereClause = gep->whereClause;
-
- path_factors = lappend(path_factors, pf);
- }
-
- /*
- * Setup links to the previous path factor in the path.
- *
- * If the previous path factor represents an edge, this path factor
- * represents an adjacent vertex; the source vertex for an edge
- * pointing left or the destination vertex for an edge pointing right.
- * If this path factor represents an edge, the previous path factor
- * represents an adjacent vertex; source vertex for an edge pointing
- * right or the destination vertex for an edge pointing left.
- *
- * Edge pointing in any direction is treated similar to that pointing
- * in right direction here. When constructing a query in
- * generate_query_for_graph_path(), we will try links in both the
- * directions.
- *
- * If multiple edge patterns share the same variable name, they
- * constrain the adjacent vertex patterns since an edge can connect
- * only one pair of vertices. These adjacent vertex patterns need to
- * be merged even though they have different variables. Such element
- * patterns form a walk of graph where vertex and edges are repeated.
- * For example, in (a)-[b]->(c)<-[b]-(d), (a) and (d) represent the
- * same vertex element. This is slightly harder to implement and
- * probably less useful. Hence not supported for now.
- */
- if (prev_pf)
- {
- if (prev_pf->kind == EDGE_PATTERN_RIGHT || prev_pf->kind == EDGE_PATTERN_ANY)
- {
- Assert(!IS_EDGE_PATTERN(pf->kind));
- if (prev_pf->dest_pf && prev_pf->dest_pf != pf)
- ereport(ERROR,
- errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
- errmsg("an edge cannot connect more than two vertices even in a cyclic pattern"));
- prev_pf->dest_pf = pf;
- }
- else if (prev_pf->kind == EDGE_PATTERN_LEFT)
- {
- Assert(!IS_EDGE_PATTERN(pf->kind));
- if (prev_pf->src_pf && prev_pf->src_pf != pf)
- ereport(ERROR,
- errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
- errmsg("an edge cannot connect more than two vertices even in a cyclic pattern"));
- prev_pf->src_pf = pf;
- }
- else
- {
- Assert(prev_pf->kind == VERTEX_PATTERN);
- Assert(IS_EDGE_PATTERN(pf->kind));
- }
-
- if (pf->kind == EDGE_PATTERN_RIGHT || pf->kind == EDGE_PATTERN_ANY)
- {
- Assert(!IS_EDGE_PATTERN(prev_pf->kind));
- if (pf->src_pf && pf->src_pf != prev_pf)
- ereport(ERROR,
- errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
- errmsg("an edge cannot connect more than two vertices even in a cyclic pattern"));
- pf->src_pf = prev_pf;
- }
- else if (pf->kind == EDGE_PATTERN_LEFT)
- {
- Assert(!IS_EDGE_PATTERN(prev_pf->kind));
- if (pf->dest_pf && pf->dest_pf != prev_pf)
- ereport(ERROR,
- errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
- errmsg("an edge cannot connect more than two vertices even in a cyclic pattern"));
- pf->dest_pf = prev_pf;
- }
- else
- {
- Assert(pf->kind == VERTEX_PATTERN);
- Assert(IS_EDGE_PATTERN(prev_pf->kind));
- }
- }
-
- prev_pf = pf;
- }
-
- /*
- * Collect list of elements for each path factor. Do this after all the
- * edge links are setup correctly.
- */
- foreach_ptr(struct path_factor, pf, path_factors)
- path_elem_lists = lappend(path_elem_lists,
- get_path_elements_for_path_factor(rte->relid, pf));
-
- pathqueries = generate_queries_for_path_pattern_recurse(rte, pathqueries,
- NIL, path_elem_lists, 0);
- if (!pathqueries)
- pathqueries = list_make1(generate_query_for_empty_path_pattern(rte));
-
- return pathqueries;
-}
-
-/*
- * Recursive workhorse function of generate_queries_for_path_pattern().
- *
- * `elempos` is the position of the next element being added in the path being
- * built.
- */
-static List *
-generate_queries_for_path_pattern_recurse(RangeTblEntry *rte, List *pathqueries, List *cur_path, List *path_elem_lists, int elempos)
-{
- List *path_elems = list_nth_node(List, path_elem_lists, elempos);
-
- /* Guard against stack overflow due to complex path patterns. */
- check_stack_depth();
-
- foreach_ptr(struct path_element, pe, path_elems)
- {
- CHECK_FOR_INTERRUPTS();
-
- /* Update current path being built with current element. */
- cur_path = lappend(cur_path, pe);
-
- /*
- * If this is the last element in the path, generate query for the
- * completed path. Else recurse processing the next element.
- */
- if (list_length(path_elem_lists) == list_length(cur_path))
- {
- Query *pathquery = generate_query_for_graph_path(rte, cur_path);
-
- Assert(elempos == list_length(path_elem_lists) - 1);
- if (pathquery)
- pathqueries = lappend(pathqueries, pathquery);
- }
- else
- pathqueries = generate_queries_for_path_pattern_recurse(rte, pathqueries,
- cur_path,
- path_elem_lists,
- elempos + 1);
- /* Make way for the next element at the same position. */
- cur_path = list_delete_last(cur_path);
- }
-
- return pathqueries;
-}
-
-/*
- * Construct a query representing given graph path.
- *
- * The query contains:
- *
- * 1. targetlist corresponding to the COLUMNS clause of GRAPH_TABLE clause
- *
- * 2. quals corresponding to the WHERE clause of individual elements, WHERE
- * clause in GRAPH_TABLE clause and quals representing edge-vertex links.
- *
- * 3. fromlist containing all elements in the path
- *
- * The collations of property expressions are obtained from the catalog. The
- * collations of expressions in COLUMNS and WHERE clauses are assigned before
- * rewriting the graph table. The collations of the edge-vertex link quals are
- * assigned when crafting those quals. Thus everything in the query that requires
- * collation assignment has been taken care of already. No separate collation
- * assignment is required in this function.
- *
- * More details in the prologue of generate_queries_for_path_pattern().
- */
-static Query *
-generate_query_for_graph_path(RangeTblEntry *rte, List *graph_path)
-{
- Query *path_query = makeNode(Query);
- List *fromlist = NIL;
- List *qual_exprs = NIL;
- List *vars;
-
- path_query->commandType = CMD_SELECT;
-
- foreach_ptr(struct path_element, pe, graph_path)
- {
- struct path_factor *pf = pe->path_factor;
- RangeTblRef *rtr;
- Relation rel;
- ParseNamespaceItem *pni;
-
- Assert(pf->kind == VERTEX_PATTERN || IS_EDGE_PATTERN(pf->kind));
-
- /* Add conditions representing edge connections. */
- if (IS_EDGE_PATTERN(pf->kind))
- {
- struct path_element *src_pe;
- struct path_element *dest_pe;
- Expr *edge_qual = NULL;
-
- Assert(pf->src_pf && pf->dest_pf);
- src_pe = list_nth(graph_path, pf->src_pf->factorpos);
- dest_pe = list_nth(graph_path, pf->dest_pf->factorpos);
-
- /* Make sure that the links of adjacent vertices are correct. */
- Assert(pf->src_pf == src_pe->path_factor &&
- pf->dest_pf == dest_pe->path_factor);
-
- if (src_pe->elemoid == pe->srcvertexid &&
- dest_pe->elemoid == pe->destvertexid)
- edge_qual = makeBoolExpr(AND_EXPR,
- list_concat(copyObject(pe->src_quals),
- copyObject(pe->dest_quals)),
- -1);
-
- /*
- * An edge pattern in any direction matches edges in both
- * directions, try swapping source and destination. When the
- * source and destination is the same vertex table, quals
- * corresponding to either direction may get satisfied. Hence OR
- * the quals corresponding to both the directions.
- */
- if (pf->kind == EDGE_PATTERN_ANY &&
- dest_pe->elemoid == pe->srcvertexid &&
- src_pe->elemoid == pe->destvertexid)
- {
- List *src_quals = copyObject(pe->dest_quals);
- List *dest_quals = copyObject(pe->src_quals);
- Expr *rev_edge_qual;
-
- /* Swap the source and destination varnos in the quals. */
- ChangeVarNodes((Node *) dest_quals, pe->path_factor->src_pf->factorpos + 1,
- pe->path_factor->dest_pf->factorpos + 1, 0);
- ChangeVarNodes((Node *) src_quals, pe->path_factor->dest_pf->factorpos + 1,
- pe->path_factor->src_pf->factorpos + 1, 0);
-
- rev_edge_qual = makeBoolExpr(AND_EXPR, list_concat(src_quals, dest_quals), -1);
- if (edge_qual)
- edge_qual = makeBoolExpr(OR_EXPR, list_make2(edge_qual, rev_edge_qual), -1);
- else
- edge_qual = rev_edge_qual;
- }
-
- /*
- * If the given edge element does not connect the adjacent vertex
- * elements in this path, the path is broken. Abandon this path as
- * it won't return any rows.
- */
- if (edge_qual == NULL)
- return NULL;
-
- qual_exprs = lappend(qual_exprs, edge_qual);
- }
- else
- Assert(!pe->src_quals && !pe->dest_quals);
-
- /*
- * Create RangeTblEntry for this element table.
- *
- * SQL/PGQ standard (Ref. Section 11.19, Access rule 2 and General
- * rule 4) does not specify whose access privileges to use when
- * accessing the element tables: property graph owner's or current
- * user's. It is safer to use current user's privileges to avoid
- * unprivileged data access through a property graph. This is inline
- * with the views being security_invoker by default.
- */
- rel = table_open(pe->reloid, AccessShareLock);
- pni = addRangeTableEntryForRelation(make_parsestate(NULL), rel, AccessShareLock,
- NULL, true, false);
- table_close(rel, NoLock);
- path_query->rtable = lappend(path_query->rtable, pni->p_rte);
- path_query->rteperminfos = lappend(path_query->rteperminfos, pni->p_perminfo);
- pni->p_rte->perminfoindex = list_length(path_query->rteperminfos);
- rtr = makeNode(RangeTblRef);
- rtr->rtindex = list_length(path_query->rtable);
- fromlist = lappend(fromlist, rtr);
-
- /*
- * Make sure that the assumption mentioned in create_pe_for_element()
- * holds true; that the elements' RangeTblEntrys are added in the
- * order in which their respective path factors appear in the list of
- * path factors representing the path pattern.
- */
- Assert(pf->factorpos + 1 == rtr->rtindex);
-
- if (pf->whereClause)
- {
- Node *tr;
-
- tr = replace_property_refs(rte->relid, pf->whereClause, list_make1(pe));
-
- qual_exprs = lappend(qual_exprs, tr);
- }
- }
-
- if (rte->graph_pattern->whereClause)
- {
- Node *path_quals = replace_property_refs(rte->relid,
- (Node *) rte->graph_pattern->whereClause,
- graph_path);
-
- qual_exprs = lappend(qual_exprs, path_quals);
- }
-
- path_query->jointree = makeFromExpr(fromlist,
- qual_exprs ? (Node *) makeBoolExpr(AND_EXPR, qual_exprs, -1) : NULL);
-
- /* Construct query targetlist from COLUMNS specification of GRAPH_TABLE. */
- path_query->targetList = castNode(List,
- replace_property_refs(rte->relid,
- (Node *) rte->graph_table_columns,
- graph_path));
-
- /*
- * Mark the columns being accessed in the path query as requiring SELECT
- * privilege. Any lateral columns should have been handled when the
- * corresponding ColumnRefs were transformed. Ignore those here.
- */
- vars = pull_vars_of_level((Node *) list_make2(qual_exprs, path_query->targetList), 0);
- foreach_node(Var, var, vars)
- {
- RTEPermissionInfo *perminfo = getRTEPermissionInfo(path_query->rteperminfos,
- rt_fetch(var->varno, path_query->rtable));
-
- /* Must offset the attnum to fit in a bitmapset */
- perminfo->selectedCols = bms_add_member(perminfo->selectedCols,
- var->varattno - FirstLowInvalidHeapAttributeNumber);
- }
-
- return path_query;
-}
-
-/*
- * Construct a query which would not return any rows.
- *
- * More details in the prologue of generate_queries_for_path_pattern().
- */
-static Query *
-generate_query_for_empty_path_pattern(RangeTblEntry *rte)
-{
- Query *query = makeNode(Query);
-
- query->commandType = CMD_SELECT;
- query->rtable = NIL;
- query->rteperminfos = NIL;
- query->jointree = makeFromExpr(NIL, (Node *) makeBoolConst(false, false));
-
- /*
- * Even though no rows are returned, the result still projects the same
- * columns as projected by GRAPH_TABLE clause. Do this by constructing a
- * target list full of NULL values.
- */
- foreach_node(TargetEntry, te, rte->graph_table_columns)
- {
- Node *nte = (Node *) te->expr;
-
- te->expr = (Expr *) makeNullConst(exprType(nte), exprTypmod(nte), exprCollation(nte));
- query->targetList = lappend(query->targetList, te);
- }
-
- return query;
-}
-
-/*
- * Construct a query which is UNION of given path queries.
- *
- * The UNION query derives collations of its targetlist entries from the
- * corresponding targetlist entries of the path queries. The targetlists of path
- * queries being UNION'ed already have collations assigned. No separate
- * collation assignment required in this function.
- *
- * The function destroys given pathqueries list while constructing
- * SetOperationStmt recursively. Hence the function always returns with
- * `pathqueries` set to NIL.
- */
-static Query *
-generate_union_from_pathqueries(List **pathqueries)
-{
- List *rtable = NIL;
- Query *sampleQuery = linitial_node(Query, *pathqueries);
- SetOperationStmt *sostmt;
- Query *union_query;
- int resno;
- ListCell *lctl,
- *lct,
- *lcm,
- *lcc;
-
- Assert(list_length(*pathqueries) > 0);
-
- /* If there's only one pathquery, no need to construct a UNION query. */
- if (list_length(*pathqueries) == 1)
- {
- *pathqueries = NIL;
- return sampleQuery;
- }
-
- sostmt = castNode(SetOperationStmt,
- generate_setop_from_pathqueries(*pathqueries, &rtable, NULL));
-
- /* Encapsulate the set operation statement into a Query. */
- union_query = makeNode(Query);
- union_query->commandType = CMD_SELECT;
- union_query->rtable = rtable;
- union_query->setOperations = (Node *) sostmt;
- union_query->rteperminfos = NIL;
- union_query->jointree = makeFromExpr(NIL, NULL);
-
- /*
- * Generate dummy targetlist for outer query using column names from one
- * of the queries and common datatypes/collations of topmost set
- * operation. It shouldn't matter which query. Also it shouldn't matter
- * which RT index is used as varno in the target list entries, as long as
- * it corresponds to a real RT entry; else funny things may happen when
- * the tree is mashed by rule rewriting. So we use 1 since there's always
- * one RT entry at least.
- */
- Assert(rt_fetch(1, rtable));
- union_query->targetList = NULL;
- resno = 1;
- forfour(lct, sostmt->colTypes,
- lcm, sostmt->colTypmods,
- lcc, sostmt->colCollations,
- lctl, sampleQuery->targetList)
- {
- Oid colType = lfirst_oid(lct);
- int32 colTypmod = lfirst_int(lcm);
- Oid colCollation = lfirst_oid(lcc);
- TargetEntry *sample_tle = (TargetEntry *) lfirst(lctl);
- char *colName;
- TargetEntry *tle;
- Var *var;
-
- Assert(!sample_tle->resjunk);
- colName = pstrdup(sample_tle->resname);
- var = makeVar(1, sample_tle->resno, colType, colTypmod, colCollation, 0);
- var->location = exprLocation((Node *) sample_tle->expr);
- tle = makeTargetEntry((Expr *) var, (AttrNumber) resno++, colName, false);
- union_query->targetList = lappend(union_query->targetList, tle);
- }
-
- *pathqueries = NIL;
- return union_query;
-}
-
-/*
- * Construct a query which is UNION of all the given path queries.
- *
- * The function destroys given pathqueries list while constructing
- * SetOperationStmt recursively.
- */
-static Node *
-generate_setop_from_pathqueries(List *pathqueries, List **rtable, List **targetlist)
-{
- SetOperationStmt *sostmt;
- Query *lquery;
- Node *rarg;
- RangeTblRef *lrtr = makeNode(RangeTblRef);
- List *rtargetlist;
- ParseNamespaceItem *pni;
-
- /* Guard against stack overflow due to many path queries. */
- check_stack_depth();
-
- /* Recursion termination condition. */
- if (list_length(pathqueries) == 0)
- {
- *targetlist = NIL;
- return NULL;
- }
-
- lquery = linitial_node(Query, pathqueries);
-
- /*
- * Each path query will become a subquery of the UNION statement. So any
- * Vars that already refer outside the path query must be adjusted for
- * additional query level.
- */
- IncrementVarSublevelsUp((Node *) lquery, 1, 1);
-
- pni = addRangeTableEntryForSubquery(make_parsestate(NULL), lquery, NULL,
- false, false);
- *rtable = lappend(*rtable, pni->p_rte);
- lrtr->rtindex = list_length(*rtable);
- rarg = generate_setop_from_pathqueries(list_delete_first(pathqueries), rtable, &rtargetlist);
- if (rarg == NULL)
- {
- /*
- * No further path queries in the list. Convert the last query into a
- * RangeTblRef as expected by SetOperationStmt. Extract a list of the
- * non-junk TLEs for upper-level processing.
- */
- if (targetlist)
- {
- *targetlist = NIL;
- foreach_node(TargetEntry, tle, lquery->targetList)
- {
- if (!tle->resjunk)
- *targetlist = lappend(*targetlist, tle);
- }
- }
- return (Node *) lrtr;
- }
-
- sostmt = makeNode(SetOperationStmt);
- sostmt->op = SETOP_UNION;
- sostmt->all = true;
- sostmt->larg = (Node *) lrtr;
- sostmt->rarg = rarg;
- constructSetOpTargetlist(NULL, sostmt, lquery->targetList, rtargetlist, targetlist, "UNION", false);
-
- return (Node *) sostmt;
-}
-
-/*
- * Construct a path_element object for the graph element given by `elemoid`
- * satisfied by the path factor `pf`.
- *
- * If the type of graph element does not fit the element pattern kind, the
- * function returns NULL.
- */
-static struct path_element *
-create_pe_for_element(struct path_factor *pf, Oid elemoid)
-{
- HeapTuple eletup = SearchSysCache1(PROPGRAPHELOID, ObjectIdGetDatum(elemoid));
- Form_pg_propgraph_element pgeform;
- struct path_element *pe;
-
- if (!eletup)
- elog(ERROR, "cache lookup failed for property graph element %u", elemoid);
- pgeform = ((Form_pg_propgraph_element) GETSTRUCT(eletup));
-
- if ((pgeform->pgekind == PGEKIND_VERTEX && pf->kind != VERTEX_PATTERN) ||
- (pgeform->pgekind == PGEKIND_EDGE && !IS_EDGE_PATTERN(pf->kind)))
- {
- ReleaseSysCache(eletup);
- return NULL;
- }
-
- pe = palloc0_object(struct path_element);
- pe->path_factor = pf;
- pe->elemoid = elemoid;
- pe->reloid = pgeform->pgerelid;
-
- /*
- * When a path is converted into a query
- * (generate_query_for_graph_path()), a RangeTblEntry will be created for
- * every element in the path. Fixing rtindexes of RangeTblEntrys here
- * makes it possible to craft elements' qual expressions only once while
- * we have access to the catalog entry. Otherwise they need to be crafted
- * as many times as the number of paths a given element appears in,
- * fetching catalog entry again each time. Hence we simply assume
- * RangeTblEntrys will be created in the same order in which the
- * corresponding path factors appear in the list of path factors
- * representing a path pattern. That way their rtindexes will be same as
- * path_factor::factorpos + 1.
- */
- if (IS_EDGE_PATTERN(pf->kind))
- {
- pe->srcvertexid = pgeform->pgesrcvertexid;
- pe->destvertexid = pgeform->pgedestvertexid;
- Assert(pf->src_pf && pf->dest_pf);
-
- pe->src_quals = build_edge_vertex_link_quals(eletup, pf->factorpos + 1, pf->src_pf->factorpos + 1,
- pe->srcvertexid,
- Anum_pg_propgraph_element_pgesrckey,
- Anum_pg_propgraph_element_pgesrcref,
- Anum_pg_propgraph_element_pgesrceqop);
- pe->dest_quals = build_edge_vertex_link_quals(eletup, pf->factorpos + 1, pf->dest_pf->factorpos + 1,
- pe->destvertexid,
- Anum_pg_propgraph_element_pgedestkey,
- Anum_pg_propgraph_element_pgedestref,
- Anum_pg_propgraph_element_pgedesteqop);
- }
-
- ReleaseSysCache(eletup);
-
- return pe;
-}
-
-/*
- * Returns the list of OIDs of graph labels which the given label expression
- * resolves to in the given property graph.
- */
-static List *
-get_labels_for_expr(Oid propgraphid, Node *labelexpr)
-{
- List *label_oids;
-
- if (!labelexpr)
- {
- Relation rel;
- SysScanDesc scan;
- ScanKeyData key[1];
- HeapTuple tup;
-
- /*
- * According to section 9.2 "Contextual inference of a set of labels"
- * subclause 2.a.ii of SQL/PGQ standard, element pattern which does
- * not have a label expression is considered to have label expression
- * equivalent to '%|!%' which is set of all labels.
- */
- label_oids = NIL;
- rel = table_open(PropgraphLabelRelationId, AccessShareLock);
- ScanKeyInit(&key[0],
- Anum_pg_propgraph_label_pglpgid,
- BTEqualStrategyNumber,
- F_OIDEQ, ObjectIdGetDatum(propgraphid));
- scan = systable_beginscan(rel, PropgraphLabelGraphNameIndexId,
- true, NULL, 1, key);
- while (HeapTupleIsValid(tup = systable_getnext(scan)))
- {
- Form_pg_propgraph_label label = (Form_pg_propgraph_label) GETSTRUCT(tup);
-
- label_oids = lappend_oid(label_oids, label->oid);
- }
- systable_endscan(scan);
- table_close(rel, AccessShareLock);
- }
- else if (IsA(labelexpr, GraphLabelRef))
- {
- GraphLabelRef *glr = castNode(GraphLabelRef, labelexpr);
-
- label_oids = list_make1_oid(glr->labelid);
- }
- else if (IsA(labelexpr, BoolExpr))
- {
- BoolExpr *be = castNode(BoolExpr, labelexpr);
- List *label_exprs = be->args;
-
- label_oids = NIL;
- foreach_node(GraphLabelRef, glr, label_exprs)
- label_oids = lappend_oid(label_oids, glr->labelid);
- }
- else
- {
- /*
- * should not reach here since gram.y will not generate a label
- * expression with other node types.
- */
- elog(ERROR, "unsupported label expression node: %d", (int) nodeTag(labelexpr));
- }
-
- return label_oids;
-}
-
-/*
- * Return a list of all the graph elements that satisfy the graph element pattern
- * represented by the given path_factor `pf`.
- *
- * First we find all the graph labels that satisfy the label expression in path
- * factor. Each label is associated with one or more graph elements. A union of
- * all such elements satisfies the element pattern. We create one path_element
- * object representing every element whose graph element kind qualifies the
- * element pattern kind. A list of all such path_element objects is returned.
- *
- * Note that we need to report an error for an explicitly specified label which
- * is not associated with any graph element of the required kind. So we have to
- * treat each label separately. Without that requirement we could have collected
- * all the unique elements first and then created path_element objects for them
- * to simplify the code.
- */
-static List *
-get_path_elements_for_path_factor(Oid propgraphid, struct path_factor *pf)
-{
- List *label_oids = get_labels_for_expr(propgraphid, pf->labelexpr);
- List *elem_oids_seen = NIL;
- List *pf_elem_oids = NIL;
- List *path_elements = NIL;
- List *unresolved_labels = NIL;
- Relation rel;
- SysScanDesc scan;
- ScanKeyData key[1];
- HeapTuple tup;
-
- /*
- * A property graph element can be either a vertex or an edge. Other types
- * of path factors like nested path pattern need to be handled separately
- * when supported.
- */
- Assert(pf->kind == VERTEX_PATTERN || IS_EDGE_PATTERN(pf->kind));
-
- rel = table_open(PropgraphElementLabelRelationId, AccessShareLock);
- foreach_oid(labeloid, label_oids)
- {
- bool found = false;
-
- ScanKeyInit(&key[0],
- Anum_pg_propgraph_element_label_pgellabelid,
- BTEqualStrategyNumber,
- F_OIDEQ, ObjectIdGetDatum(labeloid));
- scan = systable_beginscan(rel, PropgraphElementLabelLabelIndexId, true,
- NULL, 1, key);
- while (HeapTupleIsValid(tup = systable_getnext(scan)))
- {
- Form_pg_propgraph_element_label label_elem = (Form_pg_propgraph_element_label) GETSTRUCT(tup);
- Oid elem_oid = label_elem->pgelelid;
-
- if (!list_member_oid(elem_oids_seen, elem_oid))
- {
- /*
- * Create path_element object if the new element qualifies the
- * element pattern kind.
- */
- struct path_element *pe = create_pe_for_element(pf, elem_oid);
-
- if (pe)
- {
- path_elements = lappend(path_elements, pe);
-
- /* Remember qualified elements. */
- pf_elem_oids = lappend_oid(pf_elem_oids, elem_oid);
- found = true;
- }
-
- /*
- * Remember qualified and unqualified elements processed so
- * far to avoid processing already processed elements again.
- */
- elem_oids_seen = lappend_oid(elem_oids_seen, label_elem->pgelelid);
- }
- else if (list_member_oid(pf_elem_oids, elem_oid))
- {
- /*
- * The graph element is known to qualify the given element
- * pattern. Flag that the current label has at least one
- * qualified element associated with it.
- */
- found = true;
- }
- }
-
- if (!found)
- {
- /*
- * We did not find any qualified element associated with this
- * label. The label or its properties can not be associated with
- * the given element pattern. Throw an error if the label was
- * explicitly specified in the element pattern. Otherwise remember
- * it for later use.
- */
- if (!pf->labelexpr)
- unresolved_labels = lappend_oid(unresolved_labels, labeloid);
- else
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("no property graph element of type \"%s\" has label \"%s\" associated with it in property graph \"%s\"",
- pf->kind == VERTEX_PATTERN ? "vertex" : "edge",
- &nb