DEV Community

Cover image for How AGE is executed on top of PostgreSQL
Mohamed Mokhtar
Mohamed Mokhtar

Posted on • Updated on

How AGE is executed on top of PostgreSQL


Hey everyone

Today I will explain to you how Apache AGE works in top of Postgresql it is considered as a complimentary part of the old blogs I have published before you can find them on my profile, lets get started!

First of all thanks to Postgresql being friendly with their extension they have taken into consideration that there are some HOOKS can be added to their source code one of them which is mainly used by Apache AGE is

What is post_parse_analyze_hook?

it is a function address assigned to NULL on Postgresql

Null starte

And if it gets an address it will be called, i.e. when an extension is loaded on Postgresql session

And it has added an effect on that Postgresql variable when the queries are being executed that hook will be used.
When does it used? That's the decision of PostgreSQL not extensions' decision so that in the current time it is being called after the analyze and parse state.


What is attached to that function call?

ParseState and QueryTree and JumpleState. If you miss any part of those terminologies you can find POSTS related to them on my blog also.

What happens after Apache AGE gets that calling and what function is being used for that?

    if (post_parse_analyze_hook)
        (*post_parse_analyze_hook) (pstate, query, jstate);

Enter fullscreen mode Exit fullscreen mode

Apache AGE has set post_parse_analyze_hook to post_parse_analyze
Through the following code at src/cypher/anaylze

void post_parse_analyze_init(void)
    prev_post_parse_analyze_hook = post_parse_analyze_hook;
    post_parse_analyze_hook = post_parse_analyze;
Enter fullscreen mode Exit fullscreen mode

post_parse_analyze is a part of apache age and it's purpose is?

A: To change every cyhper call to subquery node
Q: How?
Post parsing: i.e. second parsing.

  • Go to every part of the query in the from statement (because our cypher call is being executed at the FROM part)

How to find them? In the parse state we can find them on field RangeTblEntry

For every entry of those we check them if it is

  • Function call
  • Subquery

  • If a function call it may be a cypher call so we need to make a check here [Simply string matching]

  • Got it? but why do we need to check another subqueries? because their from list may consist of a cypher call (We are solving that recursively)

What function does that conversion? convert_cypher_walker

find cypher() calls in FROM clauses and convert them to SELECT subqueries


  • KEEPS CHECKING a NODE if it is an RTETblEntry (the nodes on the FROM list)
if (they are function as cypher is defined as function) { 
  // check if it is cypher or not 
  if (cypher) CONVERT TO SUB_QUERY
if there is real existing sub query check if it contains a cypher in their FROM list or not (i.e. RECURSIVE CALL)
Enter fullscreen mode Exit fullscreen mode


Portion of the code of convert_cypher_walker

static bool convert_cypher_walker(Node *node, ParseState *pstate)
    if (!node)
        return false;

    if (IsA(node, RangeTblEntry))
        RangeTblEntry *rte = (RangeTblEntry *)node;

        switch (rte->rtekind)
        case RTE_SUBQUERY:
            // traverse other RTE_SUBQUERYs
            return convert_cypher_walker((Node *)rte->subquery, pstate);
        case RTE_FUNCTION:
            if (is_rte_cypher(rte))
                convert_cypher_to_subquery(rte, pstate);
            return false;
            return false;
Enter fullscreen mode Exit fullscreen mode

Thanks for reading till here I have reached to an end of today's blog I hope you feel it has given you good understanding of Postgresql extensions and AGE

                        _ _                
   __ _  ___   ___   __| | |__  _   _  ___ 
  / _` |/ _ \ / _ \ / _` | '_ \| | | |/ _ \
 | (_| | (_) | (_) | (_| | |_) | |_| |  __/
  \__, |\___/ \___/ \__,_|_.__/ \__, |\___|
  |___/                         |___/      

Enter fullscreen mode Exit fullscreen mode

Resources & References

Top comments (0)