tests: Add a test C++ extension module master github/master
authorPeter Eisentraut <peter@eisentraut.org>
Tue, 20 Jan 2026 15:24:57 +0000 (16:24 +0100)
committerPeter Eisentraut <peter@eisentraut.org>
Tue, 20 Jan 2026 15:42:30 +0000 (16:42 +0100)
While we already test that our headers are valid C++ using
headerscheck, it turns out that the macros we define might still
expand to invalid C++ code.  This adds a minimal test extension that
is compiled using C++ to test that it's actually possible to build and
run extensions written in C++.  Future commits will improve C++
compatibility of some of our macros and add usage of them to this
extension make sure that they don't regress in the future.

The test module is for the moment disabled when using MSVC.  In
particular, the use of designated initializers in PG_MODULE_MAGIC
would require C++20, for which we are currently not set up.  (GCC and
Clang support it as extensions.)  It is planned to fix this.

Author: Jelte Fennema-Nio <postgres@jeltef.nl>
Discussion: https://www.postgresql.org/message-id/flat/CAGECzQR21OnnKiZO_1rLWO0-16kg1JBxnVq-wymYW0-_1cUNtg@mail.gmail.com

15 files changed:
configure
configure.ac
src/Makefile.global.in
src/makefiles/meson.build
src/test/modules/Makefile
src/test/modules/meson.build
src/test/modules/test_cplusplusext/.gitignore [new file with mode: 0644]
src/test/modules/test_cplusplusext/Makefile [new file with mode: 0644]
src/test/modules/test_cplusplusext/README [new file with mode: 0644]
src/test/modules/test_cplusplusext/expected/test_cplusplusext.out [new file with mode: 0644]
src/test/modules/test_cplusplusext/meson.build [new file with mode: 0644]
src/test/modules/test_cplusplusext/sql/test_cplusplusext.sql [new file with mode: 0644]
src/test/modules/test_cplusplusext/test_cplusplusext--1.0.sql [new file with mode: 0644]
src/test/modules/test_cplusplusext/test_cplusplusext.control [new file with mode: 0644]
src/test/modules/test_cplusplusext/test_cplusplusext.cpp [new file with mode: 0644]

index fb6a4914b06bf470a1f6142115c785c48d1f8d05..04eeb1a741c0bdf403aeb8efcb1f621bcc08c431 100755 (executable)
--- a/configure
+++ b/configure
@@ -760,6 +760,7 @@ CLANG
 LLVM_CONFIG
 AWK
 with_llvm
 LLVM_CONFIG
 AWK
 with_llvm
+have_cxx
 ac_ct_CXX
 CXXFLAGS
 CXX
 ac_ct_CXX
 CXXFLAGS
 CXX
@@ -4769,6 +4770,13 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $
 ac_compiler_gnu=$ac_cv_c_compiler_gnu
 
 
 ac_compiler_gnu=$ac_cv_c_compiler_gnu
 
 
+if test -n "$ac_ct_CXX"; then
+  have_cxx=yes
+else
+  have_cxx=no
+fi
+
+
 # Check if it's Intel's compiler, which (usually) pretends to be gcc,
 # but has idiosyncrasies of its own.  We assume icc will define
 # __INTEL_COMPILER regardless of CFLAGS.
 # Check if it's Intel's compiler, which (usually) pretends to be gcc,
 # but has idiosyncrasies of its own.  We assume icc will define
 # __INTEL_COMPILER regardless of CFLAGS.
index d3febfe58f1a100c613d3f1c9b7f9a239c511042..13c75170f7a6fdc91c0ab1521f030b211785cadc 100644 (file)
@@ -387,6 +387,13 @@ fi
 
 AC_PROG_CXX([$pgac_cxx_list])
 
 
 AC_PROG_CXX([$pgac_cxx_list])
 
+if test -n "$ac_ct_CXX"; then
+  have_cxx=yes
+else
+  have_cxx=no
+fi
+AC_SUBST(have_cxx)
+
 # Check if it's Intel's compiler, which (usually) pretends to be gcc,
 # but has idiosyncrasies of its own.  We assume icc will define
 # __INTEL_COMPILER regardless of CFLAGS.
 # Check if it's Intel's compiler, which (usually) pretends to be gcc,
 # but has idiosyncrasies of its own.  We assume icc will define
 # __INTEL_COMPILER regardless of CFLAGS.
index 371cd7eba2c1812ae59ca01dc75d176f79458f57..947a2d79e291767d59a232c8e9a67f8e5c8d7b25 100644 (file)
@@ -280,6 +280,8 @@ PERMIT_DECLARATION_AFTER_STATEMENT = @PERMIT_DECLARATION_AFTER_STATEMENT@
 PERMIT_MISSING_VARIABLE_DECLARATIONS = @PERMIT_MISSING_VARIABLE_DECLARATIONS@
 CXXFLAGS = @CXXFLAGS@
 
 PERMIT_MISSING_VARIABLE_DECLARATIONS = @PERMIT_MISSING_VARIABLE_DECLARATIONS@
 CXXFLAGS = @CXXFLAGS@
 
+have_cxx = @have_cxx@
+
 LLVM_CPPFLAGS = @LLVM_CPPFLAGS@
 LLVM_CFLAGS = @LLVM_CFLAGS@
 LLVM_CXXFLAGS = @LLVM_CXXFLAGS@
 LLVM_CPPFLAGS = @LLVM_CPPFLAGS@
 LLVM_CFLAGS = @LLVM_CFLAGS@
 LLVM_CXXFLAGS = @LLVM_CXXFLAGS@
index aa2f9a87b14eaebbbda9ff21cad111fbf351aad4..77f7a729cc20ef69ecf324f3c7042695b113794d 100644 (file)
@@ -118,6 +118,8 @@ pgxs_kv = {
   'FLEXFLAGS': ' '.join(flex_flags),
 
   'LIBS': var_libs,
   'FLEXFLAGS': ' '.join(flex_flags),
 
   'LIBS': var_libs,
+
+  'have_cxx': have_cxx ? 'yes' : 'no',
 }
 
 if llvm.found()
 }
 
 if llvm.found()
index 4c6d56d97d8c385621ca5265c7b268091cd9b98f..44c7163c1cd5d76fe73277d6208978b2f22eb892 100644 (file)
@@ -75,5 +75,11 @@ else
 ALWAYS_SUBDIRS += ldap_password_func
 endif
 
 ALWAYS_SUBDIRS += ldap_password_func
 endif
 
+ifeq ($(have_cxx),yes)
+SUBDIRS += test_cplusplusext
+else
+ALWAYS_SUBDIRS += test_cplusplusext
+endif
+
 $(recurse)
 $(recurse_always)
 $(recurse)
 $(recurse_always)
index 1b31c5b98d6cf2671fc7d91db96823582c14efc6..2634a519935ae96dda619923b05d7fe77cc60b90 100644 (file)
@@ -21,6 +21,7 @@ subdir('test_bitmapset')
 subdir('test_bloomfilter')
 subdir('test_cloexec')
 subdir('test_copy_callbacks')
 subdir('test_bloomfilter')
 subdir('test_cloexec')
 subdir('test_copy_callbacks')
+subdir('test_cplusplusext')
 subdir('test_custom_rmgrs')
 subdir('test_custom_stats')
 subdir('test_ddl_deparse')
 subdir('test_custom_rmgrs')
 subdir('test_custom_stats')
 subdir('test_ddl_deparse')
diff --git a/src/test/modules/test_cplusplusext/.gitignore b/src/test/modules/test_cplusplusext/.gitignore
new file mode 100644 (file)
index 0000000..913175f
--- /dev/null
@@ -0,0 +1,3 @@
+/log/
+/results/
+/tmp_check/
diff --git a/src/test/modules/test_cplusplusext/Makefile b/src/test/modules/test_cplusplusext/Makefile
new file mode 100644 (file)
index 0000000..88cd440
--- /dev/null
@@ -0,0 +1,26 @@
+# src/test/modules/test_cplusplusext/Makefile
+
+MODULE_big = test_cplusplusext
+OBJS = \
+   $(WIN32RES) \
+   test_cplusplusext.o
+PGFILEDESC = "test_cplusplusext - test C++ compatibility of PostgreSQL headers"
+
+EXTENSION = test_cplusplusext
+DATA = test_cplusplusext--1.0.sql
+
+REGRESS = test_cplusplusext
+
+# Use C++ compiler for linking because this module includes C++ files
+override COMPILER = $(CXX) $(CXXFLAGS)
+
+ifdef USE_PGXS
+PG_CONFIG = pg_config
+PGXS := $(shell $(PG_CONFIG) --pgxs)
+include $(PGXS)
+else
+subdir = src/test/modules/test_cplusplusext
+top_builddir = ../../../..
+include $(top_builddir)/src/Makefile.global
+include $(top_srcdir)/contrib/contrib-global.mk
+endif
diff --git a/src/test/modules/test_cplusplusext/README b/src/test/modules/test_cplusplusext/README
new file mode 100644 (file)
index 0000000..8e4090e
--- /dev/null
@@ -0,0 +1,10 @@
+test_cplusplusext - Test C++ Extension Compatibility
+====================================================
+
+This test module verifies that PostgreSQL headers and macros work
+correctly when compiled with a C++ compiler.
+
+While PostgreSQL already tests that headers are syntactically valid
+C++ using headerscheck, the macros defined in those headers might
+still expand to invalid C++ code.  This module catches such issues by
+actually compiling and running an extension that's written in C++.
diff --git a/src/test/modules/test_cplusplusext/expected/test_cplusplusext.out b/src/test/modules/test_cplusplusext/expected/test_cplusplusext.out
new file mode 100644 (file)
index 0000000..ab0b04b
--- /dev/null
@@ -0,0 +1,7 @@
+CREATE EXTENSION test_cplusplusext;
+SELECT test_cplusplus_add(1, 2);
+ test_cplusplus_add 
+--------------------
+                  3
+(1 row)
+
diff --git a/src/test/modules/test_cplusplusext/meson.build b/src/test/modules/test_cplusplusext/meson.build
new file mode 100644 (file)
index 0000000..d13210c
--- /dev/null
@@ -0,0 +1,42 @@
+# Copyright (c) 2025-2026, PostgreSQL Global Development Group
+
+if not have_cxx
+  subdir_done()
+endif
+
+# Currently not supported, to be fixed.
+if cc.get_id() == 'msvc'
+  subdir_done()
+endif
+
+test_cplusplusext_sources = files(
+  'test_cplusplusext.cpp',
+)
+
+if host_system == 'windows'
+  test_cplusplusext_sources += rc_lib_gen.process(win32ver_rc, extra_args: [
+    '--NAME', 'test_cplusplusext',
+    '--FILEDESC', 'test_cplusplusext - test C++ compatibility of PostgreSQL headers',])
+endif
+
+test_cplusplusext = shared_module('test_cplusplusext',
+  test_cplusplusext_sources,
+  kwargs: pg_test_mod_args,
+)
+test_install_libs += test_cplusplusext
+
+test_install_data += files(
+  'test_cplusplusext.control',
+  'test_cplusplusext--1.0.sql',
+)
+
+tests += {
+  'name': 'test_cplusplusext',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'test_cplusplusext',
+    ],
+  },
+}
diff --git a/src/test/modules/test_cplusplusext/sql/test_cplusplusext.sql b/src/test/modules/test_cplusplusext/sql/test_cplusplusext.sql
new file mode 100644 (file)
index 0000000..a416824
--- /dev/null
@@ -0,0 +1,3 @@
+CREATE EXTENSION test_cplusplusext;
+
+SELECT test_cplusplus_add(1, 2);
diff --git a/src/test/modules/test_cplusplusext/test_cplusplusext--1.0.sql b/src/test/modules/test_cplusplusext/test_cplusplusext--1.0.sql
new file mode 100644 (file)
index 0000000..c54acb7
--- /dev/null
@@ -0,0 +1,8 @@
+/* src/test/modules/test_cplusplusext/test_cplusplusext--1.0.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION test_cplusplusext" to load this file. \quit
+
+CREATE FUNCTION test_cplusplus_add(int4, int4) RETURNS int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT;
diff --git a/src/test/modules/test_cplusplusext/test_cplusplusext.control b/src/test/modules/test_cplusplusext/test_cplusplusext.control
new file mode 100644 (file)
index 0000000..640a0a5
--- /dev/null
@@ -0,0 +1,4 @@
+comment = 'Test module for C++ extension compatibility'
+default_version = '1.0'
+module_pathname = '$libdir/test_cplusplusext'
+relocatable = true
diff --git a/src/test/modules/test_cplusplusext/test_cplusplusext.cpp b/src/test/modules/test_cplusplusext/test_cplusplusext.cpp
new file mode 100644 (file)
index 0000000..435937c
--- /dev/null
@@ -0,0 +1,37 @@
+/*--------------------------------------------------------------------------
+ *
+ * test_cplusplusext.cpp
+ *     Test that PostgreSQL headers compile with a C++ compiler.
+ *
+ * This file is compiled with a C++ compiler to verify that PostgreSQL
+ * headers remain compatible with C++ extensions.
+ *
+ * Copyright (c) 2025-2026, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ *     src/test/modules/test_cplusplusext/test_cplusplusext.cpp
+ *
+ * -------------------------------------------------------------------------
+ */
+
+extern "C" {
+#include "postgres.h"
+#include "fmgr.h"
+
+PG_MODULE_MAGIC;
+
+PG_FUNCTION_INFO_V1(test_cplusplus_add);
+}
+
+/*
+ * Simple function that returns the sum of two integers.  This verifies that
+ * C++ extension modules can be loaded and called correctly at runtime.
+ */
+extern "C" Datum
+test_cplusplus_add(PG_FUNCTION_ARGS)
+{
+   int32       a = PG_GETARG_INT32(0);
+   int32       b = PG_GETARG_INT32(1);
+
+   PG_RETURN_INT32(a + b);
+}