LCOV - differential code coverage report
Current view: top level - src/backend/parser - parse_graphtable.c (source / functions) Coverage Total Hit UNC GNC
Current: bed3ffbf9d952be6c7d739d068cdce44c046dfb7 vs 574581b50ac9c63dd9e4abebb731a3b67e5b50f6 Lines: 91.2 % 125 114 11 114
Current Date: 2026-05-05 10:23:31 +0900 Functions: 100.0 % 7 7 7
Baseline: lcov-20260505-025707-baseline Branches: 75.9 % 137 104 33 104
Baseline Date: 2026-05-05 10:27:06 +0900 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(30,360] days: 91.2 % 125 114 11 114
Function coverage date bins:
(30,360] days: 100.0 % 7 7 7
Branch coverage date bins:
(30,360] days: 75.9 % 137 104 33 104

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*-------------------------------------------------------------------------
                                  2                 :                :  *
                                  3                 :                :  * parse_graphtable.c
                                  4                 :                :  *    parsing of GRAPH_TABLE
                                  5                 :                :  *
                                  6                 :                :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
                                  7                 :                :  * Portions Copyright (c) 1994, Regents of the University of California
                                  8                 :                :  *
                                  9                 :                :  *
                                 10                 :                :  * IDENTIFICATION
                                 11                 :                :  *    src/backend/parser/parse_graphtable.c
                                 12                 :                :  *
                                 13                 :                :  *-------------------------------------------------------------------------
                                 14                 :                :  */
                                 15                 :                : 
                                 16                 :                : #include "postgres.h"
                                 17                 :                : 
                                 18                 :                : #include "access/genam.h"
                                 19                 :                : #include "access/htup_details.h"
                                 20                 :                : #include "access/table.h"
                                 21                 :                : #include "catalog/pg_propgraph_label.h"
                                 22                 :                : #include "catalog/pg_propgraph_property.h"
                                 23                 :                : #include "miscadmin.h"
                                 24                 :                : #include "nodes/makefuncs.h"
                                 25                 :                : #include "parser/parse_collate.h"
                                 26                 :                : #include "parser/parse_expr.h"
                                 27                 :                : #include "parser/parse_graphtable.h"
                                 28                 :                : #include "parser/parse_node.h"
                                 29                 :                : #include "utils/fmgroids.h"
                                 30                 :                : #include "utils/lsyscache.h"
                                 31                 :                : #include "utils/relcache.h"
                                 32                 :                : #include "utils/syscache.h"
                                 33                 :                : 
                                 34                 :                : 
                                 35                 :                : /*
                                 36                 :                :  * Return human-readable name of the type of graph element pattern in
                                 37                 :                :  * GRAPH_TABLE clause, usually for error message purpose.
                                 38                 :                :  */
                                 39                 :                : static const char *
   50 peter@eisentraut.org       40                 :GNC           4 : get_gep_kind_name(GraphElementPatternKind gepkind)
                                 41                 :                : {
                                 42   [ -  -  -  -  :              4 :     switch (gepkind)
                                              +  - ]
                                 43                 :                :     {
   50 peter@eisentraut.org       44                 :UNC           0 :         case VERTEX_PATTERN:
                                 45                 :              0 :             return "vertex";
                                 46                 :              0 :         case EDGE_PATTERN_LEFT:
                                 47                 :              0 :             return "edge pointing left";
                                 48                 :              0 :         case EDGE_PATTERN_RIGHT:
                                 49                 :              0 :             return "edge pointing right";
                                 50                 :              0 :         case EDGE_PATTERN_ANY:
                                 51                 :              0 :             return "edge pointing any direction";
   50 peter@eisentraut.org       52                 :GNC           4 :         case PAREN_EXPR:
                                 53                 :              4 :             return "nested path pattern";
                                 54                 :                :     }
                                 55                 :                : 
                                 56                 :                :     /*
                                 57                 :                :      * When a GraphElementPattern is constructed by the parser, it will set a
                                 58                 :                :      * value from the GraphElementPatternKind enum. But we may get here if the
                                 59                 :                :      * GraphElementPatternKind value stored in a catalog is corrupted.
                                 60                 :                :      */
   50 peter@eisentraut.org       61                 :UNC           0 :     return "unknown";
                                 62                 :                : }
                                 63                 :                : 
                                 64                 :                : /*
                                 65                 :                :  * Transform a property reference.
                                 66                 :                :  *
                                 67                 :                :  * A property reference is parsed as a ColumnRef of the form:
                                 68                 :                :  * <variable>.<property>. If <variable> is one of the variables bound to an
                                 69                 :                :  * element pattern in the graph pattern and <property> can be resolved as a
                                 70                 :                :  * property of the property graph, then we return a GraphPropertyRef node
                                 71                 :                :  * representing the property reference. If the <variable> exists in the graph
                                 72                 :                :  * pattern but <property> does not exist in the property graph, we raise an
                                 73                 :                :  * error. However, if <variable> does not exist in the graph pattern, we return
                                 74                 :                :  * NULL to let the caller handle it as some other kind of ColumnRef. The
                                 75                 :                :  * variables bound to the element patterns in the graph pattern are expected to
                                 76                 :                :  * be collected in the GraphTableParseState.
                                 77                 :                :  */
                                 78                 :                : Node *
   50 peter@eisentraut.org       79                 :GNC     1196885 : transformGraphTablePropertyRef(ParseState *pstate, ColumnRef *cref)
                                 80                 :                : {
                                 81                 :        1196885 :     GraphTableParseState *gpstate = pstate->p_graph_table_pstate;
                                 82                 :                : 
                                 83         [ +  + ]:        1196885 :     if (!gpstate)
                                 84                 :        1195194 :         return NULL;
                                 85                 :                : 
                                 86         [ +  + ]:           1691 :     if (list_length(cref->fields) == 2)
                                 87                 :                :     {
                                 88                 :           1679 :         Node       *field1 = linitial(cref->fields);
                                 89                 :           1679 :         Node       *field2 = lsecond(cref->fields);
                                 90                 :                :         char       *elvarname;
                                 91                 :                :         char       *propname;
                                 92                 :                : 
                                 93   [ +  -  +  + ]:           1679 :         if (IsA(field1, A_Star) || IsA(field2, A_Star))
                                 94                 :                :         {
                                 95         [ +  + ]:              8 :             if (pstate->p_expr_kind == EXPR_KIND_SELECT_TARGET)
                                 96         [ +  - ]:              4 :                 ereport(ERROR,
                                 97                 :                :                         errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                 98                 :                :                         errmsg("\"*\" is not supported here"),
                                 99                 :                :                         parser_errposition(pstate, cref->location));
                                100                 :                :             else
                                101         [ +  - ]:              4 :                 ereport(ERROR,
                                102                 :                :                         errcode(ERRCODE_SYNTAX_ERROR),
                                103                 :                :                         errmsg("\"*\" not allowed here"),
                                104                 :                :                         parser_errposition(pstate, cref->location));
                                105                 :                :         }
                                106                 :                : 
                                107                 :           1671 :         elvarname = strVal(field1);
                                108                 :           1671 :         propname = strVal(field2);
                                109                 :                : 
                                110         [ +  + ]:           1671 :         if (list_member(gpstate->variables, field1))
                                111                 :                :         {
                                112                 :                :             GraphPropertyRef *gpr;
                                113                 :                :             HeapTuple   pgptup;
                                114                 :                :             Form_pg_propgraph_property pgpform;
                                115                 :                : 
                                116                 :                :             /*
                                117                 :                :              * If we are transforming expression in an element pattern,
                                118                 :                :              * property references containing only that variable are allowed.
                                119                 :                :              */
   35                           120         [ +  + ]:           1649 :             if (gpstate->cur_gep)
                                121                 :                :             {
                                122         [ +  + ]:            159 :                 if (!gpstate->cur_gep->variable ||
                                123         [ +  + ]:            151 :                     strcmp(elvarname, gpstate->cur_gep->variable) != 0)
                                124         [ +  - ]:             16 :                     ereport(ERROR,
                                125                 :                :                             errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                126                 :                :                             errmsg("non-local element variable reference is not supported"),
                                127                 :                :                             parser_errposition(pstate, cref->location));
                                128                 :                :             }
                                129                 :                : 
                                130                 :           1633 :             gpr = makeNode(GraphPropertyRef);
   50                           131                 :           1633 :             pgptup = SearchSysCache2(PROPGRAPHPROPNAME, ObjectIdGetDatum(gpstate->graphid), CStringGetDatum(propname));
                                132         [ +  + ]:           1633 :             if (!HeapTupleIsValid(pgptup))
                                133         [ +  - ]:              4 :                 ereport(ERROR,
                                134                 :                :                         errcode(ERRCODE_SYNTAX_ERROR),
                                135                 :                :                         errmsg("property \"%s\" does not exist", propname));
                                136                 :           1629 :             pgpform = (Form_pg_propgraph_property) GETSTRUCT(pgptup);
                                137                 :                : 
                                138                 :           1629 :             gpr->location = cref->location;
                                139                 :           1629 :             gpr->elvarname = elvarname;
                                140                 :           1629 :             gpr->propid = pgpform->oid;
                                141                 :           1629 :             gpr->typeId = pgpform->pgptypid;
                                142                 :           1629 :             gpr->typmod = pgpform->pgptypmod;
                                143                 :           1629 :             gpr->collation = pgpform->pgpcollation;
                                144                 :                : 
                                145                 :           1629 :             ReleaseSysCache(pgptup);
                                146                 :                : 
                                147                 :           1629 :             return (Node *) gpr;
                                148                 :                :         }
                                149                 :                :     }
                                150                 :                : 
                                151                 :             34 :     return NULL;
                                152                 :                : }
                                153                 :                : 
                                154                 :                : /*
                                155                 :                :  * Transform a label expression.
                                156                 :                :  *
                                157                 :                :  * A label expression is parsed as either a ColumnRef with a single field or a
                                158                 :                :  * label expression like label disjunction. The single field in the ColumnRef is
                                159                 :                :  * treated as a label name and transformed to a GraphLabelRef node. The label
                                160                 :                :  * expression is recursively transformed into an expression tree containing
                                161                 :                :  * GraphLabelRef nodes corresponding to the names of the labels appearing in the
                                162                 :                :  * expression. If any label name cannot be resolved to a label in the property
                                163                 :                :  * graph, an error is raised.
                                164                 :                :  */
                                165                 :                : static Node *
                                166                 :           1767 : transformLabelExpr(GraphTableParseState *gpstate, Node *labelexpr)
                                167                 :                : {
                                168                 :                :     Node       *result;
                                169                 :                : 
                                170         [ +  + ]:           1767 :     if (labelexpr == NULL)
                                171                 :            662 :         return NULL;
                                172                 :                : 
                                173                 :           1105 :     check_stack_depth();
                                174                 :                : 
                                175      [ +  +  - ]:           1105 :     switch (nodeTag(labelexpr))
                                176                 :                :     {
                                177                 :           1050 :         case T_ColumnRef:
                                178                 :                :             {
                                179                 :           1050 :                 ColumnRef  *cref = (ColumnRef *) labelexpr;
                                180                 :                :                 const char *labelname;
                                181                 :                :                 Oid         labelid;
                                182                 :                :                 GraphLabelRef *lref;
                                183                 :                : 
                                184         [ -  + ]:           1050 :                 Assert(list_length(cref->fields) == 1);
                                185                 :           1050 :                 labelname = strVal(linitial(cref->fields));
                                186                 :                : 
                                187                 :           1050 :                 labelid = GetSysCacheOid2(PROPGRAPHLABELNAME, Anum_pg_propgraph_label_oid, ObjectIdGetDatum(gpstate->graphid), CStringGetDatum(labelname));
                                188         [ +  + ]:           1050 :                 if (!labelid)
                                189         [ +  - ]:              4 :                     ereport(ERROR,
                                190                 :                :                             errcode(ERRCODE_UNDEFINED_OBJECT),
                                191                 :                :                             errmsg("label \"%s\" does not exist in property graph \"%s\"", labelname, get_rel_name(gpstate->graphid)));
                                192                 :                : 
                                193                 :           1046 :                 lref = makeNode(GraphLabelRef);
                                194                 :           1046 :                 lref->labelid = labelid;
                                195                 :           1046 :                 lref->location = cref->location;
                                196                 :                : 
                                197                 :           1046 :                 result = (Node *) lref;
                                198                 :           1046 :                 break;
                                199                 :                :             }
                                200                 :                : 
                                201                 :             55 :         case T_BoolExpr:
                                202                 :                :             {
                                203                 :             55 :                 BoolExpr   *be = (BoolExpr *) labelexpr;
                                204                 :                :                 ListCell   *lc;
                                205                 :             55 :                 List       *args = NIL;
                                206                 :                : 
                                207   [ +  -  +  +  :            165 :                 foreach(lc, be->args)
                                              +  + ]
                                208                 :                :                 {
                                209                 :            114 :                     Node       *arg = (Node *) lfirst(lc);
                                210                 :                : 
                                211                 :            114 :                     arg = transformLabelExpr(gpstate, arg);
                                212                 :            110 :                     args = lappend(args, arg);
                                213                 :                :                 }
                                214                 :                : 
                                215                 :             51 :                 result = (Node *) makeBoolExpr(be->boolop, args, be->location);
                                216                 :             51 :                 break;
                                217                 :                :             }
                                218                 :                : 
   50 peter@eisentraut.org      219                 :UNC           0 :         default:
                                220                 :                :             /* should not reach here */
                                221         [ #  # ]:              0 :             elog(ERROR, "unsupported label expression node: %d", (int) nodeTag(labelexpr));
                                222                 :                :             result = NULL;      /* keep compiler quiet */
                                223                 :                :             break;
                                224                 :                :     }
                                225                 :                : 
   50 peter@eisentraut.org      226                 :GNC        1097 :     return result;
                                227                 :                : }
                                228                 :                : 
                                229                 :                : /*
                                230                 :                :  * Transform a GraphElementPattern.
                                231                 :                :  *
                                232                 :                :  * Transform the label expression and the where clause in the element pattern
                                233                 :                :  * given by GraphElementPattern. The variable name in the GraphElementPattern is
                                234                 :                :  * added to the list of variables in the GraphTableParseState which is used to
                                235                 :                :  * resolve property references in this element pattern or elsewhere in the
                                236                 :                :  * GRAPH_TABLE.
                                237                 :                :  */
                                238                 :                : static Node *
                                239                 :           1657 : transformGraphElementPattern(ParseState *pstate, GraphElementPattern *gep)
                                240                 :                : {
                                241                 :           1657 :     GraphTableParseState *gpstate = pstate->p_graph_table_pstate;
                                242                 :                : 
                                243         [ +  + ]:           1657 :     if (gep->quantifier)
                                244         [ +  - ]:              4 :         ereport(ERROR,
                                245                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                246                 :                :                  errmsg("element pattern quantifier is not supported")));
                                247                 :                : 
   35                           248         [ -  + ]:           1653 :     Assert(!gpstate->cur_gep);
                                249                 :                : 
                                250                 :           1653 :     gpstate->cur_gep = gep;
                                251                 :                : 
   50                           252                 :           1653 :     gep->labelexpr = transformLabelExpr(gpstate, gep->labelexpr);
                                253                 :                : 
                                254                 :           1649 :     gep->whereClause = transformExpr(pstate, gep->whereClause, EXPR_KIND_WHERE);
                                255                 :                : 
                                256                 :                :     /*
                                257                 :                :      * Assign collations here for the reason mentioned in the prologue of
                                258                 :                :      * transformGraphPattern().
                                259                 :                :      */
                                260                 :           1629 :     assign_expr_collations(pstate, gep->whereClause);
                                261                 :                : 
   35                           262                 :           1629 :     gpstate->cur_gep = NULL;
                                263                 :                : 
   50                           264                 :           1629 :     return (Node *) gep;
                                265                 :                : }
                                266                 :                : 
                                267                 :                : /*
                                268                 :                :  * Transform a path term (list of GraphElementPattern's).
                                269                 :                :  */
                                270                 :                : static Node *
                                271                 :            559 : transformPathTerm(ParseState *pstate, List *path_term)
                                272                 :                : {
                                273                 :            559 :     List       *result = NIL;
   39                           274                 :            559 :     GraphElementPattern *prev_gep = NULL;
                                275                 :                : 
   50                           276   [ +  -  +  +  :           2703 :     foreach_node(GraphElementPattern, gep, path_term)
                                              +  + ]
                                277                 :                :     {
   39                           278   [ +  +  +  +  :           1673 :         if (gep->kind != VERTEX_PATTERN && !IS_EDGE_PATTERN(gep->kind))
                                        +  +  +  + ]
                                279         [ +  - ]:              4 :             ereport(ERROR,
                                280                 :                :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                281                 :                :                      errmsg("unsupported element pattern kind: \"%s\"", get_gep_kind_name(gep->kind)),
                                282                 :                :                      parser_errposition(pstate, gep->location)));
                                283                 :                : 
                                284   [ +  +  +  +  :           1669 :         if (IS_EDGE_PATTERN(gep->kind))
                                              +  + ]
                                285                 :                :         {
                                286         [ +  + ]:            569 :             if (!prev_gep)
                                287         [ +  - ]:              4 :                 ereport(ERROR,
                                288                 :                :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                289                 :                :                          errmsg("path pattern cannot start with an edge pattern"),
                                290                 :                :                          parser_errposition(pstate, gep->location)));
                                291         [ +  + ]:            565 :             else if (prev_gep->kind != VERTEX_PATTERN)
                                292         [ +  - ]:              4 :                 ereport(ERROR,
                                293                 :                :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                294                 :                :                          errmsg("edge pattern must be preceded by a vertex pattern"),
                                295                 :                :                          parser_errposition(pstate, gep->location)));
                                296                 :                :         }
                                297                 :                :         else
                                298                 :                :         {
                                299   [ +  +  +  +  :           1100 :             if (prev_gep && !IS_EDGE_PATTERN(prev_gep->kind))
                                        +  +  +  + ]
                                300         [ +  - ]:              4 :                 ereport(ERROR,
                                301                 :                :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                302                 :                :                          errmsg("adjacent vertex patterns are not supported"),
                                303                 :                :                          parser_errposition(pstate, gep->location)));
                                304                 :                :         }
                                305                 :                : 
   50                           306                 :           1629 :         result = lappend(result,
                                307                 :           1657 :                          transformGraphElementPattern(pstate, gep));
   39                           308                 :           1629 :         prev_gep = gep;
                                309                 :                :     }
                                310                 :                : 
                                311                 :                :     /* Path pattern should have at least one element pattern. */
                                312         [ -  + ]:            515 :     Assert(prev_gep);
                                313                 :                : 
                                314   [ +  +  +  -  :            515 :     if (IS_EDGE_PATTERN(prev_gep->kind))
                                              -  + ]
                                315                 :                :     {
                                316         [ +  - ]:              4 :         ereport(ERROR,
                                317                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                318                 :                :                  errmsg("path pattern cannot end with an edge pattern"),
                                319                 :                :                  parser_errposition(pstate, prev_gep->location)));
                                320                 :                :     }
                                321                 :                : 
   50                           322                 :            511 :     return (Node *) result;
                                323                 :                : }
                                324                 :                : 
                                325                 :                : /*
                                326                 :                :  * Transform a path pattern list (list of path terms).
                                327                 :                :  */
                                328                 :                : static Node *
                                329                 :            563 : transformPathPatternList(ParseState *pstate, List *path_pattern)
                                330                 :                : {
                                331                 :            563 :     List       *result = NIL;
   35                           332                 :            563 :     GraphTableParseState *gpstate = pstate->p_graph_table_pstate;
                                333                 :                : 
                                334         [ -  + ]:            563 :     Assert(gpstate);
                                335                 :                : 
                                336                 :                :     /* Grammar doesn't allow empty path pattern list */
   50                           337         [ -  + ]:            563 :     Assert(list_length(path_pattern) > 0);
                                338                 :                : 
                                339                 :                :     /*
                                340                 :                :      * We do not support multiple path patterns in one GRAPH_TABLE clause
                                341                 :                :      * right now. But we may do so in future.
                                342                 :                :      */
                                343         [ +  + ]:            563 :     if (list_length(path_pattern) != 1)
                                344         [ +  - ]:              4 :         ereport(ERROR,
                                345                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                346                 :                :                  errmsg("multiple path patterns in one GRAPH_TABLE clause not supported")));
                                347                 :                : 
                                348                 :                :     /*
                                349                 :                :      * Collect all the variables in the path pattern into the
                                350                 :                :      * GraphTableParseState so that we can detect any non-local element
                                351                 :                :      * variable references. We need to do this before transforming the path
                                352                 :                :      * pattern so as to detect forward references to element variables in the
                                353                 :                :      * WHERE clause of an element pattern.
                                354                 :                :      */
   35                           355   [ +  -  +  +  :           1677 :     foreach_node(List, path_term, path_pattern)
                                              +  + ]
                                356                 :                :     {
                                357   [ +  -  +  +  :           2835 :         foreach_node(GraphElementPattern, gep, path_term)
                                              +  + ]
                                358                 :                :         {
                                359         [ +  + ]:           1717 :             if (gep->variable)
                                360                 :           1364 :                 gpstate->variables = list_append_unique(gpstate->variables, makeString(pstrdup(gep->variable)));
                                361                 :                :         }
                                362                 :                :     }
                                363                 :                : 
   50                           364   [ +  -  +  +  :           1581 :     foreach_node(List, path_term, path_pattern)
                                              +  + ]
                                365                 :            559 :         result = lappend(result, transformPathTerm(pstate, path_term));
                                366                 :                : 
                                367                 :            511 :     return (Node *) result;
                                368                 :                : }
                                369                 :                : 
                                370                 :                : /*
                                371                 :                :  * Transform a GraphPattern.
                                372                 :                :  *
                                373                 :                :  * A GraphPattern consists of a list of one or more path patterns and an
                                374                 :                :  * optional where clause. Transform them. We use the previously constructed
                                375                 :                :  * list of variables in the GraphTableParseState to resolve property references
                                376                 :                :  * in the WHERE clause.
                                377                 :                :  *
                                378                 :                :  * Since most parts of the GraphPattern do not require collation assignment, we
                                379                 :                :  * assign collations to the required expressions as they are transformed.  This
                                380                 :                :  * avoids the need to traverse the whole GraphPattern again and avoids exposing
                                381                 :                :  * it to assign_expr_collations().
                                382                 :                :  */
                                383                 :                : Node *
                                384                 :            563 : transformGraphPattern(ParseState *pstate, GraphPattern *graph_pattern)
                                385                 :                : {
                                386                 :            563 :     List       *path_pattern_list = castNode(List,
                                387                 :                :                                              transformPathPatternList(pstate, graph_pattern->path_pattern_list));
                                388                 :                : 
                                389                 :            511 :     graph_pattern->path_pattern_list = path_pattern_list;
                                390                 :            511 :     graph_pattern->whereClause = transformExpr(pstate, graph_pattern->whereClause, EXPR_KIND_WHERE);
                                391                 :            511 :     assign_expr_collations(pstate, graph_pattern->whereClause);
                                392                 :                : 
                                393                 :            511 :     return (Node *) graph_pattern;
                                394                 :                : }
        

Generated by: LCOV version 2.5.0-beta