Debugging Apache AGE using Visual Studio Code in Ubuntu
Tags: postgres, apacheage
Published: 2023-07-30 13:04:08

Apache AGE (short for A Graph Extension) is an extension to PostgreSQL, giving it graph database functionality. It is open source, and contributions to the project are welcomed. An invaluable tool for this is being able to debug the AGE project, and that's what we'll be doing today.

> This article is specifically written for Ubuntu, but can be applied to other Linux distributions.

## Prerequisite
To debug AGE, we'll need the following.
- PostgreSQL installed from [source code](https://www.postgresql.org/download/).
- Download and install AGE from the [source code](https://age.apache.org/age-manual/master/intro/setup.html#installing-from-source-code).
- Download and install Visual Studio Code from [here](https://code.visualstudio.com/download#).
- A C compiler. For this article, gcc is used.

## Setup
Open the AGE source code in  VS Code. You can do that either by opening the folder in VS code or by running the following in the terminal.

```bash
cd ~/age
code .
```

Replace `~/age` with the path to your AGE source.

To configure the project for debugging, we create a folder `.vscode` in the project's root folder, and add the following files:`launch.json`, `settings.json`, and `c_cpp_properties.json`.

![launch.json, settings.json, and c_cpp_properties.json files added to the .vscode folder](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wjefcn87m4bn6ckcgdii.png)

* `launch.json`
```json
{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "(gdb) Attach",
      "type": "cppdbg",
      "request": "attach",
      "program": "/home/hallixon/postgres/bin/postgres",
      "MIMode": "gdb",
      "setupCommands": [
        {
          "description": "Enable pretty-printing for gdb",
          "text": "-enable-pretty-printing",
          "ignoreFailures": true
        },
        {
          "description": "Set Disassembly Flavor to Intel",
          "text": "-gdb-set disassembly-flavor intel",
          "ignoreFailures": true
        }
      ]
    }
  ]
}
```
The configuration above enables attaching VS Code's debugger to the `postgres` process. Replace `/home/hallixon/postgres/bin/postgres` with the path to your PostgreSQL installation.

* `settings.json`
```json
{
    "files.associations": {
        "postgres.h": "c",
        "genam.h": "c",
        "heapam.h": "c",
        "tableam.h": "c",
        "table.h": "c",
        "htup_details.h": "c",
        "skey.h": "c",
        "pg_operator.h": "c",
        "namespace.h": "c"
    }
}
```
This associates the header files with C language, and informs VS Code to use the same syntax highlighting for C on those files for this workspace.

* `c_cpp_properties.json`
```json
{
  "configurations": [
    {
      "name": "Linux",
      "includePath": [
        "/usr/include/**/**",
        "${workspaceFolder}/**",
        "/usr/include/**",
        "/home/hallixon/postgres/include/**",
        "/home/hallixon/postgres/include/server/**",
        "/home/hallixon/postgresql-13.11/src/**",
        "/home/hallixon/postgresql-13.11/**",
        "/home/hallixon/postgresql-13.11/src/backend/**",
        "/home/hallixon/postgres/lib/**",
        "${workspaceFolder}/src/include/**"
      ],
      "defines": [],
      "compilerPath": "/usr/bin/gcc",
      "cStandard": "c17",
      "cppStandard": "gnu++17",
      "intelliSenseMode": "linux-gcc-x64"
    }
  ],
  "version": 4
}
```
Replace all `/home/hallixon/postgresql-13.11` with the path to your PostgreSQL source code, and `/home/hallixon/postgres` with the path to your PostgreSQL installation.

You're now set to go.

## Running PostgreSQL and Apache AGE
You can check if PostgreSQL is running by running the following command.
```bash
ps -e | grep postgres
```
You should receive an output similar to the following.
```
18813 ?        00:00:00 postgres
18815 ?        00:00:00 postgres
18816 ?        00:00:00 postgres
18817 ?        00:00:00 postgres
18818 ?        00:00:00 postgres
18819 ?        00:00:00 postgres
18820 ?        00:00:00 postgres
```
If there was no output, then you can start PostgreSQL by running the code below in the folder containing your PostgreSQL installation.

```bash
./pg_ctl -D pgdata -l pg_logfile start
```
Where `pgdata` will be the path to PostgreSQL's database configuration files. By default, the environment variable `PGDATA` is used. `pg_logfile` is a log file for PostgreSQL to append its logs. If it doesn't exist, PostgreSQL will create it.

Now, create a new database and connect to it.
```bash
./createdb age_test
./psql age_test
```
Now, add the AGE extension to the database.
```bash
CREATE EXTENSION IF NOT EXISTS age;
LOAD 'age';
SET search_path = ag_catalog, "$user", public;
```
To run cypher commands, we need a graph database. To create one, run the following code:
```SQL
SELECT create_graph('test_graph');
```

## Attaching the Debugger
We need the ID of the `postgres` process so we can debug it while it runs. To find the process ID, run the following SQL command in the database.

```SQL
SELECT pg_backend_pid();
```

In VS Code, with the AGE project open, press **F5**. A popup will be opened for you to select the process to attach to. Now, type the process ID of the running `postgres` backend process, and select the matching process. The integrated terminal in VS Code will open, requiring Superuser access to process. 

![Image showing the integrated VS Code terminal requiring Superuser access to continue](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/par6tuol9zad61z948k4.png)

Enter `y` and put in your password.

## Debugging the Cypher `reverse()` Method
Open `agtype.c` in the src/backend/utils/adt folder, and search for `age_reverse` in the code using **Ctrl + F**. This is the method that handles the `reverse()` cypher method.

Add a breakpoint like you see in the picture.

![Image showing a breakpoint added in the age_reverse method](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qbdct58v0jx3y68eco06.png)

Now, go to your terminal and run the SQL query in your database.
```SQL
SELECT *
FROM cypher('test_graph', $$
    RETURN reverse('everywhere')
$$) AS (reverse agtype);
```
The breakpoint will be hit.

![Image showing that the breakpoint set in the age_reverse method was hit](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h393r9wixsre9zej2wy4.png)

You can view the values of the local variables by hovering over them, or in the **Run and Debug View** in VS Code, which is preferable.

![The Variables section in the Debug View showing the local variables in the age_reverse method](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vd0dfq35oesjiminxtl1.png)

You can step into the `extract_variadic_args` method, by pressing **F11**.

![Stepping into the extract_variadic_args method](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/joxpdhncihexn6a3q70l.png)

Now, step out of the method by pressing **Shift+F11**. Press **F11** to move to the next line. In the Run and Debug View, you'll find out that the variable `nargs`, which is the number of arguments passed into the `reverse()` cypher method, is changed to 1.

Press **F5** to continue running. In the terminal, you should see the result of query displayed.
```SQL
   reverse    
--------------
 "erehwyreve"
(1 row)
```

##  Conclusion
In this article, we were able to debug the AGE source code. This step taken will be one the most important in the journey to understanding and contributing to the Apache AGE project. 

Please feel free to comment below if you have questions or if this helped you. Thanks!