PostgreSQL Source Code git master
Loading...
Searching...
No Matches
propgraphcmds.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * propgraphcmds.c
4 * property graph manipulation
5 *
6 * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
8 *
9 * src/backend/commands/propgraphcmds.c
10 *
11 *-------------------------------------------------------------------------
12 */
13#include "postgres.h"
14
15#include "access/genam.h"
16#include "access/htup_details.h"
17#include "access/nbtree.h"
18#include "access/table.h"
19#include "access/xact.h"
20#include "catalog/catalog.h"
21#include "catalog/indexing.h"
22#include "catalog/namespace.h"
23#include "catalog/pg_class.h"
24#include "catalog/pg_collation_d.h"
25#include "catalog/pg_operator_d.h"
31#include "commands/defrem.h"
33#include "commands/tablecmds.h"
34#include "nodes/nodeFuncs.h"
35#include "parser/parse_coerce.h"
37#include "parser/parse_oper.h"
39#include "parser/parse_target.h"
40#include "utils/array.h"
41#include "utils/builtins.h"
42#include "utils/fmgroids.h"
43#include "utils/inval.h"
44#include "utils/lsyscache.h"
45#include "utils/rel.h"
46#include "utils/ruleutils.h"
47#include "utils/syscache.h"
48
49
74
75
77 const char *aliasname, int location);
78static void propgraph_edge_get_ref_keys(ParseState *pstate, const List *keycols, const List *refcols,
80 const char *aliasname, int location, const char *type,
82static AttrNumber *array_from_column_list(ParseState *pstate, const List *colnames, int location, Relation element_rel);
83static ArrayType *array_from_attnums(int numattrs, const AttrNumber *attnums);
85static Oid insert_label_record(Oid graphid, Oid peoid, const char *label);
86static void insert_property_records(Oid graphid, Oid ellabeloid, Oid pgerelid, const PropGraphProperties *properties);
87static void insert_property_record(Oid graphid, Oid ellabeloid, Oid pgerelid, const char *propname, const Expr *expr);
91static Oid get_vertex_oid(ParseState *pstate, Oid pgrelid, const char *alias, int location);
92static Oid get_edge_oid(ParseState *pstate, Oid pgrelid, const char *alias, int location);
94static List *get_graph_label_ids(Oid graphid);
95static List *get_label_element_label_ids(Oid labelid);
97static List *get_graph_property_ids(Oid graphid);
98
99
100/*
101 * CREATE PROPERTY GRAPH
102 */
105{
108 ListCell *lc;
114
115 if (stmt->pgname->relpersistence == RELPERSISTENCE_UNLOGGED)
118 errmsg("property graphs cannot be unlogged because they do not have storage")));
119
121
122 foreach(lc, stmt->vertex_tables)
123 {
125 struct element_info *vinfo;
126 Relation rel;
127
129 vinfo->kind = PGEKIND_VERTEX;
130
132
133 rel = table_open(vinfo->relid, NoLock);
134
135 if (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
137
138 if (vertex->vtable->alias)
139 vinfo->aliasname = vertex->vtable->alias->aliasname;
140 else
141 vinfo->aliasname = vertex->vtable->relname;
142
146 errmsg("alias \"%s\" used more than once as element table", vinfo->aliasname),
147 parser_errposition(pstate, vertex->location)));
148
149 vinfo->key = propgraph_element_get_key(pstate, vertex->vkey, rel, vinfo->aliasname, vertex->location);
150
151 vinfo->labels = vertex->labels;
152
153 table_close(rel, NoLock);
154
156
158 }
159
160 foreach(lc, stmt->edge_tables)
161 {
163 struct element_info *einfo;
164 Relation rel;
165 ListCell *lc2;
170
172 einfo->kind = PGEKIND_EDGE;
173
175
176 rel = table_open(einfo->relid, NoLock);
177
178 if (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
180
181 if (edge->etable->alias)
182 einfo->aliasname = edge->etable->alias->aliasname;
183 else
184 einfo->aliasname = edge->etable->relname;
185
189 errmsg("alias \"%s\" used more than once as element table", einfo->aliasname),
190 parser_errposition(pstate, edge->location)));
191
192 einfo->key = propgraph_element_get_key(pstate, edge->ekey, rel, einfo->aliasname, edge->location);
193
194 einfo->srcvertex = edge->esrcvertex;
195 einfo->destvertex = edge->edestvertex;
196
197 srcrelid = 0;
198 destrelid = 0;
199 foreach(lc2, vertex_infos)
200 {
201 struct element_info *vinfo = lfirst(lc2);
202
203 if (strcmp(vinfo->aliasname, edge->esrcvertex) == 0)
204 srcrelid = vinfo->relid;
205
206 if (strcmp(vinfo->aliasname, edge->edestvertex) == 0)
207 destrelid = vinfo->relid;
208
209 if (srcrelid && destrelid)
210 break;
211 }
212 if (!srcrelid)
215 errmsg("source vertex \"%s\" of edge \"%s\" does not exist",
216 edge->esrcvertex, einfo->aliasname),
217 parser_errposition(pstate, edge->location)));
218 if (!destrelid)
221 errmsg("destination vertex \"%s\" of edge \"%s\" does not exist",
222 edge->edestvertex, einfo->aliasname),
223 parser_errposition(pstate, edge->location)));
224
227
228 propgraph_edge_get_ref_keys(pstate, edge->esrckey, edge->esrcvertexcols, rel, srcrel,
229 einfo->aliasname, edge->location, "SOURCE",
230 &einfo->srckey, &einfo->srcref, &einfo->srceqop);
231 propgraph_edge_get_ref_keys(pstate, edge->edestkey, edge->edestvertexcols, rel, destrel,
232 einfo->aliasname, edge->location, "DESTINATION",
233 &einfo->destkey, &einfo->destref, &einfo->desteqop);
234
235 einfo->labels = edge->labels;
236
239
240 table_close(rel, NoLock);
241
243
245 }
246
247 cstmt->relation = stmt->pgname;
248 cstmt->oncommit = ONCOMMIT_NOOP;
249
250 /*
251 * Automatically make it temporary if any component tables are temporary
252 * (see also DefineView()).
253 */
254 if (stmt->pgname->relpersistence == RELPERSISTENCE_PERMANENT
256 {
257 cstmt->relation = copyObject(cstmt->relation);
258 cstmt->relation->relpersistence = RELPERSISTENCE_TEMP;
260 (errmsg("property graph \"%s\" will be temporary",
261 stmt->pgname->relname)));
262 }
263
265
266 foreach(lc, vertex_infos)
267 {
268 struct element_info *vinfo = lfirst(lc);
269 Oid peoid;
270
273 }
274
275 foreach(lc, edge_infos)
276 {
277 struct element_info *einfo = lfirst(lc);
278 Oid peoid;
279 ListCell *lc2;
280
281 /*
282 * Look up the vertices again. Now the vertices have OIDs assigned,
283 * which we need.
284 */
285 foreach(lc2, vertex_infos)
286 {
287 struct element_info *vinfo = lfirst(lc2);
288
289 if (strcmp(vinfo->aliasname, einfo->srcvertex) == 0)
290 {
291 einfo->srcvertexid = vinfo->elementid;
292 einfo->srcrelid = vinfo->relid;
293 }
294 if (strcmp(vinfo->aliasname, einfo->destvertex) == 0)
295 {
296 einfo->destvertexid = vinfo->elementid;
297 einfo->destrelid = vinfo->relid;
298 }
299 if (einfo->srcvertexid && einfo->destvertexid)
300 break;
301 }
302 Assert(einfo->srcvertexid);
303 Assert(einfo->destvertexid);
304 Assert(einfo->srcrelid);
305 Assert(einfo->destrelid);
308 }
309
311
315
316 return pgaddress;
317}
318
319/*
320 * Process the key clause specified for an element. If key_clause is non-NIL,
321 * then it is a list of column names. Otherwise, the primary key of the
322 * relation is used. The return value is an array of column numbers.
323 */
324static ArrayType *
326{
327 ArrayType *a;
328
329 if (key_clause == NIL)
330 {
332
333 if (!pkidx)
336 errmsg("no key specified and no suitable primary key exists for definition of element \"%s\"", aliasname),
337 parser_errposition(pstate, location));
338 else
339 {
341
343 a = array_from_attnums(indexDesc->rd_index->indkey.dim1, indexDesc->rd_index->indkey.values);
345 }
346 }
347 else
348 {
350 array_from_column_list(pstate, key_clause, location, element_rel));
351 }
352
353 return a;
354}
355
356/*
357 * Process the source or destination link of an edge.
358 *
359 * keycols and refcols are column names representing the local and referenced
360 * (vertex) columns. If they are both NIL, a matching foreign key is looked
361 * up.
362 *
363 * edge_rel and ref_rel are the local and referenced element tables.
364 *
365 * aliasname, location, and type are for error messages. type is either
366 * "SOURCE" or "DESTINATION".
367 *
368 * The outputs are arrays of column numbers in outkey and outref.
369 */
370static void
373 const char *aliasname, int location, const char *type,
375{
376 int nkeys;
379 Oid *keyeqops;
380 Datum *datums;
381
382 Assert((keycols && refcols) || (!keycols && !refcols));
383
384 if (keycols)
385 {
389 errmsg("mismatching number of columns in %s vertex definition of edge \"%s\"", type, aliasname),
390 parser_errposition(pstate, location));
391
392 nkeys = list_length(keycols);
394 refattnums = array_from_column_list(pstate, refcols, location, ref_rel);
395 keyeqops = palloc_array(Oid, nkeys);
396
397 for (int i = 0; i < nkeys; i++)
398 {
399 Oid keytype;
401 Oid keycoll;
402 Oid reftype;
404 Oid refcoll;
405 Oid opc;
406 Oid opf;
407 StrategyNumber strategy;
408
409 /*
410 * Lookup equality operator to be used for edge and vertex key.
411 * Vertex key is equivalent to primary key and edge key is similar
412 * to foreign key since edge key references vertex key. Hence
413 * vertex key is used as left operand and edge key is used as
414 * right operand. The method used to find the equality operators
415 * is similar to the method used to find equality operators for
416 * FK/PK comparison in ATAddForeignKeyConstraint() except that
417 * opclass of the vertex key type is used as a starting point.
418 * Since we need only equality operators we use both BT and HASH
419 * strategies.
420 *
421 * If the required operators do not exist, we can not construct
422 * quals linking an edge to its adjacent vertices.
423 */
427 strategy = BTEqualStrategyNumber;
429 if (!OidIsValid(opc))
430 {
432 strategy = HTEqualStrategyNumber;
433 }
434 if (OidIsValid(opc))
435 {
437 if (OidIsValid(opf))
438 {
440 if (!OidIsValid(keyeqops[i]))
441 {
442 /* Last resort, implicit cast. */
445 }
446 }
447 }
448
449 if (!OidIsValid(keyeqops[i]))
452 errmsg("no equality operator exists for %s key comparison of edge \"%s\"",
453 type, aliasname),
454 parser_errposition(pstate, location));
455
456 /*
457 * If collations of key attribute and referenced attribute are
458 * different, an edge may end up being adjacent to undesired
459 * vertices. Prohibit such a case.
460 *
461 * PK/FK allows different collations as long as they are
462 * deterministic for backward compatibility. But we can be a bit
463 * stricter here and follow SQL standard.
464 */
465 if (keycoll != refcoll &&
470 errmsg("collation mismatch in %s key of edge \"%s\": %s vs. %s",
473 parser_errposition(pstate, location));
474 }
475 }
476 else
477 {
479
481 {
482 if (tmp->confrelid == RelationGetRelid(ref_rel))
483 {
484 if (fk)
487 errmsg("more than one suitable foreign key exists for %s key of edge \"%s\"", type, aliasname),
488 parser_errposition(pstate, location));
489 fk = tmp;
490 }
491 }
492
493 if (!fk)
496 errmsg("no %s key specified and no suitable foreign key exists for definition of edge \"%s\"", type, aliasname),
497 parser_errposition(pstate, location));
498
499 nkeys = fk->nkeys;
500 keyattnums = fk->conkey;
501 refattnums = fk->confkey;
502 keyeqops = fk->conpfeqop;
503 }
504
507 datums = palloc_array(Datum, nkeys);
508 for (int i = 0; i < nkeys; i++)
509 datums[i] = ObjectIdGetDatum(keyeqops[i]);
510 *outeqop = construct_array_builtin(datums, nkeys, OIDOID);
511}
512
513/*
514 * Convert list of column names in the specified relation into an array of
515 * column numbers.
516 */
517static AttrNumber *
518array_from_column_list(ParseState *pstate, const List *colnames, int location, Relation element_rel)
519{
520 int numattrs;
521 AttrNumber *attnums;
522 int i;
523 ListCell *lc;
524
525 numattrs = list_length(colnames);
526 attnums = palloc_array(AttrNumber, numattrs);
527
528 i = 0;
529 foreach(lc, colnames)
530 {
531 char *colname = strVal(lfirst(lc));
534
535 attnum = get_attnum(relid, colname);
536 if (!attnum)
539 errmsg("column \"%s\" of relation \"%s\" does not exist",
540 colname, get_rel_name(relid)),
541 parser_errposition(pstate, location)));
542 attnums[i++] = attnum;
543 }
544
545 for (int j = 0; j < numattrs; j++)
546 {
547 for (int k = j + 1; k < numattrs; k++)
548 {
549 if (attnums[j] == attnums[k])
552 errmsg("graph key columns list must not contain duplicates"),
553 parser_errposition(pstate, location)));
554 }
555 }
556
557 return attnums;
558}
559
560static ArrayType *
562{
564
566
567 for (int i = 0; i < numattrs; i++)
568 attnumsd[i] = Int16GetDatum(attnums[i]);
569
571}
572
573static void
589
590static void
606
607/*
608 * Insert a record for an element into the pg_propgraph_element catalog. Also
609 * inserts labels and properties into their respective catalogs.
610 */
611static Oid
613{
614 Oid graphid = pgaddress.objectId;
615 Relation rel;
617 Oid peoid;
619 bool nulls[Natts_pg_propgraph_element] = {0};
623 ObjectAddresses *addrs;
624
626
628 einfo->elementid = peoid;
632 namestrcpy(&aliasname, einfo->aliasname);
638
639 if (einfo->srckey)
641 else
642 nulls[Anum_pg_propgraph_element_pgesrckey - 1] = true;
643 if (einfo->srcref)
645 else
646 nulls[Anum_pg_propgraph_element_pgesrcref - 1] = true;
647 if (einfo->srceqop)
649 else
650 nulls[Anum_pg_propgraph_element_pgesrceqop - 1] = true;
651 if (einfo->destkey)
653 else
654 nulls[Anum_pg_propgraph_element_pgedestkey - 1] = true;
655 if (einfo->destref)
657 else
658 nulls[Anum_pg_propgraph_element_pgedestref - 1] = true;
659 if (einfo->desteqop)
661 else
663
667
669
670 /* Add dependency on the property graph */
672
673 addrs = new_object_addresses();
674
675 /* Add dependency on the relation */
678 array_of_attnums_to_objectaddrs(einfo->relid, einfo->key, addrs);
679
680 /*
681 * Add dependencies on vertices and equality operators used for key
682 * comparison.
683 */
684 if (einfo->srcvertexid)
685 {
688 array_of_attnums_to_objectaddrs(einfo->relid, einfo->srckey, addrs);
689 array_of_attnums_to_objectaddrs(einfo->srcrelid, einfo->srcref, addrs);
690 array_of_opers_to_objectaddrs(einfo->srceqop, addrs);
691 }
692 if (einfo->destvertexid)
693 {
696 array_of_attnums_to_objectaddrs(einfo->relid, einfo->destkey, addrs);
697 array_of_attnums_to_objectaddrs(einfo->destrelid, einfo->destref, addrs);
698 array_of_opers_to_objectaddrs(einfo->desteqop, addrs);
699 }
700
702
703 table_close(rel, NoLock);
704
705 if (einfo->labels)
706 {
707 ListCell *lc;
708
709 foreach(lc, einfo->labels)
710 {
713
714 if (lp->label)
715 ellabeloid = insert_label_record(graphid, peoid, lp->label);
716 else
717 ellabeloid = insert_label_record(graphid, peoid, einfo->aliasname);
718 insert_property_records(graphid, ellabeloid, einfo->relid, lp->properties);
719
721 }
722 }
723 else
724 {
727
728 pr->all = true;
729 pr->location = -1;
730
731 ellabeloid = insert_label_record(graphid, peoid, einfo->aliasname);
732 insert_property_records(graphid, ellabeloid, einfo->relid, pr);
733 }
734
735 return peoid;
736}
737
738/*
739 * Insert records for a label into the pg_propgraph_label and
740 * pg_propgraph_element_label catalogs, and register dependencies.
741 *
742 * Returns the OID of the new pg_propgraph_element_label record.
743 */
744static Oid
745insert_label_record(Oid graphid, Oid peoid, const char *label)
746{
749
750 /*
751 * Insert into pg_propgraph_label if not already existing.
752 */
754 if (!labeloid)
755 {
756 Relation rel;
758 bool nulls[Natts_pg_propgraph_label] = {0};
763
765
771
775
777
780
781 table_close(rel, NoLock);
782 }
783
784 /*
785 * Insert into pg_propgraph_element_label
786 */
787 {
788 Relation rel;
790 bool nulls[Natts_pg_propgraph_element_label] = {0};
794
796
801
805
807
812
813 table_close(rel, NoLock);
814 }
815
816 return ellabeloid;
817}
818
819/*
820 * Insert records for properties into the pg_propgraph_property catalog.
821 */
822static void
824{
825 List *proplist = NIL;
826 ParseState *pstate;
828 List *tp;
829 Relation rel;
830 ListCell *lc;
831
832 if (properties->all)
833 {
835 SysScanDesc scan;
836 ScanKeyData key[1];
838
840 ScanKeyInit(&key[0],
845 true, NULL, 1, key);
847 {
849 ColumnRef *cr;
850 ResTarget *rt;
851
852 if (att->attnum <= 0 || att->attisdropped)
853 continue;
854
857
858 cr->fields = list_make1(makeString(pstrdup(NameStr(att->attname))));
859 cr->location = -1;
860
861 rt->name = pstrdup(NameStr(att->attname));
862 rt->val = (Node *) cr;
863 rt->location = -1;
864
866 }
867 systable_endscan(scan);
869 }
870 else
871 {
872 proplist = properties->properties;
873
874 foreach(lc, proplist)
875 {
877
878 if (!rt->name && !IsA(rt->val, ColumnRef))
881 errmsg("property name required"),
882 parser_errposition(NULL, rt->location));
883 }
884 }
885
887
888 pstate = make_parsestate(NULL);
890 rel,
892 NULL,
893 false,
894 true);
895 addNSItemToQuery(pstate, nsitem, true, true, true);
896
897 table_close(rel, NoLock);
898
900 if (pstate->p_resolve_unknowns)
901 resolveTargetListUnknowns(pstate, tp);
902 assign_expr_collations(pstate, (Node *) tp);
903
904 foreach(lc, tp)
905 {
907
908 insert_property_record(graphid, ellabeloid, pgerelid, te->resname, te->expr);
909 }
910}
911
912/*
913 * Insert records for a property into the pg_propgraph_property and
914 * pg_propgraph_label_property catalogs, and register dependencies.
915 */
916static void
917insert_property_record(Oid graphid, Oid ellabeloid, Oid pgerelid, const char *propname, const Expr *expr)
918{
919 Oid propoid;
920 Oid exprtypid = exprType((const Node *) expr);
921 int32 exprtypmod = exprTypmod((const Node *) expr);
922 Oid exprcollation = exprCollation((const Node *) expr);
923
924 /*
925 * Insert into pg_propgraph_property if not already existing.
926 */
928 if (!OidIsValid(propoid))
929 {
930 Relation rel;
933 bool nulls[Natts_pg_propgraph_property] = {0};
937
939
948
952
954
960 {
963 }
964
965 table_close(rel, NoLock);
966 }
967 else
968 {
971 Oid proptypid = pgpform->pgptypid;
972 int32 proptypmod = pgpform->pgptypmod;
973 Oid propcollation = pgpform->pgpcollation;
974
976
977 /*
978 * Check that in the graph, all properties with the same name have the
979 * same type (independent of which label they are on). (See SQL/PGQ
980 * subclause "Consistency check of a tabular property graph
981 * descriptor".)
982 */
984 {
987 errmsg("property \"%s\" data type mismatch: %s vs. %s",
989 errdetail("In a property graph, a property of the same name has to have the same data type in each label."));
990 }
991
992 /* Similarly for collation */
994 {
997 errmsg("property \"%s\" collation mismatch: %s vs. %s",
999 errdetail("In a property graph, a property of the same name has to have the same collation in each label."));
1000 }
1001 }
1002
1003 /*
1004 * Insert into pg_propgraph_label_property
1005 */
1006 {
1007 Relation rel;
1009 bool nulls[Natts_pg_propgraph_label_property] = {0};
1010 Oid plpoid;
1011 HeapTuple tup;
1014
1016
1022
1024 CatalogTupleInsert(rel, tup);
1026
1028
1031
1034
1036
1037 table_close(rel, NoLock);
1038 }
1039}
1040
1041/*
1042 * Check that for the given graph element, all properties with the same name
1043 * have the same expression for each label. (See SQL/PGQ subclause "Creation
1044 * of an element table descriptor".)
1045 *
1046 * We check this after all the catalog records are already inserted. This
1047 * makes it easier to share this code between CREATE PROPERTY GRAPH and ALTER
1048 * PROPERTY GRAPH. We pass in the element OID so that ALTER PROPERTY GRAPH
1049 * only has to check the element it has just operated on. CREATE PROPERTY
1050 * GRAPH checks all elements it has created.
1051 */
1052static void
1054{
1055 Relation rel1;
1056 ScanKeyData key1[1];
1059 List *propoids = NIL;
1060 List *propexprs = NIL;
1061
1063 ScanKeyInit(&key1[0],
1067
1070 {
1072 Relation rel2;
1073 ScanKeyData key2[1];
1076
1078 ScanKeyInit(&key2[0],
1082
1085 {
1087 Oid propoid;
1088 Datum datum;
1089 bool isnull;
1090 char *propexpr;
1091 ListCell *lc1,
1092 *lc2;
1093 bool found;
1094
1095 propoid = lprop->plppropid;
1097 Assert(!isnull);
1099
1100 found = false;
1102 {
1103 if (propoid == lfirst_oid(lc1))
1104 {
1105 Node *na,
1106 *nb;
1107
1110
1111 found = true;
1112
1113 if (!equal(na, nb))
1114 {
1117 List *dpcontext;
1118 char *dpa,
1119 *dpb;
1120
1122 if (!tuple3)
1123 elog(ERROR, "cache lookup failed for property graph element %u", peoid);
1125 dpcontext = deparse_context_for(get_rel_name(elform->pgerelid), elform->pgerelid);
1126
1127 dpa = deparse_expression(na, dpcontext, false, false);
1128 dpb = deparse_expression(nb, dpcontext, false, false);
1129
1130 /*
1131 * show in sorted order to keep output independent of
1132 * index order
1133 */
1134 if (strcmp(dpa, dpb) > 0)
1135 {
1136 char *tmp;
1137
1138 tmp = dpa;
1139 dpa = dpb;
1140 dpb = tmp;
1141 }
1142
1143 ereport(ERROR,
1145 errmsg("element \"%s\" property \"%s\" expression mismatch: %s vs. %s",
1147 errdetail("In a property graph element, a property of the same name has to have the same expression in each label."));
1148
1150 }
1151
1152 break;
1153 }
1154 }
1155
1156 if (!found)
1157 {
1160 }
1161 }
1164 }
1165
1168}
1169
1170/*
1171 * Check that for the given element label, all labels of the same name in the
1172 * graph have the same number and names of properties (independent of which
1173 * element they are on). (See SQL/PGQ subclause "Consistency check of a
1174 * tabular property graph descriptor".)
1175 *
1176 * We check this after all the catalog records are already inserted. This
1177 * makes it easier to share this code between CREATE PROPERTY GRAPH and ALTER
1178 * PROPERTY GRAPH. We pass in the element label OID so that some variants of
1179 * ALTER PROPERTY GRAPH only have to check the element label it has just
1180 * operated on. CREATE PROPERTY GRAPH and other ALTER PROPERTY GRAPH variants
1181 * check all labels.
1182 */
1183static void
1185{
1186 Relation rel;
1187 SysScanDesc scan;
1188 ScanKeyData key[1];
1189 HeapTuple tuple;
1190 Oid labelid = InvalidOid;
1192 List *myprops,
1193 *refprops;
1194 List *diff1,
1195 *diff2;
1196
1198
1199 /*
1200 * Get element label info
1201 */
1202 ScanKeyInit(&key[0],
1207 if (HeapTupleIsValid(tuple = systable_getnext(scan)))
1208 {
1210
1211 labelid = ellabel->pgellabelid;
1212 }
1213 systable_endscan(scan);
1214 if (!labelid)
1215 elog(ERROR, "element label %u not found", ellabeloid);
1216
1217 /*
1218 * Find a reference element label to fetch label properties. The
1219 * reference element label has to have the same label OID as the one being
1220 * checked but a different element OID.
1221 */
1222 ScanKeyInit(&key[0],
1225 F_OIDEQ, ObjectIdGetDatum(labelid));
1227 while (HeapTupleIsValid(tuple = systable_getnext(scan)))
1228 {
1230
1231 if (otherellabel->oid != ellabeloid)
1232 {
1234 break;
1235 }
1236 }
1237 systable_endscan(scan);
1238
1240
1241 /*
1242 * If there is no previous definition of this label, then we are done.
1243 */
1244 if (!ref_ellabeloid)
1245 return;
1246
1247 /*
1248 * Now check number and names.
1249 *
1250 * XXX We could provide more detail in the error messages, but that would
1251 * probably only be useful for some ALTER commands, because otherwise it's
1252 * not really clear which label definition is the wrong one, and so you'd
1253 * have to construct a rather verbose report to be of any use. Let's keep
1254 * it simple for now.
1255 */
1256
1259
1261 ereport(ERROR,
1263 errmsg("mismatching number of properties in definition of label \"%s\"", get_propgraph_label_name(labelid)));
1264
1267
1268 if (diff1 || diff2)
1269 ereport(ERROR,
1271 errmsg("mismatching property names in definition of label \"%s\"", get_propgraph_label_name(labelid)));
1272}
1273
1274/*
1275 * As above, but check all labels of a graph.
1276 */
1277static void
1288
1289/*
1290 * ALTER PROPERTY GRAPH
1291 */
1294{
1295 Oid pgrelid;
1296 ListCell *lc;
1298
1299 /*
1300 * ShareRowExclusiveLock is required because this command runs some
1301 * graph-wide consistency checks that wouldn't work if more than one ALTER
1302 * PROPERTY GRAPH could operate on the same graph at once.
1303 */
1306 stmt->missing_ok ? RVR_MISSING_OK : 0,
1308 NULL);
1309 if (pgrelid == InvalidOid)
1310 {
1312 (errmsg("relation \"%s\" does not exist, skipping",
1313 stmt->pgname->relname)));
1314 return InvalidObjectAddress;
1315 }
1316
1318
1319 foreach(lc, stmt->add_vertex_tables)
1320 {
1322 struct element_info *vinfo;
1323 Relation rel;
1324 Oid peoid;
1325
1327 vinfo->kind = PGEKIND_VERTEX;
1328
1330
1331 rel = table_open(vinfo->relid, NoLock);
1332
1334 ereport(ERROR,
1336 errmsg("cannot add temporary element table to non-temporary property graph"),
1337 errdetail("Table \"%s\" is a temporary table.", get_rel_name(vinfo->relid)),
1338 parser_errposition(pstate, vertex->vtable->location)));
1339
1340 if (vertex->vtable->alias)
1341 vinfo->aliasname = vertex->vtable->alias->aliasname;
1342 else
1343 vinfo->aliasname = vertex->vtable->relname;
1344
1345 vinfo->key = propgraph_element_get_key(pstate, vertex->vkey, rel, vinfo->aliasname, vertex->location);
1346
1347 vinfo->labels = vertex->labels;
1348
1349 table_close(rel, NoLock);
1350
1353 CStringGetDatum(vinfo->aliasname)))
1354 ereport(ERROR,
1356 errmsg("alias \"%s\" already exists in property graph \"%s\"",
1357 vinfo->aliasname, stmt->pgname->relname),
1358 parser_errposition(pstate, vertex->vtable->location));
1359
1361
1365 }
1366
1367 foreach(lc, stmt->add_edge_tables)
1368 {
1370 struct element_info *einfo;
1371 Relation rel;
1374 Oid peoid;
1375
1377 einfo->kind = PGEKIND_EDGE;
1378
1380
1381 rel = table_open(einfo->relid, NoLock);
1382
1384 ereport(ERROR,
1386 errmsg("cannot add temporary element table to non-temporary property graph"),
1387 errdetail("Table \"%s\" is a temporary table.", get_rel_name(einfo->relid)),
1388 parser_errposition(pstate, edge->etable->location)));
1389
1390 if (edge->etable->alias)
1391 einfo->aliasname = edge->etable->alias->aliasname;
1392 else
1393 einfo->aliasname = edge->etable->relname;
1394
1395 einfo->key = propgraph_element_get_key(pstate, edge->ekey, rel, einfo->aliasname, edge->location);
1396
1397 einfo->srcvertexid = get_vertex_oid(pstate, pgrelid, edge->esrcvertex, edge->location);
1398 einfo->destvertexid = get_vertex_oid(pstate, pgrelid, edge->edestvertex, edge->location);
1399
1400 einfo->srcrelid = get_element_relid(einfo->srcvertexid);
1401 einfo->destrelid = get_element_relid(einfo->destvertexid);
1402
1403 srcrel = table_open(einfo->srcrelid, AccessShareLock);
1404 destrel = table_open(einfo->destrelid, AccessShareLock);
1405
1406 propgraph_edge_get_ref_keys(pstate, edge->esrckey, edge->esrcvertexcols, rel, srcrel,
1407 einfo->aliasname, edge->location, "SOURCE",
1408 &einfo->srckey, &einfo->srcref, &einfo->srceqop);
1409 propgraph_edge_get_ref_keys(pstate, edge->edestkey, edge->edestvertexcols, rel, destrel,
1410 einfo->aliasname, edge->location, "DESTINATION",
1411 &einfo->destkey, &einfo->destref, &einfo->desteqop);
1412
1413 einfo->labels = edge->labels;
1414
1417
1418 table_close(rel, NoLock);
1419
1422 CStringGetDatum(einfo->aliasname)))
1423 ereport(ERROR,
1425 errmsg("alias \"%s\" already exists in property graph \"%s\"",
1426 einfo->aliasname, stmt->pgname->relname),
1427 parser_errposition(pstate, edge->etable->location));
1428
1430
1434 }
1435
1436 foreach(lc, stmt->drop_vertex_tables)
1437 {
1438 char *alias = strVal(lfirst(lc));
1439 Oid peoid;
1440 ObjectAddress obj;
1441
1442 peoid = get_vertex_oid(pstate, pgrelid, alias, -1);
1444 performDeletion(&obj, stmt->drop_behavior, 0);
1445 }
1446
1447 foreach(lc, stmt->drop_edge_tables)
1448 {
1449 char *alias = strVal(lfirst(lc));
1450 Oid peoid;
1451 ObjectAddress obj;
1452
1453 peoid = get_edge_oid(pstate, pgrelid, alias, -1);
1455 performDeletion(&obj, stmt->drop_behavior, 0);
1456 }
1457
1458 /* Remove any orphaned pg_propgraph_label entries */
1459 if (stmt->drop_vertex_tables || stmt->drop_edge_tables)
1460 {
1462 {
1464 {
1465 ObjectAddress obj;
1466
1468 performDeletion(&obj, stmt->drop_behavior, 0);
1469 }
1470 }
1471 }
1472
1473 foreach(lc, stmt->add_labels)
1474 {
1476 Oid peoid;
1477 Oid pgerelid;
1479
1480 Assert(lp->label);
1481
1482 if (stmt->element_kind == PROPGRAPH_ELEMENT_KIND_VERTEX)
1483 peoid = get_vertex_oid(pstate, pgrelid, stmt->element_alias, -1);
1484 else
1485 peoid = get_edge_oid(pstate, pgrelid, stmt->element_alias, -1);
1486
1488
1491
1495 }
1496
1497 if (stmt->drop_label)
1498 {
1499 Oid peoid;
1500 Oid labeloid;
1502 ObjectAddress obj;
1506 int nlabels;
1507 HeapTuple tuple;
1508
1509 if (stmt->element_kind == PROPGRAPH_ELEMENT_KIND_VERTEX)
1510 peoid = get_vertex_oid(pstate, pgrelid, stmt->element_alias, -1);
1511 else
1512 peoid = get_edge_oid(pstate, pgrelid, stmt->element_alias, -1);
1513
1517 CStringGetDatum(stmt->drop_label));
1518 if (!labeloid)
1519 ereport(ERROR,
1521 errmsg("property graph \"%s\" element \"%s\" has no label \"%s\"",
1522 get_rel_name(pgrelid), stmt->element_alias, stmt->drop_label),
1523 parser_errposition(pstate, -1));
1524
1525 /*
1526 * Is the given label associated with the element? Is this the only
1527 * label associated with the element? Scan the
1528 * pg_propgraph_element_label table to find answers to these
1529 * questions. Stop scanning when we know both answers.
1530 */
1537 true, NULL, 1, ellabelkey);
1538 nlabels = 0;
1540 {
1542
1543 nlabels++;
1544
1545 if (ellabelform->pgellabelid == labeloid)
1546 ellabeloid = ellabelform->oid;
1547
1548 if (nlabels > 1 && ellabeloid)
1549 break;
1550 }
1553
1554 if (!ellabeloid)
1555 ereport(ERROR,
1557 errmsg("property graph \"%s\" element \"%s\" has no label \"%s\"",
1558 get_rel_name(pgrelid), stmt->element_alias, stmt->drop_label),
1559 parser_errposition(pstate, -1));
1560
1561 /*
1562 * Prevent dropping the last label from an element. Every element must
1563 * have at least one label associated with it.
1564 */
1565 if (nlabels == 1)
1566 ereport(ERROR,
1568 errmsg("cannot drop the last label from element \"%s\"",
1569 stmt->element_alias),
1570 errhint("Every element must have at least one label.")));
1571
1573 performDeletion(&obj, stmt->drop_behavior, 0);
1574
1575 /* Remove any orphaned pg_propgraph_label entries */
1577 {
1579 performDeletion(&obj, stmt->drop_behavior, 0);
1580 }
1581 }
1582
1583 if (stmt->add_properties)
1584 {
1585 Oid peoid;
1586 Oid pgerelid;
1587 Oid labeloid;
1589
1590 if (stmt->element_kind == PROPGRAPH_ELEMENT_KIND_VERTEX)
1591 peoid = get_vertex_oid(pstate, pgrelid, stmt->element_alias, -1);
1592 else
1593 peoid = get_edge_oid(pstate, pgrelid, stmt->element_alias, -1);
1594
1598 CStringGetDatum(stmt->alter_label));
1599 if (labeloid)
1604 if (!ellabeloid)
1605 ereport(ERROR,
1607 errmsg("property graph \"%s\" element \"%s\" has no label \"%s\"",
1608 get_rel_name(pgrelid), stmt->element_alias, stmt->alter_label),
1609 parser_errposition(pstate, -1));
1610
1612
1614
1618 }
1619
1620 if (stmt->drop_properties)
1621 {
1622 Oid peoid;
1623 Oid labeloid;
1625 ObjectAddress obj;
1626
1627 if (stmt->element_kind == PROPGRAPH_ELEMENT_KIND_VERTEX)
1628 peoid = get_vertex_oid(pstate, pgrelid, stmt->element_alias, -1);
1629 else
1630 peoid = get_edge_oid(pstate, pgrelid, stmt->element_alias, -1);
1631
1635 CStringGetDatum(stmt->alter_label));
1636 if (labeloid)
1641
1642 if (!ellabeloid)
1643 ereport(ERROR,
1645 errmsg("property graph \"%s\" element \"%s\" has no label \"%s\"",
1646 get_rel_name(pgrelid), stmt->element_alias, stmt->alter_label),
1647 parser_errposition(pstate, -1));
1648
1649 foreach(lc, stmt->drop_properties)
1650 {
1651 char *propname = strVal(lfirst(lc));
1652 Oid propoid;
1654
1659 if (propoid)
1664 if (!plpoid)
1665 ereport(ERROR,
1667 errmsg("property graph \"%s\" element \"%s\" label \"%s\" has no property \"%s\"",
1668 get_rel_name(pgrelid), stmt->element_alias, stmt->alter_label, propname),
1669 parser_errposition(pstate, -1));
1670
1672 performDeletion(&obj, stmt->drop_behavior, 0);
1673 }
1674
1676 }
1677
1678 /* Remove any orphaned pg_propgraph_property entries */
1679 if (stmt->drop_properties || stmt->drop_vertex_tables || stmt->drop_edge_tables || stmt->drop_label)
1680 {
1682 {
1683 Relation rel;
1684 SysScanDesc scan;
1685 ScanKeyData key[1];
1686
1688 ScanKeyInit(&key[0],
1692 /* XXX no suitable index */
1693 scan = systable_beginscan(rel, InvalidOid, true, NULL, 1, key);
1694 if (!systable_getnext(scan))
1695 {
1696 ObjectAddress obj;
1697
1699 performDeletion(&obj, stmt->drop_behavior, 0);
1700 }
1701
1702 systable_endscan(scan);
1704 }
1705 }
1706
1707 /*
1708 * Invalidate relcache entry of the property graph so that the queries in
1709 * the cached plans referencing the property graph will be rewritten
1710 * considering changes to the property graph.
1711 */
1713
1714 return pgaddress;
1715}
1716
1717/*
1718 * Get OID of vertex from graph OID and element alias. Element must be a
1719 * vertex, otherwise error.
1720 */
1721static Oid
1722get_vertex_oid(ParseState *pstate, Oid pgrelid, const char *alias, int location)
1723{
1724 HeapTuple tuple;
1725 Oid peoid;
1726
1728 if (!tuple)
1729 ereport(ERROR,
1731 errmsg("property graph \"%s\" has no element with alias \"%s\"",
1732 get_rel_name(pgrelid), alias),
1733 parser_errposition(pstate, location));
1734
1736 ereport(ERROR,
1738 errmsg("element \"%s\" of property graph \"%s\" is not a vertex",
1739 alias, get_rel_name(pgrelid)),
1740 parser_errposition(pstate, location));
1741
1742 peoid = ((Form_pg_propgraph_element) GETSTRUCT(tuple))->oid;
1743
1744 ReleaseSysCache(tuple);
1745
1746 return peoid;
1747}
1748
1749/*
1750 * Get OID of edge from graph OID and element alias. Element must be an edge,
1751 * otherwise error.
1752 */
1753static Oid
1754get_edge_oid(ParseState *pstate, Oid pgrelid, const char *alias, int location)
1755{
1756 HeapTuple tuple;
1757 Oid peoid;
1758
1760 if (!tuple)
1761 ereport(ERROR,
1763 errmsg("property graph \"%s\" has no element with alias \"%s\"",
1764 get_rel_name(pgrelid), alias),
1765 parser_errposition(pstate, location));
1766
1768 ereport(ERROR,
1770 errmsg("element \"%s\" of property graph \"%s\" is not an edge",
1771 alias, get_rel_name(pgrelid)),
1772 parser_errposition(pstate, location));
1773
1774 peoid = ((Form_pg_propgraph_element) GETSTRUCT(tuple))->oid;
1775
1776 ReleaseSysCache(tuple);
1777
1778 return peoid;
1779}
1780
1781/*
1782 * Get the element table relation OID from the OID of the element.
1783 */
1784static Oid
1786{
1787 HeapTuple tuple;
1788 Oid pgerelid;
1789
1791 if (!tuple)
1792 elog(ERROR, "cache lookup failed for property graph element %u", peid);
1793
1795
1796 ReleaseSysCache(tuple);
1797
1798 return pgerelid;
1799}
1800
1801/*
1802 * Get a list of all label OIDs of a graph.
1803 */
1804static List *
1806{
1807 Relation rel;
1808 SysScanDesc scan;
1809 ScanKeyData key[1];
1810 HeapTuple tuple;
1811 List *result = NIL;
1812
1814 ScanKeyInit(&key[0],
1817 F_OIDEQ, ObjectIdGetDatum(graphid));
1819 while (HeapTupleIsValid(tuple = systable_getnext(scan)))
1820 {
1822 }
1823 systable_endscan(scan);
1825
1826 return result;
1827}
1828
1829/*
1830 * Get a list of all element label OIDs for a label.
1831 */
1832static List *
1834{
1835 Relation rel;
1836 SysScanDesc scan;
1837 ScanKeyData key[1];
1838 HeapTuple tuple;
1839 List *result = NIL;
1840
1842 ScanKeyInit(&key[0],
1845 F_OIDEQ, ObjectIdGetDatum(labelid));
1847 while (HeapTupleIsValid(tuple = systable_getnext(scan)))
1848 {
1850 }
1851 systable_endscan(scan);
1853
1854 return result;
1855}
1856
1857/*
1858 * Get the names of properties associated with the given element label OID.
1859 *
1860 * The result is a list of String nodes (so we can use list functions to
1861 * detect differences).
1862 */
1863static List *
1893
1894/*
1895 * Get a list of all property OIDs of a graph.
1896 */
1897static List *
1899{
1900 Relation rel;
1901 SysScanDesc scan;
1902 ScanKeyData key[1];
1903 HeapTuple tuple;
1904 List *result = NIL;
1905
1907 ScanKeyInit(&key[0],
1910 F_OIDEQ, ObjectIdGetDatum(graphid));
1912 while (HeapTupleIsValid(tuple = systable_getnext(scan)))
1913 {
1915 }
1916 systable_endscan(scan);
1918
1919 return result;
1920}
ArrayType * construct_array_builtin(Datum *elems, int nelems, Oid elmtype)
void deconstruct_array_builtin(const ArrayType *array, Oid elmtype, Datum **elemsp, bool **nullsp, int *nelemsp)
int16 AttrNumber
Definition attnum.h:21
static Datum values[MAXATTR]
Definition bootstrap.c:190
#define CStringGetTextDatum(s)
Definition builtins.h:98
#define TextDatumGetCString(d)
Definition builtins.h:99
#define NameStr(name)
Definition c.h:894
#define Assert(condition)
Definition c.h:1002
int32_t int32
Definition c.h:679
#define OidIsValid(objectId)
Definition c.h:917
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition catalog.c:475
uint32 result
void record_object_address_dependencies(const ObjectAddress *depender, ObjectAddresses *referenced, DependencyType behavior)
void performDeletion(const ObjectAddress *object, DropBehavior behavior, int flags)
Definition dependency.c:279
void recordDependencyOnSingleRelExpr(const ObjectAddress *depender, Node *expr, Oid relId, DependencyType behavior, DependencyType self_behavior, bool reverse_self)
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
ObjectAddresses * new_object_addresses(void)
@ DEPENDENCY_AUTO
Definition dependency.h:34
@ DEPENDENCY_NORMAL
Definition dependency.h:33
int errcode(int sqlerrcode)
Definition elog.c:875
int errhint(const char *fmt,...) pg_attribute_printf(1
int errdetail(const char *fmt,...) pg_attribute_printf(1
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228
#define NOTICE
Definition elog.h:36
#define ereport(elevel,...)
Definition elog.h:152
bool equal(const void *a, const void *b)
Definition equalfuncs.c:223
#define palloc_array(type, count)
Definition fe_memutils.h:91
#define palloc0_object(type)
Definition fe_memutils.h:90
char * format_type_with_typemod(Oid type_oid, int32 typemod)
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
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition heaptuple.c:1025
void heap_freetuple(HeapTuple htup)
Definition heaptuple.c:1372
#define HeapTupleIsValid(tuple)
Definition htup.h:78
static Datum heap_getattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
static void * GETSTRUCT(const HeapTupleData *tuple)
#define stmt
void index_close(Relation relation, LOCKMODE lockmode)
Definition indexam.c:178
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition indexam.c:134
Oid GetDefaultOpClass(Oid type_id, Oid am_id)
Definition indexcmds.c:2381
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition indexing.c:233
void CacheInvalidateRelcacheByRelid(Oid relid)
Definition inval.c:1688
int a
Definition isn.c:73
int j
Definition isn.c:78
int i
Definition isn.c:77
List * list_difference(const List *list1, const List *list2)
Definition list.c:1237
List * lappend(List *list, void *datum)
Definition list.c:339
List * lappend_oid(List *list, Oid datum)
Definition list.c:375
bool list_member(const List *list, const void *datum)
Definition list.c:661
#define NoLock
Definition lockdefs.h:34
#define ShareRowExclusiveLock
Definition lockdefs.h:41
#define AccessShareLock
Definition lockdefs.h:36
#define RowShareLock
Definition lockdefs.h:37
#define RowExclusiveLock
Definition lockdefs.h:38
char * get_rel_name(Oid relid)
Definition lsyscache.c:2242
char * get_propgraph_property_name(Oid propoid)
Definition lsyscache.c:4098
char get_rel_persistence(Oid relid)
Definition lsyscache.c:2392
AttrNumber get_attnum(Oid relid, const char *attname)
Definition lsyscache.c:1084
Oid get_opclass_family(Oid opclass)
Definition lsyscache.c:1442
char * get_collation_name(Oid colloid)
Definition lsyscache.c:1261
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition lsyscache.c:170
char * get_propgraph_label_name(Oid labeloid)
Definition lsyscache.c:4080
void get_atttypetypmodcoll(Oid relid, AttrNumber attnum, Oid *typid, int32 *typmod, Oid *collid)
Definition lsyscache.c:1169
char * pstrdup(const char *in)
Definition mcxt.c:1910
void namestrcpy(Name name, const char *str)
Definition name.c:233
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition namespace.c:442
@ RVR_MISSING_OK
Definition namespace.h:90
Oid exprType(const Node *expr)
Definition nodeFuncs.c:42
int32 exprTypmod(const Node *expr)
Definition nodeFuncs.c:304
Oid exprCollation(const Node *expr)
Definition nodeFuncs.c:826
#define IsA(nodeptr, _type_)
Definition nodes.h:162
#define copyObject(obj)
Definition nodes.h:230
#define makeNode(_type_)
Definition nodes.h:159
static char * errmsg
const ObjectAddress InvalidObjectAddress
#define ObjectAddressSet(addr, class_id, object_id)
#define ObjectAddressSubSet(addr, class_id, object_id, object_sub_id)
char * nodeToString(const void *obj)
Definition outfuncs.c:811
bool can_coerce_type(int nargs, const Oid *input_typeids, const Oid *target_typeids, CoercionContext ccontext)
void assign_expr_collations(ParseState *pstate, Node *expr)
int parser_errposition(ParseState *pstate, int location)
Definition parse_node.c:106
ParseState * make_parsestate(ParseState *parentParseState)
Definition parse_node.c:39
@ EXPR_KIND_PROPGRAPH_PROPERTY
Definition parse_node.h:86
void addNSItemToQuery(ParseState *pstate, ParseNamespaceItem *nsitem, bool addToJoinList, bool addToRelNameSpace, bool addToVarNameSpace)
ParseNamespaceItem * addRangeTableEntryForRelation(ParseState *pstate, Relation rel, LOCKMODE lockmode, Alias *alias, bool inh, bool inFromCl)
List * transformTargetList(ParseState *pstate, List *targetlist, ParseExprKind exprKind)
void resolveTargetListUnknowns(ParseState *pstate, List *targetlist)
@ PROPGRAPH_ELEMENT_KIND_VERTEX
int16 attnum
FormData_pg_attribute * Form_pg_attribute
static char * label
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition pg_depend.c:51
#define lfirst(lc)
Definition pg_list.h:172
#define lfirst_node(type, lc)
Definition pg_list.h:176
static int list_length(const List *l)
Definition pg_list.h:152
#define NIL
Definition pg_list.h:68
#define forboth(cell1, list1, cell2, list2)
Definition pg_list.h:550
#define list_make1(x1)
Definition pg_list.h:244
#define foreach_node(type, var, lst)
Definition pg_list.h:528
#define foreach_oid(var, lst)
Definition pg_list.h:503
#define lfirst_oid(lc)
Definition pg_list.h:174
END_CATALOG_STRUCT typedef FormData_pg_propgraph_element * Form_pg_propgraph_element
END_CATALOG_STRUCT typedef FormData_pg_propgraph_element_label * Form_pg_propgraph_element_label
END_CATALOG_STRUCT typedef FormData_pg_propgraph_label * Form_pg_propgraph_label
END_CATALOG_STRUCT typedef FormData_pg_propgraph_label_property * Form_pg_propgraph_label_property
END_CATALOG_STRUCT typedef FormData_pg_propgraph_property * Form_pg_propgraph_property
static Oid DatumGetObjectId(Datum X)
Definition postgres.h:242
static Datum Int16GetDatum(int16 X)
Definition postgres.h:172
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:252
static Datum NameGetDatum(const NameData *X)
Definition postgres.h:406
uint64_t Datum
Definition postgres.h:70
static Datum CStringGetDatum(const char *X)
Definition postgres.h:383
static Datum Int32GetDatum(int32 X)
Definition postgres.h:212
static int16 DatumGetInt16(Datum X)
Definition postgres.h:162
#define PointerGetDatum(X)
Definition postgres.h:354
static Datum CharGetDatum(char X)
Definition postgres.h:132
#define InvalidOid
unsigned int Oid
static int fb(int x)
@ ONCOMMIT_NOOP
Definition primnodes.h:59
@ COERCION_IMPLICIT
Definition primnodes.h:737
static void insert_property_record(Oid graphid, Oid ellabeloid, Oid pgerelid, const char *propname, const Expr *expr)
static void check_all_labels_properties(Oid pgrelid)
static Oid get_edge_oid(ParseState *pstate, Oid pgrelid, const char *alias, int location)
static Oid get_element_relid(Oid peid)
static AttrNumber * array_from_column_list(ParseState *pstate, const List *colnames, int location, Relation element_rel)
static Oid get_vertex_oid(ParseState *pstate, Oid pgrelid, const char *alias, int location)
static void insert_property_records(Oid graphid, Oid ellabeloid, Oid pgerelid, const PropGraphProperties *properties)
ObjectAddress AlterPropGraph(ParseState *pstate, const AlterPropGraphStmt *stmt)
static Oid insert_label_record(Oid graphid, Oid peoid, const char *label)
static void check_element_label_properties(Oid ellabeloid)
static List * get_element_label_property_names(Oid ellabeloid)
static List * get_graph_label_ids(Oid graphid)
ObjectAddress CreatePropGraph(ParseState *pstate, const CreatePropGraphStmt *stmt)
static Oid insert_element_record(ObjectAddress pgaddress, struct element_info *einfo)
static List * get_label_element_label_ids(Oid labelid)
static ArrayType * array_from_attnums(int numattrs, const AttrNumber *attnums)
static List * get_graph_property_ids(Oid graphid)
static void array_of_opers_to_objectaddrs(ArrayType *arr, ObjectAddresses *addrs)
static void check_element_properties(Oid peoid)
static ArrayType * propgraph_element_get_key(ParseState *pstate, const List *key_clause, Relation element_rel, const char *aliasname, int location)
static void array_of_attnums_to_objectaddrs(Oid relid, ArrayType *arr, ObjectAddresses *addrs)
static void propgraph_edge_get_ref_keys(ParseState *pstate, const List *keycols, const List *refcols, Relation edge_rel, Relation ref_rel, const char *aliasname, int location, const char *type, ArrayType **outkey, ArrayType **outref, ArrayType **outeqop)
void * stringToNode(const char *str)
Definition read.c:90
#define RelationGetRelid(relation)
Definition rel.h:516
#define RelationGetDescr(relation)
Definition rel.h:542
Oid RelationGetPrimaryKeyIndex(Relation relation, bool deferrable_ok)
Definition relcache.c:5059
List * RelationGetFKeyList(Relation relation)
Definition relcache.c:4743
List * deparse_context_for(const char *aliasname, Oid relid)
Definition ruleutils.c:4072
char * deparse_expression(Node *expr, List *dpcontext, bool forceprefix, bool showimplicit)
Definition ruleutils.c:4009
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition scankey.c:76
uint16 StrategyNumber
Definition stratnum.h:22
#define HTEqualStrategyNumber
Definition stratnum.h:41
#define BTEqualStrategyNumber
Definition stratnum.h:31
Definition pg_list.h:54
Definition nodes.h:133
bool p_resolve_unknowns
Definition parse_node.h:238
Form_pg_class rd_rel
Definition rel.h:111
Expr * expr
Definition primnodes.h:2261
ArrayType * destref
ArrayType * srckey
ArrayType * desteqop
ArrayType * srceqop
char * destvertex
ArrayType * key
ArrayType * destkey
ArrayType * srcref
Definition c.h:889
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:265
HeapTuple SearchSysCache2(SysCacheIdentifier cacheId, Datum key1, Datum key2)
Definition syscache.c:231
HeapTuple SearchSysCache1(SysCacheIdentifier cacheId, Datum key1)
Definition syscache.c:221
#define SearchSysCacheExists2(cacheId, key1, key2)
Definition syscache.h:102
#define GetSysCacheOid2(cacheId, oidcol, key1, key2)
Definition syscache.h:111
void table_close(Relation relation, LOCKMODE lockmode)
Definition table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition table.c:40
ObjectAddress DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, ObjectAddress *typaddress, const char *queryString)
Definition tablecmds.c:818
void RangeVarCallbackOwnsRelation(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
String * makeString(char *str)
Definition value.c:63
#define strVal(v)
Definition value.h:82
const char * type
void CommandCounterIncrement(void)
Definition xact.c:1130