PostgreSQL Source Code git master
Loading...
Searching...
No Matches
parse_graphtable.c
Go to the documentation of this file.
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"
23#include "miscadmin.h"
24#include "nodes/makefuncs.h"
26#include "parser/parse_expr.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 */
39static const char *
41{
42 switch (gepkind)
43 {
44 case VERTEX_PATTERN:
45 return "vertex";
47 return "edge pointing left";
49 return "edge pointing right";
51 return "edge pointing any direction";
52 case PAREN_EXPR:
53 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 */
61 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 */
78Node *
80{
82
83 if (!gpstate)
84 return NULL;
85
86 if (list_length(cref->fields) == 2)
87 {
88 Node *field1 = linitial(cref->fields);
89 Node *field2 = lsecond(cref->fields);
90 char *elvarname;
91 char *propname;
92
93 if (IsA(field1, A_Star) || IsA(field2, A_Star))
94 {
98 errmsg("\"*\" is not supported here"),
99 parser_errposition(pstate, cref->location));
100 else
103 errmsg("\"*\" not allowed here"),
104 parser_errposition(pstate, cref->location));
105 }
106
107 elvarname = strVal(field1);
109
110 if (list_member(gpstate->variables, field1))
111 {
115
116 /*
117 * If we are transforming expression in an element pattern,
118 * property references containing only that variable are allowed.
119 */
120 if (gpstate->cur_gep)
121 {
122 if (!gpstate->cur_gep->variable ||
123 strcmp(elvarname, gpstate->cur_gep->variable) != 0)
126 errmsg("non-local element variable reference is not supported"),
127 parser_errposition(pstate, cref->location));
128 }
129
135 errmsg("property \"%s\" does not exist", propname));
137
138 gpr->location = cref->location;
139 gpr->elvarname = elvarname;
140 gpr->propid = pgpform->oid;
141 gpr->typeId = pgpform->pgptypid;
142 gpr->typmod = pgpform->pgptypmod;
143 gpr->collation = pgpform->pgpcollation;
144
146
147 return (Node *) gpr;
148 }
149 }
150
151 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 containg
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 */
165static Node *
167{
168 Node *result;
169
170 if (labelexpr == NULL)
171 return NULL;
172
174
175 switch (nodeTag(labelexpr))
176 {
177 case T_ColumnRef:
178 {
179 ColumnRef *cref = (ColumnRef *) labelexpr;
180 const char *labelname;
181 Oid labelid;
183
184 Assert(list_length(cref->fields) == 1);
185 labelname = strVal(linitial(cref->fields));
186
188 if (!labelid)
191 errmsg("label \"%s\" does not exist in property graph \"%s\"", labelname, get_rel_name(gpstate->graphid)));
192
194 lref->labelid = labelid;
195 lref->location = cref->location;
196
197 result = (Node *) lref;
198 break;
199 }
200
201 case T_BoolExpr:
202 {
203 BoolExpr *be = (BoolExpr *) labelexpr;
204 ListCell *lc;
205 List *args = NIL;
206
207 foreach(lc, be->args)
208 {
209 Node *arg = (Node *) lfirst(lc);
210
212 args = lappend(args, arg);
213 }
214
215 result = (Node *) makeBoolExpr(be->boolop, args, be->location);
216 break;
217 }
218
219 default:
220 /* should not reach here */
221 elog(ERROR, "unsupported label expression node: %d", (int) nodeTag(labelexpr));
222 result = NULL; /* keep compiler quiet */
223 break;
224 }
225
226 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 */
238static Node *
240{
242
243 if (gep->quantifier)
246 errmsg("element pattern quantifier is not supported")));
247
248 Assert(!gpstate->cur_gep);
249
250 gpstate->cur_gep = gep;
251
252 gep->labelexpr = transformLabelExpr(gpstate, gep->labelexpr);
253
254 gep->whereClause = transformExpr(pstate, gep->whereClause, EXPR_KIND_WHERE);
255 assign_expr_collations(pstate, gep->whereClause);
256
257 gpstate->cur_gep = NULL;
258
259 return (Node *) gep;
260}
261
262/*
263 * Transform a path term (list of GraphElementPattern's).
264 */
265static Node *
267{
268 List *result = NIL;
270
272 {
273 if (gep->kind != VERTEX_PATTERN && !IS_EDGE_PATTERN(gep->kind))
276 errmsg("unsupported element pattern kind: \"%s\"", get_gep_kind_name(gep->kind)),
277 parser_errposition(pstate, gep->location)));
278
279 if (IS_EDGE_PATTERN(gep->kind))
280 {
281 if (!prev_gep)
284 errmsg("path pattern cannot start with an edge pattern"),
285 parser_errposition(pstate, gep->location)));
286 else if (prev_gep->kind != VERTEX_PATTERN)
289 errmsg("edge pattern must be preceded by a vertex pattern"),
290 parser_errposition(pstate, gep->location)));
291 }
292 else
293 {
294 if (prev_gep && !IS_EDGE_PATTERN(prev_gep->kind))
297 errmsg("adjacent vertex patterns are not supported"),
298 parser_errposition(pstate, gep->location)));
299 }
300
303 prev_gep = gep;
304 }
305
306 /* Path pattern should have at least one element pattern. */
308
309 if (IS_EDGE_PATTERN(prev_gep->kind))
310 {
313 errmsg("path pattern cannot end with an edge pattern"),
314 parser_errposition(pstate, prev_gep->location)));
315 }
316
317 return (Node *) result;
318}
319
320/*
321 * Transform a path pattern list (list of path terms).
322 */
323static Node *
325{
326 List *result = NIL;
328
330
331 /* Grammar doesn't allow empty path pattern list */
333
334 /*
335 * We do not support multiple path patterns in one GRAPH_TABLE clause
336 * right now. But we may do so in future.
337 */
338 if (list_length(path_pattern) != 1)
341 errmsg("multiple path patterns in one GRAPH_TABLE clause not supported")));
342
343 /*
344 * Collect all the variables in the path pattern into the
345 * GraphTableParseState so that we can detect any non-local element
346 * variable references. We need to do this before transforming the path
347 * pattern so as to detect forward references to element variables in the
348 * WHERE clause of an element pattern.
349 */
351 {
353 {
354 if (gep->variable)
355 gpstate->variables = list_append_unique(gpstate->variables, makeString(pstrdup(gep->variable)));
356 }
357 }
358
361
362 return (Node *) result;
363}
364
365/*
366 * Transform a GraphPattern.
367 *
368 * A GraphPattern consists of a list of one or more path patterns and an
369 * optional where clause. Transform them. We use the previously constructure
370 * list of variables in the GraphTableParseState to resolve property references
371 * in the WHERE clause.
372 */
373Node *
375{
376 List *path_pattern_list = castNode(List,
377 transformPathPatternList(pstate, graph_pattern->path_pattern_list));
378
379 graph_pattern->path_pattern_list = path_pattern_list;
380 graph_pattern->whereClause = transformExpr(pstate, graph_pattern->whereClause, EXPR_KIND_WHERE);
381 assign_expr_collations(pstate, graph_pattern->whereClause);
382
383 return (Node *) graph_pattern;
384}
#define Assert(condition)
Definition c.h:943
uint32 result
Datum arg
Definition elog.c:1322
int errcode(int sqlerrcode)
Definition elog.c:874
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:227
#define ereport(elevel,...)
Definition elog.h:151
#define HeapTupleIsValid(tuple)
Definition htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
List * lappend(List *list, void *datum)
Definition list.c:339
List * list_append_unique(List *list, void *datum)
Definition list.c:1343
bool list_member(const List *list, const void *datum)
Definition list.c:661
char * get_rel_name(Oid relid)
Definition lsyscache.c:2148
Expr * makeBoolExpr(BoolExprType boolop, List *args, int location)
Definition makefuncs.c:420
char * pstrdup(const char *in)
Definition mcxt.c:1781
#define IsA(nodeptr, _type_)
Definition nodes.h:164
#define nodeTag(nodeptr)
Definition nodes.h:139
#define makeNode(_type_)
Definition nodes.h:161
#define castNode(_type_, nodeptr)
Definition nodes.h:182
static char * errmsg
void assign_expr_collations(ParseState *pstate, Node *expr)
Node * transformExpr(ParseState *pstate, Node *expr, ParseExprKind exprKind)
Definition parse_expr.c:121
static Node * transformPathTerm(ParseState *pstate, List *path_term)
static const char * get_gep_kind_name(GraphElementPatternKind gepkind)
static Node * transformGraphElementPattern(ParseState *pstate, GraphElementPattern *gep)
static Node * transformLabelExpr(GraphTableParseState *gpstate, Node *labelexpr)
Node * transformGraphPattern(ParseState *pstate, GraphPattern *graph_pattern)
static Node * transformPathPatternList(ParseState *pstate, List *path_pattern)
Node * transformGraphTablePropertyRef(ParseState *pstate, ColumnRef *cref)
int parser_errposition(ParseState *pstate, int location)
Definition parse_node.c:106
@ EXPR_KIND_WHERE
Definition parse_node.h:46
@ EXPR_KIND_SELECT_TARGET
Definition parse_node.h:54
GraphElementPatternKind
@ EDGE_PATTERN_RIGHT
@ VERTEX_PATTERN
@ EDGE_PATTERN_LEFT
@ PAREN_EXPR
@ EDGE_PATTERN_ANY
#define IS_EDGE_PATTERN(kind)
#define lfirst(lc)
Definition pg_list.h:172
static int list_length(const List *l)
Definition pg_list.h:152
#define NIL
Definition pg_list.h:68
#define linitial(l)
Definition pg_list.h:178
#define lsecond(l)
Definition pg_list.h:183
#define foreach_node(type, var, lst)
Definition pg_list.h:528
END_CATALOG_STRUCT typedef FormData_pg_propgraph_property * Form_pg_propgraph_property
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:252
static Datum CStringGetDatum(const char *X)
Definition postgres.h:370
unsigned int Oid
static int fb(int x)
void check_stack_depth(void)
Definition stack_depth.c:95
Node * whereClause
List * path_pattern_list
Definition pg_list.h:54
Definition nodes.h:135
ParseExprKind p_expr_kind
Definition parse_node.h:232
GraphTableParseState * p_graph_table_pstate
Definition parse_node.h:242
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:265
HeapTuple SearchSysCache2(SysCacheIdentifier cacheId, Datum key1, Datum key2)
Definition syscache.c:231
#define GetSysCacheOid2(cacheId, oidcol, key1, key2)
Definition syscache.h:111
String * makeString(char *str)
Definition value.c:63
#define strVal(v)
Definition value.h:82