[prev in list] [next in list] [prev in thread] [next in thread] 

List:       pgsql-hackers
Subject:    Re: [RFC] building postgres with meson -v
From:       Andres Freund <andres () anarazel ! de>
Date:       2021-10-31 23:24:48
Message-ID: 20211031232448.wsma7sggfwyxppjc () alap3 ! anarazel ! de
[Download RAW message or body]

Hi,

Attached is an updated version of the meson patchset.

Changes:

- support for remaining binaries in src/bin, contrib modules

- nearly all tests, including src/test/modules etc, are integrated.

- quite a few more, but not yet all, optional dependencies (most are
  exercised in the included CI)

- runs tests on SIP enabled macos without needing a prior installation /
  installation is relocatable

- support for building docs.
  I couldn't get dbtoepub work in a vpath style build, so I changed that
  to also use pandoc. No idea if anybody uses the epub rules?

- 32bit x86 [1], 64bit aarch64 builds

- cross-building windows from linux works

- error when building with meson against a source tree with an in-tree
  autoconf build (leads to problems with pg_config.h etc)

- update-unicode, reformat-dat-files, expand-dat-files


Bigger missing pieces:

- pgxs (that's a *hard* one)

- NLS

- test / add support for platforms besides freebsd, linux, macos, windows

- remaining hardcoded configure tests (e.g. ACCEPT_TYPE_ARG*)

- win32 resource files only handled for two binaries, needs to be made
  more compact

- ecpg

- fixing up flex output

- truckloads of polishing

- some tests (e.g. pg_upgrade, because of the upcoming tap conversion,
  other tests that are shell scripts). Some tests are now run
  unconditionally that previously were opt-in.

- what exactly gets installed where

- a "dist" target

- fix "ldap" build on macos


Greetings,

Andres Freund

[1] I had not defined SIZEOF_SIZE_T. Surprisingly that still results in
a successful 64bit build, but not a successful 32bit build.

["v5-0001-ci-backend-windows-DONTMERGE-crash-reporting-back.patch" (text/x-diff)]

From 48d06672d142ffed46faaf0ab4d2fece67534dce Mon Sep 17 00:00:00 2001
From: Andres Freund <andres@anarazel.de>
Date: Thu, 9 Sep 2021 17:49:39 -0700
Subject: [PATCH v5 01/16] ci: backend: windows: DONTMERGE: crash reporting
 (backend).

---
 src/backend/main/main.c | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/src/backend/main/main.c b/src/backend/main/main.c
index ad84a45e28c..65a325723fd 100644
--- a/src/backend/main/main.c
+++ b/src/backend/main/main.c
@@ -26,6 +26,10 @@
 #include <sys/param.h>
 #endif
 
+#if defined(WIN32)
+#include <crtdbg.h>
+#endif
+
 #if defined(_M_AMD64) && _MSC_VER == 1800
 #include <math.h>
 #include <versionhelpers.h>
@@ -238,7 +242,15 @@ startup_hacks(const char *progname)
 		}
 
 		/* In case of general protection fault, don't show GUI popup box */
-		SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
+		SetErrorMode(SEM_FAILCRITICALERRORS /* | SEM_NOGPFAULTERRORBOX */);
+
+		_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
+		_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
+		_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
+		_CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
+#ifndef __MINGW64__
+		_set_abort_behavior(_CALL_REPORTFAULT | _WRITE_ABORT_MSG, _CALL_REPORTFAULT | _WRITE_ABORT_MSG);
+#endif
 
 #if defined(_M_AMD64) && _MSC_VER == 1800
 
-- 
2.23.0.385.gbc12974a89


["v5-0002-ci-Add-CI-for-FreeBSD-Linux-MacOS-and-Windows-uti.patch" (text/x-diff)]

From 2e4bba81f06ab55fad639e9657b71c5db98b6252 Mon Sep 17 00:00:00 2001
From: Andres Freund <andres@anarazel.de>
Date: Mon, 15 Mar 2021 09:25:15 -0700
Subject: [PATCH v5 02/16] ci: Add CI for FreeBSD, Linux, MacOS and Windows,
 utilizing cirrus-ci.

---
 .cirrus.yml                     | 395 ++++++++++++++++++++++++++++++++
 .dockerignore                   |   3 +
 ci/docker/linux_debian_bullseye |  13 ++
 ci/docker/windows_vs_2019       | 111 +++++++++
 ci/freebsd_gcp_repartition.sh   |  28 +++
 ci/pg_ci_base.conf              |  12 +
 ci/windows_build_config.pl      |  13 ++
 7 files changed, 575 insertions(+)
 create mode 100644 .cirrus.yml
 create mode 100644 .dockerignore
 create mode 100644 ci/docker/linux_debian_bullseye
 create mode 100644 ci/docker/windows_vs_2019
 create mode 100755 ci/freebsd_gcp_repartition.sh
 create mode 100644 ci/pg_ci_base.conf
 create mode 100644 ci/windows_build_config.pl

diff --git a/.cirrus.yml b/.cirrus.yml
new file mode 100644
index 00000000000..f75bdce6dec
--- /dev/null
+++ b/.cirrus.yml
@@ -0,0 +1,395 @@
+env:
+  # accelerate initial clone, but a bit of depth so that concurrent tasks work
+  CIRRUS_CLONE_DEPTH: 100
+  # Useful to be able to analyse what in a script takes long
+  CIRRUS_LOG_TIMESTAMP: true
+  # target to test, for all but windows
+  CHECK: check-world
+  CHECKFLAGS: -Otarget
+  PGCTLTIMEOUT: 120
+  CCACHE_MAXSIZE: "500M"
+  TEMP_CONFIG: ${CIRRUS_WORKING_DIR}/ci/pg_ci_base.conf
+  PG_TEST_EXTRA: kerberos ldap ssl
+
+
+task:
+  name: FreeBSD
+  only_if: $CIRRUS_CHANGE_MESSAGE !=~ '.*\nci-os-only:.*' || $CIRRUS_CHANGE_MESSAGE \
=~ '.*\nci-os-only:[^\n]*freebsd.*' +  compute_engine_instance:
+    image_project: pg-vm-images-aio
+    image: family/pg-aio-freebsd-13-0
+    platform: freebsd
+    cpu: 2
+    memory: 2G
+    disk: 50
+  env:
+    CCACHE_DIR: "/tmp/ccache_dir"
+
+  ccache_cache:
+    folder: "/tmp/ccache_dir"
+  sysinfo_script:
+    - export || true
+  sysconfig_script:
+    - sudo sysctl kern.corefile='/tmp/%N.%P.core'
+  repartition_script:
+    - ci/freebsd_gcp_repartition.sh
+  create_user_script:
+    - pw useradd postgres
+    - chown -R postgres:postgres .
+    - mkdir -p /tmp/ccache_dir
+    - chown -R postgres:postgres /tmp/ccache_dir
+
+  configure_script: |
+    su postgres -c './configure \
+      --enable-cassert --enable-debug --enable-tap-tests \
+      --enable-nls \
+      \
+      --with-icu \
+      --with-ldap \
+      --with-libxml \
+      --with-libxslt \
+      \
+      --with-lz4 \
+      --with-pam \
+      --with-perl \
+      --with-python \
+      --with-ssl=openssl \
+      --with-tcl --with-tclconfig=/usr/local/lib/tcl8.6/ \
+      --with-uuid=bsd \
+      \
+      --with-includes=/usr/local/include --with-libs=/usr/local/lib \
+      CC="ccache cc"'
+  build_script:
+    - su postgres -c 'gmake -s -j3 && gmake -s -j3 -C contrib'
+  upload_caches:
+    - ccache
+
+  tests_script:
+    - su postgres -c 'time gmake -s -j2 ${CHECK} ${CHECKFLAGS}'
+
+  on_failure:
+    cores_script: |
+      for corefile in $(find /tmp -name '*.core' 2>/dev/null) ; do
+        binary=$(gdb -quiet -core $corefile -batch -ex 'info auxv' | grep \
AT_EXECPATH | perl -pe "s/^.*\"(.*)\"\$/\$1/g") ; +        echo dumping $corefile for \
$binary ; +        gdb --batch --quiet -ex "thread apply all bt full" -ex "quit" \
$binary $corefile; +      done
+    log_artifacts:
+      path: "**/**.log"
+      type: text/plain
+    regress_diffs_artifacts:
+      path: "**/**.diffs"
+      type: text/plain
+    tap_artifacts:
+      path: "**/regress_log_*"
+      type: text/plain
+
+
+task:
+  name: Linux
+  only_if: $CIRRUS_CHANGE_MESSAGE !=~ '.*\nci-os-only:.*' || $CIRRUS_CHANGE_MESSAGE \
=~ '.*\nci-os-only:[^\n]*linux.*' +  compute_engine_instance:
+    image_project: pg-vm-images-aio
+    image: family/pg-aio-bullseye
+    platform: linux
+    cpu: 4
+    memory: 2G
+    nested_virtualization: false
+  env:
+    CCACHE_DIR: "/tmp/ccache_dir"
+    DEBUGINFOD_URLS: "https://debuginfod.debian.net"
+
+  ccache_cache:
+    folder: "/tmp/ccache_dir"
+
+  sysinfo_script:
+    - id
+    - uname -a
+    - cat /proc/cmdline
+    - lsblk
+    - ulimit -a -H
+    - ulimit -a -S
+    - export
+  sysconfig_script:
+    - useradd -m postgres
+    - chown -R postgres:postgres .
+    - mkdir -p /tmp/ccache_dir
+    - chown -R postgres:postgres /tmp/ccache_dir
+    - echo '* - memlock 134217728' > /etc/security/limits.d/postgres.conf
+    - su postgres -c 'ulimit -l -H'
+    - su postgres -c 'ulimit -l -S'
+    - echo '/tmp/%e-%s-%p.core' > /proc/sys/kernel/core_pattern
+
+  configure_script: |
+    su postgres -c './configure \
+      --enable-cassert --enable-debug --enable-tap-tests \
+      --enable-nls \
+      \
+      --with-gssapi \
+      --with-icu \
+      --with-ldap \
+      --with-libxml \
+      --with-libxslt \
+      --with-llvm \
+      --with-lz4 \
+      --with-pam \
+      --with-perl \
+      --with-python \
+      --with-ssl=openssl \
+      --with-systemd \
+      --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ \
+      --with-uuid=e2fs \
+      \
+      CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" CFLAGS="-O0 -ggdb"'
+  build_script:
+    - su postgres -c 'make -s -j4 && make -s -j4 -C contrib'
+  upload_caches:
+    - ccache
+
+  tests_script: |
+    su postgres -c '\
+      ulimit -c unlimited; \
+      make -s ${CHECK} ${CHECKFLAGS} -j8 \
+      '
+
+  on_failure:
+    cores_script: |
+      for corefile in $(find /tmp -name '*.core' 2>/dev/null) ; do
+        binary=$(gdb -quiet -core $corefile -batch -ex 'info auxv' | grep AT_EXECFN \
| perl -pe "s/^.*\"(.*)\"\$/\$1/g") ; +        echo dumping $corefile for $binary ;
+        gdb --batch --quiet -ex "thread apply all bt full" -ex "quit" $binary \
$corefile ; +      done
+    log_artifacts:
+      path: "**/**.log"
+      type: text/plain
+    regress_diffs_artifacts:
+      path: "**/**.diffs"
+      type: text/plain
+    tap_artifacts:
+      path: "**/regress_log_*"
+      type: text/plain
+
+
+task:
+  name: macOS
+  only_if: $CIRRUS_CHANGE_MESSAGE !=~ '.*\nci-os-only:.*' || $CIRRUS_CHANGE_MESSAGE \
=~ '.*\nci-os-only:[^\n]*(macos|darwin|osx).*' +  osx_instance:
+    image: big-sur-base
+  env:
+    CIRRUS_WORKING_DIR: ${HOME}/pgsql/
+    TEMP_CONFIG: ${CIRRUS_WORKING_DIR}/ci/pg_ci_base.conf
+    CCACHE_DIR: ${HOME}/ccache
+    HOMEBREW_CACHE: ${HOME}/homebrew-cache
+    PERL5LIB: ${HOME}/perl5/lib/perl5
+
+  sysinfo_script:
+    - id
+    - export
+  ccache_cache:
+    folder: ${CCACHE_DIR}
+  homebrew_cache:
+    folder: ${HOMEBREW_CACHE}
+  perl_cache:
+    folder: ~/perl5
+
+  cpan_install_script:
+    - perl -mIPC::Run -e 1 || cpan -T IPC::Run
+    - perl -mIO::Pty -e 1 || cpan -T IO::Pty
+  upload_caches:
+    - perl
+  core_install_script:
+    - sudo chmod 777 /cores
+  homebrew_install_script:
+    - brew install make coreutils ccache icu4c lz4 tcl-tk openldap
+  upload_caches:
+    - homebrew
+
+  configure_script: |
+    LIBS="/usr/local/lib:$LIBS"
+    INCLUDES="/usr/local/include:$INCLUDES"
+
+    INCLUDES="/usr/local/opt/openssl/include:$INCLUDES"
+    LIBS="/usr/local/opt/openssl/lib:$LIBS"
+
+    PKG_CONFIG_PATH="/usr/local/opt/icu4c/lib/pkgconfig:$PKG_CONFIG_PATH"
+    INCLUDES="/usr/local/opt/icu4c/include:$INCLUDES"
+    LIBS="/usr/local/opt/icu4c/lib:$LIBS"
+
+    LIBS="/usr/local/opt/openldap/lib:$LIBS"
+    INCLUDES="/usr/local/opt/openldap/include:$INCLUDES"
+
+    export PKG_CONFIG_PATH
+
+    ./configure \
+      --prefix=$HOME/install \
+      --with-includes="$INCLUDES" \
+      --with-libs="$LIBS" \
+      \
+      --enable-cassert --enable-debug --enable-tap-tests \
+      --enable-nls \
+      \
+      --with-icu \
+      --with-ldap \
+      --with-libxml \
+      --with-libxslt \
+      \
+      --with-lz4 \
+      --with-perl \
+      --with-python \
+      --with-ssl=openssl \
+      --with-tcl --with-tclconfig=/usr/local/opt/tcl-tk/lib/ \
+      --with-uuid=e2fs \
+      \
+      CC="ccache gcc" CFLAGS="-O0 -ggdb"
+  build_script:
+    - gmake -s -j12 && gmake -s -j12 -C contrib
+  upload_caches:
+    - ccache
+
+  tests_script:
+    - ulimit -c unlimited
+    - ulimit -n 1024
+    - gmake -s -j12 ${CHECK} ${CHECKFLAGS}
+
+  on_failure:
+    cores_script: |
+      for corefile in $(find /cores/ -name 'core.*' 2>/dev/null) ; do
+        lldb -c $corefile --batch -o 'thread backtrace all' -o 'quit' ;
+      done
+    log_artifacts:
+      path: "**/**.log"
+      type: text/plain
+    regress_diffs_artifacts:
+      path: "**/**.diffs"
+      type: text/plain
+    tap_artifacts:
+      path: "**/regress_log_*"
+      type: text/plain
+
+
+task:
+  name: Windows
+  only_if: $CIRRUS_CHANGE_MESSAGE !=~ '.*\nci-os-only:.*' || $CIRRUS_CHANGE_MESSAGE \
=~ '.*\nci-os-only:[^\n]*windows.*' +  windows_container:
+    dockerfile: ci/docker/windows_vs_2019
+    cpu: 4
+    memory: 4G
+  env:
+    PROVE_FLAGS: -j10
+    # The default working dir is in a directory msbuild complains about
+    CIRRUS_WORKING_DIR: "c:/cirrus"
+    TEMP_CONFIG: ${CIRRUS_WORKING_DIR}/ci/pg_ci_base.conf
+    # Avoid re-installing over and over
+    NO_TEMP_INSTALL: 1
+
+  sysinfo_script:
+    - chcp
+    - systeminfo
+    - powershell -Command get-psdrive -psprovider filesystem
+    - ps: Get-Item -Path 'HKLM:\SOFTWARE\Microsoft\Windows \
NT\CurrentVersion\AeDebug' +    - set
+
+  configure_script:
+    - copy ci\windows_build_config.pl src\tools\msvc\config.pl
+    - vcvarsall x64
+    - perl src/tools/msvc/mkvcbuild.pl
+  build_script:
+    - vcvarsall x64
+    # Disable file tracker, we're never going to rebuild...
+    - msbuild -m /p:TrackFileAccess=false pgsql.sln
+  tempinstall_script:
+    # Installation on windows currently only completely works from src\tools\msvc
+    - cd src\tools\msvc && perl .\install.pl %CIRRUS_WORKING_DIR%\tmp_install
+
+  check_test_script:
+    - perl src/tools/msvc/vcregress.pl check parallel
+  startcreate_test_script:
+    - tmp_install\bin\pg_ctl.exe initdb -D tmp_check\db -l tmp_check\initdb.log
+    - echo include '%TEMP_CONFIG%' >> tmp_check\db\postgresql.conf
+    - tmp_install\bin\pg_ctl.exe start -D tmp_check\db -l tmp_check\postmaster.log
+  plcheck_test_script:
+    - perl src/tools/msvc/vcregress.pl plcheck
+  isolationcheck_test_script:
+    - perl src/tools/msvc/vcregress.pl isolationcheck
+  modulescheck_test_script:
+    - perl src/tools/msvc/vcregress.pl modulescheck
+  contribcheck_test_script:
+    - perl src/tools/msvc/vcregress.pl contribcheck
+  stop_test_script:
+    - tmp_install\bin\pg_ctl.exe stop -D tmp_check\db -l tmp_check\postmaster.log
+  ssl_test_script:
+    - set with_ssl=openssl
+    - perl src/tools/msvc/vcregress.pl taptest .\src\test\ssl\
+  subscriptioncheck_test_script:
+    - perl src/tools/msvc/vcregress.pl taptest .\src\test\subscription\
+  authentication_test_script:
+    - perl src/tools/msvc/vcregress.pl taptest .\src\test\authentication\
+  recoverycheck_test_script:
+    - perl src/tools/msvc/vcregress.pl recoverycheck
+  bincheck_test_script:
+    - perl src/tools/msvc/vcregress.pl bincheck
+  upgradecheck_test_script:
+    - perl src/tools/msvc/vcregress.pl upgradecheck
+  ecpgcheck_test_script:
+    # tries to build additional stuff
+    - vcvarsall x64
+    # References ecpg_regression.proj in the current dir
+    - cd src\tools\msvc
+    - perl vcregress.pl ecpgcheck
+
+  always:
+    cores_script:
+      - cat crashlog.txt || true
+    dump_artifacts:
+      path: "crashlog.txt"
+      type: text/plain
+
+  on_failure:
+    log_artifacts:
+      path: "**/**.log"
+      type: text/plain
+    regress_diffs_artifacts:
+      path: "**/**.diffs"
+      type: text/plain
+    tap_artifacts:
+      path: "**/regress_log_*"
+      type: text/plain
+
+
+task:
+  name: CompilerWarnings
+  depends_on:
+    - Linux
+  # task that did not run count as a success, so we need to recheck Linux' condition \
here :/ +  only_if: $CIRRUS_CHANGE_MESSAGE !=~ '.*\nci-os-only:.*' || \
$CIRRUS_CHANGE_MESSAGE =~ '.*\nci-os-only:[^\n]*linux.*' +  container:
+    dockerfile: ci/docker/linux_debian_bullseye
+  env:
+    CCACHE_SIZE: "4GB"
+    CCACHE_DIR: "/tmp/ccache_dir"
+  ccache_cache:
+    folder: "/tmp/ccache_dir"
+  setup_script:
+    - echo "COPT=-Werror" > src/Makefile.custom
+    - gcc -v
+    - clang -v
+  # gcc with asserts disabled
+  always:
+    gcc_warning_script:
+      - ./configure --cache gcc.cache CC="ccache gcc"
+      - time make -s -j4 clean && time make -s -j4
+  # gcc with asserts enabled
+  always:
+    gcc_a_warning_script:
+      - ./configure --cache gcc.cache --enable-cassert CC="ccache gcc"
+      - time make -s -j4 clean && time make -s -j4
+  # clang with asserts disabled
+  always:
+    clang_warning_script:
+      - ./configure --cache clang.cache CC="ccache clang"
+      - time make -s -j4 clean && time make -s -j4
+  # clang with asserts enabled
+  always:
+    clang_a_warning_script:
+      - ./configure --cache clang.cache --enable-cassert CC="ccache clang"
+      - time make -s -j4 clean && time make -s -j4
diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 00000000000..3fceab2e97b
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,3 @@
+# Ignore everything, except ci/
+*
+!ci/*
diff --git a/ci/docker/linux_debian_bullseye b/ci/docker/linux_debian_bullseye
new file mode 100644
index 00000000000..f6c1782f16b
--- /dev/null
+++ b/ci/docker/linux_debian_bullseye
@@ -0,0 +1,13 @@
+FROM debian:bullseye
+RUN \
+  apt-get -y update && \
+  apt-get -y upgrade && \
+  DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
+    git build-essential gcc g++ libreadline-dev flex bison make perl libipc-run-perl \
\ +    libio-pty-perl clang llvm-dev libperl-dev libpython3-dev tcl-dev libldap2-dev \
\ +    libicu-dev docbook-xml docbook-xsl fop libxml2-utils xsltproc \
krb5-admin-server \ +    krb5-kdc krb5-user slapd ldap-utils libssl-dev pkg-config \
locales-all liblz4-dev \ +    libsystemd-dev libxml2-dev libxslt1-dev python3-dev \
libkrb5-dev libpam-dev \ +    libkrb5-*-heimdal uuid-dev gettext \
+    liburing-dev python3-distutils ccache && \
+  apt-get clean
diff --git a/ci/docker/windows_vs_2019 b/ci/docker/windows_vs_2019
new file mode 100644
index 00000000000..a4fcaceae96
--- /dev/null
+++ b/ci/docker/windows_vs_2019
@@ -0,0 +1,111 @@
+# escape=`
+
+# We used to use the visual studio container, but it's too outdated now
+FROM cirrusci/windowsservercore:2019
+
+SHELL ["powershell", "-NoLogo", "-NoProfile", "-Command"]
+
+
+# Install commandline debugger and log all crashes to c:\cirrus\crashlog.txt
+#
+# Done manually as doing this via chocolatey / the installer directly, ends up
+# with a lot of unnecessary chaff, making the layer unnecessarily large.
+RUN `
+    mkdir c:\t ; `
+    cd c:\t ; `
+    `
+    setx PATH \"C:\Windows Kits\10\Debuggers\x64;$Env:PATH\" /m ; `
+    `
+    curl.exe -sSL -o 'windsdksetup.exe' \
https://download.microsoft.com/download/9/7/9/97982c1d-d687-41be-9dd3-6d01e52ceb68/windowssdk/winsdksetup.exe \
; ` +    echo 'starting sdk installation (for debugger)' ; `
+    Start-Process -Wait -FilePath ".\windsdksetup.exe" `
+      -ArgumentList '/Features OptionId.WindowsDesktopDebuggers /layout c:\t\sdk \
/quiet /norestart /log c:\t\sdk.log' ` +      ; `
+    `
+    Start-Process -Wait -FilePath msiexec.exe `
+      -ArgumentList '/a \"C:\t\sdk\Installers\X64 Debuggers And \
Tools-x64_en-us.msi\" /qb /log install2.log' ` +    ; `
+    C:\Windows` Kits\10\Debuggers\x64\cdb.exe -version ; `
+    `
+    Set-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows \
NT\CurrentVersion\AeDebug' -Name 'Debugger' -Value '\"C:\Windows \
Kits\10\Debuggers\x64\cdb.exe\" -p %ld -e %ld -g -kqm -c \".lines -e; .symfix+ \
;.logappend c:\cirrus\crashlog.txt ; !peb; ~*kP ; .logclose ; q \"' ; ` +    \
New-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug' \
-Name 'Auto' -Value 1 -PropertyType DWord ; ` +    Get-ItemProperty -Path \
'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug' -Name Debugger ; ` +    \
` +    cd c:\ ; `
+    Remove-Item C:\t -Force -Recurse
+
+
+# Install perl, python, flex and bison.
+#
+# Done manually as choco takes a lot longer. I think it's download issues with
+# powershell's download stuff? That's wy curl.exe is directly used here at least...
+#
+# Using perl 5.26.3.1 for now, as newer versions don't currently work correctly
+RUN `
+    mkdir c:\t ; `
+    cd c:\t ; `
+    `
+    echo 'adding to path, before setup below, so changes are not overwritten' ; `
+    setx PATH \"C:\strawberry\perl\bin;C:\winflexbison;C:\Program \
Files\Git\usr\bin;$Env:PATH\" /m ; ` +    `
+    curl.exe -sSL -o perl.zip `
+        https://strawberryperl.com/download/5.26.3.1/strawberry-perl-5.26.3.1-64bit-portable.zip \
; ` +    echo 'installing perl' ; `
+    7z.exe x .\perl.zip -xr!c -oc:\strawberry ; `
+    `
+    curl.exe -sSL -o python.exe \
https://www.python.org/ftp/python/3.10.0/python-3.10.0-amd64.exe ; ` +    echo \
'installing python' ; ` +    Start-Process -Wait -FilePath ".\python.exe" `
+      -ArgumentList `
+        '/quiet', 'SimpleInstall=1', 'PrependPath=1', 'CompileAll=1', `
+        'TargetDir=c:\python\', 'InstallAllUsers=1', 'Shortcuts=0', `
+        'Include_docs=0', 'Include_tcltk=0', 'Include_tests=0' `
+      ; `
+    `
+    curl.exe -sSL -o winflexbison.zip `
+        https://github.com/lexxmark/winflexbison/releases/download/v2.5.24/win_flex_bison-2.5.24.zip \
; ` +    echo 'installing winflexbison' ; `
+    7z.exe x .\winflexbison.zip -oc:\winflexbison ; `
+    Rename-Item -Path c:\winflexbison\win_flex.exe c:\winflexbison\flex.exe ; `
+    Rename-Item -Path c:\winflexbison\win_bison.exe c:\winflexbison\bison.exe ; `
+    `
+    cd c:\ ; `
+    Remove-Item C:\t -Force -Recurse
+
+
+# Install openssl
+RUN `
+    mkdir c:\t ; `
+    cd c:\t ; `
+    `
+    curl.exe -o openssl-setup.exe -sSL \
https://slproweb.com/download/Win64OpenSSL-1_1_1L.exe ; ` +    echo 'staring openssl \
installation' ; ` +    Start-Process -Wait -FilePath ".\openssl-setup.exe" `
+      -ArgumentList '/DIR=c:\openssl\1.1.1l\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' ; `
+    `
+    cd c:\ ; `
+    Remove-Item C:\t -Force -Recurse
+
+
+# Install visual studio
+#
+# Adding VS path to vcvarsall.bat so user of container doesn't need to know the full \
path +RUN `
+    mkdir c:\t ; `
+    cd c:\t ; `
+    setx PATH \"c:\BuildTools\VC\Auxiliary\Build;$Env:PATH\" /m ; `
+    `
+    curl.exe -sSL -o c:\t\vs_buildtools.exe \
https://aka.ms/vs/16/release/vs_buildtools.exe ; ` +    echo 'starting visual studio \
installation' ; ` +    Start-Process -Wait `
+        -FilePath c:\t\vs_buildtools.exe `
+        -ArgumentList `
+          '--quiet', '--wait', '--norestart', '--nocache', `
+          '--installPath', 'c:\BuildTools', `
+          '--add', 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64', `
+          '--add', 'Microsoft.VisualStudio.Component.Windows10SDK.20348'  ; `
+    `
+    cd c:\ ; `
+    Remove-Item C:\t -Force -Recurse ; `
+    Remove-Item -Force -Recurse ${Env:TEMP}\*; `
+    Remove-Item -Force -Recurse \"${Env:ProgramData}\Package Cache\"
diff --git a/ci/freebsd_gcp_repartition.sh b/ci/freebsd_gcp_repartition.sh
new file mode 100755
index 00000000000..2d5e1738998
--- /dev/null
+++ b/ci/freebsd_gcp_repartition.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+set -e
+set -x
+
+# The default filesystem on freebsd gcp images is very slow to run tests on,
+# due to its 32KB block size
+#
+# XXX: It'd probably better to fix this in the image, using something like
+# https://people.freebsd.org/~lidl/blog/re-root.html
+
+# fix backup partition table after resize
+gpart recover da0
+gpart show da0
+# kill swap, so we can delete a partition
+swapoff -a || true
+# (apparently we can only have 4!?)
+gpart delete -i 3 da0
+gpart add -t freebsd-ufs -l data8k -a 4096 da0
+gpart show da0
+newfs -U -b 8192 /dev/da0p3
+
+# Migrate working directory
+du -hs $CIRRUS_WORKING_DIR
+mv $CIRRUS_WORKING_DIR $CIRRUS_WORKING_DIR.orig
+mkdir $CIRRUS_WORKING_DIR
+mount -o noatime /dev/da0p3 $CIRRUS_WORKING_DIR
+cp -r $CIRRUS_WORKING_DIR.orig/* $CIRRUS_WORKING_DIR/
diff --git a/ci/pg_ci_base.conf b/ci/pg_ci_base.conf
new file mode 100644
index 00000000000..637e3cfb343
--- /dev/null
+++ b/ci/pg_ci_base.conf
@@ -0,0 +1,12 @@
+# Tends to produce too many core files, taking a long time
+restart_after_crash = false
+
+# So that tests using the "manually" started postgres on windows can use
+# prepared statements
+max_prepared_transactions=10
+
+# Settings that make logs more useful
+log_line_prefix='%m [%p][%b][%v:%x] '
+log_checkpoints = true
+log_connections = true
+log_disconnections = true
diff --git a/ci/windows_build_config.pl b/ci/windows_build_config.pl
new file mode 100644
index 00000000000..ba82b13d69a
--- /dev/null
+++ b/ci/windows_build_config.pl
@@ -0,0 +1,13 @@
+use strict;
+use warnings;
+
+our $config;
+
+$config->{"tap_tests"} = 1;
+$config->{"asserts"} = 1;
+
+$config->{"openssl"} = "c:/openssl/1.1.1l/";
+$config->{"perl"} = "c:/strawberry/perl/";
+$config->{"python"} = "c:/python/";
+
+1;
-- 
2.23.0.385.gbc12974a89


["v5-0003-plpython-Drop-support-python2.patch" (text/x-diff)]

From 96cb64239dcee91060a038bbad47047bd8b1b1c3 Mon Sep 17 00:00:00 2001
From: Andres Freund <andres@anarazel.de>
Date: Sun, 3 Oct 2021 10:56:21 -0700
Subject: [PATCH v5 03/16] plpython: Drop support python2.

Author:
Reviewed-By:
Discussion: https://postgr.es/m/20211031184548.g4sxfe47n2kyi55r@alap3.anarazel.de
Backpatch:
---
 .cirrus.yml                                   |    3 +-
 config/python.m4                              |    4 +-
 configure                                     |    4 +-
 contrib/hstore_plpython/Makefile              |   10 +-
 .../expected/hstore_plpython.out              |   22 +-
 .../hstore_plpython2u--1.0.sql                |   19 -
 .../hstore_plpython/hstore_plpython2u.control |    6 -
 .../hstore_plpython/hstore_plpythonu--1.0.sql |   19 -
 .../hstore_plpython/hstore_plpythonu.control  |    6 -
 .../hstore_plpython/sql/hstore_plpython.sql   |   18 +-
 contrib/jsonb_plpython/Makefile               |   11 +-
 .../expected/jsonb_plpython.out               |   32 +-
 .../jsonb_plpython/jsonb_plpython2u--1.0.sql  |   19 -
 .../jsonb_plpython/jsonb_plpython2u.control   |    6 -
 .../jsonb_plpython/jsonb_plpythonu--1.0.sql   |   19 -
 .../jsonb_plpython/jsonb_plpythonu.control    |    6 -
 contrib/jsonb_plpython/sql/jsonb_plpython.sql |   30 +-
 contrib/ltree_plpython/Makefile               |   10 +-
 .../expected/ltree_plpython.out               |   10 +-
 .../ltree_plpython/ltree_plpython2u--1.0.sql  |   12 -
 .../ltree_plpython/ltree_plpython2u.control   |    6 -
 .../ltree_plpython/ltree_plpythonu--1.0.sql   |   12 -
 .../ltree_plpython/ltree_plpythonu.control    |    6 -
 contrib/ltree_plpython/sql/ltree_plpython.sql |    8 +-
 src/pl/plpython/Makefile                      |   14 -
 src/pl/plpython/expected/plpython_call.out    |   12 +-
 .../plpython/expected/plpython_composite.out  |   32 +-
 src/pl/plpython/expected/plpython_do.out      |    8 +-
 src/pl/plpython/expected/plpython_drop.out    |    3 +-
 src/pl/plpython/expected/plpython_ereport.out |   22 +-
 src/pl/plpython/expected/plpython_error.out   |   52 +-
 src/pl/plpython/expected/plpython_error_5.out |  447 --------
 src/pl/plpython/expected/plpython_global.out  |    6 +-
 src/pl/plpython/expected/plpython_import.out  |    8 +-
 src/pl/plpython/expected/plpython_newline.out |    6 +-
 src/pl/plpython/expected/plpython_params.out  |    8 +-
 src/pl/plpython/expected/plpython_quote.out   |    2 +-
 src/pl/plpython/expected/plpython_record.out  |   18 +-
 src/pl/plpython/expected/plpython_setof.out   |   18 +-
 src/pl/plpython/expected/plpython_spi.out     |   48 +-
 .../expected/plpython_subtransaction.out      |   38 +-
 src/pl/plpython/expected/plpython_test.out    |   12 +-
 .../expected/plpython_transaction.out         |   24 +-
 src/pl/plpython/expected/plpython_trigger.out |   46 +-
 src/pl/plpython/expected/plpython_types.out   |  230 ++--
 src/pl/plpython/expected/plpython_types_3.out | 1009 -----------------
 src/pl/plpython/expected/plpython_unicode.out |   16 +-
 src/pl/plpython/expected/plpython_void.out    |    6 +-
 src/pl/plpython/plpy_cursorobject.c           |    2 +-
 src/pl/plpython/plpy_main.c                   |   55 +-
 src/pl/plpython/plpy_plpymodule.c             |   16 -
 src/pl/plpython/plpy_plpymodule.h             |    2 -
 src/pl/plpython/plpy_resultobject.c           |    8 -
 src/pl/plpython/plpy_typeio.c                 |    8 -
 src/pl/plpython/plpy_util.c                   |    3 -
 src/pl/plpython/plpy_util.h                   |    2 -
 src/pl/plpython/plpython.h                    |   13 +-
 src/pl/plpython/plpython2u--1.0.sql           |   17 -
 src/pl/plpython/plpython2u.control            |    7 -
 src/pl/plpython/plpythonu--1.0.sql            |   17 -
 src/pl/plpython/plpythonu.control             |    7 -
 src/pl/plpython/regress-python3-mangle.mk     |   38 -
 src/pl/plpython/sql/plpython_call.sql         |   12 +-
 src/pl/plpython/sql/plpython_composite.sql    |   32 +-
 src/pl/plpython/sql/plpython_do.sql           |    6 +-
 src/pl/plpython/sql/plpython_drop.sql         |    4 +-
 src/pl/plpython/sql/plpython_ereport.sql      |   22 +-
 src/pl/plpython/sql/plpython_error.sql        |   48 +-
 src/pl/plpython/sql/plpython_global.sql       |    6 +-
 src/pl/plpython/sql/plpython_import.sql       |    8 +-
 src/pl/plpython/sql/plpython_newline.sql      |    6 +-
 src/pl/plpython/sql/plpython_params.sql       |    8 +-
 src/pl/plpython/sql/plpython_quote.sql        |    2 +-
 src/pl/plpython/sql/plpython_record.sql       |   18 +-
 src/pl/plpython/sql/plpython_setof.sql        |   18 +-
 src/pl/plpython/sql/plpython_spi.sql          |   48 +-
 .../plpython/sql/plpython_subtransaction.sql  |   38 +-
 src/pl/plpython/sql/plpython_test.sql         |   12 +-
 src/pl/plpython/sql/plpython_transaction.sql  |   22 +-
 src/pl/plpython/sql/plpython_trigger.sql      |   46 +-
 src/pl/plpython/sql/plpython_types.sql        |  106 +-
 src/pl/plpython/sql/plpython_unicode.sql      |   16 +-
 src/pl/plpython/sql/plpython_void.sql         |    6 +-
 83 files changed, 629 insertions(+), 2433 deletions(-)
 delete mode 100644 contrib/hstore_plpython/hstore_plpython2u--1.0.sql
 delete mode 100644 contrib/hstore_plpython/hstore_plpython2u.control
 delete mode 100644 contrib/hstore_plpython/hstore_plpythonu--1.0.sql
 delete mode 100644 contrib/hstore_plpython/hstore_plpythonu.control
 delete mode 100644 contrib/jsonb_plpython/jsonb_plpython2u--1.0.sql
 delete mode 100644 contrib/jsonb_plpython/jsonb_plpython2u.control
 delete mode 100644 contrib/jsonb_plpython/jsonb_plpythonu--1.0.sql
 delete mode 100644 contrib/jsonb_plpython/jsonb_plpythonu.control
 delete mode 100644 contrib/ltree_plpython/ltree_plpython2u--1.0.sql
 delete mode 100644 contrib/ltree_plpython/ltree_plpython2u.control
 delete mode 100644 contrib/ltree_plpython/ltree_plpythonu--1.0.sql
 delete mode 100644 contrib/ltree_plpython/ltree_plpythonu.control
 delete mode 100644 src/pl/plpython/expected/plpython_error_5.out
 delete mode 100644 src/pl/plpython/expected/plpython_types_3.out
 delete mode 100644 src/pl/plpython/plpython2u--1.0.sql
 delete mode 100644 src/pl/plpython/plpython2u.control
 delete mode 100644 src/pl/plpython/plpythonu--1.0.sql
 delete mode 100644 src/pl/plpython/plpythonu.control
 delete mode 100644 src/pl/plpython/regress-python3-mangle.mk

diff --git a/.cirrus.yml b/.cirrus.yml
index f75bdce6dec..2bb6f4a14d7 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -240,7 +240,8 @@ task:
       --with-tcl --with-tclconfig=/usr/local/opt/tcl-tk/lib/ \
       --with-uuid=e2fs \
       \
-      CC="ccache gcc" CFLAGS="-O0 -ggdb"
+      CC="ccache gcc" CFLAGS="-O0 -ggdb" \
+      PYTHON=python3
   build_script:
     - gmake -s -j12 && gmake -s -j12 -C contrib
   upload_caches:
diff --git a/config/python.m4 b/config/python.m4
index d41aeb2876a..f51d23c3d43 100644
--- a/config/python.m4
+++ b/config/python.m4
@@ -37,8 +37,8 @@ python_majorversion=`echo "$python_fullversion" | sed \
'[s/^\([0-9]*\).*/\1/]'`  python_minorversion=`echo "$python_fullversion" | sed \
'[s/^[0-9]*\.\([0-9]*\).*/\1/]'`  python_version=`echo "$python_fullversion" | sed \
'[s/^\([0-9]*\.[0-9]*\).*/\1/]'`  # Reject unsupported Python versions as soon as \
                practical.
-if test "$python_majorversion" -lt 3 -a "$python_minorversion" -lt 6; then
-  AC_MSG_ERROR([Python version $python_version is too old (version 2.6 or later is \
required)]) +if test "$python_majorversion" -lt 3; then
+  AC_MSG_ERROR([Python version $python_version is too old (version 3 or later is \
required)])  fi
 
 AC_MSG_CHECKING([for Python distutils module])
diff --git a/configure b/configure
index 4ffefe46552..1b5fd12a432 100755
--- a/configure
+++ b/configure
@@ -10123,8 +10123,8 @@ python_majorversion=`echo "$python_fullversion" | sed \
's/^\([0-9]*\).*/\1/'`  python_minorversion=`echo "$python_fullversion" | sed \
's/^[0-9]*\.\([0-9]*\).*/\1/'`  python_version=`echo "$python_fullversion" | sed \
's/^\([0-9]*\.[0-9]*\).*/\1/'`  # Reject unsupported Python versions as soon as \
                practical.
-if test "$python_majorversion" -lt 3 -a "$python_minorversion" -lt 6; then
-  as_fn_error $? "Python version $python_version is too old (version 2.6 or later is \
required)" "$LINENO" 5 +if test "$python_majorversion" -lt 3; then
+  as_fn_error $? "Python version $python_version is too old (version 3 or later is \
required)" "$LINENO" 5  fi
 
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Python distutils module" >&5
diff --git a/contrib/hstore_plpython/Makefile b/contrib/hstore_plpython/Makefile
index 6af097ae68b..9d88cda1d0f 100644
--- a/contrib/hstore_plpython/Makefile
+++ b/contrib/hstore_plpython/Makefile
@@ -6,11 +6,10 @@ OBJS = \
 	hstore_plpython.o
 PGFILEDESC = "hstore_plpython - hstore transform for plpython"
 
-EXTENSION = hstore_plpythonu hstore_plpython2u hstore_plpython3u
-DATA = hstore_plpythonu--1.0.sql hstore_plpython2u--1.0.sql \
hstore_plpython3u--1.0.sql +EXTENSION = hstore_plpython3u
+DATA = hstore_plpython3u--1.0.sql
 
 REGRESS = hstore_plpython
-REGRESS_PLPYTHON3_MANGLE := $(REGRESS)
 
 PG_CPPFLAGS = $(python_includespec) \
-DPLPYTHON_LIBNAME='"plpython$(python_majorversion)"'  
@@ -37,9 +36,4 @@ SHLIB_LINK += $(python_libspec) $(python_additional_libs)
 endif
 
 REGRESS_OPTS += --load-extension=hstore
-ifeq ($(python_majorversion),2)
-REGRESS_OPTS += --load-extension=plpythonu --load-extension=hstore_plpythonu
-endif
 EXTRA_INSTALL += contrib/hstore
-
-include $(top_srcdir)/src/pl/plpython/regress-python3-mangle.mk
diff --git a/contrib/hstore_plpython/expected/hstore_plpython.out \
b/contrib/hstore_plpython/expected/hstore_plpython.out index ecf1dd61bc1..bf238701fec \
                100644
--- a/contrib/hstore_plpython/expected/hstore_plpython.out
+++ b/contrib/hstore_plpython/expected/hstore_plpython.out
@@ -1,8 +1,8 @@
-CREATE EXTENSION hstore_plpython2u CASCADE;
-NOTICE:  installing required extension "plpython2u"
+CREATE EXTENSION hstore_plpython3u CASCADE;
+NOTICE:  installing required extension "plpython3u"
 -- test hstore -> python
 CREATE FUNCTION test1(val hstore) RETURNS int
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 TRANSFORM FOR TYPE hstore
 AS $$
 assert isinstance(val, dict)
@@ -18,7 +18,7 @@ INFO:  [('aa', 'bb'), ('cc', None)]
 
 -- the same with the versioned language name
 CREATE FUNCTION test1n(val hstore) RETURNS int
-LANGUAGE plpython2u
+LANGUAGE plpython3u
 TRANSFORM FOR TYPE hstore
 AS $$
 assert isinstance(val, dict)
@@ -34,7 +34,7 @@ INFO:  [('aa', 'bb'), ('cc', None)]
 
 -- test hstore[] -> python
 CREATE FUNCTION test1arr(val hstore[]) RETURNS int
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 TRANSFORM FOR TYPE hstore
 AS $$
 assert(val == [{'aa': 'bb', 'cc': None}, {'dd': 'ee'}])
@@ -48,7 +48,7 @@ SELECT test1arr(array['aa=>bb, cc=>NULL'::hstore, 'dd=>ee']);
 
 -- test python -> hstore
 CREATE FUNCTION test2(a int, b text) RETURNS hstore
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 TRANSFORM FOR TYPE hstore
 AS $$
 val = {'a': a, 'b': b, 'c': None}
@@ -65,14 +65,14 @@ SELECT test2(1, 'boo');
 CREATE OR REPLACE FUNCTION public.test2(a integer, b text)
  RETURNS hstore
  TRANSFORM FOR TYPE hstore
- LANGUAGE plpythonu
+ LANGUAGE plpython3u
 AS $function$
 val = {'a': a, 'b': b, 'c': None}
 return val
 $function$
 -- test python -> hstore[]
 CREATE FUNCTION test2arr() RETURNS hstore[]
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 TRANSFORM FOR TYPE hstore
 AS $$
 val = [{'a': 1, 'b': 'boo', 'c': None}, {'d': 2}]
@@ -87,7 +87,7 @@ SELECT test2arr();
 -- test python -> domain over hstore
 CREATE DOMAIN hstore_foo AS hstore CHECK(VALUE ? 'foo');
 CREATE FUNCTION test2dom(fn text) RETURNS hstore_foo
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 TRANSFORM FOR TYPE hstore
 AS $$
 return {'a': 1, fn: 'boo', 'c': None}
@@ -104,7 +104,7 @@ CONTEXT:  while creating return value
 PL/Python function "test2dom"
 -- test as part of prepare/execute
 CREATE FUNCTION test3() RETURNS void
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 TRANSFORM FOR TYPE hstore
 AS $$
 rv = plpy.execute("SELECT 'aa=>bb, cc=>NULL'::hstore AS col1")
@@ -131,7 +131,7 @@ SELECT * FROM test1;
 (1 row)
 
 CREATE FUNCTION test4() RETURNS trigger
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 TRANSFORM FOR TYPE hstore
 AS $$
 assert(TD["new"] == {'a': 1, 'b': {'aa': 'bb', 'cc': None}})
diff --git a/contrib/hstore_plpython/hstore_plpython2u--1.0.sql \
b/contrib/hstore_plpython/hstore_plpython2u--1.0.sql deleted file mode 100644
index 800765f3f0c..00000000000
--- a/contrib/hstore_plpython/hstore_plpython2u--1.0.sql
+++ /dev/null
@@ -1,19 +0,0 @@
-/* contrib/hstore_plpython/hstore_plpython2u--1.0.sql */
-
--- complain if script is sourced in psql, rather than via CREATE EXTENSION
-\echo Use "CREATE EXTENSION hstore_plpython2u" to load this file. \quit
-
-CREATE FUNCTION hstore_to_plpython2(val internal) RETURNS internal
-LANGUAGE C STRICT IMMUTABLE
-AS 'MODULE_PATHNAME', 'hstore_to_plpython';
-
-CREATE FUNCTION plpython2_to_hstore(val internal) RETURNS hstore
-LANGUAGE C STRICT IMMUTABLE
-AS 'MODULE_PATHNAME', 'plpython_to_hstore';
-
-CREATE TRANSFORM FOR hstore LANGUAGE plpython2u (
-    FROM SQL WITH FUNCTION hstore_to_plpython2(internal),
-    TO SQL WITH FUNCTION plpython2_to_hstore(internal)
-);
-
-COMMENT ON TRANSFORM FOR hstore LANGUAGE plpython2u IS 'transform between hstore and \
                Python dict';
diff --git a/contrib/hstore_plpython/hstore_plpython2u.control \
b/contrib/hstore_plpython/hstore_plpython2u.control deleted file mode 100644
index ed905671123..00000000000
--- a/contrib/hstore_plpython/hstore_plpython2u.control
+++ /dev/null
@@ -1,6 +0,0 @@
-# hstore_plpython2u extension
-comment = 'transform between hstore and plpython2u'
-default_version = '1.0'
-module_pathname = '$libdir/hstore_plpython2'
-relocatable = true
-requires = 'hstore,plpython2u'
diff --git a/contrib/hstore_plpython/hstore_plpythonu--1.0.sql \
b/contrib/hstore_plpython/hstore_plpythonu--1.0.sql deleted file mode 100644
index 52832912abc..00000000000
--- a/contrib/hstore_plpython/hstore_plpythonu--1.0.sql
+++ /dev/null
@@ -1,19 +0,0 @@
-/* contrib/hstore_plpython/hstore_plpythonu--1.0.sql */
-
--- complain if script is sourced in psql, rather than via CREATE EXTENSION
-\echo Use "CREATE EXTENSION hstore_plpythonu" to load this file. \quit
-
-CREATE FUNCTION hstore_to_plpython(val internal) RETURNS internal
-LANGUAGE C STRICT IMMUTABLE
-AS 'MODULE_PATHNAME';
-
-CREATE FUNCTION plpython_to_hstore(val internal) RETURNS hstore
-LANGUAGE C STRICT IMMUTABLE
-AS 'MODULE_PATHNAME';
-
-CREATE TRANSFORM FOR hstore LANGUAGE plpythonu (
-    FROM SQL WITH FUNCTION hstore_to_plpython(internal),
-    TO SQL WITH FUNCTION plpython_to_hstore(internal)
-);
-
-COMMENT ON TRANSFORM FOR hstore LANGUAGE plpythonu IS 'transform between hstore and \
                Python dict';
diff --git a/contrib/hstore_plpython/hstore_plpythonu.control \
b/contrib/hstore_plpython/hstore_plpythonu.control deleted file mode 100644
index 8e9b35e43bf..00000000000
--- a/contrib/hstore_plpython/hstore_plpythonu.control
+++ /dev/null
@@ -1,6 +0,0 @@
-# hstore_plpythonu extension
-comment = 'transform between hstore and plpythonu'
-default_version = '1.0'
-module_pathname = '$libdir/hstore_plpython2'
-relocatable = true
-requires = 'hstore,plpythonu'
diff --git a/contrib/hstore_plpython/sql/hstore_plpython.sql \
b/contrib/hstore_plpython/sql/hstore_plpython.sql index b6d98b7dd53..a9cfbbe13e2 \
                100644
--- a/contrib/hstore_plpython/sql/hstore_plpython.sql
+++ b/contrib/hstore_plpython/sql/hstore_plpython.sql
@@ -1,9 +1,9 @@
-CREATE EXTENSION hstore_plpython2u CASCADE;
+CREATE EXTENSION hstore_plpython3u CASCADE;
 
 
 -- test hstore -> python
 CREATE FUNCTION test1(val hstore) RETURNS int
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 TRANSFORM FOR TYPE hstore
 AS $$
 assert isinstance(val, dict)
@@ -16,7 +16,7 @@ SELECT test1('aa=>bb, cc=>NULL'::hstore);
 
 -- the same with the versioned language name
 CREATE FUNCTION test1n(val hstore) RETURNS int
-LANGUAGE plpython2u
+LANGUAGE plpython3u
 TRANSFORM FOR TYPE hstore
 AS $$
 assert isinstance(val, dict)
@@ -29,7 +29,7 @@ SELECT test1n('aa=>bb, cc=>NULL'::hstore);
 
 -- test hstore[] -> python
 CREATE FUNCTION test1arr(val hstore[]) RETURNS int
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 TRANSFORM FOR TYPE hstore
 AS $$
 assert(val == [{'aa': 'bb', 'cc': None}, {'dd': 'ee'}])
@@ -41,7 +41,7 @@ SELECT test1arr(array['aa=>bb, cc=>NULL'::hstore, 'dd=>ee']);
 
 -- test python -> hstore
 CREATE FUNCTION test2(a int, b text) RETURNS hstore
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 TRANSFORM FOR TYPE hstore
 AS $$
 val = {'a': a, 'b': b, 'c': None}
@@ -56,7 +56,7 @@ SELECT test2(1, 'boo');
 
 -- test python -> hstore[]
 CREATE FUNCTION test2arr() RETURNS hstore[]
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 TRANSFORM FOR TYPE hstore
 AS $$
 val = [{'a': 1, 'b': 'boo', 'c': None}, {'d': 2}]
@@ -70,7 +70,7 @@ SELECT test2arr();
 CREATE DOMAIN hstore_foo AS hstore CHECK(VALUE ? 'foo');
 
 CREATE FUNCTION test2dom(fn text) RETURNS hstore_foo
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 TRANSFORM FOR TYPE hstore
 AS $$
 return {'a': 1, fn: 'boo', 'c': None}
@@ -82,7 +82,7 @@ SELECT test2dom('bar');  -- fail
 
 -- test as part of prepare/execute
 CREATE FUNCTION test3() RETURNS void
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 TRANSFORM FOR TYPE hstore
 AS $$
 rv = plpy.execute("SELECT 'aa=>bb, cc=>NULL'::hstore AS col1")
@@ -103,7 +103,7 @@ INSERT INTO test1 VALUES (1, 'aa=>bb, cc=>NULL');
 SELECT * FROM test1;
 
 CREATE FUNCTION test4() RETURNS trigger
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 TRANSFORM FOR TYPE hstore
 AS $$
 assert(TD["new"] == {'a': 1, 'b': {'aa': 'bb', 'cc': None}})
diff --git a/contrib/jsonb_plpython/Makefile b/contrib/jsonb_plpython/Makefile
index ca767418943..6333ea0bbaf 100644
--- a/contrib/jsonb_plpython/Makefile
+++ b/contrib/jsonb_plpython/Makefile
@@ -8,11 +8,10 @@ PGFILEDESC = "jsonb_plpython - transform between jsonb and \
plpythonu"  
 PG_CPPFLAGS = -I$(top_srcdir)/src/pl/plpython $(python_includespec) \
-DPLPYTHON_LIBNAME='"plpython$(python_majorversion)"'  
-EXTENSION = jsonb_plpythonu jsonb_plpython2u jsonb_plpython3u
-DATA = jsonb_plpythonu--1.0.sql jsonb_plpython2u--1.0.sql jsonb_plpython3u--1.0.sql
+EXTENSION = jsonb_plpython3u
+DATA = jsonb_plpython3u--1.0.sql
 
 REGRESS = jsonb_plpython
-REGRESS_PLPYTHON3_MANGLE := $(REGRESS)
 
 ifdef USE_PGXS
 PG_CONFIG = pg_config
@@ -33,9 +32,3 @@ else
 rpathdir = $(python_libdir)
 SHLIB_LINK += $(python_libspec) $(python_additional_libs)
 endif
-
-ifeq ($(python_majorversion),2)
-REGRESS_OPTS += --load-extension=plpythonu --load-extension=jsonb_plpythonu
-endif
-
-include $(top_srcdir)/src/pl/plpython/regress-python3-mangle.mk
diff --git a/contrib/jsonb_plpython/expected/jsonb_plpython.out \
b/contrib/jsonb_plpython/expected/jsonb_plpython.out index b491fe9cc68..cac963de69c \
                100644
--- a/contrib/jsonb_plpython/expected/jsonb_plpython.out
+++ b/contrib/jsonb_plpython/expected/jsonb_plpython.out
@@ -1,8 +1,8 @@
-CREATE EXTENSION jsonb_plpython2u CASCADE;
-NOTICE:  installing required extension "plpython2u"
+CREATE EXTENSION jsonb_plpython3u CASCADE;
+NOTICE:  installing required extension "plpython3u"
 -- test jsonb -> python dict
 CREATE FUNCTION test1(val jsonb) RETURNS int
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 TRANSFORM FOR TYPE jsonb
 AS $$
 assert isinstance(val, dict)
@@ -18,7 +18,7 @@ SELECT test1('{"a": 1, "c": "NULL"}'::jsonb);
 -- test jsonb -> python dict
 -- complex dict with dicts as value
 CREATE FUNCTION test1complex(val jsonb) RETURNS int
-LANGUAGE plpython2u
+LANGUAGE plpython3u
 TRANSFORM FOR TYPE jsonb
 AS $$
 assert isinstance(val, dict)
@@ -34,7 +34,7 @@ SELECT test1complex('{"d": {"d": 1}}'::jsonb);
 -- test jsonb[] -> python dict
 -- dict with array as value
 CREATE FUNCTION test1arr(val jsonb) RETURNS int
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 TRANSFORM FOR TYPE jsonb
 AS $$
 assert isinstance(val, dict)
@@ -50,7 +50,7 @@ SELECT test1arr('{"d":[12, 1]}'::jsonb);
 -- test jsonb[] -> python list
 -- simple list
 CREATE FUNCTION test2arr(val jsonb) RETURNS int
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 TRANSFORM FOR TYPE jsonb
 AS $$
 assert isinstance(val, list)
@@ -66,7 +66,7 @@ SELECT test2arr('[12, 1]'::jsonb);
 -- test jsonb[] -> python list
 -- array of dicts
 CREATE FUNCTION test3arr(val jsonb) RETURNS int
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 TRANSFORM FOR TYPE jsonb
 AS $$
 assert isinstance(val, list)
@@ -81,7 +81,7 @@ SELECT test3arr('[{"a": 1, "b": 2}, {"c": 3,"d": 4}]'::jsonb);
 
 -- test jsonb int -> python int
 CREATE FUNCTION test1int(val jsonb) RETURNS int
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 TRANSFORM FOR TYPE jsonb
 AS $$
 assert(val == 1)
@@ -95,7 +95,7 @@ SELECT test1int('1'::jsonb);
 
 -- test jsonb string -> python string
 CREATE FUNCTION test1string(val jsonb) RETURNS text
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 TRANSFORM FOR TYPE jsonb
 AS $$
 assert(val == "a")
@@ -109,7 +109,7 @@ SELECT test1string('"a"'::jsonb);
 
 -- test jsonb null -> python None
 CREATE FUNCTION test1null(val jsonb) RETURNS int
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 TRANSFORM FOR TYPE jsonb
 AS $$
 assert(val == None)
@@ -123,7 +123,7 @@ SELECT test1null('null'::jsonb);
 
 -- test python -> jsonb
 CREATE FUNCTION roundtrip(val jsonb) RETURNS jsonb
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 TRANSFORM FOR TYPE jsonb
 as $$
 return val
@@ -238,7 +238,7 @@ SELECT roundtrip('["string", "string2"]'::jsonb);
 
 -- complex numbers -> jsonb
 CREATE FUNCTION testComplexNumbers() RETURNS jsonb
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 TRANSFORM FOR TYPE jsonb
 AS $$
 x = 1 + 2j
@@ -250,7 +250,7 @@ CONTEXT:  while creating return value
 PL/Python function "testcomplexnumbers"
 -- range -> jsonb
 CREATE FUNCTION testRange() RETURNS jsonb
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 TRANSFORM FOR TYPE jsonb
 AS $$
 x = range(3)
@@ -264,7 +264,7 @@ SELECT testRange();
 
 -- 0xff -> jsonb
 CREATE FUNCTION testDecimal() RETURNS jsonb
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 TRANSFORM FOR TYPE jsonb
 AS $$
 x = 0xff
@@ -278,7 +278,7 @@ SELECT testDecimal();
 
 -- tuple -> jsonb
 CREATE FUNCTION testTuple() RETURNS jsonb
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 TRANSFORM FOR TYPE jsonb
 AS $$
 x = (1, 'String', None)
@@ -292,7 +292,7 @@ SELECT testTuple();
 
 -- interesting dict -> jsonb
 CREATE FUNCTION test_dict1() RETURNS jsonb
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 TRANSFORM FOR TYPE jsonb
 AS $$
 x = {"a": 1, None: 2, 33: 3}
diff --git a/contrib/jsonb_plpython/jsonb_plpython2u--1.0.sql \
b/contrib/jsonb_plpython/jsonb_plpython2u--1.0.sql deleted file mode 100644
index 2526d14ee19..00000000000
--- a/contrib/jsonb_plpython/jsonb_plpython2u--1.0.sql
+++ /dev/null
@@ -1,19 +0,0 @@
-/* contrib/jsonb_plpython/jsonb_plpython2u--1.0.sql */
-
--- complain if script is sourced in psql, rather than via CREATE EXTENSION
-\echo Use "CREATE EXTENSION jsonb_plpython2u" to load this file. \quit
-
-CREATE FUNCTION jsonb_to_plpython2(val internal) RETURNS internal
-LANGUAGE C STRICT IMMUTABLE
-AS 'MODULE_PATHNAME', 'jsonb_to_plpython';
-
-CREATE FUNCTION plpython2_to_jsonb(val internal) RETURNS jsonb
-LANGUAGE C STRICT IMMUTABLE
-AS 'MODULE_PATHNAME', 'plpython_to_jsonb';
-
-CREATE TRANSFORM FOR jsonb LANGUAGE plpython2u (
-    FROM SQL WITH FUNCTION jsonb_to_plpython2(internal),
-    TO SQL WITH FUNCTION plpython2_to_jsonb(internal)
-);
-
-COMMENT ON TRANSFORM FOR jsonb LANGUAGE plpython2u IS 'transform between jsonb and \
                Python';
diff --git a/contrib/jsonb_plpython/jsonb_plpython2u.control \
b/contrib/jsonb_plpython/jsonb_plpython2u.control deleted file mode 100644
index d26368316b6..00000000000
--- a/contrib/jsonb_plpython/jsonb_plpython2u.control
+++ /dev/null
@@ -1,6 +0,0 @@
-# jsonb_plpython2u extension
-comment = 'transform between jsonb and plpython2u'
-default_version = '1.0'
-module_pathname = '$libdir/jsonb_plpython2'
-relocatable = true
-requires = 'plpython2u'
diff --git a/contrib/jsonb_plpython/jsonb_plpythonu--1.0.sql \
b/contrib/jsonb_plpython/jsonb_plpythonu--1.0.sql deleted file mode 100644
index 3fa89885a63..00000000000
--- a/contrib/jsonb_plpython/jsonb_plpythonu--1.0.sql
+++ /dev/null
@@ -1,19 +0,0 @@
-/* contrib/jsonb_plpython/jsonb_plpythonu--1.0.sql */
-
--- complain if script is sourced in psql, rather than via CREATE EXTENSION
-\echo Use "CREATE EXTENSION jsonb_plpythonu" to load this file. \quit
-
-CREATE FUNCTION jsonb_to_plpython(val internal) RETURNS internal
-LANGUAGE C STRICT IMMUTABLE
-AS 'MODULE_PATHNAME';
-
-CREATE FUNCTION plpython_to_jsonb(val internal) RETURNS jsonb
-LANGUAGE C STRICT IMMUTABLE
-AS 'MODULE_PATHNAME';
-
-CREATE TRANSFORM FOR jsonb LANGUAGE plpythonu (
-    FROM SQL WITH FUNCTION jsonb_to_plpython(internal),
-    TO SQL WITH FUNCTION plpython_to_jsonb(internal)
-);
-
-COMMENT ON TRANSFORM FOR jsonb LANGUAGE plpythonu IS 'transform between jsonb and \
                Python';
diff --git a/contrib/jsonb_plpython/jsonb_plpythonu.control \
b/contrib/jsonb_plpython/jsonb_plpythonu.control deleted file mode 100644
index 6f8fa4f184b..00000000000
--- a/contrib/jsonb_plpython/jsonb_plpythonu.control
+++ /dev/null
@@ -1,6 +0,0 @@
-# jsonb_plpythonu extension
-comment = 'transform between jsonb and plpythonu'
-default_version = '1.0'
-module_pathname = '$libdir/jsonb_plpython2'
-relocatable = true
-requires = 'plpythonu'
diff --git a/contrib/jsonb_plpython/sql/jsonb_plpython.sql \
b/contrib/jsonb_plpython/sql/jsonb_plpython.sql index 2ee1bca0a98..29dc33279a0 100644
--- a/contrib/jsonb_plpython/sql/jsonb_plpython.sql
+++ b/contrib/jsonb_plpython/sql/jsonb_plpython.sql
@@ -1,8 +1,8 @@
-CREATE EXTENSION jsonb_plpython2u CASCADE;
+CREATE EXTENSION jsonb_plpython3u CASCADE;
 
 -- test jsonb -> python dict
 CREATE FUNCTION test1(val jsonb) RETURNS int
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 TRANSFORM FOR TYPE jsonb
 AS $$
 assert isinstance(val, dict)
@@ -15,7 +15,7 @@ SELECT test1('{"a": 1, "c": "NULL"}'::jsonb);
 -- test jsonb -> python dict
 -- complex dict with dicts as value
 CREATE FUNCTION test1complex(val jsonb) RETURNS int
-LANGUAGE plpython2u
+LANGUAGE plpython3u
 TRANSFORM FOR TYPE jsonb
 AS $$
 assert isinstance(val, dict)
@@ -29,7 +29,7 @@ SELECT test1complex('{"d": {"d": 1}}'::jsonb);
 -- test jsonb[] -> python dict
 -- dict with array as value
 CREATE FUNCTION test1arr(val jsonb) RETURNS int
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 TRANSFORM FOR TYPE jsonb
 AS $$
 assert isinstance(val, dict)
@@ -42,7 +42,7 @@ SELECT test1arr('{"d":[12, 1]}'::jsonb);
 -- test jsonb[] -> python list
 -- simple list
 CREATE FUNCTION test2arr(val jsonb) RETURNS int
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 TRANSFORM FOR TYPE jsonb
 AS $$
 assert isinstance(val, list)
@@ -55,7 +55,7 @@ SELECT test2arr('[12, 1]'::jsonb);
 -- test jsonb[] -> python list
 -- array of dicts
 CREATE FUNCTION test3arr(val jsonb) RETURNS int
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 TRANSFORM FOR TYPE jsonb
 AS $$
 assert isinstance(val, list)
@@ -67,7 +67,7 @@ SELECT test3arr('[{"a": 1, "b": 2}, {"c": 3,"d": 4}]'::jsonb);
 
 -- test jsonb int -> python int
 CREATE FUNCTION test1int(val jsonb) RETURNS int
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 TRANSFORM FOR TYPE jsonb
 AS $$
 assert(val == 1)
@@ -78,7 +78,7 @@ SELECT test1int('1'::jsonb);
 
 -- test jsonb string -> python string
 CREATE FUNCTION test1string(val jsonb) RETURNS text
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 TRANSFORM FOR TYPE jsonb
 AS $$
 assert(val == "a")
@@ -89,7 +89,7 @@ SELECT test1string('"a"'::jsonb);
 
 -- test jsonb null -> python None
 CREATE FUNCTION test1null(val jsonb) RETURNS int
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 TRANSFORM FOR TYPE jsonb
 AS $$
 assert(val == None)
@@ -100,7 +100,7 @@ SELECT test1null('null'::jsonb);
 
 -- test python -> jsonb
 CREATE FUNCTION roundtrip(val jsonb) RETURNS jsonb
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 TRANSFORM FOR TYPE jsonb
 as $$
 return val
@@ -129,7 +129,7 @@ SELECT roundtrip('["string", "string2"]'::jsonb);
 
 -- complex numbers -> jsonb
 CREATE FUNCTION testComplexNumbers() RETURNS jsonb
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 TRANSFORM FOR TYPE jsonb
 AS $$
 x = 1 + 2j
@@ -140,7 +140,7 @@ SELECT testComplexNumbers();
 
 -- range -> jsonb
 CREATE FUNCTION testRange() RETURNS jsonb
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 TRANSFORM FOR TYPE jsonb
 AS $$
 x = range(3)
@@ -151,7 +151,7 @@ SELECT testRange();
 
 -- 0xff -> jsonb
 CREATE FUNCTION testDecimal() RETURNS jsonb
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 TRANSFORM FOR TYPE jsonb
 AS $$
 x = 0xff
@@ -162,7 +162,7 @@ SELECT testDecimal();
 
 -- tuple -> jsonb
 CREATE FUNCTION testTuple() RETURNS jsonb
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 TRANSFORM FOR TYPE jsonb
 AS $$
 x = (1, 'String', None)
@@ -173,7 +173,7 @@ SELECT testTuple();
 
 -- interesting dict -> jsonb
 CREATE FUNCTION test_dict1() RETURNS jsonb
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 TRANSFORM FOR TYPE jsonb
 AS $$
 x = {"a": 1, None: 2, 33: 3}
diff --git a/contrib/ltree_plpython/Makefile b/contrib/ltree_plpython/Makefile
index 12a01467721..406d2789c9c 100644
--- a/contrib/ltree_plpython/Makefile
+++ b/contrib/ltree_plpython/Makefile
@@ -6,11 +6,10 @@ OBJS = \
 	ltree_plpython.o
 PGFILEDESC = "ltree_plpython - ltree transform for plpython"
 
-EXTENSION = ltree_plpythonu ltree_plpython2u ltree_plpython3u
-DATA = ltree_plpythonu--1.0.sql ltree_plpython2u--1.0.sql ltree_plpython3u--1.0.sql
+EXTENSION = ltree_plpython3u
+DATA = ltree_plpython3u--1.0.sql
 
 REGRESS = ltree_plpython
-REGRESS_PLPYTHON3_MANGLE := $(REGRESS)
 
 PG_CPPFLAGS = $(python_includespec) \
-DPLPYTHON_LIBNAME='"plpython$(python_majorversion)"'  
@@ -37,9 +36,4 @@ SHLIB_LINK += $(python_libspec) $(python_additional_libs)
 endif
 
 REGRESS_OPTS += --load-extension=ltree
-ifeq ($(python_majorversion),2)
-REGRESS_OPTS += --load-extension=plpythonu --load-extension=ltree_plpythonu
-endif
 EXTRA_INSTALL += contrib/ltree
-
-include $(top_srcdir)/src/pl/plpython/regress-python3-mangle.mk
diff --git a/contrib/ltree_plpython/expected/ltree_plpython.out \
b/contrib/ltree_plpython/expected/ltree_plpython.out index f28897fee48..bd32541fdb3 \
                100644
--- a/contrib/ltree_plpython/expected/ltree_plpython.out
+++ b/contrib/ltree_plpython/expected/ltree_plpython.out
@@ -1,7 +1,7 @@
-CREATE EXTENSION ltree_plpython2u CASCADE;
-NOTICE:  installing required extension "plpython2u"
+CREATE EXTENSION ltree_plpython3u CASCADE;
+NOTICE:  installing required extension "plpython3u"
 CREATE FUNCTION test1(val ltree) RETURNS int
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 TRANSFORM FOR TYPE ltree
 AS $$
 plpy.info(repr(val))
@@ -15,7 +15,7 @@ INFO:  ['aa', 'bb', 'cc']
 (1 row)
 
 CREATE FUNCTION test1n(val ltree) RETURNS int
-LANGUAGE plpython2u
+LANGUAGE plpython3u
 TRANSFORM FOR TYPE ltree
 AS $$
 plpy.info(repr(val))
@@ -29,7 +29,7 @@ INFO:  ['aa', 'bb', 'cc']
 (1 row)
 
 CREATE FUNCTION test2() RETURNS ltree
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 TRANSFORM FOR TYPE ltree
 AS $$
 return ['foo', 'bar', 'baz']
diff --git a/contrib/ltree_plpython/ltree_plpython2u--1.0.sql \
b/contrib/ltree_plpython/ltree_plpython2u--1.0.sql deleted file mode 100644
index 5c4a7037013..00000000000
--- a/contrib/ltree_plpython/ltree_plpython2u--1.0.sql
+++ /dev/null
@@ -1,12 +0,0 @@
-/* contrib/ltree_plpython/ltree_plpython2u--1.0.sql */
-
--- complain if script is sourced in psql, rather than via CREATE EXTENSION
-\echo Use "CREATE EXTENSION ltree_plpython2u" to load this file. \quit
-
-CREATE FUNCTION ltree_to_plpython2(val internal) RETURNS internal
-LANGUAGE C STRICT IMMUTABLE
-AS 'MODULE_PATHNAME', 'ltree_to_plpython';
-
-CREATE TRANSFORM FOR ltree LANGUAGE plpython2u (
-    FROM SQL WITH FUNCTION ltree_to_plpython2(internal)
-);
diff --git a/contrib/ltree_plpython/ltree_plpython2u.control \
b/contrib/ltree_plpython/ltree_plpython2u.control deleted file mode 100644
index bedfd0acbad..00000000000
--- a/contrib/ltree_plpython/ltree_plpython2u.control
+++ /dev/null
@@ -1,6 +0,0 @@
-# ltree_plpython2u extension
-comment = 'transform between ltree and plpython2u'
-default_version = '1.0'
-module_pathname = '$libdir/ltree_plpython2'
-relocatable = true
-requires = 'ltree,plpython2u'
diff --git a/contrib/ltree_plpython/ltree_plpythonu--1.0.sql \
b/contrib/ltree_plpython/ltree_plpythonu--1.0.sql deleted file mode 100644
index ee93edf28b9..00000000000
--- a/contrib/ltree_plpython/ltree_plpythonu--1.0.sql
+++ /dev/null
@@ -1,12 +0,0 @@
-/* contrib/ltree_plpython/ltree_plpythonu--1.0.sql */
-
--- complain if script is sourced in psql, rather than via CREATE EXTENSION
-\echo Use "CREATE EXTENSION ltree_plpythonu" to load this file. \quit
-
-CREATE FUNCTION ltree_to_plpython(val internal) RETURNS internal
-LANGUAGE C STRICT IMMUTABLE
-AS 'MODULE_PATHNAME';
-
-CREATE TRANSFORM FOR ltree LANGUAGE plpythonu (
-    FROM SQL WITH FUNCTION ltree_to_plpython(internal)
-);
diff --git a/contrib/ltree_plpython/ltree_plpythonu.control \
b/contrib/ltree_plpython/ltree_plpythonu.control deleted file mode 100644
index b03c89a2e6e..00000000000
--- a/contrib/ltree_plpython/ltree_plpythonu.control
+++ /dev/null
@@ -1,6 +0,0 @@
-# ltree_plpythonu extension
-comment = 'transform between ltree and plpythonu'
-default_version = '1.0'
-module_pathname = '$libdir/ltree_plpython2'
-relocatable = true
-requires = 'ltree,plpythonu'
diff --git a/contrib/ltree_plpython/sql/ltree_plpython.sql \
b/contrib/ltree_plpython/sql/ltree_plpython.sql index 210f5428a5a..0b8d28399a6 100644
--- a/contrib/ltree_plpython/sql/ltree_plpython.sql
+++ b/contrib/ltree_plpython/sql/ltree_plpython.sql
@@ -1,8 +1,8 @@
-CREATE EXTENSION ltree_plpython2u CASCADE;
+CREATE EXTENSION ltree_plpython3u CASCADE;
 
 
 CREATE FUNCTION test1(val ltree) RETURNS int
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 TRANSFORM FOR TYPE ltree
 AS $$
 plpy.info(repr(val))
@@ -13,7 +13,7 @@ SELECT test1('aa.bb.cc'::ltree);
 
 
 CREATE FUNCTION test1n(val ltree) RETURNS int
-LANGUAGE plpython2u
+LANGUAGE plpython3u
 TRANSFORM FOR TYPE ltree
 AS $$
 plpy.info(repr(val))
@@ -24,7 +24,7 @@ SELECT test1n('aa.bb.cc'::ltree);
 
 
 CREATE FUNCTION test2() RETURNS ltree
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 TRANSFORM FOR TYPE ltree
 AS $$
 return ['foo', 'bar', 'baz']
diff --git a/src/pl/plpython/Makefile b/src/pl/plpython/Makefile
index 9e95285af89..a8feacdef06 100644
--- a/src/pl/plpython/Makefile
+++ b/src/pl/plpython/Makefile
@@ -35,9 +35,6 @@ OBJS = \
 	plpy_util.o
 
 DATA = $(NAME)u.control $(NAME)u--1.0.sql
-ifeq ($(python_majorversion),2)
-DATA += plpythonu.control plpythonu--1.0.sql
-endif
 
 # header files to install - it's not clear which of these might be needed
 # so install them all.
@@ -77,11 +74,6 @@ endif # win32
 SHLIB_LINK = $(python_libspec) $(python_additional_libs) $(filter -lintl,$(LIBS))
 
 REGRESS_OPTS = --dbname=$(PL_TESTDB)
-# Only load plpythonu with Python 2.  The test files themselves load
-# the versioned language plpython(2|3)u.
-ifeq ($(python_majorversion),2)
-REGRESS_OPTS += --load-extension=plpythonu
-endif
 
 REGRESS = \
 	plpython_schema \
@@ -108,8 +100,6 @@ REGRESS = \
 	plpython_transaction \
 	plpython_drop
 
-REGRESS_PLPYTHON3_MANGLE := $(REGRESS)
-
 include $(top_srcdir)/src/Makefile.shlib
 
 all: all-lib
@@ -127,7 +117,6 @@ uninstall: uninstall-lib uninstall-data
 install-data: installdirs
 	$(INSTALL_DATA) $(addprefix $(srcdir)/, $(DATA)) '$(DESTDIR)$(datadir)/extension/'
 	$(INSTALL_DATA) $(addprefix $(srcdir)/, $(INCS)) '$(DESTDIR)$(includedir_server)'
-	$(INSTALL_DATA) $(srcdir)/regress-python3-mangle.mk \
'$(DESTDIR)$(pgxsdir)/src/pl/plpython'  
 uninstall-data:
 	rm -f $(addprefix '$(DESTDIR)$(datadir)/extension'/, $(notdir $(DATA)))
@@ -136,9 +125,6 @@ uninstall-data:
 .PHONY: install-data uninstall-data
 
 
-include $(srcdir)/regress-python3-mangle.mk
-
-
 check: submake-pg-regress
 	$(pg_regress_check) $(REGRESS_OPTS) $(REGRESS)
 
diff --git a/src/pl/plpython/expected/plpython_call.out \
b/src/pl/plpython/expected/plpython_call.out index 55e1027246a..4c0690067a0 100644
--- a/src/pl/plpython/expected/plpython_call.out
+++ b/src/pl/plpython/expected/plpython_call.out
@@ -2,14 +2,14 @@
 -- Tests for procedures / CALL syntax
 --
 CREATE PROCEDURE test_proc1()
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 AS $$
 pass
 $$;
 CALL test_proc1();
 -- error: can't return non-None
 CREATE PROCEDURE test_proc2()
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 AS $$
 return 5
 $$;
@@ -18,7 +18,7 @@ ERROR:  PL/Python procedure did not return None
 CONTEXT:  PL/Python procedure "test_proc2"
 CREATE TABLE test1 (a int);
 CREATE PROCEDURE test_proc3(x int)
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 AS $$
 plpy.execute("INSERT INTO test1 VALUES (%s)" % x)
 $$;
@@ -31,7 +31,7 @@ SELECT * FROM test1;
 
 -- output arguments
 CREATE PROCEDURE test_proc5(INOUT a text)
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 AS $$
 return [a + '+' + a]
 $$;
@@ -42,7 +42,7 @@ CALL test_proc5('abc');
 (1 row)
 
 CREATE PROCEDURE test_proc6(a int, INOUT b int, INOUT c int)
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 AS $$
 return (b * a, c * a)
 $$;
@@ -54,7 +54,7 @@ CALL test_proc6(2, 3, 4);
 
 -- OUT parameters
 CREATE PROCEDURE test_proc9(IN a int, OUT b int)
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 AS $$
 plpy.notice("a: %s" % (a))
 return (a * 2,)
diff --git a/src/pl/plpython/expected/plpython_composite.out \
b/src/pl/plpython/expected/plpython_composite.out index af801923343..bb101e07d53 \
                100644
--- a/src/pl/plpython/expected/plpython_composite.out
+++ b/src/pl/plpython/expected/plpython_composite.out
@@ -1,6 +1,6 @@
 CREATE FUNCTION multiout_simple(OUT i integer, OUT j integer) AS $$
 return (1, 2)
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT multiout_simple();
  multiout_simple 
 -----------------
@@ -27,7 +27,7 @@ SELECT (multiout_simple()).j + 3;
 
 CREATE FUNCTION multiout_simple_setof(n integer = 1, OUT integer, OUT integer) \
RETURNS SETOF record AS $$  return [(1, 2)] * n
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT multiout_simple_setof();
  multiout_simple_setof 
 -----------------------
@@ -67,7 +67,7 @@ elif typ == 'obj':
     return type_record
 elif typ == 'str':
     return "('%s',%r)" % (first, second)
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT * FROM multiout_record_as('dict', 'foo', 1, 'f');
  first | second 
 -------+--------
@@ -237,7 +237,7 @@ for i in range(n):
     power = 2 ** i
     length = plpy.execute("select length('%d')" % power)[0]['length']
     yield power, length
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT * FROM multiout_setof(3);
  power_of_2 | length 
 ------------+--------
@@ -260,7 +260,7 @@ CREATE FUNCTION multiout_return_table() RETURNS TABLE (x integer, \
y text) AS $$  return [{'x': 4, 'y' :'four'},
         {'x': 7, 'y' :'seven'},
         {'x': 0, 'y' :'zero'}]
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT * FROM multiout_return_table();
  x |   y   
 ---+-------
@@ -273,7 +273,7 @@ CREATE FUNCTION multiout_array(OUT integer[], OUT text) RETURNS \
SETOF record AS  yield [[1], 'a']
 yield [[1,2], 'b']
 yield [[1,2,3], None]
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT * FROM multiout_array();
  column1 | column2 
 ---------+---------
@@ -284,11 +284,11 @@ SELECT * FROM multiout_array();
 
 CREATE FUNCTION singleout_composite(OUT type_record) AS $$
 return {'first': 1, 'second': 2}
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 CREATE FUNCTION multiout_composite(OUT type_record) RETURNS SETOF type_record AS $$
 return [{'first': 1, 'second': 2},
        {'first': 3, 'second': 4	}]
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT * FROM singleout_composite();
  first | second 
 -------+--------
@@ -305,7 +305,7 @@ SELECT * FROM multiout_composite();
 -- composite OUT parameters in functions returning RECORD not supported yet
 CREATE FUNCTION multiout_composite(INOUT n integer, OUT type_record) AS $$
 return (n, (n * 2, n * 3))
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 CREATE FUNCTION multiout_table_type_setof(typ text, returnnull boolean, INOUT n \
integer, OUT table_record) RETURNS SETOF record AS $$  if returnnull:
     d = None
@@ -323,7 +323,7 @@ elif typ == 'str':
     d = "(%r,%r)" % (n * 2, n * 3)
 for i in range(n):
     yield (i, d)
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT * FROM multiout_composite(2);
  n | column2 
 ---+---------
@@ -438,7 +438,7 @@ CREATE TABLE changing (
 CREATE FUNCTION changing_test(OUT n integer, OUT changing) RETURNS SETOF record AS \
$$  return [(1, {'i': 1, 'j': 2}),
         (1, (3, 4))]
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT * FROM changing_test();
  n | column2 
 ---+---------
@@ -474,7 +474,7 @@ yield {'tab': [('first', 1), ('second', 2)],
 yield {'tab': [('first', 1), ('second', 2)],
       'typ': [{'first': 'third', 'second': 3},
               {'first': 'fourth', 'second': 4}]}
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT * FROM composite_types_table();
             tab             |            typ             
 ----------------------------+----------------------------
@@ -486,7 +486,7 @@ SELECT * FROM composite_types_table();
 -- check what happens if the output record descriptor changes
 CREATE FUNCTION return_record(t text) RETURNS record AS $$
 return {'t': t, 'val': 10}
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT * FROM return_record('abc') AS r(t text, val integer);
   t  | val 
 -----+-----
@@ -525,7 +525,7 @@ SELECT * FROM return_record('999') AS r(val text, t integer);
 
 CREATE FUNCTION return_record_2(t text) RETURNS record AS $$
 return {'v1':1,'v2':2,t:3}
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT * FROM return_record_2('v3') AS (v3 int, v2 int, v1 int);
  v3 | v2 | v1 
 ----+----+----
@@ -572,7 +572,7 @@ SELECT * FROM return_record_2('v3') AS (v1 int, v2 int, v3 int);
 -- multi-dimensional array of composite types.
 CREATE FUNCTION composite_type_as_list()  RETURNS type_record[] AS $$
   return [[('first', 1), ('second', 1)], [('first', 2), ('second', 2)], [('first', \
                3), ('second', 3)]];
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT * FROM composite_type_as_list();
                                composite_type_as_list                               
 ------------------------------------------------------------------------------------
@@ -585,7 +585,7 @@ SELECT * FROM composite_type_as_list();
 -- on the issue.
 CREATE FUNCTION composite_type_as_list_broken()  RETURNS type_record[] AS $$
   return [['first', 1]];
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT * FROM composite_type_as_list_broken();
 ERROR:  malformed record literal: "first"
 DETAIL:  Missing left parenthesis.
diff --git a/src/pl/plpython/expected/plpython_do.out \
b/src/pl/plpython/expected/plpython_do.out index e300530e031..d131a4c0ed6 100644
--- a/src/pl/plpython/expected/plpython_do.out
+++ b/src/pl/plpython/expected/plpython_do.out
@@ -1,8 +1,6 @@
-DO $$ plpy.notice("This is plpythonu.") $$ LANGUAGE plpythonu;
-NOTICE:  This is plpythonu.
-DO $$ plpy.notice("This is plpython2u.") $$ LANGUAGE plpython2u;
-NOTICE:  This is plpython2u.
-DO $$ raise Exception("error test") $$ LANGUAGE plpythonu;
+DO $$ plpy.notice("This is plpython3u.") $$ LANGUAGE plpython3u;
+NOTICE:  This is plpython3u.
+DO $$ raise Exception("error test") $$ LANGUAGE plpython3u;
 ERROR:  Exception: error test
 CONTEXT:  Traceback (most recent call last):
   PL/Python anonymous code block, line 1, in <module>
diff --git a/src/pl/plpython/expected/plpython_drop.out \
b/src/pl/plpython/expected/plpython_drop.out index a0e3b5c4ef6..97bb54a55e7 100644
--- a/src/pl/plpython/expected/plpython_drop.out
+++ b/src/pl/plpython/expected/plpython_drop.out
@@ -2,5 +2,4 @@
 -- For paranoia's sake, don't leave an untrusted language sitting around
 --
 SET client_min_messages = WARNING;
-DROP EXTENSION plpythonu CASCADE;
-DROP EXTENSION IF EXISTS plpython2u CASCADE;
+DROP EXTENSION plpython3u CASCADE;
diff --git a/src/pl/plpython/expected/plpython_ereport.out \
b/src/pl/plpython/expected/plpython_ereport.out index b73bfff5115..b38bb91e894 100644
--- a/src/pl/plpython/expected/plpython_ereport.out
+++ b/src/pl/plpython/expected/plpython_ereport.out
@@ -17,7 +17,7 @@ plpy.info('This is message text.',
 plpy.notice('notice', detail='some detail')
 plpy.warning('warning', detail='some detail')
 plpy.error('stop on error', detail='some detail', hint='some hint')
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT elog_test();
 INFO:  info
 DETAIL:  some detail
@@ -38,42 +38,42 @@ CONTEXT:  Traceback (most recent call last):
   PL/Python function "elog_test", line 18, in <module>
     plpy.error('stop on error', detail='some detail', hint='some hint')
 PL/Python function "elog_test"
-DO $$ plpy.info('other types', detail=(10, 20)) $$ LANGUAGE plpythonu;
+DO $$ plpy.info('other types', detail=(10, 20)) $$ LANGUAGE plpython3u;
 INFO:  other types
 DETAIL:  (10, 20)
 DO $$
 import time;
 from datetime import date
 plpy.info('other types', detail=date(2016, 2, 26))
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 INFO:  other types
 DETAIL:  2016-02-26
 DO $$
 basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana']
 plpy.info('other types', detail=basket)
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 INFO:  other types
 DETAIL:  ['apple', 'orange', 'apple', 'pear', 'orange', 'banana']
 -- should fail
-DO $$ plpy.info('wrong sqlstate', sqlstate='54444A') $$ LANGUAGE plpythonu;
+DO $$ plpy.info('wrong sqlstate', sqlstate='54444A') $$ LANGUAGE plpython3u;
 ERROR:  ValueError: invalid SQLSTATE code
 CONTEXT:  Traceback (most recent call last):
   PL/Python anonymous code block, line 1, in <module>
     plpy.info('wrong sqlstate', sqlstate='54444A') 
 PL/Python anonymous code block
-DO $$ plpy.info('unsupported argument', blabla='fooboo') $$ LANGUAGE plpythonu;
+DO $$ plpy.info('unsupported argument', blabla='fooboo') $$ LANGUAGE plpython3u;
 ERROR:  TypeError: 'blabla' is an invalid keyword argument for this function
 CONTEXT:  Traceback (most recent call last):
   PL/Python anonymous code block, line 1, in <module>
     plpy.info('unsupported argument', blabla='fooboo') 
 PL/Python anonymous code block
-DO $$ plpy.info('first message', message='second message') $$ LANGUAGE plpythonu;
+DO $$ plpy.info('first message', message='second message') $$ LANGUAGE plpython3u;
 ERROR:  TypeError: argument 'message' given by name and position
 CONTEXT:  Traceback (most recent call last):
   PL/Python anonymous code block, line 1, in <module>
     plpy.info('first message', message='second message') 
 PL/Python anonymous code block
-DO $$ plpy.info('first message', 'second message', message='third message') $$ \
LANGUAGE plpythonu; +DO $$ plpy.info('first message', 'second message', \
message='third message') $$ LANGUAGE plpython3u;  ERROR:  TypeError: argument \
'message' given by name and position  CONTEXT:  Traceback (most recent call last):
   PL/Python anonymous code block, line 1, in <module>
@@ -96,7 +96,7 @@ kwargs = {
 }
 # ignore None values
 plpy.error(**dict((k, v) for k, v in iter(kwargs.items()) if v))
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT raise_exception('hello', 'world');
 ERROR:  plpy.Error: hello
 DETAIL:  world
@@ -189,7 +189,7 @@ try:
 except Exception as e:
     plpy.info(e.spidata)
     raise e
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 INFO:  (119577128, None, 'some hint', None, 0, None, 'users_tab', None, 'user_type', \
None)  ERROR:  plpy.SPIError: plpy.Error: my message
 HINT:  some hint
@@ -199,7 +199,7 @@ try:
 except Exception as e:
     plpy.info('sqlstate: %s, hint: %s, table_name: %s, datatype_name: %s' % \
(e.sqlstate, e.hint, e.table_name, e.datatype_name))  raise e
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 INFO:  sqlstate: XX987, hint: some hint, table_name: users_tab, datatype_name: \
user_type  ERROR:  plpy.Error: my message
 HINT:  some hint
diff --git a/src/pl/plpython/expected/plpython_error.out \
b/src/pl/plpython/expected/plpython_error.out index b2f8fe83eb6..7fe864a1a57 100644
--- a/src/pl/plpython/expected/plpython_error.out
+++ b/src/pl/plpython/expected/plpython_error.out
@@ -6,7 +6,7 @@
 CREATE FUNCTION python_syntax_error() RETURNS text
         AS
 '.syntaxerror'
-        LANGUAGE plpythonu;
+        LANGUAGE plpython3u;
 ERROR:  could not compile PL/Python function "python_syntax_error"
 DETAIL:  SyntaxError: invalid syntax (<string>, line 2)
 /* With check_function_bodies = false the function should get defined
@@ -16,7 +16,7 @@ SET check_function_bodies = false;
 CREATE FUNCTION python_syntax_error() RETURNS text
         AS
 '.syntaxerror'
-        LANGUAGE plpythonu;
+        LANGUAGE plpython3u;
 SELECT python_syntax_error();
 ERROR:  could not compile PL/Python function "python_syntax_error"
 DETAIL:  SyntaxError: invalid syntax (<string>, line 2)
@@ -30,7 +30,7 @@ RESET check_function_bodies;
 CREATE FUNCTION sql_syntax_error() RETURNS text
         AS
 'plpy.execute("syntax error")'
-        LANGUAGE plpythonu;
+        LANGUAGE plpython3u;
 SELECT sql_syntax_error();
 ERROR:  spiexceptions.SyntaxError: syntax error at or near "syntax"
 LINE 1: syntax error
@@ -45,7 +45,7 @@ PL/Python function "sql_syntax_error"
 CREATE FUNCTION exception_index_invalid(text) RETURNS text
 	AS
 'return args[1]'
-	LANGUAGE plpythonu;
+	LANGUAGE plpython3u;
 SELECT exception_index_invalid('test');
 ERROR:  IndexError: list index out of range
 CONTEXT:  Traceback (most recent call last):
@@ -58,7 +58,7 @@ CREATE FUNCTION exception_index_invalid_nested() RETURNS text
 	AS
 'rv = plpy.execute("SELECT test5(''foo'')")
 return rv[0]'
-	LANGUAGE plpythonu;
+	LANGUAGE plpython3u;
 SELECT exception_index_invalid_nested();
 ERROR:  spiexceptions.UndefinedFunction: function test5(unknown) does not exist
 LINE 1: SELECT test5('foo')
@@ -81,7 +81,7 @@ if len(rv):
 	return rv[0]["fname"]
 return None
 '
-	LANGUAGE plpythonu;
+	LANGUAGE plpython3u;
 SELECT invalid_type_uncaught('rick');
 ERROR:  spiexceptions.UndefinedObject: type "test" does not exist
 CONTEXT:  Traceback (most recent call last):
@@ -105,7 +105,7 @@ if len(rv):
 	return rv[0]["fname"]
 return None
 '
-	LANGUAGE plpythonu;
+	LANGUAGE plpython3u;
 SELECT invalid_type_caught('rick');
 NOTICE:  type "test" does not exist
  invalid_type_caught 
@@ -129,7 +129,7 @@ if len(rv):
 	return rv[0]["fname"]
 return None
 '
-	LANGUAGE plpythonu;
+	LANGUAGE plpython3u;
 SELECT invalid_type_reraised('rick');
 ERROR:  plpy.Error: type "test" does not exist
 CONTEXT:  Traceback (most recent call last):
@@ -147,7 +147,7 @@ if len(rv):
 	return rv[0]["fname"]
 return None
 '
-	LANGUAGE plpythonu;
+	LANGUAGE plpython3u;
 SELECT valid_type('rick');
  valid_type 
 ------------
@@ -170,7 +170,7 @@ def fun3():
 fun3()
 return "not reached"
 '
-	LANGUAGE plpythonu;
+	LANGUAGE plpython3u;
 SELECT nested_error();
 ERROR:  plpy.Error: boom
 CONTEXT:  Traceback (most recent call last):
@@ -199,7 +199,7 @@ def fun3():
 fun3()
 return "not reached"
 '
-	LANGUAGE plpythonu;
+	LANGUAGE plpython3u;
 SELECT nested_error_raise();
 ERROR:  plpy.Error: boom
 CONTEXT:  Traceback (most recent call last):
@@ -228,7 +228,7 @@ def fun3():
 fun3()
 return "you''ve been warned"
 '
-	LANGUAGE plpythonu;
+	LANGUAGE plpython3u;
 SELECT nested_warning();
 WARNING:  boom
    nested_warning   
@@ -241,9 +241,9 @@ WARNING:  boom
 CREATE FUNCTION toplevel_attribute_error() RETURNS void AS
 $$
 plpy.nonexistent
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT toplevel_attribute_error();
-ERROR:  AttributeError: 'module' object has no attribute 'nonexistent'
+ERROR:  AttributeError: module 'plpy' has no attribute 'nonexistent'
 CONTEXT:  Traceback (most recent call last):
   PL/Python function "toplevel_attribute_error", line 2, in <module>
     plpy.nonexistent
@@ -261,7 +261,7 @@ def third():
   plpy.execute("select sql_error()")
 
 first()
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 CREATE OR REPLACE FUNCTION sql_error() RETURNS void AS $$
 begin
   select 1/0;
@@ -274,7 +274,7 @@ end
 $$ LANGUAGE plpgsql;
 CREATE OR REPLACE FUNCTION sql_from_python_error() RETURNS void AS $$
 plpy.execute("select sql_error()")
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT python_traceback();
 ERROR:  spiexceptions.DivisionByZero: division by zero
 CONTEXT:  Traceback (most recent call last):
@@ -325,7 +325,7 @@ except spiexceptions.NotNullViolation as e:
     plpy.notice("Violated the NOT NULL constraint, sqlstate %s" % e.sqlstate)
 except spiexceptions.UniqueViolation as e:
     plpy.notice("Violated the UNIQUE constraint, sqlstate %s" % e.sqlstate)
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT specific_exception(2);
  specific_exception 
 --------------------
@@ -351,7 +351,7 @@ NOTICE:  Violated the UNIQUE constraint, sqlstate 23505
 CREATE FUNCTION python_unique_violation() RETURNS void AS $$
 plpy.execute("insert into specific values (1)")
 plpy.execute("insert into specific values (1)")
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 CREATE FUNCTION catch_python_unique_violation() RETURNS text AS $$
 begin
     begin
@@ -374,7 +374,7 @@ CREATE FUNCTION manual_subxact() RETURNS void AS $$
 plpy.execute("savepoint save")
 plpy.execute("create table foo(x integer)")
 plpy.execute("rollback to save")
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT manual_subxact();
 ERROR:  plpy.SPIError: SPI_execute failed: SPI_ERROR_TRANSACTION
 CONTEXT:  Traceback (most recent call last):
@@ -389,7 +389,7 @@ rollback = plpy.prepare("rollback to save")
 plpy.execute(save)
 plpy.execute("create table foo(x integer)")
 plpy.execute(rollback)
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT manual_subxact_prepared();
 ERROR:  plpy.SPIError: SPI_execute_plan failed: SPI_ERROR_TRANSACTION
 CONTEXT:  Traceback (most recent call last):
@@ -400,7 +400,7 @@ PL/Python function "manual_subxact_prepared"
  */
 CREATE FUNCTION plpy_raise_spiexception() RETURNS void AS $$
 raise plpy.spiexceptions.DivisionByZero()
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 DO $$
 BEGIN
 	SELECT plpy_raise_spiexception();
@@ -414,7 +414,7 @@ CREATE FUNCTION plpy_raise_spiexception_override() RETURNS void \
AS $$  exc = plpy.spiexceptions.DivisionByZero()
 exc.sqlstate = 'SILLY'
 raise exc
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 DO $$
 BEGIN
 	SELECT plpy_raise_spiexception_override();
@@ -425,18 +425,18 @@ $$ LANGUAGE plpgsql;
 /* test the context stack trace for nested execution levels
  */
 CREATE FUNCTION notice_innerfunc() RETURNS int AS $$
-plpy.execute("DO LANGUAGE plpythonu $x$ plpy.notice('inside DO') $x$")
+plpy.execute("DO LANGUAGE plpython3u $x$ plpy.notice('inside DO') $x$")
 return 1
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 CREATE FUNCTION notice_outerfunc() RETURNS int AS $$
 plpy.execute("SELECT notice_innerfunc()")
 return 1
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 \set SHOW_CONTEXT always
 SELECT notice_outerfunc();
 NOTICE:  inside DO
 CONTEXT:  PL/Python anonymous code block
-SQL statement "DO LANGUAGE plpythonu $x$ plpy.notice('inside DO') $x$"
+SQL statement "DO LANGUAGE plpython3u $x$ plpy.notice('inside DO') $x$"
 PL/Python function "notice_innerfunc"
 SQL statement "SELECT notice_innerfunc()"
 PL/Python function "notice_outerfunc"
diff --git a/src/pl/plpython/expected/plpython_error_5.out \
b/src/pl/plpython/expected/plpython_error_5.out deleted file mode 100644
index bc66ab55340..00000000000
--- a/src/pl/plpython/expected/plpython_error_5.out
+++ /dev/null
@@ -1,447 +0,0 @@
--- test error handling, i forgot to restore Warn_restart in
--- the trigger handler once. the errors and subsequent core dump were
--- interesting.
-/* Flat out Python syntax error
- */
-CREATE FUNCTION python_syntax_error() RETURNS text
-        AS
-'.syntaxerror'
-        LANGUAGE plpython3u;
-ERROR:  could not compile PL/Python function "python_syntax_error"
-DETAIL:  SyntaxError: invalid syntax (<string>, line 2)
-/* With check_function_bodies = false the function should get defined
- * and the error reported when called
- */
-SET check_function_bodies = false;
-CREATE FUNCTION python_syntax_error() RETURNS text
-        AS
-'.syntaxerror'
-        LANGUAGE plpython3u;
-SELECT python_syntax_error();
-ERROR:  could not compile PL/Python function "python_syntax_error"
-DETAIL:  SyntaxError: invalid syntax (<string>, line 2)
-/* Run the function twice to check if the hashtable entry gets cleaned up */
-SELECT python_syntax_error();
-ERROR:  could not compile PL/Python function "python_syntax_error"
-DETAIL:  SyntaxError: invalid syntax (<string>, line 2)
-RESET check_function_bodies;
-/* Flat out syntax error
- */
-CREATE FUNCTION sql_syntax_error() RETURNS text
-        AS
-'plpy.execute("syntax error")'
-        LANGUAGE plpython3u;
-SELECT sql_syntax_error();
-ERROR:  spiexceptions.SyntaxError: syntax error at or near "syntax"
-LINE 1: syntax error
-        ^
-QUERY:  syntax error
-CONTEXT:  Traceback (most recent call last):
-  PL/Python function "sql_syntax_error", line 1, in <module>
-    plpy.execute("syntax error")
-PL/Python function "sql_syntax_error"
-/* check the handling of uncaught python exceptions
- */
-CREATE FUNCTION exception_index_invalid(text) RETURNS text
-	AS
-'return args[1]'
-	LANGUAGE plpython3u;
-SELECT exception_index_invalid('test');
-ERROR:  IndexError: list index out of range
-CONTEXT:  Traceback (most recent call last):
-  PL/Python function "exception_index_invalid", line 1, in <module>
-    return args[1]
-PL/Python function "exception_index_invalid"
-/* check handling of nested exceptions
- */
-CREATE FUNCTION exception_index_invalid_nested() RETURNS text
-	AS
-'rv = plpy.execute("SELECT test5(''foo'')")
-return rv[0]'
-	LANGUAGE plpython3u;
-SELECT exception_index_invalid_nested();
-ERROR:  spiexceptions.UndefinedFunction: function test5(unknown) does not exist
-LINE 1: SELECT test5('foo')
-               ^
-HINT:  No function matches the given name and argument types. You might need to add \
                explicit type casts.
-QUERY:  SELECT test5('foo')
-CONTEXT:  Traceback (most recent call last):
-  PL/Python function "exception_index_invalid_nested", line 1, in <module>
-    rv = plpy.execute("SELECT test5('foo')")
-PL/Python function "exception_index_invalid_nested"
-/* a typo
- */
-CREATE FUNCTION invalid_type_uncaught(a text) RETURNS text
-	AS
-'if "plan" not in SD:
-	q = "SELECT fname FROM users WHERE lname = $1"
-	SD["plan"] = plpy.prepare(q, [ "test" ])
-rv = plpy.execute(SD["plan"], [ a ])
-if len(rv):
-	return rv[0]["fname"]
-return None
-'
-	LANGUAGE plpython3u;
-SELECT invalid_type_uncaught('rick');
-ERROR:  spiexceptions.UndefinedObject: type "test" does not exist
-CONTEXT:  Traceback (most recent call last):
-  PL/Python function "invalid_type_uncaught", line 3, in <module>
-    SD["plan"] = plpy.prepare(q, [ "test" ])
-PL/Python function "invalid_type_uncaught"
-/* for what it's worth catch the exception generated by
- * the typo, and return None
- */
-CREATE FUNCTION invalid_type_caught(a text) RETURNS text
-	AS
-'if "plan" not in SD:
-	q = "SELECT fname FROM users WHERE lname = $1"
-	try:
-		SD["plan"] = plpy.prepare(q, [ "test" ])
-	except plpy.SPIError as ex:
-		plpy.notice(str(ex))
-		return None
-rv = plpy.execute(SD["plan"], [ a ])
-if len(rv):
-	return rv[0]["fname"]
-return None
-'
-	LANGUAGE plpython3u;
-SELECT invalid_type_caught('rick');
-NOTICE:  type "test" does not exist
- invalid_type_caught 
----------------------
- 
-(1 row)
-
-/* for what it's worth catch the exception generated by
- * the typo, and reraise it as a plain error
- */
-CREATE FUNCTION invalid_type_reraised(a text) RETURNS text
-	AS
-'if "plan" not in SD:
-	q = "SELECT fname FROM users WHERE lname = $1"
-	try:
-		SD["plan"] = plpy.prepare(q, [ "test" ])
-	except plpy.SPIError as ex:
-		plpy.error(str(ex))
-rv = plpy.execute(SD["plan"], [ a ])
-if len(rv):
-	return rv[0]["fname"]
-return None
-'
-	LANGUAGE plpython3u;
-SELECT invalid_type_reraised('rick');
-ERROR:  plpy.Error: type "test" does not exist
-CONTEXT:  Traceback (most recent call last):
-  PL/Python function "invalid_type_reraised", line 6, in <module>
-    plpy.error(str(ex))
-PL/Python function "invalid_type_reraised"
-/* no typo no messing about
- */
-CREATE FUNCTION valid_type(a text) RETURNS text
-	AS
-'if "plan" not in SD:
-	SD["plan"] = plpy.prepare("SELECT fname FROM users WHERE lname = $1", [ "text" ])
-rv = plpy.execute(SD["plan"], [ a ])
-if len(rv):
-	return rv[0]["fname"]
-return None
-'
-	LANGUAGE plpython3u;
-SELECT valid_type('rick');
- valid_type 
-------------
- 
-(1 row)
-
-/* error in nested functions to get a traceback
-*/
-CREATE FUNCTION nested_error() RETURNS text
-	AS
-'def fun1():
-	plpy.error("boom")
-
-def fun2():
-	fun1()
-
-def fun3():
-	fun2()
-
-fun3()
-return "not reached"
-'
-	LANGUAGE plpython3u;
-SELECT nested_error();
-ERROR:  plpy.Error: boom
-CONTEXT:  Traceback (most recent call last):
-  PL/Python function "nested_error", line 10, in <module>
-    fun3()
-  PL/Python function "nested_error", line 8, in fun3
-    fun2()
-  PL/Python function "nested_error", line 5, in fun2
-    fun1()
-  PL/Python function "nested_error", line 2, in fun1
-    plpy.error("boom")
-PL/Python function "nested_error"
-/* raising plpy.Error is just like calling plpy.error
-*/
-CREATE FUNCTION nested_error_raise() RETURNS text
-	AS
-'def fun1():
-	raise plpy.Error("boom")
-
-def fun2():
-	fun1()
-
-def fun3():
-	fun2()
-
-fun3()
-return "not reached"
-'
-	LANGUAGE plpython3u;
-SELECT nested_error_raise();
-ERROR:  plpy.Error: boom
-CONTEXT:  Traceback (most recent call last):
-  PL/Python function "nested_error_raise", line 10, in <module>
-    fun3()
-  PL/Python function "nested_error_raise", line 8, in fun3
-    fun2()
-  PL/Python function "nested_error_raise", line 5, in fun2
-    fun1()
-  PL/Python function "nested_error_raise", line 2, in fun1
-    raise plpy.Error("boom")
-PL/Python function "nested_error_raise"
-/* using plpy.warning should not produce a traceback
-*/
-CREATE FUNCTION nested_warning() RETURNS text
-	AS
-'def fun1():
-	plpy.warning("boom")
-
-def fun2():
-	fun1()
-
-def fun3():
-	fun2()
-
-fun3()
-return "you''ve been warned"
-'
-	LANGUAGE plpython3u;
-SELECT nested_warning();
-WARNING:  boom
-   nested_warning   
---------------------
- you've been warned
-(1 row)
-
-/* AttributeError at toplevel used to give segfaults with the traceback
-*/
-CREATE FUNCTION toplevel_attribute_error() RETURNS void AS
-$$
-plpy.nonexistent
-$$ LANGUAGE plpython3u;
-SELECT toplevel_attribute_error();
-ERROR:  AttributeError: module 'plpy' has no attribute 'nonexistent'
-CONTEXT:  Traceback (most recent call last):
-  PL/Python function "toplevel_attribute_error", line 2, in <module>
-    plpy.nonexistent
-PL/Python function "toplevel_attribute_error"
-/* Calling PL/Python functions from SQL and vice versa should not lose context.
- */
-CREATE OR REPLACE FUNCTION python_traceback() RETURNS void AS $$
-def first():
-  second()
-
-def second():
-  third()
-
-def third():
-  plpy.execute("select sql_error()")
-
-first()
-$$ LANGUAGE plpython3u;
-CREATE OR REPLACE FUNCTION sql_error() RETURNS void AS $$
-begin
-  select 1/0;
-end
-$$ LANGUAGE plpgsql;
-CREATE OR REPLACE FUNCTION python_from_sql_error() RETURNS void AS $$
-begin
-  select python_traceback();
-end
-$$ LANGUAGE plpgsql;
-CREATE OR REPLACE FUNCTION sql_from_python_error() RETURNS void AS $$
-plpy.execute("select sql_error()")
-$$ LANGUAGE plpython3u;
-SELECT python_traceback();
-ERROR:  spiexceptions.DivisionByZero: division by zero
-CONTEXT:  Traceback (most recent call last):
-  PL/Python function "python_traceback", line 11, in <module>
-    first()
-  PL/Python function "python_traceback", line 3, in first
-    second()
-  PL/Python function "python_traceback", line 6, in second
-    third()
-  PL/Python function "python_traceback", line 9, in third
-    plpy.execute("select sql_error()")
-PL/Python function "python_traceback"
-SELECT sql_error();
-ERROR:  division by zero
-CONTEXT:  SQL statement "select 1/0"
-PL/pgSQL function sql_error() line 3 at SQL statement
-SELECT python_from_sql_error();
-ERROR:  spiexceptions.DivisionByZero: division by zero
-CONTEXT:  Traceback (most recent call last):
-  PL/Python function "python_traceback", line 11, in <module>
-    first()
-  PL/Python function "python_traceback", line 3, in first
-    second()
-  PL/Python function "python_traceback", line 6, in second
-    third()
-  PL/Python function "python_traceback", line 9, in third
-    plpy.execute("select sql_error()")
-PL/Python function "python_traceback"
-SQL statement "select python_traceback()"
-PL/pgSQL function python_from_sql_error() line 3 at SQL statement
-SELECT sql_from_python_error();
-ERROR:  spiexceptions.DivisionByZero: division by zero
-CONTEXT:  Traceback (most recent call last):
-  PL/Python function "sql_from_python_error", line 2, in <module>
-    plpy.execute("select sql_error()")
-PL/Python function "sql_from_python_error"
-/* check catching specific types of exceptions
- */
-CREATE TABLE specific (
-    i integer PRIMARY KEY
-);
-CREATE FUNCTION specific_exception(i integer) RETURNS void AS
-$$
-from plpy import spiexceptions
-try:
-    plpy.execute("insert into specific values (%s)" % (i or "NULL"));
-except spiexceptions.NotNullViolation as e:
-    plpy.notice("Violated the NOT NULL constraint, sqlstate %s" % e.sqlstate)
-except spiexceptions.UniqueViolation as e:
-    plpy.notice("Violated the UNIQUE constraint, sqlstate %s" % e.sqlstate)
-$$ LANGUAGE plpython3u;
-SELECT specific_exception(2);
- specific_exception 
---------------------
- 
-(1 row)
-
-SELECT specific_exception(NULL);
-NOTICE:  Violated the NOT NULL constraint, sqlstate 23502
- specific_exception 
---------------------
- 
-(1 row)
-
-SELECT specific_exception(2);
-NOTICE:  Violated the UNIQUE constraint, sqlstate 23505
- specific_exception 
---------------------
- 
-(1 row)
-
-/* SPI errors in PL/Python functions should preserve the SQLSTATE value
- */
-CREATE FUNCTION python_unique_violation() RETURNS void AS $$
-plpy.execute("insert into specific values (1)")
-plpy.execute("insert into specific values (1)")
-$$ LANGUAGE plpython3u;
-CREATE FUNCTION catch_python_unique_violation() RETURNS text AS $$
-begin
-    begin
-        perform python_unique_violation();
-    exception when unique_violation then
-        return 'ok';
-    end;
-    return 'not reached';
-end;
-$$ language plpgsql;
-SELECT catch_python_unique_violation();
- catch_python_unique_violation 
--------------------------------
- ok
-(1 row)
-
-/* manually starting subtransactions - a bad idea
- */
-CREATE FUNCTION manual_subxact() RETURNS void AS $$
-plpy.execute("savepoint save")
-plpy.execute("create table foo(x integer)")
-plpy.execute("rollback to save")
-$$ LANGUAGE plpython3u;
-SELECT manual_subxact();
-ERROR:  plpy.SPIError: SPI_execute failed: SPI_ERROR_TRANSACTION
-CONTEXT:  Traceback (most recent call last):
-  PL/Python function "manual_subxact", line 2, in <module>
-    plpy.execute("savepoint save")
-PL/Python function "manual_subxact"
-/* same for prepared plans
- */
-CREATE FUNCTION manual_subxact_prepared() RETURNS void AS $$
-save = plpy.prepare("savepoint save")
-rollback = plpy.prepare("rollback to save")
-plpy.execute(save)
-plpy.execute("create table foo(x integer)")
-plpy.execute(rollback)
-$$ LANGUAGE plpython3u;
-SELECT manual_subxact_prepared();
-ERROR:  plpy.SPIError: SPI_execute_plan failed: SPI_ERROR_TRANSACTION
-CONTEXT:  Traceback (most recent call last):
-  PL/Python function "manual_subxact_prepared", line 4, in <module>
-    plpy.execute(save)
-PL/Python function "manual_subxact_prepared"
-/* raising plpy.spiexception.* from python code should preserve sqlstate
- */
-CREATE FUNCTION plpy_raise_spiexception() RETURNS void AS $$
-raise plpy.spiexceptions.DivisionByZero()
-$$ LANGUAGE plpython3u;
-DO $$
-BEGIN
-	SELECT plpy_raise_spiexception();
-EXCEPTION WHEN division_by_zero THEN
-	-- NOOP
-END
-$$ LANGUAGE plpgsql;
-/* setting a custom sqlstate should be handled
- */
-CREATE FUNCTION plpy_raise_spiexception_override() RETURNS void AS $$
-exc = plpy.spiexceptions.DivisionByZero()
-exc.sqlstate = 'SILLY'
-raise exc
-$$ LANGUAGE plpython3u;
-DO $$
-BEGIN
-	SELECT plpy_raise_spiexception_override();
-EXCEPTION WHEN SQLSTATE 'SILLY' THEN
-	-- NOOP
-END
-$$ LANGUAGE plpgsql;
-/* test the context stack trace for nested execution levels
- */
-CREATE FUNCTION notice_innerfunc() RETURNS int AS $$
-plpy.execute("DO LANGUAGE plpythonu $x$ plpy.notice('inside DO') $x$")
-return 1
-$$ LANGUAGE plpythonu;
-CREATE FUNCTION notice_outerfunc() RETURNS int AS $$
-plpy.execute("SELECT notice_innerfunc()")
-return 1
-$$ LANGUAGE plpythonu;
-\set SHOW_CONTEXT always
-SELECT notice_outerfunc();
-NOTICE:  inside DO
-CONTEXT:  PL/Python anonymous code block
-SQL statement "DO LANGUAGE plpythonu $x$ plpy.notice('inside DO') $x$"
-PL/Python function "notice_innerfunc"
-SQL statement "SELECT notice_innerfunc()"
-PL/Python function "notice_outerfunc"
- notice_outerfunc 
-------------------
-                1
-(1 row)
-
diff --git a/src/pl/plpython/expected/plpython_global.out \
b/src/pl/plpython/expected/plpython_global.out index 192e3e48a72..a4cfb1483f9 100644
--- a/src/pl/plpython/expected/plpython_global.out
+++ b/src/pl/plpython/expected/plpython_global.out
@@ -8,7 +8,7 @@ CREATE FUNCTION global_test_one() returns text
 if "global_test" not in GD:
 	GD["global_test"] = "set by global_test_one"
 return "SD: " + SD["global_test"] + ", GD: " + GD["global_test"]'
-    LANGUAGE plpythonu;
+    LANGUAGE plpython3u;
 CREATE FUNCTION global_test_two() returns text
     AS
 'if "global_test" not in SD:
@@ -16,7 +16,7 @@ CREATE FUNCTION global_test_two() returns text
 if "global_test" not in GD:
 	GD["global_test"] = "set by global_test_two"
 return "SD: " + SD["global_test"] + ", GD: " + GD["global_test"]'
-    LANGUAGE plpythonu;
+    LANGUAGE plpython3u;
 CREATE FUNCTION static_test() returns int4
     AS
 'if "call" in SD:
@@ -25,7 +25,7 @@ else:
 	SD["call"] = 1
 return SD["call"]
 '
-    LANGUAGE plpythonu;
+    LANGUAGE plpython3u;
 SELECT static_test();
  static_test 
 -------------
diff --git a/src/pl/plpython/expected/plpython_import.out \
b/src/pl/plpython/expected/plpython_import.out index b59e1821a79..854e989eaf9 100644
--- a/src/pl/plpython/expected/plpython_import.out
+++ b/src/pl/plpython/expected/plpython_import.out
@@ -6,7 +6,7 @@ CREATE FUNCTION import_fail() returns text
 except ImportError:
 	return "failed as expected"
 return "succeeded, that wasn''t supposed to happen"'
-    LANGUAGE plpythonu;
+    LANGUAGE plpython3u;
 CREATE FUNCTION import_succeed() returns text
 	AS
 'try:
@@ -25,7 +25,7 @@ except Exception as ex:
 	plpy.notice("import failed -- %s" % str(ex))
 	return "failed, that wasn''t supposed to happen"
 return "succeeded, as expected"'
-    LANGUAGE plpythonu;
+    LANGUAGE plpython3u;
 CREATE FUNCTION import_test_one(p text) RETURNS text
 	AS
 'try:
@@ -35,7 +35,7 @@ except ImportError:
     import sha
     digest = sha.new(p)
 return digest.hexdigest()'
-	LANGUAGE plpythonu;
+	LANGUAGE plpython3u;
 CREATE FUNCTION import_test_two(u users) RETURNS text
 	AS
 'plain = u["fname"] + u["lname"]
@@ -46,7 +46,7 @@ except ImportError:
     import sha
     digest = sha.new(plain);
 return "sha hash of " + plain + " is " + digest.hexdigest()'
-	LANGUAGE plpythonu;
+	LANGUAGE plpython3u;
 -- import python modules
 --
 SELECT import_fail();
diff --git a/src/pl/plpython/expected/plpython_newline.out \
b/src/pl/plpython/expected/plpython_newline.out index 27dc2f8ab0c..2bc149257e7 100644
--- a/src/pl/plpython/expected/plpython_newline.out
+++ b/src/pl/plpython/expected/plpython_newline.out
@@ -3,13 +3,13 @@
 --
 CREATE OR REPLACE FUNCTION newline_lf() RETURNS integer AS
 E'x = 100\ny = 23\nreturn x + y\n'
-LANGUAGE plpythonu;
+LANGUAGE plpython3u;
 CREATE OR REPLACE FUNCTION newline_cr() RETURNS integer AS
 E'x = 100\ry = 23\rreturn x + y\r'
-LANGUAGE plpythonu;
+LANGUAGE plpython3u;
 CREATE OR REPLACE FUNCTION newline_crlf() RETURNS integer AS
 E'x = 100\r\ny = 23\r\nreturn x + y\r\n'
-LANGUAGE plpythonu;
+LANGUAGE plpython3u;
 SELECT newline_lf();
  newline_lf 
 ------------
diff --git a/src/pl/plpython/expected/plpython_params.out \
b/src/pl/plpython/expected/plpython_params.out index 46ea7dfb90b..d1a36f36239 100644
--- a/src/pl/plpython/expected/plpython_params.out
+++ b/src/pl/plpython/expected/plpython_params.out
@@ -3,12 +3,12 @@
 --
 CREATE FUNCTION test_param_names0(integer, integer) RETURNS int AS $$
 return args[0] + args[1]
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 CREATE FUNCTION test_param_names1(a0 integer, a1 text) RETURNS boolean AS $$
 assert a0 == args[0]
 assert a1 == args[1]
 return True
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 CREATE FUNCTION test_param_names2(u users) RETURNS text AS $$
 assert u == args[0]
 if isinstance(u, dict):
@@ -19,7 +19,7 @@ if isinstance(u, dict):
 else:
     s = str(u)
 return s
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 -- use deliberately wrong parameter names
 CREATE FUNCTION test_param_names3(a0 integer) RETURNS boolean AS $$
 try:
@@ -28,7 +28,7 @@ try:
 except NameError as e:
 	assert e.args[0].find("a1") > -1
 	return True
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT test_param_names0(2,7);
  test_param_names0 
 -------------------
diff --git a/src/pl/plpython/expected/plpython_quote.out \
b/src/pl/plpython/expected/plpython_quote.out index eed72923aec..1fbe93d5351 100644
--- a/src/pl/plpython/expected/plpython_quote.out
+++ b/src/pl/plpython/expected/plpython_quote.out
@@ -8,7 +8,7 @@ CREATE FUNCTION quote(t text, how text) RETURNS text AS $$
         return plpy.quote_ident(t)
     else:
         raise plpy.Error("unrecognized quote type %s" % how)
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT quote(t, 'literal') FROM (VALUES
        ('abc'),
        ('a''bc'),
diff --git a/src/pl/plpython/expected/plpython_record.out \
b/src/pl/plpython/expected/plpython_record.out index 458330713a8..31de198582b 100644
--- a/src/pl/plpython/expected/plpython_record.out
+++ b/src/pl/plpython/expected/plpython_record.out
@@ -23,7 +23,7 @@ elif typ == 'obj':
 	type_record.first = first
 	type_record.second = second
 	return type_record
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 CREATE FUNCTION test_type_record_as(typ text, first text, second integer, retnull \
boolean) RETURNS type_record AS $$  if retnull:
 	return None
@@ -40,17 +40,17 @@ elif typ == 'obj':
 	return type_record
 elif typ == 'str':
 	return "('%s',%r)" % (first, second)
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 CREATE FUNCTION test_in_out_params(first in text, second out text) AS $$
 return first + '_in_to_out';
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 CREATE FUNCTION test_in_out_params_multi(first in text,
                                          second out text, third out text) AS $$
 return (first + '_record_in_to_out_1', first + '_record_in_to_out_2');
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 CREATE FUNCTION test_inout_params(first inout text) AS $$
 return first + '_inout';
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 -- Test tuple returning functions
 SELECT * FROM test_table_record_as('dict', null, null, false);
  first | second 
@@ -340,7 +340,7 @@ SELECT * FROM test_type_record_as('obj', 'one', 1, false);
 -- errors cases
 CREATE FUNCTION test_type_record_error1() RETURNS type_record AS $$
     return { 'first': 'first' }
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT * FROM test_type_record_error1();
 ERROR:  key "second" not found in mapping
 HINT:  To return null in a column, add the value None to the mapping with the key \
named after the column. @@ -348,7 +348,7 @@ CONTEXT:  while creating return value
 PL/Python function "test_type_record_error1"
 CREATE FUNCTION test_type_record_error2() RETURNS type_record AS $$
     return [ 'first' ]
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT * FROM test_type_record_error2();
 ERROR:  length of returned sequence did not match number of columns in row
 CONTEXT:  while creating return value
@@ -357,7 +357,7 @@ CREATE FUNCTION test_type_record_error3() RETURNS type_record AS \
$$  class type_record: pass
     type_record.first = 'first'
     return type_record
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT * FROM test_type_record_error3();
 ERROR:  attribute "second" does not exist in Python object
 HINT:  To return null in a column, let the returned object have an attribute named \
after column with value None. @@ -365,7 +365,7 @@ CONTEXT:  while creating return \
value  PL/Python function "test_type_record_error3"
 CREATE FUNCTION test_type_record_error4() RETURNS type_record AS $$
     return 'foo'
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT * FROM test_type_record_error4();
 ERROR:  malformed record literal: "foo"
 DETAIL:  Missing left parenthesis.
diff --git a/src/pl/plpython/expected/plpython_setof.out \
b/src/pl/plpython/expected/plpython_setof.out index 170dbc394de..39409400290 100644
--- a/src/pl/plpython/expected/plpython_setof.out
+++ b/src/pl/plpython/expected/plpython_setof.out
@@ -3,20 +3,20 @@
 --
 CREATE FUNCTION test_setof_error() RETURNS SETOF text AS $$
 return 37
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT test_setof_error();
 ERROR:  returned object cannot be iterated
 DETAIL:  PL/Python set-returning functions must return an iterable object.
 CONTEXT:  PL/Python function "test_setof_error"
 CREATE FUNCTION test_setof_as_list(count integer, content text) RETURNS SETOF text \
AS $$  return [ content ]*count
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 CREATE FUNCTION test_setof_as_tuple(count integer, content text) RETURNS SETOF text \
AS $$  t = ()
 for i in range(count):
 	t += ( content, )
 return t
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 CREATE FUNCTION test_setof_as_iterator(count integer, content text) RETURNS SETOF \
text AS $$  class producer:
 	def __init__ (self, icount, icontent):
@@ -24,13 +24,13 @@ class producer:
 		self.icount = icount
 	def __iter__ (self):
 		return self
-	def next (self):
+	def __next__ (self):
 		if self.icount == 0:
 			raise StopIteration
 		self.icount -= 1
 		return self.icontent
 return producer(count, content)
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 CREATE FUNCTION test_setof_spi_in_iterator() RETURNS SETOF text AS
 $$
     for s in ('Hello', 'Brave', 'New', 'World'):
@@ -38,7 +38,7 @@ $$
         yield s
         plpy.execute('select 2')
 $$
-LANGUAGE plpythonu;
+LANGUAGE plpython3u;
 -- Test set returning functions
 SELECT test_setof_as_list(0, 'list');
  test_setof_as_list 
@@ -130,7 +130,7 @@ global x
 while x <= lim:
     yield x
     x = x + 1
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT ugly(1, 5);
  ugly 
 ------
@@ -155,7 +155,7 @@ CREATE OR REPLACE FUNCTION get_user_records()
 RETURNS SETOF users
 AS $$
     return plpy.execute("SELECT * FROM users ORDER BY username")
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT get_user_records();
    get_user_records   
 ----------------------
@@ -179,7 +179,7 @@ CREATE OR REPLACE FUNCTION get_user_records2()
 RETURNS TABLE(fname text, lname text, username text, userid int)
 AS $$
     return plpy.execute("SELECT * FROM users ORDER BY username")
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT get_user_records2();
   get_user_records2   
 ----------------------
diff --git a/src/pl/plpython/expected/plpython_spi.out \
b/src/pl/plpython/expected/plpython_spi.out index a09df68c7d1..391fdb0e645 100644
--- a/src/pl/plpython/expected/plpython_spi.out
+++ b/src/pl/plpython/expected/plpython_spi.out
@@ -6,17 +6,17 @@ CREATE FUNCTION nested_call_one(a text) RETURNS text
 'q = "SELECT nested_call_two(''%s'')" % a
 r = plpy.execute(q)
 return r[0]'
-	LANGUAGE plpythonu ;
+	LANGUAGE plpython3u ;
 CREATE FUNCTION nested_call_two(a text) RETURNS text
 	AS
 'q = "SELECT nested_call_three(''%s'')" % a
 r = plpy.execute(q)
 return r[0]'
-	LANGUAGE plpythonu ;
+	LANGUAGE plpython3u ;
 CREATE FUNCTION nested_call_three(a text) RETURNS text
 	AS
 'return a'
-	LANGUAGE plpythonu ;
+	LANGUAGE plpython3u ;
 -- some spi stuff
 CREATE FUNCTION spi_prepared_plan_test_one(a text) RETURNS text
 	AS
@@ -30,7 +30,7 @@ except Exception as ex:
 	plpy.error(str(ex))
 return None
 '
-	LANGUAGE plpythonu;
+	LANGUAGE plpython3u;
 CREATE FUNCTION spi_prepared_plan_test_two(a text) RETURNS text
 	AS
 'if "myplan" not in SD:
@@ -43,7 +43,7 @@ except Exception as ex:
 	plpy.error(str(ex))
 return None
 '
-	LANGUAGE plpythonu;
+	LANGUAGE plpython3u;
 CREATE FUNCTION spi_prepared_plan_test_nested(a text) RETURNS text
 	AS
 'if "myplan" not in SD:
@@ -57,7 +57,7 @@ except Exception as ex:
 	plpy.error(str(ex))
 return None
 '
-	LANGUAGE plpythonu;
+	LANGUAGE plpython3u;
 CREATE FUNCTION join_sequences(s sequences) RETURNS text
 	AS
 'if not s["multipart"]:
@@ -69,7 +69,7 @@ for r in rv:
 	seq = seq + r["sequence"]
 return seq
 '
-	LANGUAGE plpythonu;
+	LANGUAGE plpython3u;
 CREATE FUNCTION spi_recursive_sum(a int) RETURNS int
 	AS
 'r = 0
@@ -77,7 +77,7 @@ if a > 1:
     r = plpy.execute("SELECT spi_recursive_sum(%d) as a" % (a-1))[0]["a"]
 return a + r
 '
-	LANGUAGE plpythonu;
+	LANGUAGE plpython3u;
 --
 -- spi and nested calls
 --
@@ -155,7 +155,7 @@ if result.status() > 0:
    return result.nrows()
 else:
    return None
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT result_metadata_test($$SELECT 1 AS foo, '11'::text AS bar UNION SELECT 2, \
'22'$$);  INFO:  True
 INFO:  ['foo', 'bar']
@@ -177,7 +177,7 @@ CREATE FUNCTION result_nrows_test(cmd text) RETURNS int
 AS $$
 result = plpy.execute(cmd)
 return result.nrows()
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT result_nrows_test($$SELECT 1$$);
  result_nrows_test 
 -------------------
@@ -206,7 +206,7 @@ CREATE FUNCTION result_len_test(cmd text) RETURNS int
 AS $$
 result = plpy.execute(cmd)
 return len(result)
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT result_len_test($$SELECT 1$$);
  result_len_test 
 -----------------
@@ -254,7 +254,7 @@ except TypeError:
 else:
     assert False, "TypeError not raised"
 
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT result_subscript_test();
 INFO:  2
 INFO:  4
@@ -272,7 +272,7 @@ result = plpy.execute("select 1 where false")
 
 plpy.info(result[:])
 
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT result_empty_test();
 INFO:  []
  result_empty_test 
@@ -285,7 +285,7 @@ AS $$
 plan = plpy.prepare(cmd)
 result = plpy.execute(plan)
 return str(result)
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT result_str_test($$SELECT 1 AS foo UNION SELECT 2$$);
                       result_str_test                       
 ------------------------------------------------------------
@@ -306,12 +306,12 @@ for row in res:
     if row['lname'] == 'doe':
         does += 1
 return does
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 CREATE FUNCTION double_cursor_close() RETURNS int AS $$
 res = plpy.cursor("select fname, lname from users")
 res.close()
 res.close()
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 CREATE FUNCTION cursor_fetch() RETURNS int AS $$
 res = plpy.cursor("select fname, lname from users")
 assert len(res.fetch(3)) == 3
@@ -329,7 +329,7 @@ except StopIteration:
     pass
 else:
     assert False, "StopIteration not raised"
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 CREATE FUNCTION cursor_mix_next_and_fetch() RETURNS int AS $$
 res = plpy.cursor("select fname, lname from users order by fname")
 assert len(res.fetch(2)) == 2
@@ -342,7 +342,7 @@ except AttributeError:
 assert item['fname'] == 'rick'
 
 assert len(res.fetch(2)) == 1
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 CREATE FUNCTION fetch_after_close() RETURNS int AS $$
 res = plpy.cursor("select fname, lname from users")
 res.close()
@@ -352,7 +352,7 @@ except ValueError:
     pass
 else:
     assert False, "ValueError not raised"
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 CREATE FUNCTION next_after_close() RETURNS int AS $$
 res = plpy.cursor("select fname, lname from users")
 res.close()
@@ -365,7 +365,7 @@ except ValueError:
     pass
 else:
     assert False, "ValueError not raised"
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 CREATE FUNCTION cursor_fetch_next_empty() RETURNS int AS $$
 res = plpy.cursor("select fname, lname from users where false")
 assert len(res.fetch(1)) == 0
@@ -378,7 +378,7 @@ except StopIteration:
     pass
 else:
     assert False, "StopIteration not raised"
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 CREATE FUNCTION cursor_plan() RETURNS SETOF text AS $$
 plan = plpy.prepare(
     "select fname, lname from users where fname like $1 || '%' order by fname",
@@ -387,12 +387,12 @@ for row in plpy.cursor(plan, ["w"]):
     yield row['fname']
 for row in plan.cursor(["j"]):
     yield row['fname']
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 CREATE FUNCTION cursor_plan_wrong_args() RETURNS SETOF text AS $$
 plan = plpy.prepare("select fname, lname from users where fname like $1 || '%'",
                     ["text"])
 c = plpy.cursor(plan, ["a", "b"])
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 CREATE TYPE test_composite_type AS (
   a1 int,
   a2 varchar
@@ -401,7 +401,7 @@ CREATE OR REPLACE FUNCTION plan_composite_args() RETURNS \
test_composite_type AS  plan = plpy.prepare("select $1 as c1", \
["test_composite_type"])  res = plpy.execute(plan, [{"a1": 3, "a2": "label"}])
 return res[0]["c1"]
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT simple_cursor_test();
  simple_cursor_test 
 --------------------
diff --git a/src/pl/plpython/expected/plpython_subtransaction.out \
b/src/pl/plpython/expected/plpython_subtransaction.out index 2a56541917d..43d9277a33b \
                100644
--- a/src/pl/plpython/expected/plpython_subtransaction.out
+++ b/src/pl/plpython/expected/plpython_subtransaction.out
@@ -14,7 +14,7 @@ with plpy.subtransaction():
         plpy.execute("INSERT INTO subtransaction_tbl VALUES ('oops')")
     elif what_error == "Python":
         raise Exception("Python exception")
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT subtransaction_ctx_test();
  subtransaction_ctx_test 
 -------------------------
@@ -71,7 +71,7 @@ with plpy.subtransaction():
             raise
         plpy.notice("Swallowed %s(%r)" % (e.__class__.__name__, e.args[0]))
 return "ok"
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT subtransaction_nested_test();
 ERROR:  spiexceptions.SyntaxError: syntax error at or near "error"
 LINE 1: error
@@ -111,7 +111,7 @@ with plpy.subtransaction():
     plpy.execute("INSERT INTO subtransaction_tbl VALUES (2)")
     plpy.execute("SELECT subtransaction_nested_test('t')")
 return "ok"
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT subtransaction_deeply_nested_test();
 NOTICE:  Swallowed SyntaxError('syntax error at or near "error"')
  subtransaction_deeply_nested_test 
@@ -133,42 +133,42 @@ TRUNCATE subtransaction_tbl;
 CREATE FUNCTION subtransaction_exit_without_enter() RETURNS void
 AS $$
 plpy.subtransaction().__exit__(None, None, None)
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 CREATE FUNCTION subtransaction_enter_without_exit() RETURNS void
 AS $$
 plpy.subtransaction().__enter__()
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 CREATE FUNCTION subtransaction_exit_twice() RETURNS void
 AS $$
 plpy.subtransaction().__enter__()
 plpy.subtransaction().__exit__(None, None, None)
 plpy.subtransaction().__exit__(None, None, None)
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 CREATE FUNCTION subtransaction_enter_twice() RETURNS void
 AS $$
 plpy.subtransaction().__enter__()
 plpy.subtransaction().__enter__()
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 CREATE FUNCTION subtransaction_exit_same_subtransaction_twice() RETURNS void
 AS $$
 s = plpy.subtransaction()
 s.__enter__()
 s.__exit__(None, None, None)
 s.__exit__(None, None, None)
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 CREATE FUNCTION subtransaction_enter_same_subtransaction_twice() RETURNS void
 AS $$
 s = plpy.subtransaction()
 s.__enter__()
 s.__enter__()
 s.__exit__(None, None, None)
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 -- No warnings here, as the subtransaction gets indeed closed
 CREATE FUNCTION subtransaction_enter_subtransaction_in_with() RETURNS void
 AS $$
 with plpy.subtransaction() as s:
     s.__enter__()
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 CREATE FUNCTION subtransaction_exit_subtransaction_in_with() RETURNS void
 AS $$
 try:
@@ -176,7 +176,7 @@ try:
         s.__exit__(None, None, None)
 except ValueError as e:
     raise ValueError(e)
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT subtransaction_exit_without_enter();
 ERROR:  ValueError: this subtransaction has not been entered
 CONTEXT:  Traceback (most recent call last):
@@ -255,7 +255,7 @@ try:
     plpy.execute(p, ["wrong"])
 except plpy.SPIError:
     plpy.warning("Caught a SPI error")
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT subtransaction_mix_explicit_and_implicit();
 WARNING:  Caught a SPI error from an explicit subtransaction
 WARNING:  Caught a SPI error
@@ -278,7 +278,7 @@ AS $$
 s = plpy.subtransaction()
 s.enter()
 s.exit(None, None, None)
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT subtransaction_alternative_names();
  subtransaction_alternative_names 
 ----------------------------------
@@ -294,7 +294,7 @@ with plpy.subtransaction():
          plpy.execute("INSERT INTO subtransaction_tbl VALUES ('a')")
      except plpy.SPIError:
          plpy.notice("caught")
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT try_catch_inside_subtransaction();
 NOTICE:  caught
  try_catch_inside_subtransaction 
@@ -318,7 +318,7 @@ with plpy.subtransaction():
          plpy.execute("INSERT INTO subtransaction_tbl VALUES (1)")
      except plpy.SPIError:
          plpy.notice("caught")
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT pk_violation_inside_subtransaction();
 NOTICE:  caught
  pk_violation_inside_subtransaction 
@@ -340,7 +340,7 @@ with plpy.subtransaction():
     cur.fetch(10)
 fetched = cur.fetch(10);
 return int(fetched[5]["i"])
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 CREATE FUNCTION cursor_aborted_subxact() RETURNS int AS $$
 try:
     with plpy.subtransaction():
@@ -351,7 +351,7 @@ except plpy.SPIError:
     fetched = cur.fetch(10)
     return int(fetched[5]["i"])
 return 0 # not reached
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 CREATE FUNCTION cursor_plan_aborted_subxact() RETURNS int AS $$
 try:
     with plpy.subtransaction():
@@ -364,7 +364,7 @@ except plpy.SPIError:
     fetched = cur.fetch(5)
     return fetched[2]["i"]
 return 0 # not reached
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 CREATE FUNCTION cursor_close_aborted_subxact() RETURNS boolean AS $$
 try:
     with plpy.subtransaction():
@@ -374,7 +374,7 @@ except plpy.SPIError:
     cur.close()
     return True
 return False # not reached
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT cursor_in_subxact();
  cursor_in_subxact 
 -------------------
diff --git a/src/pl/plpython/expected/plpython_test.out \
b/src/pl/plpython/expected/plpython_test.out index 39b994f4468..13c14119c08 100644
--- a/src/pl/plpython/expected/plpython_test.out
+++ b/src/pl/plpython/expected/plpython_test.out
@@ -1,7 +1,7 @@
 -- first some tests of basic functionality
-CREATE EXTENSION plpython2u;
+CREATE EXTENSION plpython3u;
 -- really stupid function just to get the module loaded
-CREATE FUNCTION stupid() RETURNS text AS 'return "zarkon"' LANGUAGE plpythonu;
+CREATE FUNCTION stupid() RETURNS text AS 'return "zarkon"' LANGUAGE plpython3u;
 select stupid();
  stupid 
 --------
@@ -9,7 +9,7 @@ select stupid();
 (1 row)
 
 -- check 2/3 versioning
-CREATE FUNCTION stupidn() RETURNS text AS 'return "zarkon"' LANGUAGE plpython2u;
+CREATE FUNCTION stupidn() RETURNS text AS 'return "zarkon"' LANGUAGE plpython3u;
 select stupidn();
  stupidn 
 ---------
@@ -26,7 +26,7 @@ for key in keys:
     out.append("%s: %s" % (key, u[key]))
 words = a1 + " " + a2 + " => {" + ", ".join(out) + "}"
 return words'
-	LANGUAGE plpythonu;
+	LANGUAGE plpython3u;
 select "Argument test #1"(users, fname, lname) from users where lname = 'doe' order \
by 1;  Argument test #1                            
 -----------------------------------------------------------------------
@@ -41,7 +41,7 @@ $$
 contents = list(filter(lambda x: not x.startswith("__"), dir(plpy)))
 contents.sort()
 return contents
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 select module_contents();
  module_contents 
 -----------------
@@ -78,7 +78,7 @@ plpy.info('info', 37, [1, 2, 3])
 plpy.notice('notice')
 plpy.warning('warning')
 plpy.error('error')
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT elog_test_basic();
 INFO:  info
 INFO:  37
diff --git a/src/pl/plpython/expected/plpython_transaction.out \
b/src/pl/plpython/expected/plpython_transaction.out index 14152993c75..393ea21eaad \
                100644
--- a/src/pl/plpython/expected/plpython_transaction.out
+++ b/src/pl/plpython/expected/plpython_transaction.out
@@ -1,6 +1,6 @@
 CREATE TABLE test1 (a int, b text);
 CREATE PROCEDURE transaction_test1()
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 AS $$
 for i in range(0, 10):
     plpy.execute("INSERT INTO test1 (a) VALUES (%d)" % i)
@@ -22,7 +22,7 @@ SELECT * FROM test1;
 
 TRUNCATE test1;
 DO
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 $$
 for i in range(0, 10):
     plpy.execute("INSERT INTO test1 (a) VALUES (%d)" % i)
@@ -44,7 +44,7 @@ SELECT * FROM test1;
 TRUNCATE test1;
 -- not allowed in a function
 CREATE FUNCTION transaction_test2() RETURNS int
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 AS $$
 for i in range(0, 10):
     plpy.execute("INSERT INTO test1 (a) VALUES (%d)" % i)
@@ -64,7 +64,7 @@ SELECT * FROM test1;
 
 -- also not allowed if procedure is called from a function
 CREATE FUNCTION transaction_test3() RETURNS int
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 AS $$
 plpy.execute("CALL transaction_test1()")
 return 1
@@ -82,19 +82,19 @@ SELECT * FROM test1;
 
 -- DO block inside function
 CREATE FUNCTION transaction_test4() RETURNS int
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 AS $$
-plpy.execute("DO LANGUAGE plpythonu $x$ plpy.commit() $x$")
+plpy.execute("DO LANGUAGE plpython3u $x$ plpy.commit() $x$")
 return 1
 $$;
 SELECT transaction_test4();
 ERROR:  spiexceptions.InvalidTransactionTermination: invalid transaction termination
 CONTEXT:  Traceback (most recent call last):
   PL/Python function "transaction_test4", line 2, in <module>
-    plpy.execute("DO LANGUAGE plpythonu $x$ plpy.commit() $x$")
+    plpy.execute("DO LANGUAGE plpython3u $x$ plpy.commit() $x$")
 PL/Python function "transaction_test4"
 -- commit inside subtransaction (prohibited)
-DO LANGUAGE plpythonu $$
+DO LANGUAGE plpython3u $$
 s = plpy.subtransaction()
 s.enter()
 plpy.commit()
@@ -106,7 +106,7 @@ CONTEXT:  PL/Python anonymous code block
 CREATE TABLE test2 (x int);
 INSERT INTO test2 VALUES (0), (1), (2), (3), (4);
 TRUNCATE test1;
-DO LANGUAGE plpythonu $$
+DO LANGUAGE plpython3u $$
 for row in plpy.cursor("SELECT * FROM test2 ORDER BY x"):
     plpy.execute("INSERT INTO test1 (a) VALUES (%s)" % row['x'])
     plpy.commit()
@@ -129,7 +129,7 @@ SELECT * FROM pg_cursors;
 
 -- error in cursor loop with commit
 TRUNCATE test1;
-DO LANGUAGE plpythonu $$
+DO LANGUAGE plpython3u $$
 for row in plpy.cursor("SELECT * FROM test2 ORDER BY x"):
     plpy.execute("INSERT INTO test1 (a) VALUES (12/(%s-2))" % row['x'])
     plpy.commit()
@@ -153,7 +153,7 @@ SELECT * FROM pg_cursors;
 
 -- rollback inside cursor loop
 TRUNCATE test1;
-DO LANGUAGE plpythonu $$
+DO LANGUAGE plpython3u $$
 for row in plpy.cursor("SELECT * FROM test2 ORDER BY x"):
     plpy.execute("INSERT INTO test1 (a) VALUES (%s)" % row['x'])
     plpy.rollback()
@@ -170,7 +170,7 @@ SELECT * FROM pg_cursors;
 
 -- first commit then rollback inside cursor loop
 TRUNCATE test1;
-DO LANGUAGE plpythonu $$
+DO LANGUAGE plpython3u $$
 for row in plpy.cursor("SELECT * FROM test2 ORDER BY x"):
     plpy.execute("INSERT INTO test1 (a) VALUES (%s)" % row['x'])
     if row['x'] % 2 == 0:
diff --git a/src/pl/plpython/expected/plpython_trigger.out \
b/src/pl/plpython/expected/plpython_trigger.out index 742988a5b59..dd1ca32fa49 100644
--- a/src/pl/plpython/expected/plpython_trigger.out
+++ b/src/pl/plpython/expected/plpython_trigger.out
@@ -15,20 +15,20 @@ if TD["new"]["fname"] == "william":
 	TD["new"]["fname"] = TD["args"][0]
 	rv = "MODIFY"
 return rv'
-	LANGUAGE plpythonu;
+	LANGUAGE plpython3u;
 CREATE FUNCTION users_update() returns trigger
 	AS
 'if TD["event"] == "UPDATE":
 	if TD["old"]["fname"] != TD["new"]["fname"] and TD["old"]["fname"] == \
TD["args"][0]:  return "SKIP"
 return None'
-	LANGUAGE plpythonu;
+	LANGUAGE plpython3u;
 CREATE FUNCTION users_delete() RETURNS trigger
 	AS
 'if TD["old"]["fname"] == TD["args"][0]:
 	return "SKIP"
 return None'
-	LANGUAGE plpythonu;
+	LANGUAGE plpython3u;
 CREATE TRIGGER users_insert_trig BEFORE INSERT ON users FOR EACH ROW
 	EXECUTE PROCEDURE users_insert ('willem');
 CREATE TRIGGER users_update_trig BEFORE UPDATE ON users FOR EACH ROW
@@ -71,7 +71,7 @@ CREATE TABLE trigger_test_generated (
 	i int,
         j int GENERATED ALWAYS AS (i * 2) STORED
 );
-CREATE FUNCTION trigger_data() RETURNS trigger LANGUAGE plpythonu AS $$
+CREATE FUNCTION trigger_data() RETURNS trigger LANGUAGE plpython3u AS $$
 
 if 'relid' in TD:
 	TD['relid'] = "bogus:12345"
@@ -328,7 +328,7 @@ INSERT INTO trigger_test VALUES (0, 'zero');
 CREATE FUNCTION stupid1() RETURNS trigger
 AS $$
     return 37
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 CREATE TRIGGER stupid_trigger1
 BEFORE INSERT ON trigger_test
 FOR EACH ROW EXECUTE PROCEDURE stupid1();
@@ -341,7 +341,7 @@ DROP TRIGGER stupid_trigger1 ON trigger_test;
 CREATE FUNCTION stupid2() RETURNS trigger
 AS $$
     return "MODIFY"
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 CREATE TRIGGER stupid_trigger2
 BEFORE DELETE ON trigger_test
 FOR EACH ROW EXECUTE PROCEDURE stupid2();
@@ -353,7 +353,7 @@ INSERT INTO trigger_test VALUES (0, 'zero');
 CREATE FUNCTION stupid3() RETURNS trigger
 AS $$
     return "foo"
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 CREATE TRIGGER stupid_trigger3
 BEFORE UPDATE ON trigger_test
 FOR EACH ROW EXECUTE PROCEDURE stupid3();
@@ -365,8 +365,8 @@ DROP TRIGGER stupid_trigger3 ON trigger_test;
 -- Unicode variant
 CREATE FUNCTION stupid3u() RETURNS trigger
 AS $$
-    return u"foo"
-$$ LANGUAGE plpythonu;
+    return "foo"
+$$ LANGUAGE plpython3u;
 CREATE TRIGGER stupid_trigger3
 BEFORE UPDATE ON trigger_test
 FOR EACH ROW EXECUTE PROCEDURE stupid3u();
@@ -380,7 +380,7 @@ CREATE FUNCTION stupid4() RETURNS trigger
 AS $$
     del TD["new"]
     return "MODIFY";
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 CREATE TRIGGER stupid_trigger4
 BEFORE UPDATE ON trigger_test
 FOR EACH ROW EXECUTE PROCEDURE stupid4();
@@ -394,7 +394,7 @@ CREATE FUNCTION stupid5() RETURNS trigger
 AS $$
     TD["new"] = ['foo', 'bar']
     return "MODIFY";
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 CREATE TRIGGER stupid_trigger5
 BEFORE UPDATE ON trigger_test
 FOR EACH ROW EXECUTE PROCEDURE stupid5();
@@ -408,7 +408,7 @@ CREATE FUNCTION stupid6() RETURNS trigger
 AS $$
     TD["new"] = {1: 'foo', 2: 'bar'}
     return "MODIFY";
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 CREATE TRIGGER stupid_trigger6
 BEFORE UPDATE ON trigger_test
 FOR EACH ROW EXECUTE PROCEDURE stupid6();
@@ -422,7 +422,7 @@ CREATE FUNCTION stupid7() RETURNS trigger
 AS $$
     TD["new"] = {'v': 'foo', 'a': 'bar'}
     return "MODIFY";
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 CREATE TRIGGER stupid_trigger7
 BEFORE UPDATE ON trigger_test
 FOR EACH ROW EXECUTE PROCEDURE stupid7();
@@ -434,9 +434,9 @@ DROP TRIGGER stupid_trigger7 ON trigger_test;
 -- Unicode variant
 CREATE FUNCTION stupid7u() RETURNS trigger
 AS $$
-    TD["new"] = {u'v': 'foo', u'a': 'bar'}
+    TD["new"] = {'v': 'foo', 'a': 'bar'}
     return "MODIFY"
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 CREATE TRIGGER stupid_trigger7
 BEFORE UPDATE ON trigger_test
 FOR EACH ROW EXECUTE PROCEDURE stupid7u();
@@ -461,7 +461,7 @@ CREATE FUNCTION test_null() RETURNS trigger
 AS $$
     TD["new"]['v'] = None
     return "MODIFY"
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 CREATE TRIGGER test_null_trigger
 BEFORE UPDATE ON trigger_test
 FOR EACH ROW EXECUTE PROCEDURE test_null();
@@ -481,7 +481,7 @@ SET DateStyle = 'ISO';
 CREATE FUNCTION set_modif_time() RETURNS trigger AS $$
     TD['new']['modif_time'] = '2010-10-13 21:57:28.930486'
     return 'MODIFY'
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 CREATE TABLE pb (a TEXT, modif_time TIMESTAMP(0) WITHOUT TIME ZONE);
 CREATE TRIGGER set_modif_time BEFORE UPDATE ON pb
   FOR EACH ROW EXECUTE PROCEDURE set_modif_time();
@@ -507,7 +507,7 @@ CREATE FUNCTION composite_trigger_f() RETURNS trigger AS $$
     TD['new']['f1'] = (3, False)
     TD['new']['f2'] = {'k': 7, 'l': 'yes', 'ignored': 10}
     return 'MODIFY'
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 CREATE TRIGGER composite_trigger BEFORE INSERT ON composite_trigger_test
   FOR EACH ROW EXECUTE PROCEDURE composite_trigger_f();
 INSERT INTO composite_trigger_test VALUES (NULL, NULL);
@@ -521,7 +521,7 @@ SELECT * FROM composite_trigger_test;
 CREATE TABLE composite_trigger_noop_test (f1 comp1, f2 comp2);
 CREATE FUNCTION composite_trigger_noop_f() RETURNS trigger AS $$
     return 'MODIFY'
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 CREATE TRIGGER composite_trigger_noop BEFORE INSERT ON composite_trigger_noop_test
   FOR EACH ROW EXECUTE PROCEDURE composite_trigger_noop_f();
 INSERT INTO composite_trigger_noop_test VALUES (NULL, NULL);
@@ -540,7 +540,7 @@ CREATE TYPE comp3 AS (c1 comp1, c2 comp2, m integer);
 CREATE TABLE composite_trigger_nested_test(c comp3);
 CREATE FUNCTION composite_trigger_nested_f() RETURNS trigger AS $$
     return 'MODIFY'
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 CREATE TRIGGER composite_trigger_nested BEFORE INSERT ON \
composite_trigger_nested_test  FOR EACH ROW EXECUTE PROCEDURE \
composite_trigger_nested_f();  INSERT INTO composite_trigger_nested_test VALUES \
(NULL); @@ -555,7 +555,7 @@ SELECT * FROM composite_trigger_nested_test;
 (3 rows)
 
 -- check that using a function as a trigger over two tables works correctly
-CREATE FUNCTION trig1234() RETURNS trigger LANGUAGE plpythonu AS $$
+CREATE FUNCTION trig1234() RETURNS trigger LANGUAGE plpython3u AS $$
     TD["new"]["data"] = '1234'
     return 'MODIFY'
 $$;
@@ -581,7 +581,7 @@ SELECT * FROM b;
 -- check that SQL run in trigger code can see transition tables
 CREATE TABLE transition_table_test (id int, name text);
 INSERT INTO transition_table_test VALUES (1, 'a');
-CREATE FUNCTION transition_table_test_f() RETURNS trigger LANGUAGE plpythonu AS
+CREATE FUNCTION transition_table_test_f() RETURNS trigger LANGUAGE plpython3u AS
 $$
     rv = plpy.execute("SELECT * FROM old_table")
     assert(rv.nrows() == 1)
@@ -601,7 +601,7 @@ DROP TABLE transition_table_test;
 DROP FUNCTION transition_table_test_f();
 -- dealing with generated columns
 CREATE FUNCTION generated_test_func1() RETURNS trigger
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 AS $$
 TD['new']['j'] = 5  # not allowed
 return 'MODIFY'
diff --git a/src/pl/plpython/expected/plpython_types.out \
b/src/pl/plpython/expected/plpython_types.out index 0a2659fe292..a470911c2ec 100644
--- a/src/pl/plpython/expected/plpython_types.out
+++ b/src/pl/plpython/expected/plpython_types.out
@@ -7,23 +7,23 @@
 CREATE FUNCTION test_type_conversion_bool(x bool) RETURNS bool AS $$
 plpy.info(x, type(x))
 return x
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT * FROM test_type_conversion_bool(true);
-INFO:  (True, <type 'bool'>)
+INFO:  (True, <class 'bool'>)
  test_type_conversion_bool 
 ---------------------------
  t
 (1 row)
 
 SELECT * FROM test_type_conversion_bool(false);
-INFO:  (False, <type 'bool'>)
+INFO:  (False, <class 'bool'>)
  test_type_conversion_bool 
 ---------------------------
  f
 (1 row)
 
 SELECT * FROM test_type_conversion_bool(null);
-INFO:  (None, <type 'NoneType'>)
+INFO:  (None, <class 'NoneType'>)
  test_type_conversion_bool 
 ---------------------------
  
@@ -48,7 +48,7 @@ elif n == 5:
    ret = [0]
 plpy.info(ret, not not ret)
 return ret
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT * FROM test_type_conversion_bool_other(0);
 INFO:  (0, False)
  test_type_conversion_bool_other 
@@ -94,16 +94,16 @@ INFO:  ([0], True)
 CREATE FUNCTION test_type_conversion_char(x char) RETURNS char AS $$
 plpy.info(x, type(x))
 return x
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT * FROM test_type_conversion_char('a');
-INFO:  ('a', <type 'str'>)
+INFO:  ('a', <class 'str'>)
  test_type_conversion_char 
 ---------------------------
  a
 (1 row)
 
 SELECT * FROM test_type_conversion_char(null);
-INFO:  (None, <type 'NoneType'>)
+INFO:  (None, <class 'NoneType'>)
  test_type_conversion_char 
 ---------------------------
  
@@ -112,23 +112,23 @@ INFO:  (None, <type 'NoneType'>)
 CREATE FUNCTION test_type_conversion_int2(x int2) RETURNS int2 AS $$
 plpy.info(x, type(x))
 return x
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT * FROM test_type_conversion_int2(100::int2);
-INFO:  (100, <type 'int'>)
+INFO:  (100, <class 'int'>)
  test_type_conversion_int2 
 ---------------------------
                        100
 (1 row)
 
 SELECT * FROM test_type_conversion_int2(-100::int2);
-INFO:  (-100, <type 'int'>)
+INFO:  (-100, <class 'int'>)
  test_type_conversion_int2 
 ---------------------------
                       -100
 (1 row)
 
 SELECT * FROM test_type_conversion_int2(null);
-INFO:  (None, <type 'NoneType'>)
+INFO:  (None, <class 'NoneType'>)
  test_type_conversion_int2 
 ---------------------------
                           
@@ -137,23 +137,23 @@ INFO:  (None, <type 'NoneType'>)
 CREATE FUNCTION test_type_conversion_int4(x int4) RETURNS int4 AS $$
 plpy.info(x, type(x))
 return x
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT * FROM test_type_conversion_int4(100);
-INFO:  (100, <type 'int'>)
+INFO:  (100, <class 'int'>)
  test_type_conversion_int4 
 ---------------------------
                        100
 (1 row)
 
 SELECT * FROM test_type_conversion_int4(-100);
-INFO:  (-100, <type 'int'>)
+INFO:  (-100, <class 'int'>)
  test_type_conversion_int4 
 ---------------------------
                       -100
 (1 row)
 
 SELECT * FROM test_type_conversion_int4(null);
-INFO:  (None, <type 'NoneType'>)
+INFO:  (None, <class 'NoneType'>)
  test_type_conversion_int4 
 ---------------------------
                           
@@ -162,30 +162,30 @@ INFO:  (None, <type 'NoneType'>)
 CREATE FUNCTION test_type_conversion_int8(x int8) RETURNS int8 AS $$
 plpy.info(x, type(x))
 return x
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT * FROM test_type_conversion_int8(100);
-INFO:  (100L, <type 'long'>)
+INFO:  (100, <class 'int'>)
  test_type_conversion_int8 
 ---------------------------
                        100
 (1 row)
 
 SELECT * FROM test_type_conversion_int8(-100);
-INFO:  (-100L, <type 'long'>)
+INFO:  (-100, <class 'int'>)
  test_type_conversion_int8 
 ---------------------------
                       -100
 (1 row)
 
 SELECT * FROM test_type_conversion_int8(5000000000);
-INFO:  (5000000000L, <type 'long'>)
+INFO:  (5000000000, <class 'int'>)
  test_type_conversion_int8 
 ---------------------------
                 5000000000
 (1 row)
 
 SELECT * FROM test_type_conversion_int8(null);
-INFO:  (None, <type 'NoneType'>)
+INFO:  (None, <class 'NoneType'>)
  test_type_conversion_int8 
 ---------------------------
                           
@@ -196,7 +196,7 @@ CREATE FUNCTION test_type_conversion_numeric(x numeric) RETURNS \
numeric AS $$  # between decimal and cdecimal
 plpy.info(str(x), x.__class__.__name__)
 return x
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT * FROM test_type_conversion_numeric(100);
 INFO:  ('100', 'Decimal')
  test_type_conversion_numeric 
@@ -256,30 +256,30 @@ INFO:  ('None', 'NoneType')
 CREATE FUNCTION test_type_conversion_float4(x float4) RETURNS float4 AS $$
 plpy.info(x, type(x))
 return x
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT * FROM test_type_conversion_float4(100);
-INFO:  (100.0, <type 'float'>)
+INFO:  (100.0, <class 'float'>)
  test_type_conversion_float4 
 -----------------------------
                          100
 (1 row)
 
 SELECT * FROM test_type_conversion_float4(-100);
-INFO:  (-100.0, <type 'float'>)
+INFO:  (-100.0, <class 'float'>)
  test_type_conversion_float4 
 -----------------------------
                         -100
 (1 row)
 
 SELECT * FROM test_type_conversion_float4(5000.5);
-INFO:  (5000.5, <type 'float'>)
+INFO:  (5000.5, <class 'float'>)
  test_type_conversion_float4 
 -----------------------------
                       5000.5
 (1 row)
 
 SELECT * FROM test_type_conversion_float4(null);
-INFO:  (None, <type 'NoneType'>)
+INFO:  (None, <class 'NoneType'>)
  test_type_conversion_float4 
 -----------------------------
                             
@@ -288,37 +288,37 @@ INFO:  (None, <type 'NoneType'>)
 CREATE FUNCTION test_type_conversion_float8(x float8) RETURNS float8 AS $$
 plpy.info(x, type(x))
 return x
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT * FROM test_type_conversion_float8(100);
-INFO:  (100.0, <type 'float'>)
+INFO:  (100.0, <class 'float'>)
  test_type_conversion_float8 
 -----------------------------
                          100
 (1 row)
 
 SELECT * FROM test_type_conversion_float8(-100);
-INFO:  (-100.0, <type 'float'>)
+INFO:  (-100.0, <class 'float'>)
  test_type_conversion_float8 
 -----------------------------
                         -100
 (1 row)
 
 SELECT * FROM test_type_conversion_float8(5000000000.5);
-INFO:  (5000000000.5, <type 'float'>)
+INFO:  (5000000000.5, <class 'float'>)
  test_type_conversion_float8 
 -----------------------------
                 5000000000.5
 (1 row)
 
 SELECT * FROM test_type_conversion_float8(null);
-INFO:  (None, <type 'NoneType'>)
+INFO:  (None, <class 'NoneType'>)
  test_type_conversion_float8 
 -----------------------------
                             
 (1 row)
 
 SELECT * FROM test_type_conversion_float8(100100100.654321);
-INFO:  (100100100.654321, <type 'float'>)
+INFO:  (100100100.654321, <class 'float'>)
  test_type_conversion_float8 
 -----------------------------
             100100100.654321
@@ -327,23 +327,23 @@ INFO:  (100100100.654321, <type 'float'>)
 CREATE FUNCTION test_type_conversion_oid(x oid) RETURNS oid AS $$
 plpy.info(x, type(x))
 return x
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT * FROM test_type_conversion_oid(100);
-INFO:  (100L, <type 'long'>)
+INFO:  (100, <class 'int'>)
  test_type_conversion_oid 
 --------------------------
                       100
 (1 row)
 
 SELECT * FROM test_type_conversion_oid(2147483649);
-INFO:  (2147483649L, <type 'long'>)
+INFO:  (2147483649, <class 'int'>)
  test_type_conversion_oid 
 --------------------------
                2147483649
 (1 row)
 
 SELECT * FROM test_type_conversion_oid(null);
-INFO:  (None, <type 'NoneType'>)
+INFO:  (None, <class 'NoneType'>)
  test_type_conversion_oid 
 --------------------------
                          
@@ -352,16 +352,16 @@ INFO:  (None, <type 'NoneType'>)
 CREATE FUNCTION test_type_conversion_text(x text) RETURNS text AS $$
 plpy.info(x, type(x))
 return x
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT * FROM test_type_conversion_text('hello world');
-INFO:  ('hello world', <type 'str'>)
+INFO:  ('hello world', <class 'str'>)
  test_type_conversion_text 
 ---------------------------
  hello world
 (1 row)
 
 SELECT * FROM test_type_conversion_text(null);
-INFO:  (None, <type 'NoneType'>)
+INFO:  (None, <class 'NoneType'>)
  test_type_conversion_text 
 ---------------------------
  
@@ -370,23 +370,23 @@ INFO:  (None, <type 'NoneType'>)
 CREATE FUNCTION test_type_conversion_bytea(x bytea) RETURNS bytea AS $$
 plpy.info(x, type(x))
 return x
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT * FROM test_type_conversion_bytea('hello world');
-INFO:  ('hello world', <type 'str'>)
+INFO:  (b'hello world', <class 'bytes'>)
  test_type_conversion_bytea 
 ----------------------------
  \x68656c6c6f20776f726c64
 (1 row)
 
 SELECT * FROM test_type_conversion_bytea(E'null\\000byte');
-INFO:  ('null\x00byte', <type 'str'>)
+INFO:  (b'null\x00byte', <class 'bytes'>)
  test_type_conversion_bytea 
 ----------------------------
  \x6e756c6c0062797465
 (1 row)
 
 SELECT * FROM test_type_conversion_bytea(null);
-INFO:  (None, <type 'NoneType'>)
+INFO:  (None, <class 'NoneType'>)
  test_type_conversion_bytea 
 ----------------------------
  
@@ -395,14 +395,14 @@ INFO:  (None, <type 'NoneType'>)
 CREATE FUNCTION test_type_marshal() RETURNS bytea AS $$
 import marshal
 return marshal.dumps('hello world')
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 CREATE FUNCTION test_type_unmarshal(x bytea) RETURNS text AS $$
 import marshal
 try:
     return marshal.loads(x)
 except ValueError as e:
     return 'FAILED: ' + str(e)
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT test_type_unmarshal(x) FROM test_type_marshal() x;
  test_type_unmarshal 
 ---------------------
@@ -415,7 +415,7 @@ SELECT test_type_unmarshal(x) FROM test_type_marshal() x;
 CREATE DOMAIN booltrue AS bool CHECK (VALUE IS TRUE OR VALUE IS NULL);
 CREATE FUNCTION test_type_conversion_booltrue(x booltrue, y bool) RETURNS booltrue \
AS $$  return y
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT * FROM test_type_conversion_booltrue(true, true);
  test_type_conversion_booltrue 
 -------------------------------
@@ -432,21 +432,21 @@ CREATE DOMAIN uint2 AS int2 CHECK (VALUE >= 0);
 CREATE FUNCTION test_type_conversion_uint2(x uint2, y int) RETURNS uint2 AS $$
 plpy.info(x, type(x))
 return y
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT * FROM test_type_conversion_uint2(100::uint2, 50);
-INFO:  (100, <type 'int'>)
+INFO:  (100, <class 'int'>)
  test_type_conversion_uint2 
 ----------------------------
                          50
 (1 row)
 
 SELECT * FROM test_type_conversion_uint2(100::uint2, -50);
-INFO:  (100, <type 'int'>)
+INFO:  (100, <class 'int'>)
 ERROR:  value for domain uint2 violates check constraint "uint2_check"
 CONTEXT:  while creating return value
 PL/Python function "test_type_conversion_uint2"
 SELECT * FROM test_type_conversion_uint2(null, 1);
-INFO:  (None, <type 'NoneType'>)
+INFO:  (None, <class 'NoneType'>)
  test_type_conversion_uint2 
 ----------------------------
                           1
@@ -455,7 +455,7 @@ INFO:  (None, <type 'NoneType'>)
 CREATE DOMAIN nnint AS int CHECK (VALUE IS NOT NULL);
 CREATE FUNCTION test_type_conversion_nnint(x nnint, y int) RETURNS nnint AS $$
 return y
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT * FROM test_type_conversion_nnint(10, 20);
  test_type_conversion_nnint 
 ----------------------------
@@ -472,9 +472,9 @@ CREATE DOMAIN bytea10 AS bytea CHECK (octet_length(VALUE) = 10 \
AND VALUE IS NOT  CREATE FUNCTION test_type_conversion_bytea10(x bytea10, y bytea) \
RETURNS bytea10 AS $$  plpy.info(x, type(x))
 return y
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT * FROM test_type_conversion_bytea10('hello wold', 'hello wold');
-INFO:  ('hello wold', <type 'str'>)
+INFO:  (b'hello wold', <class 'bytes'>)
  test_type_conversion_bytea10 
 ------------------------------
  \x68656c6c6f20776f6c64
@@ -483,14 +483,14 @@ INFO:  ('hello wold', <type 'str'>)
 SELECT * FROM test_type_conversion_bytea10('hello world', 'hello wold');
 ERROR:  value for domain bytea10 violates check constraint "bytea10_check"
 SELECT * FROM test_type_conversion_bytea10('hello word', 'hello world');
-INFO:  ('hello word', <type 'str'>)
+INFO:  (b'hello word', <class 'bytes'>)
 ERROR:  value for domain bytea10 violates check constraint "bytea10_check"
 CONTEXT:  while creating return value
 PL/Python function "test_type_conversion_bytea10"
 SELECT * FROM test_type_conversion_bytea10(null, 'hello word');
 ERROR:  value for domain bytea10 violates check constraint "bytea10_check"
 SELECT * FROM test_type_conversion_bytea10('hello word', null);
-INFO:  ('hello word', <type 'str'>)
+INFO:  (b'hello word', <class 'bytes'>)
 ERROR:  value for domain bytea10 violates check constraint "bytea10_check"
 CONTEXT:  while creating return value
 PL/Python function "test_type_conversion_bytea10"
@@ -500,58 +500,58 @@ PL/Python function "test_type_conversion_bytea10"
 CREATE FUNCTION test_type_conversion_array_int4(x int4[]) RETURNS int4[] AS $$
 plpy.info(x, type(x))
 return x
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT * FROM test_type_conversion_array_int4(ARRAY[0, 100]);
-INFO:  ([0, 100], <type 'list'>)
+INFO:  ([0, 100], <class 'list'>)
  test_type_conversion_array_int4 
 ---------------------------------
  {0,100}
 (1 row)
 
 SELECT * FROM test_type_conversion_array_int4(ARRAY[0,-100,55]);
-INFO:  ([0, -100, 55], <type 'list'>)
+INFO:  ([0, -100, 55], <class 'list'>)
  test_type_conversion_array_int4 
 ---------------------------------
  {0,-100,55}
 (1 row)
 
 SELECT * FROM test_type_conversion_array_int4(ARRAY[NULL,1]);
-INFO:  ([None, 1], <type 'list'>)
+INFO:  ([None, 1], <class 'list'>)
  test_type_conversion_array_int4 
 ---------------------------------
  {NULL,1}
 (1 row)
 
 SELECT * FROM test_type_conversion_array_int4(ARRAY[]::integer[]);
-INFO:  ([], <type 'list'>)
+INFO:  ([], <class 'list'>)
  test_type_conversion_array_int4 
 ---------------------------------
  {}
 (1 row)
 
 SELECT * FROM test_type_conversion_array_int4(NULL);
-INFO:  (None, <type 'NoneType'>)
+INFO:  (None, <class 'NoneType'>)
  test_type_conversion_array_int4 
 ---------------------------------
  
 (1 row)
 
 SELECT * FROM test_type_conversion_array_int4(ARRAY[[1,2,3],[4,5,6]]);
-INFO:  ([[1, 2, 3], [4, 5, 6]], <type 'list'>)
+INFO:  ([[1, 2, 3], [4, 5, 6]], <class 'list'>)
  test_type_conversion_array_int4 
 ---------------------------------
  {{1,2,3},{4,5,6}}
 (1 row)
 
 SELECT * FROM test_type_conversion_array_int4(ARRAY[[[1,2,NULL],[NULL,5,6]],[[NULL,8,9],[10,11,12]]]);
                
-INFO:  ([[[1, 2, None], [None, 5, 6]], [[None, 8, 9], [10, 11, 12]]], <type 'list'>)
+INFO:  ([[[1, 2, None], [None, 5, 6]], [[None, 8, 9], [10, 11, 12]]], <class \
'list'>)  test_type_conversion_array_int4          
 ---------------------------------------------------
  {{{1,2,NULL},{NULL,5,6}},{{NULL,8,9},{10,11,12}}}
 (1 row)
 
 SELECT * FROM test_type_conversion_array_int4('[2:4]={1,2,3}');
-INFO:  ([1, 2, 3], <type 'list'>)
+INFO:  ([1, 2, 3], <class 'list'>)
  test_type_conversion_array_int4 
 ---------------------------------
  {1,2,3}
@@ -560,9 +560,9 @@ INFO:  ([1, 2, 3], <type 'list'>)
 CREATE FUNCTION test_type_conversion_array_int8(x int8[]) RETURNS int8[] AS $$
 plpy.info(x, type(x))
 return x
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT * FROM test_type_conversion_array_int8(ARRAY[[[1,2,NULL],[NULL,5,6]],[[NULL,8,9],[10,11,12]]]::int8[]);
                
-INFO:  ([[[1L, 2L, None], [None, 5L, 6L]], [[None, 8L, 9L], [10L, 11L, 12L]]], <type \
'list'>) +INFO:  ([[[1, 2, None], [None, 5, 6]], [[None, 8, 9], [10, 11, 12]]], \
<class 'list'>)  test_type_conversion_array_int8          
 ---------------------------------------------------
  {{{1,2,NULL},{NULL,5,6}},{{NULL,8,9},{10,11,12}}}
@@ -571,10 +571,10 @@ INFO:  ([[[1L, 2L, None], [None, 5L, 6L]], [[None, 8L, 9L], \
[10L, 11L, 12L]]], <  CREATE FUNCTION test_type_conversion_array_date(x date[]) \
RETURNS date[] AS $$  plpy.info(x, type(x))
 return x
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT * FROM test_type_conversion_array_date(ARRAY[[['2016-09-21','2016-09-22',NULL],[NULL,'2016-10-21','2016-10-22']],
                
             [[NULL,'2016-11-21','2016-10-21'],['2015-09-21','2015-09-22','2014-09-21']]]::date[]);
                
-INFO:  ([[['09-21-2016', '09-22-2016', None], [None, '10-21-2016', '10-22-2016']], \
[[None, '11-21-2016', '10-21-2016'], ['09-21-2015', '09-22-2015', '09-21-2014']]], \
<type 'list'>) +INFO:  ([[['09-21-2016', '09-22-2016', None], [None, '10-21-2016', \
'10-22-2016']], [[None, '11-21-2016', '10-21-2016'], ['09-21-2015', '09-22-2015', \
                '09-21-2014']]], <class 'list'>)
                                                  test_type_conversion_array_date     \
                
 ---------------------------------------------------------------------------------------------------------------------------------
  {{{09-21-2016,09-22-2016,NULL},{NULL,10-21-2016,10-22-2016}},{{NULL,11-21-2016,10-21-2016},{09-21-2015,09-22-2015,09-21-2014}}}
 @@ -583,12 +583,12 @@ INFO:  ([[['09-21-2016', '09-22-2016', None], [None, \
'10-21-2016', '10-22-2016']  CREATE FUNCTION test_type_conversion_array_timestamp(x \
timestamp[]) RETURNS timestamp[] AS $$  plpy.info(x, type(x))
 return x
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT * FROM test_type_conversion_array_timestamp(ARRAY[[['2016-09-21 \
                15:34:24.078792-04','2016-10-22 11:34:24.078795-04',NULL],
             [NULL,'2016-10-21 11:34:25.078792-04','2016-10-21 11:34:24.098792-04']],
             [[NULL,'2016-01-21 11:34:24.078792-04','2016-11-21 11:34:24.108792-04'],
             ['2015-09-21 11:34:24.079792-04','2014-09-21 \
                11:34:24.078792-04','2013-09-21 11:34:24.078792-04']]]::timestamp[]);
-INFO:  ([[['Wed Sep 21 15:34:24.078792 2016', 'Sat Oct 22 11:34:24.078795 2016', \
None], [None, 'Fri Oct 21 11:34:25.078792 2016', 'Fri Oct 21 11:34:24.098792 2016']], \
[[None, 'Thu Jan 21 11:34:24.078792 2016', 'Mon Nov 21 11:34:24.108792 2016'], ['Mon \
Sep 21 11:34:24.079792 2015', 'Sun Sep 21 11:34:24.078792 2014', 'Sat Sep 21 \
11:34:24.078792 2013']]], <type 'list'>) +INFO:  ([[['Wed Sep 21 15:34:24.078792 \
2016', 'Sat Oct 22 11:34:24.078795 2016', None], [None, 'Fri Oct 21 11:34:25.078792 \
2016', 'Fri Oct 21 11:34:24.098792 2016']], [[None, 'Thu Jan 21 11:34:24.078792 \
2016', 'Mon Nov 21 11:34:24.108792 2016'], ['Mon Sep 21 11:34:24.079792 2015', 'Sun \
Sep 21 11:34:24.078792 2014', 'Sat Sep 21 11:34:24.078792 2013']]], <class 'list'>)  \
test_type_conversion_array_timestamp                                                  \
                
 ------------------------------------------------------------------------------------- \
-------------------------------------------------------------------------------------- \
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
  {{{"Wed Sep 21 15:34:24.078792 2016","Sat Oct 22 11:34:24.078795 \
2016",NULL},{NULL,"Fri Oct 21 11:34:25.078792 2016","Fri Oct 21 11:34:24.098792 \
2016"}},{{NULL,"Thu Jan 21 11:34:24.078792 2016","Mon Nov 21 11:34:24.108792 \
2016"},{"Mon Sep 21 11:34:24.079792 2015","Sun Sep 21 11:34:24.078792 2014","Sat Sep \
21 11:34:24.078792 2013"}}} @@ -598,9 +598,9 @@ CREATE OR REPLACE FUNCTION \
pyreturnmultidemint4(h int4, i int4, j int4, k int4 )  m = [[[[x for x in range(h)] \
for y in range(i)] for z in range(j)] for w in range(k)]  plpy.info(m, type(m))
 return m
-$BODY$ LANGUAGE plpythonu;
+$BODY$ LANGUAGE plpython3u;
 select pyreturnmultidemint4(8,5,3,2);
-INFO:  ([[[[0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, \
7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7]], [[0, 1, 2, 3, 4, 5, 6, 7], \
[0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, \
2, 3, 4, 5, 6, 7]], [[0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, \
4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7]]], [[[0, 1, 2, 3, 4, \
5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, \
7], [0, 1, 2, 3, 4, 5, 6, 7]], [[0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], \
[0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7]], [[0, \
1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, \
3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7]]]], <type 'list'>) +INFO:  ([[[[0, 1, 2, 3, \
4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, \
6, 7], [0, 1, 2, 3, 4, 5, 6, 7]], [[0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, \
7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7]], \
[[0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, \
2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7]]], [[[0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, \
3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, \
5, 6, 7]], [[0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, \
7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7]], [[0, 1, 2, 3, 4, 5, 6, 7], \
[0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, \
2, 3, 4, 5, 6, 7]]]], <class 'list'>)  pyreturnmultidemint4                           \
                
 ------------------------------------------------------------------------------------- \
-------------------------------------------------------------------------------------- \
-------------------------------------------------------------------------------------- \
-------------------------------------------------------------------------------------- \
-------------------------------------------------------------------------------------- \
----------------------------------------------------------------------------------------------------------------------------------
  {{{{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3, \
4,5,6,7}},{{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0, \
1,2,3,4,5,6,7}},{{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6, \
7},{0,1,2,3,4,5,6,7}}},{{{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2, \
3,4,5,6,7},{0,1,2,3,4,5,6,7}},{{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{ \
0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7}},{{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7}}}}
 @@ -610,9 +610,9 @@ CREATE OR REPLACE FUNCTION pyreturnmultidemint8(h int4, i int4, \
j int4, k int4 )  m = [[[[x for x in range(h)] for y in range(i)] for z in range(j)] \
for w in range(k)]  plpy.info(m, type(m))
 return m
-$BODY$ LANGUAGE plpythonu;
+$BODY$ LANGUAGE plpython3u;
 select pyreturnmultidemint8(5,5,3,2);
-INFO:  ([[[[0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, \
1, 2, 3, 4]], [[0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], \
[0, 1, 2, 3, 4]], [[0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, \
4], [0, 1, 2, 3, 4]]], [[[0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, \
3, 4], [0, 1, 2, 3, 4]], [[0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, \
2, 3, 4], [0, 1, 2, 3, 4]], [[0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, \
1, 2, 3, 4], [0, 1, 2, 3, 4]]]], <type 'list'>) +INFO:  ([[[[0, 1, 2, 3, 4], [0, 1, \
2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4]], [[0, 1, 2, 3, 4], [0, \
1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4]], [[0, 1, 2, 3, 4], \
[0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4]]], [[[0, 1, 2, 3, \
4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4]], [[0, 1, 2, \
3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4]], [[0, 1, \
2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4]]]], \
<class 'list'>)  pyreturnmultidemint8                                                 \
                
 ------------------------------------------------------------------------------------- \
-------------------------------------------------------------------------------------- \
-------------------------------------------------------------------------------------- \
--------------------------------------------------------------------------------------------------------------------------
  {{{{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4}},{{0,1,2,3,4},{0,1,2, \
3,4},{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4}},{{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4},{0,1,2, \
3,4},{0,1,2,3,4}}},{{{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4}},{{0, \
1,2,3,4},{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4}},{{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4}}}}
 @@ -622,9 +622,9 @@ CREATE OR REPLACE FUNCTION pyreturnmultidemfloat4(h int4, i \
int4, j int4, k int4  m = [[[[x for x in range(h)] for y in range(i)] for z in \
range(j)] for w in range(k)]  plpy.info(m, type(m))
 return m
-$BODY$ LANGUAGE plpythonu;
+$BODY$ LANGUAGE plpython3u;
 select pyreturnmultidemfloat4(6,5,3,2);
-INFO:  ([[[[0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, \
4, 5], [0, 1, 2, 3, 4, 5]], [[0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, \
5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5]], [[0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], \
[0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5]]], [[[0, 1, 2, 3, 4, 5], \
[0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5]], [[0, \
1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, \
3, 4, 5]], [[0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, \
4, 5], [0, 1, 2, 3, 4, 5]]]], <type 'list'>) +INFO:  ([[[[0, 1, 2, 3, 4, 5], [0, 1, \
2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5]], [[0, 1, 2, \
3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, \
5]], [[0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], \
[0, 1, 2, 3, 4, 5]]], [[[0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], \
[0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5]], [[0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, \
1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5]], [[0, 1, 2, 3, 4, 5], [0, 1, \
2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5]]]], <class \
'list'>)  pyreturnmultidemfloat4                                                      \
                
 ------------------------------------------------------------------------------------- \
-------------------------------------------------------------------------------------- \
-------------------------------------------------------------------------------------- \
-------------------------------------------------------------------------------------- \
------------------------------------------------------------------------------------------------
  {{{{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5}},{{0,1,2,3, \
4,5},{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5}},{{0,1,2,3,4,5},{0,1,2,3, \
4,5},{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5}}},{{{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2, \
3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5}},{{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2, \
3,4,5},{0,1,2,3,4,5}},{{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5}}}}
 @@ -634,9 +634,9 @@ CREATE OR REPLACE FUNCTION pyreturnmultidemfloat8(h int4, i \
int4, j int4, k int4  m = [[[[x for x in range(h)] for y in range(i)] for z in \
range(j)] for w in range(k)]  plpy.info(m, type(m))
 return m
-$BODY$ LANGUAGE plpythonu;
+$BODY$ LANGUAGE plpython3u;
 select pyreturnmultidemfloat8(7,5,3,2);
-INFO:  ([[[[0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, \
1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6]], [[0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, \
6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6]], [[0, 1, 2, \
3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, \
1, 2, 3, 4, 5, 6]]], [[[0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, \
5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6]], [[0, 1, 2, 3, 4, 5, 6], [0, 1, \
2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6]], \
[[0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, \
5, 6], [0, 1, 2, 3, 4, 5, 6]]]], <type 'list'>) +INFO:  ([[[[0, 1, 2, 3, 4, 5, 6], \
[0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, \
5, 6]], [[0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, \
2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6]], [[0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, \
6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6]]], [[[0, 1, \
2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], \
[0, 1, 2, 3, 4, 5, 6]], [[0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, \
4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6]], [[0, 1, 2, 3, 4, 5, 6], [0, \
1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, \
6]]]], <class 'list'>)  pyreturnmultidemfloat8                                        \
                
 ------------------------------------------------------------------------------------- \
-------------------------------------------------------------------------------------- \
-------------------------------------------------------------------------------------- \
-------------------------------------------------------------------------------------- \
------------------------------------------------------------------------------------------------------------------------------------------------------------
  {{{{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6}}, \
{{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6}},{{0, \
1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6}}},{{{0,1, \
2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6}},{{0,1,2,3, \
4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6}},{{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6}}}}
 @@ -645,16 +645,16 @@ INFO:  ([[[[0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, \
1, 2, 3, 4, 5, 6],  CREATE FUNCTION test_type_conversion_array_text(x text[]) RETURNS \
text[] AS $$  plpy.info(x, type(x))
 return x
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT * FROM test_type_conversion_array_text(ARRAY['foo', 'bar']);
-INFO:  (['foo', 'bar'], <type 'list'>)
+INFO:  (['foo', 'bar'], <class 'list'>)
  test_type_conversion_array_text 
 ---------------------------------
  {foo,bar}
 (1 row)
 
 SELECT * FROM test_type_conversion_array_text(ARRAY[['foo', 'bar'],['foo2', \
                'bar2']]);
-INFO:  ([['foo', 'bar'], ['foo2', 'bar2']], <type 'list'>)
+INFO:  ([['foo', 'bar'], ['foo2', 'bar2']], <class 'list'>)
  test_type_conversion_array_text 
 ---------------------------------
  {{foo,bar},{foo2,bar2}}
@@ -663,9 +663,9 @@ INFO:  ([['foo', 'bar'], ['foo2', 'bar2']], <type 'list'>)
 CREATE FUNCTION test_type_conversion_array_bytea(x bytea[]) RETURNS bytea[] AS $$
 plpy.info(x, type(x))
 return x
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT * FROM test_type_conversion_array_bytea(ARRAY[E'\\xdeadbeef'::bytea, NULL]);
-INFO:  (['\xde\xad\xbe\xef', None], <type 'list'>)
+INFO:  ([b'\xde\xad\xbe\xef', None], <class 'list'>)
  test_type_conversion_array_bytea 
 ----------------------------------
  {"\\xdeadbeef",NULL}
@@ -673,7 +673,7 @@ INFO:  (['\xde\xad\xbe\xef', None], <type 'list'>)
 
 CREATE FUNCTION test_type_conversion_array_mixed1() RETURNS text[] AS $$
 return [123, 'abc']
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT * FROM test_type_conversion_array_mixed1();
  test_type_conversion_array_mixed1 
 -----------------------------------
@@ -682,14 +682,14 @@ SELECT * FROM test_type_conversion_array_mixed1();
 
 CREATE FUNCTION test_type_conversion_array_mixed2() RETURNS int[] AS $$
 return [123, 'abc']
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT * FROM test_type_conversion_array_mixed2();
 ERROR:  invalid input syntax for type integer: "abc"
 CONTEXT:  while creating return value
 PL/Python function "test_type_conversion_array_mixed2"
 CREATE FUNCTION test_type_conversion_mdarray_malformed() RETURNS int[] AS $$
 return [[1,2,3],[4,5]]
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT * FROM test_type_conversion_mdarray_malformed();
 ERROR:  wrong length of inner sequence: has length 2, but 3 was expected
 DETAIL:  To construct a multidimensional array, the inner sequences must all have \
the same length. @@ -697,14 +697,14 @@ CONTEXT:  while creating return value
 PL/Python function "test_type_conversion_mdarray_malformed"
 CREATE FUNCTION test_type_conversion_mdarray_toodeep() RETURNS int[] AS $$
 return [[[[[[[1]]]]]]]
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT * FROM test_type_conversion_mdarray_toodeep();
 ERROR:  number of array dimensions exceeds the maximum allowed (6)
 CONTEXT:  while creating return value
 PL/Python function "test_type_conversion_mdarray_toodeep"
 CREATE FUNCTION test_type_conversion_array_record() RETURNS type_record[] AS $$
 return [{'first': 'one', 'second': 42}, {'first': 'two', 'second': 11}]
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT * FROM test_type_conversion_array_record();
  test_type_conversion_array_record 
 -----------------------------------
@@ -713,7 +713,7 @@ SELECT * FROM test_type_conversion_array_record();
 
 CREATE FUNCTION test_type_conversion_array_string() RETURNS text[] AS $$
 return 'abc'
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT * FROM test_type_conversion_array_string();
  test_type_conversion_array_string 
 -----------------------------------
@@ -722,7 +722,7 @@ SELECT * FROM test_type_conversion_array_string();
 
 CREATE FUNCTION test_type_conversion_array_tuple() RETURNS text[] AS $$
 return ('abc', 'def')
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT * FROM test_type_conversion_array_tuple();
  test_type_conversion_array_tuple 
 ----------------------------------
@@ -731,7 +731,7 @@ SELECT * FROM test_type_conversion_array_tuple();
 
 CREATE FUNCTION test_type_conversion_array_error() RETURNS int[] AS $$
 return 5
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT * FROM test_type_conversion_array_error();
 ERROR:  return value of function with array return type is not a Python sequence
 CONTEXT:  while creating return value
@@ -743,16 +743,16 @@ CREATE DOMAIN ordered_pair_domain AS integer[] CHECK \
(array_length(VALUE,1)=2 AN  CREATE FUNCTION test_type_conversion_array_domain(x \
ordered_pair_domain) RETURNS ordered_pair_domain AS $$  plpy.info(x, type(x))
 return x
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT * FROM test_type_conversion_array_domain(ARRAY[0, 100]::ordered_pair_domain);
-INFO:  ([0, 100], <type 'list'>)
+INFO:  ([0, 100], <class 'list'>)
  test_type_conversion_array_domain 
 -----------------------------------
  {0,100}
 (1 row)
 
 SELECT * FROM test_type_conversion_array_domain(NULL::ordered_pair_domain);
-INFO:  (None, <type 'NoneType'>)
+INFO:  (None, <class 'NoneType'>)
  test_type_conversion_array_domain 
 -----------------------------------
  
@@ -760,7 +760,7 @@ INFO:  (None, <type 'NoneType'>)
 
 CREATE FUNCTION test_type_conversion_array_domain_check_violation() RETURNS \
ordered_pair_domain AS $$  return [2,1]
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT * FROM test_type_conversion_array_domain_check_violation();
 ERROR:  value for domain ordered_pair_domain violates check constraint \
"ordered_pair_domain_check"  CONTEXT:  while creating return value
@@ -771,9 +771,9 @@ PL/Python function \
"test_type_conversion_array_domain_check_violation"  CREATE FUNCTION \
test_read_uint2_array(x uint2[]) RETURNS uint2 AS $$  plpy.info(x, type(x))
 return x[0]
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 select test_read_uint2_array(array[1::uint2]);
-INFO:  ([1], <type 'list'>)
+INFO:  ([1], <class 'list'>)
  test_read_uint2_array 
 -----------------------
                      1
@@ -781,7 +781,7 @@ INFO:  ([1], <type 'list'>)
 
 CREATE FUNCTION test_build_uint2_array(x int2) RETURNS uint2[] AS $$
 return [x, x]
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 select test_build_uint2_array(1::int2);
  test_build_uint2_array 
 ------------------------
@@ -800,7 +800,7 @@ PL/Python function "test_build_uint2_array"
 CREATE FUNCTION test_type_conversion_domain_array(x integer[])
   RETURNS ordered_pair_domain[] AS $$
 return [x, x]
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 select test_type_conversion_domain_array(array[2,4]);
 ERROR:  return value of function with array return type is not a Python sequence
 CONTEXT:  while creating return value
@@ -813,9 +813,9 @@ CREATE FUNCTION test_type_conversion_domain_array2(x \
ordered_pair_domain)  RETURNS integer AS $$
 plpy.info(x, type(x))
 return x[1]
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 select test_type_conversion_domain_array2(array[2,4]);
-INFO:  ([2, 4], <type 'list'>)
+INFO:  ([2, 4], <class 'list'>)
  test_type_conversion_domain_array2 
 ------------------------------------
                                   4
@@ -827,9 +827,9 @@ CREATE FUNCTION test_type_conversion_array_domain_array(x \
ordered_pair_domain[])  RETURNS ordered_pair_domain AS $$
 plpy.info(x, type(x))
 return x[0]
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 select test_type_conversion_array_domain_array(array[array[2,4]::ordered_pair_domain]);
                
-INFO:  ([[2, 4]], <type 'list'>)
+INFO:  ([[2, 4]], <class 'list'>)
  test_type_conversion_array_domain_array 
 -----------------------------------------
  {2,4}
@@ -846,7 +846,7 @@ CREATE TABLE employee (
 INSERT INTO employee VALUES ('John', 100, 10), ('Mary', 200, 10);
 CREATE OR REPLACE FUNCTION test_composite_table_input(e employee) RETURNS integer AS \
$$  return e['basesalary'] + e['bonus']
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT name, test_composite_table_input(employee.*) FROM employee;
  name | test_composite_table_input 
 ------+----------------------------
@@ -876,7 +876,7 @@ CREATE TYPE named_pair AS (
 );
 CREATE OR REPLACE FUNCTION test_composite_type_input(p named_pair) RETURNS integer \
AS $$  return sum(p.values())
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT test_composite_type_input(row(1, 2));
  test_composite_type_input 
 ---------------------------
@@ -896,7 +896,7 @@ SELECT test_composite_type_input(row(1, 2));
 CREATE TYPE nnint_container AS (f1 int, f2 nnint);
 CREATE FUNCTION nnint_test(x int, y int) RETURNS nnint_container AS $$
 return {'f1': x, 'f2': y}
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT nnint_test(null, 3);
  nnint_test 
 ------------
@@ -913,7 +913,7 @@ PL/Python function "nnint_test"
 CREATE DOMAIN ordered_named_pair AS named_pair_2 CHECK((VALUE).i <= (VALUE).j);
 CREATE FUNCTION read_ordered_named_pair(p ordered_named_pair) RETURNS integer AS $$
 return p['i'] + p['j']
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT read_ordered_named_pair(row(1, 2));
  read_ordered_named_pair 
 -------------------------
@@ -924,7 +924,7 @@ SELECT read_ordered_named_pair(row(2, 1));  -- fail
 ERROR:  value for domain ordered_named_pair violates check constraint \
"ordered_named_pair_check"  CREATE FUNCTION build_ordered_named_pair(i int, j int) \
RETURNS ordered_named_pair AS $$  return {'i': i, 'j': j}
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT build_ordered_named_pair(1,2);
  build_ordered_named_pair 
 --------------------------
@@ -937,7 +937,7 @@ CONTEXT:  while creating return value
 PL/Python function "build_ordered_named_pair"
 CREATE FUNCTION build_ordered_named_pairs(i int, j int) RETURNS ordered_named_pair[] \
AS $$  return [{'i': i, 'j': j}, {'i': i, 'j': j+1}]
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT build_ordered_named_pairs(1,2);
  build_ordered_named_pairs 
 ---------------------------
@@ -952,7 +952,7 @@ PL/Python function "build_ordered_named_pairs"
 -- Prepared statements
 --
 CREATE OR REPLACE FUNCTION test_prep_bool_input() RETURNS int
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 AS $$
 plan = plpy.prepare("SELECT CASE WHEN $1 THEN 1 ELSE 0 END AS val", ['boolean'])
 rv = plpy.execute(plan, ['fa'], 5) # 'fa' is true in Python
@@ -965,7 +965,7 @@ SELECT test_prep_bool_input(); -- 1
 (1 row)
 
 CREATE OR REPLACE FUNCTION test_prep_bool_output() RETURNS bool
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 AS $$
 plan = plpy.prepare("SELECT $1 = 1 AS val", ['int'])
 rv = plpy.execute(plan, [0], 5)
@@ -980,7 +980,7 @@ INFO:  {'val': False}
 (1 row)
 
 CREATE OR REPLACE FUNCTION test_prep_bytea_input(bb bytea) RETURNS int
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 AS $$
 plan = plpy.prepare("SELECT octet_length($1) AS val", ['bytea'])
 rv = plpy.execute(plan, [bb], 5)
@@ -993,7 +993,7 @@ SELECT test_prep_bytea_input(E'a\\000b'); -- 3 (embedded null \
formerly truncated  (1 row)
 
 CREATE OR REPLACE FUNCTION test_prep_bytea_output() RETURNS bytea
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 AS $$
 plan = plpy.prepare("SELECT decode('aa00bb', 'hex') AS val")
 rv = plpy.execute(plan, [], 5)
@@ -1001,7 +1001,7 @@ plpy.info(rv[0])
 return rv[0]['val']
 $$;
 SELECT test_prep_bytea_output();
-INFO:  {'val': '\xaa\x00\xbb'}
+INFO:  {'val': b'\xaa\x00\xbb'}
  test_prep_bytea_output 
 ------------------------
  \xaa00bb
diff --git a/src/pl/plpython/expected/plpython_types_3.out \
b/src/pl/plpython/expected/plpython_types_3.out deleted file mode 100644
index a6ec10d5e18..00000000000
--- a/src/pl/plpython/expected/plpython_types_3.out
+++ /dev/null
@@ -1,1009 +0,0 @@
---
--- Test data type behavior
---
---
--- Base/common types
---
-CREATE FUNCTION test_type_conversion_bool(x bool) RETURNS bool AS $$
-plpy.info(x, type(x))
-return x
-$$ LANGUAGE plpython3u;
-SELECT * FROM test_type_conversion_bool(true);
-INFO:  (True, <class 'bool'>)
- test_type_conversion_bool 
----------------------------
- t
-(1 row)
-
-SELECT * FROM test_type_conversion_bool(false);
-INFO:  (False, <class 'bool'>)
- test_type_conversion_bool 
----------------------------
- f
-(1 row)
-
-SELECT * FROM test_type_conversion_bool(null);
-INFO:  (None, <class 'NoneType'>)
- test_type_conversion_bool 
----------------------------
- 
-(1 row)
-
--- test various other ways to express Booleans in Python
-CREATE FUNCTION test_type_conversion_bool_other(n int) RETURNS bool AS $$
-# numbers
-if n == 0:
-   ret = 0
-elif n == 1:
-   ret = 5
-# strings
-elif n == 2:
-   ret = ''
-elif n == 3:
-   ret = 'fa' # true in Python, false in PostgreSQL
-# containers
-elif n == 4:
-   ret = []
-elif n == 5:
-   ret = [0]
-plpy.info(ret, not not ret)
-return ret
-$$ LANGUAGE plpython3u;
-SELECT * FROM test_type_conversion_bool_other(0);
-INFO:  (0, False)
- test_type_conversion_bool_other 
----------------------------------
- f
-(1 row)
-
-SELECT * FROM test_type_conversion_bool_other(1);
-INFO:  (5, True)
- test_type_conversion_bool_other 
----------------------------------
- t
-(1 row)
-
-SELECT * FROM test_type_conversion_bool_other(2);
-INFO:  ('', False)
- test_type_conversion_bool_other 
----------------------------------
- f
-(1 row)
-
-SELECT * FROM test_type_conversion_bool_other(3);
-INFO:  ('fa', True)
- test_type_conversion_bool_other 
----------------------------------
- t
-(1 row)
-
-SELECT * FROM test_type_conversion_bool_other(4);
-INFO:  ([], False)
- test_type_conversion_bool_other 
----------------------------------
- f
-(1 row)
-
-SELECT * FROM test_type_conversion_bool_other(5);
-INFO:  ([0], True)
- test_type_conversion_bool_other 
----------------------------------
- t
-(1 row)
-
-CREATE FUNCTION test_type_conversion_char(x char) RETURNS char AS $$
-plpy.info(x, type(x))
-return x
-$$ LANGUAGE plpython3u;
-SELECT * FROM test_type_conversion_char('a');
-INFO:  ('a', <class 'str'>)
- test_type_conversion_char 
----------------------------
- a
-(1 row)
-
-SELECT * FROM test_type_conversion_char(null);
-INFO:  (None, <class 'NoneType'>)
- test_type_conversion_char 
----------------------------
- 
-(1 row)
-
-CREATE FUNCTION test_type_conversion_int2(x int2) RETURNS int2 AS $$
-plpy.info(x, type(x))
-return x
-$$ LANGUAGE plpython3u;
-SELECT * FROM test_type_conversion_int2(100::int2);
-INFO:  (100, <class 'int'>)
- test_type_conversion_int2 
----------------------------
-                       100
-(1 row)
-
-SELECT * FROM test_type_conversion_int2(-100::int2);
-INFO:  (-100, <class 'int'>)
- test_type_conversion_int2 
----------------------------
-                      -100
-(1 row)
-
-SELECT * FROM test_type_conversion_int2(null);
-INFO:  (None, <class 'NoneType'>)
- test_type_conversion_int2 
----------------------------
-                          
-(1 row)
-
-CREATE FUNCTION test_type_conversion_int4(x int4) RETURNS int4 AS $$
-plpy.info(x, type(x))
-return x
-$$ LANGUAGE plpython3u;
-SELECT * FROM test_type_conversion_int4(100);
-INFO:  (100, <class 'int'>)
- test_type_conversion_int4 
----------------------------
-                       100
-(1 row)
-
-SELECT * FROM test_type_conversion_int4(-100);
-INFO:  (-100, <class 'int'>)
- test_type_conversion_int4 
----------------------------
-                      -100
-(1 row)
-
-SELECT * FROM test_type_conversion_int4(null);
-INFO:  (None, <class 'NoneType'>)
- test_type_conversion_int4 
----------------------------
-                          
-(1 row)
-
-CREATE FUNCTION test_type_conversion_int8(x int8) RETURNS int8 AS $$
-plpy.info(x, type(x))
-return x
-$$ LANGUAGE plpython3u;
-SELECT * FROM test_type_conversion_int8(100);
-INFO:  (100, <class 'int'>)
- test_type_conversion_int8 
----------------------------
-                       100
-(1 row)
-
-SELECT * FROM test_type_conversion_int8(-100);
-INFO:  (-100, <class 'int'>)
- test_type_conversion_int8 
----------------------------
-                      -100
-(1 row)
-
-SELECT * FROM test_type_conversion_int8(5000000000);
-INFO:  (5000000000, <class 'int'>)
- test_type_conversion_int8 
----------------------------
-                5000000000
-(1 row)
-
-SELECT * FROM test_type_conversion_int8(null);
-INFO:  (None, <class 'NoneType'>)
- test_type_conversion_int8 
----------------------------
-                          
-(1 row)
-
-CREATE FUNCTION test_type_conversion_numeric(x numeric) RETURNS numeric AS $$
-# print just the class name, not the type, to avoid differences
-# between decimal and cdecimal
-plpy.info(str(x), x.__class__.__name__)
-return x
-$$ LANGUAGE plpython3u;
-SELECT * FROM test_type_conversion_numeric(100);
-INFO:  ('100', 'Decimal')
- test_type_conversion_numeric 
-------------------------------
-                          100
-(1 row)
-
-SELECT * FROM test_type_conversion_numeric(-100);
-INFO:  ('-100', 'Decimal')
- test_type_conversion_numeric 
-------------------------------
-                         -100
-(1 row)
-
-SELECT * FROM test_type_conversion_numeric(100.0);
-INFO:  ('100.0', 'Decimal')
- test_type_conversion_numeric 
-------------------------------
-                        100.0
-(1 row)
-
-SELECT * FROM test_type_conversion_numeric(100.00);
-INFO:  ('100.00', 'Decimal')
- test_type_conversion_numeric 
-------------------------------
-                       100.00
-(1 row)
-
-SELECT * FROM test_type_conversion_numeric(5000000000.5);
-INFO:  ('5000000000.5', 'Decimal')
- test_type_conversion_numeric 
-------------------------------
-                 5000000000.5
-(1 row)
-
-SELECT * FROM test_type_conversion_numeric(1234567890.0987654321);
-INFO:  ('1234567890.0987654321', 'Decimal')
- test_type_conversion_numeric 
-------------------------------
-        1234567890.0987654321
-(1 row)
-
-SELECT * FROM test_type_conversion_numeric(-1234567890.0987654321);
-INFO:  ('-1234567890.0987654321', 'Decimal')
- test_type_conversion_numeric 
-------------------------------
-       -1234567890.0987654321
-(1 row)
-
-SELECT * FROM test_type_conversion_numeric(null);
-INFO:  ('None', 'NoneType')
- test_type_conversion_numeric 
-------------------------------
-                             
-(1 row)
-
-CREATE FUNCTION test_type_conversion_float4(x float4) RETURNS float4 AS $$
-plpy.info(x, type(x))
-return x
-$$ LANGUAGE plpython3u;
-SELECT * FROM test_type_conversion_float4(100);
-INFO:  (100.0, <class 'float'>)
- test_type_conversion_float4 
------------------------------
-                         100
-(1 row)
-
-SELECT * FROM test_type_conversion_float4(-100);
-INFO:  (-100.0, <class 'float'>)
- test_type_conversion_float4 
------------------------------
-                        -100
-(1 row)
-
-SELECT * FROM test_type_conversion_float4(5000.5);
-INFO:  (5000.5, <class 'float'>)
- test_type_conversion_float4 
------------------------------
-                      5000.5
-(1 row)
-
-SELECT * FROM test_type_conversion_float4(null);
-INFO:  (None, <class 'NoneType'>)
- test_type_conversion_float4 
------------------------------
-                            
-(1 row)
-
-CREATE FUNCTION test_type_conversion_float8(x float8) RETURNS float8 AS $$
-plpy.info(x, type(x))
-return x
-$$ LANGUAGE plpython3u;
-SELECT * FROM test_type_conversion_float8(100);
-INFO:  (100.0, <class 'float'>)
- test_type_conversion_float8 
------------------------------
-                         100
-(1 row)
-
-SELECT * FROM test_type_conversion_float8(-100);
-INFO:  (-100.0, <class 'float'>)
- test_type_conversion_float8 
------------------------------
-                        -100
-(1 row)
-
-SELECT * FROM test_type_conversion_float8(5000000000.5);
-INFO:  (5000000000.5, <class 'float'>)
- test_type_conversion_float8 
------------------------------
-                5000000000.5
-(1 row)
-
-SELECT * FROM test_type_conversion_float8(null);
-INFO:  (None, <class 'NoneType'>)
- test_type_conversion_float8 
------------------------------
-                            
-(1 row)
-
-SELECT * FROM test_type_conversion_float8(100100100.654321);
-INFO:  (100100100.654321, <class 'float'>)
- test_type_conversion_float8 
------------------------------
-            100100100.654321
-(1 row)
-
-CREATE FUNCTION test_type_conversion_oid(x oid) RETURNS oid AS $$
-plpy.info(x, type(x))
-return x
-$$ LANGUAGE plpython3u;
-SELECT * FROM test_type_conversion_oid(100);
-INFO:  (100, <class 'int'>)
- test_type_conversion_oid 
---------------------------
-                      100
-(1 row)
-
-SELECT * FROM test_type_conversion_oid(2147483649);
-INFO:  (2147483649, <class 'int'>)
- test_type_conversion_oid 
---------------------------
-               2147483649
-(1 row)
-
-SELECT * FROM test_type_conversion_oid(null);
-INFO:  (None, <class 'NoneType'>)
- test_type_conversion_oid 
---------------------------
-                         
-(1 row)
-
-CREATE FUNCTION test_type_conversion_text(x text) RETURNS text AS $$
-plpy.info(x, type(x))
-return x
-$$ LANGUAGE plpython3u;
-SELECT * FROM test_type_conversion_text('hello world');
-INFO:  ('hello world', <class 'str'>)
- test_type_conversion_text 
----------------------------
- hello world
-(1 row)
-
-SELECT * FROM test_type_conversion_text(null);
-INFO:  (None, <class 'NoneType'>)
- test_type_conversion_text 
----------------------------
- 
-(1 row)
-
-CREATE FUNCTION test_type_conversion_bytea(x bytea) RETURNS bytea AS $$
-plpy.info(x, type(x))
-return x
-$$ LANGUAGE plpython3u;
-SELECT * FROM test_type_conversion_bytea('hello world');
-INFO:  (b'hello world', <class 'bytes'>)
- test_type_conversion_bytea 
-----------------------------
- \x68656c6c6f20776f726c64
-(1 row)
-
-SELECT * FROM test_type_conversion_bytea(E'null\\000byte');
-INFO:  (b'null\x00byte', <class 'bytes'>)
- test_type_conversion_bytea 
-----------------------------
- \x6e756c6c0062797465
-(1 row)
-
-SELECT * FROM test_type_conversion_bytea(null);
-INFO:  (None, <class 'NoneType'>)
- test_type_conversion_bytea 
-----------------------------
- 
-(1 row)
-
-CREATE FUNCTION test_type_marshal() RETURNS bytea AS $$
-import marshal
-return marshal.dumps('hello world')
-$$ LANGUAGE plpython3u;
-CREATE FUNCTION test_type_unmarshal(x bytea) RETURNS text AS $$
-import marshal
-try:
-    return marshal.loads(x)
-except ValueError as e:
-    return 'FAILED: ' + str(e)
-$$ LANGUAGE plpython3u;
-SELECT test_type_unmarshal(x) FROM test_type_marshal() x;
- test_type_unmarshal 
----------------------
- hello world
-(1 row)
-
---
--- Domains
---
-CREATE DOMAIN booltrue AS bool CHECK (VALUE IS TRUE OR VALUE IS NULL);
-CREATE FUNCTION test_type_conversion_booltrue(x booltrue, y bool) RETURNS booltrue \
                AS $$
-return y
-$$ LANGUAGE plpython3u;
-SELECT * FROM test_type_conversion_booltrue(true, true);
- test_type_conversion_booltrue 
--------------------------------
- t
-(1 row)
-
-SELECT * FROM test_type_conversion_booltrue(false, true);
-ERROR:  value for domain booltrue violates check constraint "booltrue_check"
-SELECT * FROM test_type_conversion_booltrue(true, false);
-ERROR:  value for domain booltrue violates check constraint "booltrue_check"
-CONTEXT:  while creating return value
-PL/Python function "test_type_conversion_booltrue"
-CREATE DOMAIN uint2 AS int2 CHECK (VALUE >= 0);
-CREATE FUNCTION test_type_conversion_uint2(x uint2, y int) RETURNS uint2 AS $$
-plpy.info(x, type(x))
-return y
-$$ LANGUAGE plpython3u;
-SELECT * FROM test_type_conversion_uint2(100::uint2, 50);
-INFO:  (100, <class 'int'>)
- test_type_conversion_uint2 
-----------------------------
-                         50
-(1 row)
-
-SELECT * FROM test_type_conversion_uint2(100::uint2, -50);
-INFO:  (100, <class 'int'>)
-ERROR:  value for domain uint2 violates check constraint "uint2_check"
-CONTEXT:  while creating return value
-PL/Python function "test_type_conversion_uint2"
-SELECT * FROM test_type_conversion_uint2(null, 1);
-INFO:  (None, <class 'NoneType'>)
- test_type_conversion_uint2 
-----------------------------
-                          1
-(1 row)
-
-CREATE DOMAIN nnint AS int CHECK (VALUE IS NOT NULL);
-CREATE FUNCTION test_type_conversion_nnint(x nnint, y int) RETURNS nnint AS $$
-return y
-$$ LANGUAGE plpython3u;
-SELECT * FROM test_type_conversion_nnint(10, 20);
- test_type_conversion_nnint 
-----------------------------
-                         20
-(1 row)
-
-SELECT * FROM test_type_conversion_nnint(null, 20);
-ERROR:  value for domain nnint violates check constraint "nnint_check"
-SELECT * FROM test_type_conversion_nnint(10, null);
-ERROR:  value for domain nnint violates check constraint "nnint_check"
-CONTEXT:  while creating return value
-PL/Python function "test_type_conversion_nnint"
-CREATE DOMAIN bytea10 AS bytea CHECK (octet_length(VALUE) = 10 AND VALUE IS NOT \
                NULL);
-CREATE FUNCTION test_type_conversion_bytea10(x bytea10, y bytea) RETURNS bytea10 AS \
                $$
-plpy.info(x, type(x))
-return y
-$$ LANGUAGE plpython3u;
-SELECT * FROM test_type_conversion_bytea10('hello wold', 'hello wold');
-INFO:  (b'hello wold', <class 'bytes'>)
- test_type_conversion_bytea10 
-------------------------------
- \x68656c6c6f20776f6c64
-(1 row)
-
-SELECT * FROM test_type_conversion_bytea10('hello world', 'hello wold');
-ERROR:  value for domain bytea10 violates check constraint "bytea10_check"
-SELECT * FROM test_type_conversion_bytea10('hello word', 'hello world');
-INFO:  (b'hello word', <class 'bytes'>)
-ERROR:  value for domain bytea10 violates check constraint "bytea10_check"
-CONTEXT:  while creating return value
-PL/Python function "test_type_conversion_bytea10"
-SELECT * FROM test_type_conversion_bytea10(null, 'hello word');
-ERROR:  value for domain bytea10 violates check constraint "bytea10_check"
-SELECT * FROM test_type_conversion_bytea10('hello word', null);
-INFO:  (b'hello word', <class 'bytes'>)
-ERROR:  value for domain bytea10 violates check constraint "bytea10_check"
-CONTEXT:  while creating return value
-PL/Python function "test_type_conversion_bytea10"
---
--- Arrays
---
-CREATE FUNCTION test_type_conversion_array_int4(x int4[]) RETURNS int4[] AS $$
-plpy.info(x, type(x))
-return x
-$$ LANGUAGE plpython3u;
-SELECT * FROM test_type_conversion_array_int4(ARRAY[0, 100]);
-INFO:  ([0, 100], <class 'list'>)
- test_type_conversion_array_int4 
----------------------------------
- {0,100}
-(1 row)
-
-SELECT * FROM test_type_conversion_array_int4(ARRAY[0,-100,55]);
-INFO:  ([0, -100, 55], <class 'list'>)
- test_type_conversion_array_int4 
----------------------------------
- {0,-100,55}
-(1 row)
-
-SELECT * FROM test_type_conversion_array_int4(ARRAY[NULL,1]);
-INFO:  ([None, 1], <class 'list'>)
- test_type_conversion_array_int4 
----------------------------------
- {NULL,1}
-(1 row)
-
-SELECT * FROM test_type_conversion_array_int4(ARRAY[]::integer[]);
-INFO:  ([], <class 'list'>)
- test_type_conversion_array_int4 
----------------------------------
- {}
-(1 row)
-
-SELECT * FROM test_type_conversion_array_int4(NULL);
-INFO:  (None, <class 'NoneType'>)
- test_type_conversion_array_int4 
----------------------------------
- 
-(1 row)
-
-SELECT * FROM test_type_conversion_array_int4(ARRAY[[1,2,3],[4,5,6]]);
-INFO:  ([[1, 2, 3], [4, 5, 6]], <class 'list'>)
- test_type_conversion_array_int4 
----------------------------------
- {{1,2,3},{4,5,6}}
-(1 row)
-
-SELECT * FROM test_type_conversion_array_int4(ARRAY[[[1,2,NULL],[NULL,5,6]],[[NULL,8,9],[10,11,12]]]);
                
-INFO:  ([[[1, 2, None], [None, 5, 6]], [[None, 8, 9], [10, 11, 12]]], <class \
                'list'>)
-          test_type_conversion_array_int4          
----------------------------------------------------
- {{{1,2,NULL},{NULL,5,6}},{{NULL,8,9},{10,11,12}}}
-(1 row)
-
-SELECT * FROM test_type_conversion_array_int4('[2:4]={1,2,3}');
-INFO:  ([1, 2, 3], <class 'list'>)
- test_type_conversion_array_int4 
----------------------------------
- {1,2,3}
-(1 row)
-
-CREATE FUNCTION test_type_conversion_array_int8(x int8[]) RETURNS int8[] AS $$
-plpy.info(x, type(x))
-return x
-$$ LANGUAGE plpython3u;
-SELECT * FROM test_type_conversion_array_int8(ARRAY[[[1,2,NULL],[NULL,5,6]],[[NULL,8,9],[10,11,12]]]::int8[]);
                
-INFO:  ([[[1, 2, None], [None, 5, 6]], [[None, 8, 9], [10, 11, 12]]], <class \
                'list'>)
-          test_type_conversion_array_int8          
----------------------------------------------------
- {{{1,2,NULL},{NULL,5,6}},{{NULL,8,9},{10,11,12}}}
-(1 row)
-
-CREATE FUNCTION test_type_conversion_array_date(x date[]) RETURNS date[] AS $$
-plpy.info(x, type(x))
-return x
-$$ LANGUAGE plpython3u;
-SELECT * FROM test_type_conversion_array_date(ARRAY[[['2016-09-21','2016-09-22',NULL],[NULL,'2016-10-21','2016-10-22']],
                
-            [[NULL,'2016-11-21','2016-10-21'],['2015-09-21','2015-09-22','2014-09-21']]]::date[]);
                
-INFO:  ([[['09-21-2016', '09-22-2016', None], [None, '10-21-2016', '10-22-2016']], \
[[None, '11-21-2016', '10-21-2016'], ['09-21-2015', '09-22-2015', '09-21-2014']]], \
                <class 'list'>)
-                                                 test_type_conversion_array_date     \
                
----------------------------------------------------------------------------------------------------------------------------------
                
- {{{09-21-2016,09-22-2016,NULL},{NULL,10-21-2016,10-22-2016}},{{NULL,11-21-2016,10-21-2016},{09-21-2015,09-22-2015,09-21-2014}}}
                
-(1 row)
-
-CREATE FUNCTION test_type_conversion_array_timestamp(x timestamp[]) RETURNS \
                timestamp[] AS $$
-plpy.info(x, type(x))
-return x
-$$ LANGUAGE plpython3u;
-SELECT * FROM test_type_conversion_array_timestamp(ARRAY[[['2016-09-21 \
                15:34:24.078792-04','2016-10-22 11:34:24.078795-04',NULL],
-            [NULL,'2016-10-21 11:34:25.078792-04','2016-10-21 11:34:24.098792-04']],
-            [[NULL,'2016-01-21 11:34:24.078792-04','2016-11-21 11:34:24.108792-04'],
-            ['2015-09-21 11:34:24.079792-04','2014-09-21 \
                11:34:24.078792-04','2013-09-21 11:34:24.078792-04']]]::timestamp[]);
-INFO:  ([[['Wed Sep 21 15:34:24.078792 2016', 'Sat Oct 22 11:34:24.078795 2016', \
None], [None, 'Fri Oct 21 11:34:25.078792 2016', 'Fri Oct 21 11:34:24.098792 2016']], \
[[None, 'Thu Jan 21 11:34:24.078792 2016', 'Mon Nov 21 11:34:24.108792 2016'], ['Mon \
Sep 21 11:34:24.079792 2015', 'Sun Sep 21 11:34:24.078792 2014', 'Sat Sep 21 \
                11:34:24.078792 2013']]], <class 'list'>)
-                                                                                     \
test_type_conversion_array_timestamp                                                  \
                
-------------------------------------------------------------------------------------- \
-------------------------------------------------------------------------------------- \
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
                
- {{{"Wed Sep 21 15:34:24.078792 2016","Sat Oct 22 11:34:24.078795 \
2016",NULL},{NULL,"Fri Oct 21 11:34:25.078792 2016","Fri Oct 21 11:34:24.098792 \
2016"}},{{NULL,"Thu Jan 21 11:34:24.078792 2016","Mon Nov 21 11:34:24.108792 \
2016"},{"Mon Sep 21 11:34:24.079792 2015","Sun Sep 21 11:34:24.078792 2014","Sat Sep \
                21 11:34:24.078792 2013"}}}
-(1 row)
-
-CREATE OR REPLACE FUNCTION pyreturnmultidemint4(h int4, i int4, j int4, k int4 ) \
                RETURNS int4[] AS $BODY$
-m = [[[[x for x in range(h)] for y in range(i)] for z in range(j)] for w in \
                range(k)]
-plpy.info(m, type(m))
-return m
-$BODY$ LANGUAGE plpython3u;
-select pyreturnmultidemint4(8,5,3,2);
-INFO:  ([[[[0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, \
7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7]], [[0, 1, 2, 3, 4, 5, 6, 7], \
[0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, \
2, 3, 4, 5, 6, 7]], [[0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, \
4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7]]], [[[0, 1, 2, 3, 4, \
5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, \
7], [0, 1, 2, 3, 4, 5, 6, 7]], [[0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], \
[0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7]], [[0, \
1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, \
                3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7]]]], <class 'list'>)
-                                                                                     \
pyreturnmultidemint4                                                                  \
                
-------------------------------------------------------------------------------------- \
-------------------------------------------------------------------------------------- \
-------------------------------------------------------------------------------------- \
-------------------------------------------------------------------------------------- \
-------------------------------------------------------------------------------------- \
----------------------------------------------------------------------------------------------------------------------------------
                
- {{{{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3, \
4,5,6,7}},{{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0, \
1,2,3,4,5,6,7}},{{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6, \
7},{0,1,2,3,4,5,6,7}}},{{{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2, \
3,4,5,6,7},{0,1,2,3,4,5,6,7}},{{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{ \
0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7}},{{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7},{0,1,2,3,4,5,6,7}}}}
                
-(1 row)
-
-CREATE OR REPLACE FUNCTION pyreturnmultidemint8(h int4, i int4, j int4, k int4 ) \
                RETURNS int8[] AS $BODY$
-m = [[[[x for x in range(h)] for y in range(i)] for z in range(j)] for w in \
                range(k)]
-plpy.info(m, type(m))
-return m
-$BODY$ LANGUAGE plpython3u;
-select pyreturnmultidemint8(5,5,3,2);
-INFO:  ([[[[0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, \
1, 2, 3, 4]], [[0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], \
[0, 1, 2, 3, 4]], [[0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, \
4], [0, 1, 2, 3, 4]]], [[[0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, \
3, 4], [0, 1, 2, 3, 4]], [[0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, \
2, 3, 4], [0, 1, 2, 3, 4]], [[0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, \
                1, 2, 3, 4], [0, 1, 2, 3, 4]]]], <class 'list'>)
-                                                                                     \
pyreturnmultidemint8                                                                  \
                
-------------------------------------------------------------------------------------- \
-------------------------------------------------------------------------------------- \
-------------------------------------------------------------------------------------- \
--------------------------------------------------------------------------------------------------------------------------
                
- {{{{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4}},{{0,1,2,3,4},{0,1,2, \
3,4},{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4}},{{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4},{0,1,2, \
3,4},{0,1,2,3,4}}},{{{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4}},{{0, \
1,2,3,4},{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4}},{{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4},{0,1,2,3,4}}}}
                
-(1 row)
-
-CREATE OR REPLACE FUNCTION pyreturnmultidemfloat4(h int4, i int4, j int4, k int4 ) \
                RETURNS float4[] AS $BODY$
-m = [[[[x for x in range(h)] for y in range(i)] for z in range(j)] for w in \
                range(k)]
-plpy.info(m, type(m))
-return m
-$BODY$ LANGUAGE plpython3u;
-select pyreturnmultidemfloat4(6,5,3,2);
-INFO:  ([[[[0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, \
4, 5], [0, 1, 2, 3, 4, 5]], [[0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, \
5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5]], [[0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], \
[0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5]]], [[[0, 1, 2, 3, 4, 5], \
[0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5]], [[0, \
1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, \
3, 4, 5]], [[0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, \
                4, 5], [0, 1, 2, 3, 4, 5]]]], <class 'list'>)
-                                                                                     \
pyreturnmultidemfloat4                                                                \
                
-------------------------------------------------------------------------------------- \
-------------------------------------------------------------------------------------- \
-------------------------------------------------------------------------------------- \
-------------------------------------------------------------------------------------- \
------------------------------------------------------------------------------------------------
                
- {{{{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5}},{{0,1,2,3, \
4,5},{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5}},{{0,1,2,3,4,5},{0,1,2,3, \
4,5},{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5}}},{{{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2, \
3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5}},{{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2, \
3,4,5},{0,1,2,3,4,5}},{{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5},{0,1,2,3,4,5}}}}
                
-(1 row)
-
-CREATE OR REPLACE FUNCTION pyreturnmultidemfloat8(h int4, i int4, j int4, k int4 ) \
                RETURNS float8[] AS $BODY$
-m = [[[[x for x in range(h)] for y in range(i)] for z in range(j)] for w in \
                range(k)]
-plpy.info(m, type(m))
-return m
-$BODY$ LANGUAGE plpython3u;
-select pyreturnmultidemfloat8(7,5,3,2);
-INFO:  ([[[[0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, \
1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6]], [[0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, \
6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6]], [[0, 1, 2, \
3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, \
1, 2, 3, 4, 5, 6]]], [[[0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, \
5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6]], [[0, 1, 2, 3, 4, 5, 6], [0, 1, \
2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6]], \
[[0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, \
                5, 6], [0, 1, 2, 3, 4, 5, 6]]]], <class 'list'>)
-                                                                                     \
pyreturnmultidemfloat8                                                                \
                
-------------------------------------------------------------------------------------- \
-------------------------------------------------------------------------------------- \
-------------------------------------------------------------------------------------- \
-------------------------------------------------------------------------------------- \
------------------------------------------------------------------------------------------------------------------------------------------------------------
                
- {{{{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6}}, \
{{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6}},{{0, \
1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6}}},{{{0,1, \
2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6}},{{0,1,2,3, \
4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6}},{{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6},{0,1,2,3,4,5,6}}}}
                
-(1 row)
-
-CREATE FUNCTION test_type_conversion_array_text(x text[]) RETURNS text[] AS $$
-plpy.info(x, type(x))
-return x
-$$ LANGUAGE plpython3u;
-SELECT * FROM test_type_conversion_array_text(ARRAY['foo', 'bar']);
-INFO:  (['foo', 'bar'], <class 'list'>)
- test_type_conversion_array_text 
----------------------------------
- {foo,bar}
-(1 row)
-
-SELECT * FROM test_type_conversion_array_text(ARRAY[['foo', 'bar'],['foo2', \
                'bar2']]);
-INFO:  ([['foo', 'bar'], ['foo2', 'bar2']], <class 'list'>)
- test_type_conversion_array_text 
----------------------------------
- {{foo,bar},{foo2,bar2}}
-(1 row)
-
-CREATE FUNCTION test_type_conversion_array_bytea(x bytea[]) RETURNS bytea[] AS $$
-plpy.info(x, type(x))
-return x
-$$ LANGUAGE plpython3u;
-SELECT * FROM test_type_conversion_array_bytea(ARRAY[E'\\xdeadbeef'::bytea, NULL]);
-INFO:  ([b'\xde\xad\xbe\xef', None], <class 'list'>)
- test_type_conversion_array_bytea 
-----------------------------------
- {"\\xdeadbeef",NULL}
-(1 row)
-
-CREATE FUNCTION test_type_conversion_array_mixed1() RETURNS text[] AS $$
-return [123, 'abc']
-$$ LANGUAGE plpython3u;
-SELECT * FROM test_type_conversion_array_mixed1();
- test_type_conversion_array_mixed1 
------------------------------------
- {123,abc}
-(1 row)
-
-CREATE FUNCTION test_type_conversion_array_mixed2() RETURNS int[] AS $$
-return [123, 'abc']
-$$ LANGUAGE plpython3u;
-SELECT * FROM test_type_conversion_array_mixed2();
-ERROR:  invalid input syntax for type integer: "abc"
-CONTEXT:  while creating return value
-PL/Python function "test_type_conversion_array_mixed2"
-CREATE FUNCTION test_type_conversion_mdarray_malformed() RETURNS int[] AS $$
-return [[1,2,3],[4,5]]
-$$ LANGUAGE plpython3u;
-SELECT * FROM test_type_conversion_mdarray_malformed();
-ERROR:  wrong length of inner sequence: has length 2, but 3 was expected
-DETAIL:  To construct a multidimensional array, the inner sequences must all have \
                the same length.
-CONTEXT:  while creating return value
-PL/Python function "test_type_conversion_mdarray_malformed"
-CREATE FUNCTION test_type_conversion_mdarray_toodeep() RETURNS int[] AS $$
-return [[[[[[[1]]]]]]]
-$$ LANGUAGE plpython3u;
-SELECT * FROM test_type_conversion_mdarray_toodeep();
-ERROR:  number of array dimensions exceeds the maximum allowed (6)
-CONTEXT:  while creating return value
-PL/Python function "test_type_conversion_mdarray_toodeep"
-CREATE FUNCTION test_type_conversion_array_record() RETURNS type_record[] AS $$
-return [{'first': 'one', 'second': 42}, {'first': 'two', 'second': 11}]
-$$ LANGUAGE plpython3u;
-SELECT * FROM test_type_conversion_array_record();
- test_type_conversion_array_record 
------------------------------------
- {"(one,42)","(two,11)"}
-(1 row)
-
-CREATE FUNCTION test_type_conversion_array_string() RETURNS text[] AS $$
-return 'abc'
-$$ LANGUAGE plpython3u;
-SELECT * FROM test_type_conversion_array_string();
- test_type_conversion_array_string 
------------------------------------
- {a,b,c}
-(1 row)
-
-CREATE FUNCTION test_type_conversion_array_tuple() RETURNS text[] AS $$
-return ('abc', 'def')
-$$ LANGUAGE plpython3u;
-SELECT * FROM test_type_conversion_array_tuple();
- test_type_conversion_array_tuple 
-----------------------------------
- {abc,def}
-(1 row)
-
-CREATE FUNCTION test_type_conversion_array_error() RETURNS int[] AS $$
-return 5
-$$ LANGUAGE plpython3u;
-SELECT * FROM test_type_conversion_array_error();
-ERROR:  return value of function with array return type is not a Python sequence
-CONTEXT:  while creating return value
-PL/Python function "test_type_conversion_array_error"
---
--- Domains over arrays
---
-CREATE DOMAIN ordered_pair_domain AS integer[] CHECK (array_length(VALUE,1)=2 AND \
                VALUE[1] < VALUE[2]);
-CREATE FUNCTION test_type_conversion_array_domain(x ordered_pair_domain) RETURNS \
                ordered_pair_domain AS $$
-plpy.info(x, type(x))
-return x
-$$ LANGUAGE plpython3u;
-SELECT * FROM test_type_conversion_array_domain(ARRAY[0, 100]::ordered_pair_domain);
-INFO:  ([0, 100], <class 'list'>)
- test_type_conversion_array_domain 
------------------------------------
- {0,100}
-(1 row)
-
-SELECT * FROM test_type_conversion_array_domain(NULL::ordered_pair_domain);
-INFO:  (None, <class 'NoneType'>)
- test_type_conversion_array_domain 
------------------------------------
- 
-(1 row)
-
-CREATE FUNCTION test_type_conversion_array_domain_check_violation() RETURNS \
                ordered_pair_domain AS $$
-return [2,1]
-$$ LANGUAGE plpython3u;
-SELECT * FROM test_type_conversion_array_domain_check_violation();
-ERROR:  value for domain ordered_pair_domain violates check constraint \
                "ordered_pair_domain_check"
-CONTEXT:  while creating return value
-PL/Python function "test_type_conversion_array_domain_check_violation"
---
--- Arrays of domains
---
-CREATE FUNCTION test_read_uint2_array(x uint2[]) RETURNS uint2 AS $$
-plpy.info(x, type(x))
-return x[0]
-$$ LANGUAGE plpythonu;
-select test_read_uint2_array(array[1::uint2]);
-INFO:  ([1], <class 'list'>)
- test_read_uint2_array 
------------------------
-                     1
-(1 row)
-
-CREATE FUNCTION test_build_uint2_array(x int2) RETURNS uint2[] AS $$
-return [x, x]
-$$ LANGUAGE plpythonu;
-select test_build_uint2_array(1::int2);
- test_build_uint2_array 
-------------------------
- {1,1}
-(1 row)
-
-select test_build_uint2_array(-1::int2);  -- fail
-ERROR:  value for domain uint2 violates check constraint "uint2_check"
-CONTEXT:  while creating return value
-PL/Python function "test_build_uint2_array"
---
--- ideally this would work, but for now it doesn't, because the return value
--- is [[2,4], [2,4]] which our conversion code thinks should become a 2-D
--- integer array, not an array of arrays.
---
-CREATE FUNCTION test_type_conversion_domain_array(x integer[])
-  RETURNS ordered_pair_domain[] AS $$
-return [x, x]
-$$ LANGUAGE plpythonu;
-select test_type_conversion_domain_array(array[2,4]);
-ERROR:  return value of function with array return type is not a Python sequence
-CONTEXT:  while creating return value
-PL/Python function "test_type_conversion_domain_array"
-select test_type_conversion_domain_array(array[4,2]);  -- fail
-ERROR:  return value of function with array return type is not a Python sequence
-CONTEXT:  while creating return value
-PL/Python function "test_type_conversion_domain_array"
-CREATE FUNCTION test_type_conversion_domain_array2(x ordered_pair_domain)
-  RETURNS integer AS $$
-plpy.info(x, type(x))
-return x[1]
-$$ LANGUAGE plpythonu;
-select test_type_conversion_domain_array2(array[2,4]);
-INFO:  ([2, 4], <class 'list'>)
- test_type_conversion_domain_array2 
-------------------------------------
-                                  4
-(1 row)
-
-select test_type_conversion_domain_array2(array[4,2]);  -- fail
-ERROR:  value for domain ordered_pair_domain violates check constraint \
                "ordered_pair_domain_check"
-CREATE FUNCTION test_type_conversion_array_domain_array(x ordered_pair_domain[])
-  RETURNS ordered_pair_domain AS $$
-plpy.info(x, type(x))
-return x[0]
-$$ LANGUAGE plpythonu;
-select test_type_conversion_array_domain_array(array[array[2,4]::ordered_pair_domain]);
                
-INFO:  ([[2, 4]], <class 'list'>)
- test_type_conversion_array_domain_array 
------------------------------------------
- {2,4}
-(1 row)
-
----
---- Composite types
----
-CREATE TABLE employee (
-    name text,
-    basesalary integer,
-    bonus integer
-);
-INSERT INTO employee VALUES ('John', 100, 10), ('Mary', 200, 10);
-CREATE OR REPLACE FUNCTION test_composite_table_input(e employee) RETURNS integer AS \
                $$
-return e['basesalary'] + e['bonus']
-$$ LANGUAGE plpython3u;
-SELECT name, test_composite_table_input(employee.*) FROM employee;
- name | test_composite_table_input 
-------+----------------------------
- John |                        110
- Mary |                        210
-(2 rows)
-
-ALTER TABLE employee DROP bonus;
-SELECT name, test_composite_table_input(employee.*) FROM employee;
-ERROR:  KeyError: 'bonus'
-CONTEXT:  Traceback (most recent call last):
-  PL/Python function "test_composite_table_input", line 2, in <module>
-    return e['basesalary'] + e['bonus']
-PL/Python function "test_composite_table_input"
-ALTER TABLE employee ADD bonus integer;
-UPDATE employee SET bonus = 10;
-SELECT name, test_composite_table_input(employee.*) FROM employee;
- name | test_composite_table_input 
-------+----------------------------
- John |                        110
- Mary |                        210
-(2 rows)
-
-CREATE TYPE named_pair AS (
-    i integer,
-    j integer
-);
-CREATE OR REPLACE FUNCTION test_composite_type_input(p named_pair) RETURNS integer \
                AS $$
-return sum(p.values())
-$$ LANGUAGE plpython3u;
-SELECT test_composite_type_input(row(1, 2));
- test_composite_type_input 
----------------------------
-                         3
-(1 row)
-
-ALTER TYPE named_pair RENAME TO named_pair_2;
-SELECT test_composite_type_input(row(1, 2));
- test_composite_type_input 
----------------------------
-                         3
-(1 row)
-
---
--- Domains within composite
---
-CREATE TYPE nnint_container AS (f1 int, f2 nnint);
-CREATE FUNCTION nnint_test(x int, y int) RETURNS nnint_container AS $$
-return {'f1': x, 'f2': y}
-$$ LANGUAGE plpythonu;
-SELECT nnint_test(null, 3);
- nnint_test 
-------------
- (,3)
-(1 row)
-
-SELECT nnint_test(3, null);  -- fail
-ERROR:  value for domain nnint violates check constraint "nnint_check"
-CONTEXT:  while creating return value
-PL/Python function "nnint_test"
---
--- Domains of composite
---
-CREATE DOMAIN ordered_named_pair AS named_pair_2 CHECK((VALUE).i <= (VALUE).j);
-CREATE FUNCTION read_ordered_named_pair(p ordered_named_pair) RETURNS integer AS $$
-return p['i'] + p['j']
-$$ LANGUAGE plpythonu;
-SELECT read_ordered_named_pair(row(1, 2));
- read_ordered_named_pair 
--------------------------
-                       3
-(1 row)
-
-SELECT read_ordered_named_pair(row(2, 1));  -- fail
-ERROR:  value for domain ordered_named_pair violates check constraint \
                "ordered_named_pair_check"
-CREATE FUNCTION build_ordered_named_pair(i int, j int) RETURNS ordered_named_pair AS \
                $$
-return {'i': i, 'j': j}
-$$ LANGUAGE plpythonu;
-SELECT build_ordered_named_pair(1,2);
- build_ordered_named_pair 
---------------------------
- (1,2)
-(1 row)
-
-SELECT build_ordered_named_pair(2,1);  -- fail
-ERROR:  value for domain ordered_named_pair violates check constraint \
                "ordered_named_pair_check"
-CONTEXT:  while creating return value
-PL/Python function "build_ordered_named_pair"
-CREATE FUNCTION build_ordered_named_pairs(i int, j int) RETURNS ordered_named_pair[] \
                AS $$
-return [{'i': i, 'j': j}, {'i': i, 'j': j+1}]
-$$ LANGUAGE plpythonu;
-SELECT build_ordered_named_pairs(1,2);
- build_ordered_named_pairs 
----------------------------
- {"(1,2)","(1,3)"}
-(1 row)
-
-SELECT build_ordered_named_pairs(2,1);  -- fail
-ERROR:  value for domain ordered_named_pair violates check constraint \
                "ordered_named_pair_check"
-CONTEXT:  while creating return value
-PL/Python function "build_ordered_named_pairs"
---
--- Prepared statements
---
-CREATE OR REPLACE FUNCTION test_prep_bool_input() RETURNS int
-LANGUAGE plpython3u
-AS $$
-plan = plpy.prepare("SELECT CASE WHEN $1 THEN 1 ELSE 0 END AS val", ['boolean'])
-rv = plpy.execute(plan, ['fa'], 5) # 'fa' is true in Python
-return rv[0]['val']
-$$;
-SELECT test_prep_bool_input(); -- 1
- test_prep_bool_input 
-----------------------
-                    1
-(1 row)
-
-CREATE OR REPLACE FUNCTION test_prep_bool_output() RETURNS bool
-LANGUAGE plpython3u
-AS $$
-plan = plpy.prepare("SELECT $1 = 1 AS val", ['int'])
-rv = plpy.execute(plan, [0], 5)
-plpy.info(rv[0])
-return rv[0]['val']
-$$;
-SELECT test_prep_bool_output(); -- false
-INFO:  {'val': False}
- test_prep_bool_output 
------------------------
- f
-(1 row)
-
-CREATE OR REPLACE FUNCTION test_prep_bytea_input(bb bytea) RETURNS int
-LANGUAGE plpython3u
-AS $$
-plan = plpy.prepare("SELECT octet_length($1) AS val", ['bytea'])
-rv = plpy.execute(plan, [bb], 5)
-return rv[0]['val']
-$$;
-SELECT test_prep_bytea_input(E'a\\000b'); -- 3 (embedded null formerly truncated \
                value)
- test_prep_bytea_input 
------------------------
-                     3
-(1 row)
-
-CREATE OR REPLACE FUNCTION test_prep_bytea_output() RETURNS bytea
-LANGUAGE plpython3u
-AS $$
-plan = plpy.prepare("SELECT decode('aa00bb', 'hex') AS val")
-rv = plpy.execute(plan, [], 5)
-plpy.info(rv[0])
-return rv[0]['val']
-$$;
-SELECT test_prep_bytea_output();
-INFO:  {'val': b'\xaa\x00\xbb'}
- test_prep_bytea_output 
-------------------------
- \xaa00bb
-(1 row)
-
diff --git a/src/pl/plpython/expected/plpython_unicode.out \
b/src/pl/plpython/expected/plpython_unicode.out index c7546dd4587..fd54b0b88e8 100644
--- a/src/pl/plpython/expected/plpython_unicode.out
+++ b/src/pl/plpython/expected/plpython_unicode.out
@@ -11,24 +11,24 @@ CREATE TABLE unicode_test (
 	testvalue  text NOT NULL
 );
 CREATE FUNCTION unicode_return() RETURNS text AS E'
-return u"\\xA0"
-' LANGUAGE plpythonu;
+return "\\xA0"
+' LANGUAGE plpython3u;
 CREATE FUNCTION unicode_trigger() RETURNS trigger AS E'
-TD["new"]["testvalue"] = u"\\xA0"
+TD["new"]["testvalue"] = "\\xA0"
 return "MODIFY"
-' LANGUAGE plpythonu;
+' LANGUAGE plpython3u;
 CREATE TRIGGER unicode_test_bi BEFORE INSERT ON unicode_test
   FOR EACH ROW EXECUTE PROCEDURE unicode_trigger();
 CREATE FUNCTION unicode_plan1() RETURNS text AS E'
 plan = plpy.prepare("SELECT $1 AS testvalue", ["text"])
-rv = plpy.execute(plan, [u"\\xA0"], 1)
+rv = plpy.execute(plan, ["\\xA0"], 1)
 return rv[0]["testvalue"]
-' LANGUAGE plpythonu;
+' LANGUAGE plpython3u;
 CREATE FUNCTION unicode_plan2() RETURNS text AS E'
-plan = plpy.prepare("SELECT $1 || $2 AS testvalue", ["text", u"text"])
+plan = plpy.prepare("SELECT $1 || $2 AS testvalue", ["text", "text"])
 rv = plpy.execute(plan, ["foo", "bar"], 1)
 return rv[0]["testvalue"]
-' LANGUAGE plpythonu;
+' LANGUAGE plpython3u;
 SELECT unicode_return();
  unicode_return 
 ----------------
diff --git a/src/pl/plpython/expected/plpython_void.out \
b/src/pl/plpython/expected/plpython_void.out index 1080d12d6b2..07d0760783e 100644
--- a/src/pl/plpython/expected/plpython_void.out
+++ b/src/pl/plpython/expected/plpython_void.out
@@ -3,14 +3,14 @@
 --
 CREATE FUNCTION test_void_func1() RETURNS void AS $$
 x = 10
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 -- illegal: can't return non-None value in void-returning func
 CREATE FUNCTION test_void_func2() RETURNS void AS $$
 return 10
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 CREATE FUNCTION test_return_none() RETURNS int AS $$
 None
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 -- Tests for functions returning void
 SELECT test_void_func1(), test_void_func1() IS NULL AS "is null";
  test_void_func1 | is null 
diff --git a/src/pl/plpython/plpy_cursorobject.c \
b/src/pl/plpython/plpy_cursorobject.c index 08d8b607e38..f8591358bc8 100644
--- a/src/pl/plpython/plpy_cursorobject.c
+++ b/src/pl/plpython/plpy_cursorobject.c
@@ -40,7 +40,7 @@ static PyTypeObject PLy_CursorType = {
 	.tp_name = "PLyCursor",
 	.tp_basicsize = sizeof(PLyCursorObject),
 	.tp_dealloc = PLy_cursor_dealloc,
-	.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_ITER,
+	.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
 	.tp_doc = PLy_cursor_doc,
 	.tp_iter = PyObject_SelfIter,
 	.tp_iternext = PLy_cursor_iternext,
diff --git a/src/pl/plpython/plpy_main.c b/src/pl/plpython/plpy_main.c
index 3eedaa80da7..21303c1586b 100644
--- a/src/pl/plpython/plpy_main.c
+++ b/src/pl/plpython/plpy_main.c
@@ -28,27 +28,13 @@
  * exported functions
  */
 
-#if PY_MAJOR_VERSION >= 3
-/* Use separate names to reduce confusion */
-#define plpython_validator plpython3_validator
-#define plpython_call_handler plpython3_call_handler
-#define plpython_inline_handler plpython3_inline_handler
-#endif
-
 extern void _PG_init(void);
 
 PG_MODULE_MAGIC;
 
-PG_FUNCTION_INFO_V1(plpython_validator);
-PG_FUNCTION_INFO_V1(plpython_call_handler);
-PG_FUNCTION_INFO_V1(plpython_inline_handler);
-
-#if PY_MAJOR_VERSION < 3
-/* Define aliases plpython2_call_handler etc */
-PG_FUNCTION_INFO_V1(plpython2_validator);
-PG_FUNCTION_INFO_V1(plpython2_call_handler);
-PG_FUNCTION_INFO_V1(plpython2_inline_handler);
-#endif
+PG_FUNCTION_INFO_V1(plpython3_validator);
+PG_FUNCTION_INFO_V1(plpython3_call_handler);
+PG_FUNCTION_INFO_V1(plpython3_inline_handler);
 
 
 static bool PLy_procedure_is_trigger(Form_pg_proc procStruct);
@@ -125,13 +111,9 @@ PLy_initialize(void)
 	if (inited)
 		return;
 
-#if PY_MAJOR_VERSION >= 3
 	PyImport_AppendInittab("plpy", PyInit_plpy);
-#endif
 	Py_Initialize();
-#if PY_MAJOR_VERSION >= 3
 	PyImport_ImportModule("plpy");
-#endif
 	PLy_init_interp();
 	PLy_init_plpy();
 	if (PyErr_Occurred())
@@ -171,7 +153,7 @@ PLy_init_interp(void)
 }
 
 Datum
-plpython_validator(PG_FUNCTION_ARGS)
+plpython3_validator(PG_FUNCTION_ARGS)
 {
 	Oid			funcoid = PG_GETARG_OID(0);
 	HeapTuple	tuple;
@@ -203,17 +185,8 @@ plpython_validator(PG_FUNCTION_ARGS)
 	PG_RETURN_VOID();
 }
 
-#if PY_MAJOR_VERSION < 3
 Datum
-plpython2_validator(PG_FUNCTION_ARGS)
-{
-	/* call plpython validator with our fcinfo so it gets our oid */
-	return plpython_validator(fcinfo);
-}
-#endif							/* PY_MAJOR_VERSION < 3 */
-
-Datum
-plpython_call_handler(PG_FUNCTION_ARGS)
+plpython3_call_handler(PG_FUNCTION_ARGS)
 {
 	bool		nonatomic;
 	Datum		retval;
@@ -284,16 +257,8 @@ plpython_call_handler(PG_FUNCTION_ARGS)
 	return retval;
 }
 
-#if PY_MAJOR_VERSION < 3
-Datum
-plpython2_call_handler(PG_FUNCTION_ARGS)
-{
-	return plpython_call_handler(fcinfo);
-}
-#endif							/* PY_MAJOR_VERSION < 3 */
-
 Datum
-plpython_inline_handler(PG_FUNCTION_ARGS)
+plpython3_inline_handler(PG_FUNCTION_ARGS)
 {
 	LOCAL_FCINFO(fake_fcinfo, 0);
 	InlineCodeBlock *codeblock = (InlineCodeBlock *) \
DatumGetPointer(PG_GETARG_DATUM(0)); @@ -368,14 +333,6 @@ \
plpython_inline_handler(PG_FUNCTION_ARGS)  PG_RETURN_VOID();
 }
 
-#if PY_MAJOR_VERSION < 3
-Datum
-plpython2_inline_handler(PG_FUNCTION_ARGS)
-{
-	return plpython_inline_handler(fcinfo);
-}
-#endif							/* PY_MAJOR_VERSION < 3 */
-
 static bool
 PLy_procedure_is_trigger(Form_pg_proc procStruct)
 {
diff --git a/src/pl/plpython/plpy_plpymodule.c b/src/pl/plpython/plpy_plpymodule.c
index 0365acc95b0..0eefd34afcd 100644
--- a/src/pl/plpython/plpy_plpymodule.c
+++ b/src/pl/plpython/plpy_plpymodule.c
@@ -109,7 +109,6 @@ static PyMethodDef PLy_exc_methods[] = {
 	{NULL, NULL, 0, NULL}
 };
 
-#if PY_MAJOR_VERSION >= 3
 static PyModuleDef PLy_module = {
 	PyModuleDef_HEAD_INIT,
 	.m_name = "plpy",
@@ -141,7 +140,6 @@ PyInit_plpy(void)
 
 	return m;
 }
-#endif							/* PY_MAJOR_VERSION >= 3 */
 
 void
 PLy_init_plpy(void)
@@ -150,10 +148,6 @@ PLy_init_plpy(void)
 			   *main_dict,
 			   *plpy_mod;
 
-#if PY_MAJOR_VERSION < 3
-	PyObject   *plpy;
-#endif
-
 	/*
 	 * initialize plpy module
 	 */
@@ -162,13 +156,7 @@ PLy_init_plpy(void)
 	PLy_subtransaction_init_type();
 	PLy_cursor_init_type();
 
-#if PY_MAJOR_VERSION >= 3
 	PyModule_Create(&PLy_module);
-	/* for Python 3 we initialized the exceptions in PyInit_plpy */
-#else
-	plpy = Py_InitModule("plpy", PLy_methods);
-	PLy_add_exceptions(plpy);
-#endif
 
 	/* PyDict_SetItemString(plpy, "PlanType", (PyObject *) &PLy_PlanType); */
 
@@ -191,11 +179,7 @@ PLy_add_exceptions(PyObject *plpy)
 	PyObject   *excmod;
 	HASHCTL		hash_ctl;
 
-#if PY_MAJOR_VERSION < 3
-	excmod = Py_InitModule("spiexceptions", PLy_exc_methods);
-#else
 	excmod = PyModule_Create(&PLy_exc_module);
-#endif
 	if (excmod == NULL)
 		PLy_elog(ERROR, "could not create the spiexceptions module");
 
diff --git a/src/pl/plpython/plpy_plpymodule.h b/src/pl/plpython/plpy_plpymodule.h
index 54d78101ceb..ad6436aca78 100644
--- a/src/pl/plpython/plpy_plpymodule.h
+++ b/src/pl/plpython/plpy_plpymodule.h
@@ -11,9 +11,7 @@
 extern HTAB *PLy_spi_exceptions;
 
 
-#if PY_MAJOR_VERSION >= 3
 PyMODINIT_FUNC PyInit_plpy(void);
-#endif
 extern void PLy_init_plpy(void);
 
 #endif							/* PLPY_PLPYMODULE_H */
diff --git a/src/pl/plpython/plpy_resultobject.c \
b/src/pl/plpython/plpy_resultobject.c index 54f39419c84..f289617ba80 100644
--- a/src/pl/plpython/plpy_resultobject.c
+++ b/src/pl/plpython/plpy_resultobject.c
@@ -226,19 +226,11 @@ PLy_result_str(PyObject *arg)
 {
 	PLyResultObject *ob = (PLyResultObject *) arg;
 
-#if PY_MAJOR_VERSION >= 3
 	return PyUnicode_FromFormat("<%s status=%S nrows=%S rows=%S>",
 								Py_TYPE(ob)->tp_name,
 								ob->status,
 								ob->nrows,
 								ob->rows);
-#else
-	return PyString_FromFormat("<%s status=%ld nrows=%ld rows=%s>",
-							   ob->ob_type->tp_name,
-							   PyInt_AsLong(ob->status),
-							   PyInt_AsLong(ob->nrows),
-							   PyString_AsString(PyObject_Str(ob->rows)));
-#endif
 }
 
 static PyObject *
diff --git a/src/pl/plpython/plpy_typeio.c b/src/pl/plpython/plpy_typeio.c
index 5e807b139f1..adf37a9b882 100644
--- a/src/pl/plpython/plpy_typeio.c
+++ b/src/pl/plpython/plpy_typeio.c
@@ -1032,25 +1032,17 @@ PLyObject_AsString(PyObject *plrv)
 	else if (PyFloat_Check(plrv))
 	{
 		/* use repr() for floats, str() is lossy */
-#if PY_MAJOR_VERSION >= 3
 		PyObject   *s = PyObject_Repr(plrv);
 
 		plrv_bo = PLyUnicode_Bytes(s);
 		Py_XDECREF(s);
-#else
-		plrv_bo = PyObject_Repr(plrv);
-#endif
 	}
 	else
 	{
-#if PY_MAJOR_VERSION >= 3
 		PyObject   *s = PyObject_Str(plrv);
 
 		plrv_bo = PLyUnicode_Bytes(s);
 		Py_XDECREF(s);
-#else
-		plrv_bo = PyObject_Str(plrv);
-#endif
 	}
 	if (!plrv_bo)
 		PLy_elog(ERROR, "could not create string representation of Python object");
diff --git a/src/pl/plpython/plpy_util.c b/src/pl/plpython/plpy_util.c
index 4a7d7264d79..693d0396c48 100644
--- a/src/pl/plpython/plpy_util.c
+++ b/src/pl/plpython/plpy_util.c
@@ -95,7 +95,6 @@ PLyUnicode_AsString(PyObject *unicode)
 	return rv;
 }
 
-#if PY_MAJOR_VERSION >= 3
 /*
  * Convert a C string in the PostgreSQL server encoding to a Python
  * unicode object.  Reference ownership is passed to the caller.
@@ -126,5 +125,3 @@ PLyUnicode_FromString(const char *s)
 {
 	return PLyUnicode_FromStringAndSize(s, strlen(s));
 }
-
-#endif							/* PY_MAJOR_VERSION >= 3 */
diff --git a/src/pl/plpython/plpy_util.h b/src/pl/plpython/plpy_util.h
index c9ba7edc0ec..7c6577925ea 100644
--- a/src/pl/plpython/plpy_util.h
+++ b/src/pl/plpython/plpy_util.h
@@ -11,9 +11,7 @@
 extern PyObject *PLyUnicode_Bytes(PyObject *unicode);
 extern char *PLyUnicode_AsString(PyObject *unicode);
 
-#if PY_MAJOR_VERSION >= 3
 extern PyObject *PLyUnicode_FromString(const char *s);
 extern PyObject *PLyUnicode_FromStringAndSize(const char *s, Py_ssize_t size);
-#endif
 
 #endif							/* PLPY_UTIL_H */
diff --git a/src/pl/plpython/plpython.h b/src/pl/plpython/plpython.h
index 994457b37d6..68426b12f76 100644
--- a/src/pl/plpython/plpython.h
+++ b/src/pl/plpython/plpython.h
@@ -69,26 +69,21 @@
  * compatibility layer for Python 3 that when asked to convert a C
  * string to a Python string it converts the C string from the
  * PostgreSQL server encoding to a Python Unicode object.
+ *
+ * FIXME
  */
-#if PY_MAJOR_VERSION >= 3
 #define PyString_Check(x) 0
 #define PyString_AsString(x) PLyUnicode_AsString(x)
 #define PyString_FromString(x) PLyUnicode_FromString(x)
 #define PyString_FromStringAndSize(x, size) PLyUnicode_FromStringAndSize(x, size)
-#endif
 
 /*
  * Python 3 only has long.
+ *
+ * FIXME
  */
-#if PY_MAJOR_VERSION >= 3
 #define PyInt_FromLong(x) PyLong_FromLong(x)
 #define PyInt_AsLong(x) PyLong_AsLong(x)
-#endif
-
-/* Python 3 removed the Py_TPFLAGS_HAVE_ITER flag */
-#if PY_MAJOR_VERSION >= 3
-#define Py_TPFLAGS_HAVE_ITER 0
-#endif
 
 /* define our text domain for translations */
 #undef TEXTDOMAIN
diff --git a/src/pl/plpython/plpython2u--1.0.sql \
b/src/pl/plpython/plpython2u--1.0.sql deleted file mode 100644
index 69f74775678..00000000000
--- a/src/pl/plpython/plpython2u--1.0.sql
+++ /dev/null
@@ -1,17 +0,0 @@
-/* src/pl/plpython/plpython2u--1.0.sql */
-
-CREATE FUNCTION plpython2_call_handler() RETURNS language_handler
-  LANGUAGE c AS 'MODULE_PATHNAME';
-
-CREATE FUNCTION plpython2_inline_handler(internal) RETURNS void
-  STRICT LANGUAGE c AS 'MODULE_PATHNAME';
-
-CREATE FUNCTION plpython2_validator(oid) RETURNS void
-  STRICT LANGUAGE c AS 'MODULE_PATHNAME';
-
-CREATE LANGUAGE plpython2u
-  HANDLER plpython2_call_handler
-  INLINE plpython2_inline_handler
-  VALIDATOR plpython2_validator;
-
-COMMENT ON LANGUAGE plpython2u IS 'PL/Python2U untrusted procedural language';
diff --git a/src/pl/plpython/plpython2u.control b/src/pl/plpython/plpython2u.control
deleted file mode 100644
index 39c2b791efe..00000000000
--- a/src/pl/plpython/plpython2u.control
+++ /dev/null
@@ -1,7 +0,0 @@
-# plpython2u extension
-comment = 'PL/Python2U untrusted procedural language'
-default_version = '1.0'
-module_pathname = '$libdir/plpython2'
-relocatable = false
-schema = pg_catalog
-superuser = true
diff --git a/src/pl/plpython/plpythonu--1.0.sql b/src/pl/plpython/plpythonu--1.0.sql
deleted file mode 100644
index 4c6f7c3f140..00000000000
--- a/src/pl/plpython/plpythonu--1.0.sql
+++ /dev/null
@@ -1,17 +0,0 @@
-/* src/pl/plpython/plpythonu--1.0.sql */
-
-CREATE FUNCTION plpython_call_handler() RETURNS language_handler
-  LANGUAGE c AS 'MODULE_PATHNAME';
-
-CREATE FUNCTION plpython_inline_handler(internal) RETURNS void
-  STRICT LANGUAGE c AS 'MODULE_PATHNAME';
-
-CREATE FUNCTION plpython_validator(oid) RETURNS void
-  STRICT LANGUAGE c AS 'MODULE_PATHNAME';
-
-CREATE LANGUAGE plpythonu
-  HANDLER plpython_call_handler
-  INLINE plpython_inline_handler
-  VALIDATOR plpython_validator;
-
-COMMENT ON LANGUAGE plpythonu IS 'PL/PythonU untrusted procedural language';
diff --git a/src/pl/plpython/plpythonu.control b/src/pl/plpython/plpythonu.control
deleted file mode 100644
index ae91b1c255c..00000000000
--- a/src/pl/plpython/plpythonu.control
+++ /dev/null
@@ -1,7 +0,0 @@
-# plpythonu extension
-comment = 'PL/PythonU untrusted procedural language'
-default_version = '1.0'
-module_pathname = '$libdir/plpython2'
-relocatable = false
-schema = pg_catalog
-superuser = true
diff --git a/src/pl/plpython/regress-python3-mangle.mk \
b/src/pl/plpython/regress-python3-mangle.mk deleted file mode 100644
index a785818a172..00000000000
--- a/src/pl/plpython/regress-python3-mangle.mk
+++ /dev/null
@@ -1,38 +0,0 @@
-ifeq ($(python_majorversion),3)
-# Adjust regression tests for Python 3 compatibility
-#
-# Mention those regression test files that need to be mangled in the
-# variable REGRESS_PLPYTHON3_MANGLE.  They will be copied to a
-# subdirectory python3/ and have their Python syntax and other bits
-# adjusted to work with Python 3.
-
-# Note that the order of the tests needs to be preserved in this
-# expression.
-REGRESS := $(foreach test,$(REGRESS),$(if $(filter \
                $(test),$(REGRESS_PLPYTHON3_MANGLE)),python3/$(test),$(test)))
-
-.PHONY: pgregress-python3-mangle
-pgregress-python3-mangle:
-	$(MKDIR_P) sql/python3 expected/python3 results/python3
-	for file in $(patsubst %,$(srcdir)/sql/%.sql,$(REGRESS_PLPYTHON3_MANGLE)) \
                $(patsubst %,$(srcdir)/expected/%*.out,$(REGRESS_PLPYTHON3_MANGLE)); \
                do \
-	  sed \
-	      -e "s/<type 'exceptions\.\([[:alpha:]]*\)'>/<class '\1'>/g" \
-	      -e "s/<type 'long'>/<class 'int'>/g" \
-	      -e "s/\([0-9][0-9]*\)L/\1/g" \
-	      -e 's/\([ [{]\)u"/\1"/g' \
-	      -e "s/\([ [{]\)u'/\1'/g" \
-	      -e "s/def next/def __next__/g" \
-	      -e "s/LANGUAGE plpythonu/LANGUAGE plpython3u/g" \
-	      -e "s/LANGUAGE plpython2u/LANGUAGE plpython3u/g" \
-	      -e "s/EXTENSION plpythonu/EXTENSION plpython3u/g" \
-	      -e "s/EXTENSION plpython2u/EXTENSION plpython3u/g" \
-	      -e "s/EXTENSION \([^ ]*\)_plpythonu/EXTENSION \1_plpython3u/g" \
-	      -e "s/EXTENSION \([^ ]*\)_plpython2u/EXTENSION \1_plpython3u/g" \
-	      -e 's/installing required extension "plpython2u"/installing required \
                extension "plpython3u"/g' \
-	    $$file >`echo $$file | sed 's,^.*/\([^/][^/]*/\)\([^/][^/]*\)$$,\1python3/\2,'` \
                || exit; \
-	done
-
-check installcheck: pgregress-python3-mangle
-
-pg_regress_clean_files += sql/python3/ expected/python3/ results/python3/
-
-endif # Python 3
diff --git a/src/pl/plpython/sql/plpython_call.sql \
b/src/pl/plpython/sql/plpython_call.sql index b0b3705ae3c..daa4bc377d7 100644
--- a/src/pl/plpython/sql/plpython_call.sql
+++ b/src/pl/plpython/sql/plpython_call.sql
@@ -3,7 +3,7 @@
 --
 
 CREATE PROCEDURE test_proc1()
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 AS $$
 pass
 $$;
@@ -13,7 +13,7 @@ CALL test_proc1();
 
 -- error: can't return non-None
 CREATE PROCEDURE test_proc2()
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 AS $$
 return 5
 $$;
@@ -24,7 +24,7 @@ CALL test_proc2();
 CREATE TABLE test1 (a int);
 
 CREATE PROCEDURE test_proc3(x int)
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 AS $$
 plpy.execute("INSERT INTO test1 VALUES (%s)" % x)
 $$;
@@ -37,7 +37,7 @@ SELECT * FROM test1;
 -- output arguments
 
 CREATE PROCEDURE test_proc5(INOUT a text)
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 AS $$
 return [a + '+' + a]
 $$;
@@ -46,7 +46,7 @@ CALL test_proc5('abc');
 
 
 CREATE PROCEDURE test_proc6(a int, INOUT b int, INOUT c int)
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 AS $$
 return (b * a, c * a)
 $$;
@@ -57,7 +57,7 @@ CALL test_proc6(2, 3, 4);
 -- OUT parameters
 
 CREATE PROCEDURE test_proc9(IN a int, OUT b int)
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 AS $$
 plpy.notice("a: %s" % (a))
 return (a * 2,)
diff --git a/src/pl/plpython/sql/plpython_composite.sql \
b/src/pl/plpython/sql/plpython_composite.sql index 0fd2f5d5e3b..21757701cc1 100644
--- a/src/pl/plpython/sql/plpython_composite.sql
+++ b/src/pl/plpython/sql/plpython_composite.sql
@@ -1,6 +1,6 @@
 CREATE FUNCTION multiout_simple(OUT i integer, OUT j integer) AS $$
 return (1, 2)
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT multiout_simple();
 SELECT * FROM multiout_simple();
@@ -9,7 +9,7 @@ SELECT (multiout_simple()).j + 3;
 
 CREATE FUNCTION multiout_simple_setof(n integer = 1, OUT integer, OUT integer) \
RETURNS SETOF record AS $$  return [(1, 2)] * n
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT multiout_simple_setof();
 SELECT * FROM multiout_simple_setof();
@@ -34,7 +34,7 @@ elif typ == 'obj':
     return type_record
 elif typ == 'str':
     return "('%s',%r)" % (first, second)
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT * FROM multiout_record_as('dict', 'foo', 1, 'f');
 SELECT multiout_record_as('dict', 'foo', 1, 'f');
@@ -77,7 +77,7 @@ for i in range(n):
     power = 2 ** i
     length = plpy.execute("select length('%d')" % power)[0]['length']
     yield power, length
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT * FROM multiout_setof(3);
 SELECT multiout_setof(5);
@@ -86,7 +86,7 @@ CREATE FUNCTION multiout_return_table() RETURNS TABLE (x integer, y \
text) AS $$  return [{'x': 4, 'y' :'four'},
         {'x': 7, 'y' :'seven'},
         {'x': 0, 'y' :'zero'}]
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT * FROM multiout_return_table();
 
@@ -94,18 +94,18 @@ CREATE FUNCTION multiout_array(OUT integer[], OUT text) RETURNS \
SETOF record AS  yield [[1], 'a']
 yield [[1,2], 'b']
 yield [[1,2,3], None]
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT * FROM multiout_array();
 
 CREATE FUNCTION singleout_composite(OUT type_record) AS $$
 return {'first': 1, 'second': 2}
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 CREATE FUNCTION multiout_composite(OUT type_record) RETURNS SETOF type_record AS $$
 return [{'first': 1, 'second': 2},
        {'first': 3, 'second': 4	}]
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT * FROM singleout_composite();
 SELECT * FROM multiout_composite();
@@ -113,7 +113,7 @@ SELECT * FROM multiout_composite();
 -- composite OUT parameters in functions returning RECORD not supported yet
 CREATE FUNCTION multiout_composite(INOUT n integer, OUT type_record) AS $$
 return (n, (n * 2, n * 3))
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 CREATE FUNCTION multiout_table_type_setof(typ text, returnnull boolean, INOUT n \
integer, OUT table_record) RETURNS SETOF record AS $$  if returnnull:
@@ -132,7 +132,7 @@ elif typ == 'str':
     d = "(%r,%r)" % (n * 2, n * 3)
 for i in range(n):
     yield (i, d)
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT * FROM multiout_composite(2);
 SELECT * FROM multiout_table_type_setof('dict', 'f', 3);
@@ -157,7 +157,7 @@ CREATE TABLE changing (
 CREATE FUNCTION changing_test(OUT n integer, OUT changing) RETURNS SETOF record AS \
$$  return [(1, {'i': 1, 'j': 2}),
         (1, (3, 4))]
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT * FROM changing_test();
 ALTER TABLE changing DROP COLUMN j;
@@ -178,14 +178,14 @@ yield {'tab': [('first', 1), ('second', 2)],
 yield {'tab': [('first', 1), ('second', 2)],
       'typ': [{'first': 'third', 'second': 3},
               {'first': 'fourth', 'second': 4}]}
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT * FROM composite_types_table();
 
 -- check what happens if the output record descriptor changes
 CREATE FUNCTION return_record(t text) RETURNS record AS $$
 return {'t': t, 'val': 10}
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT * FROM return_record('abc') AS r(t text, val integer);
 SELECT * FROM return_record('abc') AS r(t text, val bigint);
@@ -196,7 +196,7 @@ SELECT * FROM return_record('999') AS r(val text, t integer);
 
 CREATE FUNCTION return_record_2(t text) RETURNS record AS $$
 return {'v1':1,'v2':2,t:3}
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT * FROM return_record_2('v3') AS (v3 int, v2 int, v1 int);
 SELECT * FROM return_record_2('v3') AS (v2 int, v3 int, v1 int);
@@ -211,7 +211,7 @@ SELECT * FROM return_record_2('v3') AS (v1 int, v2 int, v3 int);
 -- multi-dimensional array of composite types.
 CREATE FUNCTION composite_type_as_list()  RETURNS type_record[] AS $$
   return [[('first', 1), ('second', 1)], [('first', 2), ('second', 2)], [('first', \
                3), ('second', 3)]];
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT * FROM composite_type_as_list();
 
 -- Starting with PostgreSQL 10, a composite type in an array cannot be
@@ -220,5 +220,5 @@ SELECT * FROM composite_type_as_list();
 -- on the issue.
 CREATE FUNCTION composite_type_as_list_broken()  RETURNS type_record[] AS $$
   return [['first', 1]];
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT * FROM composite_type_as_list_broken();
diff --git a/src/pl/plpython/sql/plpython_do.sql \
b/src/pl/plpython/sql/plpython_do.sql index 0e281a08ee8..d49413268e9 100644
--- a/src/pl/plpython/sql/plpython_do.sql
+++ b/src/pl/plpython/sql/plpython_do.sql
@@ -1,5 +1,3 @@
-DO $$ plpy.notice("This is plpythonu.") $$ LANGUAGE plpythonu;
+DO $$ plpy.notice("This is plpython3u.") $$ LANGUAGE plpython3u;
 
-DO $$ plpy.notice("This is plpython2u.") $$ LANGUAGE plpython2u;
-
-DO $$ raise Exception("error test") $$ LANGUAGE plpythonu;
+DO $$ raise Exception("error test") $$ LANGUAGE plpython3u;
diff --git a/src/pl/plpython/sql/plpython_drop.sql \
b/src/pl/plpython/sql/plpython_drop.sql index 72d5d657ec3..e4f373b2bc7 100644
--- a/src/pl/plpython/sql/plpython_drop.sql
+++ b/src/pl/plpython/sql/plpython_drop.sql
@@ -3,6 +3,4 @@
 --
 SET client_min_messages = WARNING;
 
-DROP EXTENSION plpythonu CASCADE;
-
-DROP EXTENSION IF EXISTS plpython2u CASCADE;
+DROP EXTENSION plpython3u CASCADE;
diff --git a/src/pl/plpython/sql/plpython_ereport.sql \
b/src/pl/plpython/sql/plpython_ereport.sql index 58df2057ef5..3bcf8f5cde9 100644
--- a/src/pl/plpython/sql/plpython_ereport.sql
+++ b/src/pl/plpython/sql/plpython_ereport.sql
@@ -17,28 +17,28 @@ plpy.info('This is message text.',
 plpy.notice('notice', detail='some detail')
 plpy.warning('warning', detail='some detail')
 plpy.error('stop on error', detail='some detail', hint='some hint')
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT elog_test();
 
-DO $$ plpy.info('other types', detail=(10, 20)) $$ LANGUAGE plpythonu;
+DO $$ plpy.info('other types', detail=(10, 20)) $$ LANGUAGE plpython3u;
 
 DO $$
 import time;
 from datetime import date
 plpy.info('other types', detail=date(2016, 2, 26))
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 DO $$
 basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana']
 plpy.info('other types', detail=basket)
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 -- should fail
-DO $$ plpy.info('wrong sqlstate', sqlstate='54444A') $$ LANGUAGE plpythonu;
-DO $$ plpy.info('unsupported argument', blabla='fooboo') $$ LANGUAGE plpythonu;
-DO $$ plpy.info('first message', message='second message') $$ LANGUAGE plpythonu;
-DO $$ plpy.info('first message', 'second message', message='third message') $$ \
LANGUAGE plpythonu; +DO $$ plpy.info('wrong sqlstate', sqlstate='54444A') $$ LANGUAGE \
plpython3u; +DO $$ plpy.info('unsupported argument', blabla='fooboo') $$ LANGUAGE \
plpython3u; +DO $$ plpy.info('first message', message='second message') $$ LANGUAGE \
plpython3u; +DO $$ plpy.info('first message', 'second message', message='third \
message') $$ LANGUAGE plpython3u;  
 -- raise exception in python, handle exception in plgsql
 CREATE OR REPLACE FUNCTION raise_exception(_message text, _detail text DEFAULT NULL, \
_hint text DEFAULT NULL, @@ -57,7 +57,7 @@ kwargs = {
 }
 # ignore None values
 plpy.error(**dict((k, v) for k, v in iter(kwargs.items()) if v))
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT raise_exception('hello', 'world');
 SELECT raise_exception('message text', 'detail text', _sqlstate => 'YY333');
@@ -128,7 +128,7 @@ try:
 except Exception as e:
     plpy.info(e.spidata)
     raise e
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 DO $$
 try:
@@ -136,4 +136,4 @@ try:
 except Exception as e:
     plpy.info('sqlstate: %s, hint: %s, table_name: %s, datatype_name: %s' % \
(e.sqlstate, e.hint, e.table_name, e.datatype_name))  raise e
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
diff --git a/src/pl/plpython/sql/plpython_error.sql \
b/src/pl/plpython/sql/plpython_error.sql index 88d6936fd0d..11f14ec5a7c 100644
--- a/src/pl/plpython/sql/plpython_error.sql
+++ b/src/pl/plpython/sql/plpython_error.sql
@@ -7,7 +7,7 @@
 CREATE FUNCTION python_syntax_error() RETURNS text
         AS
 '.syntaxerror'
-        LANGUAGE plpythonu;
+        LANGUAGE plpython3u;
 
 /* With check_function_bodies = false the function should get defined
  * and the error reported when called
@@ -17,7 +17,7 @@ SET check_function_bodies = false;
 CREATE FUNCTION python_syntax_error() RETURNS text
         AS
 '.syntaxerror'
-        LANGUAGE plpythonu;
+        LANGUAGE plpython3u;
 
 SELECT python_syntax_error();
 /* Run the function twice to check if the hashtable entry gets cleaned up */
@@ -30,7 +30,7 @@ RESET check_function_bodies;
 CREATE FUNCTION sql_syntax_error() RETURNS text
         AS
 'plpy.execute("syntax error")'
-        LANGUAGE plpythonu;
+        LANGUAGE plpython3u;
 
 SELECT sql_syntax_error();
 
@@ -40,7 +40,7 @@ SELECT sql_syntax_error();
 CREATE FUNCTION exception_index_invalid(text) RETURNS text
 	AS
 'return args[1]'
-	LANGUAGE plpythonu;
+	LANGUAGE plpython3u;
 
 SELECT exception_index_invalid('test');
 
@@ -51,7 +51,7 @@ CREATE FUNCTION exception_index_invalid_nested() RETURNS text
 	AS
 'rv = plpy.execute("SELECT test5(''foo'')")
 return rv[0]'
-	LANGUAGE plpythonu;
+	LANGUAGE plpython3u;
 
 SELECT exception_index_invalid_nested();
 
@@ -68,7 +68,7 @@ if len(rv):
 	return rv[0]["fname"]
 return None
 '
-	LANGUAGE plpythonu;
+	LANGUAGE plpython3u;
 
 SELECT invalid_type_uncaught('rick');
 
@@ -90,7 +90,7 @@ if len(rv):
 	return rv[0]["fname"]
 return None
 '
-	LANGUAGE plpythonu;
+	LANGUAGE plpython3u;
 
 SELECT invalid_type_caught('rick');
 
@@ -111,7 +111,7 @@ if len(rv):
 	return rv[0]["fname"]
 return None
 '
-	LANGUAGE plpythonu;
+	LANGUAGE plpython3u;
 
 SELECT invalid_type_reraised('rick');
 
@@ -127,7 +127,7 @@ if len(rv):
 	return rv[0]["fname"]
 return None
 '
-	LANGUAGE plpythonu;
+	LANGUAGE plpython3u;
 
 SELECT valid_type('rick');
 
@@ -147,7 +147,7 @@ def fun3():
 fun3()
 return "not reached"
 '
-	LANGUAGE plpythonu;
+	LANGUAGE plpython3u;
 
 SELECT nested_error();
 
@@ -167,7 +167,7 @@ def fun3():
 fun3()
 return "not reached"
 '
-	LANGUAGE plpythonu;
+	LANGUAGE plpython3u;
 
 SELECT nested_error_raise();
 
@@ -187,7 +187,7 @@ def fun3():
 fun3()
 return "you''ve been warned"
 '
-	LANGUAGE plpythonu;
+	LANGUAGE plpython3u;
 
 SELECT nested_warning();
 
@@ -196,7 +196,7 @@ SELECT nested_warning();
 CREATE FUNCTION toplevel_attribute_error() RETURNS void AS
 $$
 plpy.nonexistent
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT toplevel_attribute_error();
 
@@ -213,7 +213,7 @@ def third():
   plpy.execute("select sql_error()")
 
 first()
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 CREATE OR REPLACE FUNCTION sql_error() RETURNS void AS $$
 begin
@@ -229,7 +229,7 @@ $$ LANGUAGE plpgsql;
 
 CREATE OR REPLACE FUNCTION sql_from_python_error() RETURNS void AS $$
 plpy.execute("select sql_error()")
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT python_traceback();
 SELECT sql_error();
@@ -251,7 +251,7 @@ except spiexceptions.NotNullViolation as e:
     plpy.notice("Violated the NOT NULL constraint, sqlstate %s" % e.sqlstate)
 except spiexceptions.UniqueViolation as e:
     plpy.notice("Violated the UNIQUE constraint, sqlstate %s" % e.sqlstate)
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT specific_exception(2);
 SELECT specific_exception(NULL);
@@ -262,7 +262,7 @@ SELECT specific_exception(2);
 CREATE FUNCTION python_unique_violation() RETURNS void AS $$
 plpy.execute("insert into specific values (1)")
 plpy.execute("insert into specific values (1)")
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 CREATE FUNCTION catch_python_unique_violation() RETURNS text AS $$
 begin
@@ -283,7 +283,7 @@ CREATE FUNCTION manual_subxact() RETURNS void AS $$
 plpy.execute("savepoint save")
 plpy.execute("create table foo(x integer)")
 plpy.execute("rollback to save")
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT manual_subxact();
 
@@ -295,7 +295,7 @@ rollback = plpy.prepare("rollback to save")
 plpy.execute(save)
 plpy.execute("create table foo(x integer)")
 plpy.execute(rollback)
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT manual_subxact_prepared();
 
@@ -303,7 +303,7 @@ SELECT manual_subxact_prepared();
  */
 CREATE FUNCTION plpy_raise_spiexception() RETURNS void AS $$
 raise plpy.spiexceptions.DivisionByZero()
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 DO $$
 BEGIN
@@ -319,7 +319,7 @@ CREATE FUNCTION plpy_raise_spiexception_override() RETURNS void \
AS $$  exc = plpy.spiexceptions.DivisionByZero()
 exc.sqlstate = 'SILLY'
 raise exc
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 DO $$
 BEGIN
@@ -332,14 +332,14 @@ $$ LANGUAGE plpgsql;
 /* test the context stack trace for nested execution levels
  */
 CREATE FUNCTION notice_innerfunc() RETURNS int AS $$
-plpy.execute("DO LANGUAGE plpythonu $x$ plpy.notice('inside DO') $x$")
+plpy.execute("DO LANGUAGE plpython3u $x$ plpy.notice('inside DO') $x$")
 return 1
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 CREATE FUNCTION notice_outerfunc() RETURNS int AS $$
 plpy.execute("SELECT notice_innerfunc()")
 return 1
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 \set SHOW_CONTEXT always
 
diff --git a/src/pl/plpython/sql/plpython_global.sql \
b/src/pl/plpython/sql/plpython_global.sql index 32502b41eee..96d20492861 100644
--- a/src/pl/plpython/sql/plpython_global.sql
+++ b/src/pl/plpython/sql/plpython_global.sql
@@ -9,7 +9,7 @@ CREATE FUNCTION global_test_one() returns text
 if "global_test" not in GD:
 	GD["global_test"] = "set by global_test_one"
 return "SD: " + SD["global_test"] + ", GD: " + GD["global_test"]'
-    LANGUAGE plpythonu;
+    LANGUAGE plpython3u;
 
 CREATE FUNCTION global_test_two() returns text
     AS
@@ -18,7 +18,7 @@ CREATE FUNCTION global_test_two() returns text
 if "global_test" not in GD:
 	GD["global_test"] = "set by global_test_two"
 return "SD: " + SD["global_test"] + ", GD: " + GD["global_test"]'
-    LANGUAGE plpythonu;
+    LANGUAGE plpython3u;
 
 
 CREATE FUNCTION static_test() returns int4
@@ -29,7 +29,7 @@ else:
 	SD["call"] = 1
 return SD["call"]
 '
-    LANGUAGE plpythonu;
+    LANGUAGE plpython3u;
 
 
 SELECT static_test();
diff --git a/src/pl/plpython/sql/plpython_import.sql \
b/src/pl/plpython/sql/plpython_import.sql index ec887677e1e..3031eef2e69 100644
--- a/src/pl/plpython/sql/plpython_import.sql
+++ b/src/pl/plpython/sql/plpython_import.sql
@@ -7,7 +7,7 @@ CREATE FUNCTION import_fail() returns text
 except ImportError:
 	return "failed as expected"
 return "succeeded, that wasn''t supposed to happen"'
-    LANGUAGE plpythonu;
+    LANGUAGE plpython3u;
 
 
 CREATE FUNCTION import_succeed() returns text
@@ -28,7 +28,7 @@ except Exception as ex:
 	plpy.notice("import failed -- %s" % str(ex))
 	return "failed, that wasn''t supposed to happen"
 return "succeeded, as expected"'
-    LANGUAGE plpythonu;
+    LANGUAGE plpython3u;
 
 CREATE FUNCTION import_test_one(p text) RETURNS text
 	AS
@@ -39,7 +39,7 @@ except ImportError:
     import sha
     digest = sha.new(p)
 return digest.hexdigest()'
-	LANGUAGE plpythonu;
+	LANGUAGE plpython3u;
 
 CREATE FUNCTION import_test_two(u users) RETURNS text
 	AS
@@ -51,7 +51,7 @@ except ImportError:
     import sha
     digest = sha.new(plain);
 return "sha hash of " + plain + " is " + digest.hexdigest()'
-	LANGUAGE plpythonu;
+	LANGUAGE plpython3u;
 
 
 -- import python modules
diff --git a/src/pl/plpython/sql/plpython_newline.sql \
b/src/pl/plpython/sql/plpython_newline.sql index f9cee9491bb..cb22ba923f9 100644
--- a/src/pl/plpython/sql/plpython_newline.sql
+++ b/src/pl/plpython/sql/plpython_newline.sql
@@ -4,15 +4,15 @@
 
 CREATE OR REPLACE FUNCTION newline_lf() RETURNS integer AS
 E'x = 100\ny = 23\nreturn x + y\n'
-LANGUAGE plpythonu;
+LANGUAGE plpython3u;
 
 CREATE OR REPLACE FUNCTION newline_cr() RETURNS integer AS
 E'x = 100\ry = 23\rreturn x + y\r'
-LANGUAGE plpythonu;
+LANGUAGE plpython3u;
 
 CREATE OR REPLACE FUNCTION newline_crlf() RETURNS integer AS
 E'x = 100\r\ny = 23\r\nreturn x + y\r\n'
-LANGUAGE plpythonu;
+LANGUAGE plpython3u;
 
 
 SELECT newline_lf();
diff --git a/src/pl/plpython/sql/plpython_params.sql \
b/src/pl/plpython/sql/plpython_params.sql index ee75c4dc410..8bab4888592 100644
--- a/src/pl/plpython/sql/plpython_params.sql
+++ b/src/pl/plpython/sql/plpython_params.sql
@@ -4,13 +4,13 @@
 
 CREATE FUNCTION test_param_names0(integer, integer) RETURNS int AS $$
 return args[0] + args[1]
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 CREATE FUNCTION test_param_names1(a0 integer, a1 text) RETURNS boolean AS $$
 assert a0 == args[0]
 assert a1 == args[1]
 return True
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 CREATE FUNCTION test_param_names2(u users) RETURNS text AS $$
 assert u == args[0]
@@ -22,7 +22,7 @@ if isinstance(u, dict):
 else:
     s = str(u)
 return s
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 -- use deliberately wrong parameter names
 CREATE FUNCTION test_param_names3(a0 integer) RETURNS boolean AS $$
@@ -32,7 +32,7 @@ try:
 except NameError as e:
 	assert e.args[0].find("a1") > -1
 	return True
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 
 SELECT test_param_names0(2,7);
diff --git a/src/pl/plpython/sql/plpython_quote.sql \
b/src/pl/plpython/sql/plpython_quote.sql index 346b5485daf..a1133e7e266 100644
--- a/src/pl/plpython/sql/plpython_quote.sql
+++ b/src/pl/plpython/sql/plpython_quote.sql
@@ -9,7 +9,7 @@ CREATE FUNCTION quote(t text, how text) RETURNS text AS $$
         return plpy.quote_ident(t)
     else:
         raise plpy.Error("unrecognized quote type %s" % how)
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT quote(t, 'literal') FROM (VALUES
        ('abc'),
diff --git a/src/pl/plpython/sql/plpython_record.sql \
b/src/pl/plpython/sql/plpython_record.sql index 9bab4c9e82d..52bad8bccea 100644
--- a/src/pl/plpython/sql/plpython_record.sql
+++ b/src/pl/plpython/sql/plpython_record.sql
@@ -27,7 +27,7 @@ elif typ == 'obj':
 	type_record.first = first
 	type_record.second = second
 	return type_record
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 CREATE FUNCTION test_type_record_as(typ text, first text, second integer, retnull \
boolean) RETURNS type_record AS $$  if retnull:
@@ -45,20 +45,20 @@ elif typ == 'obj':
 	return type_record
 elif typ == 'str':
 	return "('%s',%r)" % (first, second)
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 CREATE FUNCTION test_in_out_params(first in text, second out text) AS $$
 return first + '_in_to_out';
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 CREATE FUNCTION test_in_out_params_multi(first in text,
                                          second out text, third out text) AS $$
 return (first + '_record_in_to_out_1', first + '_record_in_to_out_2');
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 CREATE FUNCTION test_inout_params(first inout text) AS $$
 return first + '_inout';
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 
 -- Test tuple returning functions
@@ -136,14 +136,14 @@ SELECT * FROM test_type_record_as('obj', 'one', 1, false);
 
 CREATE FUNCTION test_type_record_error1() RETURNS type_record AS $$
     return { 'first': 'first' }
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT * FROM test_type_record_error1();
 
 
 CREATE FUNCTION test_type_record_error2() RETURNS type_record AS $$
     return [ 'first' ]
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT * FROM test_type_record_error2();
 
@@ -152,12 +152,12 @@ CREATE FUNCTION test_type_record_error3() RETURNS type_record \
AS $$  class type_record: pass
     type_record.first = 'first'
     return type_record
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT * FROM test_type_record_error3();
 
 CREATE FUNCTION test_type_record_error4() RETURNS type_record AS $$
     return 'foo'
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT * FROM test_type_record_error4();
diff --git a/src/pl/plpython/sql/plpython_setof.sql \
b/src/pl/plpython/sql/plpython_setof.sql index 16c2eef0ad6..4cfb10192c0 100644
--- a/src/pl/plpython/sql/plpython_setof.sql
+++ b/src/pl/plpython/sql/plpython_setof.sql
@@ -4,21 +4,21 @@
 
 CREATE FUNCTION test_setof_error() RETURNS SETOF text AS $$
 return 37
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT test_setof_error();
 
 
 CREATE FUNCTION test_setof_as_list(count integer, content text) RETURNS SETOF text \
AS $$  return [ content ]*count
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 CREATE FUNCTION test_setof_as_tuple(count integer, content text) RETURNS SETOF text \
AS $$  t = ()
 for i in range(count):
 	t += ( content, )
 return t
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 CREATE FUNCTION test_setof_as_iterator(count integer, content text) RETURNS SETOF \
text AS $$  class producer:
@@ -27,13 +27,13 @@ class producer:
 		self.icount = icount
 	def __iter__ (self):
 		return self
-	def next (self):
+	def __next__ (self):
 		if self.icount == 0:
 			raise StopIteration
 		self.icount -= 1
 		return self.icontent
 return producer(count, content)
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 CREATE FUNCTION test_setof_spi_in_iterator() RETURNS SETOF text AS
 $$
@@ -42,7 +42,7 @@ $$
         yield s
         plpy.execute('select 2')
 $$
-LANGUAGE plpythonu;
+LANGUAGE plpython3u;
 
 
 -- Test set returning functions
@@ -69,7 +69,7 @@ global x
 while x <= lim:
     yield x
     x = x + 1
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT ugly(1, 5);
 
@@ -81,7 +81,7 @@ CREATE OR REPLACE FUNCTION get_user_records()
 RETURNS SETOF users
 AS $$
     return plpy.execute("SELECT * FROM users ORDER BY username")
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT get_user_records();
 SELECT * FROM get_user_records();
@@ -91,7 +91,7 @@ CREATE OR REPLACE FUNCTION get_user_records2()
 RETURNS TABLE(fname text, lname text, username text, userid int)
 AS $$
     return plpy.execute("SELECT * FROM users ORDER BY username")
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT get_user_records2();
 SELECT * FROM get_user_records2();
diff --git a/src/pl/plpython/sql/plpython_spi.sql \
b/src/pl/plpython/sql/plpython_spi.sql index dd77833ed56..112add93fc9 100644
--- a/src/pl/plpython/sql/plpython_spi.sql
+++ b/src/pl/plpython/sql/plpython_spi.sql
@@ -7,19 +7,19 @@ CREATE FUNCTION nested_call_one(a text) RETURNS text
 'q = "SELECT nested_call_two(''%s'')" % a
 r = plpy.execute(q)
 return r[0]'
-	LANGUAGE plpythonu ;
+	LANGUAGE plpython3u ;
 
 CREATE FUNCTION nested_call_two(a text) RETURNS text
 	AS
 'q = "SELECT nested_call_three(''%s'')" % a
 r = plpy.execute(q)
 return r[0]'
-	LANGUAGE plpythonu ;
+	LANGUAGE plpython3u ;
 
 CREATE FUNCTION nested_call_three(a text) RETURNS text
 	AS
 'return a'
-	LANGUAGE plpythonu ;
+	LANGUAGE plpython3u ;
 
 -- some spi stuff
 
@@ -35,7 +35,7 @@ except Exception as ex:
 	plpy.error(str(ex))
 return None
 '
-	LANGUAGE plpythonu;
+	LANGUAGE plpython3u;
 
 CREATE FUNCTION spi_prepared_plan_test_two(a text) RETURNS text
 	AS
@@ -49,7 +49,7 @@ except Exception as ex:
 	plpy.error(str(ex))
 return None
 '
-	LANGUAGE plpythonu;
+	LANGUAGE plpython3u;
 
 CREATE FUNCTION spi_prepared_plan_test_nested(a text) RETURNS text
 	AS
@@ -64,7 +64,7 @@ except Exception as ex:
 	plpy.error(str(ex))
 return None
 '
-	LANGUAGE plpythonu;
+	LANGUAGE plpython3u;
 
 CREATE FUNCTION join_sequences(s sequences) RETURNS text
 	AS
@@ -77,7 +77,7 @@ for r in rv:
 	seq = seq + r["sequence"]
 return seq
 '
-	LANGUAGE plpythonu;
+	LANGUAGE plpython3u;
 
 CREATE FUNCTION spi_recursive_sum(a int) RETURNS int
 	AS
@@ -86,7 +86,7 @@ if a > 1:
     r = plpy.execute("SELECT spi_recursive_sum(%d) as a" % (a-1))[0]["a"]
 return a + r
 '
-	LANGUAGE plpythonu;
+	LANGUAGE plpython3u;
 
 --
 -- spi and nested calls
@@ -120,7 +120,7 @@ if result.status() > 0:
    return result.nrows()
 else:
    return None
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT result_metadata_test($$SELECT 1 AS foo, '11'::text AS bar UNION SELECT 2, \
'22'$$);  SELECT result_metadata_test($$CREATE TEMPORARY TABLE foo1 (a int, b \
text)$$); @@ -129,7 +129,7 @@ CREATE FUNCTION result_nrows_test(cmd text) RETURNS int
 AS $$
 result = plpy.execute(cmd)
 return result.nrows()
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT result_nrows_test($$SELECT 1$$);
 SELECT result_nrows_test($$CREATE TEMPORARY TABLE foo2 (a int, b text)$$);
@@ -140,7 +140,7 @@ CREATE FUNCTION result_len_test(cmd text) RETURNS int
 AS $$
 result = plpy.execute(cmd)
 return len(result)
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT result_len_test($$SELECT 1$$);
 SELECT result_len_test($$CREATE TEMPORARY TABLE foo3 (a int, b text)$$);
@@ -170,7 +170,7 @@ except TypeError:
 else:
     assert False, "TypeError not raised"
 
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT result_subscript_test();
 
@@ -180,7 +180,7 @@ result = plpy.execute("select 1 where false")
 
 plpy.info(result[:])
 
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT result_empty_test();
 
@@ -189,7 +189,7 @@ AS $$
 plan = plpy.prepare(cmd)
 result = plpy.execute(plan)
 return str(result)
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT result_str_test($$SELECT 1 AS foo UNION SELECT 2$$);
 SELECT result_str_test($$CREATE TEMPORARY TABLE foo1 (a int, b text)$$);
@@ -203,13 +203,13 @@ for row in res:
     if row['lname'] == 'doe':
         does += 1
 return does
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 CREATE FUNCTION double_cursor_close() RETURNS int AS $$
 res = plpy.cursor("select fname, lname from users")
 res.close()
 res.close()
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 CREATE FUNCTION cursor_fetch() RETURNS int AS $$
 res = plpy.cursor("select fname, lname from users")
@@ -228,7 +228,7 @@ except StopIteration:
     pass
 else:
     assert False, "StopIteration not raised"
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 CREATE FUNCTION cursor_mix_next_and_fetch() RETURNS int AS $$
 res = plpy.cursor("select fname, lname from users order by fname")
@@ -242,7 +242,7 @@ except AttributeError:
 assert item['fname'] == 'rick'
 
 assert len(res.fetch(2)) == 1
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 CREATE FUNCTION fetch_after_close() RETURNS int AS $$
 res = plpy.cursor("select fname, lname from users")
@@ -253,7 +253,7 @@ except ValueError:
     pass
 else:
     assert False, "ValueError not raised"
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 CREATE FUNCTION next_after_close() RETURNS int AS $$
 res = plpy.cursor("select fname, lname from users")
@@ -267,7 +267,7 @@ except ValueError:
     pass
 else:
     assert False, "ValueError not raised"
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 CREATE FUNCTION cursor_fetch_next_empty() RETURNS int AS $$
 res = plpy.cursor("select fname, lname from users where false")
@@ -281,7 +281,7 @@ except StopIteration:
     pass
 else:
     assert False, "StopIteration not raised"
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 CREATE FUNCTION cursor_plan() RETURNS SETOF text AS $$
 plan = plpy.prepare(
@@ -291,13 +291,13 @@ for row in plpy.cursor(plan, ["w"]):
     yield row['fname']
 for row in plan.cursor(["j"]):
     yield row['fname']
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 CREATE FUNCTION cursor_plan_wrong_args() RETURNS SETOF text AS $$
 plan = plpy.prepare("select fname, lname from users where fname like $1 || '%'",
                     ["text"])
 c = plpy.cursor(plan, ["a", "b"])
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 CREATE TYPE test_composite_type AS (
   a1 int,
@@ -308,7 +308,7 @@ CREATE OR REPLACE FUNCTION plan_composite_args() RETURNS \
test_composite_type AS  plan = plpy.prepare("select $1 as c1", \
["test_composite_type"])  res = plpy.execute(plan, [{"a1": 3, "a2": "label"}])
 return res[0]["c1"]
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT simple_cursor_test();
 SELECT double_cursor_close();
diff --git a/src/pl/plpython/sql/plpython_subtransaction.sql \
b/src/pl/plpython/sql/plpython_subtransaction.sql index cc4b1ae102b..c65c380f40c \
                100644
--- a/src/pl/plpython/sql/plpython_subtransaction.sql
+++ b/src/pl/plpython/sql/plpython_subtransaction.sql
@@ -17,7 +17,7 @@ with plpy.subtransaction():
         plpy.execute("INSERT INTO subtransaction_tbl VALUES ('oops')")
     elif what_error == "Python":
         raise Exception("Python exception")
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT subtransaction_ctx_test();
 SELECT * FROM subtransaction_tbl;
@@ -45,7 +45,7 @@ with plpy.subtransaction():
             raise
         plpy.notice("Swallowed %s(%r)" % (e.__class__.__name__, e.args[0]))
 return "ok"
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT subtransaction_nested_test();
 SELECT * FROM subtransaction_tbl;
@@ -65,7 +65,7 @@ with plpy.subtransaction():
     plpy.execute("INSERT INTO subtransaction_tbl VALUES (2)")
     plpy.execute("SELECT subtransaction_nested_test('t')")
 return "ok"
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT subtransaction_deeply_nested_test();
 SELECT * FROM subtransaction_tbl;
@@ -76,25 +76,25 @@ TRUNCATE subtransaction_tbl;
 CREATE FUNCTION subtransaction_exit_without_enter() RETURNS void
 AS $$
 plpy.subtransaction().__exit__(None, None, None)
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 CREATE FUNCTION subtransaction_enter_without_exit() RETURNS void
 AS $$
 plpy.subtransaction().__enter__()
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 CREATE FUNCTION subtransaction_exit_twice() RETURNS void
 AS $$
 plpy.subtransaction().__enter__()
 plpy.subtransaction().__exit__(None, None, None)
 plpy.subtransaction().__exit__(None, None, None)
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 CREATE FUNCTION subtransaction_enter_twice() RETURNS void
 AS $$
 plpy.subtransaction().__enter__()
 plpy.subtransaction().__enter__()
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 CREATE FUNCTION subtransaction_exit_same_subtransaction_twice() RETURNS void
 AS $$
@@ -102,7 +102,7 @@ s = plpy.subtransaction()
 s.__enter__()
 s.__exit__(None, None, None)
 s.__exit__(None, None, None)
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 CREATE FUNCTION subtransaction_enter_same_subtransaction_twice() RETURNS void
 AS $$
@@ -110,14 +110,14 @@ s = plpy.subtransaction()
 s.__enter__()
 s.__enter__()
 s.__exit__(None, None, None)
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 -- No warnings here, as the subtransaction gets indeed closed
 CREATE FUNCTION subtransaction_enter_subtransaction_in_with() RETURNS void
 AS $$
 with plpy.subtransaction() as s:
     s.__enter__()
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 CREATE FUNCTION subtransaction_exit_subtransaction_in_with() RETURNS void
 AS $$
@@ -126,7 +126,7 @@ try:
         s.__exit__(None, None, None)
 except ValueError as e:
     raise ValueError(e)
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT subtransaction_exit_without_enter();
 SELECT subtransaction_enter_without_exit();
@@ -159,7 +159,7 @@ try:
     plpy.execute(p, ["wrong"])
 except plpy.SPIError:
     plpy.warning("Caught a SPI error")
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT subtransaction_mix_explicit_and_implicit();
 SELECT * FROM subtransaction_tbl;
@@ -172,7 +172,7 @@ AS $$
 s = plpy.subtransaction()
 s.enter()
 s.exit(None, None, None)
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT subtransaction_alternative_names();
 
@@ -186,7 +186,7 @@ with plpy.subtransaction():
          plpy.execute("INSERT INTO subtransaction_tbl VALUES ('a')")
      except plpy.SPIError:
          plpy.notice("caught")
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT try_catch_inside_subtransaction();
 SELECT * FROM subtransaction_tbl;
@@ -202,7 +202,7 @@ with plpy.subtransaction():
          plpy.execute("INSERT INTO subtransaction_tbl VALUES (1)")
      except plpy.SPIError:
          plpy.notice("caught")
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT pk_violation_inside_subtransaction();
 SELECT * FROM subtransaction_tbl;
@@ -217,7 +217,7 @@ with plpy.subtransaction():
     cur.fetch(10)
 fetched = cur.fetch(10);
 return int(fetched[5]["i"])
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 CREATE FUNCTION cursor_aborted_subxact() RETURNS int AS $$
 try:
@@ -229,7 +229,7 @@ except plpy.SPIError:
     fetched = cur.fetch(10)
     return int(fetched[5]["i"])
 return 0 # not reached
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 CREATE FUNCTION cursor_plan_aborted_subxact() RETURNS int AS $$
 try:
@@ -243,7 +243,7 @@ except plpy.SPIError:
     fetched = cur.fetch(5)
     return fetched[2]["i"]
 return 0 # not reached
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 CREATE FUNCTION cursor_close_aborted_subxact() RETURNS boolean AS $$
 try:
@@ -254,7 +254,7 @@ except plpy.SPIError:
     cur.close()
     return True
 return False # not reached
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT cursor_in_subxact();
 SELECT cursor_aborted_subxact();
diff --git a/src/pl/plpython/sql/plpython_test.sql \
b/src/pl/plpython/sql/plpython_test.sql index 5f1be9c94a8..aa22a274155 100644
--- a/src/pl/plpython/sql/plpython_test.sql
+++ b/src/pl/plpython/sql/plpython_test.sql
@@ -1,13 +1,13 @@
 -- first some tests of basic functionality
-CREATE EXTENSION plpython2u;
+CREATE EXTENSION plpython3u;
 
 -- really stupid function just to get the module loaded
-CREATE FUNCTION stupid() RETURNS text AS 'return "zarkon"' LANGUAGE plpythonu;
+CREATE FUNCTION stupid() RETURNS text AS 'return "zarkon"' LANGUAGE plpython3u;
 
 select stupid();
 
 -- check 2/3 versioning
-CREATE FUNCTION stupidn() RETURNS text AS 'return "zarkon"' LANGUAGE plpython2u;
+CREATE FUNCTION stupidn() RETURNS text AS 'return "zarkon"' LANGUAGE plpython3u;
 
 select stupidn();
 
@@ -21,7 +21,7 @@ for key in keys:
     out.append("%s: %s" % (key, u[key]))
 words = a1 + " " + a2 + " => {" + ", ".join(out) + "}"
 return words'
-	LANGUAGE plpythonu;
+	LANGUAGE plpython3u;
 
 select "Argument test #1"(users, fname, lname) from users where lname = 'doe' order \
by 1;  
@@ -32,7 +32,7 @@ $$
 contents = list(filter(lambda x: not x.startswith("__"), dir(plpy)))
 contents.sort()
 return contents
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 select module_contents();
 
@@ -47,6 +47,6 @@ plpy.info('info', 37, [1, 2, 3])
 plpy.notice('notice')
 plpy.warning('warning')
 plpy.error('error')
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT elog_test_basic();
diff --git a/src/pl/plpython/sql/plpython_transaction.sql \
b/src/pl/plpython/sql/plpython_transaction.sql index 33b37e5b7fc..f9062254572 100644
--- a/src/pl/plpython/sql/plpython_transaction.sql
+++ b/src/pl/plpython/sql/plpython_transaction.sql
@@ -2,7 +2,7 @@ CREATE TABLE test1 (a int, b text);
 
 
 CREATE PROCEDURE transaction_test1()
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 AS $$
 for i in range(0, 10):
     plpy.execute("INSERT INTO test1 (a) VALUES (%d)" % i)
@@ -20,7 +20,7 @@ SELECT * FROM test1;
 TRUNCATE test1;
 
 DO
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 $$
 for i in range(0, 10):
     plpy.execute("INSERT INTO test1 (a) VALUES (%d)" % i)
@@ -37,7 +37,7 @@ TRUNCATE test1;
 
 -- not allowed in a function
 CREATE FUNCTION transaction_test2() RETURNS int
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 AS $$
 for i in range(0, 10):
     plpy.execute("INSERT INTO test1 (a) VALUES (%d)" % i)
@@ -55,7 +55,7 @@ SELECT * FROM test1;
 
 -- also not allowed if procedure is called from a function
 CREATE FUNCTION transaction_test3() RETURNS int
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 AS $$
 plpy.execute("CALL transaction_test1()")
 return 1
@@ -68,9 +68,9 @@ SELECT * FROM test1;
 
 -- DO block inside function
 CREATE FUNCTION transaction_test4() RETURNS int
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 AS $$
-plpy.execute("DO LANGUAGE plpythonu $x$ plpy.commit() $x$")
+plpy.execute("DO LANGUAGE plpython3u $x$ plpy.commit() $x$")
 return 1
 $$;
 
@@ -78,7 +78,7 @@ SELECT transaction_test4();
 
 
 -- commit inside subtransaction (prohibited)
-DO LANGUAGE plpythonu $$
+DO LANGUAGE plpython3u $$
 s = plpy.subtransaction()
 s.enter()
 plpy.commit()
@@ -91,7 +91,7 @@ INSERT INTO test2 VALUES (0), (1), (2), (3), (4);
 
 TRUNCATE test1;
 
-DO LANGUAGE plpythonu $$
+DO LANGUAGE plpython3u $$
 for row in plpy.cursor("SELECT * FROM test2 ORDER BY x"):
     plpy.execute("INSERT INTO test1 (a) VALUES (%s)" % row['x'])
     plpy.commit()
@@ -106,7 +106,7 @@ SELECT * FROM pg_cursors;
 -- error in cursor loop with commit
 TRUNCATE test1;
 
-DO LANGUAGE plpythonu $$
+DO LANGUAGE plpython3u $$
 for row in plpy.cursor("SELECT * FROM test2 ORDER BY x"):
     plpy.execute("INSERT INTO test1 (a) VALUES (12/(%s-2))" % row['x'])
     plpy.commit()
@@ -120,7 +120,7 @@ SELECT * FROM pg_cursors;
 -- rollback inside cursor loop
 TRUNCATE test1;
 
-DO LANGUAGE plpythonu $$
+DO LANGUAGE plpython3u $$
 for row in plpy.cursor("SELECT * FROM test2 ORDER BY x"):
     plpy.execute("INSERT INTO test1 (a) VALUES (%s)" % row['x'])
     plpy.rollback()
@@ -134,7 +134,7 @@ SELECT * FROM pg_cursors;
 -- first commit then rollback inside cursor loop
 TRUNCATE test1;
 
-DO LANGUAGE plpythonu $$
+DO LANGUAGE plpython3u $$
 for row in plpy.cursor("SELECT * FROM test2 ORDER BY x"):
     plpy.execute("INSERT INTO test1 (a) VALUES (%s)" % row['x'])
     if row['x'] % 2 == 0:
diff --git a/src/pl/plpython/sql/plpython_trigger.sql \
b/src/pl/plpython/sql/plpython_trigger.sql index 19852dc5851..e5504b9ab1d 100644
--- a/src/pl/plpython/sql/plpython_trigger.sql
+++ b/src/pl/plpython/sql/plpython_trigger.sql
@@ -16,7 +16,7 @@ if TD["new"]["fname"] == "william":
 	TD["new"]["fname"] = TD["args"][0]
 	rv = "MODIFY"
 return rv'
-	LANGUAGE plpythonu;
+	LANGUAGE plpython3u;
 
 
 CREATE FUNCTION users_update() returns trigger
@@ -25,7 +25,7 @@ CREATE FUNCTION users_update() returns trigger
 	if TD["old"]["fname"] != TD["new"]["fname"] and TD["old"]["fname"] == \
TD["args"][0]:  return "SKIP"
 return None'
-	LANGUAGE plpythonu;
+	LANGUAGE plpython3u;
 
 
 CREATE FUNCTION users_delete() RETURNS trigger
@@ -33,7 +33,7 @@ CREATE FUNCTION users_delete() RETURNS trigger
 'if TD["old"]["fname"] == TD["args"][0]:
 	return "SKIP"
 return None'
-	LANGUAGE plpythonu;
+	LANGUAGE plpython3u;
 
 
 CREATE TRIGGER users_insert_trig BEFORE INSERT ON users FOR EACH ROW
@@ -72,7 +72,7 @@ CREATE TABLE trigger_test_generated (
         j int GENERATED ALWAYS AS (i * 2) STORED
 );
 
-CREATE FUNCTION trigger_data() RETURNS trigger LANGUAGE plpythonu AS $$
+CREATE FUNCTION trigger_data() RETURNS trigger LANGUAGE plpython3u AS $$
 
 if 'relid' in TD:
 	TD['relid'] = "bogus:12345"
@@ -157,7 +157,7 @@ INSERT INTO trigger_test VALUES (0, 'zero');
 CREATE FUNCTION stupid1() RETURNS trigger
 AS $$
     return 37
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 CREATE TRIGGER stupid_trigger1
 BEFORE INSERT ON trigger_test
@@ -173,7 +173,7 @@ DROP TRIGGER stupid_trigger1 ON trigger_test;
 CREATE FUNCTION stupid2() RETURNS trigger
 AS $$
     return "MODIFY"
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 CREATE TRIGGER stupid_trigger2
 BEFORE DELETE ON trigger_test
@@ -191,7 +191,7 @@ INSERT INTO trigger_test VALUES (0, 'zero');
 CREATE FUNCTION stupid3() RETURNS trigger
 AS $$
     return "foo"
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 CREATE TRIGGER stupid_trigger3
 BEFORE UPDATE ON trigger_test
@@ -206,8 +206,8 @@ DROP TRIGGER stupid_trigger3 ON trigger_test;
 
 CREATE FUNCTION stupid3u() RETURNS trigger
 AS $$
-    return u"foo"
-$$ LANGUAGE plpythonu;
+    return "foo"
+$$ LANGUAGE plpython3u;
 
 CREATE TRIGGER stupid_trigger3
 BEFORE UPDATE ON trigger_test
@@ -224,7 +224,7 @@ CREATE FUNCTION stupid4() RETURNS trigger
 AS $$
     del TD["new"]
     return "MODIFY";
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 CREATE TRIGGER stupid_trigger4
 BEFORE UPDATE ON trigger_test
@@ -241,7 +241,7 @@ CREATE FUNCTION stupid5() RETURNS trigger
 AS $$
     TD["new"] = ['foo', 'bar']
     return "MODIFY";
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 CREATE TRIGGER stupid_trigger5
 BEFORE UPDATE ON trigger_test
@@ -258,7 +258,7 @@ CREATE FUNCTION stupid6() RETURNS trigger
 AS $$
     TD["new"] = {1: 'foo', 2: 'bar'}
     return "MODIFY";
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 CREATE TRIGGER stupid_trigger6
 BEFORE UPDATE ON trigger_test
@@ -275,7 +275,7 @@ CREATE FUNCTION stupid7() RETURNS trigger
 AS $$
     TD["new"] = {'v': 'foo', 'a': 'bar'}
     return "MODIFY";
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 CREATE TRIGGER stupid_trigger7
 BEFORE UPDATE ON trigger_test
@@ -290,9 +290,9 @@ DROP TRIGGER stupid_trigger7 ON trigger_test;
 
 CREATE FUNCTION stupid7u() RETURNS trigger
 AS $$
-    TD["new"] = {u'v': 'foo', u'a': 'bar'}
+    TD["new"] = {'v': 'foo', 'a': 'bar'}
     return "MODIFY"
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 CREATE TRIGGER stupid_trigger7
 BEFORE UPDATE ON trigger_test
@@ -318,7 +318,7 @@ CREATE FUNCTION test_null() RETURNS trigger
 AS $$
     TD["new"]['v'] = None
     return "MODIFY"
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 CREATE TRIGGER test_null_trigger
 BEFORE UPDATE ON trigger_test
@@ -341,7 +341,7 @@ SET DateStyle = 'ISO';
 CREATE FUNCTION set_modif_time() RETURNS trigger AS $$
     TD['new']['modif_time'] = '2010-10-13 21:57:28.930486'
     return 'MODIFY'
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 CREATE TABLE pb (a TEXT, modif_time TIMESTAMP(0) WITHOUT TIME ZONE);
 
@@ -365,7 +365,7 @@ CREATE FUNCTION composite_trigger_f() RETURNS trigger AS $$
     TD['new']['f1'] = (3, False)
     TD['new']['f2'] = {'k': 7, 'l': 'yes', 'ignored': 10}
     return 'MODIFY'
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 CREATE TRIGGER composite_trigger BEFORE INSERT ON composite_trigger_test
   FOR EACH ROW EXECUTE PROCEDURE composite_trigger_f();
@@ -380,7 +380,7 @@ CREATE TABLE composite_trigger_noop_test (f1 comp1, f2 comp2);
 
 CREATE FUNCTION composite_trigger_noop_f() RETURNS trigger AS $$
     return 'MODIFY'
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 CREATE TRIGGER composite_trigger_noop BEFORE INSERT ON composite_trigger_noop_test
   FOR EACH ROW EXECUTE PROCEDURE composite_trigger_noop_f();
@@ -399,7 +399,7 @@ CREATE TABLE composite_trigger_nested_test(c comp3);
 
 CREATE FUNCTION composite_trigger_nested_f() RETURNS trigger AS $$
     return 'MODIFY'
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 CREATE TRIGGER composite_trigger_nested BEFORE INSERT ON \
composite_trigger_nested_test  FOR EACH ROW EXECUTE PROCEDURE \
composite_trigger_nested_f(); @@ -410,7 +410,7 @@ INSERT INTO \
composite_trigger_nested_test VALUES (ROW(ROW(NULL, 't'), ROW(1, 'f'  SELECT * FROM \
composite_trigger_nested_test;  
 -- check that using a function as a trigger over two tables works correctly
-CREATE FUNCTION trig1234() RETURNS trigger LANGUAGE plpythonu AS $$
+CREATE FUNCTION trig1234() RETURNS trigger LANGUAGE plpython3u AS $$
     TD["new"]["data"] = '1234'
     return 'MODIFY'
 $$;
@@ -432,7 +432,7 @@ SELECT * FROM b;
 CREATE TABLE transition_table_test (id int, name text);
 INSERT INTO transition_table_test VALUES (1, 'a');
 
-CREATE FUNCTION transition_table_test_f() RETURNS trigger LANGUAGE plpythonu AS
+CREATE FUNCTION transition_table_test_f() RETURNS trigger LANGUAGE plpython3u AS
 $$
     rv = plpy.execute("SELECT * FROM old_table")
     assert(rv.nrows() == 1)
@@ -455,7 +455,7 @@ DROP FUNCTION transition_table_test_f();
 -- dealing with generated columns
 
 CREATE FUNCTION generated_test_func1() RETURNS trigger
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 AS $$
 TD['new']['j'] = 5  # not allowed
 return 'MODIFY'
diff --git a/src/pl/plpython/sql/plpython_types.sql \
b/src/pl/plpython/sql/plpython_types.sql index 0d207d9c015..40f4f79d99f 100644
--- a/src/pl/plpython/sql/plpython_types.sql
+++ b/src/pl/plpython/sql/plpython_types.sql
@@ -9,7 +9,7 @@
 CREATE FUNCTION test_type_conversion_bool(x bool) RETURNS bool AS $$
 plpy.info(x, type(x))
 return x
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT * FROM test_type_conversion_bool(true);
 SELECT * FROM test_type_conversion_bool(false);
@@ -35,7 +35,7 @@ elif n == 5:
    ret = [0]
 plpy.info(ret, not not ret)
 return ret
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT * FROM test_type_conversion_bool_other(0);
 SELECT * FROM test_type_conversion_bool_other(1);
@@ -48,7 +48,7 @@ SELECT * FROM test_type_conversion_bool_other(5);
 CREATE FUNCTION test_type_conversion_char(x char) RETURNS char AS $$
 plpy.info(x, type(x))
 return x
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT * FROM test_type_conversion_char('a');
 SELECT * FROM test_type_conversion_char(null);
@@ -57,7 +57,7 @@ SELECT * FROM test_type_conversion_char(null);
 CREATE FUNCTION test_type_conversion_int2(x int2) RETURNS int2 AS $$
 plpy.info(x, type(x))
 return x
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT * FROM test_type_conversion_int2(100::int2);
 SELECT * FROM test_type_conversion_int2(-100::int2);
@@ -67,7 +67,7 @@ SELECT * FROM test_type_conversion_int2(null);
 CREATE FUNCTION test_type_conversion_int4(x int4) RETURNS int4 AS $$
 plpy.info(x, type(x))
 return x
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT * FROM test_type_conversion_int4(100);
 SELECT * FROM test_type_conversion_int4(-100);
@@ -77,7 +77,7 @@ SELECT * FROM test_type_conversion_int4(null);
 CREATE FUNCTION test_type_conversion_int8(x int8) RETURNS int8 AS $$
 plpy.info(x, type(x))
 return x
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT * FROM test_type_conversion_int8(100);
 SELECT * FROM test_type_conversion_int8(-100);
@@ -90,7 +90,7 @@ CREATE FUNCTION test_type_conversion_numeric(x numeric) RETURNS \
numeric AS $$  # between decimal and cdecimal
 plpy.info(str(x), x.__class__.__name__)
 return x
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT * FROM test_type_conversion_numeric(100);
 SELECT * FROM test_type_conversion_numeric(-100);
@@ -105,7 +105,7 @@ SELECT * FROM test_type_conversion_numeric(null);
 CREATE FUNCTION test_type_conversion_float4(x float4) RETURNS float4 AS $$
 plpy.info(x, type(x))
 return x
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT * FROM test_type_conversion_float4(100);
 SELECT * FROM test_type_conversion_float4(-100);
@@ -116,7 +116,7 @@ SELECT * FROM test_type_conversion_float4(null);
 CREATE FUNCTION test_type_conversion_float8(x float8) RETURNS float8 AS $$
 plpy.info(x, type(x))
 return x
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT * FROM test_type_conversion_float8(100);
 SELECT * FROM test_type_conversion_float8(-100);
@@ -128,7 +128,7 @@ SELECT * FROM test_type_conversion_float8(100100100.654321);
 CREATE FUNCTION test_type_conversion_oid(x oid) RETURNS oid AS $$
 plpy.info(x, type(x))
 return x
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT * FROM test_type_conversion_oid(100);
 SELECT * FROM test_type_conversion_oid(2147483649);
@@ -138,7 +138,7 @@ SELECT * FROM test_type_conversion_oid(null);
 CREATE FUNCTION test_type_conversion_text(x text) RETURNS text AS $$
 plpy.info(x, type(x))
 return x
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT * FROM test_type_conversion_text('hello world');
 SELECT * FROM test_type_conversion_text(null);
@@ -147,7 +147,7 @@ SELECT * FROM test_type_conversion_text(null);
 CREATE FUNCTION test_type_conversion_bytea(x bytea) RETURNS bytea AS $$
 plpy.info(x, type(x))
 return x
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT * FROM test_type_conversion_bytea('hello world');
 SELECT * FROM test_type_conversion_bytea(E'null\\000byte');
@@ -157,7 +157,7 @@ SELECT * FROM test_type_conversion_bytea(null);
 CREATE FUNCTION test_type_marshal() RETURNS bytea AS $$
 import marshal
 return marshal.dumps('hello world')
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 CREATE FUNCTION test_type_unmarshal(x bytea) RETURNS text AS $$
 import marshal
@@ -165,7 +165,7 @@ try:
     return marshal.loads(x)
 except ValueError as e:
     return 'FAILED: ' + str(e)
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT test_type_unmarshal(x) FROM test_type_marshal() x;
 
@@ -178,7 +178,7 @@ CREATE DOMAIN booltrue AS bool CHECK (VALUE IS TRUE OR VALUE IS \
NULL);  
 CREATE FUNCTION test_type_conversion_booltrue(x booltrue, y bool) RETURNS booltrue \
AS $$  return y
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT * FROM test_type_conversion_booltrue(true, true);
 SELECT * FROM test_type_conversion_booltrue(false, true);
@@ -190,7 +190,7 @@ CREATE DOMAIN uint2 AS int2 CHECK (VALUE >= 0);
 CREATE FUNCTION test_type_conversion_uint2(x uint2, y int) RETURNS uint2 AS $$
 plpy.info(x, type(x))
 return y
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT * FROM test_type_conversion_uint2(100::uint2, 50);
 SELECT * FROM test_type_conversion_uint2(100::uint2, -50);
@@ -201,7 +201,7 @@ CREATE DOMAIN nnint AS int CHECK (VALUE IS NOT NULL);
 
 CREATE FUNCTION test_type_conversion_nnint(x nnint, y int) RETURNS nnint AS $$
 return y
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT * FROM test_type_conversion_nnint(10, 20);
 SELECT * FROM test_type_conversion_nnint(null, 20);
@@ -213,7 +213,7 @@ CREATE DOMAIN bytea10 AS bytea CHECK (octet_length(VALUE) = 10 \
AND VALUE IS NOT  CREATE FUNCTION test_type_conversion_bytea10(x bytea10, y bytea) \
RETURNS bytea10 AS $$  plpy.info(x, type(x))
 return y
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT * FROM test_type_conversion_bytea10('hello wold', 'hello wold');
 SELECT * FROM test_type_conversion_bytea10('hello world', 'hello wold');
@@ -229,7 +229,7 @@ SELECT * FROM test_type_conversion_bytea10('hello word', null);
 CREATE FUNCTION test_type_conversion_array_int4(x int4[]) RETURNS int4[] AS $$
 plpy.info(x, type(x))
 return x
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT * FROM test_type_conversion_array_int4(ARRAY[0, 100]);
 SELECT * FROM test_type_conversion_array_int4(ARRAY[0,-100,55]);
@@ -243,14 +243,14 @@ SELECT * FROM test_type_conversion_array_int4('[2:4]={1,2,3}');
 CREATE FUNCTION test_type_conversion_array_int8(x int8[]) RETURNS int8[] AS $$
 plpy.info(x, type(x))
 return x
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT * FROM test_type_conversion_array_int8(ARRAY[[[1,2,NULL],[NULL,5,6]],[[NULL,8,9],[10,11,12]]]::int8[]);
  
 CREATE FUNCTION test_type_conversion_array_date(x date[]) RETURNS date[] AS $$
 plpy.info(x, type(x))
 return x
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT * FROM test_type_conversion_array_date(ARRAY[[['2016-09-21','2016-09-22',NULL],[NULL,'2016-10-21','2016-10-22']],
                
             [[NULL,'2016-11-21','2016-10-21'],['2015-09-21','2015-09-22','2014-09-21']]]::date[]);
 @@ -258,7 +258,7 @@ SELECT * FROM \
test_type_conversion_array_date(ARRAY[[['2016-09-21','2016-09-22',  CREATE FUNCTION \
test_type_conversion_array_timestamp(x timestamp[]) RETURNS timestamp[] AS $$  \
plpy.info(x, type(x))  return x
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT * FROM test_type_conversion_array_timestamp(ARRAY[[['2016-09-21 \
                15:34:24.078792-04','2016-10-22 11:34:24.078795-04',NULL],
             [NULL,'2016-10-21 11:34:25.078792-04','2016-10-21 11:34:24.098792-04']],
@@ -270,7 +270,7 @@ CREATE OR REPLACE FUNCTION pyreturnmultidemint4(h int4, i int4, j \
int4, k int4 )  m = [[[[x for x in range(h)] for y in range(i)] for z in range(j)] \
for w in range(k)]  plpy.info(m, type(m))
 return m
-$BODY$ LANGUAGE plpythonu;
+$BODY$ LANGUAGE plpython3u;
 
 select pyreturnmultidemint4(8,5,3,2);
 
@@ -278,7 +278,7 @@ CREATE OR REPLACE FUNCTION pyreturnmultidemint8(h int4, i int4, j \
int4, k int4 )  m = [[[[x for x in range(h)] for y in range(i)] for z in range(j)] \
for w in range(k)]  plpy.info(m, type(m))
 return m
-$BODY$ LANGUAGE plpythonu;
+$BODY$ LANGUAGE plpython3u;
 
 select pyreturnmultidemint8(5,5,3,2);
 
@@ -286,7 +286,7 @@ CREATE OR REPLACE FUNCTION pyreturnmultidemfloat4(h int4, i int4, \
j int4, k int4  m = [[[[x for x in range(h)] for y in range(i)] for z in range(j)] \
for w in range(k)]  plpy.info(m, type(m))
 return m
-$BODY$ LANGUAGE plpythonu;
+$BODY$ LANGUAGE plpython3u;
 
 select pyreturnmultidemfloat4(6,5,3,2);
 
@@ -294,14 +294,14 @@ CREATE OR REPLACE FUNCTION pyreturnmultidemfloat8(h int4, i \
int4, j int4, k int4  m = [[[[x for x in range(h)] for y in range(i)] for z in \
range(j)] for w in range(k)]  plpy.info(m, type(m))
 return m
-$BODY$ LANGUAGE plpythonu;
+$BODY$ LANGUAGE plpython3u;
 
 select pyreturnmultidemfloat8(7,5,3,2);
 
 CREATE FUNCTION test_type_conversion_array_text(x text[]) RETURNS text[] AS $$
 plpy.info(x, type(x))
 return x
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT * FROM test_type_conversion_array_text(ARRAY['foo', 'bar']);
 SELECT * FROM test_type_conversion_array_text(ARRAY[['foo', 'bar'],['foo2', \
'bar2']]); @@ -310,59 +310,59 @@ SELECT * FROM \
test_type_conversion_array_text(ARRAY[['foo', 'bar'],['foo2', 'bar  CREATE FUNCTION \
test_type_conversion_array_bytea(x bytea[]) RETURNS bytea[] AS $$  plpy.info(x, \
type(x))  return x
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT * FROM test_type_conversion_array_bytea(ARRAY[E'\\xdeadbeef'::bytea, NULL]);
 
 
 CREATE FUNCTION test_type_conversion_array_mixed1() RETURNS text[] AS $$
 return [123, 'abc']
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT * FROM test_type_conversion_array_mixed1();
 
 
 CREATE FUNCTION test_type_conversion_array_mixed2() RETURNS int[] AS $$
 return [123, 'abc']
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT * FROM test_type_conversion_array_mixed2();
 
 CREATE FUNCTION test_type_conversion_mdarray_malformed() RETURNS int[] AS $$
 return [[1,2,3],[4,5]]
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT * FROM test_type_conversion_mdarray_malformed();
 
 CREATE FUNCTION test_type_conversion_mdarray_toodeep() RETURNS int[] AS $$
 return [[[[[[[1]]]]]]]
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT * FROM test_type_conversion_mdarray_toodeep();
 
 
 CREATE FUNCTION test_type_conversion_array_record() RETURNS type_record[] AS $$
 return [{'first': 'one', 'second': 42}, {'first': 'two', 'second': 11}]
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT * FROM test_type_conversion_array_record();
 
 
 CREATE FUNCTION test_type_conversion_array_string() RETURNS text[] AS $$
 return 'abc'
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT * FROM test_type_conversion_array_string();
 
 CREATE FUNCTION test_type_conversion_array_tuple() RETURNS text[] AS $$
 return ('abc', 'def')
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT * FROM test_type_conversion_array_tuple();
 
 CREATE FUNCTION test_type_conversion_array_error() RETURNS int[] AS $$
 return 5
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT * FROM test_type_conversion_array_error();
 
@@ -376,14 +376,14 @@ CREATE DOMAIN ordered_pair_domain AS integer[] CHECK \
(array_length(VALUE,1)=2 AN  CREATE FUNCTION test_type_conversion_array_domain(x \
ordered_pair_domain) RETURNS ordered_pair_domain AS $$  plpy.info(x, type(x))
 return x
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT * FROM test_type_conversion_array_domain(ARRAY[0, 100]::ordered_pair_domain);
 SELECT * FROM test_type_conversion_array_domain(NULL::ordered_pair_domain);
 
 CREATE FUNCTION test_type_conversion_array_domain_check_violation() RETURNS \
ordered_pair_domain AS $$  return [2,1]
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 SELECT * FROM test_type_conversion_array_domain_check_violation();
 
 
@@ -394,13 +394,13 @@ SELECT * FROM \
test_type_conversion_array_domain_check_violation();  CREATE FUNCTION \
test_read_uint2_array(x uint2[]) RETURNS uint2 AS $$  plpy.info(x, type(x))
 return x[0]
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 select test_read_uint2_array(array[1::uint2]);
 
 CREATE FUNCTION test_build_uint2_array(x int2) RETURNS uint2[] AS $$
 return [x, x]
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 select test_build_uint2_array(1::int2);
 select test_build_uint2_array(-1::int2);  -- fail
@@ -413,7 +413,7 @@ select test_build_uint2_array(-1::int2);  -- fail
 CREATE FUNCTION test_type_conversion_domain_array(x integer[])
   RETURNS ordered_pair_domain[] AS $$
 return [x, x]
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 select test_type_conversion_domain_array(array[2,4]);
 select test_type_conversion_domain_array(array[4,2]);  -- fail
@@ -422,7 +422,7 @@ CREATE FUNCTION test_type_conversion_domain_array2(x \
ordered_pair_domain)  RETURNS integer AS $$
 plpy.info(x, type(x))
 return x[1]
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 select test_type_conversion_domain_array2(array[2,4]);
 select test_type_conversion_domain_array2(array[4,2]);  -- fail
@@ -431,7 +431,7 @@ CREATE FUNCTION test_type_conversion_array_domain_array(x \
ordered_pair_domain[])  RETURNS ordered_pair_domain AS $$
 plpy.info(x, type(x))
 return x[0]
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 select test_type_conversion_array_domain_array(array[array[2,4]::ordered_pair_domain]);
  
@@ -450,7 +450,7 @@ INSERT INTO employee VALUES ('John', 100, 10), ('Mary', 200, 10);
 
 CREATE OR REPLACE FUNCTION test_composite_table_input(e employee) RETURNS integer AS \
$$  return e['basesalary'] + e['bonus']
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT name, test_composite_table_input(employee.*) FROM employee;
 
@@ -470,7 +470,7 @@ CREATE TYPE named_pair AS (
 
 CREATE OR REPLACE FUNCTION test_composite_type_input(p named_pair) RETURNS integer \
AS $$  return sum(p.values())
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT test_composite_type_input(row(1, 2));
 
@@ -487,7 +487,7 @@ CREATE TYPE nnint_container AS (f1 int, f2 nnint);
 
 CREATE FUNCTION nnint_test(x int, y int) RETURNS nnint_container AS $$
 return {'f1': x, 'f2': y}
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT nnint_test(null, 3);
 SELECT nnint_test(3, null);  -- fail
@@ -501,21 +501,21 @@ CREATE DOMAIN ordered_named_pair AS named_pair_2 \
CHECK((VALUE).i <= (VALUE).j);  
 CREATE FUNCTION read_ordered_named_pair(p ordered_named_pair) RETURNS integer AS $$
 return p['i'] + p['j']
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT read_ordered_named_pair(row(1, 2));
 SELECT read_ordered_named_pair(row(2, 1));  -- fail
 
 CREATE FUNCTION build_ordered_named_pair(i int, j int) RETURNS ordered_named_pair AS \
$$  return {'i': i, 'j': j}
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT build_ordered_named_pair(1,2);
 SELECT build_ordered_named_pair(2,1);  -- fail
 
 CREATE FUNCTION build_ordered_named_pairs(i int, j int) RETURNS ordered_named_pair[] \
AS $$  return [{'i': i, 'j': j}, {'i': i, 'j': j+1}]
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 SELECT build_ordered_named_pairs(1,2);
 SELECT build_ordered_named_pairs(2,1);  -- fail
@@ -526,7 +526,7 @@ SELECT build_ordered_named_pairs(2,1);  -- fail
 --
 
 CREATE OR REPLACE FUNCTION test_prep_bool_input() RETURNS int
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 AS $$
 plan = plpy.prepare("SELECT CASE WHEN $1 THEN 1 ELSE 0 END AS val", ['boolean'])
 rv = plpy.execute(plan, ['fa'], 5) # 'fa' is true in Python
@@ -537,7 +537,7 @@ SELECT test_prep_bool_input(); -- 1
 
 
 CREATE OR REPLACE FUNCTION test_prep_bool_output() RETURNS bool
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 AS $$
 plan = plpy.prepare("SELECT $1 = 1 AS val", ['int'])
 rv = plpy.execute(plan, [0], 5)
@@ -549,7 +549,7 @@ SELECT test_prep_bool_output(); -- false
 
 
 CREATE OR REPLACE FUNCTION test_prep_bytea_input(bb bytea) RETURNS int
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 AS $$
 plan = plpy.prepare("SELECT octet_length($1) AS val", ['bytea'])
 rv = plpy.execute(plan, [bb], 5)
@@ -560,7 +560,7 @@ SELECT test_prep_bytea_input(E'a\\000b'); -- 3 (embedded null \
formerly truncated  
 
 CREATE OR REPLACE FUNCTION test_prep_bytea_output() RETURNS bytea
-LANGUAGE plpythonu
+LANGUAGE plpython3u
 AS $$
 plan = plpy.prepare("SELECT decode('aa00bb', 'hex') AS val")
 rv = plpy.execute(plan, [], 5)
diff --git a/src/pl/plpython/sql/plpython_unicode.sql \
b/src/pl/plpython/sql/plpython_unicode.sql index a11e5eeaa21..14f7b4e0053 100644
--- a/src/pl/plpython/sql/plpython_unicode.sql
+++ b/src/pl/plpython/sql/plpython_unicode.sql
@@ -14,28 +14,28 @@ CREATE TABLE unicode_test (
 );
 
 CREATE FUNCTION unicode_return() RETURNS text AS E'
-return u"\\xA0"
-' LANGUAGE plpythonu;
+return "\\xA0"
+' LANGUAGE plpython3u;
 
 CREATE FUNCTION unicode_trigger() RETURNS trigger AS E'
-TD["new"]["testvalue"] = u"\\xA0"
+TD["new"]["testvalue"] = "\\xA0"
 return "MODIFY"
-' LANGUAGE plpythonu;
+' LANGUAGE plpython3u;
 
 CREATE TRIGGER unicode_test_bi BEFORE INSERT ON unicode_test
   FOR EACH ROW EXECUTE PROCEDURE unicode_trigger();
 
 CREATE FUNCTION unicode_plan1() RETURNS text AS E'
 plan = plpy.prepare("SELECT $1 AS testvalue", ["text"])
-rv = plpy.execute(plan, [u"\\xA0"], 1)
+rv = plpy.execute(plan, ["\\xA0"], 1)
 return rv[0]["testvalue"]
-' LANGUAGE plpythonu;
+' LANGUAGE plpython3u;
 
 CREATE FUNCTION unicode_plan2() RETURNS text AS E'
-plan = plpy.prepare("SELECT $1 || $2 AS testvalue", ["text", u"text"])
+plan = plpy.prepare("SELECT $1 || $2 AS testvalue", ["text", "text"])
 rv = plpy.execute(plan, ["foo", "bar"], 1)
 return rv[0]["testvalue"]
-' LANGUAGE plpythonu;
+' LANGUAGE plpython3u;
 
 
 SELECT unicode_return();
diff --git a/src/pl/plpython/sql/plpython_void.sql \
b/src/pl/plpython/sql/plpython_void.sql index 77d7f59e4c7..5a1a6711fb0 100644
--- a/src/pl/plpython/sql/plpython_void.sql
+++ b/src/pl/plpython/sql/plpython_void.sql
@@ -4,16 +4,16 @@
 
 CREATE FUNCTION test_void_func1() RETURNS void AS $$
 x = 10
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 -- illegal: can't return non-None value in void-returning func
 CREATE FUNCTION test_void_func2() RETURNS void AS $$
 return 10
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 CREATE FUNCTION test_return_none() RETURNS int AS $$
 None
-$$ LANGUAGE plpythonu;
+$$ LANGUAGE plpython3u;
 
 
 -- Tests for functions returning void
-- 
2.23.0.385.gbc12974a89


["v5-0004-meson-prereq-output-and-depencency-tracking-work.patch" (text/x-diff)]

From 604a2932f353f0bd12f7ed45ed7fe7124e8aad7f Mon Sep 17 00:00:00 2001
From: Andres Freund <andres@anarazel.de>
Date: Mon, 8 Mar 2021 13:47:39 -0800
Subject: [PATCH v5 04/16] meson: prereq: output and depencency tracking work.

---
 src/backend/utils/misc/Makefile  |  5 ++++-
 src/backend/utils/misc/guc.c     |  2 +-
 src/bin/initdb/initdb.c          |  5 +++--
 src/bin/psql/Makefile            |  4 ++--
 src/bin/psql/create_help.pl      | 16 ++++++++++++----
 src/tools/msvc/MSBuildProject.pm |  9 +++++++--
 src/tools/msvc/Mkvcbuild.pm      |  3 +++
 src/tools/msvc/Solution.pm       |  2 +-
 src/tools/msvc/pgflex.pl         |  4 ++--
 9 files changed, 35 insertions(+), 15 deletions(-)

diff --git a/src/backend/utils/misc/Makefile b/src/backend/utils/misc/Makefile
index 1d5327cf644..14861fd96b2 100644
--- a/src/backend/utils/misc/Makefile
+++ b/src/backend/utils/misc/Makefile
@@ -37,8 +37,11 @@ endif
 
 include $(top_srcdir)/src/backend/common.mk
 
+guc-file.c.h: guc-file.l
+	flex -o $@ $<
+
 # guc-file is compiled as part of guc
-guc.o: guc-file.c
+guc.o: guc-file.c.h
 
 # Note: guc-file.c is not deleted by 'make clean',
 # since we want to ship it in distribution tarballs.
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index e91d5a3cfda..a0ac8cf0341 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -12572,4 +12572,4 @@ check_default_with_oids(bool *newval, void **extra, GucSource \
source)  return true;
 }
 
-#include "guc-file.c"
+#include "guc-file.c.h"
diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
index 1ed4808d53f..9067a06e58a 100644
--- a/src/bin/initdb/initdb.c
+++ b/src/bin/initdb/initdb.c
@@ -1368,8 +1368,9 @@ bootstrap_template1(void)
 
 	if (strcmp(headerline, *bki_lines) != 0)
 	{
-		pg_log_error("input file \"%s\" does not belong to PostgreSQL %s",
-					 bki_file, PG_VERSION);
+		pg_log_error("input file \"%s\" does not belong to PostgreSQL %s (expect %s, is \
%s)", +					 bki_file, PG_VERSION,
+					 headerline, *bki_lines);
 		fprintf(stderr,
 				_("Check your installation or specify the correct path "
 				  "using the option -L.\n"));
diff --git a/src/bin/psql/Makefile b/src/bin/psql/Makefile
index d00881163c0..3851da1c8ef 100644
--- a/src/bin/psql/Makefile
+++ b/src/bin/psql/Makefile
@@ -56,7 +56,7 @@ sql_help.c: sql_help.h
 	touch $@
 
 sql_help.h: create_help.pl $(wildcard $(REFDOCDIR)/*.sgml)
-	$(PERL) $< $(REFDOCDIR) $*
+	$(PERL) $< $(REFDOCDIR) . $*
 
 psqlscanslash.c: FLEXFLAGS = -Cfe -p -p
 psqlscanslash.c: FLEX_NO_BACKUP=yes
@@ -81,7 +81,7 @@ clean distclean:
 # files removed here are supposed to be in the distribution tarball,
 # so do not clean them in the clean/distclean rules
 maintainer-clean: distclean
-	rm -f sql_help.h sql_help.c psqlscanslash.c
+	rm -f sql_help.h sql_help.c sql_help.dep psqlscanslash.c
 
 check:
 	$(prove_check)
diff --git a/src/bin/psql/create_help.pl b/src/bin/psql/create_help.pl
index 83324239740..40eb6ac2d3f 100644
--- a/src/bin/psql/create_help.pl
+++ b/src/bin/psql/create_help.pl
@@ -23,9 +23,12 @@ use strict;
 use warnings;
 
 my $docdir = $ARGV[0] or die "$0: missing required argument: docdir\n";
-my $hfile = $ARGV[1] . '.h'
+my $outdir = $ARGV[1] or die "$0: missing required argument: outdir\n";
+
+my $hfile = $ARGV[2] . '.h'
   or die "$0: missing required argument: output file\n";
-my $cfile = $ARGV[1] . '.c';
+my $cfile = $ARGV[2] . '.c';
+my $depfile = $ARGV[2] . '.dep';
 
 my $hfilebasename;
 if ($hfile =~ m!.*/([^/]+)$!)
@@ -43,10 +46,12 @@ $define =~ s/\W/_/g;
 
 opendir(DIR, $docdir)
   or die "$0: could not open documentation source dir '$docdir': $!\n";
-open(my $hfile_handle, '>', $hfile)
+open(my $hfile_handle, '>', $outdir . '/' . $hfile)
   or die "$0: could not open output file '$hfile': $!\n";
-open(my $cfile_handle, '>', $cfile)
+open(my $cfile_handle, '>', $outdir . '/' . $cfile)
   or die "$0: could not open output file '$cfile': $!\n";
+open(my $depfile_handle, '>', $outdir . '/' . $depfile)
+  or die "$0: could not open output file '$depfile': $!\n";
 
 print $hfile_handle "/*
  * *** Do not change this file by hand. It is automatically
@@ -98,6 +103,8 @@ foreach my $file (sort readdir DIR)
 	my ($cmdid, @cmdnames, $cmddesc, $cmdsynopsis);
 	$file =~ /\.sgml$/ or next;
 
+	print $depfile_handle "$cfile $hfile: $docdir/$file\n";
+
 	open(my $fh, '<', "$docdir/$file") or next;
 	my $filecontent = join('', <$fh>);
 	close $fh;
@@ -216,4 +223,5 @@ print $hfile_handle "
 
 close $cfile_handle;
 close $hfile_handle;
+close $depfile_handle;
 closedir DIR;
diff --git a/src/tools/msvc/MSBuildProject.pm b/src/tools/msvc/MSBuildProject.pm
index fdd22e89eb2..036e44fcb83 100644
--- a/src/tools/msvc/MSBuildProject.pm
+++ b/src/tools/msvc/MSBuildProject.pm
@@ -211,14 +211,19 @@ EOF
 			}
 			else    #if ($grammarFile =~ /\.l$/)
 			{
+				if ($outputFile eq 'src/backend/utils/misc/guc-file.c')
+				{
+					$outputFile = 'src/backend/utils/misc/guc-file.c.h';
+				}
+
 				print $f <<EOF;
     <CustomBuild Include="$grammarFile">
       <Message Condition="'\$(Configuration)|\$(Platform)'=='Debug|$self->{platform}'">Running \
                flex on $grammarFile</Message>
-      <Command Condition="'\$(Configuration)|\$(Platform)'=='Debug|$self->{platform}'">perl \
"src\\tools\\msvc\\pgflex.pl" "$grammarFile"</Command> +      <Command \
Condition="'\$(Configuration)|\$(Platform)'=='Debug|$self->{platform}'">perl \
                "src\\tools\\msvc\\pgflex.pl" "$grammarFile" "$outputFile"</Command>
       <AdditionalInputs \
Condition="'\$(Configuration)|\$(Platform)'=='Debug|$self->{platform}'">%(AdditionalInputs)</AdditionalInputs>
                
       <Outputs Condition="'\$(Configuration)|\$(Platform)'=='Debug|$self->{platform}'">$outputFile;%(Outputs)</Outputs>
                
       <Message Condition="'\$(Configuration)|\$(Platform)'=='Release|$self->{platform}'">Running \
                flex on $grammarFile</Message>
-      <Command Condition="'\$(Configuration)|\$(Platform)'=='Release|$self->{platform}'">perl \
"src\\tools\\msvc\\pgflex.pl" "$grammarFile"</Command> +      <Command \
Condition="'\$(Configuration)|\$(Platform)'=='Release|$self->{platform}'">perl \
                "src\\tools\\msvc\\pgflex.pl" "$grammarFile" "$outputFile"</Command>
       <AdditionalInputs \
Condition="'\$(Configuration)|\$(Platform)'=='Release|$self->{platform}'">%(AdditionalInputs)</AdditionalInputs>
                
       <Outputs Condition="'\$(Configuration)|\$(Platform)'=='Release|$self->{platform}'">$outputFile;%(Outputs)</Outputs>
  </CustomBuild>
diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm
index 4362bd44fd1..b8e62c6d3f7 100644
--- a/src/tools/msvc/Mkvcbuild.pm
+++ b/src/tools/msvc/Mkvcbuild.pm
@@ -330,6 +330,7 @@ sub mkvcbuild
 	$pgregress_ecpg->AddFile('src/test/regress/pg_regress.c');
 	$pgregress_ecpg->AddIncludeDir('src/port');
 	$pgregress_ecpg->AddIncludeDir('src/test/regress');
+	$pgregress_ecpg->AddDefine('DLSUFFIX=".dll"');
 	$pgregress_ecpg->AddDefine('HOST_TUPLE="i686-pc-win32vc"');
 	$pgregress_ecpg->AddLibrary('ws2_32.lib');
 	$pgregress_ecpg->AddDirResourceFile('src/interfaces/ecpg/test');
@@ -345,6 +346,7 @@ sub mkvcbuild
 	$isolation_tester->AddIncludeDir('src/port');
 	$isolation_tester->AddIncludeDir('src/test/regress');
 	$isolation_tester->AddIncludeDir('src/interfaces/libpq');
+	$isolation_tester->AddDefine('DLSUFFIX=".dll"');
 	$isolation_tester->AddDefine('HOST_TUPLE="i686-pc-win32vc"');
 	$isolation_tester->AddLibrary('ws2_32.lib');
 	$isolation_tester->AddDirResourceFile('src/test/isolation');
@@ -356,6 +358,7 @@ sub mkvcbuild
 	$pgregress_isolation->AddFile('src/test/regress/pg_regress.c');
 	$pgregress_isolation->AddIncludeDir('src/port');
 	$pgregress_isolation->AddIncludeDir('src/test/regress');
+	$pgregress_isolation->AddDefine('DLSUFFIX=".dll"');
 	$pgregress_isolation->AddDefine('HOST_TUPLE="i686-pc-win32vc"');
 	$pgregress_isolation->AddLibrary('ws2_32.lib');
 	$pgregress_isolation->AddDirResourceFile('src/test/isolation');
diff --git a/src/tools/msvc/Solution.pm b/src/tools/msvc/Solution.pm
index 43fd1be0888..dc78d3b65c3 100644
--- a/src/tools/msvc/Solution.pm
+++ b/src/tools/msvc/Solution.pm
@@ -689,7 +689,7 @@ sub GenerateFiles
 	{
 		print "Generating sql_help.h...\n";
 		chdir('src/bin/psql');
-		system("perl create_help.pl ../../../doc/src/sgml/ref sql_help");
+		system("perl create_help.pl ../../../doc/src/sgml/ref . sql_help");
 		chdir('../../..');
 	}
 
diff --git a/src/tools/msvc/pgflex.pl b/src/tools/msvc/pgflex.pl
index 0728b85d4de..19f26ff213f 100644
--- a/src/tools/msvc/pgflex.pl
+++ b/src/tools/msvc/pgflex.pl
@@ -29,6 +29,8 @@ unless ($verparts[0] == 2
 }
 
 my $input = shift;
+my $output = shift;
+
 if ($input !~ /\.l$/)
 {
 	print "Input must be a .l file\n";
@@ -40,8 +42,6 @@ elsif (!-e $input)
 	exit 1;
 }
 
-(my $output = $input) =~ s/\.l$/.c/;
-
 # get flex flags from make file
 my $makefile = dirname($input) . "/Makefile";
 my ($mf, $make);
-- 
2.23.0.385.gbc12974a89


["v5-0005-meson-prereq-move-snowball_create.sql-creation-in.patch" (text/x-diff)]

From 931ff07e713d7869a16a23dcf770f5fd30c18df8 Mon Sep 17 00:00:00 2001
From: Andres Freund <andres@anarazel.de>
Date: Mon, 8 Mar 2021 14:59:22 -0800
Subject: [PATCH v5 05/16] meson: prereq: move snowball_create.sql creation
 into perl file.

FIXME: deduplicate with Install.pm
---
 src/backend/snowball/Makefile           |  27 +-----
 src/backend/snowball/snowball_create.pl | 110 ++++++++++++++++++++++++
 2 files changed, 113 insertions(+), 24 deletions(-)
 create mode 100644 src/backend/snowball/snowball_create.pl

diff --git a/src/backend/snowball/Makefile b/src/backend/snowball/Makefile
index 50b9199910c..259104f8eb3 100644
--- a/src/backend/snowball/Makefile
+++ b/src/backend/snowball/Makefile
@@ -119,29 +119,8 @@ all: all-shared-lib $(SQLSCRIPT)
 
 include $(top_srcdir)/src/Makefile.shlib
 
-$(SQLSCRIPT): Makefile snowball_func.sql.in snowball.sql.in
-	echo '-- Language-specific snowball dictionaries' > $@
-	cat $(srcdir)/snowball_func.sql.in >> $@
-	@set -e; \
-	set $(LANGUAGES) ; \
-	while [ "$$#" -gt 0 ] ; \
-	do \
-		lang=$$1; shift; \
-		nonascdictname=$$lang; \
-		ascdictname=$$1; shift; \
-		if [ -s $(srcdir)/stopwords/$${lang}.stop ] ; then \
-			stop=", StopWords=$${lang}" ; \
-		else \
-			stop=""; \
-		fi; \
-		cat $(srcdir)/snowball.sql.in | \
-			sed -e "s#_LANGNAME_#$$lang#g" | \
-			sed -e "s#_DICTNAME_#$${lang}_stem#g" | \
-			sed -e "s#_CFGNAME_#$$lang#g" | \
-			sed -e "s#_ASCDICTNAME_#$${ascdictname}_stem#g" | \
-			sed -e "s#_NONASCDICTNAME_#$${nonascdictname}_stem#g" | \
-			sed -e "s#_STOPWORDS_#$$stop#g" ; \
-	done >> $@
+$(SQLSCRIPT): snowball_create.pl Makefile snowball_func.sql.in snowball.sql.in
+	$(PERL) $< --input ${srcdir} --output .
 
 install: all installdirs install-lib
 	$(INSTALL_DATA) $(SQLSCRIPT) '$(DESTDIR)$(datadir)'
@@ -171,4 +150,4 @@ uninstall: uninstall-lib
 	done
 
 clean distclean maintainer-clean: clean-lib
-	rm -f $(OBJS) $(SQLSCRIPT)
+	rm -f $(OBJS) $(SQLSCRIPT) snowball_create.dep
diff --git a/src/backend/snowball/snowball_create.pl b/src/backend/snowball/snowball_create.pl
new file mode 100644
index 00000000000..d9d79f3668f
--- /dev/null
+++ b/src/backend/snowball/snowball_create.pl
@@ -0,0 +1,110 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+use Getopt::Long;
+
+my $output_path = '';
+my $makefile_path = '';
+my $input_path = '';
+
+GetOptions(
+	'output:s'   => \$output_path,
+	'input:s'    => \$input_path) || usage();
+
+# Make sure input_path ends in a slash if needed.
+if ($input_path ne '' && substr($input_path, -1) ne '/')
+{
+	$output_path .= '/';
+}
+
+# Make sure output_path ends in a slash if needed.
+if ($output_path ne '' && substr($output_path, -1) ne '/')
+{
+	$output_path .= '/';
+}
+
+GenerateTsearchFiles();
+
+sub usage
+{
+	die <<EOM;
+Usage: snowball_create.pl --input/-i <path> --input <path>
+    --output        Output directory (default '.')
+    --input         Input directory
+
+snowball_create.pl creates snowball.sql from snowball.sql.in
+EOM
+}
+
+sub GenerateTsearchFiles
+{
+	my $target = shift;
+	my $output_file = "$output_path/snowball_create.sql";
+
+	print "Generating tsearch script...";
+	my $F;
+	my $D;
+	my $tmpl = read_file("$input_path/snowball.sql.in");
+	my $mf   = read_file("$input_path/Makefile");
+
+	open($D, '>', "$output_path/snowball_create.dep")
+	  || die "Could not write snowball_create.dep";
+
+	print $D "$output_file: $input_path/Makefile\n";
+	print $D "$output_file: $input_path/snowball.sql.in\n";
+	print $D "$output_file: $input_path/snowball_func.sql.in\n";
+
+	$mf =~ s{\\\r?\n}{}g;
+	$mf =~ /^LANGUAGES\s*=\s*(.*)$/m
+	  || die "Could not find LANGUAGES line in snowball Makefile\n";
+	my @pieces = split /\s+/, $1;
+	open($F, '>', $output_file)
+	  || die "Could not write snowball_create.sql";
+
+	print $F "-- Language-specific snowball dictionaries\n";
+
+	print $F read_file("$input_path/snowball_func.sql.in");
+
+	while ($#pieces > 0)
+	{
+		my $lang    = shift @pieces || last;
+		my $asclang = shift @pieces || last;
+		my $txt     = $tmpl;
+		my $stop    = '';
+		my $stopword_path = "$input_path/stopwords/$lang.stop";
+
+		if (-s "$stopword_path")
+		{
+			$stop = ", StopWords=$lang";
+
+			print $D "$output_file: $stopword_path\n";
+		}
+
+		$txt =~ s#_LANGNAME_#${lang}#gs;
+		$txt =~ s#_DICTNAME_#${lang}_stem#gs;
+		$txt =~ s#_CFGNAME_#${lang}#gs;
+		$txt =~ s#_ASCDICTNAME_#${asclang}_stem#gs;
+		$txt =~ s#_NONASCDICTNAME_#${lang}_stem#gs;
+		$txt =~ s#_STOPWORDS_#$stop#gs;
+		print $F $txt;
+		print ".";
+	}
+	close($F);
+	close($D);
+	print "\n";
+	return;
+}
+
+
+sub read_file
+{
+	my $filename = shift;
+	my $F;
+	local $/ = undef;
+	open($F, '<', $filename) || die "Could not open file $filename\n";
+	my $txt = <$F>;
+	close($F);
+
+	return $txt;
+}
-- 
2.23.0.385.gbc12974a89


["v5-0006-meson-prereq-add-output-path-arg-in-generate-lwlo.patch" (text/x-diff)]

From 5e712fa7763cb28a4ab8f763cab6d3746c24f857 Mon Sep 17 00:00:00 2001
From: Andres Freund <andres@anarazel.de>
Date: Wed, 10 Mar 2021 01:43:07 -0800
Subject: [PATCH v5 06/16] meson: prereq: add output path arg in
 generate-lwlocknames.pl

---
 src/backend/storage/lmgr/generate-lwlocknames.pl | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/src/backend/storage/lmgr/generate-lwlocknames.pl \
b/src/backend/storage/lmgr/generate-lwlocknames.pl index 8a44946594d..315156b29f1 \
                100644
--- a/src/backend/storage/lmgr/generate-lwlocknames.pl
+++ b/src/backend/storage/lmgr/generate-lwlocknames.pl
@@ -5,15 +5,21 @@
 
 use strict;
 use warnings;
+use Getopt::Long;
+
+my $output_path = '.';
 
 my $lastlockidx = -1;
 my $continue    = "\n";
 
+GetOptions(
+	'output:s'       => \$output_path);
+
 open my $lwlocknames, '<', $ARGV[0] or die;
 
 # Include PID in suffix in case parallel make runs this multiple times.
-my $htmp = "lwlocknames.h.tmp$$";
-my $ctmp = "lwlocknames.c.tmp$$";
+my $htmp = "$output_path/lwlocknames.h.tmp$$";
+my $ctmp = "$output_path/lwlocknames.c.tmp$$";
 open my $h, '>', $htmp or die "Could not open $htmp: $!";
 open my $c, '>', $ctmp or die "Could not open $ctmp: $!";
 
@@ -65,7 +71,7 @@ printf $h "#define NUM_INDIVIDUAL_LWLOCKS		%s\n", $lastlockidx + 1;
 close $h;
 close $c;
 
-rename($htmp, 'lwlocknames.h') || die "rename: $htmp: $!";
-rename($ctmp, 'lwlocknames.c') || die "rename: $ctmp: $!";
+rename($htmp, "$output_path/lwlocknames.h") || die "rename: $htmp to \
$output_path/lwlocknames.h: $!"; +rename($ctmp, "$output_path/lwlocknames.c") || die \
"rename: $ctmp: $!";  
 close $lwlocknames;
-- 
2.23.0.385.gbc12974a89


["v5-0007-meson-prereq-add-src-tools-gen_versioning_script..patch" (text/x-diff)]

From 0fd47642701e4941c6a2bb3eca29b9509b999399 Mon Sep 17 00:00:00 2001
From: Andres Freund <andres@anarazel.de>
Date: Wed, 10 Mar 2021 15:11:13 -0800
Subject: [PATCH v5 07/16] meson: prereq: add
 src/tools/gen_versioning_script.pl.

Currently the logic is all in src/Makefile.shlib. This adds a sketch
of a generation script that can be used from meson.
---
 src/tools/gen_versioning_script.pl | 58 ++++++++++++++++++++++++++++++
 1 file changed, 58 insertions(+)
 create mode 100644 src/tools/gen_versioning_script.pl

diff --git a/src/tools/gen_versioning_script.pl b/src/tools/gen_versioning_script.pl
new file mode 100644
index 00000000000..862b5e14aad
--- /dev/null
+++ b/src/tools/gen_versioning_script.pl
@@ -0,0 +1,58 @@
+use strict;
+use warnings;
+
+my $format = $ARGV[0] or die "$0: missing required argument: format\n";
+my $input = $ARGV[1] or die "$0: missing required argument: input\n";
+my $output = $ARGV[2] or die "$0: missing required argument: output\n";
+
+#FIXME: handle format argument, so we can reuse the one script for several platforms
+if (not ($format eq 'gnu' or $format eq 'darwin'))
+{
+	die "$0: $format is not yet handled (only gnu is)\n";
+}
+
+open(my $input_handle, '<', $input)
+  or die "$0: could not open input file '$input': $!\n";
+
+open(my $output_handle, '>', $output)
+  or die "$0: could not open output file '$output': $!\n";
+
+
+if ($format eq 'gnu')
+{
+	print $output_handle "{
+  global:
+";
+}
+
+while (<$input_handle>)
+{
+	if (/^#/)
+	{
+		# don't do anything with a comment
+	}
+	elsif (/^([^\s]+)\s+([^\s]+)/)
+	{
+		if ($format eq 'gnu')
+		{
+			print $output_handle "    $1;\n";
+		}
+		elsif ($format eq 'darwin')
+		{
+			print $output_handle "    _$1\n";
+		}
+	}
+	else
+	{
+		die "$0: unexpected line $_\n";
+	}
+}
+
+if ($format eq 'gnu')
+{
+	print $output_handle "  local: *;
+};
+";
+}
+
+exit(0);
-- 
2.23.0.385.gbc12974a89


["v5-0008-meson-prereq-generate-errcodes.pl-accept-output-f.patch" (text/x-diff)]

From 8e6ee0e31e25238ff8ea50938a20f1775001c88d Mon Sep 17 00:00:00 2001
From: Andres Freund <andres@anarazel.de>
Date: Mon, 27 Sep 2021 00:14:09 -0700
Subject: [PATCH v5 08/16] meson: prereq: generate-errcodes.pl: accept output
 file

---
 src/backend/utils/Makefile             |  2 +-
 src/backend/utils/generate-errcodes.pl | 13 ++++++++-----
 src/tools/msvc/Solution.pm             |  2 +-
 3 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/src/backend/utils/Makefile b/src/backend/utils/Makefile
index ef8df254826..469caf0d704 100644
--- a/src/backend/utils/Makefile
+++ b/src/backend/utils/Makefile
@@ -52,7 +52,7 @@ fmgr-stamp: Gen_fmgrtab.pl $(catalogdir)/Catalog.pm \
$(top_srcdir)/src/include/ca  touch $@
 
 errcodes.h: $(top_srcdir)/src/backend/utils/errcodes.txt generate-errcodes.pl
-	$(PERL) $(srcdir)/generate-errcodes.pl $< > $@
+	$(PERL) $(srcdir)/generate-errcodes.pl $< $@
 
 ifneq ($(enable_dtrace), yes)
 probes.h: Gen_dummy_probes.sed
diff --git a/src/backend/utils/generate-errcodes.pl \
b/src/backend/utils/generate-errcodes.pl index c5cdd388138..57ec2a5ca21 100644
--- a/src/backend/utils/generate-errcodes.pl
+++ b/src/backend/utils/generate-errcodes.pl
@@ -6,11 +6,13 @@
 use strict;
 use warnings;
 
-print
+open my $errcodes, '<', $ARGV[0] or die;
+open my $out, '>', $ARGV[1] or die;
+
+print $out
   "/* autogenerated from src/backend/utils/errcodes.txt, do not edit */\n";
-print "/* there is deliberately not an #ifndef ERRCODES_H here */\n";
+print $out "/* there is deliberately not an #ifndef ERRCODES_H here */\n";
 
-open my $errcodes, '<', $ARGV[0] or die;
 
 while (<$errcodes>)
 {
@@ -25,7 +27,7 @@ while (<$errcodes>)
 	{
 		my $header = $1;
 		$header =~ s/^\s+//;
-		print "\n/* $header */\n";
+		print $out "\n/* $header */\n";
 		next;
 	}
 
@@ -40,7 +42,8 @@ while (<$errcodes>)
 	# And quote them
 	$sqlstate =~ s/([^,])/'$1'/g;
 
-	print "#define $errcode_macro MAKE_SQLSTATE($sqlstate)\n";
+	print $out "#define $errcode_macro MAKE_SQLSTATE($sqlstate)\n";
 }
 
 close $errcodes;
+close $out;
diff --git a/src/tools/msvc/Solution.pm b/src/tools/msvc/Solution.pm
index dc78d3b65c3..40cd6020421 100644
--- a/src/tools/msvc/Solution.pm
+++ b/src/tools/msvc/Solution.pm
@@ -659,7 +659,7 @@ sub GenerateFiles
 	{
 		print "Generating errcodes.h...\n";
 		system(
-			'perl src/backend/utils/generate-errcodes.pl src/backend/utils/errcodes.txt > \
src/backend/utils/errcodes.h' +			'perl src/backend/utils/generate-errcodes.pl \
src/backend/utils/errcodes.txt src/backend/utils/errcodes.h'  );
 		copyFile('src/backend/utils/errcodes.h',
 			'src/include/utils/errcodes.h');
-- 
2.23.0.385.gbc12974a89


["v5-0009-meson-prereq-remove-unhelpful-chattiness-in-snowb.patch" (text/x-diff)]

From b47c7af10cea83c78e8f3c75bf083c42d6adfd55 Mon Sep 17 00:00:00 2001
From: Andres Freund <andres@anarazel.de>
Date: Mon, 27 Sep 2021 15:41:24 -0700
Subject: [PATCH v5 09/16] meson: prereq: remove unhelpful chattiness in
 snowball_create.pl.

---
 src/backend/snowball/snowball_create.pl | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/src/backend/snowball/snowball_create.pl b/src/backend/snowball/snowball_create.pl
index d9d79f3668f..285cf4f5d90 100644
--- a/src/backend/snowball/snowball_create.pl
+++ b/src/backend/snowball/snowball_create.pl
@@ -42,7 +42,6 @@ sub GenerateTsearchFiles
 	my $target = shift;
 	my $output_file = "$output_path/snowball_create.sql";
 
-	print "Generating tsearch script...";
 	my $F;
 	my $D;
 	my $tmpl = read_file("$input_path/snowball.sql.in");
@@ -88,11 +87,9 @@ sub GenerateTsearchFiles
 		$txt =~ s#_NONASCDICTNAME_#${lang}_stem#gs;
 		$txt =~ s#_STOPWORDS_#$stop#gs;
 		print $F $txt;
-		print ".";
 	}
 	close($F);
 	close($D);
-	print "\n";
 	return;
 }
 
-- 
2.23.0.385.gbc12974a89


["v5-0010-meson-prereq-Can-we-get-away-with-not-export-all-.patch" (text/x-diff)]

From bfcc214e472040810bb59110280e734b2c5f1f2b Mon Sep 17 00:00:00 2001
From: Andres Freund <andres@anarazel.de>
Date: Wed, 29 Sep 2021 00:29:10 -0700
Subject: [PATCH v5 10/16] meson: prereq: Can we get away with not
 export-all'ing libraries?

---
 configure                                  | 49 ++++++++++++++++++++++
 configure.ac                               | 10 +++++
 contrib/hstore/hstore.h                    | 16 +++----
 contrib/ltree/ltree.h                      | 40 +++++++++---------
 src/Makefile.global.in                     |  1 +
 src/Makefile.shlib                         | 12 ++++++
 src/include/c.h                            | 15 +++++--
 src/include/fmgr.h                         |  6 ++-
 src/include/jit/jit.h                      |  2 +-
 src/include/pg_config.h.in                 |  3 ++
 src/include/replication/output_plugin.h    |  2 +
 src/pl/plpython/plpy_elog.h                |  8 ++--
 src/pl/plpython/plpy_typeio.h              | 18 ++++----
 src/pl/plpython/plpy_util.h                |  8 ++--
 src/test/modules/test_shm_mq/test_shm_mq.h |  2 +-
 src/test/modules/worker_spi/worker_spi.c   |  2 +-
 src/tools/msvc/Solution.pm                 |  1 +
 17 files changed, 142 insertions(+), 53 deletions(-)

diff --git a/configure b/configure
index 1b5fd12a432..fd15801b34c 100755
--- a/configure
+++ b/configure
@@ -735,6 +735,7 @@ CPP
 CFLAGS_SL
 BITCODE_CXXFLAGS
 BITCODE_CFLAGS
+CFLAGS_SL_MOD
 CFLAGS_VECTORIZE
 CFLAGS_UNROLL_LOOPS
 PERMIT_DECLARATION_AFTER_STATEMENT
@@ -6421,6 +6422,54 @@ fi
   if test -n "$NOT_THE_CFLAGS"; then
     CFLAGS="$CFLAGS -Wno-stringop-truncation"
   fi
+
+  # If the compiler knows how to hide symbols, use that. But only for shared \
libraries, +  # for postgres itself that'd be too verbose for now.
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${CC} supports \
-fvisibility=hidden, for CFLAGS_SL_MOD" >&5 +$as_echo_n "checking whether ${CC} \
supports -fvisibility=hidden, for CFLAGS_SL_MOD... " >&6; } +if \
${pgac_cv_prog_CC_cflags__fvisibility_hidden+:} false; then : +  $as_echo_n "(cached) \
" >&6 +else
+  pgac_save_CFLAGS=$CFLAGS
+pgac_save_CC=$CC
+CC=${CC}
+CFLAGS="${CFLAGS_SL_MOD} -fvisibility=hidden"
+ac_save_c_werror_flag=$ac_c_werror_flag
+ac_c_werror_flag=yes
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  pgac_cv_prog_CC_cflags__fvisibility_hidden=yes
+else
+  pgac_cv_prog_CC_cflags__fvisibility_hidden=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_c_werror_flag=$ac_save_c_werror_flag
+CFLAGS="$pgac_save_CFLAGS"
+CC="$pgac_save_CC"
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: \
$pgac_cv_prog_CC_cflags__fvisibility_hidden" >&5 +$as_echo \
"$pgac_cv_prog_CC_cflags__fvisibility_hidden" >&6; } +if test \
x"$pgac_cv_prog_CC_cflags__fvisibility_hidden" = x"yes"; then +  \
CFLAGS_SL_MOD="${CFLAGS_SL_MOD} -fvisibility=hidden" +fi
+
+
+  if test "$pgac_cv_prog_CC_cflags__fvisibility_hidden" = yes; then
+
+$as_echo "#define HAVE_VISIBILITY_ATTRIBUTE 1" >>confdefs.h
+
+  fi
+
 elif test "$ICC" = yes; then
   # Intel's compiler has a bug/misoptimization in checking for
   # division by NAN (NaN == 0), -mp1 fixes it, so add it to the CFLAGS.
diff --git a/configure.ac b/configure.ac
index 44ee3ebe2f1..973f83db52c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -541,6 +541,15 @@ if test "$GCC" = yes -a "$ICC" = no; then
   if test -n "$NOT_THE_CFLAGS"; then
     CFLAGS="$CFLAGS -Wno-stringop-truncation"
   fi
+
+  # If the compiler knows how to hide symbols, use that. But only for shared \
libraries, +  # for postgres itself that'd be too verbose for now.
+  PGAC_PROG_CC_VAR_OPT(CFLAGS_SL_MOD, [-fvisibility=hidden])
+  if test "$pgac_cv_prog_CC_cflags__fvisibility_hidden" = yes; then
+     AC_DEFINE(HAVE_VISIBILITY_ATTRIBUTE, 1,
+               [Define to 1 if your compiler knows the visibility("hidden") \
attribute.]) +  fi
+
 elif test "$ICC" = yes; then
   # Intel's compiler has a bug/misoptimization in checking for
   # division by NAN (NaN == 0), -mp1 fixes it, so add it to the CFLAGS.
@@ -564,6 +573,7 @@ fi
 
 AC_SUBST(CFLAGS_UNROLL_LOOPS)
 AC_SUBST(CFLAGS_VECTORIZE)
+AC_SUBST(CFLAGS_SL_MOD)
 
 # Determine flags used to emit bitcode for JIT inlining. Need to test
 # for behaviour changing compiler flags, to keep compatibility with
diff --git a/contrib/hstore/hstore.h b/contrib/hstore/hstore.h
index bf4a565ed9b..625134c9f69 100644
--- a/contrib/hstore/hstore.h
+++ b/contrib/hstore/hstore.h
@@ -147,7 +147,7 @@ typedef struct
 	} while (0)
 
 /* DatumGetHStoreP includes support for reading old-format hstore values */
-extern HStore *hstoreUpgrade(Datum orig);
+extern PGDLLEXPORT HStore *hstoreUpgrade(Datum orig);
 
 #define DatumGetHStoreP(d) hstoreUpgrade(d)
 
@@ -168,14 +168,14 @@ typedef struct
 	bool		needfree;		/* need to pfree the value? */
 } Pairs;
 
-extern int	hstoreUniquePairs(Pairs *a, int32 l, int32 *buflen);
-extern HStore *hstorePairs(Pairs *pairs, int32 pcount, int32 buflen);
+extern PGDLLEXPORT int	hstoreUniquePairs(Pairs *a, int32 l, int32 *buflen);
+extern PGDLLEXPORT HStore *hstorePairs(Pairs *pairs, int32 pcount, int32 buflen);
 
-extern size_t hstoreCheckKeyLen(size_t len);
-extern size_t hstoreCheckValLen(size_t len);
+extern PGDLLEXPORT size_t hstoreCheckKeyLen(size_t len);
+extern PGDLLEXPORT size_t hstoreCheckValLen(size_t len);
 
-extern int	hstoreFindKey(HStore *hs, int *lowbound, char *key, int keylen);
-extern Pairs *hstoreArrayToPairs(ArrayType *a, int *npairs);
+extern PGDLLEXPORT int	hstoreFindKey(HStore *hs, int *lowbound, char *key, int \
keylen); +extern PGDLLEXPORT Pairs *hstoreArrayToPairs(ArrayType *a, int *npairs);
 
 #define HStoreContainsStrategyNumber	7
 #define HStoreExistsStrategyNumber		9
@@ -194,7 +194,7 @@ extern Pairs *hstoreArrayToPairs(ArrayType *a, int *npairs);
 #if HSTORE_POLLUTE_NAMESPACE
 #define HSTORE_POLLUTE(newname_,oldname_) \
 	PG_FUNCTION_INFO_V1(oldname_);		  \
-	Datum newname_(PG_FUNCTION_ARGS);	  \
+	extern PGDLLEXPORT Datum newname_(PG_FUNCTION_ARGS);	  \
 	Datum oldname_(PG_FUNCTION_ARGS) { return newname_(fcinfo); } \
 	extern int no_such_variable
 #else
diff --git a/contrib/ltree/ltree.h b/contrib/ltree/ltree.h
index 5b4be5e680a..d8bcdedbdbe 100644
--- a/contrib/ltree/ltree.h
+++ b/contrib/ltree/ltree.h
@@ -176,30 +176,30 @@ typedef struct
 
 
 /* use in array iterator */
-Datum		ltree_isparent(PG_FUNCTION_ARGS);
-Datum		ltree_risparent(PG_FUNCTION_ARGS);
-Datum		ltq_regex(PG_FUNCTION_ARGS);
-Datum		ltq_rregex(PG_FUNCTION_ARGS);
-Datum		lt_q_regex(PG_FUNCTION_ARGS);
-Datum		lt_q_rregex(PG_FUNCTION_ARGS);
-Datum		ltxtq_exec(PG_FUNCTION_ARGS);
-Datum		ltxtq_rexec(PG_FUNCTION_ARGS);
-Datum		_ltq_regex(PG_FUNCTION_ARGS);
-Datum		_ltq_rregex(PG_FUNCTION_ARGS);
-Datum		_lt_q_regex(PG_FUNCTION_ARGS);
-Datum		_lt_q_rregex(PG_FUNCTION_ARGS);
-Datum		_ltxtq_exec(PG_FUNCTION_ARGS);
-Datum		_ltxtq_rexec(PG_FUNCTION_ARGS);
-Datum		_ltree_isparent(PG_FUNCTION_ARGS);
-Datum		_ltree_risparent(PG_FUNCTION_ARGS);
+PGDLLEXPORT Datum		ltree_isparent(PG_FUNCTION_ARGS);
+PGDLLEXPORT Datum		ltree_risparent(PG_FUNCTION_ARGS);
+PGDLLEXPORT Datum		ltq_regex(PG_FUNCTION_ARGS);
+PGDLLEXPORT Datum		ltq_rregex(PG_FUNCTION_ARGS);
+PGDLLEXPORT Datum		lt_q_regex(PG_FUNCTION_ARGS);
+PGDLLEXPORT Datum		lt_q_rregex(PG_FUNCTION_ARGS);
+PGDLLEXPORT Datum		ltxtq_exec(PG_FUNCTION_ARGS);
+PGDLLEXPORT Datum		ltxtq_rexec(PG_FUNCTION_ARGS);
+PGDLLEXPORT Datum		_ltq_regex(PG_FUNCTION_ARGS);
+PGDLLEXPORT Datum		_ltq_rregex(PG_FUNCTION_ARGS);
+PGDLLEXPORT Datum		_lt_q_regex(PG_FUNCTION_ARGS);
+PGDLLEXPORT Datum		_lt_q_rregex(PG_FUNCTION_ARGS);
+PGDLLEXPORT Datum		_ltxtq_exec(PG_FUNCTION_ARGS);
+PGDLLEXPORT Datum		_ltxtq_rexec(PG_FUNCTION_ARGS);
+PGDLLEXPORT Datum		_ltree_isparent(PG_FUNCTION_ARGS);
+PGDLLEXPORT Datum		_ltree_risparent(PG_FUNCTION_ARGS);
 
 /* Concatenation functions */
-Datum		ltree_addltree(PG_FUNCTION_ARGS);
-Datum		ltree_addtext(PG_FUNCTION_ARGS);
-Datum		ltree_textadd(PG_FUNCTION_ARGS);
+PGDLLEXPORT Datum		ltree_addltree(PG_FUNCTION_ARGS);
+PGDLLEXPORT Datum		ltree_addtext(PG_FUNCTION_ARGS);
+PGDLLEXPORT Datum		ltree_textadd(PG_FUNCTION_ARGS);
 
 /* Util function */
-Datum		ltree_in(PG_FUNCTION_ARGS);
+PGDLLEXPORT Datum		ltree_in(PG_FUNCTION_ARGS);
 
 bool		ltree_execute(ITEM *curitem, void *checkval,
 						  bool calcnot, bool (*chkcond) (void *checkval, ITEM *val));
diff --git a/src/Makefile.global.in b/src/Makefile.global.in
index 533c12fef95..c7c701dcb93 100644
--- a/src/Makefile.global.in
+++ b/src/Makefile.global.in
@@ -259,6 +259,7 @@ SUN_STUDIO_CC = @SUN_STUDIO_CC@
 CXX = @CXX@
 CFLAGS = @CFLAGS@
 CFLAGS_SL = @CFLAGS_SL@
+CFLAGS_SL_MOD = @CFLAGS_SL_MOD@
 CFLAGS_UNROLL_LOOPS = @CFLAGS_UNROLL_LOOPS@
 CFLAGS_VECTORIZE = @CFLAGS_VECTORIZE@
 CFLAGS_SSE42 = @CFLAGS_SSE42@
diff --git a/src/Makefile.shlib b/src/Makefile.shlib
index 551023c6fb0..d36782aa942 100644
--- a/src/Makefile.shlib
+++ b/src/Makefile.shlib
@@ -253,6 +253,18 @@ ifeq ($(PORTNAME), win32)
 endif
 
 
+# If the shared library doesn't have an export file, mark all symbols not
+# explicitly exported using PGDLLEXPORT as hidden. We can't pass these flags
+# when building a library with explicit exports, as the symbols would be
+# hidden before the linker script / exported symbol list takes effect.
+#
+# XXX: This probably isn't the best location, but not clear instead?
+ifeq ($(SHLIB_EXPORTS),)
+  LDFLAGS += $(CFLAGS_SL_MOD)
+  override CFLAGS += $(CFLAGS_SL_MOD)
+  override CXXFLAGS += $(CFLAGS_SL_MOD)
+endif
+
 
 ##
 ## BUILD
diff --git a/src/include/c.h b/src/include/c.h
index c8ede082739..9b539a2657b 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -1312,11 +1312,18 @@ extern long long strtoll(const char *str, char **endptr, int \
base);  extern unsigned long long strtoull(const char *str, char **endptr, int base);
 #endif
 
-/* no special DLL markers on most ports */
-#ifndef PGDLLIMPORT
-#define PGDLLIMPORT
+/*
+ * If the platform knows __attribute__((visibility("*"))), i.e. gcc like
+ * compilers, we use that.
+ */
+#if !defined(PGDLLIMPORT) && defined(HAVE_VISIBILITY_ATTRIBUTE)
+#define PGDLLIMPORT __attribute__((visibility("default")))
+#define PGDLLEXPORT __attribute__((visibility("default")))
 #endif
-#ifndef PGDLLEXPORT
+
+/* No special DLL markers on the remaining ports. */
+#if !defined(PGDLLIMPORT)
+#define PGDLLIMPORT
 #define PGDLLEXPORT
 #endif
 
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index ab7b85c86e1..679443cca19 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -413,7 +413,7 @@ typedef const Pg_finfo_record *(*PGFInfoFunction) (void);
  *	info function, since authors shouldn't need to be explicitly aware of it.
  */
 #define PG_FUNCTION_INFO_V1(funcname) \
-extern Datum funcname(PG_FUNCTION_ARGS); \
+extern PGDLLEXPORT Datum funcname(PG_FUNCTION_ARGS); \
 extern PGDLLEXPORT const Pg_finfo_record * CppConcat(pg_finfo_,funcname)(void); \
 const Pg_finfo_record * \
 CppConcat(pg_finfo_,funcname) (void) \
@@ -424,6 +424,10 @@ CppConcat(pg_finfo_,funcname) (void) \
 extern int no_such_variable
 
 
+extern PGDLLEXPORT void _PG_init(void);
+extern PGDLLEXPORT void _PG_fini(void);
+
+
 /*-------------------------------------------------------------------------
  *		Support for verifying backend compatibility of loaded modules
  *
diff --git a/src/include/jit/jit.h b/src/include/jit/jit.h
index b634df30b98..74617ad1b64 100644
--- a/src/include/jit/jit.h
+++ b/src/include/jit/jit.h
@@ -63,7 +63,7 @@ typedef struct JitContext
 
 typedef struct JitProviderCallbacks JitProviderCallbacks;
 
-extern void _PG_jit_provider_init(JitProviderCallbacks *cb);
+extern PGDLLEXPORT void _PG_jit_provider_init(JitProviderCallbacks *cb);
 typedef void (*JitProviderInit) (JitProviderCallbacks *cb);
 typedef void (*JitProviderResetAfterErrorCB) (void);
 typedef void (*JitProviderReleaseContextCB) (JitContext *context);
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index 15ffdd895aa..e3ab1c7752f 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -710,6 +710,9 @@
 /* Define to 1 if you have the <uuid/uuid.h> header file. */
 #undef HAVE_UUID_UUID_H
 
+/* Define to 1 if your compiler knows the visibility("hidden") attribute. */
+#undef HAVE_VISIBILITY_ATTRIBUTE
+
 /* Define to 1 if you have the `wcstombs_l' function. */
 #undef HAVE_WCSTOMBS_L
 
diff --git a/src/include/replication/output_plugin.h \
b/src/include/replication/output_plugin.h index 810495ed0e4..a087f14dadd 100644
--- a/src/include/replication/output_plugin.h
+++ b/src/include/replication/output_plugin.h
@@ -35,6 +35,8 @@ typedef struct OutputPluginOptions
  */
 typedef void (*LogicalOutputPluginInit) (struct OutputPluginCallbacks *cb);
 
+extern PGDLLEXPORT void _PG_output_plugin_init(struct OutputPluginCallbacks *cb);
+
 /*
  * Callback that gets called in a user-defined plugin. ctx->private_data can
  * be set to some private data.
diff --git a/src/pl/plpython/plpy_elog.h b/src/pl/plpython/plpy_elog.h
index e02ef4ffe9f..aeade82ce10 100644
--- a/src/pl/plpython/plpy_elog.h
+++ b/src/pl/plpython/plpy_elog.h
@@ -34,13 +34,13 @@ extern PyObject *PLy_exc_spi_error;
 	} while(0)
 #endif							/* HAVE__BUILTIN_CONSTANT_P */
 
-extern void PLy_elog_impl(int elevel, const char *fmt,...) pg_attribute_printf(2, \
3); +extern PGDLLEXPORT void PLy_elog_impl(int elevel, const char *fmt,...) \
pg_attribute_printf(2, 3);  
-extern void PLy_exception_set(PyObject *exc, const char *fmt,...) \
pg_attribute_printf(2, 3); +extern PGDLLEXPORT void PLy_exception_set(PyObject *exc, \
const char *fmt,...) pg_attribute_printf(2, 3);  
-extern void PLy_exception_set_plural(PyObject *exc, const char *fmt_singular, const \
char *fmt_plural, +extern PGDLLEXPORT void PLy_exception_set_plural(PyObject *exc, \
                const char *fmt_singular, const char *fmt_plural,
 									 unsigned long n,...) pg_attribute_printf(2, 5) pg_attribute_printf(3, 5);
 
-extern void PLy_exception_set_with_details(PyObject *excclass, ErrorData *edata);
+extern PGDLLEXPORT void PLy_exception_set_with_details(PyObject *excclass, ErrorData \
*edata);  
 #endif							/* PLPY_ELOG_H */
diff --git a/src/pl/plpython/plpy_typeio.h b/src/pl/plpython/plpy_typeio.h
index d11e6ae1b89..87e3b2c464e 100644
--- a/src/pl/plpython/plpy_typeio.h
+++ b/src/pl/plpython/plpy_typeio.h
@@ -147,29 +147,29 @@ struct PLyObToDatum
 };
 
 
-extern PyObject *PLy_input_convert(PLyDatumToOb *arg, Datum val);
-extern Datum PLy_output_convert(PLyObToDatum *arg, PyObject *val,
+extern PGDLLEXPORT PyObject *PLy_input_convert(PLyDatumToOb *arg, Datum val);
+extern PGDLLEXPORT Datum PLy_output_convert(PLyObToDatum *arg, PyObject *val,
 								bool *isnull);
 
-extern PyObject *PLy_input_from_tuple(PLyDatumToOb *arg, HeapTuple tuple,
+extern PGDLLEXPORT PyObject *PLy_input_from_tuple(PLyDatumToOb *arg, HeapTuple \
tuple,  TupleDesc desc, bool include_generated);
 
-extern void PLy_input_setup_func(PLyDatumToOb *arg, MemoryContext arg_mcxt,
+extern PGDLLEXPORT void PLy_input_setup_func(PLyDatumToOb *arg, MemoryContext \
arg_mcxt,  Oid typeOid, int32 typmod,
 								 struct PLyProcedure *proc);
-extern void PLy_output_setup_func(PLyObToDatum *arg, MemoryContext arg_mcxt,
+extern PGDLLEXPORT void PLy_output_setup_func(PLyObToDatum *arg, MemoryContext \
arg_mcxt,  Oid typeOid, int32 typmod,
 								  struct PLyProcedure *proc);
 
-extern void PLy_input_setup_tuple(PLyDatumToOb *arg, TupleDesc desc,
+extern PGDLLEXPORT void PLy_input_setup_tuple(PLyDatumToOb *arg, TupleDesc desc,
 								  struct PLyProcedure *proc);
-extern void PLy_output_setup_tuple(PLyObToDatum *arg, TupleDesc desc,
+extern PGDLLEXPORT void PLy_output_setup_tuple(PLyObToDatum *arg, TupleDesc desc,
 								   struct PLyProcedure *proc);
 
-extern void PLy_output_setup_record(PLyObToDatum *arg, TupleDesc desc,
+extern PGDLLEXPORT void PLy_output_setup_record(PLyObToDatum *arg, TupleDesc desc,
 									struct PLyProcedure *proc);
 
 /* conversion from Python objects to C strings --- exported for transforms */
-extern char *PLyObject_AsString(PyObject *plrv);
+extern PGDLLEXPORT char *PLyObject_AsString(PyObject *plrv);
 
 #endif							/* PLPY_TYPEIO_H */
diff --git a/src/pl/plpython/plpy_util.h b/src/pl/plpython/plpy_util.h
index 7c6577925ea..6f491b0f95b 100644
--- a/src/pl/plpython/plpy_util.h
+++ b/src/pl/plpython/plpy_util.h
@@ -8,10 +8,10 @@
 
 #include "plpython.h"
 
-extern PyObject *PLyUnicode_Bytes(PyObject *unicode);
-extern char *PLyUnicode_AsString(PyObject *unicode);
+extern PGDLLEXPORT PyObject *PLyUnicode_Bytes(PyObject *unicode);
+extern PGDLLEXPORT char *PLyUnicode_AsString(PyObject *unicode);
 
-extern PyObject *PLyUnicode_FromString(const char *s);
-extern PyObject *PLyUnicode_FromStringAndSize(const char *s, Py_ssize_t size);
+extern PGDLLEXPORT PyObject *PLyUnicode_FromString(const char *s);
+extern PGDLLEXPORT PyObject *PLyUnicode_FromStringAndSize(const char *s, Py_ssize_t \
size);  
 #endif							/* PLPY_UTIL_H */
diff --git a/src/test/modules/test_shm_mq/test_shm_mq.h \
b/src/test/modules/test_shm_mq/test_shm_mq.h index a6661218347..a7a36714a48 100644
--- a/src/test/modules/test_shm_mq/test_shm_mq.h
+++ b/src/test/modules/test_shm_mq/test_shm_mq.h
@@ -40,6 +40,6 @@ extern void test_shm_mq_setup(int64 queue_size, int32 nworkers,
 							  shm_mq_handle **input);
 
 /* Main entrypoint for a worker. */
-extern void test_shm_mq_main(Datum) pg_attribute_noreturn();
+extern PGDLLEXPORT void test_shm_mq_main(Datum) pg_attribute_noreturn();
 
 #endif
diff --git a/src/test/modules/worker_spi/worker_spi.c \
b/src/test/modules/worker_spi/worker_spi.c index 0b6246676b6..e267bc3cffa 100644
--- a/src/test/modules/worker_spi/worker_spi.c
+++ b/src/test/modules/worker_spi/worker_spi.c
@@ -47,7 +47,7 @@ PG_MODULE_MAGIC;
 PG_FUNCTION_INFO_V1(worker_spi_launch);
 
 void		_PG_init(void);
-void		worker_spi_main(Datum) pg_attribute_noreturn();
+PGDLLEXPORT void worker_spi_main(Datum) pg_attribute_noreturn();
 
 /* GUC variables */
 static int	worker_spi_naptime = 10;
diff --git a/src/tools/msvc/Solution.pm b/src/tools/msvc/Solution.pm
index 40cd6020421..85b877b80b2 100644
--- a/src/tools/msvc/Solution.pm
+++ b/src/tools/msvc/Solution.pm
@@ -432,6 +432,7 @@ sub GenerateFiles
 		HAVE_WINLDAP_H                           => undef,
 		HAVE_WCSTOMBS_L                          => 1,
 		HAVE_WCTYPE_H                            => 1,
+		HAVE_VISIBILITY_ATTRIBUTE                => undef,
 		HAVE_WRITEV                              => undef,
 		HAVE_X509_GET_SIGNATURE_NID              => 1,
 		HAVE_X86_64_POPCNTQ                      => undef,
-- 
2.23.0.385.gbc12974a89


["v5-0011-meson-prereq-Handle-DLSUFFIX-in-msvc-builds-simil.patch" (text/x-diff)]

From c1571bfd8f3eb811ad0f8916d189f94d3f98ec80 Mon Sep 17 00:00:00 2001
From: Andres Freund <andres@anarazel.de>
Date: Thu, 30 Sep 2021 10:20:24 -0700
Subject: [PATCH v5 11/16] meson: prereq: Handle DLSUFFIX in msvc builds
 similar to other build envs.

---
 src/include/port/win32_port.h | 3 ---
 src/tools/msvc/Mkvcbuild.pm   | 3 +++
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/include/port/win32_port.h b/src/include/port/win32_port.h
index c1c4831595a..72b2d2b5a01 100644
--- a/src/include/port/win32_port.h
+++ b/src/include/port/win32_port.h
@@ -529,9 +529,6 @@ typedef unsigned short mode_t;
 #define W_OK 2
 #define R_OK 4
 
-/* Pulled from Makefile.port in MinGW */
-#define DLSUFFIX ".dll"
-
 #endif							/* _MSC_VER */
 
 #if (defined(_MSC_VER) && (_MSC_VER < 1900)) || \
diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm
index b8e62c6d3f7..47b5c43357a 100644
--- a/src/tools/msvc/Mkvcbuild.pm
+++ b/src/tools/msvc/Mkvcbuild.pm
@@ -195,6 +195,7 @@ sub mkvcbuild
 		'syncrep_gram.y');
 	$postgres->AddFiles('src/backend/utils/adt', 'jsonpath_scan.l',
 		'jsonpath_gram.y');
+	$postgres->AddDefine('DLSUFFIX=".dll"');
 	$postgres->AddDefine('BUILDING_DLL');
 	$postgres->AddLibrary('secur32.lib');
 	$postgres->AddLibrary('ws2_32.lib');
@@ -298,6 +299,7 @@ sub mkvcbuild
 	my $libecpg = $solution->AddProject('libecpg', 'dll', 'interfaces',
 		'src/interfaces/ecpg/ecpglib');
 	$libecpg->AddDefine('FRONTEND');
+	$libecpg->AddDefine('DLSUFFIX=".dll"');
 	$libecpg->AddIncludeDir('src/interfaces/ecpg/include');
 	$libecpg->AddIncludeDir('src/interfaces/libpq');
 	$libecpg->AddIncludeDir('src/port');
@@ -845,6 +847,7 @@ sub mkvcbuild
 	$pgregress->AddFile('src/test/regress/pg_regress.c');
 	$pgregress->AddFile('src/test/regress/pg_regress_main.c');
 	$pgregress->AddIncludeDir('src/port');
+	$pgregress->AddDefine('DLSUFFIX=".dll"');
 	$pgregress->AddDefine('HOST_TUPLE="i686-pc-win32vc"');
 	$pgregress->AddLibrary('ws2_32.lib');
 	$pgregress->AddDirResourceFile('src/test/regress');
-- 
2.23.0.385.gbc12974a89


["v5-0012-prereq-make-unicode-targets-work-in-vpath-builds.patch" (text/x-diff)]

From 386bab39b951a71336c57611f8ff10977995ec9f Mon Sep 17 00:00:00 2001
From: Andres Freund <andres@anarazel.de>
Date: Wed, 27 Oct 2021 09:59:33 -0700
Subject: [PATCH v5 12/16] prereq: make unicode targets work in vpath builds.

---
 contrib/unaccent/Makefile                         |  4 ++--
 src/common/unicode/Makefile                       |  8 ++++----
 src/common/unicode/generate-unicode_norm_table.pl | 11 ++++++-----
 3 files changed, 12 insertions(+), 11 deletions(-)

diff --git a/contrib/unaccent/Makefile b/contrib/unaccent/Makefile
index b8307d1601e..d6c466e07ad 100644
--- a/contrib/unaccent/Makefile
+++ b/contrib/unaccent/Makefile
@@ -27,12 +27,12 @@ include $(top_builddir)/src/Makefile.global
 include $(top_srcdir)/contrib/contrib-global.mk
 endif
 
-update-unicode: unaccent.rules
+update-unicode: $(srcdir)/unaccent.rules
 
 # Allow running this even without --with-python
 PYTHON ?= python
 
-unaccent.rules: generate_unaccent_rules.py ../../src/common/unicode/UnicodeData.txt \
Latin-ASCII.xml +$(srcdir)/unaccent.rules: generate_unaccent_rules.py \
../../src/common/unicode/UnicodeData.txt Latin-ASCII.xml  $(PYTHON) $< \
--unicode-data-file $(word 2,$^) --latin-ascii-file $(word 3,$^) >$@  
 # Only download it once; dependencies must match src/common/unicode/
diff --git a/src/common/unicode/Makefile b/src/common/unicode/Makefile
index a3683dd86b9..40a5f7bc0fe 100644
--- a/src/common/unicode/Makefile
+++ b/src/common/unicode/Makefile
@@ -12,14 +12,14 @@ subdir = src/common/unicode
 top_builddir = ../../..
 include $(top_builddir)/src/Makefile.global
 
-override CPPFLAGS := -DFRONTEND $(CPPFLAGS)
+override CPPFLAGS := -DFRONTEND -I$(abs_top_builddir)/src/common/unicode $(CPPFLAGS)
 LIBS += $(PTHREAD_LIBS)
 
 # By default, do nothing.
 all:
 
 update-unicode: unicode_norm_table.h unicode_combining_table.h \
                unicode_east_asian_fw_table.h unicode_normprops_table.h \
                unicode_norm_hashfunc.h
-	mv $^ ../../../src/include/common/
+	mv $^ $(top_srcdir)/src/include/common/
 	$(MAKE) normalization-check
 
 # These files are part of the Unicode Character Database. Download
@@ -33,7 +33,7 @@ UnicodeData.txt EastAsianWidth.txt DerivedNormalizationProps.txt \
CompositionExcl  unicode_norm_hashfunc.h: unicode_norm_table.h
 
 unicode_norm_table.h: generate-unicode_norm_table.pl UnicodeData.txt \
                CompositionExclusions.txt
-	$(PERL) generate-unicode_norm_table.pl
+	$(PERL) $< $(CURDIR)
 
 unicode_combining_table.h: generate-unicode_combining_table.pl UnicodeData.txt
 	$(PERL) $^ >$@
@@ -58,7 +58,7 @@ submake-common:
 	$(MAKE) -C .. all
 
 norm_test_table.h: generate-norm_test_table.pl NormalizationTest.txt
-	perl generate-norm_test_table.pl NormalizationTest.txt $@
+	perl $^ $@
 
 .PHONY: normalization-check
 
diff --git a/src/common/unicode/generate-unicode_norm_table.pl \
b/src/common/unicode/generate-unicode_norm_table.pl index 114ab30d3f1..4d2c603ff27 \
                100644
--- a/src/common/unicode/generate-unicode_norm_table.pl
+++ b/src/common/unicode/generate-unicode_norm_table.pl
@@ -15,15 +15,16 @@ use FindBin;
 use lib "$FindBin::RealBin/../../tools/";
 use PerfectHash;
 
-my $output_table_file = "unicode_norm_table.h";
-my $output_func_file  = "unicode_norm_hashfunc.h";
+my $directory = $ARGV[0];
+my $output_table_file = "$directory/unicode_norm_table.h";
+my $output_func_file  = "$directory/unicode_norm_hashfunc.h";
 
 my $FH;
 
 # Read list of codes that should be excluded from re-composition.
 my @composition_exclusion_codes = ();
-open($FH, '<', "CompositionExclusions.txt")
-  or die "Could not open CompositionExclusions.txt: $!.";
+open($FH, '<', "$directory/CompositionExclusions.txt")
+  or die "Could not open $directory/CompositionExclusions.txt: $!.";
 while (my $line = <$FH>)
 {
 	if ($line =~ /^([[:xdigit:]]+)/)
@@ -38,7 +39,7 @@ close $FH;
 # and character decomposition mapping
 my @characters     = ();
 my %character_hash = ();
-open($FH, '<', "UnicodeData.txt")
+open($FH, '<', "$directory/UnicodeData.txt")
   or die "Could not open UnicodeData.txt: $!.";
 while (my $line = <$FH>)
 {
-- 
2.23.0.385.gbc12974a89


["v5-0013-wip-don-t-run-ldap-tests-on-windows.patch" (text/x-diff)]

From 418ac644ce3c51c73c50166f126392610c5c2d0e Mon Sep 17 00:00:00 2001
From: Andres Freund <andres@anarazel.de>
Date: Sun, 10 Oct 2021 13:49:12 -0700
Subject: [PATCH v5 13/16] wip: don't run ldap tests on windows.

---
 src/test/ldap/t/001_auth.pl | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/src/test/ldap/t/001_auth.pl b/src/test/ldap/t/001_auth.pl
index 5a9a0098327..8850fc1cb1b 100644
--- a/src/test/ldap/t/001_auth.pl
+++ b/src/test/ldap/t/001_auth.pl
@@ -6,6 +6,13 @@ use warnings;
 use PostgreSQL::Test::Utils;
 use PostgreSQL::Test::Cluster;
 use Test::More;
+use Config;
+
+if ($Config{osname} eq 'MSWin32')
+{
+	plan skip_all => 'ldap tests ';
+	exit;
+}
 
 if ($ENV{with_ldap} eq 'yes')
 {
-- 
2.23.0.385.gbc12974a89


["v5-0014-wip-split-TESTDIR-into-two.patch" (text/x-diff)]

From fb2933a9bba05d79ce920f9f161a732c615c4897 Mon Sep 17 00:00:00 2001
From: Andres Freund <andres@anarazel.de>
Date: Wed, 27 Oct 2021 10:10:37 -0700
Subject: [PATCH v5 14/16] wip: split TESTDIR into two.

---
 src/Makefile.global.in                 |  9 ++++---
 src/bin/psql/t/010_tab_completion.pl   | 34 +++++++++++++-------------
 src/test/perl/PostgreSQL/Test/Utils.pm |  2 +-
 src/tools/msvc/vcregress.pl            |  2 ++
 4 files changed, 26 insertions(+), 21 deletions(-)

diff --git a/src/Makefile.global.in b/src/Makefile.global.in
index c7c701dcb93..014029c9a9c 100644
--- a/src/Makefile.global.in
+++ b/src/Makefile.global.in
@@ -450,7 +450,8 @@ define prove_installcheck
 rm -rf '$(CURDIR)'/tmp_check
 $(MKDIR_P) '$(CURDIR)'/tmp_check
 cd $(srcdir) && \
-   TESTDIR='$(CURDIR)' PATH="$(bindir):$(CURDIR):$$PATH" \
+   TESTOUTDIR='$(CURDIR)/tmp_check' TESTDIR='$(CURDIR)' \
+   PATH="$(bindir):$(CURDIR):$$PATH" \
    PGPORT='6$(DEF_PGPORT)' top_builddir='$(CURDIR)/$(top_builddir)' \
    PG_REGRESS='$(CURDIR)/$(top_builddir)/src/test/regress/pg_regress' \
    $(PROVE) $(PG_PROVE_FLAGS) $(PROVE_FLAGS) $(if $(PROVE_TESTS),$(PROVE_TESTS),t/*.pl)
@@ -460,8 +461,9 @@ define prove_installcheck
 rm -rf '$(CURDIR)'/tmp_check
 $(MKDIR_P) '$(CURDIR)'/tmp_check
 cd $(srcdir) && \
-   TESTDIR='$(CURDIR)' PATH="$(bindir):$(CURDIR):$$PATH" \
-   PGPORT='6$(DEF_PGPORT)' top_builddir='$(top_builddir)' \
+   TESTOUTDIR='$(CURDIR)/tmp_check' TESTDIR='$(CURDIR)' \
+   PATH="$(bindir):$(CURDIR):$$PATH" PGPORT='6$(DEF_PGPORT)' \
+   top_builddir='$(top_builddir)' \
    PG_REGRESS='$(top_builddir)/src/test/regress/pg_regress' \
    $(PROVE) $(PG_PROVE_FLAGS) $(PROVE_FLAGS) $(if $(PROVE_TESTS),$(PROVE_TESTS),t/*.pl)
 endef
@@ -471,6 +473,7 @@ define prove_check
 rm -rf '$(CURDIR)'/tmp_check
 $(MKDIR_P) '$(CURDIR)'/tmp_check
 cd $(srcdir) && \
+   TESTOUTDIR='$(CURDIR)/tmp_check' \
    TESTDIR='$(CURDIR)' $(with_temp_install) PGPORT='6$(DEF_PGPORT)' \
    PG_REGRESS='$(CURDIR)/$(top_builddir)/src/test/regress/pg_regress' \
    $(PROVE) $(PG_PROVE_FLAGS) $(PROVE_FLAGS) $(if $(PROVE_TESTS),$(PROVE_TESTS),t/*.pl)
diff --git a/src/bin/psql/t/010_tab_completion.pl b/src/bin/psql/t/010_tab_completion.pl
index 55b318517ea..33f6a6c12fd 100644
--- a/src/bin/psql/t/010_tab_completion.pl
+++ b/src/bin/psql/t/010_tab_completion.pl
@@ -67,23 +67,23 @@ delete $ENV{LS_COLORS};
 # to run in the build directory so that we can use relative paths to
 # access the tmp_check subdirectory; otherwise the output from filename
 # completion tests is too variable.
-if ($ENV{TESTDIR})
+if ($ENV{TESTOUTDIR})
 {
-	chdir $ENV{TESTDIR} or die "could not chdir to \"$ENV{TESTDIR}\": $!";
+	chdir "$ENV{TESTOUTDIR}" or die "could not chdir to \"$ENV{TESTOUTDIR}\": $!";
 }
 
 # Create some junk files for filename completion testing.
 my $FH;
-open $FH, ">", "tmp_check/somefile"
-  or die("could not create file \"tmp_check/somefile\": $!");
+open $FH, ">", "somefile"
+  or die("could not create file \"somefile\": $!");
 print $FH "some stuff\n";
 close $FH;
-open $FH, ">", "tmp_check/afile123"
-  or die("could not create file \"tmp_check/afile123\": $!");
+open $FH, ">", "afile123"
+  or die("could not create file \"afile123\": $!");
 print $FH "more stuff\n";
 close $FH;
-open $FH, ">", "tmp_check/afile456"
-  or die("could not create file \"tmp_check/afile456\": $!");
+open $FH, ">", "afile456"
+  or die("could not create file \"afile456\": $!");
 print $FH "other stuff\n";
 close $FH;
 
@@ -184,16 +184,16 @@ clear_query();
 
 # check filename completion
 check_completion(
-	"\\lo_import tmp_check/some\t",
-	qr|tmp_check/somefile |,
+	"\\lo_import some\t",
+	qr|somefile |,
 	"filename completion with one possibility");
 
 clear_query();
 
 # note: readline might print a bell before the completion
 check_completion(
-	"\\lo_import tmp_check/af\t",
-	qr|tmp_check/af\a?ile|,
+	"\\lo_import af\t",
+	qr|af\a?ile|,
 	"filename completion with multiple possibilities");
 
 clear_query();
@@ -202,15 +202,15 @@ clear_query();
 # note: broken versions of libedit want to backslash the closing quote;
 # not much we can do about that
 check_completion(
-	"COPY foo FROM tmp_check/some\t",
-	qr|'tmp_check/somefile\\?' |,
+	"COPY foo FROM some\t",
+	qr|'somefile\\?' |,
 	"quoted filename completion with one possibility");
 
 clear_line();
 
 check_completion(
-	"COPY foo FROM tmp_check/af\t",
-	qr|'tmp_check/afile|,
+	"COPY foo FROM af\t",
+	qr|'afile|,
 	"quoted filename completion with multiple possibilities");
 
 # some versions of readline/libedit require two tabs here, some only need one
@@ -218,7 +218,7 @@ check_completion(
 # the quotes might appear, too
 check_completion(
 	"\t\t",
-	qr|afile123'? +'?(tmp_check/)?afile456|,
+	qr|afile123'? +'?afile456|,
 	"offer multiple file choices");
 
 clear_line();
diff --git a/src/test/perl/PostgreSQL/Test/Utils.pm b/src/test/perl/PostgreSQL/Test/Utils.pm
index f29d43f1f32..7878bc4ef48 100644
--- a/src/test/perl/PostgreSQL/Test/Utils.pm
+++ b/src/test/perl/PostgreSQL/Test/Utils.pm
@@ -187,7 +187,7 @@ INIT
 	# Determine output directories, and create them.  The base path is the
 	# TESTDIR environment variable, which is normally set by the invoking
 	# Makefile.
-	$tmp_check = $ENV{TESTDIR} ? "$ENV{TESTDIR}/tmp_check" : "tmp_check";
+	$tmp_check = $ENV{TESTOUTDIR} ? "$ENV{TESTOUTDIR}" : "tmp_check";
 	$log_path = "$tmp_check/log";
 
 	mkdir $tmp_check;
diff --git a/src/tools/msvc/vcregress.pl b/src/tools/msvc/vcregress.pl
index fc826da3ff2..cf099033ebd 100644
--- a/src/tools/msvc/vcregress.pl
+++ b/src/tools/msvc/vcregress.pl
@@ -252,6 +252,8 @@ sub tap_check
 	# add the module build dir as the second element in the PATH
 	$ENV{PATH} =~ s!;!;$topdir/$Config/$module;!;
 
+	$ENV{TESTOUTDIR} = "$dir/tmp_check";
+
 	rmtree('tmp_check');
 	system(@args);
 	my $status = $? >> 8;
-- 
2.23.0.385.gbc12974a89


["v5-0015-meson-Add-draft-of-a-meson-based-buildsystem.patch" (text/x-diff)]

From 8152a34caee2ce97112a860c01b1c6a0b4cef73f Mon Sep 17 00:00:00 2001
From: Andres Freund <andres@anarazel.de>
Date: Fri, 10 Sep 2021 09:51:51 -0700
Subject: [PATCH v5 15/16] meson: Add draft of a meson based buildsystem.

Author: Andres Freund
Author: Thomas Munro
Author: John Naylor <john.naylor@enterprisedb.com>
---
 configure                                     |    6 +
 configure.ac                                  |    6 +
 contrib/adminpack/meson.build                 |   20 +
 contrib/amcheck/meson.build                   |   37 +
 contrib/auth_delay/meson.build                |    4 +
 contrib/auto_explain/meson.build              |   13 +
 contrib/bloom/meson.build                     |   38 +
 contrib/bool_plperl/meson.build               |   37 +
 contrib/btree_gin/meson.build                 |   51 +
 contrib/btree_gist/meson.build                |   79 +
 contrib/citext/meson.build                    |   29 +
 contrib/cube/meson.build                      |   42 +
 contrib/dblink/meson.build                    |   29 +
 contrib/dict_int/meson.build                  |   19 +
 contrib/dict_xsyn/meson.build                 |   26 +
 contrib/earthdistance/meson.build             |   20 +
 contrib/file_fdw/meson.build                  |   19 +
 contrib/fuzzystrmatch/meson.build             |   23 +
 contrib/hstore/meson.build                    |   36 +
 contrib/hstore_plperl/meson.build             |   38 +
 contrib/hstore_plpython/meson.build           |   34 +
 contrib/intagg/meson.build                    |    6 +
 contrib/intarray/meson.build                  |   34 +
 contrib/isn/meson.build                       |   25 +
 contrib/jsonb_plperl/meson.build              |   37 +
 contrib/jsonb_plpython/meson.build            |   33 +
 contrib/lo/meson.build                        |   24 +
 contrib/ltree/meson.build                     |   36 +
 contrib/ltree_plpython/meson.build            |   34 +
 contrib/meson.build                           |   63 +
 contrib/oid2name/meson.build                  |   14 +
 contrib/old_snapshot/meson.build              |   14 +
 contrib/pageinspect/meson.build               |   45 +
 contrib/passwordcheck/meson.build             |   27 +
 contrib/pg_buffercache/meson.build            |   16 +
 contrib/pg_freespacemap/meson.build           |   15 +
 contrib/pg_prewarm/meson.build                |   16 +
 contrib/pg_stat_statements/meson.build        |   31 +
 contrib/pg_surgery/meson.build                |   23 +
 contrib/pg_trgm/meson.build                   |   33 +
 contrib/pg_visibility/meson.build             |   25 +
 contrib/pgcrypto/meson.build                  |  117 +
 contrib/pgrowlocks/meson.build                |   15 +
 contrib/pgstattuple/meson.build               |   30 +
 contrib/postgres_fdw/meson.build              |   31 +
 contrib/seg/meson.build                       |   40 +
 contrib/sepgsql/meson.build                   |   34 +
 contrib/spi/meson.build                       |   43 +
 contrib/sslinfo/meson.build                   |   21 +
 contrib/tablefunc/meson.build                 |   23 +
 contrib/tcn/meson.build                       |   13 +
 contrib/test_decoding/meson.build             |   69 +
 contrib/tsm_system_rows/meson.build           |   22 +
 contrib/tsm_system_time/meson.build           |   22 +
 contrib/unaccent/meson.build                  |   30 +
 contrib/uuid-ossp/meson.build                 |   31 +
 contrib/vacuumlo/meson.build                  |   14 +
 contrib/xml2/meson.build                      |   30 +
 conversion_helpers.txt                        |    6 +
 doc/src/sgml/meson.build                      |  241 ++
 doc/src/sgml/resolv.xsl                       |    7 +
 doc/src/sgml/version.sgml.in                  |    2 +
 meson.build                                   | 2130 +++++++++++++++++
 meson_options.txt                             |   90 +
 src/backend/access/brin/meson.build           |   12 +
 src/backend/access/common/meson.build         |   18 +
 src/backend/access/gin/meson.build            |   17 +
 src/backend/access/gist/meson.build           |   13 +
 src/backend/access/hash/meson.build           |   12 +
 src/backend/access/heap/meson.build           |   11 +
 src/backend/access/index/meson.build          |    6 +
 src/backend/access/meson.build                |   13 +
 src/backend/access/nbtree/meson.build         |   13 +
 src/backend/access/rmgrdesc/meson.build       |   26 +
 src/backend/access/spgist/meson.build         |   13 +
 src/backend/access/table/meson.build          |    6 +
 src/backend/access/tablesample/meson.build    |    5 +
 src/backend/access/transam/meson.build        |   28 +
 src/backend/bootstrap/meson.build             |   12 +
 src/backend/catalog/meson.build               |   41 +
 src/backend/commands/meson.build              |   50 +
 src/backend/executor/meson.build              |   67 +
 src/backend/foreign/meson.build               |    3 +
 src/backend/jit/llvm/meson.build              |   41 +
 src/backend/jit/meson.build                   |    3 +
 src/backend/lib/meson.build                   |   12 +
 src/backend/libpq/meson.build                 |   28 +
 src/backend/main/meson.build                  |    2 +
 src/backend/meson.build                       |  197 ++
 src/backend/nodes/meson.build                 |   17 +
 src/backend/optimizer/geqo/meson.build        |   17 +
 src/backend/optimizer/meson.build             |    5 +
 src/backend/optimizer/path/meson.build        |   11 +
 src/backend/optimizer/plan/meson.build        |   10 +
 src/backend/optimizer/prep/meson.build        |    7 +
 src/backend/optimizer/util/meson.build        |   16 +
 src/backend/parser/meson.build                |   43 +
 src/backend/partitioning/meson.build          |    5 +
 src/backend/port/meson.build                  |   28 +
 src/backend/port/win32/meson.build            |    6 +
 src/backend/postmaster/meson.build            |   15 +
 src/backend/regex/meson.build                 |   15 +
 .../replication/libpqwalreceiver/meson.build  |   13 +
 src/backend/replication/logical/meson.build   |   14 +
 src/backend/replication/meson.build           |   42 +
 src/backend/replication/pgoutput/meson.build  |   11 +
 src/backend/rewrite/meson.build               |    9 +
 src/backend/snowball/meson.build              |   83 +
 src/backend/statistics/meson.build            |    6 +
 src/backend/storage/buffer/meson.build        |    7 +
 src/backend/storage/file/meson.build          |    8 +
 src/backend/storage/freespace/meson.build     |    5 +
 src/backend/storage/ipc/meson.build           |   20 +
 src/backend/storage/large_object/meson.build  |    3 +
 src/backend/storage/lmgr/meson.build          |   18 +
 src/backend/storage/meson.build               |    9 +
 src/backend/storage/page/meson.build          |    5 +
 src/backend/storage/smgr/meson.build          |    4 +
 src/backend/storage/sync/meson.build          |    4 +
 src/backend/tcop/meson.build                  |    8 +
 src/backend/tsearch/meson.build               |   21 +
 src/backend/utils/activity/meson.build        |    5 +
 src/backend/utils/adt/meson.build             |  118 +
 src/backend/utils/cache/meson.build           |   16 +
 src/backend/utils/error/meson.build           |    4 +
 src/backend/utils/fmgr/meson.build            |    8 +
 src/backend/utils/hash/meson.build            |    4 +
 src/backend/utils/init/meson.build            |    4 +
 .../utils/mb/conversion_procs/meson.build     |   38 +
 src/backend/utils/mb/meson.build              |    9 +
 src/backend/utils/meson.build                 |   13 +
 src/backend/utils/misc/meson.build            |   28 +
 src/backend/utils/mmgr/meson.build            |   10 +
 src/backend/utils/resowner/meson.build        |    3 +
 src/backend/utils/sort/meson.build            |    7 +
 src/backend/utils/time/meson.build            |    4 +
 src/bin/initdb/meson.build                    |   24 +
 src/bin/meson.build                           |   20 +
 src/bin/pg_amcheck/meson.build                |   22 +
 src/bin/pg_archivecleanup/meson.build         |   14 +
 src/bin/pg_basebackup/meson.build             |   44 +
 src/bin/pg_checksums/meson.build              |   16 +
 src/bin/pg_config/meson.build                 |   14 +
 src/bin/pg_controldata/meson.build            |   14 +
 src/bin/pg_ctl/meson.build                    |   17 +
 src/bin/pg_dump/meson.build                   |   69 +
 src/bin/pg_resetwal/meson.build               |   15 +
 src/bin/pg_rewind/meson.build                 |   34 +
 src/bin/pg_test_fsync/meson.build             |   14 +
 src/bin/pg_test_timing/meson.build            |   14 +
 src/bin/pg_upgrade/meson.build                |   26 +
 src/bin/pg_verifybackup/meson.build           |   25 +
 src/bin/pg_waldump/meson.build                |   23 +
 src/bin/pgbench/meson.build                   |   38 +
 src/bin/pgevent/meson.build                   |   32 +
 src/bin/psql/meson.build                      |   65 +
 src/bin/scripts/meson.build                   |   46 +
 src/common/meson.build                        |  155 ++
 src/common/unicode/meson.build                |   99 +
 src/fe_utils/meson.build                      |   27 +
 src/include/catalog/meson.build               |  129 +
 src/include/meson.build                       |   50 +
 src/include/parser/meson.build                |   10 +
 src/include/pch/c_pch.h                       |    1 +
 src/include/pch/postgres_pch.h                |    1 +
 src/include/pg_config_ext.h.meson             |    7 +
 src/include/storage/meson.build               |   16 +
 src/include/utils/meson.build                 |   22 +
 src/interfaces/libpq/meson.build              |   99 +
 src/meson.build                               |   10 +
 src/pl/meson.build                            |    4 +
 src/pl/plperl/meson.build                     |   81 +
 src/pl/plpgsql/meson.build                    |    1 +
 src/pl/plpgsql/src/meson.build                |   67 +
 src/pl/plpython/meson.build                   |   78 +
 src/port/meson.build                          |  191 ++
 src/port/win32ver.rc.in                       |   41 +
 src/test/authentication/meson.build           |    9 +
 src/test/isolation/meson.build                |   49 +
 src/test/kerberos/meson.build                 |   12 +
 src/test/ldap/meson.build                     |    9 +
 src/test/meson.build                          |   19 +
 src/test/modules/brin/meson.build             |   19 +
 src/test/modules/commit_ts/meson.build        |   20 +
 src/test/modules/delay_execution/meson.build  |   15 +
 src/test/modules/dummy_index_am/meson.build   |   20 +
 src/test/modules/dummy_seclabel/meson.build   |   20 +
 src/test/modules/libpq_pipeline/meson.build   |   21 +
 src/test/modules/meson.build                  |   25 +
 src/test/modules/plsample/meson.build         |   20 +
 src/test/modules/snapshot_too_old/meson.build |   11 +
 src/test/modules/spgist_name_ops/meson.build  |   20 +
 .../ssl_passphrase_callback/meson.build       |   45 +
 src/test/modules/test_bloomfilter/meson.build |   20 +
 src/test/modules/test_ddl_deparse/meson.build |   40 +
 src/test/modules/test_extensions/meson.build  |   38 +
 .../modules/test_ginpostinglist/meson.build   |   20 +
 src/test/modules/test_integerset/meson.build  |   20 +
 src/test/modules/test_misc/meson.build        |    8 +
 src/test/modules/test_parser/meson.build      |   20 +
 src/test/modules/test_pg_dump/meson.build     |   24 +
 src/test/modules/test_predtest/meson.build    |   20 +
 src/test/modules/test_rbtree/meson.build      |   20 +
 src/test/modules/test_regex/meson.build       |   21 +
 src/test/modules/test_rls_hooks/meson.build   |   19 +
 src/test/modules/test_shm_mq/meson.build      |   24 +
 src/test/modules/unsafe_tests/meson.build     |    9 +
 src/test/modules/worker_spi/meson.build       |   23 +
 src/test/recovery/meson.build                 |   33 +
 src/test/regress/meson.build                  |   57 +
 src/test/ssl/meson.build                      |   10 +
 src/test/subscription/meson.build             |   34 +
 src/timezone/meson.build                      |   50 +
 src/timezone/tznames/meson.build              |   20 +
 src/tools/find_meson                          |   20 +
 src/tools/irlink                              |   28 +
 src/tools/msvc/export2def.pl                  |   22 +
 src/tools/msvc/gendef2.pl                     |  177 ++
 .../relativize_shared_library_references      |   84 +
 src/tools/relpath.py                          |    6 +
 src/tools/testwrap                            |   22 +
 221 files changed, 8521 insertions(+)
 create mode 100644 contrib/adminpack/meson.build
 create mode 100644 contrib/amcheck/meson.build
 create mode 100644 contrib/auth_delay/meson.build
 create mode 100644 contrib/auto_explain/meson.build
 create mode 100644 contrib/bloom/meson.build
 create mode 100644 contrib/bool_plperl/meson.build
 create mode 100644 contrib/btree_gin/meson.build
 create mode 100644 contrib/btree_gist/meson.build
 create mode 100644 contrib/citext/meson.build
 create mode 100644 contrib/cube/meson.build
 create mode 100644 contrib/dblink/meson.build
 create mode 100644 contrib/dict_int/meson.build
 create mode 100644 contrib/dict_xsyn/meson.build
 create mode 100644 contrib/earthdistance/meson.build
 create mode 100644 contrib/file_fdw/meson.build
 create mode 100644 contrib/fuzzystrmatch/meson.build
 create mode 100644 contrib/hstore/meson.build
 create mode 100644 contrib/hstore_plperl/meson.build
 create mode 100644 contrib/hstore_plpython/meson.build
 create mode 100644 contrib/intagg/meson.build
 create mode 100644 contrib/intarray/meson.build
 create mode 100644 contrib/isn/meson.build
 create mode 100644 contrib/jsonb_plperl/meson.build
 create mode 100644 contrib/jsonb_plpython/meson.build
 create mode 100644 contrib/lo/meson.build
 create mode 100644 contrib/ltree/meson.build
 create mode 100644 contrib/ltree_plpython/meson.build
 create mode 100644 contrib/meson.build
 create mode 100644 contrib/oid2name/meson.build
 create mode 100644 contrib/old_snapshot/meson.build
 create mode 100644 contrib/pageinspect/meson.build
 create mode 100644 contrib/passwordcheck/meson.build
 create mode 100644 contrib/pg_buffercache/meson.build
 create mode 100644 contrib/pg_freespacemap/meson.build
 create mode 100644 contrib/pg_prewarm/meson.build
 create mode 100644 contrib/pg_stat_statements/meson.build
 create mode 100644 contrib/pg_surgery/meson.build
 create mode 100644 contrib/pg_trgm/meson.build
 create mode 100644 contrib/pg_visibility/meson.build
 create mode 100644 contrib/pgcrypto/meson.build
 create mode 100644 contrib/pgrowlocks/meson.build
 create mode 100644 contrib/pgstattuple/meson.build
 create mode 100644 contrib/postgres_fdw/meson.build
 create mode 100644 contrib/seg/meson.build
 create mode 100644 contrib/sepgsql/meson.build
 create mode 100644 contrib/spi/meson.build
 create mode 100644 contrib/sslinfo/meson.build
 create mode 100644 contrib/tablefunc/meson.build
 create mode 100644 contrib/tcn/meson.build
 create mode 100644 contrib/test_decoding/meson.build
 create mode 100644 contrib/tsm_system_rows/meson.build
 create mode 100644 contrib/tsm_system_time/meson.build
 create mode 100644 contrib/unaccent/meson.build
 create mode 100644 contrib/uuid-ossp/meson.build
 create mode 100644 contrib/vacuumlo/meson.build
 create mode 100644 contrib/xml2/meson.build
 create mode 100644 conversion_helpers.txt
 create mode 100644 doc/src/sgml/meson.build
 create mode 100644 doc/src/sgml/resolv.xsl
 create mode 100644 doc/src/sgml/version.sgml.in
 create mode 100644 meson.build
 create mode 100644 meson_options.txt
 create mode 100644 src/backend/access/brin/meson.build
 create mode 100644 src/backend/access/common/meson.build
 create mode 100644 src/backend/access/gin/meson.build
 create mode 100644 src/backend/access/gist/meson.build
 create mode 100644 src/backend/access/hash/meson.build
 create mode 100644 src/backend/access/heap/meson.build
 create mode 100644 src/backend/access/index/meson.build
 create mode 100644 src/backend/access/meson.build
 create mode 100644 src/backend/access/nbtree/meson.build
 create mode 100644 src/backend/access/rmgrdesc/meson.build
 create mode 100644 src/backend/access/spgist/meson.build
 create mode 100644 src/backend/access/table/meson.build
 create mode 100644 src/backend/access/tablesample/meson.build
 create mode 100644 src/backend/access/transam/meson.build
 create mode 100644 src/backend/bootstrap/meson.build
 create mode 100644 src/backend/catalog/meson.build
 create mode 100644 src/backend/commands/meson.build
 create mode 100644 src/backend/executor/meson.build
 create mode 100644 src/backend/foreign/meson.build
 create mode 100644 src/backend/jit/llvm/meson.build
 create mode 100644 src/backend/jit/meson.build
 create mode 100644 src/backend/lib/meson.build
 create mode 100644 src/backend/libpq/meson.build
 create mode 100644 src/backend/main/meson.build
 create mode 100644 src/backend/meson.build
 create mode 100644 src/backend/nodes/meson.build
 create mode 100644 src/backend/optimizer/geqo/meson.build
 create mode 100644 src/backend/optimizer/meson.build
 create mode 100644 src/backend/optimizer/path/meson.build
 create mode 100644 src/backend/optimizer/plan/meson.build
 create mode 100644 src/backend/optimizer/prep/meson.build
 create mode 100644 src/backend/optimizer/util/meson.build
 create mode 100644 src/backend/parser/meson.build
 create mode 100644 src/backend/partitioning/meson.build
 create mode 100644 src/backend/port/meson.build
 create mode 100644 src/backend/port/win32/meson.build
 create mode 100644 src/backend/postmaster/meson.build
 create mode 100644 src/backend/regex/meson.build
 create mode 100644 src/backend/replication/libpqwalreceiver/meson.build
 create mode 100644 src/backend/replication/logical/meson.build
 create mode 100644 src/backend/replication/meson.build
 create mode 100644 src/backend/replication/pgoutput/meson.build
 create mode 100644 src/backend/rewrite/meson.build
 create mode 100644 src/backend/snowball/meson.build
 create mode 100644 src/backend/statistics/meson.build
 create mode 100644 src/backend/storage/buffer/meson.build
 create mode 100644 src/backend/storage/file/meson.build
 create mode 100644 src/backend/storage/freespace/meson.build
 create mode 100644 src/backend/storage/ipc/meson.build
 create mode 100644 src/backend/storage/large_object/meson.build
 create mode 100644 src/backend/storage/lmgr/meson.build
 create mode 100644 src/backend/storage/meson.build
 create mode 100644 src/backend/storage/page/meson.build
 create mode 100644 src/backend/storage/smgr/meson.build
 create mode 100644 src/backend/storage/sync/meson.build
 create mode 100644 src/backend/tcop/meson.build
 create mode 100644 src/backend/tsearch/meson.build
 create mode 100644 src/backend/utils/activity/meson.build
 create mode 100644 src/backend/utils/adt/meson.build
 create mode 100644 src/backend/utils/cache/meson.build
 create mode 100644 src/backend/utils/error/meson.build
 create mode 100644 src/backend/utils/fmgr/meson.build
 create mode 100644 src/backend/utils/hash/meson.build
 create mode 100644 src/backend/utils/init/meson.build
 create mode 100644 src/backend/utils/mb/conversion_procs/meson.build
 create mode 100644 src/backend/utils/mb/meson.build
 create mode 100644 src/backend/utils/meson.build
 create mode 100644 src/backend/utils/misc/meson.build
 create mode 100644 src/backend/utils/mmgr/meson.build
 create mode 100644 src/backend/utils/resowner/meson.build
 create mode 100644 src/backend/utils/sort/meson.build
 create mode 100644 src/backend/utils/time/meson.build
 create mode 100644 src/bin/initdb/meson.build
 create mode 100644 src/bin/meson.build
 create mode 100644 src/bin/pg_amcheck/meson.build
 create mode 100644 src/bin/pg_archivecleanup/meson.build
 create mode 100644 src/bin/pg_basebackup/meson.build
 create mode 100644 src/bin/pg_checksums/meson.build
 create mode 100644 src/bin/pg_config/meson.build
 create mode 100644 src/bin/pg_controldata/meson.build
 create mode 100644 src/bin/pg_ctl/meson.build
 create mode 100644 src/bin/pg_dump/meson.build
 create mode 100644 src/bin/pg_resetwal/meson.build
 create mode 100644 src/bin/pg_rewind/meson.build
 create mode 100644 src/bin/pg_test_fsync/meson.build
 create mode 100644 src/bin/pg_test_timing/meson.build
 create mode 100644 src/bin/pg_upgrade/meson.build
 create mode 100644 src/bin/pg_verifybackup/meson.build
 create mode 100644 src/bin/pg_waldump/meson.build
 create mode 100644 src/bin/pgbench/meson.build
 create mode 100644 src/bin/pgevent/meson.build
 create mode 100644 src/bin/psql/meson.build
 create mode 100644 src/bin/scripts/meson.build
 create mode 100644 src/common/meson.build
 create mode 100644 src/common/unicode/meson.build
 create mode 100644 src/fe_utils/meson.build
 create mode 100644 src/include/catalog/meson.build
 create mode 100644 src/include/meson.build
 create mode 100644 src/include/parser/meson.build
 create mode 100644 src/include/pch/c_pch.h
 create mode 100644 src/include/pch/postgres_pch.h
 create mode 100644 src/include/pg_config_ext.h.meson
 create mode 100644 src/include/storage/meson.build
 create mode 100644 src/include/utils/meson.build
 create mode 100644 src/interfaces/libpq/meson.build
 create mode 100644 src/meson.build
 create mode 100644 src/pl/meson.build
 create mode 100644 src/pl/plperl/meson.build
 create mode 100644 src/pl/plpgsql/meson.build
 create mode 100644 src/pl/plpgsql/src/meson.build
 create mode 100644 src/pl/plpython/meson.build
 create mode 100644 src/port/meson.build
 create mode 100644 src/port/win32ver.rc.in
 create mode 100644 src/test/authentication/meson.build
 create mode 100644 src/test/isolation/meson.build
 create mode 100644 src/test/kerberos/meson.build
 create mode 100644 src/test/ldap/meson.build
 create mode 100644 src/test/meson.build
 create mode 100644 src/test/modules/brin/meson.build
 create mode 100644 src/test/modules/commit_ts/meson.build
 create mode 100644 src/test/modules/delay_execution/meson.build
 create mode 100644 src/test/modules/dummy_index_am/meson.build
 create mode 100644 src/test/modules/dummy_seclabel/meson.build
 create mode 100644 src/test/modules/libpq_pipeline/meson.build
 create mode 100644 src/test/modules/meson.build
 create mode 100644 src/test/modules/plsample/meson.build
 create mode 100644 src/test/modules/snapshot_too_old/meson.build
 create mode 100644 src/test/modules/spgist_name_ops/meson.build
 create mode 100644 src/test/modules/ssl_passphrase_callback/meson.build
 create mode 100644 src/test/modules/test_bloomfilter/meson.build
 create mode 100644 src/test/modules/test_ddl_deparse/meson.build
 create mode 100644 src/test/modules/test_extensions/meson.build
 create mode 100644 src/test/modules/test_ginpostinglist/meson.build
 create mode 100644 src/test/modules/test_integerset/meson.build
 create mode 100644 src/test/modules/test_misc/meson.build
 create mode 100644 src/test/modules/test_parser/meson.build
 create mode 100644 src/test/modules/test_pg_dump/meson.build
 create mode 100644 src/test/modules/test_predtest/meson.build
 create mode 100644 src/test/modules/test_rbtree/meson.build
 create mode 100644 src/test/modules/test_regex/meson.build
 create mode 100644 src/test/modules/test_rls_hooks/meson.build
 create mode 100644 src/test/modules/test_shm_mq/meson.build
 create mode 100644 src/test/modules/unsafe_tests/meson.build
 create mode 100644 src/test/modules/worker_spi/meson.build
 create mode 100644 src/test/recovery/meson.build
 create mode 100644 src/test/regress/meson.build
 create mode 100644 src/test/ssl/meson.build
 create mode 100644 src/test/subscription/meson.build
 create mode 100644 src/timezone/meson.build
 create mode 100644 src/timezone/tznames/meson.build
 create mode 100755 src/tools/find_meson
 create mode 100644 src/tools/irlink
 create mode 100644 src/tools/msvc/export2def.pl
 create mode 100644 src/tools/msvc/gendef2.pl
 create mode 100755 src/tools/relativize_shared_library_references
 create mode 100755 src/tools/relpath.py
 create mode 100755 src/tools/testwrap

diff --git a/configure b/configure
index fd15801b34c..c91295fcab5 100755
--- a/configure
+++ b/configure
@@ -21045,3 +21045,9 @@ if test -n "$ac_unrecognized_opts" && test \
"$enable_option_checking" != no; then  $as_echo "$as_me: WARNING: unrecognized \
options: $ac_unrecognized_opts" >&2;}  fi
 
+
+# Ensure that any meson build directories would reconfigure and see that
+# there's a conflicting in-tree build and can error out.
+if test "$vpath_build"="no"; then
+  touch meson.build
+fi
diff --git a/configure.ac b/configure.ac
index 973f83db52c..95c1f7ac6c9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2494,3 +2494,9 @@ AC_CONFIG_HEADERS([src/interfaces/ecpg/include/ecpg_config.h],
                   [echo >src/interfaces/ecpg/include/stamp-h])
 
 AC_OUTPUT
+
+# Ensure that any meson build directories would reconfigure and see that
+# there's a conflicting in-tree build and can error out.
+if test "$vpath_build"="no"; then
+  touch meson.build
+fi
diff --git a/contrib/adminpack/meson.build b/contrib/adminpack/meson.build
new file mode 100644
index 00000000000..457a6089445
--- /dev/null
+++ b/contrib/adminpack/meson.build
@@ -0,0 +1,20 @@
+autoinc = shared_module('adminpack',
+  ['adminpack.c'],
+  kwargs: contrib_mod_args,
+)
+
+install_data(
+  'adminpack.control',
+  'adminpack--1.0.sql',
+  'adminpack--1.0--1.1.sql',
+  'adminpack--1.1--2.0.sql',
+  'adminpack--2.0--2.1.sql',
+  kwargs: contrib_data_args,
+)
+
+regress_tests += {
+  'name': 'adminpack',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': ['adminpack'],
+}
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
new file mode 100644
index 00000000000..e656d35f41f
--- /dev/null
+++ b/contrib/amcheck/meson.build
@@ -0,0 +1,37 @@
+amcheck = shared_module('amcheck', [
+    'verify_heapam.c',
+    'verify_nbtree.c',
+  ],
+  kwargs: contrib_mod_args,
+)
+
+install_data(
+  'amcheck.control',
+  'amcheck--1.0.sql',
+  'amcheck--1.0--1.1.sql',
+  'amcheck--1.1--1.2.sql',
+  'amcheck--1.2--1.3.sql',
+  kwargs: contrib_data_args,
+)
+
+regress_tests += {
+  'name': 'amcheck',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'check',
+    'check_btree',
+    'check_heap'
+  ],
+}
+
+tap_tests += {
+  'name': 'amcheck',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tests': [
+    't/001_verify_heapam.pl',
+    't/002_cic.pl',
+    't/003_cic_2pc.pl',
+  ],
+}
diff --git a/contrib/auth_delay/meson.build b/contrib/auth_delay/meson.build
new file mode 100644
index 00000000000..941bb6f39a4
--- /dev/null
+++ b/contrib/auth_delay/meson.build
@@ -0,0 +1,4 @@
+autoinc = shared_module('auth_delay',
+  ['auth_delay.c'],
+  kwargs: contrib_mod_args,
+)
diff --git a/contrib/auto_explain/meson.build b/contrib/auto_explain/meson.build
new file mode 100644
index 00000000000..321896efa2c
--- /dev/null
+++ b/contrib/auto_explain/meson.build
@@ -0,0 +1,13 @@
+auto_explain = shared_module('auto_explain',
+  files('auto_explain.c'),
+  kwargs: contrib_mod_args,
+)
+
+tap_tests += {
+  'name': 'auto_explain',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tests': [
+    't/001_auto_explain.pl',
+  ]
+}
diff --git a/contrib/bloom/meson.build b/contrib/bloom/meson.build
new file mode 100644
index 00000000000..5c5d33c7f7a
--- /dev/null
+++ b/contrib/bloom/meson.build
@@ -0,0 +1,38 @@
+bloom_sources = files(
+  'blcost.c',
+  'blinsert.c',
+  'blscan.c',
+  'blutils.c',
+  'blvacuum.c',
+  'blvalidate.c',
+)
+
+bloom = shared_module('bloom',
+  bloom_sources,
+  c_pch: '../../src/include/pch/c_pch.h',
+  kwargs: contrib_mod_args,
+)
+
+install_data(
+  'bloom.control',
+  'bloom--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+regress_tests += {
+  'name': 'bloom',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'bloom'
+  ],
+}
+
+tap_tests += {
+  'name': 'bloom',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tests': [
+    't/001_wal.pl',
+  ],
+}
diff --git a/contrib/bool_plperl/meson.build b/contrib/bool_plperl/meson.build
new file mode 100644
index 00000000000..e15dc5285eb
--- /dev/null
+++ b/contrib/bool_plperl/meson.build
@@ -0,0 +1,37 @@
+if not perl_dep.found()
+  subdir_done()
+endif
+
+bool_plperl_sources = files(
+  'bool_plperl.c',
+)
+
+bool_plperl = shared_module('bool_plperl',
+  bool_plperl_sources,
+  include_directories: [plperl_inc, include_directories('.')],
+  kwargs: pg_mod_args + {
+    'dependencies': [perl_dep, contrib_mod_args['dependencies']],
+  },
+)
+
+install_data(
+  'bool_plperl.control',
+  'bool_plperl--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+install_data(
+  'bool_plperlu.control',
+  'bool_plperlu--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+regress_tests += {
+  'name': 'bool_plperl',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'bool_plperl',
+    'bool_plperlu',
+  ],
+}
diff --git a/contrib/btree_gin/meson.build b/contrib/btree_gin/meson.build
new file mode 100644
index 00000000000..d25ece7500e
--- /dev/null
+++ b/contrib/btree_gin/meson.build
@@ -0,0 +1,51 @@
+btree_gin = shared_module('btree_gin',
+  files('btree_gin.c'),
+  kwargs: contrib_mod_args,
+)
+
+install_data(
+  'btree_gin.control',
+  'btree_gin--1.0.sql',
+  'btree_gin--1.0--1.1.sql',
+  'btree_gin--1.1--1.2.sql',
+  'btree_gin--1.2--1.3.sql',
+  kwargs: contrib_data_args,
+)
+
+regress_tests += {
+  'name': 'btree_gin',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'install_btree_gin',
+    'int2',
+    'int4',
+    'int8',
+    'float4',
+    'float8',
+    'money',
+    'oid',
+    'timestamp',
+    'timestamptz',
+    'time',
+    'timetz',
+    'date',
+    'interval',
+    'macaddr',
+    'macaddr8',
+    'inet',
+    'cidr',
+    'text',
+    'varchar',
+    'char',
+    'bytea',
+    'bit',
+    'varbit',
+    'numeric',
+    'enum',
+    'uuid',
+    'name',
+    'bool',
+    'bpchar',
+  ],
+}
diff --git a/contrib/btree_gist/meson.build b/contrib/btree_gist/meson.build
new file mode 100644
index 00000000000..8ee0faea401
--- /dev/null
+++ b/contrib/btree_gist/meson.build
@@ -0,0 +1,79 @@
+btree_gist_sources = files(
+  'btree_bit.c',
+  'btree_bytea.c',
+  'btree_cash.c',
+  'btree_date.c',
+  'btree_enum.c',
+  'btree_float4.c',
+  'btree_float8.c',
+  'btree_gist.c',
+  'btree_inet.c',
+  'btree_int2.c',
+  'btree_int4.c',
+  'btree_int8.c',
+  'btree_interval.c',
+  'btree_macaddr.c',
+  'btree_macaddr8.c',
+  'btree_numeric.c',
+  'btree_oid.c',
+  'btree_text.c',
+  'btree_time.c',
+  'btree_ts.c',
+  'btree_utils_num.c',
+  'btree_utils_var.c',
+  'btree_uuid.c',
+)
+
+btree_gist = shared_module('btree_gist',
+  btree_gist_sources,
+  c_pch: '../../src/include/pch/c_pch.h',
+  kwargs: contrib_mod_args,
+)
+
+install_data(
+  'btree_gist.control',
+  'btree_gist--1.0--1.1.sql',
+  'btree_gist--1.1--1.2.sql',
+  'btree_gist--1.2.sql',
+  'btree_gist--1.2--1.3.sql',
+  'btree_gist--1.3--1.4.sql',
+  'btree_gist--1.4--1.5.sql',
+  'btree_gist--1.5--1.6.sql',
+  kwargs: contrib_data_args,
+)
+
+regress_tests += {
+  'name': 'btree_gist',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'init',
+    'int2',
+    'int4',
+    'int8',
+    'float4',
+    'float8',
+    'cash',
+    'oid',
+    'timestamp',
+    'timestamptz',
+    'time',
+    'timetz',
+    'date',
+    'interval',
+    'macaddr',
+    'macaddr8',
+    'inet',
+    'cidr',
+    'text',
+    'varchar',
+    'char',
+    'bytea',
+    'bit',
+    'varbit',
+    'numeric',
+    'uuid',
+    'not_equal',
+    'enum',
+  ],
+}
diff --git a/contrib/citext/meson.build b/contrib/citext/meson.build
new file mode 100644
index 00000000000..f2e9ff2117d
--- /dev/null
+++ b/contrib/citext/meson.build
@@ -0,0 +1,29 @@
+citext_sources = files(
+  'citext.c',
+)
+
+citext = shared_module('citext',
+  citext_sources,
+  kwargs: contrib_mod_args,
+)
+
+install_data(
+  'citext.control',
+  'citext--1.0--1.1.sql',
+  'citext--1.1--1.2.sql',
+  'citext--1.2--1.3.sql',
+  'citext--1.3--1.4.sql',
+  'citext--1.4.sql',
+  'citext--1.4--1.5.sql',
+  'citext--1.5--1.6.sql',
+  kwargs: contrib_data_args,
+)
+
+regress_tests += {
+  'name': 'citext',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'citext'
+  ],
+}
diff --git a/contrib/cube/meson.build b/contrib/cube/meson.build
new file mode 100644
index 00000000000..3cf7ebdd8ea
--- /dev/null
+++ b/contrib/cube/meson.build
@@ -0,0 +1,42 @@
+cube_sources = files(
+  'cube.c',
+)
+
+# cubescan is compiled as part of cubeparse
+cubescan = custom_target('cubescan',
+  input: ['cubescan.l'],
+  output: ['cubescan.c'],
+  command: [flex, '-o', '@OUTPUT@', '@INPUT@'])
+
+cube_sources += custom_target('cubeparse',
+  input: 'cubeparse.y',
+  output: 'cubeparse.c',
+  depends: cubescan,
+  command: [bison, bisonflags, '-o', '@OUTPUT@', '@INPUT0@'])
+
+cube = shared_module('cube',
+  cube_sources,
+  include_directories: include_directories('.'),
+  kwargs: contrib_mod_args,
+)
+
+install_data(
+  'cube.control',
+  'cube--1.0--1.1.sql',
+  'cube--1.1--1.2.sql',
+  'cube--1.2.sql',
+  'cube--1.2--1.3.sql',
+  'cube--1.3--1.4.sql',
+  'cube--1.4--1.5.sql',
+  kwargs: contrib_data_args,
+)
+
+regress_tests += {
+  'name': 'cube',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'cube',
+    'cube_sci',
+  ],
+}
diff --git a/contrib/dblink/meson.build b/contrib/dblink/meson.build
new file mode 100644
index 00000000000..7ac253700c9
--- /dev/null
+++ b/contrib/dblink/meson.build
@@ -0,0 +1,29 @@
+dblink_sources = files(
+  'dblink.c',
+)
+
+dblink = shared_module('dblink',
+  dblink_sources,
+  kwargs: contrib_mod_args + {
+      'dependencies': pg_mod_args['dependencies'] + [libpq],
+  },
+)
+
+install_data(
+  'dblink.control',
+  'dblink--1.0--1.1.sql',
+  'dblink--1.1--1.2.sql',
+  'dblink--1.2.sql',
+  kwargs: contrib_data_args,
+)
+
+regress_tests += {
+  'name': 'dblink',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'paths',
+    'dblink'
+  ],
+  'regress_args': ['--dlpath', meson.build_root() / 'src/test/regress'],
+}
diff --git a/contrib/dict_int/meson.build b/contrib/dict_int/meson.build
new file mode 100644
index 00000000000..7c23b275c5a
--- /dev/null
+++ b/contrib/dict_int/meson.build
@@ -0,0 +1,19 @@
+dict_int = shared_module('dict_int',
+  files('dict_int.c'),
+  kwargs: contrib_mod_args,
+)
+
+install_data(
+  'dict_int.control',
+  'dict_int--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+regress_tests += {
+  'name': 'dict_int',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'dict_int'
+  ],
+}
diff --git a/contrib/dict_xsyn/meson.build b/contrib/dict_xsyn/meson.build
new file mode 100644
index 00000000000..7cbabba02f1
--- /dev/null
+++ b/contrib/dict_xsyn/meson.build
@@ -0,0 +1,26 @@
+dict_xsyn = shared_module('dict_xsyn',
+  files('dict_xsyn.c'),
+  kwargs: contrib_mod_args,
+)
+
+install_data(
+  'dict_xsyn.control',
+  'dict_xsyn--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+install_data(
+  'xsyn_sample.rules',
+  kwargs: contrib_data_args + {
+    'install_dir': get_option('datadir') / 'tsearch_data'
+  }
+)
+
+regress_tests += {
+  'name': 'dict_xsyn',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'dict_xsyn'
+  ],
+}
diff --git a/contrib/earthdistance/meson.build b/contrib/earthdistance/meson.build
new file mode 100644
index 00000000000..d56abf4f260
--- /dev/null
+++ b/contrib/earthdistance/meson.build
@@ -0,0 +1,20 @@
+earthdistance = shared_module('earthdistance',
+  files('earthdistance.c'),
+  kwargs: contrib_mod_args,
+)
+
+install_data(
+  'earthdistance.control',
+  'earthdistance--1.0--1.1.sql',
+  'earthdistance--1.1.sql',
+  kwargs: contrib_data_args,
+)
+
+regress_tests += {
+  'name': 'earthdistance',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'earthdistance'
+  ],
+}
diff --git a/contrib/file_fdw/meson.build b/contrib/file_fdw/meson.build
new file mode 100644
index 00000000000..0cd3348dfd0
--- /dev/null
+++ b/contrib/file_fdw/meson.build
@@ -0,0 +1,19 @@
+file_fdw = shared_module('file_fdw',
+  files('file_fdw.c'),
+  kwargs: contrib_mod_args,
+)
+
+install_data(
+  'file_fdw.control',
+  'file_fdw--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+regress_tests += {
+  'name': 'file_fdw',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'file_fdw'
+  ],
+}
diff --git a/contrib/fuzzystrmatch/meson.build b/contrib/fuzzystrmatch/meson.build
new file mode 100644
index 00000000000..d1e75479668
--- /dev/null
+++ b/contrib/fuzzystrmatch/meson.build
@@ -0,0 +1,23 @@
+fuzzystrmatch = shared_module('fuzzystrmatch',
+  files(
+    'fuzzystrmatch.c',
+    'dmetaphone.c'
+  ),
+  kwargs: contrib_mod_args,
+)
+
+install_data(
+  'fuzzystrmatch.control',
+  'fuzzystrmatch--1.0--1.1.sql',
+  'fuzzystrmatch--1.1.sql',
+  kwargs: contrib_data_args,
+)
+
+regress_tests += {
+  'name': 'fuzzystrmatch',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'fuzzystrmatch'
+  ],
+}
diff --git a/contrib/hstore/meson.build b/contrib/hstore/meson.build
new file mode 100644
index 00000000000..661e61f9692
--- /dev/null
+++ b/contrib/hstore/meson.build
@@ -0,0 +1,36 @@
+# .. so that includes of hstore/hstore.h work
+hstore_inc = include_directories('.', '../')
+
+hstore = shared_module('hstore',
+  files(
+    'hstore_compat.c',
+    'hstore_gin.c',
+    'hstore_gist.c',
+    'hstore_io.c',
+    'hstore_op.c',
+    'hstore_subs.c',
+  ),
+  c_pch: '../../src/include/pch/c_pch.h',
+  kwargs: contrib_mod_args,
+)
+
+install_data(
+  'hstore.control',
+  'hstore--1.1--1.2.sql',
+  'hstore--1.3--1.4.sql',
+  'hstore--1.4.sql',
+  'hstore--1.4--1.5.sql',
+  'hstore--1.5--1.6.sql',
+  'hstore--1.6--1.7.sql',
+  'hstore--1.7--1.8.sql',
+  kwargs: contrib_data_args,
+)
+
+regress_tests += {
+  'name': 'hstore',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'hstore'
+  ],
+}
diff --git a/contrib/hstore_plperl/meson.build b/contrib/hstore_plperl/meson.build
new file mode 100644
index 00000000000..48231cb1c9e
--- /dev/null
+++ b/contrib/hstore_plperl/meson.build
@@ -0,0 +1,38 @@
+if not perl_dep.found()
+  subdir_done()
+endif
+
+hstore_plperl_sources = files(
+  'hstore_plperl.c',
+)
+
+hstore_plperl = shared_module('hstore_plperl',
+  hstore_plperl_sources,
+  include_directories: [plperl_inc, hstore_inc],
+  kwargs: pg_mod_args + {
+    'dependencies': [perl_dep, contrib_mod_args['dependencies']],
+  },
+)
+
+install_data(
+  'hstore_plperl.control',
+  'hstore_plperl--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+install_data(
+  'hstore_plperlu.control',
+  'hstore_plperlu--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+regress_tests += {
+  'name': 'hstore_plperl',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'hstore_plperl',
+    'hstore_plperlu',
+    'create_transform',
+  ],
+}
diff --git a/contrib/hstore_plpython/meson.build \
b/contrib/hstore_plpython/meson.build new file mode 100644
index 00000000000..98114e46f5e
--- /dev/null
+++ b/contrib/hstore_plpython/meson.build
@@ -0,0 +1,34 @@
+if not python3.found()
+  subdir_done()
+endif
+
+hstore_plpython_sources = files(
+  'hstore_plpython.c',
+)
+
+hstore_plpython = shared_module('hstore_plpython3',
+  hstore_plpython_sources,
+  include_directories: [plpython_inc, hstore_inc, ],
+  kwargs: pg_mod_args + {
+    'c_args': ['-DPLPYTHON_LIBNAME="plpython3"'] + contrib_mod_args['c_args'],
+    'dependencies': [python3, contrib_mod_args['dependencies']],
+  },
+)
+
+install_data(
+  'hstore_plpython3u--1.0.sql',
+  'hstore_plpython3u.control',
+  kwargs: contrib_data_args,
+)
+
+hstore_plpython_regress = [
+  'hstore_plpython'
+]
+
+regress_tests += {
+  'name': 'hstore_plpython',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': hstore_plpython_regress,
+  'regress_args': ['--load-extension=hstore'],
+}
diff --git a/contrib/intagg/meson.build b/contrib/intagg/meson.build
new file mode 100644
index 00000000000..a0f39366f47
--- /dev/null
+++ b/contrib/intagg/meson.build
@@ -0,0 +1,6 @@
+install_data(
+  'intagg.control',
+  'intagg--1.0--1.1.sql',
+  'intagg--1.1.sql',
+  kwargs: contrib_data_args,
+)
diff --git a/contrib/intarray/meson.build b/contrib/intarray/meson.build
new file mode 100644
index 00000000000..d4fe99ca275
--- /dev/null
+++ b/contrib/intarray/meson.build
@@ -0,0 +1,34 @@
+intarray_sources = files(
+  '_int_bool.c',
+  '_int_gin.c',
+  '_int_gist.c',
+  '_int_op.c',
+  '_int_selfuncs.c',
+  '_int_tool.c',
+  '_intbig_gist.c',
+)
+
+intarray = shared_module('_int',
+  intarray_sources,
+  kwargs: contrib_mod_args,
+)
+
+install_data(
+  'intarray.control',
+  'intarray--1.0--1.1.sql',
+  'intarray--1.1--1.2.sql',
+  'intarray--1.2.sql',
+  'intarray--1.2--1.3.sql',
+  'intarray--1.3--1.4.sql',
+  'intarray--1.4--1.5.sql',
+  kwargs: contrib_data_args,
+)
+
+regress_tests += {
+  'name': 'intarray',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    '_int'
+  ],
+}
diff --git a/contrib/isn/meson.build b/contrib/isn/meson.build
new file mode 100644
index 00000000000..ca919800b9f
--- /dev/null
+++ b/contrib/isn/meson.build
@@ -0,0 +1,25 @@
+isn_sources = files(
+  'isn.c',
+)
+
+isn = shared_module('isn',
+  isn_sources,
+  kwargs: contrib_mod_args,
+)
+
+install_data(
+  'isn.control',
+  'isn--1.0--1.1.sql',
+  'isn--1.1--1.2.sql',
+  'isn--1.1.sql',
+  kwargs: contrib_data_args,
+)
+
+regress_tests += {
+  'name': 'isn',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'isn'
+  ],
+}
diff --git a/contrib/jsonb_plperl/meson.build b/contrib/jsonb_plperl/meson.build
new file mode 100644
index 00000000000..c34090e5f5c
--- /dev/null
+++ b/contrib/jsonb_plperl/meson.build
@@ -0,0 +1,37 @@
+if not perl_dep.found()
+  subdir_done()
+endif
+
+jsonb_plperl_sources = files(
+  'jsonb_plperl.c',
+)
+
+jsonb_plperl = shared_module('jsonb_plperl',
+  jsonb_plperl_sources,
+  include_directories: [plperl_inc],
+  kwargs: pg_mod_args + {
+    'dependencies': [perl_dep, contrib_mod_args['dependencies']],
+  },
+)
+
+install_data(
+  'jsonb_plperl.control',
+  'jsonb_plperl--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+install_data(
+  'jsonb_plperlu.control',
+  'jsonb_plperlu--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+regress_tests += {
+  'name': 'jsonb_plperl',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'jsonb_plperl',
+    'jsonb_plperlu',
+  ],
+}
diff --git a/contrib/jsonb_plpython/meson.build b/contrib/jsonb_plpython/meson.build
new file mode 100644
index 00000000000..aa372d52e26
--- /dev/null
+++ b/contrib/jsonb_plpython/meson.build
@@ -0,0 +1,33 @@
+if not python3.found()
+  subdir_done()
+endif
+
+jsonb_plpython_sources = files(
+  'jsonb_plpython.c',
+)
+
+jsonb_plpython = shared_module('jsonb_plpython3',
+  jsonb_plpython_sources,
+  include_directories: [plpython_inc],
+  kwargs: pg_mod_args + {
+    'c_args': ['-DPLPYTHON_LIBNAME="plpython3"'] + contrib_mod_args['c_args'],
+    'dependencies': [python3, contrib_mod_args['dependencies']],
+  },
+)
+
+install_data(
+  'jsonb_plpython3u.control',
+  'jsonb_plpython3u--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+jsonb_plpython_regress = [
+  'jsonb_plpython'
+]
+
+regress_tests += {
+  'name': 'jsonb_plpython',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': jsonb_plpython_regress,
+}
diff --git a/contrib/lo/meson.build b/contrib/lo/meson.build
new file mode 100644
index 00000000000..ca9bbc42015
--- /dev/null
+++ b/contrib/lo/meson.build
@@ -0,0 +1,24 @@
+lo_sources = files(
+  'lo.c',
+)
+
+lo = shared_module('lo',
+  lo_sources,
+  kwargs: contrib_mod_args,
+)
+
+install_data(
+  'lo.control',
+  'lo--1.0--1.1.sql',
+  'lo--1.1.sql',
+  kwargs: contrib_data_args,
+)
+
+regress_tests += {
+  'name': 'lo',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'lo'
+  ],
+}
diff --git a/contrib/ltree/meson.build b/contrib/ltree/meson.build
new file mode 100644
index 00000000000..12909945350
--- /dev/null
+++ b/contrib/ltree/meson.build
@@ -0,0 +1,36 @@
+ltree_sources = files(
+  '_ltree_gist.c',
+  '_ltree_op.c',
+  'crc32.c',
+  'lquery_op.c',
+  'ltree_gist.c',
+  'ltree_io.c',
+  'ltree_op.c',
+  'ltxtquery_io.c',
+  'ltxtquery_op.c',
+)
+
+# .. so that includes of ltree/ltree.h work
+ltree_inc = include_directories('.', '../')
+
+ltree = shared_module('ltree',
+  ltree_sources,
+  kwargs: contrib_mod_args,
+)
+
+install_data(
+  'ltree.control',
+  'ltree--1.0--1.1.sql',
+  'ltree--1.1--1.2.sql',
+  'ltree--1.1.sql',
+  kwargs: contrib_data_args,
+)
+
+regress_tests += {
+  'name': 'ltree',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'ltree'
+  ],
+}
diff --git a/contrib/ltree_plpython/meson.build b/contrib/ltree_plpython/meson.build
new file mode 100644
index 00000000000..df30c84c6a9
--- /dev/null
+++ b/contrib/ltree_plpython/meson.build
@@ -0,0 +1,34 @@
+if not python3.found()
+  subdir_done()
+endif
+
+ltree_plpython_sources = files(
+  'ltree_plpython.c',
+)
+
+ltree_plpython = shared_module('ltree_plpython3',
+  ltree_plpython_sources,
+  include_directories: [plpython_inc, ltree_inc],
+  kwargs: pg_mod_args + {
+    'c_args': ['-DPLPYTHON_LIBNAME="plpython3"'] + contrib_mod_args['c_args'],
+    'dependencies': [python3, contrib_mod_args['dependencies']],
+  },
+)
+
+install_data(
+  'ltree_plpython3u--1.0.sql',
+  'ltree_plpython3u.control',
+  kwargs: contrib_data_args,
+)
+
+ltree_plpython_regress = [
+  'ltree_plpython'
+]
+
+regress_tests += {
+  'name': 'ltree_plpython',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': ltree_plpython_regress,
+  'regress_args': ['--load-extension=ltree'],
+}
diff --git a/contrib/meson.build b/contrib/meson.build
new file mode 100644
index 00000000000..720181023c8
--- /dev/null
+++ b/contrib/meson.build
@@ -0,0 +1,63 @@
+contrib_mod_args = pg_mod_args
+
+contrib_data_dir = get_option('datadir') / 'extension'
+contrib_data_args = {
+  'install_dir': contrib_data_dir
+}
+
+subdir('adminpack')
+subdir('amcheck')
+subdir('auth_delay')
+subdir('auto_explain')
+subdir('bloom')
+subdir('bool_plperl')
+subdir('btree_gin')
+subdir('btree_gist')
+subdir('citext')
+subdir('cube')
+subdir('dblink')
+subdir('dict_int')
+subdir('dict_xsyn')
+subdir('earthdistance')
+subdir('file_fdw')
+subdir('fuzzystrmatch')
+subdir('hstore')
+subdir('hstore_plperl')
+subdir('hstore_plpython')
+subdir('intagg')
+subdir('intarray')
+subdir('isn')
+subdir('jsonb_plperl')
+subdir('jsonb_plpython')
+subdir('lo')
+subdir('ltree')
+subdir('ltree_plpython')
+subdir('oid2name')
+subdir('old_snapshot')
+subdir('pageinspect')
+subdir('passwordcheck')
+subdir('pg_buffercache')
+subdir('pgcrypto')
+subdir('pg_freespacemap')
+subdir('pg_prewarm')
+subdir('pgrowlocks')
+subdir('pg_stat_statements')
+subdir('pgstattuple')
+subdir('pg_surgery')
+subdir('pg_trgm')
+subdir('pg_visibility')
+subdir('postgres_fdw')
+subdir('seg')
+subdir('sepgsql')
+subdir('spi')
+subdir('sslinfo')
+# start-scripts doesn't contain build products
+subdir('tablefunc')
+subdir('tcn')
+subdir('test_decoding')
+subdir('tsm_system_rows')
+subdir('tsm_system_time')
+subdir('unaccent')
+subdir('uuid-ossp')
+subdir('vacuumlo')
+subdir('xml2')
diff --git a/contrib/oid2name/meson.build b/contrib/oid2name/meson.build
new file mode 100644
index 00000000000..bee34d2137c
--- /dev/null
+++ b/contrib/oid2name/meson.build
@@ -0,0 +1,14 @@
+executable('oid2name',
+  ['oid2name.c'],
+  dependencies: [frontend_code, libpq],
+  kwargs: default_bin_args,
+)
+
+tap_tests += {
+  'name' : 'oid2name',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tests' :[
+    't/001_basic.pl',
+  ]
+}
diff --git a/contrib/old_snapshot/meson.build b/contrib/old_snapshot/meson.build
new file mode 100644
index 00000000000..5785c29e9f8
--- /dev/null
+++ b/contrib/old_snapshot/meson.build
@@ -0,0 +1,14 @@
+old_snapshot_sources = files(
+  'time_mapping.c',
+)
+
+old_snapshot = shared_module('old_snapshot',
+  old_snapshot_sources,
+  kwargs: contrib_mod_args,
+)
+
+install_data(
+  'old_snapshot.control',
+  'old_snapshot--1.0.sql',
+  kwargs: contrib_data_args,
+)
diff --git a/contrib/pageinspect/meson.build b/contrib/pageinspect/meson.build
new file mode 100644
index 00000000000..4bd5b1784e0
--- /dev/null
+++ b/contrib/pageinspect/meson.build
@@ -0,0 +1,45 @@
+pageinspect = shared_module('pageinspect',
+  files(
+    'brinfuncs.c',
+    'btreefuncs.c',
+    'fsmfuncs.c',
+    'ginfuncs.c',
+    'gistfuncs.c',
+    'hashfuncs.c',
+    'heapfuncs.c',
+    'rawpage.c',
+  ),
+  kwargs: contrib_mod_args,
+)
+
+install_data(
+  'pageinspect--1.0--1.1.sql',
+  'pageinspect--1.1--1.2.sql',
+  'pageinspect--1.2--1.3.sql',
+  'pageinspect--1.3--1.4.sql',
+  'pageinspect--1.4--1.5.sql',
+  'pageinspect--1.5--1.6.sql',
+  'pageinspect--1.5.sql',
+  'pageinspect--1.6--1.7.sql',
+  'pageinspect--1.7--1.8.sql',
+  'pageinspect--1.8--1.9.sql',
+  'pageinspect--1.9--1.10.sql',
+  'pageinspect.control',
+  kwargs: contrib_data_args,
+)
+
+regress_tests += {
+  'name': 'pageinspect',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'page',
+    'btree',
+    'brin',
+    'gin',
+    'gist',
+    'hash',
+    'checksum',
+    'oldextversions',
+  ],
+}
diff --git a/contrib/passwordcheck/meson.build b/contrib/passwordcheck/meson.build
new file mode 100644
index 00000000000..ae5db94d0e1
--- /dev/null
+++ b/contrib/passwordcheck/meson.build
@@ -0,0 +1,27 @@
+passwordcheck_sources = files(
+  'passwordcheck.c',
+)
+
+passwordcheck_c_args = []
+passwordcheck_deps = []
+
+# uncomment the following two lines to enable cracklib support
+# passwordcheck_c_args += ['-DUSE_CRACKLIB', \
'-DCRACKLIB_DICTPATH="/usr/lib/cracklib_dict"'] +# passwordcheck_deps += \
[cc.find_library('crack')] +
+passwordcheck = shared_module('passwordcheck',
+  passwordcheck_sources,
+  kwargs: contrib_mod_args + {
+    'c_args': contrib_mod_args.get('c_args') + passwordcheck_c_args,
+    'dependencies': contrib_mod_args.get('dependencies') + passwordcheck_deps,
+  }
+)
+
+regress_tests += {
+  'name': 'passwordcheck',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'passwordcheck'
+  ],
+}
diff --git a/contrib/pg_buffercache/meson.build b/contrib/pg_buffercache/meson.build
new file mode 100644
index 00000000000..f4f540218b6
--- /dev/null
+++ b/contrib/pg_buffercache/meson.build
@@ -0,0 +1,16 @@
+pg_buffercache = shared_module('pg_buffercache',
+  files(
+    'pg_buffercache_pages.c',
+  ),
+  c_pch: '../../src/include/pch/postgres_pch.h',
+  kwargs: contrib_mod_args,
+)
+
+install_data(
+  'pg_buffercache--1.0--1.1.sql',
+  'pg_buffercache--1.1--1.2.sql',
+  'pg_buffercache--1.2--1.3.sql',
+  'pg_buffercache--1.2.sql',
+  'pg_buffercache.control',
+  kwargs: contrib_data_args,
+)
diff --git a/contrib/pg_freespacemap/meson.build \
b/contrib/pg_freespacemap/meson.build new file mode 100644
index 00000000000..feb1e225f48
--- /dev/null
+++ b/contrib/pg_freespacemap/meson.build
@@ -0,0 +1,15 @@
+pg_freespacemap = shared_module('pg_freespacemap',
+  files(
+    'pg_freespacemap.c',
+  ),
+  c_pch: '../../src/include/pch/postgres_pch.h',
+  kwargs: contrib_mod_args,
+)
+
+install_data(
+  'pg_freespacemap--1.0--1.1.sql',
+  'pg_freespacemap--1.1--1.2.sql',
+  'pg_freespacemap--1.1.sql',
+  'pg_freespacemap.control',
+  kwargs: contrib_data_args,
+)
diff --git a/contrib/pg_prewarm/meson.build b/contrib/pg_prewarm/meson.build
new file mode 100644
index 00000000000..c93ccc2db6d
--- /dev/null
+++ b/contrib/pg_prewarm/meson.build
@@ -0,0 +1,16 @@
+pg_prewarm = shared_module('pg_prewarm',
+  files(
+    'autoprewarm.c',
+    'pg_prewarm.c',
+  ),
+  c_pch: '../../src/include/pch/postgres_pch.h',
+  kwargs: contrib_mod_args,
+)
+
+install_data(
+  'pg_prewarm--1.0--1.1.sql',
+  'pg_prewarm--1.1--1.2.sql',
+  'pg_prewarm--1.1.sql',
+  'pg_prewarm.control',
+  kwargs: contrib_data_args,
+)
diff --git a/contrib/pg_stat_statements/meson.build \
b/contrib/pg_stat_statements/meson.build new file mode 100644
index 00000000000..6ed70ac0f18
--- /dev/null
+++ b/contrib/pg_stat_statements/meson.build
@@ -0,0 +1,31 @@
+pg_stat_statements = shared_module('pg_stat_statements',
+  files('pg_stat_statements.c'),
+  kwargs: contrib_mod_args + {
+      'dependencies': contrib_mod_args['dependencies'],
+  },
+)
+
+install_data(
+  'pg_stat_statements.control',
+  'pg_stat_statements--1.4.sql',
+  'pg_stat_statements--1.8--1.9.sql',
+  'pg_stat_statements--1.7--1.8.sql',
+  'pg_stat_statements--1.6--1.7.sql',
+  'pg_stat_statements--1.5--1.6.sql',
+  'pg_stat_statements--1.4--1.5.sql',
+  'pg_stat_statements--1.3--1.4.sql',
+  'pg_stat_statements--1.2--1.3.sql',
+  'pg_stat_statements--1.1--1.2.sql',
+  'pg_stat_statements--1.0--1.1.sql',
+  kwargs: contrib_data_args,
+)
+
+regress_tests += {
+  'name': 'pg_stat_statements',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'pg_stat_statements'
+  ],
+  'regress_args': ['--temp-config', files('pg_stat_statements.conf')],
+}
diff --git a/contrib/pg_surgery/meson.build b/contrib/pg_surgery/meson.build
new file mode 100644
index 00000000000..58de871b041
--- /dev/null
+++ b/contrib/pg_surgery/meson.build
@@ -0,0 +1,23 @@
+pg_surgery = shared_module('pg_surgery',
+  files(
+    'heap_surgery.c',
+  ),
+  c_pch: '../../src/include/pch/postgres_pch.h',
+  kwargs: contrib_mod_args,
+)
+
+install_data(
+  'pg_surgery--1.0.sql',
+  'pg_surgery.control',
+  kwargs: contrib_data_args,
+)
+
+
+regress_tests += {
+  'name': 'pg_surgery',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'heap_surgery'
+  ],
+}
diff --git a/contrib/pg_trgm/meson.build b/contrib/pg_trgm/meson.build
new file mode 100644
index 00000000000..0a56926ad6b
--- /dev/null
+++ b/contrib/pg_trgm/meson.build
@@ -0,0 +1,33 @@
+pg_trgm = shared_module('pg_trgm',
+  files(
+    'trgm_gin.c',
+    'trgm_gist.c',
+    'trgm_op.c',
+    'trgm_regexp.c',
+  ),
+  c_pch: '../../src/include/pch/postgres_pch.h',
+  kwargs: contrib_mod_args,
+)
+
+install_data(
+  'pg_trgm--1.0--1.1.sql',
+  'pg_trgm--1.1--1.2.sql',
+  'pg_trgm--1.2--1.3.sql',
+  'pg_trgm--1.3--1.4.sql',
+  'pg_trgm--1.3.sql',
+  'pg_trgm--1.4--1.5.sql',
+  'pg_trgm--1.5--1.6.sql',
+  'pg_trgm.control',
+  kwargs: contrib_data_args,
+)
+
+regress_tests += {
+  'name': 'pg_trgm',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'pg_trgm',
+    'pg_word_trgm',
+    'pg_strict_word_trgm',
+  ],
+}
diff --git a/contrib/pg_visibility/meson.build b/contrib/pg_visibility/meson.build
new file mode 100644
index 00000000000..5fd0e8cd986
--- /dev/null
+++ b/contrib/pg_visibility/meson.build
@@ -0,0 +1,25 @@
+pg_visibility = shared_module('pg_visibility',
+  files(
+    'pg_visibility.c',
+  ),
+  c_pch: '../../src/include/pch/postgres_pch.h',
+  kwargs: contrib_mod_args,
+)
+
+install_data(
+  'pg_visibility--1.0--1.1.sql',
+  'pg_visibility--1.1--1.2.sql',
+  'pg_visibility--1.1.sql',
+  'pg_visibility.control',
+  kwargs: contrib_data_args,
+)
+
+
+regress_tests += {
+  'name': 'pg_visibility',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'pg_visibility'
+  ],
+}
diff --git a/contrib/pgcrypto/meson.build b/contrib/pgcrypto/meson.build
new file mode 100644
index 00000000000..f20076b84a0
--- /dev/null
+++ b/contrib/pgcrypto/meson.build
@@ -0,0 +1,117 @@
+pgcrypto_sources = files(
+  'crypt-blowfish.c',
+  'crypt-des.c',
+  'crypt-gensalt.c',
+  'crypt-md5.c',
+  'mbuf.c',
+  'pgcrypto.c',
+  'pgp-armor.c',
+  'pgp-cfb.c',
+  'pgp-compress.c',
+  'pgp-decrypt.c',
+  'pgp-encrypt.c',
+  'pgp-info.c',
+  'pgp-mpi.c',
+  'pgp-pgsql.c',
+  'pgp-pubdec.c',
+  'pgp-pubenc.c',
+  'pgp-pubkey.c',
+  'pgp-s2k.c',
+  'pgp.c',
+  'px-crypt.c',
+  'px-hmac.c',
+  'px.c',
+)
+
+pgcrypto_regress = [
+  'init',
+  'md5',
+  'sha1',
+  'hmac-md5',
+  'hmac-sha1',
+  'blowfish',
+  'rijndael',
+  'crypt-des',
+  'crypt-md5',
+  'crypt-blowfish',
+  'crypt-xdes',
+  'pgp-armor',
+  'pgp-decrypt',
+  'pgp-encrypt',
+  'pgp-pubkey-decrypt',
+  'pgp-pubkey-encrypt',
+  'pgp-info',
+]
+
+
+pgcrypto_internal_sources = files(
+  'internal.c',
+  'internal-sha2.c',
+  'blf.c',
+  'rijndael.c',
+  'pgp-mpi-internal.c',
+  'imath.c',
+)
+
+pgcrypto_internal_regress = [
+  'sha2',
+]
+
+
+pgcrypto_openssl_sources = files(
+  'openssl.c',
+  'pgp-mpi-openssl.c',
+)
+pgcrypto_openssl_regress = [
+  'sha2',
+  'des',
+  '3des',
+  'cast5',
+]
+
+# TODO: implement rijndael.c generation
+
+pgcrypto_deps = []
+if ssl.found()
+  pgcrypto_deps += ssl
+  pgcrypto_sources += pgcrypto_openssl_sources
+  pgcrypto_regress += pgcrypto_openssl_regress
+else
+  pgcrypto_sources += pgcrypto_internal_sources
+  pgcrypto_regress += pgcrypto_internal_regress
+endif
+
+if zlib.found()
+  pgcrypto_deps += zlib
+  pgcrypto_regress += 'pgp-compression'
+else
+  pgcrypto_regress += 'pgp-zlib-DISABLED'
+endif
+
+pgcrypto = shared_module('pgcrypto',
+  pgcrypto_sources,
+  c_pch: '../../src/include/pch/postgres_pch.h',
+  kwargs: contrib_mod_args + {
+    'dependencies': [pgcrypto_deps, contrib_mod_args['dependencies']]
+  },
+)
+
+install_data(
+  'pgcrypto--1.0--1.1.sql',
+  'pgcrypto--1.1--1.2.sql',
+  'pgcrypto--1.2--1.3.sql',
+  'pgcrypto--1.3.sql',
+  'pgcrypto.control',
+  kwargs: contrib_data_args,
+)
+
+
+regress_tests += {
+  'name': 'pgcrypto',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    pgcrypto_regress
+  ],
+}
+
diff --git a/contrib/pgrowlocks/meson.build b/contrib/pgrowlocks/meson.build
new file mode 100644
index 00000000000..26c68248fce
--- /dev/null
+++ b/contrib/pgrowlocks/meson.build
@@ -0,0 +1,15 @@
+pgrowlocks = shared_module('pgrowlocks',
+  files(
+    'pgrowlocks.c',
+  ),
+  c_pch: '../../src/include/pch/postgres_pch.h',
+  kwargs: contrib_mod_args,
+)
+
+install_data(
+  'pgrowlocks--1.0--1.1.sql',
+  'pgrowlocks--1.1--1.2.sql',
+  'pgrowlocks--1.2.sql',
+  'pgrowlocks.control',
+  kwargs: contrib_data_args,
+)
diff --git a/contrib/pgstattuple/meson.build b/contrib/pgstattuple/meson.build
new file mode 100644
index 00000000000..4ed41b3743c
--- /dev/null
+++ b/contrib/pgstattuple/meson.build
@@ -0,0 +1,30 @@
+pgstattuple = shared_module('pgstattuple',
+  files(
+    'pgstatapprox.c',
+    'pgstatindex.c',
+    'pgstattuple.c',
+  ),
+  c_pch: '../../src/include/pch/postgres_pch.h',
+  kwargs: contrib_mod_args,
+)
+
+install_data(
+  'pgstattuple--1.0--1.1.sql',
+  'pgstattuple--1.1--1.2.sql',
+  'pgstattuple--1.2--1.3.sql',
+  'pgstattuple--1.3--1.4.sql',
+  'pgstattuple--1.4--1.5.sql',
+  'pgstattuple--1.4.sql',
+  'pgstattuple.control',
+  kwargs: contrib_data_args,
+)
+
+
+regress_tests += {
+  'name': 'pgstattuple',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'pgstattuple'
+  ],
+}
diff --git a/contrib/postgres_fdw/meson.build b/contrib/postgres_fdw/meson.build
new file mode 100644
index 00000000000..507d01448b1
--- /dev/null
+++ b/contrib/postgres_fdw/meson.build
@@ -0,0 +1,31 @@
+postgres_fdw_sources = files(
+  'connection.c',
+  'deparse.c',
+  'option.c',
+  'postgres_fdw.c',
+  'shippable.c',
+)
+
+postgres_fdw = shared_module('postgres_fdw',
+  postgres_fdw_sources,
+  kwargs: contrib_mod_args + {
+      'dependencies': pg_mod_args['dependencies'] + [libpq],
+  },
+)
+
+install_data(
+  'postgres_fdw.control',
+  'postgres_fdw--1.0.sql',
+  'postgres_fdw--1.0--1.1.sql',
+  kwargs: contrib_data_args,
+)
+
+regress_tests += {
+  'name': 'postgres_fdw',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'postgres_fdw'
+  ],
+  'regress_args': ['--dlpath', meson.build_root() / 'src/test/regress'],
+}
diff --git a/contrib/seg/meson.build b/contrib/seg/meson.build
new file mode 100644
index 00000000000..a66a4b4c218
--- /dev/null
+++ b/contrib/seg/meson.build
@@ -0,0 +1,40 @@
+seg_sources = files(
+  'seg.c',
+)
+
+# segscan is compiled as part of segparse
+segscan = custom_target('segscan',
+  input: ['segscan.l'],
+  output: ['segscan.c'],
+  command: [flex, '-o', '@OUTPUT@', '@INPUT@'])
+
+seg_sources += custom_target('segparse',
+  input: 'segparse.y',
+  output: 'segparse.c',
+  depends: segscan,
+  command: [bison, bisonflags, '-o', '@OUTPUT@', '@INPUT0@'])
+
+seg = shared_module('seg',
+  seg_sources,
+  include_directories: include_directories('.'),
+  kwargs: contrib_mod_args,
+)
+
+install_data(
+  'seg.control',
+  'seg--1.0--1.1.sql',
+  'seg--1.1--1.2.sql',
+  'seg--1.1.sql',
+  'seg--1.2--1.3.sql',
+  'seg--1.3--1.4.sql',
+  kwargs: contrib_data_args,
+)
+
+regress_tests += {
+  'name': 'seg',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'seg',
+  ],
+}
diff --git a/contrib/sepgsql/meson.build b/contrib/sepgsql/meson.build
new file mode 100644
index 00000000000..852c6740569
--- /dev/null
+++ b/contrib/sepgsql/meson.build
@@ -0,0 +1,34 @@
+if not selinux.found()
+  subdir_done()
+endif
+
+sepgsql_sources = files(
+  'database.c',
+  'dml.c',
+  'hooks.c',
+  'label.c',
+  'proc.c',
+  'relation.c',
+  'schema.c',
+  'selinux.c',
+  'uavc.c',
+)
+
+sepgsql = shared_module('sepgsql',
+  sepgsql_sources,
+  c_pch: '../../src/include/pch/postgres_pch.h',
+  kwargs: contrib_mod_args + {
+    'dependencies': [selinux, pg_mod_args['dependencies']],
+  }
+)
+
+custom_target('sepgsql.sql',
+  input: 'sepgsql.sql.in',
+  output: 'sepgsql.sql',
+  command: [sed, '-e', 's,MODULE_PATHNAME,$libdir/sepgsql,g', '@INPUT@'],
+  capture: true,
+  install: true,
+  install_dir: contrib_data_args['install_dir'],
+)
+
+# TODO: implement sepgsql tests
diff --git a/contrib/spi/meson.build b/contrib/spi/meson.build
new file mode 100644
index 00000000000..51bc96ea657
--- /dev/null
+++ b/contrib/spi/meson.build
@@ -0,0 +1,43 @@
+autoinc = shared_module('autoinc',
+  ['autoinc.c'],
+  kwargs: contrib_mod_args,
+)
+
+install_data('autoinc.control', 'autoinc--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+
+insert_username = shared_module('insert_username',
+  ['insert_username.c'],
+  kwargs: contrib_mod_args,
+)
+
+install_data('insert_username.control', 'insert_username--1.0.sql',
+  install_dir: get_option('datadir') / 'extension'
+)
+
+
+moddatetime = shared_module('moddatetime',
+  ['moddatetime.c'],
+  kwargs: contrib_mod_args,
+)
+
+install_data('moddatetime.control', 'moddatetime--1.0.sql',
+  install_dir: get_option('datadir') / 'extension'
+)
+
+# this is needed for the regression tests;
+# comment out if you want a quieter refint package for other uses
+refint_cflags = ['-DREFINT_VERBOSE']
+
+refint = shared_module('refint',
+  ['refint.c'],
+  kwargs: contrib_mod_args + {
+    'c_args': refint_cflags + contrib_mod_args['c_args'],
+  },
+)
+
+install_data('refint.control', 'refint--1.0.sql',
+  kwargs: contrib_data_args,
+)
diff --git a/contrib/sslinfo/meson.build b/contrib/sslinfo/meson.build
new file mode 100644
index 00000000000..27ee59d62d5
--- /dev/null
+++ b/contrib/sslinfo/meson.build
@@ -0,0 +1,21 @@
+if not ssl.found()
+  subdir_done()
+endif
+
+sslinfo = shared_module('sslinfo',
+  files(
+    'sslinfo.c',
+  ),
+  c_pch: '../../src/include/pch/postgres_pch.h',
+  kwargs: contrib_mod_args + {
+    'dependencies': [ssl, pg_mod_args['dependencies']],
+  }
+)
+
+install_data(
+  'sslinfo--1.0--1.1.sql',
+  'sslinfo--1.1--1.2.sql',
+  'sslinfo--1.2.sql',
+  'sslinfo.control',
+  kwargs: contrib_data_args,
+)
diff --git a/contrib/tablefunc/meson.build b/contrib/tablefunc/meson.build
new file mode 100644
index 00000000000..955b1ae6795
--- /dev/null
+++ b/contrib/tablefunc/meson.build
@@ -0,0 +1,23 @@
+tablefunc = shared_module('tablefunc',
+  files(
+    'tablefunc.c',
+  ),
+  c_pch: '../../src/include/pch/postgres_pch.h',
+  kwargs: contrib_mod_args,
+)
+
+install_data(
+  'tablefunc--1.0.sql',
+  'tablefunc.control',
+  kwargs: contrib_data_args,
+)
+
+
+regress_tests += {
+  'name': 'tablefunc',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'tablefunc'
+  ],
+}
diff --git a/contrib/tcn/meson.build b/contrib/tcn/meson.build
new file mode 100644
index 00000000000..b3a663f64bc
--- /dev/null
+++ b/contrib/tcn/meson.build
@@ -0,0 +1,13 @@
+tcn = shared_module('tcn',
+  files(
+    'tcn.c',
+  ),
+  c_pch: '../../src/include/pch/postgres_pch.h',
+  kwargs: contrib_mod_args,
+)
+
+install_data(
+  'tcn--1.0.sql',
+  'tcn.control',
+  kwargs: contrib_data_args,
+)
diff --git a/contrib/test_decoding/meson.build b/contrib/test_decoding/meson.build
new file mode 100644
index 00000000000..d26b43cbe79
--- /dev/null
+++ b/contrib/test_decoding/meson.build
@@ -0,0 +1,69 @@
+test_decoding_sources = files(
+  'test_decoding.c',
+)
+
+test_decoding = shared_module('test_decoding',
+  test_decoding_sources,
+  kwargs: contrib_mod_args,
+)
+
+
+regress_tests += {
+  'name': 'test_decoding',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'ddl',
+    'xact',
+    'rewrite',
+    'toast',
+    'permissions',
+    'decoding_in_xact',
+    'decoding_into_rel',
+    'binary',
+    'prepared',
+    'replorigin',
+    'time',
+    'messages',
+    'spill',
+    'slot',
+    'truncate',
+    'stream',
+    'stats',
+    'twophase',
+    'twophase_stream',
+  ],
+  'regress_args': [
+    '--temp-config', files('logical.conf')
+  ]
+}
+
+isolation_tests += {
+  'name': 'test_decoding',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'specs': [
+    'mxact',
+    'delayed_startup',
+    'ondisk_startup',
+    'concurrent_ddl_dml',
+    'oldest_xmin',
+    'snapshot_transfer',
+    'subxact_without_top',
+    'concurrent_stream',
+    'twophase_snapshot',
+  ],
+  'regress_args': [
+    '--temp-config', files('logical.conf')
+  ]
+}
+
+
+tap_tests += {
+  'name': 'test_decoding',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tests': [
+    't/001_repl_stats.pl',
+  ],
+}
diff --git a/contrib/tsm_system_rows/meson.build \
b/contrib/tsm_system_rows/meson.build new file mode 100644
index 00000000000..2c8f4487f8d
--- /dev/null
+++ b/contrib/tsm_system_rows/meson.build
@@ -0,0 +1,22 @@
+tsm_system_rows = shared_module('tsm_system_rows',
+  files(
+    'tsm_system_rows.c',
+  ),
+  c_pch: '../../src/include/pch/postgres_pch.h',
+  kwargs: contrib_mod_args,
+)
+
+install_data(
+  'tsm_system_rows--1.0.sql',
+  'tsm_system_rows.control',
+  kwargs: contrib_data_args,
+)
+
+regress_tests += {
+  'name': 'tsm_system_rows',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'tsm_system_rows',
+  ],
+}
diff --git a/contrib/tsm_system_time/meson.build \
b/contrib/tsm_system_time/meson.build new file mode 100644
index 00000000000..df9c4aa4b51
--- /dev/null
+++ b/contrib/tsm_system_time/meson.build
@@ -0,0 +1,22 @@
+tsm_system_time = shared_module('tsm_system_time',
+  files(
+    'tsm_system_time.c',
+  ),
+  c_pch: '../../src/include/pch/postgres_pch.h',
+  kwargs: contrib_mod_args,
+)
+
+install_data(
+  'tsm_system_time--1.0.sql',
+  'tsm_system_time.control',
+  kwargs: contrib_data_args,
+)
+
+regress_tests += {
+  'name': 'tsm_system_time',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'tsm_system_time',
+  ],
+}
diff --git a/contrib/unaccent/meson.build b/contrib/unaccent/meson.build
new file mode 100644
index 00000000000..e77bf790d8c
--- /dev/null
+++ b/contrib/unaccent/meson.build
@@ -0,0 +1,30 @@
+unaccent = shared_module('unaccent',
+  files(
+    'unaccent.c',
+  ),
+  c_pch: '../../src/include/pch/postgres_pch.h',
+  kwargs: contrib_mod_args,
+)
+
+install_data(
+  'unaccent--1.0--1.1.sql',
+  'unaccent--1.1.sql',
+  'unaccent.control',
+  kwargs: contrib_data_args,
+)
+
+install_data(
+  'unaccent.rules',
+   install_dir: get_option('datadir') / 'tsearch_data'
+)
+
+# XXX: Implement downlo
+regress_tests += {
+  'name': 'unaccent',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'unaccent',
+  ],
+  'regress_args': ['--encoding=UTF8'],
+}
diff --git a/contrib/uuid-ossp/meson.build b/contrib/uuid-ossp/meson.build
new file mode 100644
index 00000000000..dad1ec228bd
--- /dev/null
+++ b/contrib/uuid-ossp/meson.build
@@ -0,0 +1,31 @@
+if not uuid.found()
+  subdir_done()
+endif
+
+uuid_ossp = shared_module('uuid-ossp',
+  files(
+    'uuid-ossp.c',
+  ),
+  c_pch: '../../src/include/pch/postgres_pch.h',
+  kwargs: contrib_mod_args + {
+    'dependencies': [uuid, pg_mod_args['dependencies']],
+  },
+
+)
+
+install_data(
+  'uuid-ossp--1.0--1.1.sql',
+  'uuid-ossp--1.1.sql',
+  'uuid-ossp.control',
+  kwargs: contrib_data_args,
+)
+
+
+regress_tests += {
+  'name': 'uuid-ossp',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'uuid_ossp'
+  ],
+}
diff --git a/contrib/vacuumlo/meson.build b/contrib/vacuumlo/meson.build
new file mode 100644
index 00000000000..99e76daacf9
--- /dev/null
+++ b/contrib/vacuumlo/meson.build
@@ -0,0 +1,14 @@
+executable('vacuumlo',
+  ['vacuumlo.c'],
+  dependencies: [frontend_code, libpq],
+  kwargs: default_bin_args,
+)
+
+tap_tests += {
+  'name' : 'vacuumlo',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tests' :[
+    't/001_basic.pl',
+  ]
+}
diff --git a/contrib/xml2/meson.build b/contrib/xml2/meson.build
new file mode 100644
index 00000000000..6f8a26e4f0a
--- /dev/null
+++ b/contrib/xml2/meson.build
@@ -0,0 +1,30 @@
+if not libxml.found()
+  subdir_done()
+endif
+
+xml2 = shared_module('pgxml',
+  files(
+    'xpath.c',
+    'xslt_proc.c',
+  ),
+  c_pch: '../../src/include/pch/postgres_pch.h',
+  kwargs: contrib_mod_args + {
+    'dependencies': [libxml, libxslt, contrib_mod_args['dependencies']],
+  },
+)
+
+install_data(
+  'xml2--1.0--1.1.sql',
+  'xml2--1.1.sql',
+  'xml2.control',
+  kwargs: contrib_data_args,
+)
+
+regress_tests += {
+  'name': 'xml2',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'xml2',
+  ],
+}
diff --git a/conversion_helpers.txt b/conversion_helpers.txt
new file mode 100644
index 00000000000..e5879b4fe77
--- /dev/null
+++ b/conversion_helpers.txt
@@ -0,0 +1,6 @@
+convert list of files to quoted-one-per-line:
+
+	?\b\(\(?:\w\|\d\|_\|-\)+\)\.o ?\(?:\\
+\)? →   '\1.c',
+
+
diff --git a/doc/src/sgml/meson.build b/doc/src/sgml/meson.build
new file mode 100644
index 00000000000..4576e20a189
--- /dev/null
+++ b/doc/src/sgml/meson.build
@@ -0,0 +1,241 @@
+alldocs = []
+doc_generated = []
+
+xmllint = find_program('xmllint', native: true, required: false)
+pandoc = find_program('pandoc', native: true, required: false)
+xsltproc = find_program('xsltproc', native: true, required: false)
+fop = find_program('fop', native: true, required: false)
+
+
+configure_file(
+  input: 'version.sgml.in',
+  output: 'version.sgml',
+  configuration: cdata,
+)
+
+doc_generated += custom_target('features-supported.sgml',
+  input: files(
+    '../../../src/backend/catalog/sql_feature_packages.txt',
+    '../../../src/backend/catalog/sql_features.txt'),
+  output: 'features-supported.sgml',
+  command: [perl, files('mk_feature_tables.pl'), 'YES', '@INPUT@'],
+  build_by_default: false,
+  install: false,
+  capture: true)
+
+doc_generated += custom_target('features-unsupported.sgml',
+  input: files(
+    '../../../src/backend/catalog/sql_feature_packages.txt',
+    '../../../src/backend/catalog/sql_features.txt'),
+  output: 'features-unsupported.sgml',
+  command: [perl, files('mk_feature_tables.pl'), 'NO', '@INPUT@'],
+  build_by_default: false,
+  install: false,
+  capture: true)
+
+doc_generated += custom_target('errcodes-table.sgml',
+  input: files(
+    '../../../src/backend/utils/errcodes.txt'),
+  output: 'errcodes-table.sgml',
+  command: [perl, files('generate-errcodes-table.pl'), '@INPUT@'],
+  build_by_default: false,
+  install: false,
+  capture: true)
+
+# FIXME: this actually has further inputs, adding depfile support to
+# generate-keywords-table.pl is probably the best way to address that
+# robustly.
+doc_generated += custom_target('keywords-table.sgml',
+  input: files(
+    '../../../src/include/parser/kwlist.h'),
+  output: 'keywords-table.sgml',
+  command: [perl, files('generate-keywords-table.pl'), '@CURRENT_SOURCE_DIR@'],
+  build_by_default: false,
+  install: false,
+  capture: true)
+
+# For everything else we need at least xmllint
+if not xmllint.found()
+  subdir_done()
+endif
+
+# Compute validity just once
+postgres_sgml_valid = custom_target('postgres.sgml.valid',
+  input: 'postgres.sgml',
+  output: 'postgres.sgml.valid',
+  command: [xmllint, '--noout', '--valid', '--path', '@OUTDIR@'],
+  build_by_default: true,
+  capture: true,
+)
+alldocs += postgres_sgml_valid
+
+
+#
+# Full documentation as html, text
+#
+if xsltproc.found()
+  xsltproc_flags = [
+    '--stringparam', 'pg.version', pg_version,
+    '--param', 'website.stylesheet', '1'
+  ]
+
+
+  # FIXME: Should use a wrapper around xsltproc --load-trace to compute a
+  # depfile
+  html = custom_target('html',
+    input: ['stylesheet.xsl', 'postgres.sgml'],
+    output: 'html',
+    depends: doc_generated + [postgres_sgml_valid],
+    command: [xsltproc, '--path', '@OUTDIR@', '-o', '@OUTDIR@/', xsltproc_flags, \
'@INPUT@'], +    build_by_default: false,
+  )
+  alldocs += html
+
+
+  html_help = custom_target('html_help',
+    input: ['stylesheet-hh.xsl', 'postgres.sgml'],
+    output: 'htmlhelp',
+    depends: doc_generated + [postgres_sgml_valid],
+    command: [xsltproc, '--path', '@OUTDIR@', '-o', '@OUTDIR@/', xsltproc_flags, \
'@INPUT@'], +    build_by_default: false,
+  )
+  alldocs += html_help
+
+
+  # single-page HTML
+  postgres_html = custom_target('postgres.html',
+    input: ['stylesheet-html-nochunk.xsl', 'postgres.sgml'],
+    output: 'postgres.html',
+    depends: doc_generated + [postgres_sgml_valid],
+    command: [xsltproc, '--path', '@OUTDIR@', '-o', '@OUTPUT@', xsltproc_flags, \
'@INPUT@'], +    build_by_default: false,
+  )
+  alldocs += postgres_html
+
+  # single-page text
+  if pandoc.found()
+    postgres_txt = custom_target('postgres.txt',
+      input: [postgres_html],
+      output: 'postgres.txt',
+      depends: doc_generated + [postgres_sgml_valid],
+      command: [pandoc, '-t', 'plain', '-o', '@OUTPUT@', '@INPUT@'],
+      build_by_default: false,
+    )
+    alldocs += postgres_txt
+  endif
+endif
+
+
+#
+# INSTALL in html, text
+#
+if xsltproc.found()
+  install_xml = custom_target('INSTALL.xml',
+    input: ['standalone-profile.xsl', 'standalone-install.xml'],
+    output: 'INSTALL.xml',
+    depends: doc_generated + [postgres_sgml_valid],
+    command: [xsltproc, '--path', '@OUTDIR@', '-o', '@OUTPUT@', xsltproc_flags, \
'--xinclude', '@INPUT@'], +    build_by_default: false,
+  )
+  install_html = custom_target('INSTALL.html',
+    input: ['stylesheet-text.xsl', install_xml],
+    output: 'INSTALL.html',
+    depends: doc_generated + [postgres_sgml_valid],
+    command: [xsltproc, '--path', '@OUTDIR@', '-o', '@OUTPUT@', xsltproc_flags, \
'@INPUT@'], +    build_by_default: false,
+  )
+  alldocs += install_html
+
+  if pandoc.found()
+    # XXX: Makefile does an iconv translit here, but unclear why?
+    install = custom_target('INSTALL',
+      input: [install_html],
+      output: 'INSTALL',
+      depends: doc_generated + [postgres_sgml_valid],
+      command: [pandoc, '-t', 'plain', '-o', '@OUTPUT@', '@INPUT@'],
+      build_by_default: false,
+    )
+    alldocs += postgres_txt
+  endif
+
+endif
+
+
+#
+# Man pages
+#
+if xsltproc.found()
+  # FIXME: implement / consider sqlmansectnum logic
+  man = custom_target('man',
+    input: ['stylesheet-man.xsl', 'postgres.sgml'],
+    output: ['man1', 'man3', 'man7'],
+    depends: doc_generated + [postgres_sgml_valid],
+    command: [xsltproc, '--path', '@OUTDIR@', '-o', '@OUTDIR@', xsltproc_flags, \
'@INPUT@'], +    build_by_default: false,
+  )
+endif
+
+
+#
+# Full documentation as PDF
+#
+if fop.found() and xsltproc.found()
+  xsltproc_fo_flags = xsltproc_flags + ['--stringparam', 'img.src.path', \
meson.current_source_dir() + '/'] +
+  foreach format, detail: {'A4': 'A4', 'US': 'USletter'}
+    postgres_x_fo_f = 'postgres-@0@.fo'.format(format)
+    postgres_x_pdf_f = 'postgres-@0@.pdf'.format(format)
+
+    postgres_x_fo = custom_target(postgres_x_fo_f,
+      input: ['stylesheet-fo.xsl', 'postgres.sgml'],
+      output: [postgres_x_fo_f],
+      depends: doc_generated + [postgres_sgml_valid],
+      command: [xsltproc, '--path', '@OUTDIR@/', xsltproc_fo_flags,
+                '--stringparam', 'paper.type', detail,
+                '-o', '@OUTPUT@', '@INPUT@'],
+      build_by_default: false,
+    )
+
+    postgres_x_pdf = custom_target(postgres_x_pdf_f,
+      input: [postgres_x_fo],
+      output: [postgres_x_pdf_f],
+      command: [fop, '-fo', '@INPUT@', '-pdf', '@OUTPUT@'],
+      build_by_default: false,
+    )
+    alldocs += postgres_x_pdf
+  endforeach
+endif
+
+
+#
+# epub
+#
+
+# This was previously implemented using dbtoepub - but that doesn't seem to
+# support running in build != source directory (i.e. VPATH builds already
+# weren't supported).
+if pandoc.found() and xsltproc.found()
+  # XXX: Wasn't able to make pandoc successfully resolve entities
+  # XXX: Perhaps we should just make all targets use this, to avoid repeatedly
+  # building whole thing? It's comparatively fast though.
+  postgres_full_xml = custom_target('postgres-full.xml',
+    input: ['resolv.xsl', 'postgres.sgml'],
+    output: ['postgres-full.xml'],
+    depends: doc_generated + [postgres_sgml_valid],
+    command: [xsltproc, '--path', '@OUTDIR@/', xsltproc_flags,
+              '-o', '@OUTPUT@', '@INPUT@'],
+    build_by_default: false,
+  )
+
+  postgres_epub = custom_target('postgres.epub',
+    input: [postgres_full_xml],
+    output: 'postgres.epub',
+    command: [pandoc, '-f', 'docbook', '-t', 'epub', '-o', '@OUTPUT@', \
'--resource-path=@CURRENT_SOURCE_DIR@', +              '@INPUT@'],
+    build_by_default: false,
+  )
+  alldocs += postgres_epub
+endif
+
+
+alias_target('alldocs', alldocs)
diff --git a/doc/src/sgml/resolv.xsl b/doc/src/sgml/resolv.xsl
new file mode 100644
index 00000000000..c69ba714dab
--- /dev/null
+++ b/doc/src/sgml/resolv.xsl
@@ -0,0 +1,7 @@
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+  <xsl:template match="@*|node()">
+    <xsl:copy>
+      <xsl:apply-templates select="@*|node()"/>
+    </xsl:copy>
+  </xsl:template>
+</xsl:stylesheet>
diff --git a/doc/src/sgml/version.sgml.in b/doc/src/sgml/version.sgml.in
new file mode 100644
index 00000000000..fa5ff343f40
--- /dev/null
+++ b/doc/src/sgml/version.sgml.in
@@ -0,0 +1,2 @@
+<!ENTITY version @PG_VERSION@>
+<!ENTITY majorversion @PG_MAJORVERSION@>
diff --git a/meson.build b/meson.build
new file mode 100644
index 00000000000..4cf621f375b
--- /dev/null
+++ b/meson.build
@@ -0,0 +1,2130 @@
+project('postgresql',
+  ['c'],
+  version: '15devel',
+  license: 'PostgreSQL',
+  meson_version: '>=0.54',
+  default_options: [
+    'warning_level=2',
+    'b_pie=true',
+    'b_pch=false',
+    'buildtype=release',
+  ]
+)
+
+
+
+###############################################################
+# Basic prep
+###############################################################
+
+fs = import('fs')
+windows = import('windows')
+
+thread_dep = dependency('threads')
+
+cpu_family = host_machine.cpu_family()
+
+
+# It's very easy to get into confusing states when the source directory
+# contains an in-place build. E.g. the wrong pg_config.h will be used. So just
+# refuse to build in that case.
+if fs.exists(meson.current_source_dir() / 'src' / 'include' / 'pg_config.h')
+  error('''
+****
+Non-clean source code directory detected.
+
+To build with meson the source tree may not have an in-place, ./configure
+style, build configured. Use a separate check out for meson based builds, or
+run make distclean in the source tree.
+
+You can have both meson and ./configure style builds for the same source tree
+by building out-of-source / VPATH with configure as well.
+****
+''')
+endif
+
+
+
+###############################################################
+# Version and other metadata
+###############################################################
+
+pg_version = meson.project_version()
+
+if pg_version.endswith('devel')
+  pg_version_arr = [pg_version.split('devel')[0], '0']
+elif pg_version.contains('beta')
+  pg_version_arr = pg_version.split('beta')
+elif pg_version.contains('rc')
+  pg_version_arr = pg_version.split('rc')
+else
+  pg_version_arr = pg_version.split('.')
+endif
+
+pg_version_major = pg_version_arr[0].to_int()
+pg_version_minor = pg_version_arr[1].to_int()
+
+cc = meson.get_compiler('c')
+
+cdata = configuration_data()
+
+
+cdata.set_quoted('PACKAGE_NAME', 'PostgreSQL')
+cdata.set_quoted('PACKAGE_BUGREPORT', 'pgsql-bugs@lists.postgresql.org')
+cdata.set_quoted('PACKAGE_URL', 'https://www.postgresql.org/')
+
+cdata.set_quoted('PG_VERSION', pg_version)
+cdata.set_quoted('PG_VERSION_STR', 'PostgreSQL @0@ on @1@, compiled by \
@2@-@3@'.format( +  pg_version, target_machine.cpu_family(), cc.get_id(), \
cc.version())) +cdata.set_quoted('PG_MAJORVERSION', pg_version_major.to_string())
+cdata.set('PG_MAJORVERSION_NUM', pg_version_major)
+cdata.set_quoted('PG_MINORVERSION', pg_version_minor.to_string())
+cdata.set('PG_MINORVERSION_NUM', pg_version_minor)
+cdata.set('PG_VERSION_NUM', (pg_version_major*10000)+pg_version_minor)
+cdata.set_quoted('CONFIGURE_ARGS', '')
+
+
+
+###############################################################
+# Search paths
+#
+# NB: Arguments added globally (via the below, or CFLAGS etc) are not taken
+# into account for configuration-time checks (so they are more
+# isolated). Flags that have to be taken into account for configure checks
+# have to be explicitly specified in configure tests.
+###############################################################
+
+g_inc = []
+g_c_args = []
+g_l_args = []
+
+if host_machine.system() == 'darwin'
+  # XXX, should this be required?
+  xcrun = find_program('xcrun', native: true, required: true)
+
+  sysroot = run_command(xcrun, '--show-sdk-path', check: true).stdout().strip()
+  message('sysroot is >@0@<'.format(sysroot))
+
+  g_c_args += ['-isysroot', sysroot]
+  g_l_args += ['-isysroot', sysroot]
+endif
+
+if host_machine.system() == 'linux' or host_machine.system() == 'cygwin'
+  g_c_args += '-D_GNU_SOURCE'
+endif
+
+g_c_inc = []
+
+g_c_inc += include_directories(get_option('extra_include_dirs'))
+g_c_lib = get_option('extra_lib_dirs')
+
+add_project_arguments(g_c_args, language: ['c', 'cpp'])
+add_project_link_arguments(g_l_args, language: ['c', 'cpp'])
+
+
+
+###############################################################
+# Program paths
+###############################################################
+
+# External programs
+perl = find_program(get_option('PERL'), required: true)
+flex = find_program(get_option('FLEX'), native: true)
+bison = find_program(get_option('BISON'), native: true, version: '>= 1.875')
+sed = find_program(get_option('SED'), 'sed', native: true)
+prove = find_program(get_option('PROVE'))
+tar = find_program(get_option('TAR'), native: true)
+gzip = find_program(get_option('GZIP'), native: true)
+touch = find_program('touch', native: true)
+
+# Internal programs
+find_meson = find_program('src/tools/find_meson', native: true)
+testwrap = find_program('src/tools/testwrap', native: true)
+relpath = find_program('src/tools/relpath.py', native: true)
+
+bisonflags = []
+if bison.found()
+  bison_version_c = run_command(bison, '--version', check: true)
+  # bison version string helpfully is something like
+  # >>bison (GNU bison) 3.8.1<<
+  bison_version = bison_version_c.stdout().split(' ')[3].split('\n')[0]
+  if bison_version.version_compare('>=3.0')
+    bisonflags += ['-Wno-deprecated']
+  endif
+endif
+
+
+wget = find_program('wget', required: false, native: true)
+wget_flags = ['-O', '@OUTPUT0@', '--no-use-server-timestamps']
+
+
+###############################################################
+# Path to meson (for tests etc)
+###############################################################
+
+# FIXME: this should really be part of meson, see
+# https://github.com/mesonbuild/meson/issues/8511
+meson_binpath_r = run_command(find_meson, check: true)
+
+if meson_binpath_r.returncode() != 0 or meson_binpath_r.stdout() == ''
+  error('huh, could not run find_meson.\nerrcode: @0@\nstdout: @1@\nstderr: \
@2@'.format( +    meson_binpath_r.returncode(),
+    meson_binpath_r.stdout(),
+    meson_binpath_r.stderr()))
+endif
+
+meson_binpath_s = meson_binpath_r.stdout().split('\n')
+meson_binpath_len = meson_binpath_s.length()
+
+if meson_binpath_len < 1
+  error('unexpected introspect line @0@'.format(meson_binpath_r.stdout()))
+endif
+
+i = 0
+meson_binpath = ''
+meson_args = []
+foreach e : meson_binpath_s
+  if i == 0
+    meson_binpath = e
+  else
+    meson_args += e
+  endif
+  i += 1
+endforeach
+
+meson_bin = find_program(meson_binpath, native: true)
+
+
+
+###############################################################
+# Option Handling
+###############################################################
+
+cdata.set('USE_ASSERT_CHECKING', get_option('cassert'))
+
+cdata.set('BLCKSZ', 8192, description: '''
+ Size of a disk block --- this also limits the size of a tuple.  You
+ can set it bigger if you need bigger tuples (although TOAST should
+ reduce the need to have large tuples, since fields can be spread
+ across multiple tuples).
+
+ BLCKSZ must be a power of 2.  The maximum possible value of BLCKSZ
+ is currently 2^15 (32768).  This is determined by the 15-bit widths
+ of the lp_off and lp_len fields in ItemIdData (see
+ include/storage/itemid.h).
+
+ Changing BLCKSZ requires an initdb.
+''')
+
+cdata.set('XLOG_BLCKSZ', 8192)
+cdata.set('RELSEG_SIZE', 131072)
+cdata.set('DEF_PGPORT', 5432)
+cdata.set_quoted('DEF_PGPORT_STR', '5432')
+cdata.set_quoted('PG_KRB_SRVNAM', 'postgres')
+
+
+
+###############################################################
+# Library: GSSAPI
+###############################################################
+
+gssapiopt = get_option('gssapi')
+if not gssapiopt.disabled()
+  gssapi = dependency('krb5-gssapi', required: gssapiopt)
+
+  if gssapi.found() and \
+    cc.check_header('gssapi/gssapi.h', args: g_c_args, dependencies: gssapi, \
required: gssapiopt) +
+    if not cc.has_function('gss_init_sec_context', args: g_c_args, dependencies: \
gssapi) +      error('''could not find function 'gss_init_sec_context' required for \
GSSAPI''') +    endif
+    cdata.set('ENABLE_GSS', 1)
+  endif
+
+else
+  gssapi = dependency('', required : false)
+endif
+
+
+
+###############################################################
+# Library: ldap
+###############################################################
+
+ldapopt = get_option('ldap')
+if not ldapopt.disabled()
+
+  if host_machine.system() == 'windows'
+    ldap = cc.find_library('wldap32')
+    ldap_r = ldap
+  else
+    ldap = dependency('ldap', required: false)
+
+    # Before 2.5 openldap didn't have a pkg-config file..
+    if ldap.found()
+      ldap_r = ldap
+    else
+      ldap = cc.find_library('ldap', required: ldapopt)
+      ldap_r = cc.find_library('ldap_r', required: ldapopt)
+
+      # Use ldap_r for FE if available, else assume ldap is thread-safe.
+      # On some platforms ldap_r fails to link without PTHREAD_LIBS.
+      if ldap.found() and not ldap_r.found()
+        ldap_r = ldap
+      endif
+    endif
+
+    if ldap.found() and cc.has_function('ldap_initialize', args: g_c_args, \
dependencies: [ldap, thread_dep]) +      cdata.set('HAVE_LDAP_INITIALIZE', 1)
+    endif
+  endif
+
+  if ldap.found()
+    cdata.set('USE_LDAP', 1)
+  endif
+
+else
+  ldap = dependency('', required : false)
+  ldap_r = ldap
+endif
+
+
+
+###############################################################
+# Library: LLVM
+###############################################################
+
+llvmopt = get_option('llvm')
+if not llvmopt.disabled()
+  add_languages('cpp', required : true, native: false)
+  llvm = dependency('llvm', version : '>=3.9', method: 'config-tool', required: \
llvmopt) +
+  if llvm.found()
+
+    cdata.set('USE_LLVM', 1)
+
+    cpp = meson.get_compiler('cpp')
+
+    llvm_binpath = llvm.get_variable(configtool: 'bindir')
+
+    ccache = find_program('ccache', required: false)
+    clang = find_program(llvm_binpath / 'clang', required: true)
+    llvm_lto = find_program(llvm_binpath / 'llvm-lto', required: true)
+
+    # FIXME: the includes hardcoded here suck
+    llvm_irgen_args = [
+      '-c', '-o', '@OUTPUT@', '@INPUT@',
+      '-flto=thin', '-emit-llvm',
+      '-MD', '-MQ', '@OUTPUT@', '-MF', '@DEPFILE@',
+      '-I', '@SOURCE_ROOT@/src/include',
+      '-I', '@BUILD_ROOT@/src/include',
+      '-I', '@BUILD_ROOT@/src/backend/utils/misc',
+      '-I', '@CURRENT_SOURCE_DIR@',
+      '-O2',
+      '-Wno-ignored-attributes',
+      '-Wno-empty-body',
+    ]
+
+    if ccache.found()
+      llvm_irgen_command = ccache
+      llvm_irgen_args = [clang.path()] + llvm_irgen_args
+    else
+      llvm_irgen_command = clang
+    endif
+
+    llvm_irgen_kw = {
+      'command': [llvm_irgen_command] + llvm_irgen_args,
+      'depfile': '@BASENAME@.c.bc.d',
+    }
+
+    irlink = find_program('src/tools/irlink', native: true)
+
+    llvm_irlink_kw = {
+      'command':[
+        irlink,
+        '@SOURCE_ROOT@',
+        '@BUILD_ROOT@',
+        llvm_lto,
+        '-o', '@OUTPUT0@',
+        '@PRIVATE_DIR@',
+        '@INPUT@',
+      ],
+      'install': true,
+      'install_dir': get_option('libdir'),
+    }
+
+  endif
+else
+  llvm = dependency('', required: false)
+endif
+
+
+
+###############################################################
+# Library: icu
+###############################################################
+
+if not get_option('icu').disabled()
+  icu = dependency('icu-uc', required: get_option('icu').enabled())
+  icu_i18n = dependency('icu-i18n', required: get_option('icu').enabled())
+
+  if icu.found()
+    cdata.set('USE_ICU', 1)
+  endif
+
+else
+  icu = dependency('', required : false)
+  icu_i18n = dependency('', required : false)
+endif
+
+
+
+###############################################################
+# Library: libxml
+###############################################################
+
+libxmlopt = get_option('libxml')
+if not libxmlopt.disabled()
+  libxml = dependency('libxml-2.0', required: libxmlopt, version: '>= 2.6.23')
+
+  if libxml.found()
+    cdata.set('USE_LIBXML', 1)
+  endif
+else
+  libxml = dependency('', required : false)
+endif
+
+
+
+###############################################################
+# Library: libxslt
+###############################################################
+
+libxsltopt = get_option('libxslt')
+if not libxsltopt.disabled()
+  libxslt = dependency('libxslt', required: libxsltopt)
+
+  if libxslt.found()
+    cdata.set('USE_LIBXSLT', 1)
+  endif
+else
+  libxslt = dependency('', required : false)
+endif
+
+
+
+###############################################################
+# Library: lz4
+###############################################################
+
+lz4opt = get_option('lz4')
+if not lz4opt.disabled()
+  lz4 = dependency('liblz4', required: lz4opt)
+
+  if lz4.found()
+    cdata.set('USE_LZ4', 1)
+    cdata.set('HAVE_LIBLZ4', 1)
+  endif
+
+else
+  lz4 = dependency('', required : false)
+endif
+
+
+
+###############################################################
+# Library: Perl (for plperl)
+###############################################################
+
+perlopt = get_option('perl')
+perl_dep = dependency('', required: false)
+
+if perlopt.disabled()
+  perl_may_work = false
+else
+  perl_may_work = true
+
+  # First verify that perl has the necessary dependencies installed
+  perl_mods = run_command(
+    [perl,
+     '-MConfig', '-MOpcode', '-MExtUtils::Embed', '-MExtUtils::ParseXS',
+     '-e', ''],
+    check: false)
+  if perl_mods.returncode() != 0
+    perl_may_work = false
+    perl_msg = 'perl installation does not have the required modules'
+  endif
+
+  # Then inquire perl about its configuration
+  if perl_may_work
+    # FIXME: include copy-edited comments from perl.m4
+    perl_conf_cmd = [perl, '-MConfig', '-e', 'print $Config{$ARGV[0]}']
+    perlversion = run_command(perl_conf_cmd, 'api_versionstring', check: \
true).stdout() +    archlibexp = run_command(perl_conf_cmd, 'archlibexp', check: \
true).stdout() +    privlibexp = run_command(perl_conf_cmd, 'privlibexp', check: \
true).stdout() +    useshrplib = run_command(perl_conf_cmd, 'useshrplib', check: \
true).stdout() +    libperl = run_command(perl_conf_cmd, 'libperl', check: \
true).stdout() +
+    perl_inc_dir = '@0@/CORE'.format(archlibexp)
+
+    perl_ccflags = []
+
+    if useshrplib != 'true'
+      perl_may_work = false
+      perl_msg = 'need a shared perl'
+    endif
+  endif
+
+  # XXX: should we only add directories that exist? Seems a bit annoying with
+  # macos' sysroot stuff...
+  #
+  # NB: For unknown reasons msys' python doesn't see these paths, despite gcc
+  # et al seeing them. So we can't use include_directories(), as that checks
+  # file existence.
+  if perl_may_work
+    perl_ccflags += ['-I@0@'.format(perl_inc_dir)]
+    if host_machine.system() == 'darwin'
+      perl_ccflags += ['-iwithsysroot', perl_inc_dir]
+    endif
+  endif
+
+  # check required headers are present
+  if perl_may_work and not \
+    cc.has_header('perl.h', args: g_c_args + perl_ccflags, required: false)
+    perl_may_work = false
+    perl_msg = 'missing perl.h'
+  endif
+
+  # Find perl library. This is made more complicated by the fact that the name
+  # Config.pm returns isn't directly usable (sometimes lib needs to be chopped
+  # off)
+  if perl_may_work
+    foreach p : ['perl', 'libperl', libperl, libperl.strip('lib'), fs.stem(libperl), \
fs.stem(libperl).strip('lib')] +      perl_dep_int = cc.find_library(p,
+        dirs: ['@0@/CORE'.format(archlibexp)],
+        required: false)
+      if perl_dep_int.found()
+        break
+      endif
+    endforeach
+
+    if not perl_dep_int.found()
+      perl_may_work = false
+      perl_msg = 'missing libperl'
+    endif
+  endif
+
+  if perl_may_work
+    perl_ccflags_r = run_command(perl_conf_cmd, 'ccflags', check: true).stdout()
+    message('CCFLAGS recommended by Perl: @0@'.format(perl_ccflags_r))
+
+    foreach flag : perl_ccflags_r.split(' ')
+      if flag.startswith('-D') and \
+        (not flag.startswith('-D_') or flag == '_USE_32BIT_TIME_T')
+        perl_ccflags += flag
+      endif
+    endforeach
+
+    if host_machine.system() == 'windows'
+      perl_ccflags += ['-DPLPERL_HAVE_UID_GID']
+    endif
+
+    message('CCFLAGS for embedding perl: @0@'.format(' '.join(perl_ccflags)))
+
+    # perl.m4 sayeth:
+    #
+    # We are after Embed's ldopts, but without the subset mentioned in
+    # Config's ccdlflags;
+    #
+    # FIXME: andres sayeth: But why?
+
+    ldopts = run_command(perl, '-MExtUtils::Embed', '-e', 'ldopts', check: \
true).stdout().strip() +    ccdlflags = run_command(perl_conf_cmd, 'ccdlflags', \
check: true).stdout().strip() +
+    ccdlflags_dict = {}
+
+    foreach ccdlflag : ccdlflags.split(' ')
+      ccdlflags_dict += {ccdlflag: 1}
+    endforeach
+
+    perl_ldopts = []
+    foreach ldopt : ldopts.split(' ')
+      if ldopt == ''
+        continue
+      elif ccdlflags_dict.has_key(ldopt)
+        continue
+      # strawberry perl unhelpfully has that in ldopts
+      elif ldopt == '-s'
+        continue
+      endif
+
+      perl_ldopts += ldopt.strip('"')
+    endforeach
+
+    # FIXME: check if windows handling is necessary
+
+    message('LDFLAGS for embedding perl: "@0@" (ccdlflags: "@1@", ldopts: \
"@2@")'.format( +      ' '.join(perl_ldopts), ccdlflags, ldopts))
+
+    if perl_dep_int.found()
+      perl_dep = declare_dependency(
+        compile_args: perl_ccflags,
+        link_args: perl_ldopts,
+        version: perlversion,
+      )
+    endif
+  endif # perl_may_work
+
+  if not perl_may_work
+    if perlopt.enabled()
+      error('dependency perl failed: @0@'.format(perl_msg))
+    else
+      message('disabling optional dependency perl: @0@'.format(perl_msg))
+    endif
+  endif
+endif
+
+
+
+###############################################################
+# Library: Python (for plpython)
+###############################################################
+
+pyopt = get_option('python')
+if not pyopt.disabled()
+  pm = import('python')
+  python3_inst = pm.find_installation(required: pyopt.enabled())
+  python3 = python3_inst.dependency(embed: true, required: pyopt.enabled())
+else
+  python3 = dependency('', required: false)
+endif
+
+
+
+###############################################################
+# Library: Readline
+#
+# FIXME: editline support
+###############################################################
+
+if not get_option('readline').disabled()
+  readline = dependency('readline', required: false)
+  if not readline.found()
+    readline = cc.find_library('readline',
+      required: get_option('readline').enabled())
+  endif
+
+  if readline.found()
+    cdata.set('HAVE_LIBREADLINE', 1)
+
+    if cc.has_header('readline/history.h', args: g_c_args, dependencies: [readline], \
required: false) +      history_h = 'readline/history.h'
+      cdata.set('HAVE_READLINE_HISTORY_H', 1)
+      cdata.set('HAVE_READLINE_H', false)
+    elif cc.has_header('history.h', args: g_c_args, dependencies: [readline], \
required: false) +      history_h = 'history.h'
+      cdata.set('HAVE_READLINE_HISTORY_H', false)
+      cdata.set('HAVE_HISTORY_H', 1)
+    else
+      error('''readline header not found
+If you have readline already installed, see see meson-log/meson-log.txt for details \
on the +failure.  It is possible the compiler isn't looking in the proper directory.
+Use -Dreadline=false to disable readline support.''')
+    endif
+
+    if cc.has_header('readline/readline.h', args: g_c_args, dependencies: \
[readline], required: false) +      readline_h = 'readline/readline.h'
+      cdata.set('HAVE_READLINE_READLINE_H', 1)
+    elif cc.has_header('readline.h', args: g_c_args, dependencies: [readline], \
required: false) +      readline_h = 'readline.h'
+      cdata.set('HAVE_READLINE_H', 1)
+    else
+      error('''readline header not found
+If you have readline already installed, see see meson-log/meson-log.txt for details \
on the +failure.  It is possible the compiler isn't looking in the proper directory.
+Use -Dreadline=false to disable readline support.''')
+    endif
+
+    check_funcs = [
+      'rl_completion_matches',
+      'rl_filename_completion_function',
+      'rl_reset_screen_size',
+      'append_history',
+      'history_truncate_file',
+    ]
+
+    foreach func : check_funcs
+      cdata.set('HAVE_'+func.to_upper(),
+        cc.has_function(func, args: g_c_args, dependencies: [readline]) ? 1 : false)
+    endforeach
+
+    check_vars = [
+      'rl_completion_append_character',
+      'rl_completion_suppress_quote',
+      'rl_filename_quote_characters',
+      'rl_filename_quoting_function',
+    ]
+
+    foreach var : check_vars
+      cdata.set('HAVE_'+var.to_upper(),
+        cc.has_header_symbol(readline_h, var, args: g_c_args, dependencies: \
[readline]) ? 1 : false) +    endforeach
+  endif
+else
+  readline = dependency('', required : false)
+endif
+
+
+
+###############################################################
+# Library: selinux
+###############################################################
+
+selinux = dependency('', required : false)
+selinuxopt = get_option('selinux')
+if not selinuxopt.disabled()
+  selinux = dependency('libselinux', required: selinuxopt, version: '>= 2.1.10')
+endif
+cdata.set('HAVE_LIBSELINUX',
+  selinux.found() ? 1 : false)
+
+
+
+###############################################################
+# Library: systemd
+###############################################################
+
+systemd = dependency('', required : false)
+systemdopt = get_option('systemd')
+if meson.version().version_compare('>=0.59')
+  systemdopt = systemdopt.disable_auto_if(host_machine.system() != 'linux')
+endif
+if not systemdopt.disabled()
+  systemd = dependency('libsystemd', required: systemdopt)
+endif
+cdata.set('USE_SYSTEMD',
+  systemd.found() ? 1 : false)
+
+
+
+###############################################################
+# Library: SSL
+###############################################################
+
+if get_option('ssl') == 'openssl'
+
+  # Try to find openssl via pkg-config et al, if that doesn't work, look for
+  # the library names that we know about.
+
+  # via pkg-config et al
+  ssl = dependency('openssl', required: false)
+
+  # via library + headers
+  if not ssl.found()
+    ssl_lib = cc.find_library('ssl',
+      dirs: g_c_lib,
+      header_include_directories: g_c_inc,
+      has_headers: ['openssl/ssl.h', 'openssl/err.h'])
+    crypto_lib = cc.find_library('crypto',
+      dirs: g_c_lib,
+      header_include_directories: g_c_inc)
+    ssl_int = [ssl_lib, crypto_lib]
+
+    ssl = declare_dependency(dependencies: ssl_int,
+                             include_directories: g_c_inc)
+  else
+    cc.has_header('openssl/ssl.h', args: g_c_args, dependencies: ssl, required: \
true) +    cc.has_header('openssl/err.h', args: g_c_args, dependencies: ssl, \
required: true) +
+    ssl_int = [ssl]
+  endif
+
+  cdata.set_quoted('WITH_SSL', get_option('ssl'))
+
+  check_funcs = [
+    ['CRYPTO_new_ex_data', {'required': true}],
+    ['SSL_new', {'required': true}],
+
+    # Function introduced in OpenSSL 1.0.2.
+    ['X509_get_signature_nid'],
+
+    # Functions introduced in OpenSSL 1.1.0. We used to check for
+    # OPENSSL_VERSION_NUMBER, but that didn't work with 1.1.0, because LibreSSL
+    # defines OPENSSL_VERSION_NUMBER to claim version 2.0.0, even though it
+    # doesn't have these OpenSSL 1.1.0 functions. So check for individual
+    # functions.
+    ['OPENSSL_init_ssl'],
+    ['BIO_get_data'],
+    ['BIO_meth_new'],
+    ['ASN1_STRING_get0_data'],
+    ['HMAC_CTX_new'],
+    ['HMAC_CTX_free'],
+
+    # OpenSSL versions before 1.1.0 required setting callback functions, for
+    # thread-safety. In 1.1.0, it's no longer required, and CRYPTO_lock()
+    # function was removed.
+    ['CRYPTO_lock'],
+  ]
+
+  foreach c : check_funcs
+    func = c.get(0)
+    val = cc.has_function(func, args: g_c_args, dependencies: ssl_int)
+    if not val and c.get(1, {}).get('required', false)
+      error('openssl function @0@ is required'.format(func))
+    endif
+    cdata.set('HAVE_'+func.to_upper(), val ? 1 : false)
+  endforeach
+
+  cdata.set('USE_OPENSSL', 1,
+            description: 'Define to 1 to build with OpenSSL support. \
(-Dssl=openssl)') +
+  cdata.set('OPENSSL_API_COMPAT', 0x10001000,
+            description: 'Define to the OpenSSL API version in use. This avoids \
deprecation warnings from newer OpenSSL versions.') +else
+  ssl = dependency('', required : false)
+endif
+
+
+
+###############################################################
+# Library: uuid
+###############################################################
+
+uuidopt = get_option('uuid')
+if uuidopt != 'none'
+  uuidname = uuidopt.to_upper()
+  if uuidopt == 'e2fs'
+    uuid = dependency('uuid', required: true)
+    uuidfunc = 'uuid_generate'
+    uuidheader = 'uuid/uuid.h'
+  elif uuidopt == 'bsd'
+    # libc should have uuid function
+    uuid = declare_dependency()
+    uuidfunc = 'uuid_to_string'
+    uuidheader = 'uuid.h'
+  elif uuidopt == 'ossp'
+    uuid = dependency('ossp-uuid', required: true)
+    uuidfunc = 'uuid_export'
+    uuidheader = 'ossp/uuid.h'
+  else
+    error('huh')
+  endif
+
+  if not cc.has_header_symbol(uuidheader, uuidfunc, dependencies: uuid)
+    error('uuid library @0@ missing required function @1@'.format(uuidopt, \
uuidfunc)) +  endif
+  cdata.set('HAVE_@0@'.format(uuidheader.underscorify().to_upper()), 1)
+
+  cdata.set('HAVE_UUID_@0@'.format(uuidname), 1,
+           description: 'Define to 1 if you have @0@ UUID \
support.'.format(uuidname)) +else
+  uuid = dependency('', required : false)
+endif
+
+
+
+###############################################################
+# Library: zlib
+###############################################################
+
+zlibopt = get_option('zlib')
+zlib = dependency('', required : false)
+if not zlibopt.disabled()
+  zlib_t = dependency('zlib', required: zlibopt)
+
+  if zlib_t.type_name() == 'internal'
+    # if fallback was used, we don't need to test if headers are present (they
+    # aren't built yet, so we can't test)
+    zlib = zlib_t
+  elif not zlib_t.found()
+    warning('did not find zlib')
+  elif not cc.has_header('zlib.h', args: g_c_args, dependencies: [zlib_t], required: \
zlibopt.enabled()) +    warning('zlib header not found')
+  elif not cc.has_type('z_streamp', args: g_c_args, dependencies: [zlib_t], prefix: \
'#include <zlib.h>') +    if zlibopt.enabled()
+      error('zlib version is too old')
+    else
+      warning('zlib version is too old')
+    endif
+  else
+    zlib = zlib_t
+  endif
+
+  if zlib.found()
+    cdata.set('HAVE_LIBZ', 1)
+  endif
+endif
+
+
+
+###############################################################
+# Compiler tests
+###############################################################
+
+sizeof_long = cc.sizeof('long', args: g_c_args)
+cdata.set('SIZEOF_LONG', sizeof_long)
+if sizeof_long == 8
+  cdata.set('HAVE_LONG_INT_64', 1)
+  cdata.set('PG_INT64_TYPE', 'long int')
+  cdata.set_quoted('INT64_MODIFIER', 'l')
+elif sizeof_long == 4 and cc.sizeof('long long', args: g_c_args) == 8
+  cdata.set('HAVE_LONG_LONG_INT_64', 1)
+  cdata.set('PG_INT64_TYPE', 'long long int')
+  cdata.set_quoted('INT64_MODIFIER', 'll')
+elif
+  error('do not know how to get a 64bit int')
+endif
+
+
+cdata.set('MAXIMUM_ALIGNOF', 8)
+cdata.set('ALIGNOF_SHORT', cc.alignment('short', args: g_c_args))
+cdata.set('ALIGNOF_INT', cc.alignment('int', args: g_c_args))
+cdata.set('ALIGNOF_LONG', cc.alignment('long', args: g_c_args))
+cdata.set('ALIGNOF_DOUBLE', cc.alignment('double', args: g_c_args))
+cdata.set('SIZEOF_VOID_P', cc.sizeof('void *', args: g_c_args))
+cdata.set('SIZEOF_SIZE_T', cc.sizeof('size_t', args: g_c_args))
+
+# Check if the C compiler knows computed gotos (gcc extension, also
+# available in at least clang).  If so, define HAVE_COMPUTED_GOTO.
+#
+# Checking whether computed gotos are supported syntax-wise ought to
+# be enough, as the syntax is otherwise illegal.
+if cc.compiles('''
+    static inline int foo(void)
+    {
+      void *labeladdrs[] = {&&my_label};
+      goto *labeladdrs[0];
+      my_label:
+      return 1;
+    }''',
+    args: g_c_args)
+  cdata.set('HAVE_COMPUTED_GOTO', 1)
+endif
+
+
+# XXX: for now just assume that compiler knows __func__ - it's C99 after all.
+cdata.set('HAVE_FUNCNAME__FUNC', 1)
+
+# Check if the C compiler understands _Static_assert(),
+# and define HAVE__STATIC_ASSERT if so.
+#
+# We actually check the syntax ({ _Static_assert(...) }), because we need
+# gcc-style compound expressions to be able to wrap the thing into macros.
+if cc.compiles('''
+    int main(int arg, char **argv)
+    {
+        ({ _Static_assert(1, "foo"); })
+    }
+    ''',
+    args: g_c_args)
+  cdata.set('HAVE__STATIC_ASSERT', 1)
+endif
+
+# We use <stdbool.h> if we have it and it declares type bool as having
+# size 1.  Otherwise, c.h will fall back to declaring bool as unsigned char.
+if cc.has_type('_Bool', args: g_c_args) \
+  and cc.has_type('bool', prefix: '#include <stdbool.h>', args: g_c_args) \
+  and cc.sizeof('bool', prefix: '#include <stdbool.h>', args: g_c_args) == 1
+  cdata.set('HAVE__BOOL', 1)
+  cdata.set('PG_USE_STDBOOL', 1)
+endif
+
+
+printf_attributes = ['gnu_printf', '__syslog__', 'printf']
+testsrc = 'extern void pgac_write(int ignore, const char *fmt,...) \
__attribute__((format(@0@, 2,3)));' +foreach a : printf_attributes
+  if cc.compiles(testsrc.format(a), args: g_c_args + ['-Werror'], name: 'format ' + \
a) +    cdata.set('PG_PRINTF_ATTRIBUTE', a)
+    break
+  endif
+endforeach
+
+if cc.has_function_attribute('visibility:default') and \
+  cc.has_function_attribute('visibility:hidden')
+  cdata.set('HAVE_VISIBILITY_ATTRIBUTE', 1)
+endif
+
+
+if cc.has_function('__builtin_unreachable', args: g_c_args)
+  cdata.set('HAVE__BUILTIN_UNREACHABLE', 1)
+endif
+
+if cc.has_function('__builtin_constant_p', args: g_c_args)
+  cdata.set('HAVE__BUILTIN_CONSTANT_P', 1)
+
+  if host_machine.cpu_family() == 'ppc' or host_machine.cpu_family() == 'ppc64'
+    # Check if compiler accepts "i"(x) when __builtin_constant_p(x).
+    if cc.compiles('''
+      static inline int
+      addi(int ra, int si)
+      {
+          int res = 0;
+          if (__builtin_constant_p(si))
+              __asm__ __volatile__(
+                  " addi %0,%1,%2\n" : "=r"(res) : "b"(ra), "i"(si));
+          return res;
+      }
+      int test_adds(int x) { return addi(3, x) + addi(x, 5); }
+      ''',
+      args: g_c_args)
+      cdata.set('HAVE_I_CONSTRAINT__BUILTIN_CONSTANT_P', 1)
+    endif
+  endif
+endif
+
+
+
+# XXX: The configure.ac check for __cpuid() is broken, we don't copy that
+# here. To prevent problems due to two detection methods working, stop
+# checking after one.
+if cc.links('''
+    #include <cpuid.h>
+    int main(int arg, char **argv)
+    {
+        unsigned int exx[4] = {0, 0, 0, 0};
+        __get_cpuid(1, &exx[0], &exx[1], &exx[2], &exx[3]);
+    }
+    ''', name: '__get_cpuid',
+    args: g_c_args)
+  cdata.set('HAVE__GET_CPUID', 1)
+elif cc.links('''
+    #include <intrin.h>
+    int main(int arg, char **argv)
+    {
+        unsigned int exx[4] = {0, 0, 0, 0};
+        __cpuid(exx, 1);
+    }
+    ''', name: '__cpuid',
+    args: g_c_args)
+  cdata.set('HAVE__CPUID', 1)
+endif
+
+
+
+###############################################################
+# Compiler flags
+###############################################################
+
+common_functional_flags = [
+  # Disable strict-aliasing rules; needed for gcc 3.3+
+  '-fno-strict-aliasing',
+  # Disable optimizations that assume no overflow; needed for gcc 4.3+
+  '-fwrapv',
+  '-fexcess-precision=standard'
+]
+
+add_project_arguments(cc.get_supported_arguments(common_functional_flags), language: \
'c') +
+vectorize_cflags = cc.get_supported_arguments(['-ftree-vectorize'])
+unroll_loops_cflags = cc.get_supported_arguments(['-funroll-loops'])
+
+
+common_warning_flags = [
+  '-Wmissing-prototypes',
+  '-Wpointer-arith',
+  '-Werror=vla',
+  '-Wendif-labels',
+  '-Wmissing-format-attribute',
+  '-Wimplicit-fallthrough=3',
+  '-Wcast-function-type',
+  '-Wformat-security',
+]
+
+add_project_arguments(cc.get_supported_arguments(common_warning_flags), language: \
'c') +
+if llvm.found()
+  add_project_arguments(cpp.get_supported_arguments(common_warning_flags), language: \
'cpp') +endif
+
+# A few places with imported code get a pass on -Wdeclaration-after-statement, \
remember +# the result for them
+if cc.has_argument('-Wdeclaration-after-statement')
+  add_project_arguments('-Wdeclaration-after-statement', language: 'c')
+  using_declaration_after_statement_warning = true
+else
+  using_declaration_after_statement_warning = false
+endif
+
+
+# We want to suppress a few unhelpful warnings - but gcc won't
+# complain about unrecognized -Wno-foo switches, so we have to test
+# for the positive form and if that works, add the negative form
+
+negative_warning_flags = [
+  'unused-command-line-argument',
+  'format-truncation',
+  'stringop-truncation',
+
+  # FIXME: from andres's local config
+  'clobbered',
+  'missing-field-initializers',
+  'sign-compare',
+  'unused-parameter',
+]
+
+foreach w : negative_warning_flags
+  if cc.has_argument('-W'+w)
+    add_project_arguments('-Wno-'+w, language: 'c')
+  endif
+
+  if llvm.found() and cpp.has_argument('-W'+w)
+    add_project_arguments('-Wno-'+w, language: 'cpp')
+  endif
+endforeach
+
+
+# From Project.pm
+if cc.get_id() == 'msvc'
+  add_project_arguments('/wd4018', '/wd4244', '/wd4273', '/wd4102', '/wd4090', \
'/wd4267', +    language: 'c')
+  add_project_arguments('/DWIN32', '/DWINDOWS', '/D__WINDOWS__', '/D__WIN32__',
+    '/DWIN32_STACK_RLIMIT=4194304', '/D_CRT_SECURE_NO_DEPRECATE', \
'/D_CRT_NONSTDC_NO_DEPRECATE', +        language: 'c')
+endif
+
+
+
+###############################################################
+# Atomics
+###############################################################
+
+# FIXME
+cdata.set('HAVE_SPINLOCKS', 1)
+
+if get_option('atomics')
+  # FIXME
+  cdata.set('HAVE_ATOMICS', 1)
+
+  atomic_checks = [
+    {'name': 'HAVE_GCC__SYNC_CHAR_TAS',
+     'desc': '__sync_lock_test_and_set(char)',
+     'test': '''
+char lock = 0;
+__sync_lock_test_and_set(&lock, 1);
+__sync_lock_release(&lock);'''},
+
+    {'name': 'HAVE_GCC__SYNC_INT32_TAS',
+     'desc': '__sync_lock_test_and_set(int32)',
+     'test': '''
+int lock = 0;
+__sync_lock_test_and_set(&lock, 1);
+__sync_lock_release(&lock);'''},
+
+    {'name': 'HAVE_GCC__SYNC_INT32_CAS',
+     'desc': '__sync_val_compare_and_swap(int32)',
+     'test': '''
+int val = 0;
+__sync_val_compare_and_swap(&val, 0, 37);'''},
+
+# FIXME: int64 reference
+    {'name': 'HAVE_GCC__SYNC_INT64_CAS',
+     'desc': '__sync_val_compare_and_swap(int64)',
+     'test': '''
+long val = 0;
+__sync_val_compare_and_swap(&val, 0, 37);'''},
+
+    {'name': 'HAVE_GCC__ATOMIC_INT32_CAS',
+     'desc': ' __atomic_compare_exchange_n(int32)',
+     'test': '''
+int val = 0;
+int expect = 0;
+__atomic_compare_exchange_n(&val, &expect, 37, 0, __ATOMIC_SEQ_CST, \
__ATOMIC_RELAXED);'''}, +
+# FIXME: int64 reference
+    {'name': 'HAVE_GCC__ATOMIC_INT64_CAS',
+     'desc': ' __atomic_compare_exchange_n(int64)',
+     'test': '''
+long val = 0;
+int expect = 0;
+__atomic_compare_exchange_n(&val, &expect, 37, 0, __ATOMIC_SEQ_CST, \
__ATOMIC_RELAXED);'''}, +  ]
+
+  foreach check : atomic_checks
+    test = '''
+int main(void)
+{
+@0@
+}'''.format(check['test'])
+
+    cdata.set(check['name'],
+      cc.links(test, name: check['desc'], args: g_c_args))
+  endforeach
+
+endif
+
+
+
+###############################################################
+# CRC
+###############################################################
+
+have_optimized_crc = false
+cflags_crc = []
+if cpu_family == 'x86' or cpu_family == 'x86_64'
+
+  if cc.get_id() == 'msvc'
+    cdata.set('USE_SSE42_CRC32C', false)
+    cdata.set('USE_SSE42_CRC32C_WITH_RUNTIME_CHECK', 1)
+    have_optimized_crc = true
+  else
+
+    prog = '''
+#include <nmmintrin.h>
+
+int main(void)
+{
+    unsigned int crc = 0;
+    crc = _mm_crc32_u8(crc, 0);
+    crc = _mm_crc32_u32(crc, 0);
+    /* return computed value, to prevent the above being optimized away */
+    return crc == 0;
+}
+'''
+
+    if cc.links(prog, name: '_mm_crc32_u8 and _mm_crc32_u32 without -msse4.2', args: \
g_c_args) +      cdata.set('USE_SSE42_CRC32C', 1)
+      have_optimized_crc = true
+    elif cc.links(prog, name: '_mm_crc32_u8 and _mm_crc32_u32 with -msse4.2', args: \
g_c_args + ['-msse4.2']) +      cflags_crc += '-msse4.2'
+      cdata.set('USE_SSE42_CRC32C', false)
+      cdata.set('USE_SSE42_CRC32C_WITH_RUNTIME_CHECK', 1)
+      have_optimized_crc = true
+    endif
+
+  endif
+
+elif cpu_family == 'arm' or cpu_family == 'aarch64'
+
+  prog = '''
+#include <arm_acle.h>
+
+int main(void)
+{
+    unsigned int crc = 0;
+    crc = __crc32cb(crc, 0);
+    crc = __crc32ch(crc, 0);
+    crc = __crc32cw(crc, 0);
+    crc = __crc32cd(crc, 0);
+
+    /* return computed value, to prevent the above being optimized away */
+    return crc == 0;
+}
+'''
+
+  if cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd without \
-march=armv8-a+crc', +      args: g_c_args)
+    cdata.set('USE_ARMV8_CRC32C', true)
+    have_optimized_crc = true
+  elif cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd with \
-march=armv8-a+crc', +      args: g_c_args + ['-march=armv8-a+crc'])
+    cflags_crc += '-march=armv8-a+crc'
+    cdata.set('USE_ARMV8_CRC32C', false)
+    cdata.set('USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK', 1)
+    have_optimized_crc = true
+  endif
+endif
+
+if not have_optimized_crc
+  cdata.set('USE_SLICING_BY_8_CRC32C', 1)
+endif
+
+
+
+###############################################################
+# Library / OS tests
+###############################################################
+
+header_checks = [
+  ['atomic.h'],
+  ['stdbool.h'],
+  ['copyfile.h'],
+  ['execinfo.h'],
+  ['getopt.h'],
+  ['ifaddrs.h'],
+  ['langinfo.h'],
+  ['mbarrier.h'],
+  ['poll.h'],
+  ['sys/epoll.h'],
+  ['sys/event.h'],
+  ['sys/ipc.h'],
+  ['sys/prctl.h'],
+  ['sys/procctl.h'],
+  ['sys/pstat.h'],
+  ['sys/resource.h'],
+  ['sys/select.h'],
+  ['sys/sem.h'],
+  ['sys/shm.h'],
+  ['sys/sockio.h'],
+  ['sys/tas.h'],
+  ['sys/uio.h'],
+  ['sys/un.h'],
+  ['termios.h'],
+  ['ucred.h'],
+  # FIXME: openbsd workaround
+  ['sys/ucred.h'],
+  ['wctype.h'],
+  ['netinet/tcp.h'],
+  ['net/if.h'],
+  ['crtdefs.h'],
+]
+
+foreach c : header_checks
+  varname = 'HAVE_'+c.get(0).underscorify().to_upper()
+
+  # Emulate autoconf behaviour of not-found->undef, found->1
+  found = cc.has_header(c.get(0), include_directories: g_inc, args: g_c_args)
+  cdata.set(varname, found ? 1 : false,
+            description: 'Define to 1 if you have the <@0@> header file.'.format(c))
+endforeach
+
+
+
+decl_checks = [
+  ['F_FULLFSYNC', 'fcntl.h'],
+  ['RTLD_GLOBAL', 'dlfcn.h'],
+  ['RTLD_NOW', 'dlfcn.h'],
+  ['fdatasync', 'unistd.h'],
+  ['posix_fadvise', 'fcntl.h'],
+  ['sigwait', 'signal.h'],
+  ['strlcat', 'string.h'],
+  ['strlcpy', 'string.h'],
+  ['strnlen', 'string.h'],
+  ['strsignal', 'string.h'],
+  ['strtoll', 'stdlib.h'], ['strtoull', 'stdlib.h'], # strto[u]ll may exist but not \
be declared +]
+
+# Need to check for function declarations for these functions, because
+# checking for library symbols wouldn't handle deployment target
+# restrictions on macOS
+decl_checks += [
+  ['preadv', 'sys/uio.h'],
+  ['pwritev', 'sys/uio.h'],
+]
+
+foreach c : decl_checks
+  varname = 'HAVE_DECL_'+c.get(0).underscorify().to_upper()
+
+  found = cc.has_header_symbol(c.get(1), c.get(0), args: g_c_args, kwargs: c.get(2, \
{})) +  cdata.set10(varname, found, description:
+'''Define to 1 if you have the declaration of `@0@\', and to 0 if you
+  don't.'''.format(c))
+endforeach
+
+
+
+# XXX: this is borked, HAVE_SYS_UCRED_H not defined
+if cc.has_type('struct cmsgcred',
+    include_directories: g_inc,
+    args: g_c_args + ['@0@'.format(cdata.get('HAVE_SYS_UCRED_H')) == 'false' ? \
'-DHAVE_SYS_UCRED_H' : ''], +    prefix: '''
+#include <sys/socket.h>
+#include <sys/param.h>
+#ifdef HAVE_SYS_UCRED_H
+#include <sys/ucred.h>
+#endif''')
+  cdata.set('HAVE_STRUCT_CMSGCRED', 1)
+else
+  cdata.set('HAVE_STRUCT_CMSGCRED', false)
+endif
+
+if cc.has_function('getopt', args: g_c_args) and \
+   cc.has_function('getopt_long', args: g_c_args) and \
+   cc.has_type('struct option', args: g_c_args, prefix: '#include <getopt.h>')
+  cdata.set('HAVE_GETOPT', 1)
+  cdata.set('HAVE_GETOPT_LONG', 1)
+  cdata.set('HAVE_STRUCT_OPTION', 1)
+else
+  warning('not yet implemented')
+endif
+
+
+foreach c : ['opterr', 'optreset']
+  varname = 'HAVE_INT_'+c.underscorify().to_upper()
+
+  if cc.links('''
+#include <unistd.h>
+int main(void)
+{
+    extern int @0@;
+    @0@ = 1;
+}
+'''.format(c), name: c, args: g_c_args)
+    cdata.set(varname, 1)
+  else
+    cdata.set(varname, false)
+  endif
+endforeach
+
+
+if cc.has_type('struct sockaddr_storage', args: g_c_args, prefix: '''
+#include <sys/types.h>
+#include <sys/socket.h>''')
+  cdata.set('HAVE_STRUCT_SOCKADDR_STORAGE', 1)
+endif
+
+if cc.has_member('struct sockaddr_storage', 'ss_family', args: g_c_args,
+  prefix: '''#include <sys/types.h>
+#include <sys/socket.h>''')
+  cdata.set('HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY', 1)
+endif
+
+if cc.has_member('struct sockaddr_storage', '__ss_family', args: g_c_args,
+  prefix: '''
+#include <sys/types.h>
+#include <sys/socket.h>''')
+  cdata.set('HAVE_STRUCT_SOCKADDR_STORAGE___SS_FAMILY', 1)
+endif
+
+if cc.has_type('struct sockaddr_un', args: g_c_args, prefix: '''
+#include <sys/types.h>
+#include <sys/un.h>''')
+  cdata.set('HAVE_STRUCT_SOCKADDR_UN', 1)
+endif
+
+if cc.has_type('struct addrinfo', args: g_c_args, prefix: '''
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+''')
+  cdata.set('HAVE_STRUCT_ADDRINFO', 1)
+endif
+
+if host_machine.system() == 'windows'
+  cdata.set('HAVE_STRUCT_SOCKADDR_STORAGE', 1)
+  cdata.set('HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY', 1)
+endif
+
+if cc.has_type('struct sockaddr_in6', args: g_c_args, prefix: '''
+#include <netinet/in.h>''')
+  cdata.set('HAVE_IPV6', 1)
+endif
+
+
+if cc.has_member('struct tm', 'tm_zone', args: g_c_args, prefix: '''
+#include <sys/types.h>
+#include <time.h>
+''')
+  cdata.set('HAVE_STRUCT_TM_TM_ZONE', 1)
+endif
+
+if cc.compiles('''
+#include <time.h>
+extern int foo(void);
+int foo(void)
+{
+    return timezone / 60;
+}
+''', name: 'Check if the global variable `timezone\' exists', args: g_c_args,)
+  cdata.set('HAVE_INT_TIMEZONE', 1)
+else
+  cdata.set('HAVE_INT_TIMEZONE', false)
+endif
+
+# FIXME: sys/ipc.h, sys/sem.h includes were conditional
+if cc.has_type('union semun', args: g_c_args, prefix: '''
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/sem.h>
+''')
+  cdata.set('HAVE_UNION_SEMUN', 1)
+endif
+
+if cc.compiles('''
+#include <string.h>
+int main(void)
+{
+  char buf[100];
+  switch (strerror_r(1, buf, sizeof(buf)))
+  { case 0: break; default: break; }
+}''', args: g_c_args)
+  cdata.set('STRERROR_R_INT', 1)
+else
+  cdata.set('STRERROR_R_INT', false)
+endif
+
+# FIXME
+cdata.set('pg_restrict', '__restrict')
+
+# FIXME
+if host_machine.system() == 'windows'
+  cdata.set('ACCEPT_TYPE_ARG1', 'unsigned int')
+  cdata.set('ACCEPT_TYPE_ARG2', 'struct sockaddr *')
+  cdata.set('ACCEPT_TYPE_ARG3', 'int')
+  cdata.set('ACCEPT_TYPE_RETURN', 'unsigned int PASCAL')
+else
+  cdata.set('ACCEPT_TYPE_ARG1', 'int')
+  cdata.set('ACCEPT_TYPE_ARG2', 'struct sockaddr')
+  cdata.set('ACCEPT_TYPE_ARG3', 'socklen_t')
+  cdata.set('ACCEPT_TYPE_RETURN', 'int')
+endif
+
+cdata.set('HAVE_STRUCT_ADDRINFO', 1)
+
+
+cdata.set('MEMSET_LOOP_LIMIT', 1024)
+
+
+if cc.links('''
+#include <machine/vmparam.h>
+#include <sys/exec.h>
+
+int main(void)
+{
+    PS_STRINGS->ps_nargvstr = 1;
+    PS_STRINGS->ps_argvstr = "foo";
+}
+''',
+  name: 'PS_STRINGS', args: g_c_args)
+  cdata.set('HAVE_PS_STRINGS', 1)
+else
+  cdata.set('HAVE_PS_STRINGS', false)
+endif
+
+
+m_dep = cc.find_library('m', required : false)
+
+# Most libraries are included only if they demonstrably provide a function we
+# need, but libm is an exception: always include it, because there are too
+# many compilers that play cute optimization games that will break probes for
+# standard functions such as pow().
+os_deps = [m_dep]
+
+rt_dep = cc.find_library('rt', required : false)
+
+dl_dep = cc.find_library('dl', required : false)
+
+util_dep = cc.find_library('util', required : false)
+posix4_dep = cc.find_library('posix4', required : false)
+
+getopt_dep = cc.find_library('getopt', required : false)
+gnugetopt_dep = cc.find_library('gnugetopt', required : false)
+
+execinfo_dep = cc.find_library('execinfo', required : false)
+
+func_checks = [
+  ['_configthreadlocale'],
+  ['backtrace_symbols', {'dependencies': [execinfo_dep]}],
+  ['clock_gettime', {'dependencies': [rt_dep, posix4_dep]}],
+  ['copyfile'],
+  ['dlopen', {'dependencies': [dl_dep]}],
+  ['explicit_bzero'],
+  ['fdatasync', {'dependencies': [rt_dep, posix4_dep]}],
+  ['fls'],
+  ['getaddrinfo'],
+  ['gethostbyname_r', {'dependencies': [thread_dep]}],
+  ['getifaddrs'],
+  ['getopt', {'dependencies': [getopt_dep, gnugetopt_dep]}],
+  ['getopt_long',{'dependencies': [getopt_dep, gnugetopt_dep]}],
+  ['getpeereid'],
+  ['getpeerucred'],
+  ['getpwuid_r', {'dependencies': [thread_dep]}],
+  ['getrlimit'],
+  ['getrusage'],
+  ['gettimeofday'], # XXX: This seems to be in the autoconf case
+  ['inet_aton'],
+  ['kqueue'],
+  ['link'],
+  ['mbstowcs_l'],
+  ['memset_s'],
+  ['mkdtemp'],
+  ['poll'],
+  ['posix_fadvise'],
+  ['posix_fallocate'],
+  ['ppoll'],
+  ['pread'],
+  ['pstat'],
+  ['pthread_is_threaded_np'],
+  ['pwrite'],
+  ['random'],
+  ['readlink'],
+  ['readv'],
+  ['setenv'], # FIXME: windows handling
+  ['setproctitle', {'dependencies': [util_dep]}],
+  ['setproctitle_fast'],
+  ['setsid'],
+  ['shm_open', {'dependencies': [rt_dep]}],
+  ['shm_unlink', {'dependencies': [rt_dep]}],
+  ['srandom'],
+  ['strchrnul'],
+  ['strerror_r', {'dependencies': [thread_dep]}],
+  ['strlcat'],
+  ['strlcpy'],
+  ['strnlen'],
+  ['strsignal'],
+  ['strtof'], # strsignal is checked separately
+  ['strtoll'], ['__strtoll'], ['strtoq'],
+  ['strtoull'], ['__strtoull'], ['strtouq'],
+  ['symlink'],
+  ['sync_file_range'],
+  ['syncfs'],
+  ['unsetenv'],
+  ['uselocale'],
+  ['wcstombs_l'],
+  ['writev'],
+]
+
+foreach c : func_checks
+  func = c.get(0)
+  kwargs = c.get(1, {})
+  deps = kwargs.get('dependencies', [])
+
+  varname = 'HAVE_'+func.underscorify().to_upper()
+
+  found = cc.has_function(func, args: g_c_args,
+                          kwargs: kwargs + {'dependencies': []})
+
+  if not found
+    foreach dep : deps
+      if not dep.found()
+        continue
+      endif
+      found = cc.has_function(func, args: g_c_args,
+                              kwargs: kwargs + {'dependencies': [dep]})
+      if found
+        os_deps += dep
+        break
+      endif
+    endforeach
+  endif
+
+  # Emulate autoconf behaviour of not-found->undef, found->1
+  cdata.set(varname, found  ? 1 : false,
+            description: 'Define to 1 if you have the `@0@\' function.'.format(c))
+endforeach
+
+
+
+
+
+if host_machine.system() == 'linux' or host_machine.system() == 'freebsd'
+  dlsuffix = '.so'
+elif host_machine.system() == 'darwin'
+  dlsuffix = '.dylib'
+elif host_machine.system() == 'windows'
+  dlsuffix = '.dll'
+else
+  error('not yet')
+endif
+
+cdata.set_quoted('DLSUFFIX', dlsuffix)
+
+if host_machine.system() == 'windows'
+   cdata.set('USE_WIN32_SEMAPHORES', 1)
+   cdata.set('USE_WIN32_SHARED_MEMORY', 1)
+elif host_machine.system() == 'darwin'
+   cdata.set('USE_SYSV_SEMAPHORES', 1)
+   cdata.set('USE_SYSV_SHARED_MEMORY', 1)
+else
+   cdata.set('USE_UNNAMED_POSIX_SEMAPHORES', 1)
+   cdata.set('USE_SYSV_SHARED_MEMORY', 1)
+endif
+
+
+if host_machine.system() == 'windows'
+  cdata.set('HAVE_IPV6', 1)
+  cdata.set('HAVE_SYMLINK', 1)
+  cdata.set('WIN32_STACK_RLIMIT', 4194304)
+  cdata.set('HAVE__CONFIGTHREADLOCALE', 1)
+endif
+
+if cc.get_id() == 'msvc'
+  add_project_link_arguments(
+    '/fixed:no',
+    '/dynamicbase',
+    '/nxcompat',
+    language : ['c', 'cpp'],
+  )
+endif
+
+if host_machine.system() == 'windows'
+  os_deps += cc.find_library('ws2_32', required: true)
+endif
+
+
+
+###############################################################
+# Threading
+###############################################################
+
+# Probably not worth implementing other cases anymore
+cdata.set('ENABLE_THREAD_SAFETY', 1)
+
+if thread_dep.found()
+  if cc.has_function('pthread_is_threaded_np', args: g_c_args, dependencies: \
[thread_dep]) +    cdata.set('HAVE_PTHREAD_IS_THREADED_NP', 1)
+  endif
+  if cc.has_function('pthread_barrier_wait', args: g_c_args, dependencies: \
[thread_dep]) +    cdata.set('HAVE_PTHREAD_BARRIER_WAIT', 1)
+  endif
+endif
+
+
+
+###############################################################
+# Build
+###############################################################
+
+# Collect a number of lists of things while recursing through the source
+# tree. Later steps then can use those.
+
+test_deps = []
+backend_targets = []
+
+
+# List of tap tests we later generate test() invocations for. The main
+# reason for doing it that way instead of having test() invocations
+# everywhere is that they end up being too large. A second benefit is
+# that it'd make it easier to generate data for another runner.
+tap_tests = []
+isolation_tests = []
+regress_tests = []
+
+
+# Default options for targets
+
+default_target_args = {
+  'implicit_include_directories': false,
+  'install': true,
+}
+
+default_lib_args = default_target_args + {
+  'name_prefix': 'lib',
+}
+
+internal_lib_args = default_lib_args + {
+  'build_by_default': false,
+  'install': false,
+}
+
+default_mod_args = default_lib_args + {
+  'name_prefix': '',
+}
+
+default_bin_args = default_target_args + {
+}
+
+if host_machine.system() == 'windows'
+  # nothing to do
+else
+  if host_machine.system() == 'darwin'
+    rpath_var = '@loader_path'
+  else
+    rpath_var = '$ORIGIN'
+  endif
+
+  # PG binaries might need to link to libpq, use relative path to reference
+  bin_to_lib = run_command(relpath,
+    get_option('bindir'), get_option('libdir'), check: true).stdout().strip()
+  default_bin_args += {'install_rpath':  rpath_var / bin_to_lib}
+
+  # PG extensions might need to link to libpq, use relative path to reference
+  # (often just .)
+  mod_to_lib = run_command(relpath,
+    get_option('libdir'), get_option('libdir'), check: true).stdout().strip()
+  default_mod_args += {'install_rpath': rpath_var}
+endif
+
+
+###
+### windows resources related stuff
+###
+
+rc_cdata = configuration_data()
+rc_cdata.set_quoted('ICO', meson.source_root() / 'src' / 'port' / 'win32.ico')
+
+rc_lib_cdata = rc_cdata
+rc_lib_cdata.set('VFT_TYPE', 'VFT_DLL')
+
+rc_bin_cdata = rc_cdata
+rc_bin_cdata.set('VFT_TYPE', 'VFT_APP')
+
+win32ver_rc_in = files('src/port/win32ver.rc.in')
+
+
+# First visit src/include - all targets creating headers are defined
+# within. That makes it easy to add the necessary dependencies for the
+# subsequent build steps.
+
+generated_headers = []
+generated_backend_headers = []
+
+postgres_inc = [include_directories('src/include')]
+
+if host_machine.system() == 'windows'
+  postgres_inc += include_directories('src/include/port/win32')
+
+  if cc.get_id() == 'msvc'
+    postgres_inc += include_directories('src/include/port/win32_msvc')
+  endif
+endif
+
+subdir('src/include')
+
+
+# Then through src/port and src/common, as most other things depend on them
+
+frontend_port_code = declare_dependency(
+  compile_args: ['-DFRONTEND'],
+  include_directories: [postgres_inc],
+  sources: [errcodes],
+  dependencies: os_deps,
+)
+
+backend_port_code = declare_dependency(
+  compile_args: ['-DBUILDING_DLL'],
+  include_directories: [postgres_inc],
+  sources: [errcodes],
+  dependencies: os_deps,
+)
+
+subdir('src/port')
+
+frontend_common_code = declare_dependency(
+  compile_args: ['-DFRONTEND'],
+  include_directories: [postgres_inc],
+  sources: generated_headers,
+  dependencies: os_deps,
+)
+
+backend_common_code = declare_dependency(
+  compile_args: ['-DBUILDING_DLL'],
+  include_directories: [postgres_inc],
+  sources: generated_headers,
+)
+
+subdir('src/common')
+
+frontend_shlib_code = declare_dependency(
+  compile_args: ['-DFRONTEND'],
+  include_directories: [postgres_inc],
+  link_with: [pgport_shlib, common_shlib],
+  sources: generated_headers,
+  dependencies: os_deps,
+)
+
+subdir('src/interfaces/libpq')
+subdir('src/fe_utils')
+
+frontend_code = declare_dependency(
+  compile_args: ['-DFRONTEND'],
+  include_directories: [postgres_inc],
+  link_with: [pgport_static, common_static, fe_utils],
+  sources: generated_headers,
+  dependencies: os_deps,
+)
+
+backend_code = declare_dependency(
+  compile_args: ['-DBUILDING_DLL'],
+  include_directories: [postgres_inc],
+  link_with: [],
+  sources: generated_headers + generated_backend_headers,
+  dependencies: [os_deps, ssl, lz4, icu, icu_i18n, ldap, gssapi, libxml, systemd],
+)
+
+# Note there's intentionally no dependency on pgport/common here - we want the
+# symbols from the main binary for extension modules, rather than the
+# extension linking separately to pgport/common.
+backend_mod_code = declare_dependency(
+  compile_args: [],
+  include_directories: [postgres_inc],
+  link_with: [],
+  sources: generated_headers + generated_backend_headers,
+  dependencies: [os_deps, ssl, lz4, icu, icu_i18n, ldap, gssapi, libxml, systemd],
+)
+
+# Then through the main sources. That way contrib can have dependencies on
+# main sources. Note that this explicitly doesn't enter src/test, right now a
+# few regression tests depend on contrib files.
+
+subdir('src')
+
+subdir('contrib')
+
+subdir('src/test')
+
+subdir('doc/src/sgml')
+
+
+if host_machine.system() == 'darwin'
+  meson.add_install_script('src/tools/relativize_shared_library_references')
+endif
+
+
+
+###############################################################
+# Test prep
+###############################################################
+
+# The determination of where a DESTDIR install points to is ugly, it's somewhat hard
+# to combine two absolute paths portably...
+
+prefix = get_option('prefix')
+
+test_prefix = prefix
+
+if fs.is_absolute(get_option('prefix'))
+  if host_machine.system() == 'windows'
+    if prefix.split(':\\').length() == 1
+        # just a drive
+        test_prefix = ''
+    else
+        test_prefix = prefix.split(':\\')[1]
+    endif
+  else
+    test_prefix = prefix.substring(1)
+  endif
+endif
+
+# DESTDIR for the installation used to run tests in
+test_install_destdir = meson.build_root() / 'tmp_install/'
+# DESTDIR + prefix appropriately munged
+test_install_location = test_install_destdir / test_prefix
+
+
+test('tmp_install',
+    meson_bin, args: meson_args + ['install', '--quiet', '--only-changed', \
'--no-rebuild'], +    env: {'DESTDIR':test_install_destdir},
+    priority: 100,
+    is_parallel: false,
+    suite: ['setup'])
+
+test_result_dir = meson.build_root() / 'testrun'
+
+
+# XXX: pg_regress doesn't assign unique ports on windows. To avoid the
+# inevitable conflicts from running tests in parallel, hackishly assign
+# different ports for different tests.
+
+testport=40000
+
+test_env = environment()
+
+test_env.prepend('PATH', test_install_location / get_option('bindir'))
+test_env.set('PG_REGRESS', meson.build_root() / 'src/test/regress/pg_regress')
+test_env.set('REGRESS_SHLIB', regress_module.full_path())
+
+
+
+###############################################################
+# Test Generation
+###############################################################
+
+# Define all 'pg_regress' style tests
+foreach t : regress_tests
+  test_command = [
+    pg_regress,
+    '--temp-instance', test_result_dir / t['name'] / 'pg_regress' / 'tmp_check',
+    '--inputdir', t['sd'],
+    '--outputdir', test_result_dir / t['name'] / 'pg_regress',
+    '--bindir', '',
+    '--dlpath', t['bd'],
+    '--max-concurrent-tests=20',
+    '--port=@0@'.format(testport),
+  ]
+
+  if t.has_key('regress_args')
+     test_command += t['regress_args']
+  endif
+
+  if t.has_key('schedule')
+     test_command += ['--schedule', t['schedule'],]
+  else
+     test_command += t['sql']
+  endif
+
+  test_kwargs = {
+    'suite': ['pg_regress', t['name']],
+    'priority': 10,
+    'timeout': 300,
+    'depends': test_deps + t.get('deps', []),
+    'env': test_env,
+    'workdir': t['sd'],
+    'args': [
+      meson.build_root(),
+      t['bd'],
+      t['name'],
+      'pg_regress',
+      test_command,
+    ]
+  }
+
+  # Allow test definition to override arguments
+  if t.has_key('test_kwargs')
+     test_kwargs += t['test_kwargs']
+  endif
+
+  test(t['name'] / 'pg_regress',
+    testwrap,
+    kwargs: test_kwargs,
+  )
+
+  testport = testport + 1
+endforeach
+
+
+# Define all 'isolationtester' style tests
+foreach t : isolation_tests
+  test_command = [
+    pg_isolation_regress,
+    '--temp-instance', test_result_dir / t['name'] / 'isolation' / 'tmp_check',
+    '--inputdir', t['sd'],
+    '--outputdir', test_result_dir / t['name'] / 'isolation',
+    '--bindir', '',
+    '--dlpath', t['bd'],
+    '--max-concurrent-tests=20',
+    '--port=@0@'.format(testport),
+  ]
+
+  if t.has_key('regress_args')
+     test_command += t['regress_args']
+  endif
+
+  if t.has_key('schedule')
+     test_command += ['--schedule', t['schedule'],]
+  else
+     test_command += t['specs']
+  endif
+
+  test_kwargs = {
+    'suite': ['isolation', t['name']],
+    'priority': 20,
+    'timeout': 300,
+    'depends': test_deps + t.get('deps', []),
+    'workdir': t['sd'],
+    'env': test_env,
+    'args': [
+      meson.build_root(),
+      t['bd'],
+      t['name'],
+      'isolation',
+      test_command,
+    ]
+  }
+
+  # Allow test definition to override arguments
+  if t.has_key('test_kwargs')
+     test_kwargs += t['test_kwargs']
+  endif
+
+  test(t['name'] / 'isolation',
+    testwrap,
+    kwargs: test_kwargs,
+  )
+
+  testport = testport + 1
+endforeach
+
+
+# Define all 'tap' style tests
+# FIXME: dependencies for each test
+foreach t : tap_tests
+  env = test_env
+
+  foreach name, value : t.get('env', {})
+    if name == 'PATH'
+      # FIXME: manually setting PATH again, because repeated prepend didn't work
+      # before meson 0.58.
+      env.prepend('PATH', value, test_install_location / get_option('bindir'))
+    else
+      env.set(name, value)
+    endif
+  endforeach
+
+  foreach onetap : t['tests']
+    test(t['name'] / onetap,
+      testwrap,
+      workdir: t['sd'],
+      args: [
+        meson.build_root(),
+        t['bd'],
+        t['name'],
+        onetap,
+        'perl',
+        '-I', meson.source_root() / 'src/test/perl',
+        '-I', t['sd'],
+        t['sd'] / onetap
+      ],
+      protocol: 'tap',
+      suite: ['tap', t['name']],
+      env: env,
+      depends: test_deps + t.get('deps', []),
+      timeout: 300,
+      )
+  endforeach
+endforeach
+
+
+
+###############################################################
+# Pseudo targets
+###############################################################
+
+alias_target('backend', backend_targets)
+
+
+
+###############################################################
+# The End, The End, My Friend
+###############################################################
+
+if meson.version().version_compare('>=0.57')
+
+  summary({
+    'Data Block Size' : cdata.get('BLCKSZ'),
+    'WAL Block Size' : cdata.get('XLOG_BLCKSZ')
+    }, section: 'Data Layout'
+  )
+
+  summary(
+    {
+      'host system' : '@0@ @1@'.format(host_machine.system(), \
host_machine.cpu_family()), +      'build system' : '@0@ \
@1@'.format(build_machine.system(), build_machine.cpu_family()), +    },
+    section: 'System'
+  )
+
+  summary(
+    {
+      'linker': '@0@'.format(cc.get_linker_id()),
+      'C compiler': '@0@ @1@'.format(cc.get_id(), cc.version()),
+    },
+    section: 'Compiler'
+  )
+
+  if llvm.found()
+    summary(
+      {
+        'C++ compiler': '@0@ @1@'.format(cpp.get_id(), cpp.version())
+      },
+      section: 'Compiler')
+  endif
+
+  summary(
+    {
+      'bison' : '@0@ @1@'.format(bison.full_path(), bison_version),
+    },
+    section: 'Programs'
+  )
+
+  summary(
+    {
+      'GSS': gssapi,
+      'LDAP': ldap,
+      'LLVM': llvm,
+      'icu': icu,
+      'libxml': libxml,
+      'libxslt': libxslt,
+      'lz4': lz4,
+      'perl': perl_dep,
+      'python3': python3,
+      'readline': readline,
+      'selinux': selinux,
+      'ssl': ssl,
+      'systemd': systemd,
+      'uuid': uuid,
+      'zlib': zlib,
+    },
+    section: 'External Libraries'
+  )
+
+endif
diff --git a/meson_options.txt b/meson_options.txt
new file mode 100644
index 00000000000..d80d8fa5820
--- /dev/null
+++ b/meson_options.txt
@@ -0,0 +1,90 @@
+# Data layout influencing options
+option('BLCKSZ', type : 'combo', choices : ['1', '2', '4', '8', '16', '32'], value : \
'8', +  description: 'set table block size in kB')
+
+
+# You get it
+option('cassert', type : 'boolean', value: false,
+  description: 'enable assertion checks (for debugging)')
+
+option('atomics', type : 'boolean', value: true,
+  description: 'whether to use atomic operations')
+
+
+# Compilation options
+
+option('extra_include_dirs', type : 'array',
+  description: 'non-default directories to be searched for headers')
+option('extra_lib_dirs', type : 'array',
+  description: 'non-default directories to be searched for libs')
+
+
+# External dependencies
+
+option('gssapi', type : 'feature', value: 'auto',
+  description: 'GSSAPI support')
+
+option('ldap', type : 'feature', value: 'auto',
+  description: 'LDAP support')
+
+option('llvm', type : 'feature', value: 'disabled',
+  description: 'whether to use llvm')
+
+option('icu', type : 'feature', value: 'auto',
+  description: 'ICU support')
+
+option('libxml', type : 'feature', value: 'auto',
+  description: 'XML support')
+
+option('libxslt', type : 'feature', value: 'auto',
+  description: 'XSLT support in contrib/xml2')
+
+option('lz4', type : 'feature', value: 'auto',
+  description: 'LZ4 support')
+
+option('perl', type : 'feature', value: 'auto',
+  description: 'build Perl modules (PL/Perl)')
+
+option('python', type : 'feature', value: 'auto',
+  description: 'build Python modules (PL/Python)')
+
+option('readline', type : 'feature', value : 'auto',
+  description: 'use GNU Readline or BSD Libedit for editing')
+
+option('selinux', type : 'feature', value : 'disabled',
+  description: 'build with SELinux support')
+
+option('ssl', type : 'combo', choices : ['none', 'openssl'], value : 'none',
+  description: 'use LIB for SSL/TLS support (openssl)')
+
+option('systemd', type : 'feature', value: 'auto',
+  description: 'build with systemd support')
+
+option('uuid', type : 'combo', choices : ['none', 'bsd', 'e2fs', 'ossp'], value : \
'none', +  description: 'build contrib/uuid-ossp using LIB')
+
+option('zlib', type : 'feature', value: 'auto',
+  description: 'whether to use zlib')
+
+
+# Programs
+option('BISON', type : 'string', value: 'bison',
+  description: 'path to bison binary')
+
+option('FLEX', type : 'string', value: 'flex',
+  description: 'path to flex binary')
+
+option('GZIP', type : 'string', value: 'gzip',
+  description: 'path to gzip binary')
+
+option('PERL', type : 'string', value: 'perl',
+  description: 'path to perl binary')
+
+option('PROVE', type : 'string', value: 'prove',
+  description: 'path to prove binary')
+
+option('SED', type : 'string', value: 'gsed',
+  description: 'path to sed binary')
+
+option('TAR', type : 'string', value: 'tar',
+  description: 'path to tar binary')
diff --git a/src/backend/access/brin/meson.build \
b/src/backend/access/brin/meson.build new file mode 100644
index 00000000000..a54c7532927
--- /dev/null
+++ b/src/backend/access/brin/meson.build
@@ -0,0 +1,12 @@
+backend_sources += files(
+  'brin.c',
+  'brin_bloom.c',
+  'brin_inclusion.c',
+  'brin_minmax.c',
+  'brin_minmax_multi.c',
+  'brin_pageops.c',
+  'brin_revmap.c',
+  'brin_tuple.c',
+  'brin_validate.c',
+  'brin_xlog.c',
+)
diff --git a/src/backend/access/common/meson.build \
b/src/backend/access/common/meson.build new file mode 100644
index 00000000000..857beaa32d3
--- /dev/null
+++ b/src/backend/access/common/meson.build
@@ -0,0 +1,18 @@
+backend_sources += files(
+  'attmap.c',
+  'bufmask.c',
+  'detoast.c',
+  'heaptuple.c',
+  'indextuple.c',
+  'printsimple.c',
+  'printtup.c',
+  'relation.c',
+  'reloptions.c',
+  'scankey.c',
+  'session.c',
+  'syncscan.c',
+  'toast_compression.c',
+  'toast_internals.c',
+  'tupconvert.c',
+  'tupdesc.c',
+)
diff --git a/src/backend/access/gin/meson.build b/src/backend/access/gin/meson.build
new file mode 100644
index 00000000000..56d6f343d54
--- /dev/null
+++ b/src/backend/access/gin/meson.build
@@ -0,0 +1,17 @@
+backend_sources += files(
+  'ginarrayproc.c',
+  'ginbtree.c',
+  'ginbulk.c',
+  'gindatapage.c',
+  'ginentrypage.c',
+  'ginfast.c',
+  'ginget.c',
+  'gininsert.c',
+  'ginlogic.c',
+  'ginpostinglist.c',
+  'ginscan.c',
+  'ginutil.c',
+  'ginvacuum.c',
+  'ginvalidate.c',
+  'ginxlog.c',
+)
diff --git a/src/backend/access/gist/meson.build \
b/src/backend/access/gist/meson.build new file mode 100644
index 00000000000..1a996b5e25d
--- /dev/null
+++ b/src/backend/access/gist/meson.build
@@ -0,0 +1,13 @@
+backend_sources += files(
+  'gist.c',
+  'gistbuild.c',
+  'gistbuildbuffers.c',
+  'gistget.c',
+  'gistproc.c',
+  'gistscan.c',
+  'gistsplit.c',
+  'gistutil.c',
+  'gistvacuum.c',
+  'gistvalidate.c',
+  'gistxlog.c',
+)
diff --git a/src/backend/access/hash/meson.build \
b/src/backend/access/hash/meson.build new file mode 100644
index 00000000000..22f2c691c34
--- /dev/null
+++ b/src/backend/access/hash/meson.build
@@ -0,0 +1,12 @@
+backend_sources += files(
+  'hash.c',
+  'hash_xlog.c',
+  'hashfunc.c',
+  'hashinsert.c',
+  'hashovfl.c',
+  'hashpage.c',
+  'hashsearch.c',
+  'hashsort.c',
+  'hashutil.c',
+  'hashvalidate.c',
+)
diff --git a/src/backend/access/heap/meson.build \
b/src/backend/access/heap/meson.build new file mode 100644
index 00000000000..f1dca73743c
--- /dev/null
+++ b/src/backend/access/heap/meson.build
@@ -0,0 +1,11 @@
+backend_sources += files(
+  'heapam.c',
+  'heapam_handler.c',
+  'heapam_visibility.c',
+  'heaptoast.c',
+  'hio.c',
+  'pruneheap.c',
+  'rewriteheap.c',
+  'vacuumlazy.c',
+  'visibilitymap.c',
+)
diff --git a/src/backend/access/index/meson.build \
b/src/backend/access/index/meson.build new file mode 100644
index 00000000000..18af5533e65
--- /dev/null
+++ b/src/backend/access/index/meson.build
@@ -0,0 +1,6 @@
+backend_sources += files(
+  'amapi.c',
+  'amvalidate.c',
+  'genam.c',
+  'indexam.c',
+)
diff --git a/src/backend/access/meson.build b/src/backend/access/meson.build
new file mode 100644
index 00000000000..9874291fc0a
--- /dev/null
+++ b/src/backend/access/meson.build
@@ -0,0 +1,13 @@
+subdir('brin')
+subdir('common')
+subdir('gin')
+subdir('gist')
+subdir('hash')
+subdir('heap')
+subdir('index')
+subdir('nbtree')
+subdir('rmgrdesc')
+subdir('spgist')
+subdir('table')
+subdir('tablesample')
+subdir('transam')
diff --git a/src/backend/access/nbtree/meson.build \
b/src/backend/access/nbtree/meson.build new file mode 100644
index 00000000000..07dc29e8190
--- /dev/null
+++ b/src/backend/access/nbtree/meson.build
@@ -0,0 +1,13 @@
+backend_sources += files(
+  'nbtcompare.c',
+  'nbtdedup.c',
+  'nbtinsert.c',
+  'nbtpage.c',
+  'nbtree.c',
+  'nbtsearch.c',
+  'nbtsort.c',
+  'nbtsplitloc.c',
+  'nbtutils.c',
+  'nbtvalidate.c',
+  'nbtxlog.c',
+)
diff --git a/src/backend/access/rmgrdesc/meson.build \
b/src/backend/access/rmgrdesc/meson.build new file mode 100644
index 00000000000..f3a6e0a571b
--- /dev/null
+++ b/src/backend/access/rmgrdesc/meson.build
@@ -0,0 +1,26 @@
+# used by frontend programs like pg_waldump
+rmgr_desc_sources = files(
+  'brindesc.c',
+  'clogdesc.c',
+  'committsdesc.c',
+  'dbasedesc.c',
+  'genericdesc.c',
+  'gindesc.c',
+  'gistdesc.c',
+  'hashdesc.c',
+  'heapdesc.c',
+  'logicalmsgdesc.c',
+  'mxactdesc.c',
+  'nbtdesc.c',
+  'relmapdesc.c',
+  'replorigindesc.c',
+  'seqdesc.c',
+  'smgrdesc.c',
+  'spgdesc.c',
+  'standbydesc.c',
+  'tblspcdesc.c',
+  'xactdesc.c',
+  'xlogdesc.c',
+)
+
+backend_sources += rmgr_desc_sources
diff --git a/src/backend/access/spgist/meson.build \
b/src/backend/access/spgist/meson.build new file mode 100644
index 00000000000..f18d0d2e53f
--- /dev/null
+++ b/src/backend/access/spgist/meson.build
@@ -0,0 +1,13 @@
+backend_sources += files(
+  'spgdoinsert.c',
+  'spginsert.c',
+  'spgkdtreeproc.c',
+  'spgproc.c',
+  'spgquadtreeproc.c',
+  'spgscan.c',
+  'spgtextproc.c',
+  'spgutils.c',
+  'spgvacuum.c',
+  'spgvalidate.c',
+  'spgxlog.c',
+)
diff --git a/src/backend/access/table/meson.build \
b/src/backend/access/table/meson.build new file mode 100644
index 00000000000..66c706d640e
--- /dev/null
+++ b/src/backend/access/table/meson.build
@@ -0,0 +1,6 @@
+backend_sources += files(
+  'table.c',
+  'tableam.c',
+  'tableamapi.c',
+  'toast_helper.c',
+)
diff --git a/src/backend/access/tablesample/meson.build \
b/src/backend/access/tablesample/meson.build new file mode 100644
index 00000000000..63ee8203226
--- /dev/null
+++ b/src/backend/access/tablesample/meson.build
@@ -0,0 +1,5 @@
+backend_sources += files(
+  'bernoulli.c',
+  'system.c',
+  'tablesample.c',
+)
diff --git a/src/backend/access/transam/meson.build \
b/src/backend/access/transam/meson.build new file mode 100644
index 00000000000..fe3703e0f21
--- /dev/null
+++ b/src/backend/access/transam/meson.build
@@ -0,0 +1,28 @@
+backend_sources += files(
+  'clog.c',
+  'commit_ts.c',
+  'generic_xlog.c',
+  'multixact.c',
+  'parallel.c',
+  'rmgr.c',
+  'slru.c',
+  'subtrans.c',
+  'timeline.c',
+  'transam.c',
+  'twophase.c',
+  'twophase_rmgr.c',
+  'varsup.c',
+  'xact.c',
+  'xlog.c',
+  'xlogarchive.c',
+  'xlogfuncs.c',
+  'xloginsert.c',
+  'xlogutils.c',
+)
+
+# used by frontend programs to built a frontend xlogreader
+xlogreader_sources = files(
+  'xlogreader.c',
+)
+
+backend_sources += xlogreader_sources
diff --git a/src/backend/bootstrap/meson.build b/src/backend/bootstrap/meson.build
new file mode 100644
index 00000000000..55c0be68cc4
--- /dev/null
+++ b/src/backend/bootstrap/meson.build
@@ -0,0 +1,12 @@
+backend_sources += files(
+ 'bootstrap.c')
+
+bootscanner = custom_target('bootscanner',
+  input: ['bootscanner.l'],
+  output: ['bootscanner.c'],
+  command: [flex, '-o', '@OUTPUT@', '@INPUT@'])
+
+generated_backend_sources += custom_target('bootparse',
+  input: ['bootparse.y', bootscanner[0]],
+  output: ['bootparse.c'],
+  command: [bison, bisonflags, '-o', '@OUTPUT@', '@INPUT0@'])
diff --git a/src/backend/catalog/meson.build b/src/backend/catalog/meson.build
new file mode 100644
index 00000000000..2cc23582e35
--- /dev/null
+++ b/src/backend/catalog/meson.build
@@ -0,0 +1,41 @@
+backend_sources += files(
+  'aclchk.c',
+  'catalog.c',
+  'dependency.c',
+  'heap.c',
+  'index.c',
+  'indexing.c',
+  'namespace.c',
+  'objectaccess.c',
+  'objectaddress.c',
+  'partition.c',
+  'pg_aggregate.c',
+  'pg_cast.c',
+  'pg_class.c',
+  'pg_collation.c',
+  'pg_constraint.c',
+  'pg_conversion.c',
+  'pg_db_role_setting.c',
+  'pg_depend.c',
+  'pg_enum.c',
+  'pg_inherits.c',
+  'pg_largeobject.c',
+  'pg_namespace.c',
+  'pg_operator.c',
+  'pg_proc.c',
+  'pg_publication.c',
+  'pg_range.c',
+  'pg_shdepend.c',
+  'pg_subscription.c',
+  'pg_type.c',
+  'storage.c',
+  'toasting.c',
+)
+
+
+install_data(
+  'information_schema.sql',
+  'sql_features.txt',
+  'system_functions.sql',
+  'system_views.sql',
+  install_dir: 'share/')
diff --git a/src/backend/commands/meson.build b/src/backend/commands/meson.build
new file mode 100644
index 00000000000..8e73b29a263
--- /dev/null
+++ b/src/backend/commands/meson.build
@@ -0,0 +1,50 @@
+backend_sources += files(
+  'aggregatecmds.c',
+  'alter.c',
+  'amcmds.c',
+  'analyze.c',
+  'async.c',
+  'cluster.c',
+  'collationcmds.c',
+  'comment.c',
+  'constraint.c',
+  'conversioncmds.c',
+  'copy.c',
+  'copyfrom.c',
+  'copyfromparse.c',
+  'copyto.c',
+  'createas.c',
+  'dbcommands.c',
+  'define.c',
+  'discard.c',
+  'dropcmds.c',
+  'event_trigger.c',
+  'explain.c',
+  'extension.c',
+  'foreigncmds.c',
+  'functioncmds.c',
+  'indexcmds.c',
+  'lockcmds.c',
+  'matview.c',
+  'opclasscmds.c',
+  'operatorcmds.c',
+  'policy.c',
+  'portalcmds.c',
+  'prepare.c',
+  'proclang.c',
+  'publicationcmds.c',
+  'schemacmds.c',
+  'seclabel.c',
+  'sequence.c',
+  'statscmds.c',
+  'subscriptioncmds.c',
+  'tablecmds.c',
+  'tablespace.c',
+  'trigger.c',
+  'tsearchcmds.c',
+  'typecmds.c',
+  'user.c',
+  'vacuum.c',
+  'variable.c',
+  'view.c',
+)
diff --git a/src/backend/executor/meson.build b/src/backend/executor/meson.build
new file mode 100644
index 00000000000..518674cfa28
--- /dev/null
+++ b/src/backend/executor/meson.build
@@ -0,0 +1,67 @@
+backend_sources += files(
+  'execAmi.c',
+  'execAsync.c',
+  'execCurrent.c',
+  'execExpr.c',
+  'execExprInterp.c',
+  'execGrouping.c',
+  'execIndexing.c',
+  'execJunk.c',
+  'execMain.c',
+  'execParallel.c',
+  'execPartition.c',
+  'execProcnode.c',
+  'execReplication.c',
+  'execSRF.c',
+  'execScan.c',
+  'execTuples.c',
+  'execUtils.c',
+  'functions.c',
+  'instrument.c',
+  'nodeAgg.c',
+  'nodeAppend.c',
+  'nodeBitmapAnd.c',
+  'nodeBitmapHeapscan.c',
+  'nodeBitmapIndexscan.c',
+  'nodeBitmapOr.c',
+  'nodeCtescan.c',
+  'nodeCustom.c',
+  'nodeForeignscan.c',
+  'nodeFunctionscan.c',
+  'nodeGather.c',
+  'nodeGatherMerge.c',
+  'nodeGroup.c',
+  'nodeHash.c',
+  'nodeHashjoin.c',
+  'nodeIncrementalSort.c',
+  'nodeIndexonlyscan.c',
+  'nodeIndexscan.c',
+  'nodeLimit.c',
+  'nodeLockRows.c',
+  'nodeMaterial.c',
+  'nodeMemoize.c',
+  'nodeMergeAppend.c',
+  'nodeMergejoin.c',
+  'nodeModifyTable.c',
+  'nodeNamedtuplestorescan.c',
+  'nodeNestloop.c',
+  'nodeProjectSet.c',
+  'nodeRecursiveunion.c',
+  'nodeResult.c',
+  'nodeSamplescan.c',
+  'nodeSeqscan.c',
+  'nodeSetOp.c',
+  'nodeSort.c',
+  'nodeSubplan.c',
+  'nodeSubqueryscan.c',
+  'nodeTableFuncscan.c',
+  'nodeTidrangescan.c',
+  'nodeTidscan.c',
+  'nodeUnique.c',
+  'nodeValuesscan.c',
+  'nodeWindowAgg.c',
+  'nodeWorktablescan.c',
+  'spi.c',
+  'tqueue.c',
+  'tstoreReceiver.c',
+)
diff --git a/src/backend/foreign/meson.build b/src/backend/foreign/meson.build
new file mode 100644
index 00000000000..57463db92c1
--- /dev/null
+++ b/src/backend/foreign/meson.build
@@ -0,0 +1,3 @@
+backend_sources += files(
+  'foreign.c'
+)
diff --git a/src/backend/jit/llvm/meson.build b/src/backend/jit/llvm/meson.build
new file mode 100644
index 00000000000..83a90770bca
--- /dev/null
+++ b/src/backend/jit/llvm/meson.build
@@ -0,0 +1,41 @@
+if llvm.found()
+
+  llvmjit_sources = []
+
+  # Infrastructure
+  llvmjit_sources += files(
+    'llvmjit.c',
+    'llvmjit_error.cpp',
+    'llvmjit_inline.cpp',
+    'llvmjit_wrap.cpp',
+  )
+
+  # Code generation
+  llvmjit_sources += files(
+    'llvmjit_deform.c',
+    'llvmjit_expr.c',
+  )
+
+  llvmjit = shared_module('llvmjit',
+    llvmjit_sources,
+    kwargs: pg_mod_args + {
+      'dependencies': pg_mod_args['dependencies'] + [llvm],
+    }
+  )
+
+  backend_targets += llvmjit
+
+  # Note this is intentionally is not installed to bitcodedir, as it's not
+  # for inlining
+  llvmjit_types = custom_target('llvmjit_types.bc',
+    kwargs: llvm_irgen_kw + {
+      'input': 'llvmjit_types.c',
+      'output': 'llvmjit_types.bc',
+      'depends': [postgres],
+      'install': true,
+      'install_dir': get_option('libdir')
+    }
+  )
+  backend_targets += llvmjit_types
+
+endif
diff --git a/src/backend/jit/meson.build b/src/backend/jit/meson.build
new file mode 100644
index 00000000000..63cd33a4bed
--- /dev/null
+++ b/src/backend/jit/meson.build
@@ -0,0 +1,3 @@
+backend_sources += files(
+  'jit.c'
+)
diff --git a/src/backend/lib/meson.build b/src/backend/lib/meson.build
new file mode 100644
index 00000000000..53292563d34
--- /dev/null
+++ b/src/backend/lib/meson.build
@@ -0,0 +1,12 @@
+backend_sources += files(
+  'binaryheap.c',
+  'bipartite_match.c',
+  'bloomfilter.c',
+  'dshash.c',
+  'hyperloglog.c',
+  'ilist.c',
+  'integerset.c',
+  'knapsack.c',
+  'pairingheap.c',
+  'rbtree.c'
+)
diff --git a/src/backend/libpq/meson.build b/src/backend/libpq/meson.build
new file mode 100644
index 00000000000..49867647155
--- /dev/null
+++ b/src/backend/libpq/meson.build
@@ -0,0 +1,28 @@
+backend_sources += files(
+  'auth-sasl.c',
+  'auth-scram.c',
+  'auth.c',
+  'be-fsstubs.c',
+  'be-secure-common.c',
+  'be-secure.c',
+  'crypt.c',
+  'hba.c',
+  'ifaddr.c',
+  'pqcomm.c',
+  'pqformat.c',
+  'pqmq.c',
+  'pqsignal.c',
+)
+
+if ssl.found()
+  backend_sources += files('be-secure-openssl.c')
+endif
+
+if gssapi.found()
+  backend_sources += files(
+    'be-secure-gssapi.c',
+    'be-gssapi-common.c'
+  )
+endif
+
+install_data('pg_hba.conf.sample', 'pg_ident.conf.sample', install_dir: 'share/')
diff --git a/src/backend/main/meson.build b/src/backend/main/meson.build
new file mode 100644
index 00000000000..241e125f089
--- /dev/null
+++ b/src/backend/main/meson.build
@@ -0,0 +1,2 @@
+main_file = files('main.c')
+backend_sources += main_file
diff --git a/src/backend/meson.build b/src/backend/meson.build
new file mode 100644
index 00000000000..0098411c6b2
--- /dev/null
+++ b/src/backend/meson.build
@@ -0,0 +1,197 @@
+backend_build_deps = [backend_code]
+backend_deps = [dl_dep, thread_dep]
+backend_sources = []
+backend_link_with = [pgport_srv, common_srv]
+backend_c_args = []
+
+generated_backend_sources = []
+
+subdir('access')
+subdir('bootstrap')
+subdir('catalog')
+subdir('commands')
+subdir('executor')
+subdir('foreign')
+subdir('jit')
+subdir('lib')
+subdir('libpq')
+subdir('main')
+subdir('nodes')
+subdir('optimizer')
+subdir('parser')
+subdir('partitioning')
+subdir('port')
+subdir('postmaster')
+subdir('regex')
+subdir('replication')
+subdir('rewrite')
+subdir('statistics')
+subdir('storage')
+subdir('tcop')
+subdir('tsearch')
+subdir('utils')
+
+
+postgres_link_args = []
+postgres_link_depends = []
+
+if host_machine.system() == 'windows'
+  backend_deps += cc.find_library('secur32', required: true)
+
+  if cc.get_id() == 'msvc'
+    postgres_link_args += '/STACK:@0@'.format(cdata.get('WIN32_STACK_RLIMIT'))
+  else
+    postgres_link_args += '-Wl,--stack,@0@'.format(cdata.get('WIN32_STACK_RLIMIT'))
+  endif
+endif
+
+
+# On windows when compiling with msvc we need to make postgres export all its
+# symbols so that extension libraries can use them. For that we need to scan
+# the constituting objects and generate a file specifying all the functions as
+# exported (variables need an "import" declaration in the header, hence
+# PGDLLEXPORT, but functions work without that, due to import libraries
+# basically being trampolines).
+#
+#
+# On meson there's currently no easy way to do this that I found. So we build
+# a static library with all the input objects, run our script to generate
+# exports, and build the final executable using that static library
+#
+#
+# XXX: This needs to be improved.
+#
+
+# NB: There's an outer and inner layer of == windows checks, to allow to
+# exercise most of this on !windows, by widening the outer "layer".
+
+if cc.get_id() == 'msvc' # or true
+
+  postgres_lib = static_library('postgres_lib',
+    backend_sources + timezone_sources + generated_backend_sources,
+    link_whole: backend_link_with,
+    c_pch: '../include/pch/postgres_pch.h',
+    c_args: backend_c_args,
+    implicit_include_directories: false,
+    dependencies: backend_build_deps,
+    build_by_default: false,
+    install: false,
+  )
+
+  postgres_def = custom_target('postgres.def',
+    command: [perl, files('../tools/msvc/gendef2.pl'), 'x64', '@OUTPUT@', \
'@PRIVATE_DIR@', '@INPUT@'], +    input: [postgres_lib, common_srv, pgport_srv],
+    output: 'postgres.def',
+    depends: [postgres_lib, common_srv, pgport_srv],
+    install: false,
+  )
+
+  if cc.get_id() == 'msvc'
+    postgres_link_args += '/DEF:@0@'.format(postgres_def.full_path())
+    postgres_link_depends += postgres_def
+  endif
+
+  # Unfortunately the msvc linker whines when building an executable with just
+  # libraries, hence the reuse of the 'main' object directly.
+
+  postgres = executable('postgres',
+    objects: [postgres_lib.extract_objects(main_file)],
+    link_with: [postgres_lib],
+    link_args: postgres_link_args,
+    link_depends: postgres_link_depends,
+    dependencies: backend_deps,
+    export_dynamic: true,
+    implib: true,
+    kwargs: default_bin_args,
+  )
+
+else
+
+  postgres = executable('postgres',
+    backend_sources + generated_backend_sources + timezone_sources,
+    c_pch: '../include/pch/postgres_pch.h',
+    c_args: backend_c_args,
+    link_args: postgres_link_args,
+    link_with: backend_link_with,
+    export_dynamic: true,
+    dependencies: [backend_build_deps, backend_deps],
+    kwargs: default_bin_args,
+  )
+
+endif
+
+backend_targets += postgres
+
+pg_mod_args = default_mod_args + {
+  'dependencies': [backend_mod_code],
+  'c_args': [],
+  'cpp_args': [],
+ }
+
+if cdata.has('HAVE_VISIBILITY_ATTRIBUTE')
+  pg_mod_args = pg_mod_args + {
+    'c_args': pg_mod_args['c_args'] + ['-fvisibility=hidden'],
+    'cpp_args': pg_mod_args['c_args'] + ['-fvisibility=hidden', \
'-fvisibility-inlines-hidden'], +  }
+endif
+
+# Windows / MacOs link shared modules against postgres. To avoid unnecessary
+# build-time dependencies on other operating systems, only add it when
+# necessary.
+if host_machine.system() == 'windows' or host_machine.system() == 'darwin'
+   pg_mod_args = pg_mod_args + {'link_with': [postgres]}
+endif
+if host_machine.system() == 'darwin'
+   pg_mod_args = pg_mod_args + {'link_args': ['-bundle_loader', \
'@0@'.format(postgres.full_path())]} +endif
+
+
+# Shared modules that, on some OSs, link against the server binary. Only enter
+# these after we defined the server build.
+
+subdir('jit/llvm')
+subdir('replication/libpqwalreceiver')
+subdir('replication/pgoutput')
+subdir('snowball')
+subdir('utils/mb/conversion_procs')
+
+
+if llvm.found()
+
+  # custom_target() insists on targetting files into the current
+  # directory. But we have files with the same name in different
+  # subdirectories.  generators() don't have that problem, but their results
+  # are not installable. The irlink command copies the files for us.
+  #
+  # FIXME: this needs to be in a central place
+  #
+  # generator and custom_'t accept CustomTargetIndex as 'depends', nor do they
+  # like targets with more than one output. However, a custom target accepts
+  # them as input without a problem. So we have the below transitive target :(
+
+  transitive_depend_target = custom_target('stamp',
+    input: generated_headers + generated_backend_headers + \
generated_backend_sources, +    output: 'stamp',
+    command: [touch, '@OUTPUT@'],
+    install: false)
+
+  llvm_gen = generator(llvm_irgen_command,
+    arguments: llvm_irgen_args + g_c_args,
+    depends: transitive_depend_target,
+    depfile: '@BASENAME@.c.bc.d',
+    output: ['@PLAINNAME@.bc']
+  )
+
+  bc_backend_sources = llvm_gen.process(backend_sources,
+    preserve_path_from: meson.current_source_dir())
+
+  postgres_llvm = custom_target('postgres.index.bc',
+    kwargs: llvm_irlink_kw + {
+      'input': bc_backend_sources,
+      'output': ['bitcode'],
+      },
+  )
+
+  backend_targets += postgres_llvm
+
+endif
diff --git a/src/backend/nodes/meson.build b/src/backend/nodes/meson.build
new file mode 100644
index 00000000000..9fca83fba44
--- /dev/null
+++ b/src/backend/nodes/meson.build
@@ -0,0 +1,17 @@
+backend_sources += files(
+  'bitmapset.c',
+  'copyfuncs.c',
+  'equalfuncs.c',
+  'extensible.c',
+  'list.c',
+  'makefuncs.c',
+  'nodeFuncs.c',
+  'nodes.c',
+  'outfuncs.c',
+  'params.c',
+  'print.c',
+  'read.c',
+  'readfuncs.c',
+  'tidbitmap.c',
+  'value.c',
+)
diff --git a/src/backend/optimizer/geqo/meson.build \
b/src/backend/optimizer/geqo/meson.build new file mode 100644
index 00000000000..c04f1dc2dfd
--- /dev/null
+++ b/src/backend/optimizer/geqo/meson.build
@@ -0,0 +1,17 @@
+backend_sources += files(
+  'geqo_copy.c',
+  'geqo_cx.c',
+  'geqo_erx.c',
+  'geqo_eval.c',
+  'geqo_main.c',
+  'geqo_misc.c',
+  'geqo_mutation.c',
+  'geqo_ox1.c',
+  'geqo_ox2.c',
+  'geqo_pmx.c',
+  'geqo_pool.c',
+  'geqo_px.c',
+  'geqo_random.c',
+  'geqo_recombination.c',
+  'geqo_selection.c',
+)
diff --git a/src/backend/optimizer/meson.build b/src/backend/optimizer/meson.build
new file mode 100644
index 00000000000..1ab1d9934ae
--- /dev/null
+++ b/src/backend/optimizer/meson.build
@@ -0,0 +1,5 @@
+subdir('geqo')
+subdir('path')
+subdir('plan')
+subdir('prep')
+subdir('util')
diff --git a/src/backend/optimizer/path/meson.build \
b/src/backend/optimizer/path/meson.build new file mode 100644
index 00000000000..310042e7aee
--- /dev/null
+++ b/src/backend/optimizer/path/meson.build
@@ -0,0 +1,11 @@
+backend_sources += files(
+  'allpaths.c',
+  'clausesel.c',
+  'costsize.c',
+  'equivclass.c',
+  'indxpath.c',
+  'joinpath.c',
+  'joinrels.c',
+  'pathkeys.c',
+  'tidpath.c',
+)
diff --git a/src/backend/optimizer/plan/meson.build \
b/src/backend/optimizer/plan/meson.build new file mode 100644
index 00000000000..22ec65a3845
--- /dev/null
+++ b/src/backend/optimizer/plan/meson.build
@@ -0,0 +1,10 @@
+backend_sources += files(
+  'analyzejoins.c',
+  'createplan.c',
+  'initsplan.c',
+  'planagg.c',
+  'planmain.c',
+  'planner.c',
+  'setrefs.c',
+  'subselect.c',
+)
diff --git a/src/backend/optimizer/prep/meson.build \
b/src/backend/optimizer/prep/meson.build new file mode 100644
index 00000000000..4549a5b0e79
--- /dev/null
+++ b/src/backend/optimizer/prep/meson.build
@@ -0,0 +1,7 @@
+backend_sources += files(
+  'prepagg.c',
+  'prepjointree.c',
+  'prepqual.c',
+  'preptlist.c',
+  'prepunion.c',
+)
diff --git a/src/backend/optimizer/util/meson.build \
b/src/backend/optimizer/util/meson.build new file mode 100644
index 00000000000..e7ceaf566b5
--- /dev/null
+++ b/src/backend/optimizer/util/meson.build
@@ -0,0 +1,16 @@
+backend_sources += files(
+  'appendinfo.c',
+  'clauses.c',
+  'inherit.c',
+  'joininfo.c',
+  'orclauses.c',
+  'paramassign.c',
+  'pathnode.c',
+  'placeholder.c',
+  'plancat.c',
+  'predtest.c',
+  'relnode.c',
+  'restrictinfo.c',
+  'tlist.c',
+  'var.c',
+)
diff --git a/src/backend/parser/meson.build b/src/backend/parser/meson.build
new file mode 100644
index 00000000000..5ce4d09f31b
--- /dev/null
+++ b/src/backend/parser/meson.build
@@ -0,0 +1,43 @@
+backend_sources += files(
+  'analyze.c',
+  'parse_agg.c',
+  'parse_clause.c',
+  'parse_coerce.c',
+  'parse_collate.c',
+  'parse_cte.c',
+  'parse_enr.c',
+  'parse_expr.c',
+  'parse_func.c',
+  'parse_node.c',
+  'parse_oper.c',
+  'parse_param.c',
+  'parse_relation.c',
+  'parse_target.c',
+  'parse_type.c',
+  'parse_utilcmd.c',
+  'scansup.c',
+)
+
+# Build a small utility static lib for the parser. This makes it easier to not
+# depend on gram.h already having been generated for most of the other code
+# (which depends on generated headers having been generated). The generation
+# of the parser is slow...
+
+parser_sources = [files('parser.c')]
+
+backend_scanner = custom_target('scan',
+  input: ['scan.l'],
+  output: ['scan.c'],
+  command: [flex, '-b', '-CF', '-p', '-p', '-o', '@OUTPUT@', '@INPUT0@'])
+parser_sources += backend_scanner[0]
+
+parser_sources += backend_parser_header[0]
+parser_sources += backend_parser_header[1]
+
+parser = static_library('parser',
+  parser_sources + generated_headers,
+  c_pch: '../../include/pch/c_pch.h',
+  dependencies: [backend_code],
+  kwargs: default_lib_args + {'install': false},
+)
+backend_link_with += parser
diff --git a/src/backend/partitioning/meson.build \
b/src/backend/partitioning/meson.build new file mode 100644
index 00000000000..e5e3806a0cc
--- /dev/null
+++ b/src/backend/partitioning/meson.build
@@ -0,0 +1,5 @@
+backend_sources += files(
+  'partbounds.c',
+  'partdesc.c',
+  'partprune.c',
+)
diff --git a/src/backend/port/meson.build b/src/backend/port/meson.build
new file mode 100644
index 00000000000..f1bf7f6d929
--- /dev/null
+++ b/src/backend/port/meson.build
@@ -0,0 +1,28 @@
+backend_sources += files(
+  'atomics.c',
+)
+
+
+if cdata.has('USE_UNNAMED_POSIX_SEMAPHORES') or \
cdata.has('USE_NAMED_POSIX_SEMAPHORES') +   backend_sources += files('posix_sema.c')
+endif
+
+if cdata.has('USE_SYSV_SEMAPHORES')
+   backend_sources += files('sysv_sema.c')
+endif
+
+if cdata.has('USE_WIN32_SEMAPHORES')
+   backend_sources += files('win32_sema.c')
+endif
+
+if cdata.has('USE_SYSV_SHARED_MEMORY')
+   backend_sources += files('sysv_shmem.c')
+endif
+
+if cdata.has('USE_WIN32_SHARED_MEMORY')
+   backend_sources += files('win32_shmem.c')
+endif
+
+if host_machine.system() == 'windows'
+  subdir('win32')
+endif
diff --git a/src/backend/port/win32/meson.build b/src/backend/port/win32/meson.build
new file mode 100644
index 00000000000..68fe4cc3cd0
--- /dev/null
+++ b/src/backend/port/win32/meson.build
@@ -0,0 +1,6 @@
+backend_sources += files(
+  'crashdump.c',
+  'signal.c',
+  'socket.c',
+  'timer.c',
+)
diff --git a/src/backend/postmaster/meson.build b/src/backend/postmaster/meson.build
new file mode 100644
index 00000000000..803405683e2
--- /dev/null
+++ b/src/backend/postmaster/meson.build
@@ -0,0 +1,15 @@
+backend_sources += files(
+  'autovacuum.c',
+  'auxprocess.c',
+  'bgworker.c',
+  'bgwriter.c',
+  'checkpointer.c',
+  'fork_process.c',
+  'interrupt.c',
+  'pgarch.c',
+  'pgstat.c',
+  'postmaster.c',
+  'startup.c',
+  'syslogger.c',
+  'walwriter.c',
+)
diff --git a/src/backend/regex/meson.build b/src/backend/regex/meson.build
new file mode 100644
index 00000000000..d08e21cd6d6
--- /dev/null
+++ b/src/backend/regex/meson.build
@@ -0,0 +1,15 @@
+backend_sources += files(
+  'regcomp.c',
+  'regerror.c',
+  'regexec.c',
+  'regexport.c',
+  'regfree.c',
+  'regprefix.c'
+)
+
+#FIXME
+# mark inclusion dependencies between .c files explicitly
+#regcomp.o: regcomp.c regc_lex.c regc_color.c regc_nfa.c regc_cvec.c \
+#        regc_locale.c regc_pg_locale.c
+#
+#regexec.o: regexec.c rege_dfa.c
diff --git a/src/backend/replication/libpqwalreceiver/meson.build \
b/src/backend/replication/libpqwalreceiver/meson.build new file mode 100644
index 00000000000..3fc786c80a0
--- /dev/null
+++ b/src/backend/replication/libpqwalreceiver/meson.build
@@ -0,0 +1,13 @@
+libpqwalreceiver_sources = files(
+  'libpqwalreceiver.c',
+)
+
+libpqwalreceiver = shared_module('pqwalreceiver',
+  libpqwalreceiver_sources,
+  kwargs: pg_mod_args + {
+    'name_prefix': 'lib',
+    'dependencies': pg_mod_args['dependencies'] + [libpq],
+  }
+)
+
+backend_targets += libpqwalreceiver
diff --git a/src/backend/replication/logical/meson.build \
b/src/backend/replication/logical/meson.build new file mode 100644
index 00000000000..773583a12ba
--- /dev/null
+++ b/src/backend/replication/logical/meson.build
@@ -0,0 +1,14 @@
+backend_sources += files(
+  'decode.c',
+  'launcher.c',
+  'logical.c',
+  'logicalfuncs.c',
+  'message.c',
+  'origin.c',
+  'proto.c',
+  'relation.c',
+  'reorderbuffer.c',
+  'snapbuild.c',
+  'tablesync.c',
+  'worker.c',
+)
diff --git a/src/backend/replication/meson.build \
b/src/backend/replication/meson.build new file mode 100644
index 00000000000..ee12c6d49da
--- /dev/null
+++ b/src/backend/replication/meson.build
@@ -0,0 +1,42 @@
+backend_sources += files(
+  'backup_manifest.c',
+  'basebackup.c',
+  'slot.c',
+  'slotfuncs.c',
+  'syncrep.c',
+  'walreceiver.c',
+  'walreceiverfuncs.c',
+  'walsender.c',
+)
+
+# [sync]repl_scanner is compiled as part of [sync]repl_gram. The
+# ordering is enforced by making the generation of grammar depend on
+# the scanner generation. That's unnecessarily strict, but overall
+# harmless.
+
+repl_scanner = custom_target('repl_scanner',
+  input : files('repl_scanner.l'),
+  output : ['repl_scanner.c'],
+  command: [flex, '-o', '@OUTPUT@', '@INPUT@']
+)
+
+generated_backend_sources += custom_target('repl_gram',
+  input: 'repl_gram.y',
+  output: 'repl_gram.c',
+  depends: repl_scanner,
+  command: [bison, bisonflags, '-o', '@OUTPUT@', '@INPUT0@'])
+
+
+syncrep_scanner = custom_target('syncrep_scanner',
+  input: 'syncrep_scanner.l',
+  output: 'syncrep_scanner.c',
+  command: [flex, '-o', '@OUTPUT@', '@INPUT@'])
+
+generated_backend_sources += custom_target('syncrep_gram',
+  input: 'syncrep_gram.y',
+  output: 'syncrep_gram.c',
+  depends: syncrep_scanner,
+  command: [bison, bisonflags, '-o', '@OUTPUT@', '@INPUT0@'])
+
+
+subdir('logical')
diff --git a/src/backend/replication/pgoutput/meson.build \
b/src/backend/replication/pgoutput/meson.build new file mode 100644
index 00000000000..8ff0a0c6133
--- /dev/null
+++ b/src/backend/replication/pgoutput/meson.build
@@ -0,0 +1,11 @@
+pgoutput_sources = files(
+  'pgoutput.c',
+)
+
+pgoutput = shared_module('pgoutput',
+  pgoutput_sources,
+  kwargs: pg_mod_args + {
+  }
+)
+
+backend_targets += pgoutput
diff --git a/src/backend/rewrite/meson.build b/src/backend/rewrite/meson.build
new file mode 100644
index 00000000000..032e2e409b5
--- /dev/null
+++ b/src/backend/rewrite/meson.build
@@ -0,0 +1,9 @@
+backend_sources += files(
+  'rewriteDefine.c',
+  'rewriteHandler.c',
+  'rewriteManip.c',
+  'rewriteRemove.c',
+  'rewriteSearchCycle.c',
+  'rewriteSupport.c',
+  'rowsecurity.c'
+)
diff --git a/src/backend/snowball/meson.build b/src/backend/snowball/meson.build
new file mode 100644
index 00000000000..b1e52e9a0c3
--- /dev/null
+++ b/src/backend/snowball/meson.build
@@ -0,0 +1,83 @@
+dict_snowball_sources = files(
+  'dict_snowball.c',
+  'libstemmer/api.c',
+  'libstemmer/utilities.c',
+)
+
+dict_snowball_sources += files(
+  'libstemmer/stem_ISO_8859_1_basque.c',
+  'libstemmer/stem_ISO_8859_1_catalan.c',
+  'libstemmer/stem_ISO_8859_1_danish.c',
+  'libstemmer/stem_ISO_8859_1_dutch.c',
+  'libstemmer/stem_ISO_8859_1_english.c',
+  'libstemmer/stem_ISO_8859_1_finnish.c',
+  'libstemmer/stem_ISO_8859_1_french.c',
+  'libstemmer/stem_ISO_8859_1_german.c',
+  'libstemmer/stem_ISO_8859_1_indonesian.c',
+  'libstemmer/stem_ISO_8859_1_irish.c',
+  'libstemmer/stem_ISO_8859_1_italian.c',
+  'libstemmer/stem_ISO_8859_1_norwegian.c',
+  'libstemmer/stem_ISO_8859_1_porter.c',
+  'libstemmer/stem_ISO_8859_1_portuguese.c',
+  'libstemmer/stem_ISO_8859_1_spanish.c',
+  'libstemmer/stem_ISO_8859_1_swedish.c',
+  'libstemmer/stem_ISO_8859_2_hungarian.c',
+  'libstemmer/stem_ISO_8859_2_romanian.c',
+  'libstemmer/stem_KOI8_R_russian.c',
+  'libstemmer/stem_UTF_8_arabic.c',
+  'libstemmer/stem_UTF_8_armenian.c',
+  'libstemmer/stem_UTF_8_basque.c',
+  'libstemmer/stem_UTF_8_catalan.c',
+  'libstemmer/stem_UTF_8_danish.c',
+  'libstemmer/stem_UTF_8_dutch.c',
+  'libstemmer/stem_UTF_8_english.c',
+  'libstemmer/stem_UTF_8_finnish.c',
+  'libstemmer/stem_UTF_8_french.c',
+  'libstemmer/stem_UTF_8_german.c',
+  'libstemmer/stem_UTF_8_greek.c',
+  'libstemmer/stem_UTF_8_hindi.c',
+  'libstemmer/stem_UTF_8_hungarian.c',
+  'libstemmer/stem_UTF_8_indonesian.c',
+  'libstemmer/stem_UTF_8_irish.c',
+  'libstemmer/stem_UTF_8_italian.c',
+  'libstemmer/stem_UTF_8_lithuanian.c',
+  'libstemmer/stem_UTF_8_nepali.c',
+  'libstemmer/stem_UTF_8_norwegian.c',
+  'libstemmer/stem_UTF_8_porter.c',
+  'libstemmer/stem_UTF_8_portuguese.c',
+  'libstemmer/stem_UTF_8_romanian.c',
+  'libstemmer/stem_UTF_8_russian.c',
+  'libstemmer/stem_UTF_8_serbian.c',
+  'libstemmer/stem_UTF_8_spanish.c',
+  'libstemmer/stem_UTF_8_swedish.c',
+  'libstemmer/stem_UTF_8_tamil.c',
+  'libstemmer/stem_UTF_8_turkish.c',
+  'libstemmer/stem_UTF_8_yiddish.c',
+)
+
+# see comment in src/include/snowball/header.h
+stemmer_inc = include_directories('../../include/snowball')
+
+dict_snowball = shared_module('dict_snowball',
+  dict_snowball_sources,
+  c_pch: '../../include/pch/postgres_pch.h',
+  kwargs: pg_mod_args + {
+    'include_directories': [stemmer_inc],
+  }
+)
+
+snowball_create = custom_target('snowball_create',
+  input: ['snowball_create.pl'],
+  output: ['snowball_create.sql'],
+  depfile: 'snowball_create.dep',
+  command: [perl, '@INPUT0@', '--input', '@CURRENT_SOURCE_DIR@', '--output', \
'@OUTDIR@'], +  install: true,
+  install_dir: get_option('datadir'))
+
+# FIXME: check whether the logic to select languages currently in Makefile is needed
+install_subdir('stopwords',
+  install_dir: get_option('datadir') / 'tsearch_data',
+  strip_directory: true)
+
+backend_targets += dict_snowball
+backend_targets += snowball_create
diff --git a/src/backend/statistics/meson.build b/src/backend/statistics/meson.build
new file mode 100644
index 00000000000..8530c55f73c
--- /dev/null
+++ b/src/backend/statistics/meson.build
@@ -0,0 +1,6 @@
+backend_sources += files(
+  'dependencies.c',
+  'extended_stats.c',
+  'mcv.c',
+  'mvdistinct.c',
+)
diff --git a/src/backend/storage/buffer/meson.build \
b/src/backend/storage/buffer/meson.build new file mode 100644
index 00000000000..56a59b52484
--- /dev/null
+++ b/src/backend/storage/buffer/meson.build
@@ -0,0 +1,7 @@
+backend_sources += files(
+  'buf_init.c',
+  'buf_table.c',
+  'bufmgr.c',
+  'freelist.c',
+  'localbuf.c',
+)
diff --git a/src/backend/storage/file/meson.build \
b/src/backend/storage/file/meson.build new file mode 100644
index 00000000000..e1d5047d4aa
--- /dev/null
+++ b/src/backend/storage/file/meson.build
@@ -0,0 +1,8 @@
+backend_sources += files(
+  'buffile.c',
+  'copydir.c',
+  'fd.c',
+  'fileset.c',
+  'reinit.c',
+  'sharedfileset.c',
+)
diff --git a/src/backend/storage/freespace/meson.build \
b/src/backend/storage/freespace/meson.build new file mode 100644
index 00000000000..e4200ea6527
--- /dev/null
+++ b/src/backend/storage/freespace/meson.build
@@ -0,0 +1,5 @@
+backend_sources += files(
+  'freespace.c',
+  'fsmpage.c',
+  'indexfsm.c',
+)
diff --git a/src/backend/storage/ipc/meson.build \
b/src/backend/storage/ipc/meson.build new file mode 100644
index 00000000000..516bc1d0193
--- /dev/null
+++ b/src/backend/storage/ipc/meson.build
@@ -0,0 +1,20 @@
+backend_sources += files(
+  'barrier.c',
+  'dsm.c',
+  'dsm_impl.c',
+  'ipc.c',
+  'ipci.c',
+  'latch.c',
+  'pmsignal.c',
+  'procarray.c',
+  'procsignal.c',
+  'shm_mq.c',
+  'shm_toc.c',
+  'shmem.c',
+  'shmqueue.c',
+  'signalfuncs.c',
+  'sinval.c',
+  'sinvaladt.c',
+  'standby.c',
+
+)
diff --git a/src/backend/storage/large_object/meson.build \
b/src/backend/storage/large_object/meson.build new file mode 100644
index 00000000000..8a181ab9b34
--- /dev/null
+++ b/src/backend/storage/large_object/meson.build
@@ -0,0 +1,3 @@
+backend_sources += files(
+  'inv_api.c',
+)
diff --git a/src/backend/storage/lmgr/meson.build \
b/src/backend/storage/lmgr/meson.build new file mode 100644
index 00000000000..938e7f89894
--- /dev/null
+++ b/src/backend/storage/lmgr/meson.build
@@ -0,0 +1,18 @@
+backend_sources += files(
+  'condition_variable.c',
+  'deadlock.c',
+  'lmgr.c',
+  'lock.c',
+  'lwlock.c',
+  'predicate.c',
+  'proc.c',
+  's_lock.c',
+  'spin.c',
+)
+
+lwlocknames_backend = custom_target('lwlocknames',
+  input : files('lwlocknames.txt'),
+  output : ['lwlocknames.c', 'lwlocknames.h'],
+  command : [perl, files('generate-lwlocknames.pl'), '-o', '@OUTDIR@', '@INPUT@']
+)
+generated_backend_sources += lwlocknames_backend[0]
diff --git a/src/backend/storage/meson.build b/src/backend/storage/meson.build
new file mode 100644
index 00000000000..daad628d74c
--- /dev/null
+++ b/src/backend/storage/meson.build
@@ -0,0 +1,9 @@
+subdir('buffer')
+subdir('file')
+subdir('freespace')
+subdir('ipc')
+subdir('large_object')
+subdir('lmgr')
+subdir('page')
+subdir('smgr')
+subdir('sync')
diff --git a/src/backend/storage/page/meson.build \
b/src/backend/storage/page/meson.build new file mode 100644
index 00000000000..2ecd16c952c
--- /dev/null
+++ b/src/backend/storage/page/meson.build
@@ -0,0 +1,5 @@
+backend_sources += files(
+  'bufpage.c',
+  'checksum.c',
+  'itemptr.c',
+)
diff --git a/src/backend/storage/smgr/meson.build \
b/src/backend/storage/smgr/meson.build new file mode 100644
index 00000000000..fdeb1223b32
--- /dev/null
+++ b/src/backend/storage/smgr/meson.build
@@ -0,0 +1,4 @@
+backend_sources += files(
+  'md.c',
+  'smgr.c',
+)
diff --git a/src/backend/storage/sync/meson.build \
b/src/backend/storage/sync/meson.build new file mode 100644
index 00000000000..05148b91a8e
--- /dev/null
+++ b/src/backend/storage/sync/meson.build
@@ -0,0 +1,4 @@
+backend_sources += files(
+  'sync.c',
+
+)
diff --git a/src/backend/tcop/meson.build b/src/backend/tcop/meson.build
new file mode 100644
index 00000000000..fb54aae8122
--- /dev/null
+++ b/src/backend/tcop/meson.build
@@ -0,0 +1,8 @@
+backend_sources += files(
+  'cmdtag.c',
+  'dest.c',
+  'fastpath.c',
+  'postgres.c',
+  'pquery.c',
+  'utility.c',
+)
diff --git a/src/backend/tsearch/meson.build b/src/backend/tsearch/meson.build
new file mode 100644
index 00000000000..460036b6d4c
--- /dev/null
+++ b/src/backend/tsearch/meson.build
@@ -0,0 +1,21 @@
+backend_sources += files(
+  'dict.c',
+  'dict_ispell.c',
+  'dict_simple.c',
+  'dict_synonym.c',
+  'dict_thesaurus.c',
+  'regis.c',
+  'spell.c',
+  'to_tsany.c',
+  'ts_locale.c',
+  'ts_parse.c',
+  'ts_selfuncs.c',
+  'ts_typanalyze.c',
+  'ts_utils.c',
+  'wparser.c',
+  'wparser_def.c',
+)
+
+install_subdir('dicts',
+  install_dir: get_option('datadir') / 'tsearch_data',
+  strip_directory: true)
diff --git a/src/backend/utils/activity/meson.build \
b/src/backend/utils/activity/meson.build new file mode 100644
index 00000000000..cef26eb564b
--- /dev/null
+++ b/src/backend/utils/activity/meson.build
@@ -0,0 +1,5 @@
+backend_sources += files(
+  'backend_progress.c',
+  'backend_status.c',
+  'wait_event.c',
+)
diff --git a/src/backend/utils/adt/meson.build b/src/backend/utils/adt/meson.build
new file mode 100644
index 00000000000..e1cea1eb4e4
--- /dev/null
+++ b/src/backend/utils/adt/meson.build
@@ -0,0 +1,118 @@
+backend_sources += files(
+  'acl.c',
+  'amutils.c',
+  'array_expanded.c',
+  'array_selfuncs.c',
+  'array_typanalyze.c',
+  'array_userfuncs.c',
+  'arrayfuncs.c',
+  'arraysubs.c',
+  'arrayutils.c',
+  'ascii.c',
+  'bool.c',
+  'cash.c',
+  'char.c',
+  'cryptohashfuncs.c',
+  'date.c',
+  'datetime.c',
+  'datum.c',
+  'dbsize.c',
+  'domains.c',
+  'encode.c',
+  'enum.c',
+  'expandeddatum.c',
+  'expandedrecord.c',
+  'float.c',
+  'format_type.c',
+  'formatting.c',
+  'genfile.c',
+  'geo_ops.c',
+  'geo_selfuncs.c',
+  'geo_spgist.c',
+  'inet_cidr_ntop.c',
+  'inet_net_pton.c',
+  'int.c',
+  'int8.c',
+  'json.c',
+  'jsonb.c',
+  'jsonb_gin.c',
+  'jsonb_op.c',
+  'jsonb_util.c',
+  'jsonfuncs.c',
+  'jsonbsubs.c',
+  'jsonpath.c',
+  'jsonpath_exec.c',
+  'like.c',
+  'like_support.c',
+  'lockfuncs.c',
+  'mac.c',
+  'mac8.c',
+  'mcxtfuncs.c',
+  'misc.c',
+  'multirangetypes.c',
+  'multirangetypes_selfuncs.c',
+  'name.c',
+  'network.c',
+  'network_gist.c',
+  'network_selfuncs.c',
+  'network_spgist.c',
+  'numeric.c',
+  'numutils.c',
+  'oid.c',
+  'oracle_compat.c',
+  'orderedsetaggs.c',
+  'partitionfuncs.c',
+  'pg_locale.c',
+  'pg_lsn.c',
+  'pg_upgrade_support.c',
+  'pgstatfuncs.c',
+  'pseudotypes.c',
+  'quote.c',
+  'rangetypes.c',
+  'rangetypes_gist.c',
+  'rangetypes_selfuncs.c',
+  'rangetypes_spgist.c',
+  'rangetypes_typanalyze.c',
+  'regexp.c',
+  'regproc.c',
+  'ri_triggers.c',
+  'rowtypes.c',
+  'ruleutils.c',
+  'selfuncs.c',
+  'tid.c',
+  'timestamp.c',
+  'trigfuncs.c',
+  'tsginidx.c',
+  'tsgistidx.c',
+  'tsquery.c',
+  'tsquery_cleanup.c',
+  'tsquery_gist.c',
+  'tsquery_op.c',
+  'tsquery_rewrite.c',
+  'tsquery_util.c',
+  'tsrank.c',
+  'tsvector.c',
+  'tsvector_op.c',
+  'tsvector_parser.c',
+  'uuid.c',
+  'varbit.c',
+  'varchar.c',
+  'varlena.c',
+  'version.c',
+  'windowfuncs.c',
+  'xid.c',
+  'xid8funcs.c',
+  'xml.c',
+)
+
+
+jsonpath_scan = custom_target('jsonpath_scan',
+  input: ['jsonpath_scan.l'],
+  output: ['jsonpath_scan.c'],
+  command: [flex, '-b', '-CF', '-p', '-p', '-o', '@OUTPUT@', '@INPUT@'])
+
+# jsonpath_scan is compiled as part of jsonpath_gram
+generated_backend_sources += custom_target('jsonpath_parse',
+  input: ['jsonpath_gram.y', jsonpath_scan[0]],
+  output: ['jsonpath_gram.c'],
+  command: [bison, bisonflags, '-o', '@OUTPUT@', '@INPUT0@'])
diff --git a/src/backend/utils/cache/meson.build \
b/src/backend/utils/cache/meson.build new file mode 100644
index 00000000000..92972db52ad
--- /dev/null
+++ b/src/backend/utils/cache/meson.build
@@ -0,0 +1,16 @@
+backend_sources += files(
+  'attoptcache.c',
+  'catcache.c',
+  'evtcache.c',
+  'inval.c',
+  'lsyscache.c',
+  'partcache.c',
+  'plancache.c',
+  'relcache.c',
+  'relfilenodemap.c',
+  'relmapper.c',
+  'spccache.c',
+  'syscache.c',
+  'ts_cache.c',
+  'typcache.c',
+)
diff --git a/src/backend/utils/error/meson.build \
b/src/backend/utils/error/meson.build new file mode 100644
index 00000000000..ff0ae388263
--- /dev/null
+++ b/src/backend/utils/error/meson.build
@@ -0,0 +1,4 @@
+backend_sources += files(
+  'assert.c',
+  'elog.c',
+  )
diff --git a/src/backend/utils/fmgr/meson.build b/src/backend/utils/fmgr/meson.build
new file mode 100644
index 00000000000..e545b424fd2
--- /dev/null
+++ b/src/backend/utils/fmgr/meson.build
@@ -0,0 +1,8 @@
+backend_sources += files(
+  'dfmgr.c',
+  'fmgr.c',
+  'funcapi.c',
+)
+
+# fmgrtab.c
+generated_backend_sources += fmgrtab_target[2]
diff --git a/src/backend/utils/hash/meson.build b/src/backend/utils/hash/meson.build
new file mode 100644
index 00000000000..242e2f0ecdf
--- /dev/null
+++ b/src/backend/utils/hash/meson.build
@@ -0,0 +1,4 @@
+backend_sources += files(
+  'dynahash.c',
+  'pg_crc.c'
+)
diff --git a/src/backend/utils/init/meson.build b/src/backend/utils/init/meson.build
new file mode 100644
index 00000000000..ec9d72c3df1
--- /dev/null
+++ b/src/backend/utils/init/meson.build
@@ -0,0 +1,4 @@
+backend_sources += files(
+  'globals.c',
+  'miscinit.c',
+  'postinit.c')
diff --git a/src/backend/utils/mb/conversion_procs/meson.build \
b/src/backend/utils/mb/conversion_procs/meson.build new file mode 100644
index 00000000000..b84a78b6318
--- /dev/null
+++ b/src/backend/utils/mb/conversion_procs/meson.build
@@ -0,0 +1,38 @@
+encodings = {
+  'cyrillic_and_mic': ['cyrillic_and_mic/cyrillic_and_mic.c'],
+  'euc2004_sjis2004': ['euc2004_sjis2004/euc2004_sjis2004.c'],
+  'euc_cn_and_mic': ['euc_cn_and_mic/euc_cn_and_mic.c'],
+  'euc_jp_and_sjis': ['euc_jp_and_sjis/euc_jp_and_sjis.c'],
+  'euc_kr_and_mic': ['euc_kr_and_mic/euc_kr_and_mic.c'],
+  'euc_tw_and_big5': [
+    'euc_tw_and_big5/euc_tw_and_big5.c',
+    'euc_tw_and_big5/big5.c',
+  ],
+  'latin2_and_win1250': ['latin2_and_win1250/latin2_and_win1250.c'],
+  'latin_and_mic': ['latin_and_mic/latin_and_mic.c'],
+  'utf8_and_big5': ['utf8_and_big5/utf8_and_big5.c'],
+  'utf8_and_cyrillic': ['utf8_and_cyrillic/utf8_and_cyrillic.c'],
+  'utf8_and_euc2004': ['utf8_and_euc2004/utf8_and_euc2004.c'],
+  'utf8_and_euc_cn': ['utf8_and_euc_cn/utf8_and_euc_cn.c'],
+  'utf8_and_euc_jp': ['utf8_and_euc_jp/utf8_and_euc_jp.c'],
+  'utf8_and_euc_kr': ['utf8_and_euc_kr/utf8_and_euc_kr.c'],
+  'utf8_and_euc_tw': ['utf8_and_euc_tw/utf8_and_euc_tw.c'],
+  'utf8_and_gb18030': ['utf8_and_gb18030/utf8_and_gb18030.c'],
+  'utf8_and_gbk': ['utf8_and_gbk/utf8_and_gbk.c'],
+  'utf8_and_iso8859': ['utf8_and_iso8859/utf8_and_iso8859.c'],
+  'utf8_and_iso8859_1': ['utf8_and_iso8859_1/utf8_and_iso8859_1.c'],
+  'utf8_and_johab': ['utf8_and_johab/utf8_and_johab.c'],
+  'utf8_and_sjis': ['utf8_and_sjis/utf8_and_sjis.c'],
+  'utf8_and_sjis2004': ['utf8_and_sjis2004/utf8_and_sjis2004.c'],
+  'utf8_and_uhc': ['utf8_and_uhc/utf8_and_uhc.c'],
+  'utf8_and_win': ['utf8_and_win/utf8_and_win.c'],
+}
+
+foreach encoding, sources : encodings
+  backend_targets += shared_module(encoding,
+    sources,
+    kwargs: pg_mod_args + {
+    }
+  )
+
+endforeach
diff --git a/src/backend/utils/mb/meson.build b/src/backend/utils/mb/meson.build
new file mode 100644
index 00000000000..39e45638db0
--- /dev/null
+++ b/src/backend/utils/mb/meson.build
@@ -0,0 +1,9 @@
+backend_sources += files(
+  'conv.c',
+  'mbutils.c',
+  'stringinfo_mb.c',
+  'wstrcmp.c',
+  'wstrncmp.c',
+)
+
+# Note we only enter conversion_procs once the backend build is defined
diff --git a/src/backend/utils/meson.build b/src/backend/utils/meson.build
new file mode 100644
index 00000000000..afb1c0346ba
--- /dev/null
+++ b/src/backend/utils/meson.build
@@ -0,0 +1,13 @@
+subdir('activity')
+subdir('adt')
+subdir('cache')
+subdir('error')
+subdir('fmgr')
+subdir('hash')
+subdir('init')
+subdir('mb')
+subdir('misc')
+subdir('mmgr')
+subdir('resowner')
+subdir('sort')
+subdir('time')
diff --git a/src/backend/utils/misc/meson.build b/src/backend/utils/misc/meson.build
new file mode 100644
index 00000000000..2c0090ad337
--- /dev/null
+++ b/src/backend/utils/misc/meson.build
@@ -0,0 +1,28 @@
+backend_sources += files(
+  'help_config.c',
+  'pg_config.c',
+  'pg_controldata.c',
+  'pg_rusage.c',
+  'ps_status.c',
+  'queryenvironment.c',
+  'queryjumble.c',
+  'rls.c',
+  'sampling.c',
+  'superuser.c',
+  'timeout.c',
+  'tzparser.c',
+  'guc.c',
+)
+
+# guc-file.c.h is compiled as part of guc.c
+guc_scan = custom_target('guc_scan',
+  input: ['guc-file.l'],
+  output: ['guc-file.c.h'],
+  command: [flex, '-o', '@OUTPUT@', '@INPUT@'])
+
+generated_backend_sources += guc_scan
+
+backend_build_deps += declare_dependency(sources: [guc_scan],
+  include_directories: include_directories('.'))
+
+install_data('postgresql.conf.sample', install_dir: 'share/')
diff --git a/src/backend/utils/mmgr/meson.build b/src/backend/utils/mmgr/meson.build
new file mode 100644
index 00000000000..641bb181ba1
--- /dev/null
+++ b/src/backend/utils/mmgr/meson.build
@@ -0,0 +1,10 @@
+backend_sources += files(
+  'aset.c',
+  'dsa.c',
+  'freepage.c',
+  'generation.c',
+  'mcxt.c',
+  'memdebug.c',
+  'portalmem.c',
+  'slab.c',
+)
diff --git a/src/backend/utils/resowner/meson.build \
b/src/backend/utils/resowner/meson.build new file mode 100644
index 00000000000..d30891ca027
--- /dev/null
+++ b/src/backend/utils/resowner/meson.build
@@ -0,0 +1,3 @@
+backend_sources += files(
+  'resowner.c'
+)
diff --git a/src/backend/utils/sort/meson.build b/src/backend/utils/sort/meson.build
new file mode 100644
index 00000000000..b626bdc9d96
--- /dev/null
+++ b/src/backend/utils/sort/meson.build
@@ -0,0 +1,7 @@
+backend_sources += files(
+  'logtape.c',
+  'sharedtuplestore.c',
+  'sortsupport.c',
+  'tuplesort.c',
+  'tuplestore.c',
+)
diff --git a/src/backend/utils/time/meson.build b/src/backend/utils/time/meson.build
new file mode 100644
index 00000000000..6fff8792bb0
--- /dev/null
+++ b/src/backend/utils/time/meson.build
@@ -0,0 +1,4 @@
+backend_sources += files(
+  'combocid.c',
+  'snapmgr.c',
+)
diff --git a/src/bin/initdb/meson.build b/src/bin/initdb/meson.build
new file mode 100644
index 00000000000..52f679e3116
--- /dev/null
+++ b/src/bin/initdb/meson.build
@@ -0,0 +1,24 @@
+initdb_sources = files(
+  'findtimezone.c',
+  'initdb.c'
+)
+
+initdb_sources += timezone_localtime_source
+
+#fixme: reimplement libpq_pgport logic
+
+executable('initdb',
+  initdb_sources,
+  include_directories: [timezone_inc],
+  dependencies: [frontend_code, libpq],
+  kwargs: default_bin_args,
+)
+
+tap_tests += {
+  'name': 'initdb',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tests': [
+    't/001_initdb.pl'
+  ]
+}
diff --git a/src/bin/meson.build b/src/bin/meson.build
new file mode 100644
index 00000000000..5fd5a9d2f98
--- /dev/null
+++ b/src/bin/meson.build
@@ -0,0 +1,20 @@
+subdir('initdb')
+subdir('pg_amcheck')
+subdir('pg_archivecleanup')
+subdir('pg_basebackup')
+subdir('pg_checksums')
+subdir('pg_config')
+subdir('pg_controldata')
+subdir('pg_ctl')
+subdir('pg_dump')
+subdir('pg_resetwal')
+subdir('pg_rewind')
+subdir('pg_test_fsync')
+subdir('pg_test_timing')
+subdir('pg_upgrade')
+subdir('pg_verifybackup')
+subdir('pg_waldump')
+subdir('pgbench')
+subdir('pgevent')
+subdir('psql')
+subdir('scripts')
diff --git a/src/bin/pg_amcheck/meson.build b/src/bin/pg_amcheck/meson.build
new file mode 100644
index 00000000000..69eaef8f141
--- /dev/null
+++ b/src/bin/pg_amcheck/meson.build
@@ -0,0 +1,22 @@
+pg_amcheck_sources = files(
+  'pg_amcheck.c'
+)
+
+pg_amcheck = executable('pg_amcheck',
+  pg_amcheck_sources,
+  dependencies: [frontend_code, libpq],
+  kwargs: default_bin_args,
+)
+
+tap_tests += {
+  'name': 'pg_amcheck',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tests': [
+    't/001_basic.pl',
+    't/002_nonesuch.pl',
+    't/003_check.pl',
+    't/004_verify_heapam.pl',
+    't/005_opclass_damage.pl',
+  ]
+}
diff --git a/src/bin/pg_archivecleanup/meson.build \
b/src/bin/pg_archivecleanup/meson.build new file mode 100644
index 00000000000..27742fafab7
--- /dev/null
+++ b/src/bin/pg_archivecleanup/meson.build
@@ -0,0 +1,14 @@
+pg_archivecleanup = executable('pg_archivecleanup',
+  ['pg_archivecleanup.c'],
+  dependencies: [frontend_code],
+  kwargs: default_bin_args,
+)
+
+tap_tests += {
+  'name': 'pg_archivecleanup',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tests': [
+    't/010_pg_archivecleanup.pl'
+  ]
+}
diff --git a/src/bin/pg_basebackup/meson.build b/src/bin/pg_basebackup/meson.build
new file mode 100644
index 00000000000..a629b8b02f5
--- /dev/null
+++ b/src/bin/pg_basebackup/meson.build
@@ -0,0 +1,44 @@
+common_sources = files(
+  'receivelog.c',
+  'streamutil.c',
+  'walmethods.c',
+)
+
+pg_basebackup_common = static_library('pg_basebackup_common',
+  common_sources,
+  dependencies: [frontend_code, libpq, zlib],
+  kwargs: internal_lib_args,
+)
+
+executable('pg_basebackup',
+  'pg_basebackup.c',
+  link_with: [pg_basebackup_common],
+  dependencies: [frontend_code, libpq, zlib],
+  kwargs: default_bin_args,
+)
+
+executable('pg_receivewal',
+  'pg_receivewal.c',
+  link_with: [pg_basebackup_common],
+  dependencies: [frontend_code, libpq],
+  kwargs: default_bin_args,
+)
+
+executable('pg_recvlogical',
+  'pg_recvlogical.c',
+  link_with: [pg_basebackup_common],
+  dependencies: [frontend_code, libpq],
+  kwargs: default_bin_args,
+)
+
+tap_tests += {
+  'name' : 'pg_basebackup',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'env': {'GZIP_PROGRAM': gzip.path(), 'TAR': tar.path()},
+  'tests': [
+    't/010_pg_basebackup.pl',
+    't/020_pg_receivewal.pl',
+    't/030_pg_recvlogical.pl',
+  ]
+}
diff --git a/src/bin/pg_checksums/meson.build b/src/bin/pg_checksums/meson.build
new file mode 100644
index 00000000000..bbf9582b904
--- /dev/null
+++ b/src/bin/pg_checksums/meson.build
@@ -0,0 +1,16 @@
+executable('pg_checksums',
+  ['pg_checksums.c'],
+  include_directories: [timezone_inc],
+  dependencies: [frontend_code],
+  kwargs: default_bin_args,
+)
+
+tap_tests += {
+  'name': 'pg_checksums',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tests': [
+    't/001_basic.pl',
+    't/002_actions.pl'
+  ]
+}
diff --git a/src/bin/pg_config/meson.build b/src/bin/pg_config/meson.build
new file mode 100644
index 00000000000..df0eb13f636
--- /dev/null
+++ b/src/bin/pg_config/meson.build
@@ -0,0 +1,14 @@
+executable('pg_config',
+  ['pg_config.c'],
+  dependencies: [frontend_code],
+  kwargs: default_bin_args,
+)
+
+tap_tests += {
+  'name': 'pg_config',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tests': [
+    't/001_pg_config.pl',
+  ]
+}
diff --git a/src/bin/pg_controldata/meson.build b/src/bin/pg_controldata/meson.build
new file mode 100644
index 00000000000..fa6057afa54
--- /dev/null
+++ b/src/bin/pg_controldata/meson.build
@@ -0,0 +1,14 @@
+executable('pg_controldata',
+  ['pg_controldata.c'],
+  dependencies: [frontend_code],
+  kwargs: default_bin_args,
+)
+
+tap_tests += {
+  'name': 'pg_controldata',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tests': [
+    't/001_pg_controldata.pl'
+  ]
+}
diff --git a/src/bin/pg_ctl/meson.build b/src/bin/pg_ctl/meson.build
new file mode 100644
index 00000000000..ac0d4f18192
--- /dev/null
+++ b/src/bin/pg_ctl/meson.build
@@ -0,0 +1,17 @@
+executable('pg_ctl',
+  ['pg_ctl.c'],
+  dependencies: [frontend_code, libpq],
+  kwargs: default_bin_args,
+)
+
+tap_tests += {
+  'name': 'pg_ctl',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tests': [
+    't/001_start_stop.pl',
+    't/002_status.pl',
+    't/003_promote.pl',
+    't/004_logrotate.pl'
+  ]
+}
diff --git a/src/bin/pg_dump/meson.build b/src/bin/pg_dump/meson.build
new file mode 100644
index 00000000000..ce5ef11eaeb
--- /dev/null
+++ b/src/bin/pg_dump/meson.build
@@ -0,0 +1,69 @@
+pg_dump_common_sources = files(
+  'compress_io.c',
+  'dumputils.c',
+  'parallel.c',
+  'pg_backup_archiver.c',
+  'pg_backup_custom.c',
+  'pg_backup_db.c',
+  'pg_backup_directory.c',
+  'pg_backup_null.c',
+  'pg_backup_tar.c',
+  'pg_backup_utils.c',
+)
+
+pg_dump_common = static_library('pg_dump_common',
+  pg_dump_common_sources,
+  c_pch: '../../include/pch/c_pch.h',
+  dependencies: [frontend_code, libpq, zlib],
+  kwargs: internal_lib_args,
+)
+
+pg_dump_sources = files(
+  'pg_dump.c',
+  'common.c',
+  'pg_dump_sort.c',
+)
+
+executable('pg_dump',
+  pg_dump_sources,
+  link_with: [pg_dump_common],
+  dependencies: [frontend_code, libpq, zlib],
+  kwargs: default_bin_args,
+)
+
+
+pg_dumpall_sources = files(
+  'pg_dumpall.c',
+)
+
+executable('pg_dumpall',
+  pg_dumpall_sources,
+  link_with: [pg_dump_common],
+  dependencies: [frontend_code, libpq, zlib],
+  kwargs: default_bin_args,
+)
+
+
+pg_restore_sources = files(
+  'pg_restore.c',
+)
+
+executable('pg_restore',
+  pg_restore_sources,
+  link_with: [pg_dump_common],
+  dependencies: [frontend_code, libpq, zlib],
+  kwargs: default_bin_args,
+)
+
+
+tap_tests += {
+  'name': 'pg_dump',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tests': [
+    't/001_basic.pl',
+    't/002_pg_dump.pl',
+    't/003_pg_dump_with_server.pl',
+    't/010_dump_connstr.pl',
+  ]
+}
diff --git a/src/bin/pg_resetwal/meson.build b/src/bin/pg_resetwal/meson.build
new file mode 100644
index 00000000000..7450c0f6432
--- /dev/null
+++ b/src/bin/pg_resetwal/meson.build
@@ -0,0 +1,15 @@
+executable('pg_resetwal',
+  files('pg_resetwal.c'),
+  dependencies: [frontend_code],
+  kwargs: default_bin_args,
+)
+
+tap_tests += {
+  'name': 'pg_resetwal',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tests': [
+    't/001_basic.pl',
+    't/002_corrupted.pl'
+  ]
+}
diff --git a/src/bin/pg_rewind/meson.build b/src/bin/pg_rewind/meson.build
new file mode 100644
index 00000000000..c7c59e9e523
--- /dev/null
+++ b/src/bin/pg_rewind/meson.build
@@ -0,0 +1,34 @@
+pg_rewind_sources = files(
+  'datapagemap.c',
+  'file_ops.c',
+  'filemap.c',
+  'libpq_source.c',
+  'local_source.c',
+  'parsexlog.c',
+  'pg_rewind.c',
+  'timeline.c',
+  '../../backend/access/transam/xlogreader.c',
+)
+
+pg_rewind = executable('pg_rewind',
+  pg_rewind_sources,
+  dependencies: [frontend_code, libpq, lz4],
+  kwargs: default_bin_args,
+)
+
+
+tap_tests += {
+  'name': 'pg_rewind',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tests': [
+    't/001_basic.pl',
+    't/002_databases.pl',
+    't/003_extrafiles.pl',
+    't/004_pg_xlog_symlink.pl',
+    't/005_same_timeline.pl',
+    't/006_options.pl',
+    't/007_standby_source.pl',
+    't/008_min_recovery_point.pl',
+  ]
+}
diff --git a/src/bin/pg_test_fsync/meson.build b/src/bin/pg_test_fsync/meson.build
new file mode 100644
index 00000000000..527be88d125
--- /dev/null
+++ b/src/bin/pg_test_fsync/meson.build
@@ -0,0 +1,14 @@
+executable('pg_test_fsync',
+  ['pg_test_fsync.c'],
+  dependencies: [frontend_code],
+  kwargs: default_bin_args,
+)
+
+tap_tests += {
+  'name' : 'pg_test_fsync',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tests' :[
+    't/001_basic.pl',
+  ]
+}
diff --git a/src/bin/pg_test_timing/meson.build b/src/bin/pg_test_timing/meson.build
new file mode 100644
index 00000000000..c74577df493
--- /dev/null
+++ b/src/bin/pg_test_timing/meson.build
@@ -0,0 +1,14 @@
+pg_test_timing = executable('pg_test_timing',
+  ['pg_test_timing.c'],
+  dependencies: [frontend_code],
+  kwargs: default_bin_args,
+)
+
+tap_tests += {
+  'name': 'pg_test_timing',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tests': [
+    't/001_basic.pl'
+  ]
+}
diff --git a/src/bin/pg_upgrade/meson.build b/src/bin/pg_upgrade/meson.build
new file mode 100644
index 00000000000..88d0e03446b
--- /dev/null
+++ b/src/bin/pg_upgrade/meson.build
@@ -0,0 +1,26 @@
+pg_upgrade_sources = files(
+  'check.c',
+  'controldata.c',
+  'dump.c',
+  'exec.c',
+  'file.c',
+  'function.c',
+  'info.c',
+  'option.c',
+  'parallel.c',
+  'pg_upgrade.c',
+  'relfilenode.c',
+  'server.c',
+  'tablespace.c',
+  'util.c',
+  'version.c',
+)
+
+pg_upgrade = executable('pg_upgrade',
+  pg_upgrade_sources,
+  c_pch: '../../include/pch/c_pch.h',
+  dependencies: [frontend_code, libpq],
+  kwargs: default_bin_args,
+)
+
+# FIXME: add test
diff --git a/src/bin/pg_verifybackup/meson.build \
b/src/bin/pg_verifybackup/meson.build new file mode 100644
index 00000000000..c7039ddcc49
--- /dev/null
+++ b/src/bin/pg_verifybackup/meson.build
@@ -0,0 +1,25 @@
+pg_verifybackup_sources = files(
+  'parse_manifest.c',
+  'pg_verifybackup.c'
+)
+
+pg_verifybackup = executable('pg_verifybackup',
+  pg_verifybackup_sources,
+  dependencies: [frontend_code, libpq],
+  kwargs: default_bin_args,
+)
+
+tap_tests += {
+  'name': 'pg_verifybackup',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tests': [
+    't/001_basic.pl',
+    't/002_algorithm.pl',
+    't/003_corruption.pl',
+    't/004_options.pl',
+    't/005_bad_manifest.pl',
+    't/006_encoding.pl',
+    't/007_wal.pl',
+  ]
+}
diff --git a/src/bin/pg_waldump/meson.build b/src/bin/pg_waldump/meson.build
new file mode 100644
index 00000000000..f89139f89f5
--- /dev/null
+++ b/src/bin/pg_waldump/meson.build
@@ -0,0 +1,23 @@
+pg_waldump_sources = files(
+  'compat.c',
+  'pg_waldump.c',
+  'rmgrdesc.c',
+)
+
+pg_waldump_sources += rmgr_desc_sources
+pg_waldump_sources += xlogreader_sources
+
+pg_waldump = executable('pg_waldump',
+  pg_waldump_sources,
+  dependencies: [frontend_code, lz4],
+  kwargs: default_bin_args,
+)
+
+tap_tests += {
+  'name': 'pg_waldump',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tests': [
+    't/001_basic.pl',
+  ]
+}
diff --git a/src/bin/pgbench/meson.build b/src/bin/pgbench/meson.build
new file mode 100644
index 00000000000..bc135abebfc
--- /dev/null
+++ b/src/bin/pgbench/meson.build
@@ -0,0 +1,38 @@
+pgbench_sources = files(
+  'pgbench.c',
+)
+
+# exprscan is compiled as part ofexprparse. The ordering is enforced by making
+# the generation of grammar depend on the scanner generation. That's
+# unnecessarily strict, but overall harmless.
+
+exprscan = custom_target('exprscan',
+  input : files('exprscan.l'),
+  output : ['exprscan.c'],
+  command : [flex, '-o', '@OUTPUT0@', '@INPUT@']
+)
+
+exprparse = custom_target('exprparse',
+  input: 'exprparse.y',
+  output: 'exprparse.c',
+  depends: exprscan,
+  command: [bison, bisonflags, '-o', '@OUTPUT@', '@INPUT0@'])
+pgbench_sources += exprparse
+
+executable('pgbench',
+  pgbench_sources,
+  dependencies: [frontend_code, libpq, thread_dep],
+  include_directories: include_directories('.'),
+  kwargs: default_bin_args,
+)
+
+
+tap_tests += {
+  'name' : 'pgbench',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tests' :[
+    't/001_pgbench_with_server.pl',
+    't/002_pgbench_no_server.pl'
+  ]
+}
diff --git a/src/bin/pgevent/meson.build b/src/bin/pgevent/meson.build
new file mode 100644
index 00000000000..b35287d074b
--- /dev/null
+++ b/src/bin/pgevent/meson.build
@@ -0,0 +1,32 @@
+if host_machine.system() != 'windows'
+  subdir_done()
+endif
+
+pgevent_sources = files(
+    'pgevent.c',
+)
+
+pgevent_cdata = rc_lib_cdata
+pgevent_cdata.set_quoted('FILEDESC', 'Eventlog message formatter')
+pgevent_cdata.set_quoted('INTERNAL_NAME', 'pgevent')
+pgevent_cdata.set_quoted('ORIGINAL_NAME', 'pgevent.dll')
+
+configure_file(
+  output: 'win32ver.rc',
+  input: win32ver_rc_in,
+  configuration: pgevent_cdata
+)
+
+pgevent_sources += windows.compile_resources(
+  'pgmsgevent.rc',
+  include_directories: [include_directories('.'), postgres_inc],
+)
+
+shared_library('pgevent',
+  pgevent_sources,
+  dependencies: [frontend_code],
+  vs_module_defs: 'pgevent.def',
+  kwargs: default_lib_args + {
+    'name_prefix': '',
+  },
+)
diff --git a/src/bin/psql/meson.build b/src/bin/psql/meson.build
new file mode 100644
index 00000000000..75905a52c13
--- /dev/null
+++ b/src/bin/psql/meson.build
@@ -0,0 +1,65 @@
+psql_sources = files(
+  'command.c',
+  'common.c',
+  'copy.c',
+  'crosstabview.c',
+  'describe.c',
+  'help.c',
+  'input.c',
+  'large_obj.c',
+  'mainloop.c',
+  'prompt.c',
+  'startup.c',
+  'stringutils.c',
+  'tab-complete.c',
+  'variables.c',
+)
+
+psql_sources += custom_target('psqlscanslash',
+  input: ['psqlscanslash.l'],
+  output: ['psqlscanslash.c'],
+  command: [flex, '-b', '-Cfe', '-p', '-p', '-o', '@OUTPUT@', '@INPUT@'])
+
+psql_sources += custom_target('psql_help',
+  input: ['create_help.pl'],
+  output: ['sql_help.c', 'sql_help.h'],
+  depfile: 'sql_help.dep',
+  command: [perl, '@INPUT0@', '@SOURCE_ROOT@/doc/src/sgml/ref', '@OUTDIR@', \
'sql_help']) +
+if host_machine.system() == 'windows'
+  psql_cdata = rc_bin_cdata
+  psql_cdata.set_quoted('FILEDESC', 'psql - the PostgreSQL interactive terminal')
+  psql_cdata.set_quoted('INTERNAL_NAME', 'psql')
+  psql_cdata.set_quoted('ORIGINAL_NAME', 'psql.exe')
+
+  win32_ver_rc = configure_file(
+    output: 'win32ver.rc',
+    input: win32ver_rc_in,
+    configuration: psql_cdata
+  )
+
+  psql_sources += windows.compile_resources(
+    win32_ver_rc,
+    include_directories: postgres_inc,
+  )
+endif
+
+executable('psql',
+  psql_sources,
+  c_pch: '../../include/pch/c_pch.h',
+  include_directories: include_directories('.'),
+  dependencies : [frontend_code, libpq, readline],
+  kwargs: default_bin_args,
+)
+
+tap_tests += {
+  'name': 'psql',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'env': {'with_readline': readline.found() ? 'yes' : 'no'},
+  'tests': [
+    't/001_basic.pl',
+    't/010_tab_completion.pl',
+    't/020_cancel.pl',
+  ],
+}
diff --git a/src/bin/scripts/meson.build b/src/bin/scripts/meson.build
new file mode 100644
index 00000000000..547a53500a4
--- /dev/null
+++ b/src/bin/scripts/meson.build
@@ -0,0 +1,46 @@
+scripts_common = static_library('scripts_common',
+  files('common.c'),
+  dependencies: [frontend_code, libpq],
+  kwargs: internal_lib_args,
+)
+
+binaries = [
+  'createdb',
+  'dropdb',
+  'createuser',
+  'dropuser',
+  'clusterdb',
+  'vacuumdb',
+  'reindexdb',
+  'pg_isready',
+]
+
+foreach binary : binaries
+  executable(binary,
+    files(binary + '.c'),
+    link_with: [scripts_common],
+    dependencies: [frontend_code, libpq],
+    kwargs: default_bin_args,
+  )
+endforeach
+
+tap_tests += {
+  'name': 'scripts',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tests': [
+    't/010_clusterdb.pl',
+    't/011_clusterdb_all.pl',
+    't/020_createdb.pl',
+    't/040_createuser.pl',
+    't/050_dropdb.pl',
+    't/070_dropuser.pl',
+    't/080_pg_isready.pl',
+    't/090_reindexdb.pl',
+    't/091_reindexdb_all.pl',
+    't/100_vacuumdb.pl',
+    't/101_vacuumdb_all.pl',
+    't/102_vacuumdb_stages.pl',
+    't/200_connstr.pl',
+  ]
+}
diff --git a/src/common/meson.build b/src/common/meson.build
new file mode 100644
index 00000000000..bb48a3c50a0
--- /dev/null
+++ b/src/common/meson.build
@@ -0,0 +1,155 @@
+common_sources = files(
+  'archive.c',
+  'base64.c',
+  'checksum_helper.c',
+  'config_info.c',
+  'controldata_utils.c',
+  'encnames.c',
+  'exec.c',
+  'file_perm.c',
+  'file_utils.c',
+  'hashfn.c',
+  'ip.c',
+  'jsonapi.c',
+  'keywords.c',
+  'kwlookup.c',
+  'link-canary.c',
+  'md5_common.c',
+  'pg_get_line.c',
+  'pg_lzcompress.c',
+  'pgfnames.c',
+  'psprintf.c',
+  'relpath.c',
+  'rmtree.c',
+  'saslprep.c',
+  'scram-common.c',
+  'string.c',
+  'stringinfo.c',
+  'unicode_norm.c',
+  'username.c',
+  'wait_error.c',
+  'wchar.c',
+)
+
+# FIXME: implement openssl
+if ssl.found()
+  common_sources += files(
+    'cryptohash_openssl.c',
+    'hmac_openssl.c',
+    'protocol_openssl.c',
+  )
+else
+  common_sources += files(
+    'cryptohash.c',
+    'hmac.c',
+    'md5.c',
+    'sha1.c',
+    'sha2.c',
+  )
+endif
+
+common_sources += custom_target('kwlist',
+  input: files('../include/parser/kwlist.h'),
+  output: 'kwlist_d.h',
+  command: [perl, '-I', '@SOURCE_ROOT@/src/tools', \
files('../tools/gen_keywordlist.pl'), +      '--extern', '--output', '@OUTDIR@', \
'@INPUT@']) +
+
+# The code imported from Ryu gets a pass on declaration-after-statement,
+# in order to keep it more closely aligned with its upstream.
+ryu_sources = files(
+  'd2s.c',
+  'f2s.c',
+)
+ryu_cflags = []
+
+if using_declaration_after_statement_warning
+  ryu_cflags += ['-Wno-declaration-after-statement']
+endif
+
+common_cflags = {'ryu': ryu_cflags}
+common_sources_cflags = {'ryu': ryu_sources}
+
+
+# A few files are currently only built for frontend, not server
+# (Mkvcbuild.pm has a copy of this list, too).  logging.c is excluded
+# from OBJS_FRONTEND_SHLIB (shared library) as a matter of policy,
+# because it is not appropriate for general purpose libraries such
+# as libpq to report errors directly.
+
+common_sources_frontend_shlib = common_sources
+common_sources_frontend_shlib += files(
+  'fe_memutils.c',
+  'restricted_token.c',
+  'sprompt.c',
+)
+
+common_sources_frontend_static = common_sources_frontend_shlib
+common_sources_frontend_static += files(
+  'logging.c',
+)
+
+# Build pgport once for backend, once for use in frontend binaries, and once
+# for use in shared libraries
+#
+# XXX: in most environments we could probably link_whole pgcommon_shlib
+# against pgcommon_static, instead of compiling twice.
+#
+# For the server build of pgcommon, depend on lwlocknames_h, because at least
+# cryptohash_openssl.c, hmac_openssl.c depend on it. That's arguably a
+# layering violation, but ...
+pgcommon = {}
+pgcommon_variants = {
+  'srv' : internal_lib_args + {
+    'sources': common_sources + [lwlocknames_h],
+    'dependencies': [backend_common_code],
+   },
+  'static' : default_lib_args + {
+    'sources': common_sources_frontend_static,
+    'dependencies': [frontend_common_code],
+   },
+  'shlib' : default_lib_args + {
+    'pic': true,
+    'sources': common_sources_frontend_shlib,
+    'dependencies': [frontend_common_code],
+   },
+}
+
+foreach name, opts : pgcommon_variants
+
+  # Build internal static libraries for sets of files that need to be built
+  # with different cflags
+  cflag_libs = []
+  foreach cflagname, sources: common_sources_cflags
+    if sources.length() == 0
+      continue
+    endif
+    c_args = opts.get('c_args', []) + common_cflags[cflagname]
+    cflag_libs += static_library('pgcommon_@0@_@1@'.format(cflagname, name),
+      c_pch: '../include/pch/c_pch.h',
+      include_directories: include_directories('.'),
+      kwargs: opts + {
+        'sources': sources,
+        'c_args': c_args,
+        'build_by_default': false,
+        'install': false,
+      },
+    )
+  endforeach
+
+  lib = static_library('pgcommon_@0@'.format(name),
+      link_with: cflag_libs,
+      c_pch: '../include/pch/c_pch.h',
+      include_directories: include_directories('.'),
+      kwargs: opts + {
+        'dependencies': opts['dependencies'] + [ssl],
+      }
+    )
+  pgcommon += {name: lib}
+endforeach
+
+common_srv = pgcommon['srv']
+common_shlib = pgcommon['shlib']
+common_static = pgcommon['static']
+
+subdir('unicode')
diff --git a/src/common/unicode/meson.build b/src/common/unicode/meson.build
new file mode 100644
index 00000000000..e8145e138c0
--- /dev/null
+++ b/src/common/unicode/meson.build
@@ -0,0 +1,99 @@
+# These files are part of the Unicode Character Database. Download
+# them on demand.
+
+UNICODE_VERSION = '14.0.0'
+
+unicode_data = {}
+unicode_baseurl = 'https://www.unicode.org/Public/@0@/ucd/@1@'
+
+if not wget.found()
+  subdir_done()
+endif
+
+foreach f : ['UnicodeData.txt', 'EastAsianWidth.txt', \
'DerivedNormalizationProps.txt', 'CompositionExclusions.txt', \
'NormalizationTest.txt'] +  url = unicode_baseurl.format(UNICODE_VERSION, f)
+  target = custom_target(f,
+    output: f,
+    command: [wget, wget_flags, url],
+    build_by_default: false,
+  )
+  unicode_data += {f: target}
+endforeach
+
+
+update_unicode_targets = []
+
+update_unicode_targets += \
+  custom_target('unicode_norm_table.h',
+    input: [unicode_data['UnicodeData.txt'], \
unicode_data['CompositionExclusions.txt']], +    output: ['unicode_norm_table.h', \
'unicode_norm_hashfunc.h'], +    command: [perl, \
files('generate-unicode_norm_table.pl'), '@OUTDIR@', '@INPUT@'], +    \
build_by_default: false, +  )
+
+update_unicode_targets += \
+  custom_target('unicode_combining_table.h',
+    input: [unicode_data['UnicodeData.txt']],
+    output: ['unicode_combining_table.h'],
+    command: [perl, files('generate-unicode_combining_table.pl'), '@INPUT@'],
+    build_by_default: false,
+    capture: true,
+  )
+
+update_unicode_targets += \
+  custom_target('unicode_east_asian_fw_table.h',
+    input: [unicode_data['EastAsianWidth.txt']],
+    output: ['unicode_east_asian_fw_table.h'],
+    command: [perl, files('generate-unicode_east_asian_fw_table.pl'), '@INPUT@'],
+    build_by_default: false,
+    capture: true,
+  )
+
+update_unicode_targets += \
+  custom_target('unicode_normprops_table.h',
+    input: [unicode_data['DerivedNormalizationProps.txt']],
+    output: ['unicode_normprops_table.h'],
+    command: [perl, files('generate-unicode_normprops_table.pl'), '@INPUT@'],
+    build_by_default: false,
+    capture: true,
+  )
+
+norm_test_table = custom_target('norm_test_table.h',
+    input: [unicode_data['NormalizationTest.txt']],
+    output: ['norm_test_table.h'],
+    command: [perl, files('generate-norm_test_table.pl'), '@INPUT@', '@OUTPUT@'],
+    build_by_default: false,
+  )
+
+inc = include_directories('.')
+
+norm_test = executable('norm_test',
+  ['norm_test.c', norm_test_table],
+  dependencies: [frontend_port_code],
+  include_directories: inc,
+  link_with: [pgport_static, common_static],
+  build_by_default: false,
+  kwargs: default_bin_args + {
+    'install': false,
+  }
+)
+
+if not meson.is_cross_build()
+  norm_test_valid = custom_target('norm_test.valid',
+    output: 'norm_test.valid',
+    depends: update_unicode_targets,
+    command: [norm_test],
+    build_by_default: false,
+    capture: true,
+  )
+
+  run_target('update-unicode',
+    depends: norm_test_valid,
+    command: ['cp', update_unicode_targets, '@SOURCE_ROOT@/src/include/common/']
+  )
+else
+  run_target('update-unicode',
+    depends: update_unicode_targets,
+    command: ['cp', update_unicode_targets, '@SOURCE_ROOT@/src/include/common/']
+  )
+endif
diff --git a/src/fe_utils/meson.build b/src/fe_utils/meson.build
new file mode 100644
index 00000000000..e3f0b34cf13
--- /dev/null
+++ b/src/fe_utils/meson.build
@@ -0,0 +1,27 @@
+fe_utils_sources = files(
+  'archive.c',
+  'cancel.c',
+  'conditional.c',
+  'connect_utils.c',
+  'mbprint.c',
+  'option_utils.c',
+  'parallel_slot.c',
+  'print.c',
+  'query_utils.c',
+  'recovery_gen.c',
+  'simple_list.c',
+  'string_utils.c',
+)
+
+fe_utils_sources += custom_target('psqlscan',
+  input: ['psqlscan.l'],
+  output: ['psqlscan.c'],
+  command: [flex, '-b', '-Cfe', '-p', '-p', '-o', '@OUTPUT@', '@INPUT@'])
+
+fe_utils = static_library('fe_utils',
+  fe_utils_sources + generated_headers,
+  c_pch: '../include/pch/c_pch.h',
+  include_directories :  [postgres_inc, libpq_inc],
+  c_args: ['-DFRONTEND'],
+  kwargs: default_lib_args,
+)
diff --git a/src/include/catalog/meson.build b/src/include/catalog/meson.build
new file mode 100644
index 00000000000..f5bc294c814
--- /dev/null
+++ b/src/include/catalog/meson.build
@@ -0,0 +1,129 @@
+catalog_headers = [
+  'pg_proc.h',
+  'pg_type.h',
+  'pg_attribute.h',
+  'pg_class.h',
+  'pg_attrdef.h',
+  'pg_constraint.h',
+  'pg_inherits.h',
+  'pg_index.h',
+  'pg_operator.h',
+  'pg_opfamily.h',
+  'pg_opclass.h',
+  'pg_am.h',
+  'pg_amop.h',
+  'pg_amproc.h',
+  'pg_language.h',
+  'pg_largeobject_metadata.h',
+  'pg_largeobject.h',
+  'pg_aggregate.h',
+  'pg_statistic.h',
+  'pg_statistic_ext.h',
+  'pg_statistic_ext_data.h',
+  'pg_rewrite.h',
+  'pg_trigger.h',
+  'pg_event_trigger.h',
+  'pg_description.h',
+  'pg_cast.h',
+  'pg_enum.h',
+  'pg_namespace.h',
+  'pg_conversion.h',
+  'pg_depend.h',
+  'pg_database.h',
+  'pg_db_role_setting.h',
+  'pg_tablespace.h',
+  'pg_authid.h',
+  'pg_auth_members.h',
+  'pg_shdepend.h',
+  'pg_shdescription.h',
+  'pg_ts_config.h',
+  'pg_ts_config_map.h',
+  'pg_ts_dict.h',
+  'pg_ts_parser.h',
+  'pg_ts_template.h',
+  'pg_extension.h',
+  'pg_foreign_data_wrapper.h',
+  'pg_foreign_server.h',
+  'pg_user_mapping.h',
+  'pg_foreign_table.h',
+  'pg_policy.h',
+  'pg_replication_origin.h',
+  'pg_default_acl.h',
+  'pg_init_privs.h',
+  'pg_seclabel.h',
+  'pg_shseclabel.h',
+  'pg_collation.h',
+  'pg_partitioned_table.h',
+  'pg_range.h',
+  'pg_transform.h',
+  'pg_sequence.h',
+  'pg_publication.h',
+  'pg_publication_namespace.h',
+  'pg_publication_rel.h',
+  'pg_subscription.h',
+  'pg_subscription_rel.h',
+]
+
+bki_data = files(
+  'pg_aggregate.dat',
+  'pg_am.dat',
+  'pg_amop.dat',
+  'pg_amproc.dat',
+  'pg_authid.dat',
+  'pg_cast.dat',
+  'pg_class.dat',
+  'pg_collation.dat',
+  'pg_conversion.dat',
+  'pg_database.dat',
+  'pg_language.dat',
+  'pg_namespace.dat',
+  'pg_opclass.dat',
+  'pg_operator.dat',
+  'pg_opfamily.dat',
+  'pg_proc.dat',
+  'pg_range.dat',
+  'pg_tablespace.dat',
+  'pg_ts_config.dat',
+  'pg_ts_config_map.dat',
+  'pg_ts_dict.dat',
+  'pg_ts_parser.dat',
+  'pg_ts_template.dat',
+  'pg_type.dat',
+  )
+
+
+input = []
+output_files = ['postgres.bki', 'schemapg.h', 'system_fk_info.h', \
'system_constraints.sql'] +output_install = [get_option('datadir'), \
get_option('includedir'), get_option('includedir'), get_option('datadir')] +
+foreach h : catalog_headers
+  fname = h.split('.h')[0]+'_d.h'
+  input += files(h)
+  output_files += fname
+  output_install += get_option('includedir')
+endforeach
+
+generated_headers += custom_target('generated_catalog_headers',
+    input: input,
+    depend_files: bki_data,
+    build_by_default: true,
+    install: true,
+    output: output_files,
+    install_dir: output_install,
+    command: [perl, files('../../backend/catalog/genbki.pl'), \
'--include-path=@SOURCE_ROOT@/src/include', \
'--set-version='+pg_version_major.to_string(), '--output=@OUTDIR@', '@INPUT@'] +    )
+
+
+# 'reformat-dat-files' is a convenience target for rewriting the
+# catalog data files in our standard format.  This includes collapsing
+# out any entries that are redundant with a BKI_DEFAULT annotation.
+run_target('reformat-dat-files',
+  command: [perl, files('reformat_dat_file.pl'), '--output', '@CURRENT_SOURCE_DIR@', \
bki_data], +)
+
+# 'expand-dat-files' is a convenience target for expanding out all
+# default values in the catalog data files.  This should be run before
+# altering or removing any BKI_DEFAULT annotation.
+run_target('expand-dat-files',
+  command: [perl, files('reformat_dat_file.pl'), '--output', '@CURRENT_SOURCE_DIR@', \
bki_data, '--full-tuples'], +)
diff --git a/src/include/meson.build b/src/include/meson.build
new file mode 100644
index 00000000000..c3af4a2574f
--- /dev/null
+++ b/src/include/meson.build
@@ -0,0 +1,50 @@
+configure_file(input : 'pg_config_ext.h.meson',
+  output : 'pg_config_ext.h',
+  configuration : cdata)
+
+system = host_machine.system()
+if system == 'windows'
+  system = 'win32'
+endif
+
+configure_file(
+  output : 'pg_config_os.h',
+  input: files('port/@0@.h'.format(system)),
+  install: true,
+  install_dir : get_option('includedir'),
+  copy : true)
+
+configure_file(
+  output : 'pg_config.h',
+  install : true,
+  install_dir : get_option('includedir'),
+  configuration : cdata)
+
+
+config_paths_data = configuration_data()
+config_paths_data.set_quoted('PGBINDIR', get_option('prefix') / \
get_option('bindir')) +config_paths_data.set_quoted('PGSHAREDIR', \
get_option('prefix') / get_option('datadir')) \
+config_paths_data.set_quoted('SYSCONFDIR', get_option('prefix') / \
get_option('sysconfdir')) +config_paths_data.set_quoted('INCLUDEDIR', \
get_option('prefix') / get_option('includedir')) +# FIXME: shouldn't be the same
+config_paths_data.set_quoted('PKGINCLUDEDIR', get_option('prefix') / \
get_option('includedir')) +config_paths_data.set_quoted('INCLUDEDIRSERVER', \
get_option('prefix') / get_option('includedir')) \
+config_paths_data.set_quoted('LIBDIR', get_option('prefix') / get_option('libdir')) \
+# FIXME: figure out logic for pkglibdir +config_paths_data.set_quoted('PKGLIBDIR', \
get_option('prefix') / get_option('libdir')) \
+config_paths_data.set_quoted('LOCALEDIR', get_option('prefix') / \
get_option('localedir')) +config_paths_data.set_quoted('DOCDIR', get_option('prefix') \
/ get_option('datadir') / 'doc/postgresql') +config_paths_data.set_quoted('HTMLDIR', \
get_option('prefix') / get_option('datadir') / 'doc/postgresql') \
+config_paths_data.set_quoted('MANDIR', get_option('prefix') / get_option('datadir') \
/ 'doc/postgresql') +
+configure_file(
+  output: 'pg_config_paths.h',
+  configuration: config_paths_data,
+  install: false
+)
+
+
+subdir('utils')
+subdir('storage')
+subdir('catalog')
+subdir('parser')
diff --git a/src/include/parser/meson.build b/src/include/parser/meson.build
new file mode 100644
index 00000000000..caf4c092909
--- /dev/null
+++ b/src/include/parser/meson.build
@@ -0,0 +1,10 @@
+backend_parser_header = custom_target('gram',
+  input: [files('../../backend/parser/gram.y')],
+  output: ['gram.c', 'gram.h'],
+  command: [bison, bisonflags, '-d', '-o', '@OUTPUT0@', '@INPUT0@'],
+  install: true,
+  # Only install gram.h, not gram.c
+  install_dir: [false, get_option('includedir')]
+)
+
+#generated_backend_headers += backend_parser[1]
diff --git a/src/include/pch/c_pch.h b/src/include/pch/c_pch.h
new file mode 100644
index 00000000000..f40c757ca62
--- /dev/null
+++ b/src/include/pch/c_pch.h
@@ -0,0 +1 @@
+#include "c.h"
diff --git a/src/include/pch/postgres_pch.h b/src/include/pch/postgres_pch.h
new file mode 100644
index 00000000000..71b2f35f76b
--- /dev/null
+++ b/src/include/pch/postgres_pch.h
@@ -0,0 +1 @@
+#include "postgres.h"
diff --git a/src/include/pg_config_ext.h.meson b/src/include/pg_config_ext.h.meson
new file mode 100644
index 00000000000..57cdfca0cfd
--- /dev/null
+++ b/src/include/pg_config_ext.h.meson
@@ -0,0 +1,7 @@
+/*
+ * src/include/pg_config_ext.h.in.  This is generated manually, not by
+ * autoheader, since we want to limit which symbols get defined here.
+ */
+
+/* Define to the name of a signed 64-bit integer type. */
+#mesondefine PG_INT64_TYPE
diff --git a/src/include/storage/meson.build b/src/include/storage/meson.build
new file mode 100644
index 00000000000..ef2bbb7c6f7
--- /dev/null
+++ b/src/include/storage/meson.build
@@ -0,0 +1,16 @@
+# FIXME: this creates an unnecessary lwlocknames.c - but it's not
+# obvious how to avoid that: meson insist on output files being in the
+# current dir.
+
+lwlocknames = custom_target('lwlocknames',
+  input : files('../../backend/storage/lmgr/lwlocknames.txt'),
+  output : ['lwlocknames.h', 'lwlocknames.c'],
+  command : [perl, files('../../backend/storage/lmgr/generate-lwlocknames.pl'), \
'-o', '@OUTDIR@', '@INPUT@'], +  build_by_default: true,
+  install: true,
+  install_dir: [get_option('includedir'), false],
+)
+
+lwlocknames_h = lwlocknames[0]
+
+generated_backend_headers += lwlocknames_h
diff --git a/src/include/utils/meson.build b/src/include/utils/meson.build
new file mode 100644
index 00000000000..b9c959b474d
--- /dev/null
+++ b/src/include/utils/meson.build
@@ -0,0 +1,22 @@
+errcodes = custom_target('errcodes',
+  input : files('../../backend/utils/errcodes.txt'),
+  output : ['errcodes.h'],
+  command : [perl, files('../../backend/utils/generate-errcodes.pl'), '@INPUT@', \
'@OUTPUT@'] +)
+generated_headers += errcodes
+
+generated_backend_headers += custom_target('probes.d',
+  input: files('../../backend/utils/probes.d'),
+  output : 'probes.h',
+  capture: true,
+  command : [sed, '-f', files('../../backend/utils/Gen_dummy_probes.sed'), \
'@INPUT@'] +)
+
+fmgrtab_target = custom_target('fmgrtab',
+  input: '../catalog/pg_proc.dat',
+  output : ['fmgroids.h', 'fmgrprotos.h', 'fmgrtab.c'],
+  command: [perl, '-I', '@SOURCE_ROOT@/src/backend/catalog/', \
files('../../backend/utils/Gen_fmgrtab.pl'), \
'--include-path=@SOURCE_ROOT@/src/include', '--output=@OUTDIR@', '@INPUT@'] +)
+
+generated_backend_headers += fmgrtab_target[0]
+generated_backend_headers += fmgrtab_target[1]
diff --git a/src/interfaces/libpq/meson.build b/src/interfaces/libpq/meson.build
new file mode 100644
index 00000000000..4b716f0e89d
--- /dev/null
+++ b/src/interfaces/libpq/meson.build
@@ -0,0 +1,99 @@
+libpq_sources = files(
+  'fe-auth-scram.c',
+  'fe-connect.c',
+  'fe-exec.c',
+  'fe-lobj.c',
+  'fe-misc.c',
+  'fe-print.c',
+  'fe-protocol3.c',
+  'fe-secure.c',
+  'fe-trace.c',
+  'legacy-pqsignal.c',
+  'libpq-events.c',
+  'pqexpbuffer.c',
+  'fe-auth.c',
+)
+
+if host_machine.system() == 'windows'
+  libpq_sources += files('win32.c', 'pthread-win32.c')
+endif
+
+if ssl.found()
+  libpq_sources += files('fe-secure-common.c')
+  libpq_sources += files('fe-secure-openssl.c')
+endif
+
+if gssapi.found()
+  libpq_sources += files(
+    'fe-secure-gssapi.c',
+    'fe-gssapi-common.c'
+  )
+endif
+
+export_file = custom_target('libpq_exports.list',
+  input: [files('exports.txt')],
+  output: ['@BASENAME@.list'],
+  command: [perl, files('../../tools/gen_versioning_script.pl'),
+    host_machine.system() == 'darwin' ? 'darwin' : 'gnu',
+    '@INPUT0@', '@OUTPUT0@'],
+  build_by_default: false,
+  install: false,
+)
+
+libpq_def = custom_target('libpq.def',
+  command: [perl, files('../../tools/msvc/export2def.pl'), '@OUTPUT@', '@INPUT0@', \
'libpq'], +  input: files('exports.txt'),
+  output: 'libpq.def',
+  build_by_default: false,
+  install: false,
+)
+
+# port needs to be in include path due to pthread-win32.h
+libpq_inc = include_directories('.', '../../port')
+libpq_deps = [frontend_shlib_code, thread_dep, ssl, ldap, gssapi]
+libpq_link_depends = []
+
+libpq_kwargs = default_lib_args + {
+  'version': '5.'+pg_version_major.to_string(),
+}
+
+
+if host_machine.system() == 'darwin'
+  libpq_kwargs = libpq_kwargs + {
+    'link_args': ['-exported_symbols_list', export_file.full_path()],
+    'link_depends': export_file,
+    'soversion': '5',
+  }
+elif host_machine.system() == 'windows'
+  libpq_deps += cc.find_library('secur32', required: true)
+
+  libpq_kwargs = libpq_kwargs + {
+    'vs_module_defs': libpq_def,
+    'soversion': '',
+  }
+else
+  libpq_kwargs = libpq_kwargs + {
+    'link_args': '-Wl,--version-script=' + export_file.full_path(),
+    'link_depends': export_file,
+    'soversion': '5',
+  }
+endif
+
+libpq_so = shared_library('pq',
+  libpq_sources,
+  include_directories : [libpq_inc, postgres_inc],
+  c_args: ['-DFRONTEND'],
+  c_pch: '../../include/pch/c_pch.h',
+  dependencies: libpq_deps,
+  kwargs: libpq_kwargs,
+)
+
+libpq = declare_dependency(
+  link_with: [libpq_so],
+  include_directories: [include_directories('.')]
+)
+
+install_headers('libpq-fe.h', 'libpq-events.h')
+# FIXME: adjust path
+install_headers('libpq-int.h', 'pqexpbuffer.h')
+install_data('pg_service.conf.sample', install_dir: get_option('datadir'))
diff --git a/src/meson.build b/src/meson.build
new file mode 100644
index 00000000000..414be1db419
--- /dev/null
+++ b/src/meson.build
@@ -0,0 +1,10 @@
+# libraries that other subsystems might depend uppon first, in their
+# respective dependency order
+
+subdir('timezone')
+
+subdir('backend')
+
+subdir('bin')
+
+subdir('pl')
diff --git a/src/pl/meson.build b/src/pl/meson.build
new file mode 100644
index 00000000000..b720e922093
--- /dev/null
+++ b/src/pl/meson.build
@@ -0,0 +1,4 @@
+subdir('plpgsql')
+
+subdir('plperl')
+subdir('plpython')
diff --git a/src/pl/plperl/meson.build b/src/pl/plperl/meson.build
new file mode 100644
index 00000000000..a5a994e845f
--- /dev/null
+++ b/src/pl/plperl/meson.build
@@ -0,0 +1,81 @@
+if not perl_dep.found()
+  subdir_done()
+endif
+
+plperl_sources = files(
+  'plperl.c',
+)
+
+subppdir = run_command(perl, '-e', 'use List::Util qw(first); print first { -r \
"$_/ExtUtils/xsubpp" } @INC', +  check: true).stdout()
+xsubpp = '@0@/ExtUtils/xsubpp'.format(subppdir)
+typemap = '@0@/ExtUtils/typemap'.format(subppdir)
+
+plperl_sources += custom_target('perlchunks.h',
+  input: files('plc_perlboot.pl', 'plc_trusted.pl'),
+  output: 'perlchunks.h',
+  capture: true,
+  command: [perl, files('text2macro.pl'), '--strip=^(\#.*|\s*)$', '@INPUT@']
+)
+
+plperl_sources += custom_target('plperl_opmask.h',
+  input: files('plperl_opmask.pl'),
+  output: 'plperl_opmask.h',
+  command: [perl, '@INPUT@', '@OUTPUT@']
+)
+
+foreach n : ['SPI', 'Util']
+  xs = files(n+'.xs')
+  xs_c_name = n+'.c'
+
+  # FIXME: -output option is only available in perl 5.9.3 - but that's
+  # probably a fine minimum requirement?
+  xs_c = custom_target(xs_c_name,
+    input: xs,
+    output: xs_c_name,
+    command: [perl, xsubpp, '-typemap', typemap, '-output', '@OUTPUT@', '@INPUT@']
+  )
+  plperl_sources += xs_c
+endforeach
+
+plperl_inc = include_directories('.')
+shared_module('plperl',
+  plperl_sources,
+  c_pch: '../../include/pch/postgres_pch.h',
+  include_directories: [plperl_inc, postgres_inc],
+  kwargs: pg_mod_args + {
+    'dependencies': [perl_dep, pg_mod_args['dependencies']],
+  },
+)
+
+install_data(
+  'plperl.control',
+  'plperl--1.0.sql',
+  install_dir: get_option('datadir') / 'extension'
+)
+
+install_data(
+  'plperlu.control',
+  'plperlu--1.0.sql',
+  install_dir: get_option('datadir') / 'extension'
+)
+
+regress_tests += {
+  'name': 'plperl',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'plperl_setup',
+    'plperl',
+    'plperl_lc',
+    'plperl_trigger',
+    'plperl_shared',
+    'plperl_elog',
+    'plperl_util',
+    'plperl_init',
+    'plperlu',
+    'plperl_array',
+    'plperl_call',
+    'plperl_transaction',
+   ],
+}
diff --git a/src/pl/plpgsql/meson.build b/src/pl/plpgsql/meson.build
new file mode 100644
index 00000000000..9537275d67c
--- /dev/null
+++ b/src/pl/plpgsql/meson.build
@@ -0,0 +1 @@
+subdir('src')
diff --git a/src/pl/plpgsql/src/meson.build b/src/pl/plpgsql/src/meson.build
new file mode 100644
index 00000000000..b040e5e8507
--- /dev/null
+++ b/src/pl/plpgsql/src/meson.build
@@ -0,0 +1,67 @@
+plpgsql_sources = files(
+  'pl_comp.c',
+  'pl_exec.c',
+  'pl_funcs.c',
+  'pl_handler.c',
+  'pl_scanner.c',
+)
+
+plpgsql_sources += custom_target('gram',
+  input: ['pl_gram.y'],
+  output: ['pl_gram.c', 'pl_gram.h'],
+  command: [bison, bisonflags, '-d', '-o', '@OUTPUT0@', '@INPUT0@'])
+
+gen_plerrcodes = files('generate-plerrcodes.pl')
+plpgsql_sources += custom_target('plerrcodes',
+  input: ['../../../../src/backend/utils/errcodes.txt'],
+  output: ['plerrcodes.h'],
+  command: [perl, gen_plerrcodes, '@INPUT0@'],
+  capture: true)
+
+gen_keywordlist = files('../../../../src/tools/gen_keywordlist.pl')
+plpgsql_sources += custom_target('pl_reserved_kwlist',
+  input: ['pl_reserved_kwlist.h'],
+  output: ['pl_reserved_kwlist_d.h'],
+  command: [perl, '-I', '@SOURCE_ROOT@/src/tools', gen_keywordlist, '--output', \
'@OUTDIR@', '--varname', 'ReservedPLKeywords', '@INPUT@'] +)
+
+plpgsql_sources += custom_target('pl_unreserved_kwlist',
+  input: ['pl_unreserved_kwlist.h'],
+  output: ['pl_unreserved_kwlist_d.h'],
+  command: [perl, '-I', '@SOURCE_ROOT@/src/tools', gen_keywordlist, '--output', \
'@OUTDIR@', '--varname', 'UnreservedPLKeywords', '@INPUT@'] +)
+
+shared_module('plpgsql',
+  plpgsql_sources,
+  c_pch: '../../../include/pch/postgres_pch.h',
+  include_directories: include_directories('.'),
+  kwargs: pg_mod_args,
+)
+
+install_data('plpgsql.control', 'plpgsql--1.0.sql',
+  install_dir: get_option('datadir') / 'extension'
+)
+
+install_headers('plpgsql.h',
+  install_dir: get_option('includedir') / 'server')
+
+
+regress_tests += {
+  'name': 'plpgsql',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+     'plpgsql_array',
+     'plpgsql_call',
+     'plpgsql_control',
+     'plpgsql_copy',
+     'plpgsql_domain',
+     'plpgsql_record',
+     'plpgsql_cache',
+     'plpgsql_simple',
+     'plpgsql_transaction',
+     'plpgsql_trap',
+     'plpgsql_trigger',
+     'plpgsql_varprops',
+  ],
+}
diff --git a/src/pl/plpython/meson.build b/src/pl/plpython/meson.build
new file mode 100644
index 00000000000..48a02b532aa
--- /dev/null
+++ b/src/pl/plpython/meson.build
@@ -0,0 +1,78 @@
+if not python3.found()
+  subdir_done()
+endif
+
+plpython_sources = files(
+  'plpy_cursorobject.c',
+  'plpy_elog.c',
+  'plpy_exec.c',
+  'plpy_main.c',
+  'plpy_planobject.c',
+  'plpy_plpymodule.c',
+  'plpy_procedure.c',
+  'plpy_resultobject.c',
+  'plpy_spi.c',
+  'plpy_subxactobject.c',
+  'plpy_typeio.c',
+  'plpy_util.c',
+)
+
+plpython_sources += custom_target('spiexceptions.h',
+    input: files('../../backend/utils/errcodes.txt'),
+    output: 'spiexceptions.h',
+    command: [perl, files('generate-spiexceptions.pl'), '@INPUT@'],
+    capture: true
+  )
+
+
+# FIXME: need to duplicate import library ugliness?
+plpython_inc = include_directories('.')
+
+shared_module('plpython3',
+  plpython_sources,
+  c_pch: '../../include/pch/postgres_pch.h',
+  include_directories: [plpython_inc, postgres_inc],
+  kwargs: pg_mod_args + {
+    'dependencies': [python3, pg_mod_args['dependencies']],
+  },
+)
+
+# FIXME: Only install the relevant versions
+install_data(
+  'plpython3u.control',
+  'plpython3u--1.0.sql',
+  install_dir: get_option('datadir') / 'extension'
+)
+
+plpython_regress = [
+  'plpython_schema',
+  'plpython_populate',
+  'plpython_test',
+  'plpython_do',
+  'plpython_global',
+  'plpython_import',
+  'plpython_spi',
+  'plpython_newline',
+  'plpython_void',
+  'plpython_call',
+  'plpython_params',
+  'plpython_setof',
+  'plpython_record',
+  'plpython_trigger',
+  'plpython_types',
+  'plpython_error',
+  'plpython_ereport',
+  'plpython_unicode',
+  'plpython_quote',
+  'plpython_composite',
+  'plpython_subtransaction',
+  'plpython_transaction',
+  'plpython_drop',
+]
+
+regress_tests += {
+  'name': 'plpython',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': plpython_regress,
+}
diff --git a/src/port/meson.build b/src/port/meson.build
new file mode 100644
index 00000000000..c2f35c02f1f
--- /dev/null
+++ b/src/port/meson.build
@@ -0,0 +1,191 @@
+pgport_sources = [
+  'bsearch_arg.c',
+  'chklocale.c',
+  'erand48.c',
+  'inet_net_ntop.c',
+  'noblock.c',
+  'path.c',
+  'pg_bitutils.c',
+  'pg_strong_random.c',
+  'pgcheckdir.c',
+  'pgmkdirp.c',
+  'pgsleep.c',
+  'pgstrcasecmp.c',
+  'pgstrsignal.c',
+  'pqsignal.c',
+  'qsort.c',
+  'qsort_arg.c',
+  'quotes.c',
+  'snprintf.c',
+  'strerror.c',
+  'tar.c',
+  'thread.c',
+]
+
+if host_machine.system() == 'windows'
+  pgport_sources += files(
+    'dirmod.c',
+    'kill.c',
+    'open.c',
+    'system.c',
+    'win32env.c',
+    'win32error.c',
+    'win32security.c',
+    'win32setlocale.c',
+    'win32stat.c',
+  )
+endif
+
+if cc.get_id() == 'msvc'
+  pgport_sources += files(
+    'dirent.c',
+  )
+endif
+
+# Replacement functionality to be built if corresponding configure symbol
+# is false
+replace_funcs_neg = [
+    ['dlopen'],
+    ['explicit_bzero'],
+    ['fls'],
+    ['getaddrinfo'],
+    ['getopt'],
+    ['getopt_long'],
+    ['getpeereid'],
+    ['getpeereid'],
+    ['getrusage'],
+    ['gettimeofday'],
+    ['inet_aton'],
+    ['link'],
+    ['mkdtemp'],
+    ['pread'],
+    ['preadv', 'HAVE_DECL_PREADV'],
+    ['pwrite'],
+    ['pwritev', 'HAVE_DECL_PWRITEV'],
+    ['random'],
+    ['srandom'],
+    ['strlcat'],
+    ['strlcpy'],
+    ['strnlen'],
+]
+
+# Replacement functionality to be built if corresponding configure symbol
+# is true
+replace_funcs_pos = [
+  # x86/x64
+  ['pg_crc32c_sse42', 'USE_SSE42_CRC32C'],
+  ['pg_crc32c_sse42', 'USE_SSE42_CRC32C_WITH_RUNTIME_CHECK', 'crc'],
+  ['pg_crc32c_sse42_choose', 'USE_SSE42_CRC32C_WITH_RUNTIME_CHECK'],
+  ['pg_crc32c_sb8', 'USE_SSE42_CRC32C_WITH_RUNTIME_CHECK'],
+
+  # arm / aarch64
+  ['pg_crc32c_armv8', 'USE_ARMV8_CRC32C'],
+  ['pg_crc32c_armv8', 'USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK', 'crc'],
+  ['pg_crc32c_armv8_choose', 'USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK'],
+  ['pg_crc32c_sb8', 'USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK'],
+
+  # generic fallback
+  ['pg_crc32c_sb8', 'USE_SLICING_BY_8_CRC32C'],
+]
+
+pgport_cflags = {'crc': cflags_crc}
+pgport_sources_cflags = {'crc': []}
+
+foreach f : replace_funcs_neg
+  func = f.get(0)
+  varname = f.get(1, 'HAVE_@0@'.format(func.to_upper()))
+  filename = '@0@.c'.format(func)
+
+  val = '@0@'.format(cdata.get(varname, 'false'))
+  if val == 'false' or val == '0'
+    pgport_sources += files(filename)
+  endif
+endforeach
+
+foreach f : replace_funcs_pos
+  func = f.get(0)
+  varname = f.get(1, 'HAVE_@0@'.format(func.to_upper()))
+  filename = '@0@.c'.format(func)
+
+  val = '@0@'.format(cdata.get(varname, 'false'))
+  if val == 'true' or val == '1'
+    src = files(filename)
+    if f.length() > 2
+      pgport_sources_cflags += {f[2]: pgport_sources_cflags[f[2]] + src}
+    else
+      pgport_sources += src
+    endif
+  endif
+endforeach
+
+
+if (host_machine.system() == 'windows' or host_machine.system() == 'cygwin') and \
+  (cc.get_id() != 'msvc' or cc.version().version_compare('<14.0'))
+
+  # Cygwin and (apparently, based on test results) Mingw both
+  # have a broken strtof(), so substitute the same replacement
+  # code we use with VS2013. That's not a perfect fix, since
+  # (unlike with VS2013) it doesn't avoid double-rounding, but
+  # we have no better options. To get that, though, we have to
+  # force the file to be compiled despite HAVE_STRTOF.
+  pgport_sources += files('strtof.c')
+  message('On @0@ with compiler @1@ @2@ we will use our strtof wrapper.'.format(
+    host_machine.system(), cc.get_id(), cc.version()))
+endif
+
+if not cdata.has('HAVE_PTHREAD_BARRIER_WAIT') and host_machine.system() != 'windows'
+   pgport_sources += files('pthread_barrier_wait.c')
+endif
+
+
+# Build pgport once for backend, once for use in frontend binaries, and once
+# for use in shared libraries
+pgport = {}
+pgport_variants = {
+  'srv' : internal_lib_args + {
+    'dependencies': [backend_port_code],
+   },
+  'static' : default_lib_args + {
+    'dependencies': [frontend_port_code],
+   },
+  'shlib' : default_lib_args + {
+    'pic': true,
+    'dependencies': [frontend_port_code],
+   },
+}
+
+foreach name, opts : pgport_variants
+
+  # Build internal static libraries for sets of files that need to be built
+  # with different cflags
+  cflag_libs = []
+  foreach cflagname, sources: pgport_sources_cflags
+    if sources.length() == 0
+      continue
+    endif
+    c_args = opts.get('c_args', []) + pgport_cflags[cflagname]
+    cflag_libs += static_library('pgport_@0@_@1@'.format(cflagname, name),
+      sources,
+      c_pch: '../include/pch/c_pch.h',
+      kwargs: opts + {
+        'c_args': c_args,
+        'build_by_default': false,
+        'install': false,
+      },
+    )
+  endforeach
+
+  lib = static_library('pgport_@0@'.format(name),
+      pgport_sources,
+      link_with: cflag_libs,
+      c_pch: '../include/pch/c_pch.h',
+      kwargs: opts + {
+        'dependencies': opts['dependencies'] + [ssl],
+      }
+    )
+  pgport += {name: lib}
+endforeach
+
+pgport_srv = pgport['srv']
+pgport_static = pgport['static']
+pgport_shlib = pgport['shlib']
diff --git a/src/port/win32ver.rc.in b/src/port/win32ver.rc.in
new file mode 100644
index 00000000000..d5c98e2e8fb
--- /dev/null
+++ b/src/port/win32ver.rc.in
@@ -0,0 +1,41 @@
+#include <winver.h>
+#include "pg_config.h"
+
+// https://docs.microsoft.com/en-us/windows/win32/menurc/versioninfo-resource
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION    PG_MAJORVERSION_NUM,0,PG_MINORVERSION_NUM,0
+ PRODUCTVERSION PG_MAJORVERSION_NUM,0,PG_MINORVERSION_NUM,0
+ FILEFLAGSMASK  VS_FFI_FILEFLAGSMASK
+ FILEFLAGS      0x0L
+ FILEOS         VOS_NT_WINDOWS32
+ FILETYPE	@VFT_TYPE@
+ FILESUBTYPE    0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+  BLOCK "040904B0"			// U.S. English, Unicode
+  BEGIN
+   VALUE "CompanyName",      "PostgreSQL Global Development Group"
+   VALUE "FileDescription",  @FILEDESC@
+   /*
+    * XXX: In the autoconf / src/tools/msvc build this was set differently than
+    * ProductVersion below, using the current date. But that doesn't seem like a
+    * good idea, because it makes the build not reproducible and causes
+    * unnecessary rebuilds?
+    */
+   VALUE "FileVersion",      PG_VERSION
+   VALUE "InternalName",     @INTERNAL_NAME@
+   VALUE "LegalCopyright", "Portions Copyright (c) 1996-2021, PostgreSQL Global \
Development Group. Portions Copyright (c) 1994, Regents of the University of \
California." +   VALUE "OriginalFileName", @ORIGINAL_NAME@
+   VALUE "ProductName",      "PostgreSQL"
+   VALUE "ProductVersion",   PG_VERSION
+  END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+  VALUE "Translation", 0x0409, 1200	// U.S. English, Unicode
+ END
+END
+
+IDI_ICON ICON @ICO@
diff --git a/src/test/authentication/meson.build \
b/src/test/authentication/meson.build new file mode 100644
index 00000000000..be41fb314a5
--- /dev/null
+++ b/src/test/authentication/meson.build
@@ -0,0 +1,9 @@
+tap_tests += {
+  'name': 'authentication',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tests': [
+    't/001_password.pl',
+    't/002_saslprep.pl',
+  ],
+}
diff --git a/src/test/isolation/meson.build b/src/test/isolation/meson.build
new file mode 100644
index 00000000000..ea8baa20634
--- /dev/null
+++ b/src/test/isolation/meson.build
@@ -0,0 +1,49 @@
+# pg_regress_c helpfully provided by regress/meson.build
+
+isolation_sources = pg_regress_c + files(
+  'isolation_main.c',
+)
+
+# see src/backend/replication/meson.build for depend logic
+spec_scanner = custom_target('specscanner',
+  input : files('specscanner.l'),
+  output : ['specscanner.c'],
+  command : [flex, '-o', '@OUTPUT0@', '@INPUT@']
+)
+
+isolationtester_sources = files('isolationtester.c')
+isolationtester_sources += custom_target('specparse',
+  input: 'specparse.y',
+  output: 'specparse.c',
+  depends: spec_scanner,
+  command: [bison, bisonflags, '-o', '@OUTPUT@', '@INPUT0@'])
+
+pg_isolation_regress = executable('pg_isolation_regress',
+  isolation_sources,
+  c_args: pg_regress_cflags,
+  include_directories: [pg_regress_inc],
+  dependencies: [frontend_code],
+  kwargs: default_bin_args + {
+    'install': false
+  },
+)
+
+isolationtester = executable('isolationtester',
+  isolationtester_sources,
+  include_directories: include_directories('.'),
+  dependencies: [frontend_code, libpq],
+  kwargs: default_bin_args + {
+    'install': false
+  },
+)
+
+isolation_tests += {
+  'name': 'main',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'schedule': files('isolation_schedule'),
+  'test_kwargs': {
+    'priority': 40,
+    'timeout': 1000,
+  },
+}
diff --git a/src/test/kerberos/meson.build b/src/test/kerberos/meson.build
new file mode 100644
index 00000000000..9f9957a3b4c
--- /dev/null
+++ b/src/test/kerberos/meson.build
@@ -0,0 +1,12 @@
+tap_tests += {
+  'name': 'kerberos',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tests': [
+    't/001_auth.pl',
+  ],
+  'env' : {
+    'with_gssapi': gssapi.found() ? 'yes' : 'no',
+    'with_krb_srvnam': 'postgres',
+  },
+}
diff --git a/src/test/ldap/meson.build b/src/test/ldap/meson.build
new file mode 100644
index 00000000000..58eb9adc6f5
--- /dev/null
+++ b/src/test/ldap/meson.build
@@ -0,0 +1,9 @@
+tap_tests += {
+  'name': 'ldap',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tests': [
+    't/001_auth.pl',
+  ],
+  'env' : {'with_ldap': ldap.found() ? 'yes' : 'no'},
+}
diff --git a/src/test/meson.build b/src/test/meson.build
new file mode 100644
index 00000000000..f0b0d3d3b5e
--- /dev/null
+++ b/src/test/meson.build
@@ -0,0 +1,19 @@
+subdir('regress')
+subdir('isolation')
+
+subdir('authentication')
+subdir('recovery')
+subdir('subscription')
+subdir('modules')
+
+if ssl.found()
+   subdir('ssl')
+endif
+
+if ldap.found()
+   subdir('ldap')
+endif
+
+if gssapi.found()
+   subdir('kerberos')
+endif
diff --git a/src/test/modules/brin/meson.build b/src/test/modules/brin/meson.build
new file mode 100644
index 00000000000..99ccaac5b38
--- /dev/null
+++ b/src/test/modules/brin/meson.build
@@ -0,0 +1,19 @@
+isolation_tests += {
+  'name': 'brin',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'specs': [
+    'summarization-and-inprogress-insertion',
+  ]
+}
+
+
+tap_tests += {
+  'name': 'brin',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tests': [
+    't/01_workitems.pl',
+  ],
+}
+
diff --git a/src/test/modules/commit_ts/meson.build \
b/src/test/modules/commit_ts/meson.build new file mode 100644
index 00000000000..2794d837c35
--- /dev/null
+++ b/src/test/modules/commit_ts/meson.build
@@ -0,0 +1,20 @@
+regress_tests += {
+  'name': 'commit_ts',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'commit_timestamp',
+  ]
+}
+
+tap_tests += {
+  'name': 'commit_ts',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tests': [
+    't/001_base.pl',
+    't/002_standby.pl',
+    't/003_standby_2.pl',
+    't/004_restart.pl',
+  ],
+}
diff --git a/src/test/modules/delay_execution/meson.build \
b/src/test/modules/delay_execution/meson.build new file mode 100644
index 00000000000..58fe5a1a21d
--- /dev/null
+++ b/src/test/modules/delay_execution/meson.build
@@ -0,0 +1,15 @@
+# FIXME: prevent install during main install, but not during test :/
+delay_execution = shared_module('delay_execution',
+  ['delay_execution.c'],
+  kwargs: pg_mod_args,
+)
+
+isolation_tests += {
+  'name': 'delay_execution',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'specs': [
+    'partition-addition',
+    'partition-removal-1',
+  ]
+}
diff --git a/src/test/modules/dummy_index_am/meson.build \
b/src/test/modules/dummy_index_am/meson.build new file mode 100644
index 00000000000..a9c49bd9554
--- /dev/null
+++ b/src/test/modules/dummy_index_am/meson.build
@@ -0,0 +1,20 @@
+# FIXME: prevent install during main install, but not during test :/
+dummy_index_am = shared_module('dummy_index_am',
+  ['dummy_index_am.c'],
+  kwargs: pg_mod_args,
+)
+
+install_data(
+  'dummy_index_am.control',
+  'dummy_index_am--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+regress_tests += {
+  'name': 'dummy_index_am',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'reloptions',
+  ]
+}
diff --git a/src/test/modules/dummy_seclabel/meson.build \
b/src/test/modules/dummy_seclabel/meson.build new file mode 100644
index 00000000000..ed31d8f9530
--- /dev/null
+++ b/src/test/modules/dummy_seclabel/meson.build
@@ -0,0 +1,20 @@
+# FIXME: prevent install during main install, but not during test :/
+dummy_seclabel = shared_module('dummy_seclabel',
+  ['dummy_seclabel.c'],
+  kwargs: pg_mod_args,
+)
+
+install_data(
+  'dummy_seclabel.control',
+  'dummy_seclabel--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+regress_tests += {
+  'name': 'dummy_seclabel',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'dummy_seclabel',
+  ]
+}
diff --git a/src/test/modules/libpq_pipeline/meson.build \
b/src/test/modules/libpq_pipeline/meson.build new file mode 100644
index 00000000000..2f850215a6f
--- /dev/null
+++ b/src/test/modules/libpq_pipeline/meson.build
@@ -0,0 +1,21 @@
+libpq_pipeline = executable('libpq_pipeline',
+  files(
+    'libpq_pipeline.c',
+  ),
+  dependencies: [frontend_code, libpq],
+  kwargs: default_bin_args + {
+    'install': false,
+  },
+)
+
+tap_tests += {
+  'name': 'libpq_pipeline',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'env': {
+    'PATH': meson.current_build_dir(),
+  },
+  'tests': [
+    't/001_libpq_pipeline.pl',
+  ]
+}
diff --git a/src/test/modules/meson.build b/src/test/modules/meson.build
new file mode 100644
index 00000000000..c98225c6e7b
--- /dev/null
+++ b/src/test/modules/meson.build
@@ -0,0 +1,25 @@
+subdir('brin')
+subdir('commit_ts')
+subdir('delay_execution')
+subdir('dummy_index_am')
+subdir('dummy_seclabel')
+subdir('libpq_pipeline')
+subdir('plsample')
+subdir('snapshot_too_old')
+subdir('spgist_name_ops')
+subdir('ssl_passphrase_callback')
+subdir('test_bloomfilter')
+subdir('test_ddl_deparse')
+subdir('test_extensions')
+subdir('test_ginpostinglist')
+subdir('test_integerset')
+subdir('test_misc')
+subdir('test_parser')
+subdir('test_pg_dump')
+subdir('test_predtest')
+subdir('test_rbtree')
+subdir('test_regex')
+subdir('test_rls_hooks')
+subdir('test_shm_mq')
+subdir('unsafe_tests')
+subdir('worker_spi')
diff --git a/src/test/modules/plsample/meson.build \
b/src/test/modules/plsample/meson.build new file mode 100644
index 00000000000..3f70688fb89
--- /dev/null
+++ b/src/test/modules/plsample/meson.build
@@ -0,0 +1,20 @@
+# FIXME: prevent install during main install, but not during test :/
+plsample = shared_module('plsample',
+  ['plsample.c'],
+  kwargs: pg_mod_args,
+)
+
+install_data(
+  'plsample.control',
+  'plsample--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+regress_tests += {
+  'name': 'plsample',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'plsample',
+  ]
+}
diff --git a/src/test/modules/snapshot_too_old/meson.build \
b/src/test/modules/snapshot_too_old/meson.build new file mode 100644
index 00000000000..cdf4afd18b8
--- /dev/null
+++ b/src/test/modules/snapshot_too_old/meson.build
@@ -0,0 +1,11 @@
+isolation_tests += {
+  'name': 'snapshot_too_old',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'specs': [
+    'sto_using_cursor',
+    'sto_using_select',
+    'sto_using_hash_index',
+  ],
+  'regress_args': ['--temp-config', files('sto.conf')],
+}
diff --git a/src/test/modules/spgist_name_ops/meson.build \
b/src/test/modules/spgist_name_ops/meson.build new file mode 100644
index 00000000000..19aa00892f1
--- /dev/null
+++ b/src/test/modules/spgist_name_ops/meson.build
@@ -0,0 +1,20 @@
+# FIXME: prevent install during main install, but not during test :/
+spgist_name_ops = shared_module('spgist_name_ops',
+  ['spgist_name_ops.c'],
+  kwargs: pg_mod_args,
+)
+
+install_data(
+  'spgist_name_ops.control',
+  'spgist_name_ops--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+regress_tests += {
+  'name': 'spgist_name_ops',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'spgist_name_ops',
+  ]
+}
diff --git a/src/test/modules/ssl_passphrase_callback/meson.build \
b/src/test/modules/ssl_passphrase_callback/meson.build new file mode 100644
index 00000000000..b9fa5ee1cdc
--- /dev/null
+++ b/src/test/modules/ssl_passphrase_callback/meson.build
@@ -0,0 +1,45 @@
+if not ssl.found()
+  subdir_done()
+endif
+
+# FIXME: prevent install during main install, but not during test :/
+ssl_passphrase_callback = shared_module('ssl_passphrase_func',
+  ['ssl_passphrase_func.c'],
+  kwargs: pg_mod_args + {
+    'dependencies': [ssl, pg_mod_args['dependencies']],
+  }
+)
+
+# Targets to generate or remove the ssl certificate and key. Need to be copied
+# to the source afterwards. Normally not needed.
+
+openssl = find_program('openssl', native: true, required: false)
+
+if openssl.found()
+  cert = custom_target('server.crt',
+    output: ['server.crt', 'server.ckey'],
+    command: [openssl, 'req', '-new', '-x509', '-days', '10000', '-nodes', '-out', \
'@OUTPUT0@', +      '-keyout', '@OUTPUT1@', '-subj', '/CN=localhost'],
+    build_by_default: false,
+    install: false,
+  )
+
+  # needs to agree with what's in the test script
+  pass = 'FooBaR1'
+
+  enccert = custom_target('server.key',
+    input: [cert[1]],
+    output: ['server.key'],
+    command: [openssl, 'rsa', '-aes256', '-in', '@INPUT0@', '-out', '@OUTPUT0@', \
'-passout', 'pass:@0@'.format(pass)] +  )
+endif
+
+tap_tests += {
+  'name': 'ssl_passphrase_callback',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tests': [
+    't/001_testfunc.pl',
+  ],
+  'env': {'with_ssl': 'openssl'},
+}
diff --git a/src/test/modules/test_bloomfilter/meson.build \
b/src/test/modules/test_bloomfilter/meson.build new file mode 100644
index 00000000000..2e995310876
--- /dev/null
+++ b/src/test/modules/test_bloomfilter/meson.build
@@ -0,0 +1,20 @@
+# FIXME: prevent install during main install, but not during test :/
+test_bloomfilter = shared_module('test_bloomfilter',
+  ['test_bloomfilter.c'],
+  kwargs: pg_mod_args,
+)
+
+install_data(
+  'test_bloomfilter.control',
+  'test_bloomfilter--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+regress_tests += {
+  'name': 'test_bloomfilter',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'test_bloomfilter',
+  ]
+}
diff --git a/src/test/modules/test_ddl_deparse/meson.build \
b/src/test/modules/test_ddl_deparse/meson.build new file mode 100644
index 00000000000..3618229594d
--- /dev/null
+++ b/src/test/modules/test_ddl_deparse/meson.build
@@ -0,0 +1,40 @@
+# FIXME: prevent install during main install, but not during test :/
+test_ddl_deparse = shared_module('test_ddl_deparse',
+  ['test_ddl_deparse.c'],
+  kwargs: pg_mod_args,
+)
+
+install_data(
+  'test_ddl_deparse.control',
+  'test_ddl_deparse--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+regress_tests += {
+  'name': 'test_ddl_deparse',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'test_ddl_deparse',
+    'create_extension',
+    'create_schema',
+    'create_type',
+    'create_conversion',
+    'create_domain',
+    'create_sequence_1',
+    'create_table',
+    'create_transform',
+    'alter_table',
+    'create_view',
+    'create_trigger',
+    'create_rule',
+    'comment_on',
+    'alter_function',
+    'alter_sequence',
+    'alter_ts_config',
+    'alter_type_enum',
+    'opfamily',
+    'defprivs',
+    'matviews',
+  ]
+}
diff --git a/src/test/modules/test_extensions/meson.build \
b/src/test/modules/test_extensions/meson.build new file mode 100644
index 00000000000..2ca504f8588
--- /dev/null
+++ b/src/test/modules/test_extensions/meson.build
@@ -0,0 +1,38 @@
+# FIXME: prevent install during main install, but not during test :/
+install_data(
+  'test_ext1--1.0.sql',
+  'test_ext1.control',
+  'test_ext2--1.0.sql',
+  'test_ext2.control',
+  'test_ext3--1.0.sql',
+  'test_ext3.control',
+  'test_ext4--1.0.sql',
+  'test_ext4.control',
+  'test_ext5--1.0.sql',
+  'test_ext5.control',
+  'test_ext6--1.0.sql',
+  'test_ext6.control',
+  'test_ext7--1.0--2.0.sql',
+  'test_ext7--1.0.sql',
+  'test_ext7.control',
+  'test_ext8--1.0.sql',
+  'test_ext8.control',
+  'test_ext_cyclic1--1.0.sql',
+  'test_ext_cyclic1.control',
+  'test_ext_cyclic2--1.0.sql',
+  'test_ext_cyclic2.control',
+  'test_ext_evttrig--1.0--2.0.sql',
+  'test_ext_evttrig--1.0.sql',
+  'test_ext_evttrig.control',
+  kwargs: contrib_data_args,
+)
+
+regress_tests += {
+  'name': 'test_extensions',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'test_extensions',
+    'test_extdepend',
+  ]
+}
diff --git a/src/test/modules/test_ginpostinglist/meson.build \
b/src/test/modules/test_ginpostinglist/meson.build new file mode 100644
index 00000000000..e177e90019f
--- /dev/null
+++ b/src/test/modules/test_ginpostinglist/meson.build
@@ -0,0 +1,20 @@
+# FIXME: prevent install during main install, but not during test :/
+test_ginpostinglist = shared_module('test_ginpostinglist',
+  ['test_ginpostinglist.c'],
+  kwargs: pg_mod_args,
+)
+
+install_data(
+  'test_ginpostinglist.control',
+  'test_ginpostinglist--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+regress_tests += {
+  'name': 'test_ginpostinglist',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'test_ginpostinglist',
+  ]
+}
diff --git a/src/test/modules/test_integerset/meson.build \
b/src/test/modules/test_integerset/meson.build new file mode 100644
index 00000000000..ccb8db725e5
--- /dev/null
+++ b/src/test/modules/test_integerset/meson.build
@@ -0,0 +1,20 @@
+# FIXME: prevent install during main install, but not during test :/
+test_integerset = shared_module('test_integerset',
+  ['test_integerset.c'],
+  kwargs: pg_mod_args,
+)
+
+install_data(
+  'test_integerset.control',
+  'test_integerset--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+regress_tests += {
+  'name': 'test_integerset',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'test_integerset',
+  ]
+}
diff --git a/src/test/modules/test_misc/meson.build \
b/src/test/modules/test_misc/meson.build new file mode 100644
index 00000000000..4ee8c562ac0
--- /dev/null
+++ b/src/test/modules/test_misc/meson.build
@@ -0,0 +1,8 @@
+tap_tests += {
+  'name': 'misc',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tests': [
+    't/001_constraint_validation.pl',
+  ],
+}
diff --git a/src/test/modules/test_parser/meson.build \
b/src/test/modules/test_parser/meson.build new file mode 100644
index 00000000000..c43ae95cf2c
--- /dev/null
+++ b/src/test/modules/test_parser/meson.build
@@ -0,0 +1,20 @@
+# FIXME: prevent install during main install, but not during test :/
+test_parser = shared_module('test_parser',
+  ['test_parser.c'],
+  kwargs: pg_mod_args,
+)
+
+install_data(
+  'test_parser.control',
+  'test_parser--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+regress_tests += {
+  'name': 'test_parser',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'test_parser',
+  ]
+}
diff --git a/src/test/modules/test_pg_dump/meson.build \
b/src/test/modules/test_pg_dump/meson.build new file mode 100644
index 00000000000..110b3876832
--- /dev/null
+++ b/src/test/modules/test_pg_dump/meson.build
@@ -0,0 +1,24 @@
+# FIXME: prevent install during main install, but not during test :/
+install_data(
+  'test_pg_dump.control',
+  'test_pg_dump--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+regress_tests += {
+  'name': 'test_pg_dump',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'test_pg_dump',
+  ]
+}
+
+tap_tests += {
+  'name': 'test_pg_dump',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tests': [
+    't/001_base.pl',
+  ]
+}
diff --git a/src/test/modules/test_predtest/meson.build \
b/src/test/modules/test_predtest/meson.build new file mode 100644
index 00000000000..9f9a9475c8b
--- /dev/null
+++ b/src/test/modules/test_predtest/meson.build
@@ -0,0 +1,20 @@
+# FIXME: prevent install during main install, but not during test :/
+test_predtest = shared_module('test_predtest',
+  ['test_predtest.c'],
+  kwargs: pg_mod_args,
+)
+
+install_data(
+  'test_predtest.control',
+  'test_predtest--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+regress_tests += {
+  'name': 'test_predtest',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'test_predtest',
+  ]
+}
diff --git a/src/test/modules/test_rbtree/meson.build \
b/src/test/modules/test_rbtree/meson.build new file mode 100644
index 00000000000..6bbeca39ec9
--- /dev/null
+++ b/src/test/modules/test_rbtree/meson.build
@@ -0,0 +1,20 @@
+# FIXME: prevent install during main install, but not during test :/
+test_rbtree = shared_module('test_rbtree',
+  ['test_rbtree.c'],
+  kwargs: pg_mod_args,
+)
+
+install_data(
+  'test_rbtree.control',
+  'test_rbtree--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+regress_tests += {
+  'name': 'test_rbtree',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'test_rbtree',
+  ]
+}
diff --git a/src/test/modules/test_regex/meson.build \
b/src/test/modules/test_regex/meson.build new file mode 100644
index 00000000000..c5fd92ee1c6
--- /dev/null
+++ b/src/test/modules/test_regex/meson.build
@@ -0,0 +1,21 @@
+# FIXME: prevent install during main install, but not during test :/
+test_regex = shared_module('test_regex',
+  ['test_regex.c'],
+  kwargs: pg_mod_args,
+)
+
+install_data(
+  'test_regex.control',
+  'test_regex--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+regress_tests += {
+  'name': 'test_regex',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'test_regex',
+    'test_regex_utf8',
+  ]
+}
diff --git a/src/test/modules/test_rls_hooks/meson.build \
b/src/test/modules/test_rls_hooks/meson.build new file mode 100644
index 00000000000..fb8b697e160
--- /dev/null
+++ b/src/test/modules/test_rls_hooks/meson.build
@@ -0,0 +1,19 @@
+# FIXME: prevent install during main install, but not during test :/
+test_rls_hooks = shared_module('test_rls_hooks',
+  ['test_rls_hooks.c'],
+  kwargs: pg_mod_args,
+)
+
+install_data(
+  'test_rls_hooks.control',
+  kwargs: contrib_data_args,
+)
+
+regress_tests += {
+  'name': 'test_rls_hooks',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'test_rls_hooks',
+  ]
+}
diff --git a/src/test/modules/test_shm_mq/meson.build \
b/src/test/modules/test_shm_mq/meson.build new file mode 100644
index 00000000000..159943f861e
--- /dev/null
+++ b/src/test/modules/test_shm_mq/meson.build
@@ -0,0 +1,24 @@
+# FIXME: prevent install during main install, but not during test :/
+test_shm_mq = shared_module('test_shm_mq',
+  files(
+    'setup.c',
+    'test.c',
+    'worker.c',
+  ),
+  kwargs: pg_mod_args,
+)
+
+install_data(
+  'test_shm_mq.control',
+  'test_shm_mq--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+regress_tests += {
+  'name': 'test_shm_mq',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'test_shm_mq',
+  ]
+}
diff --git a/src/test/modules/unsafe_tests/meson.build \
b/src/test/modules/unsafe_tests/meson.build new file mode 100644
index 00000000000..9ed4d587721
--- /dev/null
+++ b/src/test/modules/unsafe_tests/meson.build
@@ -0,0 +1,9 @@
+regress_tests += {
+  'name': 'unsafe_tests',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'rolenames',
+    'alter_system_table',
+  ],
+}
diff --git a/src/test/modules/worker_spi/meson.build \
b/src/test/modules/worker_spi/meson.build new file mode 100644
index 00000000000..a80bd493ea7
--- /dev/null
+++ b/src/test/modules/worker_spi/meson.build
@@ -0,0 +1,23 @@
+# FIXME: prevent install during main install, but not during test :/
+test_worker_spi = shared_module('worker_spi',
+  files(
+    'worker_spi.c',
+  ),
+  kwargs: pg_mod_args,
+)
+
+install_data(
+  'worker_spi.control',
+  'worker_spi--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+regress_tests += {
+  'name': 'worker_spi',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'sql': [
+    'worker_spi',
+  ],
+  'regress_args': ['--temp-config', files('dynamic.conf'), \
'--dbname=contrib_regression'], +}
diff --git a/src/test/recovery/meson.build b/src/test/recovery/meson.build
new file mode 100644
index 00000000000..5678e1d27ae
--- /dev/null
+++ b/src/test/recovery/meson.build
@@ -0,0 +1,33 @@
+tap_tests += {
+  'name': 'recovery',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tests' : [
+    't/001_stream_rep.pl',
+    't/002_archiving.pl',
+    't/003_recovery_targets.pl',
+    't/004_timeline_switch.pl',
+    't/005_replay_delay.pl',
+    't/006_logical_decoding.pl',
+    't/007_sync_rep.pl',
+    't/008_fsm_truncation.pl',
+    't/009_twophase.pl',
+    't/010_logical_decoding_timelines.pl',
+    't/011_crash_recovery.pl',
+    't/012_subtransactions.pl',
+    't/013_crash_restart.pl',
+    't/014_unlogged_reinit.pl',
+    't/015_promotion_pages.pl',
+    't/016_min_consistency.pl',
+    't/017_shm.pl',
+    't/018_wal_optimize.pl',
+    't/019_replslot_limit.pl',
+    't/020_archive_status.pl',
+    't/021_row_visibility.pl',
+    't/022_crash_temp_files.pl',
+    't/023_pitr_prepared_xact.pl',
+    't/024_archive_recovery.pl',
+    't/025_stuck_on_old_timeline.pl',
+    't/026_overwrite_contrecord.pl',
+  ]
+}
diff --git a/src/test/regress/meson.build b/src/test/regress/meson.build
new file mode 100644
index 00000000000..1a2f7675e87
--- /dev/null
+++ b/src/test/regress/meson.build
@@ -0,0 +1,57 @@
+# also used by isolationtester
+pg_regress_c = files('pg_regress.c')
+pg_regress_inc = include_directories('.')
+
+regress_sources = pg_regress_c + files(
+  'pg_regress_main.c'
+)
+
+pg_regress_cflags = ['-DHOST_TUPLE="frak"', '-DSHELLPROG="/bin/sh"']
+
+pg_regress = executable('pg_regress',
+  regress_sources,
+  c_args: pg_regress_cflags,
+  dependencies: [frontend_code, libpq],
+  kwargs: default_bin_args + {
+    'install': false
+  },
+)
+
+regress_module = shared_module('regress',
+  ['regress.c'],
+  kwargs: pg_mod_args + {
+    'install': false,
+  },
+)
+
+# Get some extra C modules from contrib/spi but mark them as not to be
+# installed.
+# FIXME: avoid the duplication.
+
+shared_module('autoinc',
+  ['../../../contrib/spi/autoinc.c'],
+  kwargs: pg_mod_args + {
+    'install': false,
+  },
+)
+
+shared_module('refint',
+  ['../../../contrib/spi/refint.c'],
+  kwargs: pg_mod_args + {
+    'c_args': refint_cflags + contrib_mod_args['c_args'],
+    'install': false,
+  },
+)
+
+
+regress_tests += {
+  'name': 'main',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'schedule': files('parallel_schedule'),
+  'regress_args': ['--make-testtablespace-dir'],
+  'test_kwargs': {
+    'priority': 50,
+    'timeout': 1000,
+  },
+}
diff --git a/src/test/ssl/meson.build b/src/test/ssl/meson.build
new file mode 100644
index 00000000000..42e34c9f632
--- /dev/null
+++ b/src/test/ssl/meson.build
@@ -0,0 +1,10 @@
+tap_tests += {
+  'name': 'ssl',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'env' : {'with_ssl': get_option('ssl')},
+  'tests': [
+    't/001_ssltests.pl',
+    't/002_scram.pl'
+  ],
+}
diff --git a/src/test/subscription/meson.build b/src/test/subscription/meson.build
new file mode 100644
index 00000000000..1024952e25b
--- /dev/null
+++ b/src/test/subscription/meson.build
@@ -0,0 +1,34 @@
+tap_tests += {
+  'name': 'subscription',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'env' : {'with_icu': icu.found() ? 'yes' : 'no'},
+  'tests': [
+    't/001_rep_changes.pl',
+    't/002_types.pl',
+    't/003_constraints.pl',
+    't/004_sync.pl',
+    't/005_encoding.pl',
+    't/006_rewrite.pl',
+    't/007_ddl.pl',
+    't/008_diff_schema.pl',
+    't/009_matviews.pl',
+    't/010_truncate.pl',
+    't/011_generated.pl',
+    't/012_collation.pl',
+    't/013_partition.pl',
+    't/014_binary.pl',
+    't/015_stream.pl',
+    't/016_stream_subxact.pl',
+    't/017_stream_ddl.pl',
+    't/018_stream_subxact_abort.pl',
+    't/019_stream_subxact_ddl_abort.pl',
+    't/020_messages.pl',
+    't/021_twophase.pl',
+    't/022_twophase_cascade.pl',
+    't/023_twophase_stream.pl',
+    't/024_add_drop_pub.pl',
+    't/025_rep_changes_for_schema.pl',
+    't/100_bugs.pl',
+  ],
+}
diff --git a/src/timezone/meson.build b/src/timezone/meson.build
new file mode 100644
index 00000000000..c3703a5ec7d
--- /dev/null
+++ b/src/timezone/meson.build
@@ -0,0 +1,50 @@
+# files to build into backend
+timezone_sources = files(
+  'localtime.c',
+  'pgtz.c',
+  'strftime.c',
+)
+
+
+timezone_inc = include_directories('.')
+
+timezone_localtime_source = files('localtime.c')
+
+# files needed to build zic utility program
+zic_sources = files(
+   'zic.c'
+)
+
+# we now distribute the timezone data as a single file
+tzdata = files(
+  'data/tzdata.zi'
+)
+
+
+# FIXME: For cross builds, it would need a native built libpgport/pgcommon to
+# build our zic. But for that we'd need to run a good chunk of the configure
+# tests both natively and cross. Unclear if it's worth it.
+if meson.is_cross_build()
+  zic = find_program('zic', native: true, required: false)
+else
+  zic = executable('zic', zic_sources,
+    dependencies: [frontend_code],
+    kwargs: default_bin_args + {'install': false}
+  )
+endif
+
+# FIXME: this used to be sorted - but also isn't actually used
+abbrevs_txt = custom_target('abbrevs.txt',
+  input: tzdata,
+  output: ['abbrevs.txt'],
+  command: [zic, '-P', '-b', 'fat', 'junkdir', '@INPUT@'],
+  capture: true)
+
+tzdata = custom_target('tzdata',
+  input: tzdata,
+  output: ['timezone'],
+  command: [zic, '-d', '@OUTPUT@', '@INPUT@'],
+  install: true,
+  install_dir: get_option('datadir'))
+
+subdir('tznames')
diff --git a/src/timezone/tznames/meson.build b/src/timezone/tznames/meson.build
new file mode 100644
index 00000000000..effd2880ce7
--- /dev/null
+++ b/src/timezone/tznames/meson.build
@@ -0,0 +1,20 @@
+tznames = files(
+  'Africa.txt',
+  'America.txt',
+  'Antarctica.txt',
+  'Asia.txt',
+  'Atlantic.txt',
+  'Australia.txt',
+  'Etc.txt',
+  'Europe.txt',
+  'Indian.txt',
+  'Pacific.txt',
+)
+
+tznames_sets = files(
+  'Default',
+  'Australia',
+  'India')
+
+install_data(tznames, install_dir: get_option('datadir') / 'timezonesets')
+install_data(tznames_sets, install_dir: get_option('datadir') / 'timezonesets')
diff --git a/src/tools/find_meson b/src/tools/find_meson
new file mode 100755
index 00000000000..2d75537374e
--- /dev/null
+++ b/src/tools/find_meson
@@ -0,0 +1,20 @@
+#!/usr/bin/env python3
+
+import os
+import shlex
+import sys
+
+mesonintrospect = os.environ['MESONINTROSPECT']
+components = shlex.split(mesonintrospect)
+
+if len(components) < 2:
+    print(f'expected more, got: {components}')
+    sys.exit(1)
+
+if components[-1] != 'introspect':
+    print('expected introspection at the end')
+    sys.exit(1)
+
+print('\n'.join(components[:-1]), end='')
+
+sys.exit(0)
diff --git a/src/tools/irlink b/src/tools/irlink
new file mode 100644
index 00000000000..efc2c700277
--- /dev/null
+++ b/src/tools/irlink
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+set -e
+
+srcdir="$1"
+builddir="$2"
+llvm_lto="$3"
+outputdir=$(realpath "$5")
+index="$outputdir/postgres.index.bc"
+priv="$6"
+shift 6
+numinput=$#
+
+if [ ! -d "$outputdir" ];then
+    mkdir -p "$outputdir/postgres"
+fi
+
+cd $priv
+
+# fixme, remove old contents"
+cp -r . "$outputdir/postgres"
+
+cd "$outputdir"
+
+filenames=$(for f in "$@";do echo "postgres/${f#$priv/}";done)
+"$llvm_lto" -thinlto -thinlto-action=thinlink -o "$index" $filenames
+
+exit 0
diff --git a/src/tools/msvc/export2def.pl b/src/tools/msvc/export2def.pl
new file mode 100644
index 00000000000..fb88e8b8ab9
--- /dev/null
+++ b/src/tools/msvc/export2def.pl
@@ -0,0 +1,22 @@
+# Copyright (c) 2021, PostgreSQL Global Development Group
+
+use strict;
+use warnings;
+use 5.8.0;
+use List::Util qw(max);
+
+my ($deffile, $txtfile, $libname) = @ARGV;
+
+print STDERR "Generating $deffile...\n";
+open(my $if, '<', $txtfile) || die("Could not open $txtfile\n");
+open(my $of, '>', $deffile) || die("Could not open $deffile for writing\n");
+print $of "LIBRARY $libname\nEXPORTS\n";
+while (<$if>)
+{
+	next if (/^#/);
+	next if (/^\s*$/);
+	my ($f, $o) = split;
+	print $of " $f @ $o\n";
+}
+close($of);
+close($if);
diff --git a/src/tools/msvc/gendef2.pl b/src/tools/msvc/gendef2.pl
new file mode 100644
index 00000000000..3b905d6f5da
--- /dev/null
+++ b/src/tools/msvc/gendef2.pl
@@ -0,0 +1,177 @@
+
+# Copyright (c) 2021, PostgreSQL Global Development Group
+
+use strict;
+use warnings;
+use 5.8.0;
+use List::Util qw(max);
+
+my @def;
+
+#
+# Script that generates a .DEF file for all objects in a directory
+#
+# src/tools/msvc/gendef.pl
+#
+
+# Given a symbol file path, loops over its contents
+# and returns a list of symbols of interest as a dictionary
+# of 'symbolname' -> symtype, where symtype is:
+#
+#     0    a CODE symbol, left undecorated in the .DEF
+#     1    A DATA symbol, i.e. global var export
+#
+sub extract_syms
+{
+	my ($symfile, $def) = @_;
+	open(my $f, '<', $symfile) || die "Could not open $symfile: $!\n";
+	while (<$f>)
+	{
+
+		# Expected symbol lines look like:
+		#
+		# 0   1        2      3            4            5 6
+		# IDX SYMBOL   SECT   SYMTYPE      SYMSTATIC      SYMNAME
+		# ------------------------------------------------------------------------
+		# 02E 00000130 SECTA  notype       External     | _standbyState
+		# 02F 00000009 SECT9  notype       Static       | _LocalRecoveryInProgress
+		# 064 00000020 SECTC  notype ()    Static       | _XLogCheckBuffer
+		# 065 00000000 UNDEF  notype ()    External     | _BufferGetTag
+		#
+		# See http://msdn.microsoft.com/en-us/library/b842y285.aspx
+		#
+		# We're not interested in the symbol index or offset.
+		#
+		# SECT[ION] is only examined to see whether the symbol is defined in a
+		# COFF section of the local object file; if UNDEF, it's a symbol to be
+		# resolved at link time from another object so we can't export it.
+		#
+		# SYMTYPE is always notype for C symbols as there's no typeinfo and no
+		# way to get the symbol type from name (de)mangling. However, we care
+		# if "notype" is suffixed by "()" or not. The presence of () means the
+		# symbol is a function, the absence means it isn't.
+		#
+		# SYMSTATIC indicates whether it's a compilation-unit local "static"
+		# symbol ("Static"), or whether it's available for use from other
+		# compilation units ("External"). We export all symbols that aren't
+		# static as part of the whole program DLL interface to produce UNIX-like
+		# default linkage.
+		#
+		# SYMNAME is, obviously, the symbol name. The leading underscore
+		# indicates that the _cdecl calling convention is used. See
+		# http://www.unixwiz.net/techtips/win32-callconv.html
+		# http://www.codeproject.com/Articles/1388/Calling-Conventions-Demystified
+		#
+		s/notype \(\)/func/g;
+		s/notype/data/g;
+
+		my @pieces = split;
+
+		# Skip file and section headers and other non-symbol entries
+		next unless defined($pieces[0]) and $pieces[0] =~ /^[A-F0-9]{3,}$/;
+
+		# Skip blank symbol names
+		next unless $pieces[6];
+
+		# Skip externs used from another compilation unit
+		next if ($pieces[2] eq "UNDEF");
+
+		# Skip static symbols
+		next unless ($pieces[4] eq "External");
+
+		# Skip some more MSVC-generated crud
+		next if $pieces[6] =~ /^@/;
+		next if $pieces[6] =~ /^\(/;
+
+		# __real and __xmm are out-of-line floating point literals and
+		# (for __xmm) their SIMD equivalents. They shouldn't be part
+		# of the DLL interface.
+		next if $pieces[6] =~ /^__real/;
+		next if $pieces[6] =~ /^__xmm/;
+
+		# __imp entries are imports from other DLLs, eg __imp__malloc .
+		# (We should never have one of these that hasn't already been skipped
+		# by the UNDEF test above, though).
+		next if $pieces[6] =~ /^__imp/;
+
+		# More under-documented internal crud
+		next if $pieces[6] =~ /NULL_THUNK_DATA$/;
+		next if $pieces[6] =~ /^__IMPORT_DESCRIPTOR/;
+		next if $pieces[6] =~ /^__NULL_IMPORT/;
+
+		# Skip string literals
+		next if $pieces[6] =~ /^\?\?_C/;
+
+		# We assume that if a symbol is defined as data, then as a function,
+		# the linker will reject the binary anyway. So it's OK to just pick
+		# whatever came last.
+		$def->{ $pieces[6] } = $pieces[3];
+	}
+	close($f);
+	return;
+}
+
+sub writedef
+{
+	my ($deffile, $platform, $def) = @_;
+	open(my $fh, '>', $deffile) || die "Could not write to $deffile\n";
+	print $fh "EXPORTS\n";
+	foreach my $f (sort keys %{$def})
+	{
+		my $isdata = $def->{$f} eq 'data';
+
+		# Strip the leading underscore for win32, but not x64
+		$f =~ s/^_//
+		  unless ($platform eq "x64");
+
+		# Emit just the name if it's a function symbol, or emit the name
+		# decorated with the DATA option for variables.
+		if ($isdata)
+		{
+			print $fh "  $f DATA\n";
+		}
+		else
+		{
+			print $fh "  $f\n";
+		}
+	}
+	close($fh);
+	return;
+}
+
+
+sub usage
+{
+	die(    "Usage: gendef.pl platform outputfile tempdir sourcelib\n"
+		  . "    modulepath: path to dir with obj files, no trailing slash"
+		  . "    platform: Win32 | x64");
+}
+
+usage()
+  unless scalar(@ARGV) >= 4;
+
+my $platform  = $ARGV[0];
+shift;
+my $deffile  = $ARGV[0];
+shift;
+my $tempdir  = $ARGV[0];
+shift;
+
+print STDERR "Generating $deffile in tmp dir $tempdir from ".join(' ', @ARGV)."\n";
+
+my %def = ();
+
+my $symfile = "$tempdir/all.sym";
+my $tmpfile = "$tempdir/tmp.sym";
+mkdir($tempdir);
+print STDERR "dumpbin /symbols /out:$tmpfile ".join(' ', @ARGV)."\n";
+system("dumpbin /symbols /out:$tmpfile ".join(' ', @ARGV))
+  && die "Could not call dumpbin";
+rename($tmpfile, $symfile);
+print "generated symfile to $symfile (via $tmpfile)\n";
+extract_syms($symfile, \%def);
+print "\n";
+
+writedef($deffile, $platform, \%def);
+
+print "Generated " . scalar(keys(%def)) . " symbols\n";
diff --git a/src/tools/relativize_shared_library_references \
b/src/tools/relativize_shared_library_references new file mode 100755
index 00000000000..db6431639f1
--- /dev/null
+++ b/src/tools/relativize_shared_library_references
@@ -0,0 +1,84 @@
+#!/usr/bin/env python3
+# -*-python-*-
+
+# This script updates a macos postgres installation to reference all internal
+# shared libraries using rpaths, leaving absolute install_names in the
+# libraries themselves intact.
+
+import os
+import shlex
+import sys
+import json
+import subprocess
+import shutil
+
+
+def installed_path(destdir, path):
+    if destdir is not None:
+        return f'{destdir}{path}'
+    else:
+        return path
+
+
+def collect_information():
+    shared_libraries = []
+    executables = []
+    shared_modules = []
+
+    targets = json.load(open(os.path.join(build_root, 'meson-info', \
'intro-targets.json'))) +    installed = json.load(open(os.path.join(build_root, \
'meson-info', 'intro-installed.json'))) +
+    for target in targets:
+        if not target['installed']:
+            continue
+
+        filenames = target['filename']
+
+        if target['type'] == 'shared library':
+            assert(len(filenames) == 1)
+            filename = filenames[0]
+
+            shared_libraries.append(installed[filename])
+
+        if target['type'] == 'executable':
+            assert(len(filenames) == 1)
+            filename = filenames[0]
+            executables.append(installed[filename])
+
+        if target['type'] == 'shared module':
+            assert(len(filenames) == 1)
+            filename = filenames[0]
+            shared_modules.append(installed[filename])
+
+    return shared_libraries, executables, shared_modules
+
+
+def patch_references(destdir, shared_libraries, executables, shared_modules):
+    install_name_tool = [shutil.which('install_name_tool')]
+
+    for lib in shared_libraries:
+        libname = os.path.basename(lib)
+        libpath = installed_path(destdir, lib)
+        newref = f'@rpath/{libname}'
+
+        for patch in shared_modules + executables:
+            patchpath = installed_path(destdir, patch)
+
+            #print(f'in {patchpath} replace reference to {libpath} with {newref}')
+            if not os.path.exists(patchpath):
+                print(f"path {patchpath} doesn't exist", file=sys.stderr)
+                sys.exit(1)
+
+            subprocess.check_call(install_name_tool + ['-change', lib, newref, \
patchpath]) +
+
+if __name__ == '__main__':
+    build_root = os.environ['MESON_BUILD_ROOT']
+    destdir = os.environ.get('DESTDIR', None)
+
+    print(f'making references to shared libraries relative, destdir is {destdir}', \
file=sys.stderr) +
+    shared_libraries, executables, shared_modules = collect_information()
+    patch_references(destdir, shared_libraries, executables, shared_modules)
+
+    sys.exit(0)
diff --git a/src/tools/relpath.py b/src/tools/relpath.py
new file mode 100755
index 00000000000..87bcb496ab5
--- /dev/null
+++ b/src/tools/relpath.py
@@ -0,0 +1,6 @@
+#!/usr/bin/env python3
+
+import os
+import sys
+
+print(os.path.relpath(sys.argv[2], start=sys.argv[1]))
diff --git a/src/tools/testwrap b/src/tools/testwrap
new file mode 100755
index 00000000000..aeb2019b099
--- /dev/null
+++ b/src/tools/testwrap
@@ -0,0 +1,22 @@
+#!/bin/sh
+#
+# FIXME: I should probably be a perl or python script
+#
+
+# FIXME: argument parsing
+
+basedir=$1
+builddir=$2
+testgroup=$3
+testname=$(basename -s .pl $4)
+shift 4
+
+testdir="$basedir/testrun/$testgroup/$testname"
+echo "# executing test in $testdir group $testgroup test $testname, builddir \
$builddir" +rm -rf "$testdir/"
+mkdir -p "$testdir"
+
+export TESTOUTDIR="$testdir"
+export TESTDIR="$builddir"
+
+exec "$@"
-- 
2.23.0.385.gbc12974a89


["v5-0016-meson-ci-Build-both-with-meson-and-as-before.patch" (text/x-diff)]

From 0585858de3602b88b2c8f11924d3439f457b5ab2 Mon Sep 17 00:00:00 2001
From: Andres Freund <andres@anarazel.de>
Date: Fri, 8 Oct 2021 17:29:10 -0700
Subject: [PATCH v5 16/16] meson: ci: Build both with meson and as before.

---
 .cirrus.yml | 466 ++++++++++++++++++++++++++++++++++------------------
 1 file changed, 309 insertions(+), 157 deletions(-)

diff --git a/.cirrus.yml b/.cirrus.yml
index 2bb6f4a14d7..a7f955b3c63 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -13,14 +13,13 @@ env:
 
 
 task:
-  name: FreeBSD
   only_if: $CIRRUS_CHANGE_MESSAGE !=~ '.*\nci-os-only:.*' || $CIRRUS_CHANGE_MESSAGE \
=~ '.*\nci-os-only:[^\n]*freebsd.*'  compute_engine_instance:
     image_project: pg-vm-images-aio
     image: family/pg-aio-freebsd-13-0
     platform: freebsd
-    cpu: 2
-    memory: 2G
+    cpu: 4
+    memory: 4G
     disk: 50
   env:
     CCACHE_DIR: "/tmp/ccache_dir"
@@ -39,33 +38,52 @@ task:
     - mkdir -p /tmp/ccache_dir
     - chown -R postgres:postgres /tmp/ccache_dir
 
-  configure_script: |
-    su postgres -c './configure \
-      --enable-cassert --enable-debug --enable-tap-tests \
-      --enable-nls \
-      \
-      --with-icu \
-      --with-ldap \
-      --with-libxml \
-      --with-libxslt \
-      \
-      --with-lz4 \
-      --with-pam \
-      --with-perl \
-      --with-python \
-      --with-ssl=openssl \
-      --with-tcl --with-tclconfig=/usr/local/lib/tcl8.6/ \
-      --with-uuid=bsd \
-      \
-      --with-includes=/usr/local/include --with-libs=/usr/local/lib \
-      CC="ccache cc"'
-  build_script:
-    - su postgres -c 'gmake -s -j3 && gmake -s -j3 -C contrib'
-  upload_caches:
-    - ccache
+  matrix:
+    - name: FreeBSD autoconf
+
+      configure_script: |
+        su postgres -c './configure \
+          --enable-cassert --enable-debug --enable-tap-tests \
+          --enable-nls \
+          \
+          --with-icu \
+          --with-ldap \
+          --with-libxml \
+          --with-libxslt \
+          \
+          --with-lz4 \
+          --with-pam \
+          --with-perl \
+          --with-python \
+          --with-ssl=openssl \
+          --with-tcl --with-tclconfig=/usr/local/lib/tcl8.6/ \
+          --with-uuid=bsd \
+          \
+          --with-includes=/usr/local/include --with-libs=/usr/local/lib \
+          CC="ccache cc"'
+      build_script:
+        - su postgres -c 'gmake -s -j4 && gmake -s -j4 -C contrib'
+      upload_caches:
+        - ccache
+
+      tests_script:
+        - su postgres -c 'time gmake -s -j4 ${CHECK} ${CHECKFLAGS}'
+
+    - name: FreeBSD meson
+
+      configure_script:
+        - su postgres -c 'meson setup --buildtype debug -Dcassert=true -Dssl=openssl \
-Duuid=bsd build' +      build_script:
+        - su postgres -c 'ninja -C build'
+      upload_caches:
+        - ccache
+      run_tests_script:
+        - su postgres -c 'meson test --no-rebuild -C build'
 
-  tests_script:
-    - su postgres -c 'time gmake -s -j2 ${CHECK} ${CHECKFLAGS}'
+  always:
+    meson_log_artifacts:
+      path: "build/meson-logs/*.txt"
+      type: text/plain
 
   on_failure:
     cores_script: |
@@ -83,14 +101,16 @@ task:
     tap_artifacts:
       path: "**/regress_log_*"
       type: text/plain
+    meson_test_artifacts:
+      path: "build/meson-logs/testlog.junit.xml"
+      type: text/xml
+      format: junit
 
 
 task:
-  name: Linux
   only_if: $CIRRUS_CHANGE_MESSAGE !=~ '.*\nci-os-only:.*' || $CIRRUS_CHANGE_MESSAGE \
=~ '.*\nci-os-only:[^\n]*linux.*'  compute_engine_instance:
     image_project: pg-vm-images-aio
-    image: family/pg-aio-bullseye
     platform: linux
     cpu: 4
     memory: 2G
@@ -120,37 +140,78 @@ task:
     - su postgres -c 'ulimit -l -S'
     - echo '/tmp/%e-%s-%p.core' > /proc/sys/kernel/core_pattern
 
-  configure_script: |
-    su postgres -c './configure \
-      --enable-cassert --enable-debug --enable-tap-tests \
-      --enable-nls \
-      \
-      --with-gssapi \
-      --with-icu \
-      --with-ldap \
-      --with-libxml \
-      --with-libxslt \
-      --with-llvm \
-      --with-lz4 \
-      --with-pam \
-      --with-perl \
-      --with-python \
-      --with-ssl=openssl \
-      --with-systemd \
-      --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ \
-      --with-uuid=e2fs \
-      \
-      CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" CFLAGS="-O0 -ggdb"'
-  build_script:
-    - su postgres -c 'make -s -j4 && make -s -j4 -C contrib'
-  upload_caches:
-    - ccache
+  matrix:
+    - name: Linux Autoconf
+
+      compute_engine_instance:
+        image: family/pg-aio-bullseye
+
+      configure_script: |
+        su postgres -c './configure \
+          --enable-cassert --enable-debug --enable-tap-tests \
+          --enable-nls \
+          \
+          --with-gssapi \
+          --with-icu \
+          --with-ldap \
+          --with-libxml \
+          --with-libxslt \
+          --with-llvm \
+          --with-lz4 \
+          --with-pam \
+          --with-perl \
+          --with-python \
+          --with-ssl=openssl \
+          --with-systemd \
+          --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ \
+          --with-uuid=e2fs \
+          \
+          CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" CFLAGS="-O0 -ggdb"'
+      build_script:
+        - su postgres -c 'make -s -j4 && make -s -j4 -C contrib'
+      upload_caches:
+        - ccache
+
+      tests_script: |
+        su postgres -c '\
+          ulimit -c unlimited; \
+          make -s ${CHECK} ${CHECKFLAGS} -j8 \
+          '
+
+    - name: Linux Meson
+
+      compute_engine_instance:
+        image: family/pg-aio-bullseye
+
+      configure_script:
+        - su postgres -c 'meson setup --buildtype debug -Dcassert=true -Dssl=openssl \
-Duuid=e2fs build' +      build_script:
+        - su postgres -c 'ninja -C build'
+      upload_caches:
+        - ccache
+
+      tests_script:
+        - su postgres -c 'meson test --no-rebuild -C build'
+
+    - name: Linux Meson Sid
+
+      compute_engine_instance:
+        image: family/pg-aio-sid
+
+      configure_script:
+        - su postgres -c 'meson setup --buildtype debug -Dcassert=true -Dssl=openssl \
-Duuid=ossp build' +      build_script:
+        - su postgres -c 'ninja -C build'
+      upload_caches:
+        - ccache
+
+      tests_script:
+        - su postgres -c 'meson test --no-rebuild -C build'
 
-  tests_script: |
-    su postgres -c '\
-      ulimit -c unlimited; \
-      make -s ${CHECK} ${CHECKFLAGS} -j8 \
-      '
+  always:
+    meson_log_artifacts:
+      path: "build/meson-logs/*.txt"
+      type: text/plain
 
   on_failure:
     cores_script: |
@@ -168,10 +229,13 @@ task:
     tap_artifacts:
       path: "**/regress_log_*"
       type: text/plain
+    meson_test_artifacts:
+      path: "build/meson-logs/testlog.junit.xml"
+      type: text/xml
+      format: junit
 
 
 task:
-  name: macOS
   only_if: $CIRRUS_CHANGE_MESSAGE !=~ '.*\nci-os-only:.*' || $CIRRUS_CHANGE_MESSAGE \
=~ '.*\nci-os-only:[^\n]*(macos|darwin|osx).*'  osx_instance:
     image: big-sur-base
@@ -201,56 +265,87 @@ task:
     - sudo chmod 777 /cores
   homebrew_install_script:
     - brew install make coreutils ccache icu4c lz4 tcl-tk openldap
+    - brew install meson ninja python@3.9
   upload_caches:
     - homebrew
 
-  configure_script: |
-    LIBS="/usr/local/lib:$LIBS"
-    INCLUDES="/usr/local/include:$INCLUDES"
-
-    INCLUDES="/usr/local/opt/openssl/include:$INCLUDES"
-    LIBS="/usr/local/opt/openssl/lib:$LIBS"
-
-    PKG_CONFIG_PATH="/usr/local/opt/icu4c/lib/pkgconfig:$PKG_CONFIG_PATH"
-    INCLUDES="/usr/local/opt/icu4c/include:$INCLUDES"
-    LIBS="/usr/local/opt/icu4c/lib:$LIBS"
-
-    LIBS="/usr/local/opt/openldap/lib:$LIBS"
-    INCLUDES="/usr/local/opt/openldap/include:$INCLUDES"
-
-    export PKG_CONFIG_PATH
-
-    ./configure \
-      --prefix=$HOME/install \
-      --with-includes="$INCLUDES" \
-      --with-libs="$LIBS" \
-      \
-      --enable-cassert --enable-debug --enable-tap-tests \
-      --enable-nls \
-      \
-      --with-icu \
-      --with-ldap \
-      --with-libxml \
-      --with-libxslt \
-      \
-      --with-lz4 \
-      --with-perl \
-      --with-python \
-      --with-ssl=openssl \
-      --with-tcl --with-tclconfig=/usr/local/opt/tcl-tk/lib/ \
-      --with-uuid=e2fs \
-      \
-      CC="ccache gcc" CFLAGS="-O0 -ggdb" \
-      PYTHON=python3
-  build_script:
-    - gmake -s -j12 && gmake -s -j12 -C contrib
-  upload_caches:
-    - ccache
+  matrix:
+    - name: macOS autoconf
+
+      configure_script: |
+        LIBS="/usr/local/lib:$LIBS"
+        INCLUDES="/usr/local/include:$INCLUDES"
+
+        PKG_CONFIG_PATH="/usr/local/opt/openssl/lib/pkgconfig:$PKG_CONFIG_PATH"
+        INCLUDES="/usr/local/opt/openssl/include:$INCLUDES"
+        LIBS="/usr/local/opt/openssl/lib:$LIBS"
+
+        PKG_CONFIG_PATH="/usr/local/opt/icu4c/lib/pkgconfig:$PKG_CONFIG_PATH"
+        INCLUDES="/usr/local/opt/icu4c/include:$INCLUDES"
+        LIBS="/usr/local/opt/icu4c/lib:$LIBS"
+
+        PKG_CONFIG_PATH="/usr/local/opt/openldap/lib/pkgconfig:$PKG_CONFIG_PATH"
+        LIBS="/usr/local/opt/openldap/lib:$LIBS"
+        INCLUDES="/usr/local/opt/openldap/include:$INCLUDES"
+
+        export PKG_CONFIG_PATH
+
+        ./configure \
+          --prefix=$HOME/install \
+          --with-includes="$INCLUDES" \
+          --with-libs="$LIBS" \
+          \
+          --enable-cassert --enable-debug --enable-tap-tests \
+          --enable-nls \
+          \
+          --with-icu \
+          --with-ldap \
+          --with-libxml \
+          --with-libxslt \
+          \
+          --with-lz4 \
+          --with-perl \
+          --with-python \
+          --with-ssl=openssl \
+          --with-tcl --with-tclconfig=/usr/local/opt/tcl-tk/lib/ \
+          --with-uuid=e2fs \
+          \
+          CC="ccache gcc" CFLAGS="-O0 -ggdb" \
+          PYTHON=python3
+      build_script:
+        - gmake -s -j12 && gmake -s -j12 -C contrib
+      upload_caches:
+        - ccache
+
+      tests_script:
+        - ulimit -c unlimited
+        - ulimit -n 1024
+        - gmake -s -j12 ${CHECK} ${CHECKFLAGS}
+
+    - name: macOS meson
+
+      configure_script: |
+        PKG_CONFIG_PATH="/usr/local/opt/openssl/lib/pkgconfig:$PKG_CONFIG_PATH"
+        PKG_CONFIG_PATH="/usr/local/opt/icu4c/lib/pkgconfig:$PKG_CONFIG_PATH"
+        PKG_CONFIG_PATH="/usr/local/opt/openldap/lib/pkgconfig:$PKG_CONFIG_PATH"
+
+        export PKG_CONFIG_PATH
+
+        meson setup --buildtype debug -Dcassert=true -Dssl=openssl -Duuid=e2fs build
+      build_script:
+        - ninja -C build
+      upload_caches:
+        - ccache
+
+      tests_script:
+        - ulimit -c unlimited
+        - ulimit -n 1024
+        - meson test --no-rebuild -C build
 
-  tests_script:
-    - ulimit -c unlimited
-    - ulimit -n 1024
-    - gmake -s -j12 ${CHECK} ${CHECKFLAGS}
+  always:
+    meson_log_artifacts:
+      path: "build/meson-logs/*.txt"
+      type: text/plain
 
   on_failure:
     cores_script: |
@@ -266,10 +361,13 @@ task:
     tap_artifacts:
       path: "**/regress_log_*"
       type: text/plain
+    meson_test_artifacts:
+      path: "build/meson-logs/testlog.junit.xml"
+      type: text/xml
+      format: junit
 
 
 task:
-  name: Windows
   only_if: $CIRRUS_CHANGE_MESSAGE !=~ '.*\nci-os-only:.*' || $CIRRUS_CHANGE_MESSAGE \
=~ '.*\nci-os-only:[^\n]*windows.*'  windows_container:
     dockerfile: ci/docker/windows_vs_2019
@@ -282,6 +380,8 @@ task:
     TEMP_CONFIG: ${CIRRUS_WORKING_DIR}/ci/pg_ci_base.conf
     # Avoid re-installing over and over
     NO_TEMP_INSTALL: 1
+    # Try to hide git's tar
+    PATH: c:\windows\system32;${PATH}
 
   sysinfo_script:
     - chcp
@@ -290,55 +390,103 @@ task:
     - ps: Get-Item -Path 'HKLM:\SOFTWARE\Microsoft\Windows \
                NT\CurrentVersion\AeDebug'
     - set
 
-  configure_script:
-    - copy ci\windows_build_config.pl src\tools\msvc\config.pl
-    - vcvarsall x64
-    - perl src/tools/msvc/mkvcbuild.pl
-  build_script:
-    - vcvarsall x64
-    # Disable file tracker, we're never going to rebuild...
-    - msbuild -m /p:TrackFileAccess=false pgsql.sln
-  tempinstall_script:
-    # Installation on windows currently only completely works from src\tools\msvc
-    - cd src\tools\msvc && perl .\install.pl %CIRRUS_WORKING_DIR%\tmp_install
-
-  check_test_script:
-    - perl src/tools/msvc/vcregress.pl check parallel
-  startcreate_test_script:
-    - tmp_install\bin\pg_ctl.exe initdb -D tmp_check\db -l tmp_check\initdb.log
-    - echo include '%TEMP_CONFIG%' >> tmp_check\db\postgresql.conf
-    - tmp_install\bin\pg_ctl.exe start -D tmp_check\db -l tmp_check\postmaster.log
-  plcheck_test_script:
-    - perl src/tools/msvc/vcregress.pl plcheck
-  isolationcheck_test_script:
-    - perl src/tools/msvc/vcregress.pl isolationcheck
-  modulescheck_test_script:
-    - perl src/tools/msvc/vcregress.pl modulescheck
-  contribcheck_test_script:
-    - perl src/tools/msvc/vcregress.pl contribcheck
-  stop_test_script:
-    - tmp_install\bin\pg_ctl.exe stop -D tmp_check\db -l tmp_check\postmaster.log
-  ssl_test_script:
-    - set with_ssl=openssl
-    - perl src/tools/msvc/vcregress.pl taptest .\src\test\ssl\
-  subscriptioncheck_test_script:
-    - perl src/tools/msvc/vcregress.pl taptest .\src\test\subscription\
-  authentication_test_script:
-    - perl src/tools/msvc/vcregress.pl taptest .\src\test\authentication\
-  recoverycheck_test_script:
-    - perl src/tools/msvc/vcregress.pl recoverycheck
-  bincheck_test_script:
-    - perl src/tools/msvc/vcregress.pl bincheck
-  upgradecheck_test_script:
-    - perl src/tools/msvc/vcregress.pl upgradecheck
-  ecpgcheck_test_script:
-    # tries to build additional stuff
-    - vcvarsall x64
-    # References ecpg_regression.proj in the current dir
-    - cd src\tools\msvc
-    - perl vcregress.pl ecpgcheck
+  matrix:
+    - name: Windows homegrown
+
+      configure_script:
+        - copy ci\windows_build_config.pl src\tools\msvc\config.pl
+        - vcvarsall x64
+        - perl src/tools/msvc/mkvcbuild.pl
+      build_script:
+        - vcvarsall x64
+        # Disable file tracker, we're never going to rebuild...
+        - msbuild -m /p:TrackFileAccess=false pgsql.sln
+      tempinstall_script:
+        # Installation on windows currently only completely works from \
src\tools\msvc +        - cd src\tools\msvc && perl .\install.pl \
%CIRRUS_WORKING_DIR%\tmp_install +
+      check_test_script:
+        - perl src/tools/msvc/vcregress.pl check parallel
+      startcreate_test_script:
+        - tmp_install\bin\pg_ctl.exe initdb -D tmp_check\db -l tmp_check\initdb.log
+        - echo include '%TEMP_CONFIG%' >> tmp_check\db\postgresql.conf
+        - tmp_install\bin\pg_ctl.exe start -D tmp_check\db -l \
tmp_check\postmaster.log +      plcheck_test_script:
+        - perl src/tools/msvc/vcregress.pl plcheck
+      isolationcheck_test_script:
+        - perl src/tools/msvc/vcregress.pl isolationcheck
+      modulescheck_test_script:
+        - perl src/tools/msvc/vcregress.pl modulescheck
+      contribcheck_test_script:
+        - perl src/tools/msvc/vcregress.pl contribcheck
+      stop_test_script:
+        - tmp_install\bin\pg_ctl.exe stop -D tmp_check\db -l \
tmp_check\postmaster.log +      ssl_test_script:
+        - set with_ssl=openssl
+        - perl src/tools/msvc/vcregress.pl taptest .\src\test\ssl\
+      subscriptioncheck_test_script:
+        - perl src/tools/msvc/vcregress.pl taptest .\src\test\subscription\
+      authentication_test_script:
+        - perl src/tools/msvc/vcregress.pl taptest .\src\test\authentication\
+      recoverycheck_test_script:
+        - perl src/tools/msvc/vcregress.pl recoverycheck
+      bincheck_test_script:
+        - perl src/tools/msvc/vcregress.pl bincheck
+      upgradecheck_test_script:
+        - perl src/tools/msvc/vcregress.pl upgradecheck
+      ecpgcheck_test_script:
+        # tries to build additional stuff
+        - vcvarsall x64
+        # References ecpg_regression.proj in the current dir
+        - cd src\tools\msvc
+        - perl vcregress.pl ecpgcheck
+
+    - name: Windows Meson+vs+Ninja
+
+      meson_script:
+        - pip install meson
+        - pip install ninja
+      configure_script:
+        - vcvarsall x64
+        - mkdir subprojects
+        - meson wrap install lz4
+        - meson wrap install zlib
+        - meson setup --buildtype debug --backend ninja  -Dcassert=true -Db_pch=true \
-Dssl=openssl -Dlz4=enabled -Dzlib=enabled -Dextra_lib_dirs=c:\openssl\1.1.1l\lib \
-Dextra_include_dirs=c:\openssl\1.1.1l\include build +      build_script:
+        - vcvarsall x64
+        - ninja -C build
+
+      check_script:
+        - vcvarsall x64
+        - meson test --no-rebuild -C build
+
+    - name: Windows Meson+vs+msbuild
+
+      # Need a development version of meson for now
+      meson_dev_script:
+        - git clone https://github.com/mesonbuild/meson.git
+
+      configure_script:
+        - vcvarsall x64
+        - mkdir subprojects
+        - .\meson\meson.py wrap install lz4
+        - .\meson\meson.py wrap install zlib
+        - .\meson\meson.py setup --buildtype debug --backend vs -Dcassert=true \
-Db_pch=true -Dssl=openssl -Dlz4=enabled -Dzlib=enabled \
-Dextra_lib_dirs=c:\openssl\1.1.1l\lib -Dextra_include_dirs=c:\openssl\1.1.1l\include \
build +
+      build_script:
+        - vcvarsall x64
+        - msbuild -m /p:UseMultiToolTask=true build\postgresql.sln
+
+      check_script:
+        - vcvarsall x64
+        - .\meson\meson.py test --no-rebuild -C build
 
   always:
+    meson_log_artifacts:
+      path: "build/meson-logs/*.txt"
+      type: text/plain
+    cat_dumps_script:
+
     cores_script:
       - cat crashlog.txt || true
     dump_artifacts:
@@ -355,12 +503,16 @@ task:
     tap_artifacts:
       path: "**/regress_log_*"
       type: text/plain
+    meson_test_artifacts:
+      path: "build/meson-logs/testlog.junit.xml"
+      type: text/xml
+      format: junit
 
 
 task:
   name: CompilerWarnings
   depends_on:
-    - Linux
+    - Linux Autoconf
   # task that did not run count as a success, so we need to recheck Linux' condition \
here :/  only_if: $CIRRUS_CHANGE_MESSAGE !=~ '.*\nci-os-only:.*' || \
$CIRRUS_CHANGE_MESSAGE =~ '.*\nci-os-only:[^\n]*linux.*'  container:
-- 
2.23.0.385.gbc12974a89



[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic