4

While going through the AGE code, I found this age-1.3.0.sql file where I believe all tables are created and all functions are declared.

For example line number 94

CREATE FUNCTION ag_catalog.create_graph(graph_name name)
RETURNS void
LANGUAGE c
AS 'MODULE_PATHNAME';

This I assume is the declaration of create_graph function.

I found what MODULE_PATHNAME might refer to in age.control file in line number 20

module_pathname = '$libdir/age'

And the definition of the C function to create a graph, which I suppose is this function in /src/backend/commands/graph_commands.c line number 60:-

/* function that is evoked for creating a graph */
Datum create_graph(PG_FUNCTION_ARGS)
{
    char *graph;
    Name graph_name;
    char *graph_name_str;
    Oid nsp_id;

    //if no argument is passed with the function, graph name cannot be null
    if (PG_ARGISNULL(0))
    {
        ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                        errmsg("graph name can not be NULL")));
    }

    //gets graph name as function argument
    graph_name = PG_GETARG_NAME(0);  

    graph_name_str = NameStr(*graph_name);

    //checking if the name of the graph falls under the pre-decided graph naming conventions(regex)
    if (!is_valid_graph_name(graph_name_str))
    {
        ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                        errmsg("graph name is invalid")));
    }

    //graph name must be unique, a graph with the same name should not exist
    if (graph_exists(graph_name_str))
    {
        ereport(ERROR,
                (errcode(ERRCODE_UNDEFINED_SCHEMA),
                 errmsg("graph \"%s\" already exists", graph_name_str)));
    }

    nsp_id = create_schema_for_graph(graph_name);

    //inserts the graph info into the relation which has all the other existing graphs info
    insert_graph(graph_name, nsp_id);  

    //Increment the Command counter before create the generic labels.
    CommandCounterIncrement();

    //Create the default label tables
    graph = graph_name->data;
    create_label(graph, AG_DEFAULT_LABEL_VERTEX, LABEL_TYPE_VERTEX, NIL);
    create_label(graph, AG_DEFAULT_LABEL_EDGE, LABEL_TYPE_EDGE, NIL);

    ereport(NOTICE,
            (errmsg("graph \"%s\" has been created", NameStr(*graph_name))));

    //according to postgres specification of c-language functions if function returns void this is the syntax
    PG_RETURN_VOID(); 
}

I wanted to ask how is it that when an SQL query like

SELECT * FROM ag_catalog.create_graph('graph_name');

is executed, the C function in the said file is executed? Where is the link between the two? And where can I find it?

I've dug plenty deep into the code to no avail, I still do not understand how does it all tie together.

1 Answers1

3

The CREATE EXTENSION command replaces MODULE_PATHNAME with the value of module_pathname in the control file. Typically, this is set to $libdir/shared_library_name and then MODULE_PATHNAME is used in CREATE FUNCTION commands for C-language functions, so that the script files do not need to hard-wire the name of the shared library.

The CREATE FUNCTION command provides the path to the shared library file and the link symbol for the provided function. If the link symbol is omitted it is assumed to be the same as the name of the SQL function being defined. PostgreSQL searches for a shared library in the following order:

  1. If the name is an absolute path, the given file is loaded.
  2. If the name starts with the string $libdir, that part is replaced by the PostgreSQL package library directory name, which is determined at build time.
  3. If the name does not contain a directory part, the file is searched for in the path specified by the configuration variable dynamic_library_path.
  4. Otherwise (the file was not found in the path, or it contains a non-absolute directory part), the dynamic loader will try to take the name as given, which will most likely fail. (It is unreliable to depend on the current working directory.)

If this sequence does not work, the platform-specific shared library file name extension (often .so) is appended to the given name and this sequence is tried again. If that fails as well, the load will fail.

David Jones
  • 2,879
  • 2
  • 18
  • 23