/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include "postgres.h" #include "access/genam.h" #include "access/heapam.h" #include "access/htup.h" #include "access/htup_details.h" #include "access/skey.h" #include "access/stratnum.h" #include "catalog/indexing.h" #include "catalog/namespace.h" #include "fmgr.h" #include "nodes/execnodes.h" #include "nodes/makefuncs.h" #include "storage/lockdefs.h" #include "utils/builtins.h" #include "utils/fmgroids.h" #include "utils/lsyscache.h" #include "utils/rel.h" #include "utils/relcache.h" #include "catalog/ag_graph.h" #include "catalog/ag_label.h" #include "commands/label_commands.h" #include "executor/cypher_utils.h" #include "utils/ag_cache.h" #include "utils/graphid.h" #include "pg_fix.h" /* * INSERT INTO ag_catalog.ag_label * VALUES (label_name, label_graph, label_id, label_kind, * label_relation, seq_name) */ void insert_label(const char *label_name, Oid graph_oid, int32 label_id, char label_kind, Oid label_relation, const char *seq_name) { NameData label_name_data; NameData seq_name_data; Datum values[Natts_ag_label]; bool nulls[Natts_ag_label]; Relation ag_label; HeapTuple tuple; /* * NOTE: Is it better to make use of label_id and label_kind domain types * than to use assert to check label_id and label_kind are valid? */ AssertArg(label_name); AssertArg(label_id_is_valid(label_id)); AssertArg(label_kind == LABEL_KIND_VERTEX || label_kind == LABEL_KIND_EDGE); AssertArg(OidIsValid(label_relation)); AssertArg(seq_name); ag_label = table_open(ag_label_relation_id(), RowExclusiveLock); namestrcpy(&label_name_data, label_name); values[Anum_ag_label_name - 1] = NameGetDatum(&label_name_data); nulls[Anum_ag_label_name - 1] = false; values[Anum_ag_label_graph - 1] = ObjectIdGetDatum(graph_oid); nulls[Anum_ag_label_graph - 1] = false; values[Anum_ag_label_id - 1] = Int32GetDatum(label_id); nulls[Anum_ag_label_id - 1] = false; values[Anum_ag_label_kind - 1] = CharGetDatum(label_kind); nulls[Anum_ag_label_kind - 1] = false; values[Anum_ag_label_relation - 1] = ObjectIdGetDatum(label_relation); nulls[Anum_ag_label_relation - 1] = false; namestrcpy(&seq_name_data, seq_name); values[Anum_ag_label_seq_name - 1] = NameGetDatum(&seq_name_data); nulls[Anum_ag_label_seq_name - 1] = false; tuple = heap_form_tuple(RelationGetDescr(ag_label), values, nulls); /* * CatalogTupleInsert() is originally for PostgreSQL's catalog. However, * it is used at here for convenience. */ CatalogTupleInsert(ag_label, tuple); table_close(ag_label, RowExclusiveLock); } // DELETE FROM ag_catalog.ag_label WHERE relation = relation void delete_label(Oid relation) { ScanKeyData scan_keys[1]; Relation ag_label; SysScanDesc scan_desc; HeapTuple tuple; ScanKeyInit(&scan_keys[0], Anum_ag_label_relation, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(relation)); ag_label = table_open(ag_label_relation_id(), RowExclusiveLock); scan_desc = systable_beginscan(ag_label, ag_label_relation_index_id(), true, NULL, 1, scan_keys); tuple = systable_getnext(scan_desc); if (!HeapTupleIsValid(tuple)) { ereport(ERROR, (errcode(ERRCODE_UNDEFINED_TABLE), errmsg("label (relation=%u) does not exist", relation))); } CatalogTupleDelete(ag_label, &tuple->t_self); systable_endscan(scan_desc); table_close(ag_label, RowExclusiveLock); } int32 get_label_id(const char *label_name, Oid graph_oid) { label_cache_data *cache_data; cache_data = search_label_name_graph_cache(label_name, graph_oid); if (cache_data) return cache_data->id; else return INVALID_LABEL_ID; } Oid get_label_relation(const char *label_name, Oid graph_oid) { label_cache_data *cache_data; cache_data = search_label_name_graph_cache(label_name, graph_oid); if (cache_data) return cache_data->relation; else return InvalidOid; } char *get_label_relation_name(const char *label_name, Oid graph_oid) { return get_rel_name(get_label_relation(label_name, graph_oid)); } char get_label_kind(const char *label_name, Oid label_graph) { label_cache_data *cache_data; cache_data = search_label_name_graph_cache(label_name, label_graph); if (cache_data) { return cache_data->kind; } else { return INVALID_LABEL_ID; } } PG_FUNCTION_INFO_V1(_label_name); /* * Using the graph name and the vertex/edge's graphid, find * the correct label name from ag_catalog.label */ Datum _label_name(PG_FUNCTION_ARGS) { char *label_name; label_cache_data *label_cache; Oid graph; uint32 label_id; if (PG_ARGISNULL(0) || PG_ARGISNULL(1)) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("graph_oid and label_id must not be null"))); graph = PG_GETARG_OID(0); label_id = (int32)(((uint64)AG_GETARG_GRAPHID(1)) >> ENTRY_ID_BITS); label_cache = search_label_graph_oid_cache(graph, label_id); label_name = NameStr(label_cache->name); if (IS_AG_DEFAULT_LABEL(label_name)) PG_RETURN_CSTRING(""); PG_RETURN_CSTRING(label_name); } PG_FUNCTION_INFO_V1(_label_id); Datum _label_id(PG_FUNCTION_ARGS) { Name graph_name; Name label_name; Oid graph; int32 id; if (PG_ARGISNULL(0) || PG_ARGISNULL(1)) { ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("graph_name and label_name must not be null"))); } graph_name = PG_GETARG_NAME(0); label_name = PG_GETARG_NAME(1); graph = get_graph_oid(NameStr(*graph_name)); id = get_label_id(NameStr(*label_name), graph); PG_RETURN_INT32(id); } PG_FUNCTION_INFO_V1(_extract_label_id); Datum _extract_label_id(PG_FUNCTION_ARGS) { graphid graph_oid; if (PG_ARGISNULL(0)) { ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("graph_oid must not be null"))); } graph_oid = AG_GETARG_GRAPHID(0); PG_RETURN_INT32(get_graphid_label_id(graph_oid)); } bool label_id_exists(Oid graph_oid, int32 label_id) { label_cache_data *cache_data; cache_data = search_label_graph_oid_cache(graph_oid, label_id); if (cache_data) return true; else return false; } /* * Creates A RangeVar for the given label. */ RangeVar *get_label_range_var(char *graph_name, Oid graph_oid, char *label_name) { char *relname; label_cache_data *label_cache; label_cache = search_label_name_graph_cache(label_name, graph_oid); relname = get_rel_name(label_cache->relation); return makeRangeVar(graph_name, relname, 2); } /* * Retrieves a list of all the names of a graph. * * XXX: We may want to use the cache system for this function, * however the cache system currently requires us to know the * name of the label we want. */ List *get_all_edge_labels_per_graph(EState *estate, Oid graph_oid) { List *labels = NIL; ScanKeyData scan_keys[2]; Relation ag_label; TableScanDesc scan_desc; HeapTuple tuple; TupleTableSlot *slot; ResultRelInfo *resultRelInfo; // setup scan keys to get all edges for the given graph oid ScanKeyInit(&scan_keys[1], Anum_ag_label_graph, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(graph_oid)); ScanKeyInit(&scan_keys[0], Anum_ag_label_kind, BTEqualStrategyNumber, F_CHAREQ, CharGetDatum(LABEL_TYPE_EDGE)); // setup the table to be scanned ag_label = table_open(ag_label_relation_id(), RowExclusiveLock); scan_desc = table_beginscan(ag_label, estate->es_snapshot, 2, scan_keys); resultRelInfo = create_entity_result_rel_info(estate, "ag_catalog", "ag_label"); slot = ExecInitExtraTupleSlot( estate, RelationGetDescr(resultRelInfo->ri_RelationDesc), &TTSOpsHeapTuple); // scan through the results and get all the label names. while(true) { Name label; bool isNull; Datum datum; tuple = heap_getnext(scan_desc, ForwardScanDirection); // no more labels to process if (!HeapTupleIsValid(tuple)) break; ExecStoreHeapTuple(tuple, slot, false); datum = slot_getattr(slot, Anum_ag_label_name, &isNull); label = DatumGetName(datum); labels = lappend(labels, label); } table_endscan(scan_desc); destroy_entity_result_rel_info(resultRelInfo); table_close(resultRelInfo->ri_RelationDesc, RowExclusiveLock); return labels; }