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 1155 of file rewriteGraphTable.c.

1156{
1157 List *quals = NIL;
1159 Datum datum;
1160 Datum *d1,
1161 *d2,
1162 *d3;
1163 int n1,
1164 n2,
1165 n3;
1166 ParseState *pstate = make_parsestate(NULL);
1168
1170
1173
1176
1179
1180 if (n1 != n2)
1181 elog(ERROR, "array size key (%d) vs ref (%d) mismatch for element ID %u", catalog_key_attnum, catalog_ref_attnum, pgeform->oid);
1182 if (n1 != n3)
1183 elog(ERROR, "array size key (%d) vs operator (%d) mismatch for element ID %u", catalog_key_attnum, catalog_eqop_attnum, pgeform->oid);
1184
1185 for (int i = 0; i < n1; i++)
1186 {
1189 Oid eqop = DatumGetObjectId(d3[i]);
1190 Var *keyvar;
1191 Var *refvar;
1192 Oid atttypid;
1193 int32 atttypmod;
1194 Oid attcoll;
1195 HeapTuple tup;
1197 List *args;
1201
1202 get_atttypetypmodcoll(pgeform->pgerelid, keyattn, &atttypid, &atttypmod, &attcoll);
1203 keyvar = makeVar(edgerti, keyattn, atttypid, atttypmod, attcoll, 0);
1204 get_atttypetypmodcoll(refrelid, refattn, &atttypid, &atttypmod, &attcoll);
1205 refvar = makeVar(refrti, refattn, atttypid, atttypmod, attcoll, 0);
1206
1208 if (!HeapTupleIsValid(tup))
1209 elog(ERROR, "cache lookup failed for operator %u", eqop);
1211 /* An equality operator is a binary operator returning boolean result. */
1212 Assert(opform->oprkind == 'b'
1213 && RegProcedureIsValid(opform->oprcode)
1214 && opform->oprresult == BOOLOID
1215 && !get_func_retset(opform->oprcode));
1216
1217 /*
1218 * Prepare operands and cast them to the types required by the
1219 * equality operator. Similar to PK/FK quals, referenced vertex key is
1220 * used as left operand and referencing edge key is used as right
1221 * operand.
1222 */
1226 declared_arg_types[0] = opform->oprleft;
1227 declared_arg_types[1] = opform->oprright;
1229
1231 linkqual->opno = opform->oid;
1232 linkqual->opfuncid = opform->oprcode;
1233 linkqual->opresulttype = opform->oprresult;
1234 linkqual->opretset = false;
1235 /* opcollid and inputcollid will be set by parse_collate.c */
1236 linkqual->args = args;
1237 linkqual->location = -1;
1238
1240 quals = lappend(quals, linkqual);
1241 }
1242
1243 assign_expr_collations(pstate, (Node *) quals);
1244
1245 return quals;
1246}
#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:862
#define Assert(condition)
Definition c.h:943
int32_t int32
Definition c.h:620
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:227
#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:246
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:265
Datum SysCacheGetAttrNotNull(SysCacheIdentifier cacheId, HeapTuple tup, AttrNumber attributeNumber)
Definition syscache.c:626
HeapTuple SearchSysCache1(SysCacheIdentifier cacheId, Datum key1)
Definition syscache.c:221
#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 752 of file rewriteGraphTable.c.

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

175{
178 int factorpos = 0;
180 struct path_factor *prev_pf = NULL;
181
183
184 /*
185 * Create a list of path factors representing the given path pattern
186 * linking edge path factors to their adjacent vertex path factors.
187 *
188 * While doing that merge element patterns with the same variable name
189 * into a single path_factor.
190 */
192 {
193 struct path_factor *pf = NULL;
194
195 /*
196 * Unsupported conditions should have been caught by the parser
197 * itself. We have corresponding Asserts here to document the
198 * assumptions in this code.
199 */
200 Assert(gep->kind == VERTEX_PATTERN || IS_EDGE_PATTERN(gep->kind));
201 Assert(!gep->quantifier);
202
204 {
205 if (gep->variable && other->variable &&
206 strcmp(gep->variable, other->variable) == 0)
207 {
208 if (other->kind != gep->kind)
211 errmsg("element patterns with same variable name \"%s\" but different element pattern types",
212 gep->variable)));
213
214 /*
215 * If both the element patterns have label expressions, they
216 * need to be conjuncted, which is not supported right now.
217 *
218 * However, an empty label expression means all labels.
219 * Conjunction of any label expression with all labels is the
220 * expression itself. Hence if only one of the two element
221 * patterns has a label expression use that expression.
222 */
223 if (!other->labelexpr)
224 other->labelexpr = gep->labelexpr;
225 else if (gep->labelexpr && !equal(other->labelexpr, gep->labelexpr))
228 errmsg("element patterns with same variable name \"%s\" but different label expressions are not supported",
229 gep->variable)));
230
231 /*
232 * If two element patterns have the same variable name, they
233 * represent the same set of graph elements and hence are
234 * constrained by conditions from both the element patterns.
235 */
236 if (!other->whereClause)
237 other->whereClause = gep->whereClause;
238 else if (gep->whereClause)
239 other->whereClause = (Node *) makeBoolExpr(AND_EXPR,
240 list_make2(other->whereClause, gep->whereClause),
241 -1);
242 pf = other;
243 break;
244 }
245 }
246
247 if (!pf)
248 {
249 pf = palloc0_object(struct path_factor);
250 pf->factorpos = factorpos++;
251 pf->kind = gep->kind;
252 pf->labelexpr = gep->labelexpr;
253 pf->variable = gep->variable;
254 pf->whereClause = gep->whereClause;
255
257 }
258
259 /*
260 * Setup links to the previous path factor in the path.
261 *
262 * If the previous path factor represents an edge, this path factor
263 * represents an adjacent vertex; the source vertex for an edge
264 * pointing left or the destination vertex for an edge pointing right.
265 * If this path factor represents an edge, the previous path factor
266 * represents an adjacent vertex; source vertex for an edge pointing
267 * right or the destination vertex for an edge pointing left.
268 *
269 * Edge pointing in any direction is treated similar to that pointing
270 * in right direction here. When constructing a query in
271 * generate_query_for_graph_path(), we will try links in both the
272 * directions.
273 *
274 * If multiple edge patterns share the same variable name, they
275 * constrain the adjacent vertex patterns since an edge can connect
276 * only one pair of vertexes. These adjacent vertex patterns need to
277 * be merged even though they have different variables. Such element
278 * patterns form a walk of graph where vertex and edges are repeated.
279 * For example, in (a)-[b]->(c)<-[b]-(d), (a) and (d) represent the
280 * same vertex element. This is slightly harder to implement and
281 * probably less useful. Hence not supported for now.
282 */
283 if (prev_pf)
284 {
285 if (prev_pf->kind == EDGE_PATTERN_RIGHT || prev_pf->kind == EDGE_PATTERN_ANY)
286 {
287 Assert(!IS_EDGE_PATTERN(pf->kind));
288 if (prev_pf->dest_pf && prev_pf->dest_pf != pf)
291 errmsg("an edge cannot connect more than two vertexes even in a cyclic pattern"));
292 prev_pf->dest_pf = pf;
293 }
294 else if (prev_pf->kind == EDGE_PATTERN_LEFT)
295 {
296 Assert(!IS_EDGE_PATTERN(pf->kind));
297 if (prev_pf->src_pf && prev_pf->src_pf != pf)
300 errmsg("an edge cannot connect more than two vertexes even in a cyclic pattern"));
301 prev_pf->src_pf = pf;
302 }
303 else
304 {
305 Assert(prev_pf->kind == VERTEX_PATTERN);
306 Assert(IS_EDGE_PATTERN(pf->kind));
307 }
308
309 if (pf->kind == EDGE_PATTERN_RIGHT || pf->kind == EDGE_PATTERN_ANY)
310 {
312 if (pf->src_pf && pf->src_pf != prev_pf)
315 errmsg("an edge cannot connect more than two vertexes even in a cyclic pattern"));
316 pf->src_pf = prev_pf;
317 }
318 else if (pf->kind == EDGE_PATTERN_LEFT)
319 {
321 if (pf->dest_pf && pf->dest_pf != prev_pf)
324 errmsg("an edge cannot connect more than two vertexes even in a cyclic pattern"));
325 pf->dest_pf = prev_pf;
326 }
327 else
328 {
329 Assert(pf->kind == VERTEX_PATTERN);
331 }
332 }
333
334 prev_pf = pf;
335 }
336
337 /*
338 * Collect list of elements for each path factor. Do this after all the
339 * edge links are setup correctly.
340 */
344
346 NIL, path_elem_lists, 0);
347 if (!pathqueries)
349
350 return pathqueries;
351}
int errcode(int sqlerrcode)
Definition elog.c:874
#define ereport(elevel,...)
Definition elog.h:151
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:244
#define foreach_ptr(type, var, lst)
Definition pg_list.h:501
#define foreach_node(type, var, lst)
Definition pg_list.h:528
@ 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 360 of file rewriteGraphTable.c.

361{
363
365 {
366 /* Update current path being built with current element. */
368
369 /*
370 * If this is the last element in the path, generate query for the
371 * completed path. Else recurse processing the next element.
372 */
374 {
376
378 if (pathquery)
380 }
381 else
383 cur_path,
385 elempos + 1);
386 /* Make way for the next element at the same position. */
388 }
389
390 return pathqueries;
391}
List * list_delete_last(List *list)
Definition list.c:957
#define list_nth_node(type, list, n)
Definition pg_list.h:359
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 578 of file rewriteGraphTable.c.

579{
580 Query *query = makeNode(Query);
581
582 query->commandType = CMD_SELECT;
583 query->rtable = NIL;
584 query->rteperminfos = NIL;
585 query->jointree = makeFromExpr(NIL, (Node *) makeBoolConst(false, false));
586
587 /*
588 * Even though no rows are returned, the result still projects the same
589 * columns as projected by GRAPH_TABLE clause. Do this by constructing a
590 * target list full of NULL values.
591 */
592 foreach_node(TargetEntry, te, rte->graph_table_columns)
593 {
594 Node *nte = (Node *) te->expr;
595
597 query->targetList = lappend(query->targetList, te);
598 }
599
600 return query;
601}
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:185
List * rtable
Definition parsenodes.h:178
CmdType commandType
Definition parsenodes.h:121
List * targetList
Definition parsenodes.h:201

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 415 of file rewriteGraphTable.c.

416{
418 List *fromlist = NIL;
420 List *vars;
421
422 path_query->commandType = CMD_SELECT;
423
425 {
426 struct path_factor *pf = pe->path_factor;
428 Relation rel;
430
431 Assert(pf->kind == VERTEX_PATTERN || IS_EDGE_PATTERN(pf->kind));
432
433 /* Add conditions representing edge connections. */
434 if (IS_EDGE_PATTERN(pf->kind))
435 {
436 struct path_element *src_pe;
437 struct path_element *dest_pe;
439
440 Assert(pf->src_pf && pf->dest_pf);
441 src_pe = list_nth(graph_path, pf->src_pf->factorpos);
442 dest_pe = list_nth(graph_path, pf->dest_pf->factorpos);
443
444 /* Make sure that the links of adjacent vertices are correct. */
445 Assert(pf->src_pf == src_pe->path_factor &&
446 pf->dest_pf == dest_pe->path_factor);
447
448 if (src_pe->elemoid == pe->srcvertexid &&
449 dest_pe->elemoid == pe->destvertexid)
451 list_concat(copyObject(pe->src_quals),
452 copyObject(pe->dest_quals)),
453 -1);
454
455 /*
456 * An edge pattern in any direction matches edges in both
457 * directions, try swapping source and destination. When the
458 * source and destination is the same vertex table, quals
459 * corresponding to either direction may get satisfied. Hence OR
460 * the quals corresponding to both the directions.
461 */
462 if (pf->kind == EDGE_PATTERN_ANY &&
463 dest_pe->elemoid == pe->srcvertexid &&
464 src_pe->elemoid == pe->destvertexid)
465 {
466 List *src_quals = copyObject(pe->dest_quals);
467 List *dest_quals = copyObject(pe->src_quals);
469
470 /* Swap the source and destination varnos in the quals. */
471 ChangeVarNodes((Node *) dest_quals, pe->path_factor->src_pf->factorpos + 1,
472 pe->path_factor->dest_pf->factorpos + 1, 0);
473 ChangeVarNodes((Node *) src_quals, pe->path_factor->dest_pf->factorpos + 1,
474 pe->path_factor->src_pf->factorpos + 1, 0);
475
477 if (edge_qual)
479 else
481 }
482
483 /*
484 * If the given edge element does not connect the adjacent vertex
485 * elements in this path, the path is broken. Abandon this path as
486 * it won't return any rows.
487 */
488 if (edge_qual == NULL)
489 return NULL;
490
492 }
493 else
494 Assert(!pe->src_quals && !pe->dest_quals);
495
496 /*
497 * Create RangeTblEntry for this element table.
498 *
499 * SQL/PGQ standard (Ref. Section 11.19, Access rule 2 and General
500 * rule 4) does not specify whose access privileges to use when
501 * accessing the element tables: property graph owner's or current
502 * user's. It is safer to use current user's privileges so as not to
503 * make property graphs as a hole for unpriviledged data access. This
504 * is inline with the views being security_invoker by default.
505 */
506 rel = table_open(pe->reloid, AccessShareLock);
508 NULL, true, false);
509 table_close(rel, NoLock);
510 path_query->rtable = lappend(path_query->rtable, pni->p_rte);
511 path_query->rteperminfos = lappend(path_query->rteperminfos, pni->p_perminfo);
512 pni->p_rte->perminfoindex = list_length(path_query->rteperminfos);
514 rtr->rtindex = list_length(path_query->rtable);
515 fromlist = lappend(fromlist, rtr);
516
517 /*
518 * Make sure that the assumption mentioned in create_pe_for_element()
519 * holds true; that the elements' RangeTblEntrys are added in the
520 * order in which their respective path factors appear in the list of
521 * path factors representing the path pattern.
522 */
523 Assert(pf->factorpos + 1 == rtr->rtindex);
524
525 if (pf->whereClause)
526 {
527 Node *tr;
528
529 tr = replace_property_refs(rte->relid, pf->whereClause, list_make1(pe));
530
532 }
533 }
534
535 if (rte->graph_pattern->whereClause)
536 {
538 (Node *) rte->graph_pattern->whereClause,
539 graph_path);
540
542 }
543
544 path_query->jointree = makeFromExpr(fromlist,
546
547 /* Construct query targetlist from COLUMNS specification of GRAPH_TABLE. */
548 path_query->targetList = castNode(List,
550 (Node *) rte->graph_table_columns,
551 graph_path));
552
553 /*
554 * Mark the columns being accessed in the path query as requiring SELECT
555 * privilege. Any lateral columns should have been handled when the
556 * corresponding ColumnRefs were transformed. Ignore those here.
557 */
559 foreach_node(Var, var, vars)
560 {
562 rt_fetch(var->varno, path_query->rtable));
563
564 /* Must offset the attnum to fit in a bitmapset */
565 perminfo->selectedCols = bms_add_member(perminfo->selectedCols,
566 var->varattno - FirstLowInvalidHeapAttributeNumber);
567 }
568
569 return path_query;
570}
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:331
@ 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 692 of file rewriteGraphTable.c.

693{
695 Query *lquery;
696 Node *rarg;
700
701 /* Recursion termination condition. */
702 if (list_length(pathqueries) == 0)
703 {
704 *targetlist = NIL;
705 return NULL;
706 }
707
709
711 false, false);
712 *rtable = lappend(*rtable, pni->p_rte);
713 lrtr->rtindex = list_length(*rtable);
715 if (rarg == NULL)
716 {
717 /*
718 * No further path queries in the list. Convert the last query into a
719 * RangeTblRef as expected by SetOperationStmt. Extract a list of the
720 * non-junk TLEs for upper-level processing.
721 */
722 if (targetlist)
723 {
724 *targetlist = NIL;
725 foreach_node(TargetEntry, tle, lquery->targetList)
726 {
727 if (!tle->resjunk)
728 *targetlist = lappend(*targetlist, tle);
729 }
730 }
731 return (Node *) lrtr;
732 }
733
735 sostmt->op = SETOP_UNION;
736 sostmt->all = true;
737 sostmt->larg = (Node *) lrtr;
738 sostmt->rarg = rarg;
739 constructSetOpTargetlist(NULL, sostmt, lquery->targetList, rtargetlist, targetlist, "UNION", false);
740
741 return (Node *) sostmt;
742}
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:2601
#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 616 of file rewriteGraphTable.c.

617{
618 List *rtable = NIL;
622 int resno;
623 ListCell *lctl,
624 *lct,
625 *lcm,
626 *lcc;
627
629
630 /* If there's only one pathquery, no need to construct a UNION query. */
631 if (list_length(*pathqueries) == 1)
632 {
633 *pathqueries = NIL;
634 return sampleQuery;
635 }
636
639
640 /* Encapsulate the set operation statement into a Query. */
642 union_query->commandType = CMD_SELECT;
643 union_query->rtable = rtable;
644 union_query->setOperations = (Node *) sostmt;
645 union_query->rteperminfos = NIL;
646 union_query->jointree = makeFromExpr(NIL, NULL);
647
648 /*
649 * Generate dummy targetlist for outer query using column names from one
650 * of the queries and common datatypes/collations of topmost set
651 * operation. It shouldn't matter which query. Also it shouldn't matter
652 * which RT index is used as varno in the target list entries, as long as
653 * it corresponds to a real RT entry; else funny things may happen when
654 * the tree is mashed by rule rewriting. So we use 1 since there's always
655 * one RT entry at least.
656 */
657 Assert(rt_fetch(1, rtable));
658 union_query->targetList = NULL;
659 resno = 1;
660 forfour(lct, sostmt->colTypes,
661 lcm, sostmt->colTypmods,
662 lcc, sostmt->colCollations,
663 lctl, sampleQuery->targetList)
664 {
669 char *colName;
671 Var *var;
672
673 Assert(!sample_tle->resjunk);
674 colName = pstrdup(sample_tle->resname);
675 var = makeVar(1, sample_tle->resno, colType, colTypmod, colCollation, 0);
676 var->location = exprLocation((Node *) sample_tle->expr);
677 tle = makeTargetEntry((Expr *) var, (AttrNumber) resno++, colName, false);
678 union_query->targetList = lappend(union_query->targetList, tle);
679 }
680
681 *pathqueries = NIL;
682 return union_query;
683}
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:607
#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 1291 of file rewriteGraphTable.c.

1292{
1293 Relation rel;
1294 SysScanDesc scan;
1295 ScanKeyData key[1];
1297 Node *n = NULL;
1298
1300 ScanKeyInit(&key[0],
1303 F_OIDEQ, ObjectIdGetDatum(elemoid));
1305 true, NULL, 1, key);
1306
1308 {
1310
1313
1314 if (!proptup)
1315 continue;
1318 ChangeVarNodes(n, 1, rtindex, 0);
1319
1321 break;
1322 }
1323 systable_endscan(scan);
1325
1326 return n;
1327}
#define TextDatumGetCString(d)
Definition builtins.h:99
void systable_endscan(SysScanDesc sysscan)
Definition genam.c:604
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition genam.c:515
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:231

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 815 of file rewriteGraphTable.c.

816{
818
819 if (!labelexpr)
820 {
821 Relation rel;
822 SysScanDesc scan;
823 ScanKeyData key[1];
825
826 /*
827 * According to section 9.2 "Contextual inference of a set of labels"
828 * subclause 2.a.ii of SQL/PGQ standard, element pattern which does
829 * not have a label expression is considered to have label expression
830 * equivalent to '%|!%' which is set of all labels.
831 */
832 label_oids = NIL;
834 ScanKeyInit(&key[0],
837 F_OIDEQ, ObjectIdGetDatum(propgraphid));
839 true, NULL, 1, key);
840 while (HeapTupleIsValid(tup = systable_getnext(scan)))
841 {
843
845 }
846 systable_endscan(scan);
848 }
849 else if (IsA(labelexpr, GraphLabelRef))
850 {
852
853 label_oids = list_make1_oid(glr->labelid);
854 }
855 else if (IsA(labelexpr, BoolExpr))
856 {
857 BoolExpr *be = castNode(BoolExpr, labelexpr);
858 List *label_exprs = be->args;
859
860 label_oids = NIL;
863 }
864 else
865 {
866 /*
867 * should not reach here since gram.y will not generate a label
868 * expression with other node types.
869 */
870 elog(ERROR, "unsupported label expression node: %d", (int) nodeTag(labelexpr));
871 }
872
873 return label_oids;
874}
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:274
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 893 of file rewriteGraphTable.c.

894{
895 List *label_oids = get_labels_for_expr(propgraphid, pf->labelexpr);
900 Relation rel;
901 SysScanDesc scan;
902 ScanKeyData key[1];
904
905 /*
906 * A property graph element can be either a vertex or an edge. Other types
907 * of path factors like nested path pattern need to be handled separately
908 * when supported.
909 */
910 Assert(pf->kind == VERTEX_PATTERN || IS_EDGE_PATTERN(pf->kind));
911
914 {
915 bool found = false;
916
917 ScanKeyInit(&key[0],
922 NULL, 1, key);
923 while (HeapTupleIsValid(tup = systable_getnext(scan)))
924 {
926 Oid elem_oid = label_elem->pgelelid;
927
929 {
930 /*
931 * Create path_element object if the new element qualifies the
932 * element pattern kind.
933 */
935
936 if (pe)
937 {
939
940 /* Remember qualified elements. */
942 found = true;
943 }
944
945 /*
946 * Remember qualified and unqualified elements processed so
947 * far to avoid processing already processed elements again.
948 */
950 }
952 {
953 /*
954 * The graph element is known to qualify the given element
955 * pattern. Flag that the current label has at least one
956 * qualified element associated with it.
957 */
958 found = true;
959 }
960 }
961
962 if (!found)
963 {
964 /*
965 * We did not find any qualified element associated with this
966 * label. The label or its properties can not be associated with
967 * the given element pattern. Throw an error if the label was
968 * explicitly specified in the element pattern. Otherwise remember
969 * it for later use.
970 */
971 if (!pf->labelexpr)
973 else
976 errmsg("no property graph element of type \"%s\" has label \"%s\" associated with it in property graph \"%s\"",
977 pf->kind == VERTEX_PATTERN ? "vertex" : "edge",
979 get_rel_name(propgraphid))));
980 }
981
982 systable_endscan(scan);
983 }
985
986 /*
987 * Remove the labels which were not explicitly mentioned in the label
988 * expression but do not have any qualified elements associated with them.
989 * Properties associated with such labels may not be referenced. See
990 * replace_property_refs_mutator() for more details.
991 */
993
994 return path_elements;
995}
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:3966
#define foreach_oid(var, lst)
Definition pg_list.h:503
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 1141 of file rewriteGraphTable.c.

1142{
1143 struct replace_property_refs_context context;
1144
1145 context.mappings = mappings;
1146 context.propgraphid = propgraphid;
1147
1149}
#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 1008 of file rewriteGraphTable.c.

1009{
1010 if (node == NULL)
1011 return NULL;
1012 if (IsA(node, Var))
1013 {
1014 Var *var = (Var *) node;
1015 Var *newvar = copyObject(var);
1016
1017 /*
1018 * If it's already a Var, then it was a lateral reference. Since we
1019 * are in a subquery after the rewrite, we have to increase the level
1020 * by one.
1021 */
1022 newvar->varlevelsup++;
1023
1024 return (Node *) newvar;
1025 }
1026 else if (IsA(node, GraphPropertyRef))
1027 {
1029 Node *n = NULL;
1033
1034 foreach_ptr(struct path_element, m, context->mappings)
1035 {
1036 if (m->path_factor->variable && strcmp(gpr->elvarname, m->path_factor->variable) == 0)
1037 {
1038 found_mapping = m;
1039 break;
1040 }
1041 }
1042
1043 /*
1044 * transformGraphTablePropertyRef() would not create a
1045 * GraphPropertyRef for a variable which is not present in the graph
1046 * path pattern.
1047 */
1049
1050 mapping_factor = found_mapping->path_factor;
1051
1052 /*
1053 * Find property definition for given element through any of the
1054 * associated labels qualifying the given element pattern.
1055 */
1057 {
1062
1064 {
1066 ObjectIdGetDatum(gpr->propid));
1067
1068 if (!tup)
1069 {
1070 /*
1071 * The label is associated with the given element but it
1072 * is not associated with the required property. Check
1073 * next label.
1074 */
1075 continue;
1076 }
1077
1080 ChangeVarNodes(n, 1, mapping_factor->factorpos + 1, 0);
1081
1083 }
1084 else
1085 {
1086 /*
1087 * Label is not associated with the element but it may be
1088 * associated with the property through some other element.
1089 * Save it for later use.
1090 */
1092 }
1093 }
1094
1095 /* See if we can resolve the property in some other way. */
1096 if (!n)
1097 {
1098 bool prop_associated = false;
1099
1101 {
1103 {
1104 prop_associated = true;
1105 break;
1106 }
1107 }
1108
1109 if (prop_associated)
1110 {
1111 /*
1112 * The property is associated with at least one of the labels
1113 * that satisfy given element pattern. If it's associated with
1114 * the given element (through some other label), use
1115 * corresponding value expression. Otherwise NULL. Ref.
1116 * SQL/PGQ standard section 6.5 Property Reference, General
1117 * Rule 2.b.
1118 */
1119 n = get_element_property_expr(found_mapping->elemoid, gpr->propid,
1120 mapping_factor->factorpos + 1);
1121
1122 if (!n)
1123 n = (Node *) makeNullConst(gpr->typeId, gpr->typmod, gpr->collation);
1124 }
1125
1126 }
1127
1128 if (!n)
1129 ereport(ERROR,
1131 errmsg("property \"%s\" for element variable \"%s\" not found",
1132 get_propgraph_property_name(gpr->propid), mapping_factor->variable));
1133
1134 return n;
1135 }
1136
1138}
#define OidIsValid(objectId)
Definition c.h:858
char * get_propgraph_property_name(Oid propoid)
Definition lsyscache.c:3984
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 109 of file rewriteGraphTable.c.

110{
115
116 rte = rt_fetch(rt_index, parsetree->rtable);
117
118 Assert(list_length(rte->graph_pattern->path_pattern_list) == 1);
119
120 path_pattern = linitial(rte->graph_pattern->path_pattern_list);
123
125
126 rte->rtekind = RTE_SUBQUERY;
127 rte->subquery = graph_table_query;
128 rte->lateral = true;
129
130 /*
131 * Reset no longer applicable fields, to appease
132 * WRITE_READ_PARSE_PLAN_TREES.
133 */
134 rte->graph_pattern = NULL;
135 rte->graph_table_columns = NIL;
136
137 return parsetree;
138}
@ 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().