1

In Apache AGE source code, we can see that vertices and edges can inherit from multiple labels. For this, it uses functions called create_label, create_table_for_label and, depending if it is a vertex or an edge, create_vlabel and create_elabel. All these functions can be found here.

The create_vlabel has three arguments: first the graph name, then the label name, and then an array of parent labels. Then it is going to add each of these parent labels in a list and set a variable called is_inheriting to 1.

At the end of the create_vlabel function, it is going to call create_label function, which calls create_table_for_label. In this one, it is going to check if the list of parents is different than zero and if is_inheriting is equal to 0. If this last comparison is not made (the is_inheriting comparison), when the label inherits from multiple it throws an error stating that the label table to be created must contain a default value different from the parents or the parents' label tables must have a default value equal to the child's.

static void create_table_for_label(char *graph_name, char *label_name,
                                   char *schema_name, char *rel_name,
                                   char *seq_name, char label_type,
                                   List *parents, int is_inheriting)
{
    CreateStmt *create_stmt;
    PlannedStmt *wrapper;

    create_stmt = makeNode(CreateStmt);

    // relpersistence is set to RELPERSISTENCE_PERMANENT by makeRangeVar()
    create_stmt->relation = makeRangeVar(schema_name, rel_name, -1);
    
    /*
     * When a new table has parents, do not create a column definition list.
     * Use the parents' column definition list instead, via Postgres'
     * inheritance system.
     */
    if (list_length(parents) != 0 && is_inheriting == 0)
        create_stmt->tableElts = NIL;
    else if (label_type == LABEL_TYPE_EDGE)
        create_stmt->tableElts = create_edge_table_elements(
            graph_name, label_name, schema_name, rel_name, seq_name);
    else if (label_type == LABEL_TYPE_VERTEX)
        create_stmt->tableElts = create_vertex_table_elements(
            graph_name, label_name, schema_name, rel_name, seq_name);
    else
        ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR),
                        errmsg("undefined label type \'%c\'", label_type)));

    create_stmt->inhRelations = parents;
    create_stmt->partbound = NULL;
    create_stmt->ofTypename = NULL;
    create_stmt->constraints = NIL;
    create_stmt->options = NIL;
    create_stmt->oncommit = ONCOMMIT_NOOP;
    create_stmt->tablespacename = NULL;
    create_stmt->if_not_exists = false;

    wrapper = makeNode(PlannedStmt);
    wrapper->commandType = CMD_UTILITY;
    wrapper->canSetTag = false;
    wrapper->utilityStmt = (Node *)create_stmt;
    wrapper->stmt_location = -1;
    wrapper->stmt_len = 0;

    ProcessUtility(wrapper, "(generated CREATE TABLE command)",
                   PROCESS_UTILITY_SUBCOMMAND, NULL, NULL, None_Receiver,
                   NULL);
    // CommandCounterIncrement() is called in ProcessUtility()
}

Inheriting works fine, but the output looks strange with multiple times showing the message "merging multiple inherited definitions of column..."

SELECT create_vlabel('cypher_create', 'child_vlabel_three', ARRAY['parent_vlabel', 'child_vlabel_one', 'child_vlabel_two']);
NOTICE:  VLabel child_vlabel_three will inherit from parent_vlabel
NOTICE:  VLabel child_vlabel_three will inherit from child_vlabel_one
NOTICE:  VLabel child_vlabel_three will inherit from child_vlabel_two
NOTICE:  merging multiple inherited definitions of column "id"
NOTICE:  merging multiple inherited definitions of column "properties"
NOTICE:  merging multiple inherited definitions of column "id"
NOTICE:  merging multiple inherited definitions of column "properties"
NOTICE:  merging column "id" with inherited definition
NOTICE:  merging column "properties" with inherited definition
NOTICE:  VLabel "child_vlabel_three" has been created
 create_vlabel 
---------------
 
(1 row)

If I could first create the table and then alter it so that it didn't show these repeated messages, how should I do it?

Matheus Farias
  • 716
  • 1
  • 10

1 Answers1

0

In the function definition, you need to check wether the parent column has been included in the column definition list. Here is the updated code

static void create_table_for_label(char *graph_name, char *label_name,
                                   char *schema_name, char *rel_name,
                                   char *seq_name, char label_type,
                                   List *parents, int is_inheriting)
{
    CreateStmt *create_stmt;
    PlannedStmt *wrapper;

    create_stmt = makeNode(CreateStmt);

    // relpersistence is set to RELPERSISTENCE_PERMANENT by makeRangeVar()
    create_stmt->relation = makeRangeVar(schema_name, rel_name, -1);
    
    /*
     * When a new table has parents, do not create a column definition list.
     * Use the parents' column definition list instead, via Postgres'
     * inheritance system.
     */
    if (list_length(parents) != 0 && is_inheriting == 0)
        create_stmt->tableElts = NIL;
    else if (label_type == LABEL_TYPE_EDGE)
        create_stmt->tableElts = create_edge_table_elements(
            graph_name, label_name, schema_name, rel_name, seq_name);
    else if (label_type == LABEL_TYPE_VERTEX)
        create_stmt->tableElts = create_vertex_table_elements(
            graph_name, label_name, schema_name, rel_name, seq_name);
    else
        ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR),
                        errmsg("undefined label type \'%c\'", label_type)));

    create_stmt->inhRelations = NIL;  // do not inherit from parents at creation
    create_stmt->partbound = NULL;
    create_stmt->ofTypename = NULL;
    create_stmt->constraints = NIL;
    create_stmt->options = NIL;
    create_stmt->oncommit = ONCOMMIT_NOOP;
    create_stmt->tablespacename = NULL;
    create_stmt->if_not_exists = false;

    wrapper = makeNode(PlannedStmt);
    wrapper->commandType = CMD_UTILITY;
    wrapper->canSetTag = false;
    wrapper->utilityStmt = (Node *)create_stmt;
    wrapper->stmt_location = -1;
    wrapper->stmt_len = 0;

    ProcessUtility(wrapper, "(generated CREATE TABLE command)",
                   PROCESS_UTILITY_SUBCOMMAND, NULL, NULL, None_Receiver,
                   NULL);

    // inherit from parent tables using ALTER TABLE command
    if (list_length(parents) != 0) {
        AlterTableStmt *alter_stmt;
        ListCell *lc;

        alter_stmt = makeNode(AlterTableStmt);
        alter_stmt->relation = create_stmt->relation;
        alter_stmt->cmds = NIL;
        foreach(lc, parents) {
            TypeName *parent_name = makeTypeNameFromNameList((List *) lfirst(lc));
            Node *parent = (Node *) parent_name;
            AlterTableCmd *inherit_cmd;

            inherit_cmd = makeNode(AlterTableCmd);
            inherit_cmd->subtype = AT_InheritPartition;
            inherit_cmd->def = (Node *) parent;

            alter_stmt->cmds = lappend(alter_stmt->cmds, inherit_cmd);
        }

        wrapper = makeNode(PlannedStmt);
        wrapper->commandType = CMD_UTILITY;
        wrapper->canSetTag = false;
        wrapper->utilityStmt = (Node *)alter_stmt;
        wrapper->stmt_location = -1;
        wrapper->stmt_len = 0;

        ProcessUtility(wrapper, "(generated ALTER TABLE command)",
                       PROCESS_UTILITY_SUBCOMMAND, NULL, NULL, None_Receiver,
                       NULL);
    }
}