Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
399a289
Updated CI, Labeler, Docker, and branch security files for PG18 (#2246)
jrgemignani Nov 19, 2025
146bf38
PG18 port for AGE (#2251)
kk-src Nov 25, 2025
201399f
Update CI for BaseDockerizedTest (#2254)
jrgemignani Dec 2, 2025
f364664
Fix DockerHub build warning messages (#2252)
jrgemignani Dec 2, 2025
c176b57
Fix issue 2245 - Creating more than 41 vlabels causes crash in drop_g…
jrgemignani Nov 19, 2025
2f36b1c
Add index on id columns (#2117)
MuhammadTahaNaveed Dec 3, 2025
1d9df48
Fix Issue 2256: segmentation fault when calling coalesce function (#2…
jrgemignani Dec 9, 2025
2ccdc6b
Adjust 'could not find rte for' ERROR message (#2266)
jrgemignani Dec 9, 2025
419eb13
Fix possible memory and file descriptors leaks (#2258)
ZigzagAK Dec 9, 2025
b9d35d5
Fix ORDER BY alias resolution with AS in Cypher queries (#2269)
jrgemignani Dec 10, 2025
7432ac6
Update grammar file for maintainability (#2270)
jrgemignani Dec 11, 2025
d4e9b9c
Convert string to raw string to remove invalid escape sequence warnin…
jsell-rh Dec 11, 2025
d8fc867
Migrate python driver configuration to pyproject.toml (#2272)
MuhammadTahaNaveed Dec 11, 2025
3d54a1c
Restrict age_load commands (#2274)
jrgemignani Dec 16, 2025
4d13998
Makefile: fix race condition on cypher_gram_def.h (#2273)
tureba Jan 6, 2026
43f6ca4
Revise README for Python driver updates (#2298)
M15terHyde Jan 6, 2026
5c6dbc8
Fix Issue 2289: handle empty list in IN expression (#2294)
jrgemignani Jan 9, 2026
88d2048
Fix and improve index.sql regression test coverage (#2300)
jrgemignani Jan 9, 2026
3b7510e
Fix and improve index.sql addendum (#2301)
jrgemignani Jan 10, 2026
4dd05d4
feat: Add 32-bit platform support for graphid type (#2286)
jpabbuehl Jan 12, 2026
ce5d3a1
Optimize vertex/edge field access with direct array indexing (#2302)
jrgemignani Jan 16, 2026
7112a9a
Upgrade Jest to v29 for node: protocol compatibility (#2307)
jrgemignani Jan 17, 2026
49b186e
Fix Issue 1884: Ambiguous column reference (#2306)
jrgemignani Jan 18, 2026
3656812
Replace libcsv with pg COPY for csv loading (#2310)
MuhammadTahaNaveed Jan 19, 2026
9e04372
Add RLS support and fix permission checks (#2309)
MuhammadTahaNaveed Jan 20, 2026
39224be
Merge branch 'PG18' into master
jrgemignani Jan 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .asf.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ github:
required_pull_request_reviews:
required_approving_review_count: 1

PG18:
required_pull_request_reviews:
required_approving_review_count: 1

PG17:
required_pull_request_reviews:
required_approving_review_count: 1
Expand Down
3 changes: 3 additions & 0 deletions .github/labeler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,8 @@ PG16:
PG17:
- base-branch: 'PG17'

PG18:
- base-branch: 'PG18'

master:
- base-branch: 'master'
33 changes: 17 additions & 16 deletions .github/workflows/installcheck.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ name: Build / Regression
on:
push:
branches: [ "master" ]

pull_request:
branches: [ "master" ]

Expand All @@ -11,53 +12,53 @@ jobs:
runs-on: ubuntu-latest

steps:
- name: Get latest commit id of PostgreSQL 17
- name: Get latest commit id of PostgreSQL 18
run: |
echo "PG_COMMIT_HASH=$(git ls-remote https://git.postgresql.org/git/postgresql.git refs/heads/REL_17_STABLE | awk '{print $1}')" >> $GITHUB_ENV
echo "PG_COMMIT_HASH=$(git ls-remote https://git.postgresql.org/git/postgresql.git refs/heads/REL_18_STABLE | awk '{print $1}')" >> $GITHUB_ENV

- name: Cache PostgreSQL 17
- name: Cache PostgreSQL 18
uses: actions/cache@v3
id: pg17cache
id: pg18cache
with:
path: ~/pg17
key: ${{ runner.os }}-v1-pg17-${{ env.PG_COMMIT_HASH }}
path: ~/pg18
key: ${{ runner.os }}-v1-pg18-${{ env.PG_COMMIT_HASH }}

- name: Install necessary dependencies
run: |
sudo apt-get update
sudo apt-get install -y build-essential libreadline-dev zlib1g-dev flex bison

- name: Install PostgreSQL 17 and some extensions
if: steps.pg17cache.outputs.cache-hit != 'true'
- name: Install PostgreSQL 18 and some extensions
if: steps.pg18cache.outputs.cache-hit != 'true'
run: |
git clone --depth 1 --branch REL_17_STABLE https://git.postgresql.org/git/postgresql.git ~/pg17source
cd ~/pg17source
./configure --prefix=$HOME/pg17 CFLAGS="-std=gnu99 -ggdb -O0" --enable-cassert
git clone --depth 1 --branch REL_18_STABLE https://git.postgresql.org/git/postgresql.git ~/pg18source
cd ~/pg18source
./configure --prefix=$HOME/pg18 CFLAGS="-std=gnu99 -ggdb -O0" --enable-cassert
make install -j$(nproc) > /dev/null
cd contrib
cd fuzzystrmatch
make PG_CONFIG=$HOME/pg17/bin/pg_config install -j$(nproc) > /dev/null
make PG_CONFIG=$HOME/pg18/bin/pg_config install -j$(nproc) > /dev/null
cd ../pg_trgm
make PG_CONFIG=$HOME/pg17/bin/pg_config install -j$(nproc) > /dev/null
make PG_CONFIG=$HOME/pg18/bin/pg_config install -j$(nproc) > /dev/null

- uses: actions/checkout@v3

- name: Build AGE
id: build
run: |
make PG_CONFIG=$HOME/pg17/bin/pg_config install -j$(nproc)
make PG_CONFIG=$HOME/pg18/bin/pg_config install -j$(nproc)

- name: Pull and build pgvector
id: pgvector
run: |
git clone https://github.com/pgvector/pgvector.git
cd pgvector
make PG_CONFIG=$HOME/pg17/bin/pg_config install -j$(nproc) > /dev/null
make PG_CONFIG=$HOME/pg18/bin/pg_config install -j$(nproc) > /dev/null

- name: Regression tests
id: regression_tests
run: |
make PG_CONFIG=$HOME/pg17/bin/pg_config installcheck EXTRA_TESTS="pgvector fuzzystrmatch pg_trgm"
make PG_CONFIG=$HOME/pg18/bin/pg_config installcheck EXTRA_TESTS="pgvector fuzzystrmatch pg_trgm"
continue-on-error: true

- name: Dump regression test errors
Expand Down
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@
<img src="https://img.shields.io/badge/Release-v1.6.0-FFA500?labelColor=gray&style=flat&link=https://github.com/apache/age/releases"/>
</a>
&nbsp;
<a href="https://www.postgresql.org/docs/17/index.html">
<img src="https://img.shields.io/badge/Version-Postgresql 17-00008B?labelColor=gray&style=flat&link=https://www.postgresql.org/docs/17/index.html"/>
<a href="https://www.postgresql.org/docs/18/index.html">
<img src="https://img.shields.io/badge/Version-Postgresql 18-00008B?labelColor=gray&style=flat&link=https://www.postgresql.org/docs/18/index.html"/>
</a>
&nbsp;
<a href="https://github.com/apache/age/issues">
Expand Down Expand Up @@ -125,7 +125,7 @@ Apache AGE is intended to be simple to install and run. It can be installed with
&nbsp;Install PostgreSQL
</h4>

You will need to install an AGE compatible version of Postgres<a>, for now AGE supports Postgres 11, 12, 13, 14, 15, 16 & 17. Supporting the latest versions is on AGE roadmap.
You will need to install an AGE compatible version of Postgres<a>, for now AGE supports Postgres 11, 12, 13, 14, 15, 16, 17, & 18. Supporting the latest versions is on AGE roadmap.

<h4>
&nbsp;Installation via Package Manager
Expand All @@ -143,7 +143,7 @@ sudo apt install postgresql
&nbsp;Installation From Source Code
</h4>

You can <a href="https://www.postgresql.org/ftp/source/"> download the Postgres </a> source code and install your own instance of Postgres. You can read instructions on how to install from source code for different versions on the <a href="https://www.postgresql.org/docs/17/installation.html">official Postgres Website.</a>
You can <a href="https://www.postgresql.org/ftp/source/"> download the Postgres </a> source code and install your own instance of Postgres. You can read instructions on how to install from source code for different versions on the <a href="https://www.postgresql.org/docs/18/installation.html">official Postgres Website.</a>



Expand All @@ -152,7 +152,7 @@ You can <a href="https://www.postgresql.org/ftp/source/"> download the Postgres

Clone the <a href="https://github.com/apache/age">github repository</a> or download the <a href="https://github.com/apache/age/releases">download an official release.
</a>
Run the pg_config utility and check the version of PostgreSQL. Currently, only PostgreSQL versions 11, 12, 13, 14, 15, 16 & 17 are supported. If you have any other version of Postgres, you will need to install PostgreSQL version 11, 12, 13, 14, 15, 16 & 17.
Run the pg_config utility and check the version of PostgreSQL. Currently, only PostgreSQL versions 11, 12, 13, 14, 15, 16, 17, & 18 are supported. If you have any other version of Postgres, you will need to install PostgreSQL version 11, 12, 13, 14, 15, 16, 17, & 18.
<br>

```bash
Expand Down
12 changes: 6 additions & 6 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@
#

# Build stage: Install necessary development tools for compilation and installation
FROM postgres:17 AS build
FROM postgres:18 AS build

RUN apt-get update \
&& apt-get install -y --no-install-recommends --no-install-suggests \
bison \
build-essential \
flex \
postgresql-server-dev-17
postgresql-server-dev-18

COPY . /age

Expand All @@ -34,7 +34,7 @@ RUN make && make install


# Final stage: Create a final image by copying the files created in the build stage
FROM postgres:17
FROM postgres:18

RUN apt-get update \
&& apt-get install -y --no-install-recommends --no-install-suggests \
Expand All @@ -48,9 +48,9 @@ ENV LANG=en_US.UTF-8
ENV LC_COLLATE=en_US.UTF-8
ENV LC_CTYPE=en_US.UTF-8

COPY --from=build /usr/lib/postgresql/17/lib/age.so /usr/lib/postgresql/17/lib/
COPY --from=build /usr/share/postgresql/17/extension/age--1.6.0.sql /usr/share/postgresql/17/extension/
COPY --from=build /usr/share/postgresql/17/extension/age.control /usr/share/postgresql/17/extension/
COPY --from=build /usr/lib/postgresql/18/lib/age.so /usr/lib/postgresql/18/lib/
COPY --from=build /usr/share/postgresql/18/extension/age--1.6.0.sql /usr/share/postgresql/18/extension/
COPY --from=build /usr/share/postgresql/18/extension/age.control /usr/share/postgresql/18/extension/
COPY docker/docker-entrypoint-initdb.d/00-create-extension-age.sql /docker-entrypoint-initdb.d/00-create-extension-age.sql

CMD ["postgres", "-c", "shared_preload_libraries=age"]
4 changes: 2 additions & 2 deletions docker/Dockerfile.dev
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@
#


FROM postgres:17
FROM postgres:18

RUN apt-get update
RUN apt-get install --assume-yes --no-install-recommends --no-install-suggests \
bison \
build-essential \
flex \
postgresql-server-dev-17 \
postgresql-server-dev-18 \
locales

ENV LANG=en_US.UTF-8
Expand Down
30 changes: 15 additions & 15 deletions regress/expected/cypher_match.out
Original file line number Diff line number Diff line change
Expand Up @@ -348,10 +348,10 @@ SELECT * FROM cypher('cypher_match', $$
$$) AS (i agtype);
i
----------------------------------------------------------------------------------
{"id": 1688849860263939, "label": "v2", "properties": {"id": "end"}}::vertex
{"id": 1688849860263938, "label": "v2", "properties": {"id": "middle"}}::vertex
{"id": 1688849860263938, "label": "v2", "properties": {"id": "middle"}}::vertex
{"id": 1688849860263939, "label": "v2", "properties": {"id": "end"}}::vertex
{"id": 1688849860263937, "label": "v2", "properties": {"id": "initial"}}::vertex
{"id": 1688849860263938, "label": "v2", "properties": {"id": "middle"}}::vertex
(4 rows)

SELECT * FROM cypher('cypher_match', $$
Expand Down Expand Up @@ -537,18 +537,18 @@ SELECT * FROM cypher('cypher_match', $$
$$) AS (i agtype, b agtype, c agtype);
i | b | c
---+-----------+-----------
| "end" | "middle"
0 | "end" | "middle"
1 | "end" | "middle"
| "middle" | "end"
0 | "middle" | "end"
1 | "middle" | "end"
| "middle" | "initial"
0 | "middle" | "initial"
1 | "middle" | "initial"
| "end" | "middle"
0 | "end" | "middle"
1 | "end" | "middle"
| "initial" | "middle"
0 | "initial" | "middle"
1 | "initial" | "middle"
| "middle" | "initial"
0 | "middle" | "initial"
1 | "middle" | "initial"
(12 rows)

SELECT * FROM cypher('cypher_match', $$
Expand All @@ -558,18 +558,18 @@ SELECT * FROM cypher('cypher_match', $$
$$) AS (i agtype, c agtype);
i | c
---+-----------
| "middle"
0 | "middle"
1 | "middle"
| "end"
0 | "end"
1 | "end"
| "initial"
0 | "initial"
1 | "initial"
| "middle"
0 | "middle"
1 | "middle"
| "middle"
0 | "middle"
1 | "middle"
| "initial"
0 | "initial"
1 | "initial"
(12 rows)

--
Expand Down Expand Up @@ -2421,8 +2421,8 @@ SELECT * FROM cypher('cypher_match', $$ MATCH p=(a)-[u {relationship: u.relation
SELECT * FROM cypher('cypher_match', $$ MATCH p=(a {name:a.name})-[u {relationship: u.relationship}]->(b {age:b.age}) RETURN p $$) as (a agtype);
a
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
[{"id": 281474976710659, "label": "", "properties": {"age": 3, "name": "orphan"}}::vertex, {"id": 4785074604081154, "label": "knows", "end_id": 281474976710666, "start_id": 281474976710659, "properties": {"years": 4, "relationship": "enemies"}}::edge, {"id": 281474976710666, "label": "", "properties": {"age": 6}}::vertex]::path
[{"id": 281474976710661, "label": "", "properties": {"age": 4, "name": "T"}}::vertex, {"id": 4785074604081153, "label": "knows", "end_id": 281474976710666, "start_id": 281474976710661, "properties": {"years": 3, "relationship": "friends"}}::edge, {"id": 281474976710666, "label": "", "properties": {"age": 6}}::vertex]::path
[{"id": 281474976710659, "label": "", "properties": {"age": 3, "name": "orphan"}}::vertex, {"id": 4785074604081154, "label": "knows", "end_id": 281474976710666, "start_id": 281474976710659, "properties": {"years": 4, "relationship": "enemies"}}::edge, {"id": 281474976710666, "label": "", "properties": {"age": 6}}::vertex]::path
(2 rows)

SELECT * FROM cypher('cypher_match', $$ CREATE () WITH * MATCH (x{n0:x.n1}) RETURN 0 $$) as (a agtype);
Expand Down
1 change: 1 addition & 0 deletions src/backend/catalog/ag_label.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

#include "access/genam.h"
#include "catalog/indexing.h"
#include "executor/executor.h"
#include "nodes/makefuncs.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
Expand Down
1 change: 1 addition & 0 deletions src/backend/executor/cypher_create.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

#include "postgres.h"

#include "executor/executor.h"
#include "utils/rls.h"

#include "catalog/ag_label.h"
Expand Down
5 changes: 3 additions & 2 deletions src/backend/executor/cypher_delete.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@

#include "postgres.h"

#include "executor/executor.h"
#include "storage/bufmgr.h"
#include "common/hashfn.h"
#include "miscadmin.h"
#include "storage/bufmgr.h"
#include "utils/acl.h"
#include "utils/rls.h"

Expand Down Expand Up @@ -260,7 +261,7 @@ static agtype_value *extract_entity(CustomScanState *node,
tupleDescriptor = scanTupleSlot->tts_tupleDescriptor;

/* type checking, make sure the entity is an agtype vertex or edge */
if (tupleDescriptor->attrs[entity_position -1].atttypid != AGTYPEOID)
if (TupleDescAttr(tupleDescriptor, entity_position -1)->atttypid != AGTYPEOID)
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("DELETE clause can only delete agtype")));

Expand Down
1 change: 1 addition & 0 deletions src/backend/executor/cypher_merge.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

#include "postgres.h"

#include "executor/executor.h"
#include "utils/datum.h"
#include "utils/rls.h"

Expand Down
28 changes: 22 additions & 6 deletions src/backend/executor/cypher_set.c
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ static HeapTuple update_entity_tuple(ResultRelInfo *resultRelInfo,
TM_Result result;
CommandId cid = GetCurrentCommandId(true);
ResultRelInfo **saved_resultRels = estate->es_result_relations;
bool close_indices = false;

estate->es_result_relations = &resultRelInfo;

Expand All @@ -116,7 +117,16 @@ static HeapTuple update_entity_tuple(ResultRelInfo *resultRelInfo,

if (lock_result == TM_Ok)
{
ExecOpenIndices(resultRelInfo, false);
/*
* Open indices if not already open. The resultRelInfo may already
* have indices opened by the caller (e.g., create_entity_result_rel_info),
* so only open if needed and track that we did so for cleanup.
*/
if (resultRelInfo->ri_IndexRelationDescs == NULL)
{
ExecOpenIndices(resultRelInfo, false);
close_indices = true;
}
ExecStoreVirtualTuple(elemTupleSlot);
tuple = ExecFetchSlotHeapTuple(elemTupleSlot, true, NULL);
tuple->t_self = old_tuple->t_self;
Expand Down Expand Up @@ -151,7 +161,10 @@ static HeapTuple update_entity_tuple(ResultRelInfo *resultRelInfo,
errmsg("tuple to be updated was already modified")));
}

ExecCloseIndices(resultRelInfo);
if (close_indices)
{
ExecCloseIndices(resultRelInfo);
}
estate->es_result_relations = saved_resultRels;

return tuple;
Expand All @@ -170,7 +183,10 @@ static HeapTuple update_entity_tuple(ResultRelInfo *resultRelInfo,
(update_indexes == TU_Summarizing));
}

ExecCloseIndices(resultRelInfo);
if (close_indices)
{
ExecCloseIndices(resultRelInfo);
}
}
else if (lock_result == TM_SelfModified)
{
Expand Down Expand Up @@ -320,7 +336,7 @@ static void update_all_paths(CustomScanState *node, graphid id,
agtype_value *original_entity_value;

/* skip nulls */
if (scanTupleSlot->tts_tupleDescriptor->attrs[i].atttypid != AGTYPEOID)
if (TupleDescAttr(scanTupleSlot->tts_tupleDescriptor, i)->atttypid != AGTYPEOID)
{
continue;
}
Expand Down Expand Up @@ -435,7 +451,7 @@ static void process_update_list(CustomScanState *node)
continue;
}

if (scanTupleSlot->tts_tupleDescriptor->attrs[update_item->entity_position -1].atttypid != AGTYPEOID)
if (TupleDescAttr(scanTupleSlot->tts_tupleDescriptor, update_item->entity_position -1)->atttypid != AGTYPEOID)
{
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
Expand Down Expand Up @@ -669,7 +685,7 @@ static void process_update_list(CustomScanState *node)
}

estate->es_snapshot->curcid = cid;
/* close relation */
/* close relation */
ExecCloseIndices(resultRelInfo);
table_close(resultRelInfo->ri_RelationDesc, RowExclusiveLock);

Expand Down
4 changes: 2 additions & 2 deletions src/backend/parser/cypher_clause.c
Original file line number Diff line number Diff line change
Expand Up @@ -2729,9 +2729,9 @@ static void get_res_cols(ParseState *pstate, ParseNamespaceItem *l_pnsi,
List *colnames = NIL;
List *colvars = NIL;

expandRTE(l_pnsi->p_rte, l_pnsi->p_rtindex, 0, -1, false,
expandRTE(l_pnsi->p_rte, l_pnsi->p_rtindex, 0, VAR_RETURNING_DEFAULT, -1, false,
&l_colnames, &l_colvars);
expandRTE(r_pnsi->p_rte, r_pnsi->p_rtindex, 0, -1, false,
expandRTE(r_pnsi->p_rte, r_pnsi->p_rtindex, 0, VAR_RETURNING_DEFAULT, -1, false,
&r_colnames, &r_colvars);

/* add in all colnames and colvars from the l_rte. */
Expand Down
Loading