PostgreSQL Source Code git master
Loading...
Searching...
No Matches
rewriteGraphTable.c File Reference
Include dependency graph for rewriteGraphTable.c:

Go to the source code of this file.

Data Structures

struct  path_factor
 
struct  path_element
 
struct  replace_property_refs_context
 

Functions

static Nodereplace_property_refs (Oid propgraphid, Node *node, const List *mappings)
 
static Listbuild_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 Listgenerate_queries_for_path_pattern (RangeTblEntry *rte, List *element_patterns)
 
static Querygenerate_query_for_graph_path (RangeTblEntry *rte, List *path)
 
static Nodegenerate_setop_from_pathqueries (List *pathqueries, List **rtable, List **targetlist)
 
static Listgenerate_queries_for_path_pattern_recurse (RangeTblEntry *rte, List *pathqueries, List *cur_path, List *path_pattern_lists, int elempos)
 
static Querygenerate_query_for_empty_path_pattern (RangeTblEntry *rte)
 
static Querygenerate_union_from_pathqueries (List **pathqueries)
 
static Listget_path_elements_for_path_factor (Oid propgraphid, struct path_factor *pf)
 
static bool is_property_associated_with_label (Oid labeloid, Oid propoid)
 
static Nodeget_element_property_expr (Oid elemoid, Oid propoid, int rtindex)
 
QueryrewriteGraphTable (Query *parsetree, int rt_index)
 
static struct path_elementcreate_pe_for_element (struct path_factor *pf, Oid elemoid)
 
static Listget_labels_for_expr (Oid propgraphid, Node *labelexpr)
 
static Nodereplace_property_refs_mutator (Node *node, struct replace_property_refs_context *context)
 

Function Documentation

◆ build_edge_vertex_link_quals()

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

Definition at line 1147 of file rewriteGraphTable.c.

1148{
1149 List *quals = NIL;
1151 Datum datum;
1152 Datum *d1,
1153 *d2,
1154 *d3;
1155 int n1,
1156 n2,
1157 n3;
1158 ParseState *pstate = make_parsestate(NULL);
1160
1162
1165
1168
1171
1172 if (n1 != n2)
1173 elog(ERROR, "array size key (%d) vs ref (%d) mismatch for element ID %u", catalog_key_attnum, catalog_ref_attnum, pgeform->oid);
1174 if (n1 != n3)
1175 elog(ERROR, "array size key (%d) vs operator (%d) mismatch for element ID %u", catalog_key_attnum, catalog_eqop_attnum, pgeform->oid);
1176
1177 for (int i = 0; i < n1; i++)
1178 {
1181 Oid eqop = DatumGetObjectId(d3[i]);
1182 Var *keyvar;
1183 Var *refvar;
1184 Oid atttypid;
1185 int32 atttypmod;
1186 Oid attcoll;
1187 HeapTuple tup;
1189 List *args;
1193
1194 get_atttypetypmodcoll(pgeform->pgerelid, keyattn, &atttypid, &atttypmod, &attcoll);
1195 keyvar = makeVar(edgerti, keyattn, atttypid, atttypmod, attcoll, 0);
1196 get_atttypetypmodcoll(refrelid, refattn, &atttypid, &atttypmod, &attcoll);
1197 refvar = makeVar(refrti, refattn, atttypid, atttypmod, attcoll, 0);
1198
1200 if (!HeapTupleIsValid(tup))
1201 elog(ERROR, "cache lookup failed for operator %u", eqop);
1203 /* An equality operator is a binary operator returning boolean result. */
1204 Assert(opform->oprkind == 'b'
1205 && RegProcedureIsValid(opform->oprcode)
1206 && opform->oprresult == BOOLOID
1207 && !get_func_retset(opform->oprcode));
1208
1209 /*
1210 * Prepare operands and cast them to the types required by the
1211 * equality operator. Similar to PK/FK quals, referenced vertex key is
1212 * used as left operand and referencing edge key is used as right
1213 * operand.
1214 */
1218 declared_arg_types[0] = opform->oprleft;
1219 declared_arg_types[1] = opform->oprright;
1221
1223 linkqual->opno = opform->oid;
1224 linkqual->opfuncid = opform->oprcode;
1225 linkqual->opresulttype = opform->oprresult;
1226 linkqual->opretset = false;
1227 /* opcollid and inputcollid will be set by parse_collate.c */
1228 linkqual->args = args;
1229 linkqual->location = -1;
1230
1232 quals = lappend(quals, linkqual);
1233 }
1234
1235 assign_expr_collations(pstate, (Node *) quals);
1236
1237 return quals;
1238}
#define DatumGetArrayTypeP(X)
Definition array.h:261
void deconstruct_array_builtin(const ArrayType *array, Oid elmtype, Datum **elemsp, bool **nullsp, int *nelemsp)
int16 AttrNumber
Definition attnum.h:21
#define RegProcedureIsValid(p)
Definition c.h:861
#define Assert(condition)
Definition c.h:942
int32_t int32
Definition c.h:611
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
#define HeapTupleIsValid(tuple)
Definition htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
int i
Definition isn.c:77
List * lappend(List *list, void *datum)
Definition list.c:339
bool get_func_retset(Oid funcid)
Definition lsyscache.c:1962
void get_atttypetypmodcoll(Oid relid, AttrNumber attnum, Oid *typid, int32 *typmod, Oid *collid)
Definition lsyscache.c:1062
Var * makeVar(int varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition makefuncs.c:66
Oid exprType(const Node *expr)
Definition nodeFuncs.c:42
#define makeNode(_type_)
Definition nodes.h:161
void assign_expr_collations(ParseState *pstate, Node *expr)
void make_fn_arguments(ParseState *pstate, List *fargs, Oid *actual_arg_types, Oid *declared_arg_types)
ParseState * make_parsestate(ParseState *parentParseState)
Definition parse_node.c:39
#define NIL
Definition pg_list.h:68
#define list_make2(x1, x2)
Definition pg_list.h:214
END_CATALOG_STRUCT typedef FormData_pg_operator * Form_pg_operator
Definition pg_operator.h:87
END_CATALOG_STRUCT typedef FormData_pg_propgraph_element * Form_pg_propgraph_element
static Oid DatumGetObjectId(Datum X)
Definition postgres.h:242
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:252
uint64_t Datum
Definition postgres.h:70
static int16 DatumGetInt16(Datum X)
Definition postgres.h:162
unsigned int Oid
static int fb(int x)
Definition pg_list.h:54
Definition nodes.h:135
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:264
Datum SysCacheGetAttrNotNull(SysCacheIdentifier cacheId, HeapTuple tup, AttrNumber attributeNumber)
Definition syscache.c:625
HeapTuple SearchSysCache1(SysCacheIdentifier cacheId, Datum key1)
Definition syscache.c:220
#define GetSysCacheOid1(cacheId, oidcol, key1)
Definition syscache.h:109

References Assert, assign_expr_collations(), DatumGetArrayTypeP, DatumGetInt16(), DatumGetObjectId(), deconstruct_array_builtin(), elog, ERROR, exprType(), fb(), Form_pg_operator, Form_pg_propgraph_element, get_atttypetypmodcoll(), get_func_retset(), GETSTRUCT(), GetSysCacheOid1, HeapTupleIsValid, i, lappend(), list_make2, make_fn_arguments(), make_parsestate(), makeNode, makeVar(), NIL, ObjectIdGetDatum(), RegProcedureIsValid, ReleaseSysCache(), SearchSysCache1(), and SysCacheGetAttrNotNull().

Referenced by create_pe_for_element().

◆ create_pe_for_element()

static struct path_element * create_pe_for_element ( struct path_factor pf,
Oid  elemoid 
)
static

Definition at line 745 of file rewriteGraphTable.c.

746{
749 struct path_element *pe;
750
751 if (!eletup)
752 elog(ERROR, "cache lookup failed for property graph element %u", elemoid);
754
755 if ((pgeform->pgekind == PGEKIND_VERTEX && pf->kind != VERTEX_PATTERN) ||
756 (pgeform->pgekind == PGEKIND_EDGE && !IS_EDGE_PATTERN(pf->kind)))
757 {
759 return NULL;
760 }
761
763 pe->path_factor = pf;
764 pe->elemoid = elemoid;
765 pe->reloid = pgeform->pgerelid;
766
767 /*
768 * When a path is converted into a query
769 * (generate_query_for_graph_path()), a RangeTblEntry will be created for
770 * every element in the path. Fixing rtindexes of RangeTblEntrys here
771 * makes it possible to craft elements' qual expressions only once while
772 * we have access to the catalog entry. Otherwise they need to be crafted
773 * as many times as the number of paths a given element appears in,
774 * fetching catalog entry again each time. Hence we simply assume
775 * RangeTblEntrys will be created in the same order in which the
776 * corresponding path factors appear in the list of path factors
777 * representing a path pattern. That way their rtindexes will be same as
778 * path_factor::factorpos + 1.
779 */
780 if (IS_EDGE_PATTERN(pf->kind))
781 {
782 pe->srcvertexid = pgeform->pgesrcvertexid;
783 pe->destvertexid = pgeform->pgedestvertexid;
784 Assert(pf->src_pf && pf->dest_pf);
785
786 pe->src_quals = build_edge_vertex_link_quals(eletup, pf->factorpos + 1, pf->src_pf->factorpos + 1,
787 pe->srcvertexid,
791 pe->dest_quals = build_edge_vertex_link_quals(eletup, pf->factorpos + 1, pf->dest_pf->factorpos + 1,
792 pe->destvertexid,
796 }
797
799
800 return pe;
801}
#define palloc0_object(type)
Definition fe_memutils.h:75
@ VERTEX_PATTERN
#define IS_EDGE_PATTERN(kind)
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)

References Assert, build_edge_vertex_link_quals(), path_element::elemoid, elog, ERROR, fb(), Form_pg_propgraph_element, GETSTRUCT(), IS_EDGE_PATTERN, ObjectIdGetDatum(), palloc0_object, ReleaseSysCache(), SearchSysCache1(), and VERTEX_PATTERN.

Referenced by get_path_elements_for_path_factor().

◆ generate_queries_for_path_pattern()

static List * generate_queries_for_path_pattern ( RangeTblEntry rte,
List element_patterns 
)
static

Definition at line 175 of file rewriteGraphTable.c.

176{
179 int factorpos = 0;
181 struct path_factor *prev_pf = NULL;
182
184
185 /*
186 * Create a list of path factors representing the given path pattern
187 * linking edge path factors to their adjacent vertex path factors.
188 *
189 * While doing that merge element patterns with the same variable name
190 * into a single path_factor.
191 */
193 {
194 struct path_factor *pf = NULL;
195
196 /*
197 * Unsupported conditions should have been caught by the parser
198 * itself. We have corresponding Asserts here to document the
199 * assumptions in this code.
200 */
201 Assert(gep->kind == VERTEX_PATTERN || IS_EDGE_PATTERN(gep->kind));
202 Assert(!gep->quantifier);
203
205 {
206 if (gep->variable && other->variable &&
207 strcmp(gep->variable, other->variable) == 0)
208 {
209 if (other->kind != gep->kind)
212 errmsg("element patterns with same variable name \"%s\" but different element pattern types",
213 gep->variable)));
214
215 /*
216 * If both the element patterns have label expressions, they
217 * need to be conjuncted, which is not supported right now.
218 *
219 * However, an empty label expression means all labels.
220 * Conjunction of any label expression with all labels is the
221 * expression itself. Hence if only one of the two element
222 * patterns has a label expression use that expression.
223 */
224 if (!other->labelexpr)
225 other->labelexpr = gep->labelexpr;
226 else if (gep->labelexpr && !equal(other->labelexpr, gep->labelexpr))
229 errmsg("element patterns with same variable name \"%s\" but different label expressions are not supported",
230 gep->variable)));
231
232 /*
233 * If two element patterns have the same variable name, they
234 * represent the same set of graph elements and hence are
235 * constrained by conditions from both the element patterns.
236 */
237 if (!other->whereClause)
238 other->whereClause = gep->whereClause;
239 else if (gep->whereClause)
240 other->whereClause = (Node *) makeBoolExpr(AND_EXPR,
241 list_make2(other->whereClause, gep->whereClause),
242 -1);
243 pf = other;
244 break;
245 }
246 }
247
248 if (!pf)
249 {
250 {
251 pf = palloc0_object(struct path_factor);
252 pf->factorpos = factorpos++;
253 pf->kind = gep->kind;
254 pf->labelexpr = gep->labelexpr;
255 pf->variable = gep->variable;
256 pf->whereClause = gep->whereClause;
257
259 }
260 }
261
262 /*
263 * Setup links to the previous path factor in the path.
264 *
265 * If the previous path factor represents an edge, this path factor
266 * represents an adjacent vertex; the source vertex for an edge
267 * pointing left or the destination vertex for an edge pointing right.
268 * If this path factor represents an edge, the previous path factor
269 * represents an adjacent vertex; source vertex for an edge pointing
270 * right or the destination vertex for an edge pointing left.
271 *
272 * Edge pointing in any direction is treated similar to that pointing
273 * in right direction here. When constructing a query in
274 * generate_query_for_graph_path(), we will try links in both the
275 * directions.
276 *
277 * If multiple edge patterns share the same variable name, they
278 * constrain the adjacent vertex patterns since an edge can connect
279 * only one pair of vertexes. These adjacent vertex patterns need to
280 * be merged even though they have different variables. Such element
281 * patterns form a walk of graph where vertex and edges are repeated.
282 * For example, in (a)-[b]->(c)<-[b]-(d), (a) and (d) represent the
283 * same vertex element. This is slighly harder to implement and
284 * probably less useful. Hence not supported for now.
285 */
286 if (prev_pf)
287 {
288 if (prev_pf->kind == EDGE_PATTERN_RIGHT || prev_pf->kind == EDGE_PATTERN_ANY)
289 {
290 Assert(!IS_EDGE_PATTERN(pf->kind));
291 if (prev_pf->dest_pf && prev_pf->dest_pf != pf)
294 errmsg("an edge cannot connect more than two vertexes even in a cyclic pattern"));
295 prev_pf->dest_pf = pf;
296 }
297 else if (prev_pf->kind == EDGE_PATTERN_LEFT)
298 {
299 Assert(!IS_EDGE_PATTERN(pf->kind));
300 if (prev_pf->src_pf && prev_pf->src_pf != pf)
303 errmsg("an edge cannot connect more than two vertexes even in a cyclic pattern"));
304 prev_pf->src_pf = pf;
305 }
306
307 if (pf->kind == EDGE_PATTERN_RIGHT || pf->kind == EDGE_PATTERN_ANY)
308 {
310 if (pf->src_pf && pf->src_pf != prev_pf)
313 errmsg("an edge cannot connect more than two vertexes even in a cyclic pattern"));
314 pf->src_pf = prev_pf;
315 }
316 else if (pf->kind == EDGE_PATTERN_LEFT)
317 {
319 if (pf->dest_pf && pf->dest_pf != prev_pf)
322 errmsg("an edge cannot connect more than two vertexes even in a cyclic pattern"));
323 pf->dest_pf = prev_pf;
324 }
325 }
326
327 prev_pf = pf;
328 }
329
330 /*
331 * Collect list of elements for each path factor. Do this after all the
332 * edge links are setup correctly.
333 */
337
339 NIL, path_elem_lists, 0);
340 if (!pathqueries)
342
343 return pathqueries;
344}
int errcode(int sqlerrcode)
Definition elog.c:874
#define ereport(elevel,...)
Definition elog.h:150
bool equal(const void *a, const void *b)
Definition equalfuncs.c:223
Expr * makeBoolExpr(BoolExprType boolop, List *args, int location)
Definition makefuncs.c:420
static char * errmsg
@ EDGE_PATTERN_RIGHT
@ EDGE_PATTERN_LEFT
@ EDGE_PATTERN_ANY
static int list_length(const List *l)
Definition pg_list.h:152
#define list_make1(x1)
Definition pg_list.h:212
#define foreach_ptr(type, var, lst)
Definition pg_list.h:469
#define foreach_node(type, var, lst)
Definition pg_list.h:496
@ AND_EXPR
Definition primnodes.h:964
static List * generate_queries_for_path_pattern_recurse(RangeTblEntry *rte, List *pathqueries, List *cur_path, List *path_pattern_lists, int elempos)
static List * get_path_elements_for_path_factor(Oid propgraphid, struct path_factor *pf)
static Query * generate_query_for_empty_path_pattern(RangeTblEntry *rte)

References AND_EXPR, Assert, EDGE_PATTERN_ANY, EDGE_PATTERN_LEFT, EDGE_PATTERN_RIGHT, equal(), ereport, errcode(), errmsg, ERROR, path_factor::factorpos, fb(), foreach_node, foreach_ptr, generate_queries_for_path_pattern_recurse(), generate_query_for_empty_path_pattern(), get_path_elements_for_path_factor(), IS_EDGE_PATTERN, lappend(), list_length(), list_make1, list_make2, makeBoolExpr(), NIL, palloc0_object, and VERTEX_PATTERN.

Referenced by rewriteGraphTable().

◆ generate_queries_for_path_pattern_recurse()

static List * generate_queries_for_path_pattern_recurse ( RangeTblEntry rte,
List pathqueries,
List cur_path,
List path_pattern_lists,
int  elempos 
)
static

Definition at line 353 of file rewriteGraphTable.c.

354{
356
358 {
359 /* Update current path being built with current element. */
361
362 /*
363 * If this is the last element in the path, generate query for the
364 * completed path. Else recurse processing the next element.
365 */
367 {
369
371 if (pathquery)
373 }
374 else
376 cur_path,
378 elempos + 1);
379 /* Make way for the next element at the same position. */
381 }
382
383 return pathqueries;
384}
List * list_delete_last(List *list)
Definition list.c:957
#define list_nth_node(type, list, n)
Definition pg_list.h:327
static Query * generate_query_for_graph_path(RangeTblEntry *rte, List *path)

References Assert, fb(), foreach_ptr, generate_queries_for_path_pattern_recurse(), generate_query_for_graph_path(), lappend(), list_delete_last(), list_length(), and list_nth_node.

Referenced by generate_queries_for_path_pattern(), and generate_queries_for_path_pattern_recurse().

◆ generate_query_for_empty_path_pattern()

static Query * generate_query_for_empty_path_pattern ( RangeTblEntry rte)
static

Definition at line 571 of file rewriteGraphTable.c.

572{
573 Query *query = makeNode(Query);
574
575 query->commandType = CMD_SELECT;
576 query->rtable = NIL;
577 query->rteperminfos = NIL;
578 query->jointree = makeFromExpr(NIL, (Node *) makeBoolConst(false, false));
579
580 /*
581 * Even though no rows are returned, the result still projects the same
582 * columns as projected by GRAPH_TABLE clause. Do this by constructing a
583 * target list full of NULL values.
584 */
585 foreach_node(TargetEntry, te, rte->graph_table_columns)
586 {
587 Node *nte = (Node *) te->expr;
588
590 query->targetList = lappend(query->targetList, te);
591 }
592
593 return query;
594}
FromExpr * makeFromExpr(List *fromlist, Node *quals)
Definition makefuncs.c:336
Const * makeNullConst(Oid consttype, int32 consttypmod, Oid constcollid)
Definition makefuncs.c:388
Node * makeBoolConst(bool value, bool isnull)
Definition makefuncs.c:408
int32 exprTypmod(const Node *expr)
Definition nodeFuncs.c:304
Oid exprCollation(const Node *expr)
Definition nodeFuncs.c:826
@ CMD_SELECT
Definition nodes.h:275
FromExpr * jointree
Definition parsenodes.h:182
List * rtable
Definition parsenodes.h:175
CmdType commandType
Definition parsenodes.h:121
List * targetList
Definition parsenodes.h:198

References CMD_SELECT, Query::commandType, exprCollation(), exprType(), exprTypmod(), fb(), foreach_node, Query::jointree, lappend(), makeBoolConst(), makeFromExpr(), makeNode, makeNullConst(), NIL, Query::rtable, and Query::targetList.

Referenced by generate_queries_for_path_pattern().

◆ generate_query_for_graph_path()

static Query * generate_query_for_graph_path ( RangeTblEntry rte,
List path 
)
static

Definition at line 408 of file rewriteGraphTable.c.

409{
411 List *fromlist = NIL;
413 List *vars;
414
415 path_query->commandType = CMD_SELECT;
416
418 {
419 struct path_factor *pf = pe->path_factor;
421 Relation rel;
423
424 Assert(pf->kind == VERTEX_PATTERN || IS_EDGE_PATTERN(pf->kind));
425
426 /* Add conditions representing edge connnections. */
427 if (IS_EDGE_PATTERN(pf->kind))
428 {
429 struct path_element *src_pe;
430 struct path_element *dest_pe;
432
433 Assert(pf->src_pf && pf->dest_pf);
434 src_pe = list_nth(graph_path, pf->src_pf->factorpos);
435 dest_pe = list_nth(graph_path, pf->dest_pf->factorpos);
436
437 /* Make sure that the links of adjacent vertices are correct. */
438 Assert(pf->src_pf == src_pe->path_factor &&
439 pf->dest_pf == dest_pe->path_factor);
440
441 if (src_pe->elemoid == pe->srcvertexid &&
442 dest_pe->elemoid == pe->destvertexid)
444 list_concat(copyObject(pe->src_quals),
445 copyObject(pe->dest_quals)),
446 -1);
447
448 /*
449 * An edge pattern in any direction matches edges in both
450 * directions, try swapping source and destination. When the
451 * source and destination is the same vertex table, quals
452 * corresponding to either direction may get satisfied. Hence OR
453 * the quals corresponding to both the directions.
454 */
455 if (pf->kind == EDGE_PATTERN_ANY &&
456 dest_pe->elemoid == pe->srcvertexid &&
457 src_pe->elemoid == pe->destvertexid)
458 {
459 List *src_quals = copyObject(pe->dest_quals);
460 List *dest_quals = copyObject(pe->src_quals);
462
463 /* Swap the source and destination varnos in the quals. */
464 ChangeVarNodes((Node *) dest_quals, pe->path_factor->src_pf->factorpos + 1,
465 pe->path_factor->dest_pf->factorpos + 1, 0);
466 ChangeVarNodes((Node *) src_quals, pe->path_factor->dest_pf->factorpos + 1,
467 pe->path_factor->src_pf->factorpos + 1, 0);
468
470 if (edge_qual)
472 else
474 }
475
476 /*
477 * If the given edge element does not connect the adjacent vertex
478 * elements in this path, the path is broken. Abandon this path as
479 * it won't return any rows.
480 */
481 if (edge_qual == NULL)
482 return NULL;
483
485 }
486 else
487 Assert(!pe->src_quals && !pe->dest_quals);
488
489 /*
490 * Create RangeTblEntry for this element table.
491 *
492 * SQL/PGQ standard (Ref. Section 11.19, Access rule 2 and General
493 * rule 4) does not specify whose access privileges to use when
494 * accessing the element tables: property graph owner's or current
495 * user's. It is safer to use current user's privileges so as not to
496 * make property graphs as a hole for unpriviledged data access. This
497 * is inline with the views being security_invoker by default.
498 */
499 rel = table_open(pe->reloid, AccessShareLock);
501 NULL, true, false);
502 table_close(rel, NoLock);
503 path_query->rtable = lappend(path_query->rtable, pni->p_rte);
504 path_query->rteperminfos = lappend(path_query->rteperminfos, pni->p_perminfo);
505 pni->p_rte->perminfoindex = list_length(path_query->rteperminfos);
507 rtr->rtindex = list_length(path_query->rtable);
508 fromlist = lappend(fromlist, rtr);
509
510 /*
511 * Make sure that the assumption mentioned in create_pe_for_element()
512 * holds true; that the elements' RangeTblEntrys are added in the
513 * order in which their respective path factors appear in the list of
514 * path factors representing the path pattern.
515 */
516 Assert(pf->factorpos + 1 == rtr->rtindex);
517
518 if (pf->whereClause)
519 {
520 Node *tr;
521
522 tr = replace_property_refs(rte->relid, pf->whereClause, list_make1(pe));
523
525 }
526 }
527
528 if (rte->graph_pattern->whereClause)
529 {
531 (Node *) rte->graph_pattern->whereClause,
532 graph_path);
533
535 }
536
537 path_query->jointree = makeFromExpr(fromlist,
539
540 /* Construct query targetlist from COLUMNS specification of GRAPH_TABLE. */
541 path_query->targetList = castNode(List,
543 (Node *) rte->graph_table_columns,
544 graph_path));
545
546 /*
547 * Mark the columns being accessed in the path query as requiring SELECT
548 * privilege. Any lateral columns should have been handled when the
549 * corresponding ColumnRefs were transformed. Ignore those here.
550 */
552 foreach_node(Var, var, vars)
553 {
555 rt_fetch(var->varno, path_query->rtable));
556
557 /* Must offset the attnum to fit in a bitmapset */
558 perminfo->selectedCols = bms_add_member(perminfo->selectedCols,
559 var->varattno - FirstLowInvalidHeapAttributeNumber);
560 }
561
562 return path_query;
563}
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition bitmapset.c:799
List * list_concat(List *list1, const List *list2)
Definition list.c:561
#define NoLock
Definition lockdefs.h:34
#define AccessShareLock
Definition lockdefs.h:36
#define copyObject(obj)
Definition nodes.h:232
#define castNode(_type_, nodeptr)
Definition nodes.h:182
RTEPermissionInfo * getRTEPermissionInfo(List *rteperminfos, RangeTblEntry *rte)
ParseNamespaceItem * addRangeTableEntryForRelation(ParseState *pstate, Relation rel, LOCKMODE lockmode, Alias *alias, bool inh, bool inFromCl)
#define rt_fetch(rangetable_index, rangetable)
Definition parsetree.h:31
static void * list_nth(const List *list, int n)
Definition pg_list.h:299
@ OR_EXPR
Definition primnodes.h:964
static Node * replace_property_refs(Oid propgraphid, Node *node, const List *mappings)
void ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
#define FirstLowInvalidHeapAttributeNumber
Definition sysattr.h:27
void table_close(Relation relation, LOCKMODE lockmode)
Definition table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition table.c:40
List * pull_vars_of_level(Node *node, int levelsup)
Definition var.c:339

References AccessShareLock, addRangeTableEntryForRelation(), AND_EXPR, Assert, bms_add_member(), castNode, ChangeVarNodes(), CMD_SELECT, copyObject, path_element::dest_quals, EDGE_PATTERN_ANY, fb(), FirstLowInvalidHeapAttributeNumber, foreach_node, foreach_ptr, getRTEPermissionInfo(), IS_EDGE_PATTERN, lappend(), list_concat(), list_length(), list_make1, list_make2, list_nth(), make_parsestate(), makeBoolExpr(), makeFromExpr(), makeNode, NIL, NoLock, OR_EXPR, pull_vars_of_level(), replace_property_refs(), rt_fetch, path_element::src_quals, table_close(), table_open(), and VERTEX_PATTERN.

Referenced by generate_queries_for_path_pattern_recurse().

◆ generate_setop_from_pathqueries()

static Node * generate_setop_from_pathqueries ( List pathqueries,
List **  rtable,
List **  targetlist 
)
static

Definition at line 685 of file rewriteGraphTable.c.

686{
688 Query *lquery;
689 Node *rarg;
693
694 /* Recursion termination condition. */
695 if (list_length(pathqueries) == 0)
696 {
697 *targetlist = NIL;
698 return NULL;
699 }
700
702
704 false, false);
705 *rtable = lappend(*rtable, pni->p_rte);
706 lrtr->rtindex = list_length(*rtable);
708 if (rarg == NULL)
709 {
710 /*
711 * No further path queries in the list. Convert the last query into a
712 * RangeTblRef as expected by SetOperationStmt. Extract a list of the
713 * non-junk TLEs for upper-level processing.
714 */
715 if (targetlist)
716 {
717 *targetlist = NIL;
718 foreach_node(TargetEntry, tle, lquery->targetList)
719 {
720 if (!tle->resjunk)
721 *targetlist = lappend(*targetlist, tle);
722 }
723 }
724 return (Node *) lrtr;
725 }
726
728 sostmt->op = SETOP_UNION;
729 sostmt->all = true;
730 sostmt->larg = (Node *) lrtr;
731 sostmt->rarg = rarg;
732 constructSetOpTargetlist(NULL, sostmt, lquery->targetList, rtargetlist, targetlist, "UNION", false);
733
734 return (Node *) sostmt;
735}
List * list_delete_first(List *list)
Definition list.c:943
ParseNamespaceItem * addRangeTableEntryForSubquery(ParseState *pstate, Query *subquery, Alias *alias, bool lateral, bool inFromCl)
@ SETOP_UNION
void constructSetOpTargetlist(ParseState *pstate, SetOperationStmt *op, const List *ltargetlist, const List *rtargetlist, List **targetlist, const char *context, bool recursive)
Definition analyze.c:2272
#define linitial_node(type, l)
Definition pg_list.h:181
static Node * generate_setop_from_pathqueries(List *pathqueries, List **rtable, List **targetlist)

References addRangeTableEntryForSubquery(), constructSetOpTargetlist(), fb(), foreach_node, generate_setop_from_pathqueries(), lappend(), linitial_node, list_delete_first(), list_length(), make_parsestate(), makeNode, NIL, and SETOP_UNION.

Referenced by generate_setop_from_pathqueries(), and generate_union_from_pathqueries().

◆ generate_union_from_pathqueries()

static Query * generate_union_from_pathqueries ( List **  pathqueries)
static

Definition at line 609 of file rewriteGraphTable.c.

610{
611 List *rtable = NIL;
615 int resno;
616 ListCell *lctl,
617 *lct,
618 *lcm,
619 *lcc;
620
622
623 /* If there's only one pathquery, no need to construct a UNION query. */
624 if (list_length(*pathqueries) == 1)
625 {
626 *pathqueries = NIL;
627 return sampleQuery;
628 }
629
632
633 /* Encapsulate the set operation statement into a Query. */
635 union_query->commandType = CMD_SELECT;
636 union_query->rtable = rtable;
637 union_query->setOperations = (Node *) sostmt;
638 union_query->rteperminfos = NIL;
639 union_query->jointree = makeFromExpr(NIL, NULL);
640
641 /*
642 * Generate dummy targetlist for outer query using column names from one
643 * of the queries and common datatypes/collations of topmost set
644 * operation. It shouldn't matter which query. Also it shouldn't matter
645 * which RT index is used as varno in the target list entries, as long as
646 * it corresponds to a real RT entry; else funny things may happen when
647 * the tree is mashed by rule rewriting. So we use 1 since there's always
648 * one RT entry at least.
649 */
650 Assert(rt_fetch(1, rtable));
651 union_query->targetList = NULL;
652 resno = 1;
653 forfour(lct, sostmt->colTypes,
654 lcm, sostmt->colTypmods,
655 lcc, sostmt->colCollations,
656 lctl, sampleQuery->targetList)
657 {
662 char *colName;
664 Var *var;
665
666 Assert(!sample_tle->resjunk);
667 colName = pstrdup(sample_tle->resname);
668 var = makeVar(1, sample_tle->resno, colType, colTypmod, colCollation, 0);
669 var->location = exprLocation((Node *) sample_tle->expr);
670 tle = makeTargetEntry((Expr *) var, (AttrNumber) resno++, colName, false);
671 union_query->targetList = lappend(union_query->targetList, tle);
672 }
673
674 *pathqueries = NIL;
675 return union_query;
676}
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition makefuncs.c:289
char * pstrdup(const char *in)
Definition mcxt.c:1781
int exprLocation(const Node *expr)
Definition nodeFuncs.c:1392
#define lfirst(lc)
Definition pg_list.h:172
#define lfirst_int(lc)
Definition pg_list.h:173
#define forfour(cell1, list1, cell2, list2, cell3, list3, cell4, list4)
Definition pg_list.h:575
#define lfirst_oid(lc)
Definition pg_list.h:174
ParseLoc location
Definition primnodes.h:311

References Assert, castNode, CMD_SELECT, exprLocation(), fb(), forfour, generate_setop_from_pathqueries(), lappend(), lfirst, lfirst_int, lfirst_oid, linitial_node, list_length(), Var::location, makeFromExpr(), makeNode, makeTargetEntry(), makeVar(), NIL, pstrdup(), and rt_fetch.

Referenced by rewriteGraphTable().

◆ get_element_property_expr()

static Node * get_element_property_expr ( Oid  elemoid,
Oid  propoid,
int  rtindex 
)
static

Definition at line 1283 of file rewriteGraphTable.c.

1284{
1285 Relation rel;
1286 SysScanDesc scan;
1287 ScanKeyData key[1];
1289 Node *n = NULL;
1290
1292 ScanKeyInit(&key[0],
1295 F_OIDEQ, ObjectIdGetDatum(elemoid));
1297 true, NULL, 1, key);
1298
1300 {
1302
1305
1306 if (!proptup)
1307 continue;
1310 ChangeVarNodes(n, 1, rtindex, 0);
1311
1313 break;
1314 }
1315 systable_endscan(scan);
1317
1318 return n;
1319}
#define TextDatumGetCString(d)
Definition builtins.h:99
void systable_endscan(SysScanDesc sysscan)
Definition genam.c:603
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition genam.c:514
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition genam.c:388
#define RowShareLock
Definition lockdefs.h:37
END_CATALOG_STRUCT typedef FormData_pg_propgraph_element_label * Form_pg_propgraph_element_label
void * stringToNode(const char *str)
Definition read.c:90
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition scankey.c:76
#define BTEqualStrategyNumber
Definition stratnum.h:31
HeapTuple SearchSysCache2(SysCacheIdentifier cacheId, Datum key1, Datum key2)
Definition syscache.c:230

References BTEqualStrategyNumber, ChangeVarNodes(), fb(), Form_pg_propgraph_element_label, GETSTRUCT(), HeapTupleIsValid, ObjectIdGetDatum(), ReleaseSysCache(), RowShareLock, ScanKeyInit(), SearchSysCache2(), stringToNode(), SysCacheGetAttrNotNull(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), table_open(), and TextDatumGetCString.

Referenced by replace_property_refs_mutator().

◆ get_labels_for_expr()

static List * get_labels_for_expr ( Oid  propgraphid,
Node labelexpr 
)
static

Definition at line 808 of file rewriteGraphTable.c.

809{
811
812 if (!labelexpr)
813 {
814 Relation rel;
815 SysScanDesc scan;
816 ScanKeyData key[1];
818
819 /*
820 * According to section 9.2 "Contextual inference of a set of labels"
821 * subclause 2.a.ii of SQL/PGQ standard, element pattern which does
822 * not have a label expression is considered to have label expression
823 * equivalent to '%|!%' which is set of all labels.
824 */
825 label_oids = NIL;
827 ScanKeyInit(&key[0],
830 F_OIDEQ, ObjectIdGetDatum(propgraphid));
832 true, NULL, 1, key);
833 while (HeapTupleIsValid(tup = systable_getnext(scan)))
834 {
836
838 }
839 systable_endscan(scan);
841 }
842 else if (IsA(labelexpr, GraphLabelRef))
843 {
845
846 label_oids = list_make1_oid(glr->labelid);
847 }
848 else if (IsA(labelexpr, BoolExpr))
849 {
850 BoolExpr *be = castNode(BoolExpr, labelexpr);
851 List *label_exprs = be->args;
852
853 label_oids = NIL;
856 }
857 else
858 {
859 /*
860 * should not reach here since gram.y will not generate a label
861 * expression with other node types.
862 */
863 elog(ERROR, "unsupported label expression node: %d", (int) nodeTag(labelexpr));
864 }
865
866 return label_oids;
867}
List * lappend_oid(List *list, Oid datum)
Definition list.c:375
#define IsA(nodeptr, _type_)
Definition nodes.h:164
#define nodeTag(nodeptr)
Definition nodes.h:139
static char * label
#define list_make1_oid(x1)
Definition pg_list.h:242
END_CATALOG_STRUCT typedef FormData_pg_propgraph_label * Form_pg_propgraph_label

References AccessShareLock, BTEqualStrategyNumber, castNode, elog, ERROR, fb(), foreach_node, Form_pg_propgraph_label, GETSTRUCT(), HeapTupleIsValid, IsA, label, lappend_oid(), list_make1_oid, NIL, nodeTag, ObjectIdGetDatum(), ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by get_path_elements_for_path_factor().

◆ get_path_elements_for_path_factor()

static List * get_path_elements_for_path_factor ( Oid  propgraphid,
struct path_factor pf 
)
static

Definition at line 886 of file rewriteGraphTable.c.

887{
888 List *label_oids = get_labels_for_expr(propgraphid, pf->labelexpr);
893 Relation rel;
894 SysScanDesc scan;
895 ScanKeyData key[1];
897
898 /*
899 * A property graph element can be either a vertex or an edge. Other types
900 * of path factors like nested path pattern need to be handled separately
901 * when supported.
902 */
903 Assert(pf->kind == VERTEX_PATTERN || IS_EDGE_PATTERN(pf->kind));
904
907 {
908 bool found = false;
909
910 ScanKeyInit(&key[0],
915 NULL, 1, key);
916 while (HeapTupleIsValid(tup = systable_getnext(scan)))
917 {
919 Oid elem_oid = label_elem->pgelelid;
920
922 {
923 /*
924 * Create path_element object if the new element qualifies the
925 * element pattern kind.
926 */
928
929 if (pe)
930 {
932
933 /* Remember qualified elements. */
935 found = true;
936 }
937
938 /*
939 * Rememeber qualified and unqualified elements processed so
940 * far to avoid processing already processed elements again.
941 */
943 }
945 {
946 /*
947 * The graph element is known to qualify the given element
948 * pattern. Flag that the current label has at least one
949 * qualified element associated with it.
950 */
951 found = true;
952 }
953 }
954
955 if (!found)
956 {
957 /*
958 * We did not find any qualified element associated with this
959 * label. The label or its properties can not be associated with
960 * the given element pattern. Throw an error if the label was
961 * explicitly specified in the element pattern. Otherwise remember
962 * it for later use.
963 */
964 if (!pf->labelexpr)
966 else
969 errmsg("no property graph element of type \"%s\" has label \"%s\" associated with it in property graph \"%s\"",
970 pf->kind == VERTEX_PATTERN ? "vertex" : "edge",
972 get_rel_name(propgraphid))));
973 }
974
975 systable_endscan(scan);
976 }
978
979 /*
980 * Remove the labels which were not explicitly mentioned in the label
981 * expression but do not have any qualified elements associated with them.
982 * Properties associated with such labels may not be referenced. See
983 * replace_property_refs_mutator() for more details.
984 */
986
987 return path_elements;
988}
List * list_difference_oid(const List *list1, const List *list2)
Definition list.c:1313
bool list_member_oid(const List *list, Oid datum)
Definition list.c:722
char * get_rel_name(Oid relid)
Definition lsyscache.c:2148
char * get_propgraph_label_name(Oid labeloid)
Definition lsyscache.c:3941
#define foreach_oid(var, lst)
Definition pg_list.h:471
static struct path_element * create_pe_for_element(struct path_factor *pf, Oid elemoid)
static List * get_labels_for_expr(Oid propgraphid, Node *labelexpr)

References AccessShareLock, Assert, BTEqualStrategyNumber, create_pe_for_element(), ereport, errcode(), errmsg, ERROR, fb(), foreach_oid, Form_pg_propgraph_element_label, get_labels_for_expr(), get_propgraph_label_name(), get_rel_name(), GETSTRUCT(), HeapTupleIsValid, IS_EDGE_PATTERN, lappend(), lappend_oid(), list_difference_oid(), list_member_oid(), NIL, ObjectIdGetDatum(), ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), table_open(), and VERTEX_PATTERN.

Referenced by generate_queries_for_path_pattern().

◆ is_property_associated_with_label()

◆ replace_property_refs()

static Node * replace_property_refs ( Oid  propgraphid,
Node node,
const List mappings 
)
static

Definition at line 1133 of file rewriteGraphTable.c.

1134{
1135 struct replace_property_refs_context context;
1136
1137 context.mappings = mappings;
1138 context.propgraphid = propgraphid;
1139
1141}
#define expression_tree_mutator(n, m, c)
Definition nodeFuncs.h:155
static Node * replace_property_refs_mutator(Node *node, struct replace_property_refs_context *context)

References expression_tree_mutator, replace_property_refs_context::mappings, replace_property_refs_context::propgraphid, and replace_property_refs_mutator().

Referenced by generate_query_for_graph_path().

◆ replace_property_refs_mutator()

static Node * replace_property_refs_mutator ( Node node,
struct replace_property_refs_context context 
)
static

Definition at line 1001 of file rewriteGraphTable.c.

1002{
1003 if (node == NULL)
1004 return NULL;
1005 if (IsA(node, Var))
1006 {
1007 Var *var = (Var *) node;
1008 Var *newvar = copyObject(var);
1009
1010 /*
1011 * If it's already a Var, then it was a lateral reference. Since we
1012 * are in a subquery after the rewrite, we have to increase the level
1013 * by one.
1014 */
1015 newvar->varlevelsup++;
1016
1017 return (Node *) newvar;
1018 }
1019 else if (IsA(node, GraphPropertyRef))
1020 {
1022 Node *n = NULL;
1026
1027 foreach_ptr(struct path_element, m, context->mappings)
1028 {
1029 if (m->path_factor->variable && strcmp(gpr->elvarname, m->path_factor->variable) == 0)
1030 {
1031 found_mapping = m;
1032 break;
1033 }
1034 }
1035
1036 /*
1037 * transformGraphTablePropertyRef() would not create a
1038 * GraphPropertyRef for a variable which is not present in the graph
1039 * path pattern.
1040 */
1042
1043 mapping_factor = found_mapping->path_factor;
1044
1045 /*
1046 * Find property definition for given element through any of the
1047 * associated labels qualifying the given element pattern.
1048 */
1050 {
1055
1057 {
1059 ObjectIdGetDatum(gpr->propid));
1060
1061 if (!tup)
1062 {
1063 /*
1064 * The label is associated with the given element but it
1065 * is not associated with the required property. Check
1066 * next label.
1067 */
1068 continue;
1069 }
1070
1073 ChangeVarNodes(n, 1, mapping_factor->factorpos + 1, 0);
1074
1076 }
1077 else
1078 {
1079 /*
1080 * Label is not associated with the element but it may be
1081 * associated with the property through some other element.
1082 * Save it for later use.
1083 */
1085 }
1086 }
1087
1088 /* See if we can resolve the property in some other way. */
1089 if (!n)
1090 {
1091 bool prop_associated = false;
1092
1094 {
1096 {
1097 prop_associated = true;
1098 break;
1099 }
1100 }
1101
1102 if (prop_associated)
1103 {
1104 /*
1105 * The property is associated with at least one of the labels
1106 * that satisfy given element pattern. If it's associated with
1107 * the given element (through some other label), use
1108 * correspondig value expression. Otherwise NULL. Ref. SQL/PGQ
1109 * standard section 6.5 Property Reference, General Rule 2.b.
1110 */
1111 n = get_element_property_expr(found_mapping->elemoid, gpr->propid,
1112 mapping_factor->factorpos + 1);
1113
1114 if (!n)
1115 n = (Node *) makeNullConst(gpr->typeId, gpr->typmod, gpr->collation);
1116 }
1117
1118 }
1119
1120 if (!n)
1121 ereport(ERROR,
1123 errmsg("property \"%s\" for element variable \"%s\" not found",
1124 get_propgraph_property_name(gpr->propid), mapping_factor->variable));
1125
1126 return n;
1127 }
1128
1130}
#define OidIsValid(objectId)
Definition c.h:857
char * get_propgraph_property_name(Oid propoid)
Definition lsyscache.c:3959
static Node * get_element_property_expr(Oid elemoid, Oid propoid, int rtindex)
static bool is_property_associated_with_label(Oid labeloid, Oid propoid)
#define GetSysCacheOid2(cacheId, oidcol, key1, key2)
Definition syscache.h:111

References Assert, ChangeVarNodes(), copyObject, ereport, errcode(), errmsg, ERROR, expression_tree_mutator, fb(), foreach_oid, foreach_ptr, get_element_property_expr(), get_propgraph_property_name(), GetSysCacheOid2, is_property_associated_with_label(), IsA, lappend_oid(), makeNullConst(), replace_property_refs_context::mappings, NIL, ObjectIdGetDatum(), OidIsValid, ReleaseSysCache(), replace_property_refs_mutator(), SearchSysCache2(), stringToNode(), SysCacheGetAttrNotNull(), and TextDatumGetCString.

Referenced by replace_property_refs(), and replace_property_refs_mutator().

◆ rewriteGraphTable()

Query * rewriteGraphTable ( Query parsetree,
int  rt_index 
)

Definition at line 110 of file rewriteGraphTable.c.

111{
116
117 rte = rt_fetch(rt_index, parsetree->rtable);
118
119 Assert(list_length(rte->graph_pattern->path_pattern_list) == 1);
120
121 path_pattern = linitial(rte->graph_pattern->path_pattern_list);
124
126
127 rte->rtekind = RTE_SUBQUERY;
128 rte->subquery = graph_table_query;
129 rte->lateral = true;
130
131 /*
132 * Reset no longer applicable fields, to appease
133 * WRITE_READ_PARSE_PLAN_TREES.
134 */
135 rte->graph_pattern = NULL;
136 rte->graph_table_columns = NIL;
137
138 return parsetree;
139}
@ RTE_SUBQUERY
#define linitial(l)
Definition pg_list.h:178
static Query * generate_union_from_pathqueries(List **pathqueries)
static List * generate_queries_for_path_pattern(RangeTblEntry *rte, List *element_patterns)
void AcquireRewriteLocks(Query *parsetree, bool forExecute, bool forUpdatePushedDown)

References AcquireRewriteLocks(), Assert, fb(), generate_queries_for_path_pattern(), generate_union_from_pathqueries(), linitial, list_length(), NIL, rt_fetch, Query::rtable, and RTE_SUBQUERY.

Referenced by fireRIRrules().