Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 84 additions & 25 deletions src/backend/catalog/ag_label.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

#include "access/genam.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
#include "executor/executor.h"
#include "nodes/makefuncs.h"
#include "utils/builtins.h"
Expand Down Expand Up @@ -297,46 +298,104 @@ List *get_all_edge_labels_per_graph(EState *estate, Oid graph_oid)
HeapTuple tuple;
TupleTableSlot *slot;
ResultRelInfo *resultRelInfo;
Oid index_oid;

/* 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));
index_oid = get_relname_relid("ag_label_graph_oid_index",
get_namespace_oid("ag_catalog", false));

/* 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");

Comment on lines +304 to 310
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function opens ag_label via table_open(...) but later closes resultRelInfo->ri_RelationDesc instead of the ag_label relation it opened. This double-open pattern is easy to get wrong and risks leaking a relation reference/lock if the descriptors are not the same instance. Prefer using a single relation handle throughout (e.g., use resultRelInfo->ri_RelationDesc for scanning and close that, or explicitly close ag_label if it remains separately opened).

Suggested change
ag_label = table_open(ag_label_relation_id(), AccessShareLock);
index_oid = find_usable_index_for_attr(ag_label, Anum_ag_label_graph);
resultRelInfo = create_entity_result_rel_info(estate, "ag_catalog",
"ag_label");
resultRelInfo = create_entity_result_rel_info(estate, "ag_catalog",
"ag_label");
ag_label = resultRelInfo->ri_RelationDesc;
index_oid = find_usable_index_for_attr(ag_label, Anum_ag_label_graph);

Copilot uses AI. Check for mistakes.
slot = ExecInitExtraTupleSlot(
estate, RelationGetDescr(resultRelInfo->ri_RelationDesc),
&TTSOpsHeapTuple);

/* scan through the results and get all the label names. */
while(true)
if (OidIsValid(index_oid))
{
Relation index_rel;
IndexScanDesc index_scan_desc;

slot = ExecInitExtraTupleSlot(
estate, RelationGetDescr(resultRelInfo->ri_RelationDesc),
&TTSOpsBufferHeapTuple);

index_rel = index_open(index_oid, RowExclusiveLock);

ScanKeyInit(&scan_keys[0], Anum_ag_label_name, BTEqualStrategyNumber,
F_OIDEQ, ObjectIdGetDatum(graph_oid));

index_scan_desc = index_beginscan(ag_label, index_rel, estate->es_snapshot, NULL, 1, 0);
index_rescan(index_scan_desc, scan_keys, 1, NULL, 0);

while (index_getnext_slot(index_scan_desc, ForwardScanDirection, slot))
{
Name label;
Name lval;
bool isNull;
Datum datum;
char kind;

/*There isn't field kind in index. So we should check it by hands*/
datum = slot_getattr(slot, Anum_ag_label_kind, &isNull);
if (isNull)
continue;

kind = DatumGetChar(datum);

if (kind != LABEL_TYPE_EDGE)
continue;

datum = slot_getattr(slot, Anum_ag_label_name, &isNull);
if (!isNull)
{
label = DatumGetName(datum);
lval = (Name) palloc(NAMEDATALEN);
namestrcpy(lval, NameStr(*label));
labels = lappend(labels, lval);
}
}

index_endscan(index_scan_desc);
index_close(index_rel, RowExclusiveLock);
} else
{
Name label;
bool isNull;
Datum datum;
slot = ExecInitExtraTupleSlot(
estate, RelationGetDescr(resultRelInfo->ri_RelationDesc),
&TTSOpsHeapTuple);

tuple = heap_getnext(scan_desc, ForwardScanDirection);
// 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));

/* no more labels to process */
if (!HeapTupleIsValid(tuple))
break;
scan_desc = table_beginscan(ag_label, estate->es_snapshot, 2, scan_keys);

ExecStoreHeapTuple(tuple, slot, false);
// scan through the results and get all the label names.
while(true)
{
Name label;
Name lval;
bool isNull;
Datum datum;

datum = slot_getattr(slot, Anum_ag_label_name, &isNull);
label = DatumGetName(datum);
tuple = heap_getnext(scan_desc, ForwardScanDirection);

labels = lappend(labels, label);
}
// no more labels to process
if (!HeapTupleIsValid(tuple))
break;

ExecStoreHeapTuple(tuple, slot, false);

table_endscan(scan_desc);
datum = slot_getattr(slot, Anum_ag_label_name, &isNull);
label = DatumGetName(datum);

lval = (Name) palloc(NAMEDATALEN);
namestrcpy(lval, NameStr(*label));
labels = lappend(labels, lval);
}

table_endscan(scan_desc);
}

destroy_entity_result_rel_info(resultRelInfo);
table_close(resultRelInfo->ri_RelationDesc, RowExclusiveLock);
Expand Down
Loading