git.postgresql.org Git - postgresql.git/commitdiff

189 min read Original article ↗

  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)&lt;-[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)&lt;-(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">&sect;</ulink>

-<ulink url="&commit_baseurl;c5b3253b8">&sect;</ulink>

-<ulink url="&commit_baseurl;a0dd0702e">&sect;</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