diff --git a/.github/workflows/buildimage.yml b/.github/workflows/buildimage.yml index 647bc86e..55c0624f 100644 --- a/.github/workflows/buildimage.yml +++ b/.github/workflows/buildimage.yml @@ -21,8 +21,10 @@ jobs: name: Build for Darwin x86_64 runs-on: macos-15-intel steps: - - name: Install PostgreSQL@14 - run: brew install --force postgresql@14 + - name: Install PostgreSQL@18 + run: |- + brew install --force postgresql@18 + echo "$(brew --prefix postgresql@18)/bin" >> "$GITHUB_PATH" - name: PGConfig run: |- @@ -112,6 +114,7 @@ jobs: - name: gzip the steampipe_postgres_fdw.so run: |- + if [ -f build-Darwin/steampipe_postgres_fdw.dylib ]; then mv build-Darwin/steampipe_postgres_fdw.dylib build-Darwin/steampipe_postgres_fdw.so; fi gzip build-Darwin/steampipe_postgres_fdw.so mv build-Darwin/steampipe_postgres_fdw.so.gz build-Darwin/steampipe_postgres_fdw.so.darwin_amd64.gz @@ -140,8 +143,10 @@ jobs: name: Build for Darwin ARM64 runs-on: macos-latest steps: - - name: Install PostgreSQL@14 - run: brew install --force postgresql@14 + - name: Install PostgreSQL@18 + run: |- + brew install --force postgresql@18 + echo "$(brew --prefix postgresql@18)/bin" >> "$GITHUB_PATH" - name: PGConfig run: |- @@ -231,6 +236,7 @@ jobs: - name: gzip the steampipe_postgres_fdw.so run: |- + if [ -f build-Darwin/steampipe_postgres_fdw.dylib ]; then mv build-Darwin/steampipe_postgres_fdw.dylib build-Darwin/steampipe_postgres_fdw.so; fi gzip build-Darwin/steampipe_postgres_fdw.so mv build-Darwin/steampipe_postgres_fdw.so.gz build-Darwin/steampipe_postgres_fdw.so.darwin_arm64.gz @@ -280,9 +286,9 @@ jobs: sudo env ACCEPT_EULA=Y apt-get update sudo env ACCEPT_EULA=Y apt-get upgrade - - name: Install PostgreSQL14 Dev + - name: Install PostgreSQL18 Dev run: |- - sudo apt-get -y install postgresql-server-dev-14 + sudo apt-get -y install postgresql-server-dev-18 - name: Find stuff and set env run: |- @@ -293,7 +299,7 @@ jobs: export PATH=$(pg_config --bindir):$PATH export PGXS=$(pg_config --pgxs) - export SERVER_LIB=$(pg_config --includedir)/14/server + export SERVER_LIB=$(pg_config --includedir)/18/server export INTERNAL_LIB=$(pg_config --includedir)/internal export CFLAGS="$(pg_config --cflags) -I${SERVER_LIB} -I${INTERNAL_LIB} -g" @@ -365,9 +371,9 @@ jobs: sudo env ACCEPT_EULA=Y apt-get update sudo env ACCEPT_EULA=Y apt-get upgrade - - name: Install PostgreSQL14 Dev + - name: Install PostgreSQL18 Dev run: |- - sudo apt-get -y install postgresql-server-dev-14 + sudo apt-get -y install postgresql-server-dev-18 - name: Find stuff and set env run: |- @@ -378,7 +384,7 @@ jobs: export PATH=$(pg_config --bindir):$PATH export PGXS=$(pg_config --pgxs) - export SERVER_LIB=$(pg_config --includedir)/14/server + export SERVER_LIB=$(pg_config --includedir)/18/server export INTERNAL_LIB=$(pg_config --includedir)/internal export CFLAGS="$(pg_config --cflags) -I${SERVER_LIB} -I${INTERNAL_LIB} -g" diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c953db6..d1dff7ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## v2.3.0 [2026-06-10] +_Whats new_ +- Add support for building against PostgreSQL 18. Localized, version-guarded source changes: include `commands/explain_format.h` (PG18 EXPLAIN header split) and use `PathKey.pk_cmptype`/`COMPARE_GT` instead of `pk_strategy`/`BTGreaterStrategyNumber` (both `#if PG_VERSION_NUM >= 180000`); and pass the extra `create_foreignscan_path` arguments — `fdw_restrictinfo` (added in PostgreSQL 17, `#if PG_VERSION_NUM >= 170000`) and `disabled_nodes` (added in PostgreSQL 18, `#if PG_VERSION_NUM >= 180000`). Behaviour on PostgreSQL 16 and earlier is unchanged. +- Handle nested `RestrictInfo` nodes in `pull_var_clause` on PostgreSQL 18 — multi-table JOINs on foreign tables failed with `unrecognized node type: 318` without this. (`#if PG_VERSION_NUM >= 180000`; no change on earlier versions.) + ## v2.2.4 [2026-05-25] _Bug fixes_ - Fix `statement_timeout`, `pg_cancel_backend`, and `pg_terminate_backend` having no effect when a plugin's gRPC stream stalls — a hung scan held `AccessShareLock` indefinitely, blocking partition swaps and other DDL until restart. ([#671](https://github.com/turbot/steampipe-postgres-fdw/issues/671), [#672](https://github.com/turbot/steampipe-postgres-fdw/pull/672)) diff --git a/fdw/Makefile b/fdw/Makefile index fb9508bc..e85b7ccc 100644 --- a/fdw/Makefile +++ b/fdw/Makefile @@ -58,11 +58,11 @@ inst: mkdir -p ../build-${PLATFORM} rm -f ../build-${PLATFORM}/* - cp steampipe_postgres_fdw.so ../build-${PLATFORM} + @if [ -f steampipe_postgres_fdw.dylib ]; then cp steampipe_postgres_fdw.dylib ../build-${PLATFORM}/steampipe_postgres_fdw.so; else cp steampipe_postgres_fdw.so ../build-${PLATFORM}/steampipe_postgres_fdw.so; fi cp steampipe_postgres_fdw.control ../build-${PLATFORM} cp steampipe_postgres_fdw--1.0.sql ../build-${PLATFORM} - - rm steampipe_postgres_fdw.so + + rm -f steampipe_postgres_fdw.so steampipe_postgres_fdw.dylib rm steampipe_postgres_fdw.a rm steampipe_postgres_fdw.h diff --git a/fdw/common.h b/fdw/common.h index 209bafec..f7385099 100644 --- a/fdw/common.h +++ b/fdw/common.h @@ -6,6 +6,10 @@ #include "catalog/pg_type.h" #include "commands/defrem.h" #include "commands/explain.h" +#if PG_VERSION_NUM >= 180000 +/* PG18 moved the EXPLAIN property-output API into a separate header */ +#include "commands/explain_format.h" +#endif #include "foreign/fdwapi.h" #include "foreign/foreign.h" #include "funcapi.h" diff --git a/fdw/fdw.c b/fdw/fdw.c index 8401d3fe..e28ac706 100644 --- a/fdw/fdw.c +++ b/fdw/fdw.c @@ -436,11 +436,17 @@ static void fdwGetForeignPaths(PlannerInfo *root, RelOptInfo *baserel, Oid forei baserel, NULL, /* default pathtarget */ baserel->rows, +#if PG_VERSION_NUM >= 180000 + 0, /* disabled_nodes (PG18) */ +#endif planstate->startupCost, baserel->rows * baserel->reltarget->width * 100000, // table scan is very expensive NIL, /* no pathkeys */ NULL, NULL, +#if PG_VERSION_NUM >= 170000 + NIL, /* fdw_restrictinfo (added in PG17) */ +#endif (void *)fdw_private)); /* Add each ForeignPath previously found */ @@ -458,9 +464,15 @@ static void fdwGetForeignPaths(PlannerInfo *root, RelOptInfo *baserel, Oid forei baserel, NULL, /* default pathtarget */ path->path.rows, +#if PG_VERSION_NUM >= 180000 + 0, /* disabled_nodes (PG18) */ +#endif path->path.startup_cost, path->path.total_cost, apply_pathkeys, NULL, NULL, +#if PG_VERSION_NUM >= 170000 + NIL, /* fdw_restrictinfo (added in PG17) */ +#endif (void *)fdw_private); newpath->path.param_info = path->path.param_info; add_path(baserel, (Path *)newpath); diff --git a/fdw/query.c b/fdw/query.c index 7452e6ca..738df9f8 100644 --- a/fdw/query.c +++ b/fdw/query.c @@ -13,6 +13,7 @@ #include "catalog/pg_operator.h" #include "mb/pg_wchar.h" #include "nodes/makefuncs.h" +#include "nodes/nodeFuncs.h" #include "utils/lsyscache.h" #include "miscadmin.h" #include "parser/parsetree.h" @@ -24,6 +25,34 @@ #define get_attname(x, y) get_attname(x, y, true) #endif +#if PG_VERSION_NUM >= 180000 +/* + * PG18 dropped the T_RestrictInfo case from expression_tree_walker + * (src/backend/nodes/nodeFuncs.c). When the FDW walks a clause subtree + * that contains a nested RestrictInfo (the orclause cache, certain + * join-equivalence-class derived predicates), the walker hits the + * unrecognized node tag (318) and elogs + * "unrecognized node type: 318". Restore the PG<=17 behaviour with a + * pre-pass mutator that replaces each RestrictInfo with its wrapped + * clause before pull_var_clause's walker sees it. + */ +static Node * +strip_restrictinfo_mutator(Node *node, void *context) +{ + if (node == NULL) + return NULL; + if (IsA(node, RestrictInfo)) + return strip_restrictinfo_mutator( + (Node *) ((RestrictInfo *) node)->clause, context); + return expression_tree_mutator(node, strip_restrictinfo_mutator, context); +} +#define PULL_VAR_CLAUSE_PG18_SAFE(node, flags) \ + pull_var_clause(strip_restrictinfo_mutator((node), NULL), (flags)) +#else +#define PULL_VAR_CLAUSE_PG18_SAFE(node, flags) \ + pull_var_clause((node), (flags)) +#endif + char *getOperatorString(Oid opoid); Node *unnestClause(Node *node); @@ -59,7 +88,7 @@ extractColumns(List *reltargetlist, List *restrictinfolist) List *targetcolumns; Node *node = (Node *)lfirst(lc); - targetcolumns = pull_var_clause(node, + targetcolumns = PULL_VAR_CLAUSE_PG18_SAFE(node, #if PG_VERSION_NUM >= 90600 PVC_RECURSE_AGGREGATES | PVC_RECURSE_PLACEHOLDERS); @@ -74,7 +103,7 @@ extractColumns(List *reltargetlist, List *restrictinfolist) { List *targetcolumns; RestrictInfo *node = (RestrictInfo *)lfirst(lc); - targetcolumns = pull_var_clause((Node *)node->clause, + targetcolumns = PULL_VAR_CLAUSE_PG18_SAFE((Node *)node->clause, #if PG_VERSION_NUM >= 90600 PVC_RECURSE_AGGREGATES | PVC_RECURSE_PLACEHOLDERS); @@ -341,7 +370,7 @@ colnameFromVar(Var *var, PlannerInfo *root, FdwPlanState *planstate) */ bool isAttrInRestrictInfo(Index relid, AttrNumber attno, RestrictInfo *restrictinfo) { - List *vars = pull_var_clause((Node *)restrictinfo->clause, + List *vars = PULL_VAR_CLAUSE_PG18_SAFE((Node *)restrictinfo->clause, #if PG_VERSION_NUM >= 90600 PVC_RECURSE_AGGREGATES | PVC_RECURSE_PLACEHOLDERS); @@ -528,6 +557,9 @@ findPaths(PlannerInfo *root, RelOptInfo *baserel, List *possiblePaths, NULL, /* default pathtarget */ #endif nbrows, +#if PG_VERSION_NUM >= 180000 + 0, /* disabled_nodes (PG18) */ +#endif startupCost, #if PG_VERSION_NUM >= 90600 nbrows * baserel->reltarget->width, @@ -538,6 +570,9 @@ findPaths(PlannerInfo *root, RelOptInfo *baserel, List *possiblePaths, NULL, #if PG_VERSION_NUM >= 90500 NULL, +#endif +#if PG_VERSION_NUM >= 170000 + NIL, /* fdw_restrictinfo (added in PG17) */ #endif NULL); @@ -574,7 +609,11 @@ deparse_sortgroup(PlannerInfo *root, Oid foreigntableid, RelOptInfo *rel) if ((expr = fdw_get_em_expr(ec, rel))) { +#if PG_VERSION_NUM >= 180000 + md->reversed = (key->pk_cmptype == COMPARE_GT); +#else md->reversed = (key->pk_strategy == BTGreaterStrategyNumber); +#endif md->nulls_first = key->pk_nulls_first; md->key = key; diff --git a/version/version.go b/version/version.go index db45b9da..083a78e0 100644 --- a/version/version.go +++ b/version/version.go @@ -11,7 +11,7 @@ import ( ) // The main version number that is being run at the moment. -var fdwVersion = "2.2.4" +var fdwVersion = "2.3.0" // A pre-release marker for the version. If this is "" (empty string) // then it means that it is a final release. Otherwise, this is a pre-release