Adding Custom Functions to Apache AGE Source Code: A Step-by-Step Tutorial
Published: 2023-06-04 19:55:49

In this tutorial, we will walk you through the process of adding a new function to the Apache AGE source code. For the purpose of this tutorial, we will create a simple function that takes two integer numbers as arguments, adds them together, and returns the result.

Also in the upcoming tutorial, we will improve our function by enabling it to accept `agtype` as an input, allowing seamless integration with Cypher queries. Stay tuned for more!


**What is Apache AGE ?**

Apache AGE is a graph extension for PostgreSQL, designed to enhance its capabilities by adding graph database functionality. With AGE, users can utilize the power and flexibility of PostgreSQL while also leveraging graph-based data storage, querying, and analysis. This combination allows for efficient handling of graph data within a familiar PostgreSQL environment.


**Prerequisites**

1. PostgreSQL Version 11 or 12: Make sure you have PostgreSQL installed on your machine. Apache AGE relies on PostgreSQL, so it's important to have either version 11 or 12.

2. Apache AGE Installation and Configuration: Install and configure Apache AGE to seamlessly integrate with your PostgreSQL installation. If you haven't installed PostgreSQL and Apache AGE yet, we recommend following our comprehensive step-by-step guide for easy installation on Windows. You can access the tutorial [here](https://dev.to/omarsaad/step-by-step-guide-to-install-postgresql-apache-age-on-windows-28gf). This guide will walk you through the entire process and ensure a smooth setup.


**Creating a Custom Function in Apache AGE Source Code**

In this section of the tutorial, we will go through the steps to create a custom function that adds two integer numbers and returns the result. Follow these numbered steps:

1. Create a new file named `math_functions.c` in the `src/backend/commands` folder. This file will serve as the implementation for our custom mathematical function.

2. Open the `math_functions.c` file in your preferred text editor or integrated development environment (IDE).

3. Include the necessary header files for the function implementation. These may include `postgres.h` for PostgreSQL-specific declarations and `fmgr.h` for function manager definitions.

4\. Define the `adder` function as follows:
   ```c
 #include "postgres.h"
 #include "fmgr.h"

 PG_FUNCTION_INFO_V1(adder);

 Datum
 adder(PG_FUNCTION_ARGS)
 {
    elog(INFO, "Adder function called");

    if (PG_ARGISNULL(0) || PG_ARGISNULL(1))
    {
        ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                        errmsg("Num1 and Num2 must not be NULL")));
        
    }

    // // Get the values of the two arguments
    int arg1 = PG_GETARG_INT32(0);
    int arg2 = PG_GETARG_INT32(1);
    int result = arg1 + arg2;

    PG_RETURN_INT32(result);

  }
   ```

 In the code above, we first include the necessary header files: postgres.h for PostgreSQL-specific declarations and fmgr.h for function manager definitions and `utils/agtype.h` for AGType functionality, are included.

 The line `PG_FUNCTION_INFO_V1(adder);` defines the function information for the adder function. This macro is necessary for PostgreSQL to recognize the function.

 The adder function is implemented to take two int arguments, arg1 and arg2. It calculates their sum and stores it in the result variable.

 Then a check is performed to verify if both arguments are provided. If any of the arguments is not provided (i.e., `NULL`), an error is raised using the `ereport` function, specifying that both arguments must be provided.

 Finally, `PG_RETURN_INT32(result)` is used to return the result of the addition as the output of the function.

 Note: `elog` is used to print to the console you can use it to debug your code.

5\. In the main project directory, locate the file named `Makefile` and open it. Within the `Makefile`, locate the `OBJS` section and add the following directory to it.

```
src/backend/commands/math_functions.o 
```
Adding this entry to the `OBJS` section ensures that the object file is included in the compilation process when building the project.

6\. Open the `age--1.2.0.sql` file and add the following signature to it:

```
-- Signature: adder(integer, integer)
-- Purpose: Adds two integers and returns the result.
CREATE  FUNCTION adder(int, int)
    RETURNS int
    LANGUAGE c
    AS 'MODULE_PATHNAME';
```

The above code adds a signature to the `age--1.2.0.sql` file. This signature defines a function named `adder` that takes two integer arguments. The function is implemented in the C language and its code resides in the shared library specified by `'MODULE_PATHNAME'`.

7\. Navigate to the main project directory and execute the command `make install` to build the source code.

8\. To reset the Apache AGE extension and start fresh, you can execute the following commands:

```
DROP EXTENSION age CASCADE;
CREATE EXTENSION age;
LOAD 'age';
SET search_path = ag_catalog, "$user", public;
```

9\. Run the following command to start the database server.

```
 pg_ctl -D /path/to/data/directory -l logfile -o  "-p <your_port_number>" start
```
Replace `/path/to/data/directory` with the actual path to your PostgreSQL data directory. This is the directory where the database files are stored.

Replace `<your_port_number>` with the port number on which you want the database server to listen.

Running this command will start the PostgreSQL database server using the specified data directory and port number. The server log will be written to the specified `logfile`.

10\. Testing Our Function.

First start `psql` using the following command:

```
psql -U <your_username> -p <your_port_number> -d <your_database_name>
```

Then we will call our function with 1 an 2 as an arguments.

```sql
 SELECT * FROM ag_catalog.adder(1,2) AS res;
```

Output: 

![Function call output](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3nq85d1ug28p5f1rbgi8.png)


That's fantastic! Creating your first function in the Apache AGE source code is indeed a significant step towards contributing to the project. By adding custom functionality, you can enhance the capabilities of Apache AGE and make a valuable contribution to the community.

Contributing to open-source projects like Apache AGE not only allows you to expand your skills but also enables you to collaborate with other developers and make a positive impact on the project's development.


Congratulations on taking this important step, and best of luck with your future contributions to Apache AGE!

In the upcoming tutorial, we will improve our function by enabling it to accept `agtype` as an input, allowing seamless integration with Cypher queries. Stay tuned for more!

**References**
[Guide to AGE contribution and modifying the source code to add new functions](https://dev.to/rrrokhtar/guide-to-age-contribution-and-modifying-the-source-code-to-add-new-functions-l7m)
[Apache AGE documentation](https://age.apache.org/age-manual/master/index.html)
[Apache AGE Github](https://github.com/apache/age)

**Contribute to Apache AGE**

[Apache AGE Github](https://github.com/apache/age)
[Apache AGE Viewer Github](https://github.com/apache/age-viewer)