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 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 */
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
256 /*
257 * Assign collations here for the reason mentioned in the prologue of
258 * transformGraphPattern().
259 */
260 assign_expr_collations(pstate, gep->whereClause);
261
262 gpstate->cur_gep = NULL;
263
264 return (Node *) gep;
265}
266
267/*
268 * Transform a path term (list of GraphElementPattern's).
269 */
270static Node *
272{
273 List *result = NIL;
275
277 {
278 if (gep->kind != VERTEX_PATTERN && !IS_EDGE_PATTERN(gep->kind))
281 errmsg("unsupported element pattern kind: \"%s\"", get_gep_kind_name(gep->kind)),
282 parser_errposition(pstate, gep->location)));
283
284 if (IS_EDGE_PATTERN(gep->kind))
285 {
286 if (!prev_gep)
289 errmsg("path pattern cannot start with an edge pattern"),
290 parser_errposition(pstate, gep->location)));
291 else if (prev_gep->kind != VERTEX_PATTERN)
294 errmsg("edge pattern must be preceded by a vertex pattern"),
295 parser_errposition(pstate, gep->location)));
296 }
297 else
298 {
299 if (prev_gep && !IS_EDGE_PATTERN(prev_gep->kind))
302 errmsg("adjacent vertex patterns are not supported"),
303 parser_errposition(pstate, gep->location)));
304 }
305
308 prev_gep = gep;
309 }
310
311 /* Path pattern should have at least one element pattern. */
313
314 if (IS_EDGE_PATTERN(prev_gep->kind))
315 {
318 errmsg("path pattern cannot end with an edge pattern"),
319 parser_errposition(pstate, prev_gep->location)));
320 }
321
322 return (Node *) result;
323}
324
325/*
326 * Transform a path pattern list (list of path terms).
327 */
328static Node *
330{
331 List *result = NIL;
333
335
336 /* Grammar doesn't allow empty path pattern list */
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 if (list_length(path_pattern) != 1)
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 */
356 {
358 {
359 if (gep->variable)
360 gpstate->variables = list_append_unique(gpstate->variables, makeString(pstrdup(gep->variable)));
361 }
362 }
363
366
367 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 */
383Node *
385{
386 List *path_pattern_list = castNode(List,
387 transformPathPatternList(pstate, graph_pattern->path_pattern_list));
388
389 graph_pattern->path_pattern_list = path_pattern_list;
390 graph_pattern->whereClause = transformExpr(pstate, graph_pattern->whereClause, EXPR_KIND_WHERE);
391 assign_expr_collations(pstate, graph_pattern->whereClause);
392
393 return (Node *) graph_pattern;
394}
#define Assert(condition)
Definition c.h:943
uint32 result
Datum arg
Definition elog.c:1323
int errcode(int sqlerrcode)
Definition elog.c:875
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228
#define ereport(elevel,...)
Definition elog.h:152
#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:2121
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:383
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