Compare commits
345 Commits
Author | SHA1 | Date |
---|---|---|
|
4cd8bb1b67 | |
|
4456913801 | |
|
55a0d1f730 | |
|
5e37fe0c46 | |
|
e8c3179b4d | |
|
92dc7f36fc | |
|
98d95a9b9d | |
|
c7f5e2b975 | |
|
282523549e | |
|
c98341e4ed | |
|
8d2fbca8ef | |
|
088ba75057 | |
|
a18040869a | |
|
a4040ba5da | |
|
d4dd44e715 | |
|
ea7aa6712d | |
|
d2e6cf1de0 | |
|
3d61c4dc71 | |
|
37e23f44b4 | |
|
48d89c9c1b | |
|
bb9d90ecc3 | |
|
0e6127c4f6 | |
|
f084b79a4b | |
|
1dc60e38bb | |
|
a7e686c106 | |
|
88904eda97 | |
|
9bddf57053 | |
|
4b4fa22b64 | |
|
1c09469dd2 | |
|
680b870d45 | |
|
ec13c24558 | |
|
1d947f0734 | |
|
6b2f113947 | |
|
bdd3ff085d | |
|
6b00afac39 | |
|
10f1a50f1f | |
|
52bf7a1d03 | |
|
1d0bdbd749 | |
|
be75c0ec4c | |
|
caceb35eba | |
|
08913e27d7 | |
|
17b4122e84 | |
|
c02d899b6c | |
|
421bc462b2 | |
|
ed40a0ad02 | |
|
e50563fbd8 | |
|
756e8f66e0 | |
|
95da74c47f | |
|
4139370a1d | |
|
87ec3def55 | |
|
ec141f696a | |
|
ccd7ddee36 | |
|
89674d9630 | |
|
2b5dfbbd08 | |
|
7004295065 | |
|
3b1c082791 | |
|
d5618b6b4c | |
|
ef59b659c5 | |
|
85739b34bf | |
|
1bb6c7e95f | |
|
a18f8990be | |
|
7e1f22999b | |
|
0642a4dc08 | |
|
74d945f5ae | |
|
7682d135a4 | |
|
08d94f9eb6 | |
|
8f436e4a48 | |
|
8940665d17 | |
|
1d57a36ecc | |
|
658632642a | |
|
3e96a19606 | |
|
2112aa1860 | |
|
1cf5c190aa | |
|
24585a8c04 | |
|
b7d04038cb | |
|
5e9f8d838c | |
|
202ad077bd | |
|
a383ef6831 | |
|
28b0b0e7a8 | |
|
80c6479408 | |
|
29bd3dc41c | |
|
09e96831b3 | |
|
b22c95933c | |
|
c662e68e44 | |
|
915276ee7f | |
|
3935710c17 | |
|
11f76cb4bb | |
|
35d1160ace | |
|
088731e9db | |
|
c3d21b807a | |
|
592416250c | |
|
beb222ea8d | |
|
f8335c1484 | |
|
1797ab8a4f | |
|
808626ea78 | |
|
6254ad81fc | |
|
1074035446 | |
|
0de7b5a240 | |
|
9615b52863 | |
|
a74bb6280c | |
|
6043fcb263 | |
|
ed71e65333 | |
|
ae104f06a6 | |
|
b46d311e30 | |
|
4c080c48cd | |
|
81bda6fb8e | |
|
9dcd812a40 | |
|
46f89ccf65 | |
|
51c2e63c30 | |
|
9a413e0c32 | |
|
5540096b9a | |
|
c8d9a1bd10 | |
|
7e8bff034f | |
|
41ea21ee0c | |
|
dce54db494 | |
|
6bd3474804 | |
|
d885e1a016 | |
|
26ad52713c | |
|
afcda3feff | |
|
30bf960c5c | |
|
117bd1d04f | |
|
711aec80fa | |
|
829665ebca | |
|
f7c57351a7 | |
|
565c309a1e | |
|
cee0f31ddb | |
|
2d8be01853 | |
|
9a0cc282b7 | |
|
7073f06153 | |
|
8783cae57f | |
|
b6e3f39583 | |
|
a28f75cc77 | |
|
af5fced935 | |
|
7b6a828c74 | |
|
f7bead22d4 | |
|
5ef2cd67ed | |
|
70f84e4aee | |
|
0a6adf4ccc | |
|
ab7c13beb5 | |
|
73411915a4 | |
|
665d72a2f5 | |
|
0355b12c7f | |
|
fe6d198ab2 | |
|
248ff5d52a | |
|
c52f36019f | |
|
f6959715dc | |
|
5bad6c6a1d | |
|
4775715691 | |
|
68d28ecdc0 | |
|
9e1852eac7 | |
|
2a263fe69a | |
|
3c467e6e02 | |
|
accb7d09f7 | |
|
8ac9f0fcee | |
|
c603c3ed74 | |
|
e776a7ebbb | |
|
58fef24142 | |
|
aaaf637a6b | |
|
fa4fc0b372 | |
|
9e71750fcd | |
|
e62ae64d00 | |
|
76f68f47c4 | |
|
d5231c34ab | |
|
f883cfdd77 | |
|
7c8a366ba2 | |
|
06e9c29950 | |
|
493140287a | |
|
ec25b433d4 | |
|
eedb607cd5 | |
|
8c9de08b76 | |
|
2874d7af46 | |
|
0ab42e7a80 | |
|
fcc72d8a23 | |
|
553d5ba15d | |
|
a0151aa31d | |
|
ada3ba2507 | |
|
41e2af8ff5 | |
|
a263ac6f5f | |
|
110b4192b2 | |
|
16604a6601 | |
|
cdf51da458 | |
|
381f31756e | |
|
3586aab17a | |
|
41d99249d9 | |
|
3929a5b2a6 | |
|
fdd658acec | |
|
0acb5f6e86 | |
|
d129064280 | |
|
bf05bf51ec | |
|
8afa2d0386 | |
|
12f56438fc | |
|
f0043b64a1 | |
|
edcdbe67b1 | |
|
d59c93bc50 | |
|
51009d0191 | |
|
f4242685e3 | |
|
cbb90cc4ae | |
|
9ddee5d02a | |
|
3509b7df5a | |
|
211415dd4b | |
|
683e10ab69 | |
|
852bcc5483 | |
|
b3ef1b7e39 | |
|
56e014e64e | |
|
71ccbcf3e2 | |
|
2cbfdbfa46 | |
|
9a0cdbf5af | |
|
74b55d0546 | |
|
15a3adebe8 | |
|
59da0633bb | |
|
c665cb8af3 | |
|
2fae91c5df | |
|
689c6897a4 | |
|
f01c5f2593 | |
|
6869b3ad10 | |
|
9ff8436f14 | |
|
594cb6f274 | |
|
d05174093b | |
|
3ce731d497 | |
|
6f43d5c02f | |
|
5aedec4242 | |
|
f6ea619e27 | |
|
9c243d4477 | |
|
5d673874f7 | |
|
24188959ed | |
|
542212c3d8 | |
|
3de5601bcc | |
|
1d096df7f4 | |
|
8b48d6ab02 | |
|
1cb2e1e4e8 | |
|
3ffb831beb | |
|
863713e9b7 | |
|
11d7c27352 | |
|
9683bef2ec | |
|
72fbea20c4 | |
|
ee11492a0e | |
|
4b295cc857 | |
|
14ecebe47c | |
|
188614512f | |
|
5ec056a172 | |
|
fcfedff8d1 | |
|
6cf6cf37fd | |
|
51e607878b | |
|
21464adfec | |
|
04b374fc01 | |
|
739c6d26df | |
|
00068e07c5 | |
|
9a91136a3d | |
|
8e979f7ac6 | |
|
1d55debb98 | |
|
20dc58cf5d | |
|
968ac74cde | |
|
d940cfa992 | |
|
c3579eef06 | |
|
181b8ab6d5 | |
|
b877d606c7 | |
|
6801a1ed1e | |
|
dbdde111c1 | |
|
47bd9d8917 | |
|
c019acc01b | |
|
0620c8f9a6 | |
|
3b556cb5ed | |
|
cedcc220bf | |
|
c88bf5ff1c | |
|
e14e8667cc | |
|
32b0fc23f5 | |
|
55d500de8d | |
|
5efd3f181a | |
|
0d1f18862b | |
|
c6fbb72c02 | |
|
a960799dfb | |
|
cdef2d5224 | |
|
e4ac3e6d9a | |
|
240313e286 | |
|
57ff762c82 | |
|
c028d929b5 | |
|
d4663212f4 | |
|
0dac63afc0 | |
|
92228b279a | |
|
0dc41ee5a0 | |
|
444e6cb7d6 | |
|
e535f53ce5 | |
|
21646ca1e9 | |
|
5e2439a117 | |
|
85b997a0fb | |
|
f171ec98fc | |
|
b47c8b3fb0 | |
|
0678a2fd89 | |
|
5a48a1602e | |
|
6fed82609c | |
|
9867c5b949 | |
|
184c8fc1ee | |
|
a6e86884f6 | |
|
ea5551689e | |
|
2cf4c04023 | |
|
e3c93c303d | |
|
5903196020 | |
|
c9f2fc892d | |
|
c83c556702 | |
|
2bccb58157 | |
|
0d83ab57de | |
|
20ae42e7fa | |
|
37415ef8f5 | |
|
a76a832553 | |
|
81aa660b31 | |
|
ce58c04304 | |
|
83e3fb817d | |
|
ee8f4bb7e8 | |
|
d0b093c975 | |
|
f9218d9780 | |
|
2bf1472c8e | |
|
10198b18e8 | |
|
1fe16fa746 | |
|
2d1444188c | |
|
db13afaa7b | |
|
71a4633dad | |
|
5eaf6c221e | |
|
788e09a39a | |
|
fb08f9b198 | |
|
e0b0cdbb87 | |
|
e9035f6d32 | |
|
76fdfa3c0f | |
|
6d8725efb0 | |
|
858d99be33 | |
|
7d6c401dd3 | |
|
0dca65c84d | |
|
185ac5e01e | |
|
c323f49e83 | |
|
27ac44eb2a | |
|
b87fbcbf79 | |
|
7fa109c977 | |
|
a9d28ca96f | |
|
111b4c19bc | |
|
f72cd7ffd2 | |
|
01e3c24793 | |
|
f17d31fd94 | |
|
5926ec8bbb | |
|
ab8a3fab74 | |
|
0f28a69f12 | |
|
2c190d0689 | |
|
71e556e090 | |
|
b0e982d0b5 | |
|
4e46708789 | |
|
7c0b289761 | |
|
26dc407f4a |
1131
.circleci/config.yml
|
@ -0,0 +1,33 @@
|
||||||
|
# gdbpg.py contains scripts to nicely print the postgres datastructures
|
||||||
|
# while in a gdb session. Since the vscode debugger is based on gdb this
|
||||||
|
# actually also works when debugging with vscode. Providing nice tools
|
||||||
|
# to understand the internal datastructures we are working with.
|
||||||
|
source /root/gdbpg.py
|
||||||
|
|
||||||
|
# when debugging postgres it is convenient to _always_ have a breakpoint
|
||||||
|
# trigger when an error is logged. Because .gdbinit is sourced before gdb
|
||||||
|
# is fully attached and has the sources loaded. To make sure the breakpoint
|
||||||
|
# is added when the library is loaded we temporary set the breakpoint pending
|
||||||
|
# to on. After we have added out breakpoint we revert back to the default
|
||||||
|
# configuration for breakpoint pending.
|
||||||
|
# The breakpoint is hard to read, but at entry of the function we don't have
|
||||||
|
# the level loaded in elevel. Instead we hardcode the location where the
|
||||||
|
# level of the current error is stored. Also gdb doesn't understand the
|
||||||
|
# ERROR symbol so we hardcode this to the value of ERROR. It is very unlikely
|
||||||
|
# this value will ever change in postgres, but if it does we might need to
|
||||||
|
# find a way to conditionally load the correct breakpoint.
|
||||||
|
set breakpoint pending on
|
||||||
|
break elog.c:errfinish if errordata[errordata_stack_depth].elevel == 21
|
||||||
|
set breakpoint pending auto
|
||||||
|
|
||||||
|
echo \n
|
||||||
|
echo ----------------------------------------------------------------------------------\n
|
||||||
|
echo when attaching to a postgres backend a breakpoint will be set on elog.c:errfinish \n
|
||||||
|
echo it will only break on errors being raised in postgres \n
|
||||||
|
echo \n
|
||||||
|
echo to disable this breakpoint from vscode run `-exec disable 1` in the debug console \n
|
||||||
|
echo this assumes it's the first breakpoint loaded as it is loaded from .gdbinit \n
|
||||||
|
echo this can be verified with `-exec info break`, enabling can be done with \n
|
||||||
|
echo `-exec enable 1` \n
|
||||||
|
echo ----------------------------------------------------------------------------------\n
|
||||||
|
echo \n
|
|
@ -0,0 +1 @@
|
||||||
|
postgresql-*.tar.bz2
|
|
@ -0,0 +1,7 @@
|
||||||
|
\timing on
|
||||||
|
\pset linestyle unicode
|
||||||
|
\pset border 2
|
||||||
|
\setenv PAGER 'pspg --no-mouse -bX --no-commandbar --no-topbar'
|
||||||
|
\set HISTSIZE 100000
|
||||||
|
\set PROMPT1 '\n%[%033[1m%]%M %n@%/:%> (PID: %p)%R%[%033[0m%]%# '
|
||||||
|
\set PROMPT2 ' '
|
|
@ -0,0 +1,12 @@
|
||||||
|
[[source]]
|
||||||
|
url = "https://pypi.org/simple"
|
||||||
|
verify_ssl = true
|
||||||
|
name = "pypi"
|
||||||
|
|
||||||
|
[packages]
|
||||||
|
docopt = "*"
|
||||||
|
|
||||||
|
[dev-packages]
|
||||||
|
|
||||||
|
[requires]
|
||||||
|
python_version = "3.9"
|
|
@ -0,0 +1,28 @@
|
||||||
|
{
|
||||||
|
"_meta": {
|
||||||
|
"hash": {
|
||||||
|
"sha256": "6956a6700ead5804aa56bd597c93bb4a13f208d2d49d3b5399365fd240ca0797"
|
||||||
|
},
|
||||||
|
"pipfile-spec": 6,
|
||||||
|
"requires": {
|
||||||
|
"python_version": "3.9"
|
||||||
|
},
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"name": "pypi",
|
||||||
|
"url": "https://pypi.org/simple",
|
||||||
|
"verify_ssl": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"docopt": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==0.6.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"develop": {}
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
#! /usr/bin/env pipenv-shebang
|
||||||
|
"""Generate C/C++ properties file for VSCode.
|
||||||
|
|
||||||
|
Uses pgenv to iterate postgres versions and generate
|
||||||
|
a C/C++ properties file for VSCode containing the
|
||||||
|
include paths for the postgres headers.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
generate_c_cpp_properties-json.py <target_path>
|
||||||
|
generate_c_cpp_properties-json.py (-h | --help)
|
||||||
|
generate_c_cpp_properties-json.py --version
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-h --help Show this screen.
|
||||||
|
--version Show version.
|
||||||
|
|
||||||
|
"""
|
||||||
|
import json
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
from docopt import docopt
|
||||||
|
|
||||||
|
|
||||||
|
def main(args):
|
||||||
|
target_path = args['<target_path>']
|
||||||
|
|
||||||
|
output = subprocess.check_output(['pgenv', 'versions'])
|
||||||
|
# typical output is:
|
||||||
|
# 14.8 pgsql-14.8
|
||||||
|
# * 15.3 pgsql-15.3
|
||||||
|
# 16beta2 pgsql-16beta2
|
||||||
|
# where the line marked with a * is the currently active version
|
||||||
|
#
|
||||||
|
# we are only interested in the first word of each line, which is the version number
|
||||||
|
# thus we strip the whitespace and the * from the line and split it into words
|
||||||
|
# and take the first word
|
||||||
|
versions = [line.strip('* ').split()[0] for line in output.decode('utf-8').splitlines()]
|
||||||
|
|
||||||
|
# create the list of configurations per version
|
||||||
|
configurations = []
|
||||||
|
for version in versions:
|
||||||
|
configurations.append(generate_configuration(version))
|
||||||
|
|
||||||
|
# create the json file
|
||||||
|
c_cpp_properties = {
|
||||||
|
"configurations": configurations,
|
||||||
|
"version": 4
|
||||||
|
}
|
||||||
|
|
||||||
|
# write the c_cpp_properties.json file
|
||||||
|
with open(target_path, 'w') as f:
|
||||||
|
json.dump(c_cpp_properties, f, indent=4)
|
||||||
|
|
||||||
|
|
||||||
|
def generate_configuration(version):
|
||||||
|
"""Returns a configuration for the given postgres version.
|
||||||
|
|
||||||
|
>>> generate_configuration('14.8')
|
||||||
|
{
|
||||||
|
"name": "Citus Development Configuration - Postgres 14.8",
|
||||||
|
"includePath": [
|
||||||
|
"/usr/local/include",
|
||||||
|
"/home/citus/.pgenv/src/postgresql-14.8/src/**",
|
||||||
|
"${workspaceFolder}/**",
|
||||||
|
"${workspaceFolder}/src/include/",
|
||||||
|
],
|
||||||
|
"configurationProvider": "ms-vscode.makefile-tools"
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
return {
|
||||||
|
"name": f"Citus Development Configuration - Postgres {version}",
|
||||||
|
"includePath": [
|
||||||
|
"/usr/local/include",
|
||||||
|
f"/home/citus/.pgenv/src/postgresql-{version}/src/**",
|
||||||
|
"${workspaceFolder}/**",
|
||||||
|
"${workspaceFolder}/src/include/",
|
||||||
|
],
|
||||||
|
"configurationProvider": "ms-vscode.makefile-tools"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
arguments = docopt(__doc__, version='0.1.0')
|
||||||
|
main(arguments)
|
|
@ -0,0 +1,40 @@
|
||||||
|
{
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Attach Citus (devcontainer)",
|
||||||
|
"type": "cppdbg",
|
||||||
|
"request": "attach",
|
||||||
|
"processId": "${command:pickProcess}",
|
||||||
|
"program": "/home/citus/.pgenv/pgsql/bin/postgres",
|
||||||
|
"additionalSOLibSearchPath": "/home/citus/.pgenv/pgsql/lib",
|
||||||
|
"setupCommands": [
|
||||||
|
{
|
||||||
|
"text": "handle SIGUSR1 noprint nostop pass",
|
||||||
|
"description": "let gdb not stop when SIGUSR1 is sent to process",
|
||||||
|
"ignoreFailures": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Open core file",
|
||||||
|
"type": "cppdbg",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "/home/citus/.pgenv/pgsql/bin/postgres",
|
||||||
|
"coreDumpPath": "${input:corefile}",
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"MIMode": "gdb",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"id": "corefile",
|
||||||
|
"type": "command",
|
||||||
|
"command": "extension.commandvariable.file.pickFile",
|
||||||
|
"args": {
|
||||||
|
"dialogTitle": "Select core file",
|
||||||
|
"include": "**/core*",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
|
@ -0,0 +1,222 @@
|
||||||
|
FROM ubuntu:22.04 AS base
|
||||||
|
|
||||||
|
# environment is to make python pass an interactive shell, probably not the best timezone given a wide variety of colleagues
|
||||||
|
ENV TZ=UTC
|
||||||
|
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
||||||
|
|
||||||
|
# install build tools
|
||||||
|
RUN apt update && apt install -y \
|
||||||
|
bison \
|
||||||
|
bzip2 \
|
||||||
|
cpanminus \
|
||||||
|
curl \
|
||||||
|
docbook-xml \
|
||||||
|
docbook-xsl \
|
||||||
|
flex \
|
||||||
|
gcc \
|
||||||
|
git \
|
||||||
|
libcurl4-gnutls-dev \
|
||||||
|
libicu-dev \
|
||||||
|
libkrb5-dev \
|
||||||
|
liblz4-dev \
|
||||||
|
libpam0g-dev \
|
||||||
|
libreadline-dev \
|
||||||
|
libselinux1-dev \
|
||||||
|
libssl-dev \
|
||||||
|
libxml2-utils \
|
||||||
|
libxslt-dev \
|
||||||
|
libzstd-dev \
|
||||||
|
locales \
|
||||||
|
make \
|
||||||
|
perl \
|
||||||
|
pkg-config \
|
||||||
|
python3 \
|
||||||
|
python3-pip \
|
||||||
|
software-properties-common \
|
||||||
|
sudo \
|
||||||
|
uuid-dev \
|
||||||
|
valgrind \
|
||||||
|
xsltproc \
|
||||||
|
zlib1g-dev \
|
||||||
|
&& add-apt-repository ppa:deadsnakes/ppa -y \
|
||||||
|
&& apt install -y \
|
||||||
|
python3.9-full \
|
||||||
|
# software properties pulls in pkexec, which makes the debugger unusable in vscode
|
||||||
|
&& apt purge -y \
|
||||||
|
software-properties-common \
|
||||||
|
&& apt autoremove -y \
|
||||||
|
&& apt clean
|
||||||
|
|
||||||
|
RUN sudo pip3 install pipenv pipenv-shebang
|
||||||
|
|
||||||
|
RUN cpanm install IPC::Run
|
||||||
|
|
||||||
|
RUN locale-gen en_US.UTF-8
|
||||||
|
|
||||||
|
# add the citus user to sudoers and allow all sudoers to login without a password prompt
|
||||||
|
RUN useradd -ms /bin/bash citus \
|
||||||
|
&& usermod -aG sudo citus \
|
||||||
|
&& echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
|
||||||
|
|
||||||
|
WORKDIR /home/citus
|
||||||
|
USER citus
|
||||||
|
|
||||||
|
# run all make commands with the number of cores available
|
||||||
|
RUN echo "export MAKEFLAGS=\"-j \$(nproc)\"" >> "/home/citus/.bashrc"
|
||||||
|
|
||||||
|
RUN git clone --branch v1.3.2 --depth 1 https://github.com/theory/pgenv.git .pgenv
|
||||||
|
COPY --chown=citus:citus pgenv/config/ .pgenv/config/
|
||||||
|
ENV PATH="/home/citus/.pgenv/bin:${PATH}"
|
||||||
|
ENV PATH="/home/citus/.pgenv/pgsql/bin:${PATH}"
|
||||||
|
|
||||||
|
USER citus
|
||||||
|
|
||||||
|
# build postgres versions separately for effective parrallelism and caching of already built versions when changing only certain versions
|
||||||
|
FROM base AS pg15
|
||||||
|
RUN MAKEFLAGS="-j $(nproc)" pgenv build 15.13
|
||||||
|
RUN rm .pgenv/src/*.tar*
|
||||||
|
RUN make -C .pgenv/src/postgresql-*/ clean
|
||||||
|
RUN make -C .pgenv/src/postgresql-*/src/include install
|
||||||
|
|
||||||
|
# create a staging directory with all files we want to copy from our pgenv build
|
||||||
|
# we will copy the contents of the staged folder into the final image at once
|
||||||
|
RUN mkdir .pgenv-staging/
|
||||||
|
RUN cp -r .pgenv/src .pgenv/pgsql-* .pgenv/config .pgenv-staging/
|
||||||
|
RUN rm .pgenv-staging/config/default.conf
|
||||||
|
|
||||||
|
FROM base AS pg16
|
||||||
|
RUN MAKEFLAGS="-j $(nproc)" pgenv build 16.9
|
||||||
|
RUN rm .pgenv/src/*.tar*
|
||||||
|
RUN make -C .pgenv/src/postgresql-*/ clean
|
||||||
|
RUN make -C .pgenv/src/postgresql-*/src/include install
|
||||||
|
|
||||||
|
# create a staging directory with all files we want to copy from our pgenv build
|
||||||
|
# we will copy the contents of the staged folder into the final image at once
|
||||||
|
RUN mkdir .pgenv-staging/
|
||||||
|
RUN cp -r .pgenv/src .pgenv/pgsql-* .pgenv/config .pgenv-staging/
|
||||||
|
RUN rm .pgenv-staging/config/default.conf
|
||||||
|
|
||||||
|
FROM base AS pg17
|
||||||
|
RUN MAKEFLAGS="-j $(nproc)" pgenv build 17.5
|
||||||
|
RUN rm .pgenv/src/*.tar*
|
||||||
|
RUN make -C .pgenv/src/postgresql-*/ clean
|
||||||
|
RUN make -C .pgenv/src/postgresql-*/src/include install
|
||||||
|
|
||||||
|
# create a staging directory with all files we want to copy from our pgenv build
|
||||||
|
# we will copy the contents of the staged folder into the final image at once
|
||||||
|
RUN mkdir .pgenv-staging/
|
||||||
|
RUN cp -r .pgenv/src .pgenv/pgsql-* .pgenv/config .pgenv-staging/
|
||||||
|
RUN rm .pgenv-staging/config/default.conf
|
||||||
|
|
||||||
|
FROM base AS uncrustify-builder
|
||||||
|
|
||||||
|
RUN sudo apt update && sudo apt install -y cmake tree
|
||||||
|
|
||||||
|
WORKDIR /uncrustify
|
||||||
|
RUN curl -L https://github.com/uncrustify/uncrustify/archive/uncrustify-0.68.1.tar.gz | tar xz
|
||||||
|
WORKDIR /uncrustify/uncrustify-uncrustify-0.68.1/
|
||||||
|
RUN mkdir build
|
||||||
|
WORKDIR /uncrustify/uncrustify-uncrustify-0.68.1/build/
|
||||||
|
RUN cmake ..
|
||||||
|
RUN MAKEFLAGS="-j $(nproc)" make -s
|
||||||
|
|
||||||
|
RUN make install DESTDIR=/uncrustify
|
||||||
|
|
||||||
|
# builder for all pipenv's to get them contained in a single layer
|
||||||
|
FROM base AS pipenv
|
||||||
|
|
||||||
|
WORKDIR /workspaces/citus/
|
||||||
|
|
||||||
|
# tools to sync pgenv with vscode
|
||||||
|
COPY --chown=citus:citus .vscode/Pipfile .vscode/Pipfile.lock .devcontainer/.vscode/
|
||||||
|
RUN ( cd .devcontainer/.vscode && pipenv install )
|
||||||
|
|
||||||
|
# environment to run our failure tests
|
||||||
|
COPY --chown=citus:citus src/ src/
|
||||||
|
RUN ( cd src/test/regress && pipenv install )
|
||||||
|
|
||||||
|
# assemble the final container by copying over the artifacts from separately build containers
|
||||||
|
FROM base AS devcontainer
|
||||||
|
|
||||||
|
LABEL org.opencontainers.image.source=https://github.com/citusdata/citus
|
||||||
|
LABEL org.opencontainers.image.description="Development container for the Citus project"
|
||||||
|
LABEL org.opencontainers.image.licenses=AGPL-3.0-only
|
||||||
|
|
||||||
|
RUN yes | sudo unminimize
|
||||||
|
|
||||||
|
# install developer productivity tools
|
||||||
|
RUN sudo apt update \
|
||||||
|
&& sudo apt install -y \
|
||||||
|
autoconf2.69 \
|
||||||
|
bash-completion \
|
||||||
|
fswatch \
|
||||||
|
gdb \
|
||||||
|
htop \
|
||||||
|
libdbd-pg-perl \
|
||||||
|
libdbi-perl \
|
||||||
|
lsof \
|
||||||
|
man \
|
||||||
|
net-tools \
|
||||||
|
psmisc \
|
||||||
|
pspg \
|
||||||
|
tree \
|
||||||
|
vim \
|
||||||
|
&& sudo apt clean
|
||||||
|
|
||||||
|
# Since gdb will run in the context of the root user when debugging citus we will need to both
|
||||||
|
# download the gdbpg.py script as the root user, into their home directory, as well as add .gdbinit
|
||||||
|
# as a file owned by root
|
||||||
|
# This will make that as soon as the debugger attaches to a postgres backend (or frankly any other process)
|
||||||
|
# the gdbpg.py script will be sourced and the developer can direcly use it.
|
||||||
|
RUN sudo curl -o /root/gdbpg.py https://raw.githubusercontent.com/tvesely/gdbpg/6065eee7872457785f830925eac665aa535caf62/gdbpg.py
|
||||||
|
COPY --chown=root:root .gdbinit /root/
|
||||||
|
|
||||||
|
# install developer dependencies in the global environment
|
||||||
|
RUN --mount=type=bind,source=requirements.txt,target=requirements.txt pip install -r requirements.txt
|
||||||
|
|
||||||
|
# for persistent bash history across devcontainers we need to have
|
||||||
|
# a) a directory to store the history in
|
||||||
|
# b) a prompt command to append the history to the file
|
||||||
|
# c) specify the history file to store the history in
|
||||||
|
# b and c are done in the .bashrc to make it persistent across shells only
|
||||||
|
RUN sudo install -d -o citus -g citus /commandhistory \
|
||||||
|
&& echo "export PROMPT_COMMAND='history -a' && export HISTFILE=/commandhistory/.bash_history" >> "/home/citus/.bashrc"
|
||||||
|
|
||||||
|
# install citus-dev
|
||||||
|
RUN git clone --branch develop https://github.com/citusdata/tools.git citus-tools \
|
||||||
|
&& ( cd citus-tools/citus_dev && pipenv install ) \
|
||||||
|
&& mkdir -p ~/.local/bin \
|
||||||
|
&& ln -s /home/citus/citus-tools/citus_dev/citus_dev-pipenv .local/bin/citus_dev \
|
||||||
|
&& sudo make -C citus-tools/uncrustify install bindir=/usr/local/bin pkgsysconfdir=/usr/local/etc/ \
|
||||||
|
&& mkdir -p ~/.local/share/bash-completion/completions/ \
|
||||||
|
&& ln -s ~/citus-tools/citus_dev/bash_completion ~/.local/share/bash-completion/completions/citus_dev
|
||||||
|
|
||||||
|
# TODO some LC_ALL errors, possibly solved by locale-gen
|
||||||
|
RUN git clone https://github.com/so-fancy/diff-so-fancy.git \
|
||||||
|
&& mkdir -p ~/.local/bin \
|
||||||
|
&& ln -s /home/citus/diff-so-fancy/diff-so-fancy .local/bin/
|
||||||
|
|
||||||
|
COPY --link --from=uncrustify-builder /uncrustify/usr/ /usr/
|
||||||
|
|
||||||
|
COPY --link --from=pg15 /home/citus/.pgenv-staging/ /home/citus/.pgenv/
|
||||||
|
COPY --link --from=pg16 /home/citus/.pgenv-staging/ /home/citus/.pgenv/
|
||||||
|
COPY --link --from=pg17 /home/citus/.pgenv-staging/ /home/citus/.pgenv/
|
||||||
|
|
||||||
|
COPY --link --from=pipenv /home/citus/.local/share/virtualenvs/ /home/citus/.local/share/virtualenvs/
|
||||||
|
|
||||||
|
# place to run your cluster with citus_dev
|
||||||
|
VOLUME /data
|
||||||
|
RUN sudo mkdir /data \
|
||||||
|
&& sudo chown citus:citus /data
|
||||||
|
|
||||||
|
COPY --chown=citus:citus .psqlrc .
|
||||||
|
|
||||||
|
# with the copy linking of layers github actions seem to misbehave with the ownership of the
|
||||||
|
# directories leading upto the link, hence a small patch layer to have to right ownerships set
|
||||||
|
RUN sudo chown --from=root:root citus:citus -R ~
|
||||||
|
|
||||||
|
# sets default pg version
|
||||||
|
RUN pgenv switch 17.5
|
||||||
|
|
||||||
|
# make connecting to the coordinator easy
|
||||||
|
ENV PGPORT=9700
|
|
@ -0,0 +1,11 @@
|
||||||
|
|
||||||
|
init: ../.vscode/c_cpp_properties.json ../.vscode/launch.json
|
||||||
|
|
||||||
|
../.vscode:
|
||||||
|
mkdir -p ../.vscode
|
||||||
|
|
||||||
|
../.vscode/launch.json: ../.vscode .vscode/launch.json
|
||||||
|
cp .vscode/launch.json ../.vscode/launch.json
|
||||||
|
|
||||||
|
../.vscode/c_cpp_properties.json: ../.vscode
|
||||||
|
./.vscode/generate_c_cpp_properties-json.py ../.vscode/c_cpp_properties.json
|
|
@ -0,0 +1,37 @@
|
||||||
|
{
|
||||||
|
"image": "ghcr.io/citusdata/citus-devcontainer:main",
|
||||||
|
"runArgs": [
|
||||||
|
"--cap-add=SYS_PTRACE",
|
||||||
|
"--ulimit=core=-1",
|
||||||
|
],
|
||||||
|
"forwardPorts": [
|
||||||
|
9700
|
||||||
|
],
|
||||||
|
"customizations": {
|
||||||
|
"vscode": {
|
||||||
|
"extensions": [
|
||||||
|
"eamodio.gitlens",
|
||||||
|
"GitHub.copilot-chat",
|
||||||
|
"GitHub.copilot",
|
||||||
|
"github.vscode-github-actions",
|
||||||
|
"github.vscode-pull-request-github",
|
||||||
|
"ms-vscode.cpptools-extension-pack",
|
||||||
|
"ms-vsliveshare.vsliveshare",
|
||||||
|
"rioj7.command-variable",
|
||||||
|
],
|
||||||
|
"settings": {
|
||||||
|
"files.exclude": {
|
||||||
|
"**/*.o": true,
|
||||||
|
"**/.deps/": true,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mounts": [
|
||||||
|
"type=volume,target=/data",
|
||||||
|
"source=citus-bashhistory,target=/commandhistory,type=volume",
|
||||||
|
],
|
||||||
|
"updateContentCommand": "./configure",
|
||||||
|
"postCreateCommand": "make -C .devcontainer/",
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
PGENV_MAKE_OPTIONS=(-s)
|
||||||
|
|
||||||
|
PGENV_CONFIGURE_OPTIONS=(
|
||||||
|
--enable-debug
|
||||||
|
--enable-depend
|
||||||
|
--enable-cassert
|
||||||
|
--enable-tap-tests
|
||||||
|
'CFLAGS=-ggdb -Og -g3 -fno-omit-frame-pointer -DUSE_VALGRIND'
|
||||||
|
--with-openssl
|
||||||
|
--with-libxml
|
||||||
|
--with-libxslt
|
||||||
|
--with-uuid=e2fs
|
||||||
|
--with-icu
|
||||||
|
--with-lz4
|
||||||
|
)
|
|
@ -0,0 +1,9 @@
|
||||||
|
black==23.11.0
|
||||||
|
click==8.1.7
|
||||||
|
isort==5.12.0
|
||||||
|
mypy-extensions==1.0.0
|
||||||
|
packaging==23.2
|
||||||
|
pathspec==0.11.2
|
||||||
|
platformdirs==4.0.0
|
||||||
|
tomli==2.0.1
|
||||||
|
typing_extensions==4.8.0
|
|
@ -0,0 +1,28 @@
|
||||||
|
[[source]]
|
||||||
|
name = "pypi"
|
||||||
|
url = "https://pypi.python.org/simple"
|
||||||
|
verify_ssl = true
|
||||||
|
|
||||||
|
[packages]
|
||||||
|
mitmproxy = {editable = true, ref = "main", git = "https://github.com/citusdata/mitmproxy.git"}
|
||||||
|
construct = "*"
|
||||||
|
docopt = "==0.6.2"
|
||||||
|
cryptography = ">=41.0.4"
|
||||||
|
pytest = "*"
|
||||||
|
psycopg = "*"
|
||||||
|
filelock = "*"
|
||||||
|
pytest-asyncio = "*"
|
||||||
|
pytest-timeout = "*"
|
||||||
|
pytest-xdist = "*"
|
||||||
|
pytest-repeat = "*"
|
||||||
|
pyyaml = "*"
|
||||||
|
werkzeug = "==2.3.7"
|
||||||
|
|
||||||
|
[dev-packages]
|
||||||
|
black = "*"
|
||||||
|
isort = "*"
|
||||||
|
flake8 = "*"
|
||||||
|
flake8-bugbear = "*"
|
||||||
|
|
||||||
|
[requires]
|
||||||
|
python_version = "3.9"
|
|
@ -25,10 +25,9 @@ configure -whitespace
|
||||||
|
|
||||||
# except these exceptions...
|
# except these exceptions...
|
||||||
src/backend/distributed/utils/citus_outfuncs.c -citus-style
|
src/backend/distributed/utils/citus_outfuncs.c -citus-style
|
||||||
src/backend/distributed/deparser/ruleutils_13.c -citus-style
|
|
||||||
src/backend/distributed/deparser/ruleutils_14.c -citus-style
|
|
||||||
src/backend/distributed/deparser/ruleutils_15.c -citus-style
|
src/backend/distributed/deparser/ruleutils_15.c -citus-style
|
||||||
src/backend/distributed/deparser/ruleutils_16.c -citus-style
|
src/backend/distributed/deparser/ruleutils_16.c -citus-style
|
||||||
|
src/backend/distributed/deparser/ruleutils_17.c -citus-style
|
||||||
src/backend/distributed/commands/index_pg_source.c -citus-style
|
src/backend/distributed/commands/index_pg_source.c -citus-style
|
||||||
|
|
||||||
src/include/distributed/citus_nodes.h -citus-style
|
src/include/distributed/citus_nodes.h -citus-style
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
name: 'Parallelization matrix'
|
||||||
|
inputs:
|
||||||
|
count:
|
||||||
|
required: false
|
||||||
|
default: 32
|
||||||
|
outputs:
|
||||||
|
json:
|
||||||
|
value: ${{ steps.generate_matrix.outputs.json }}
|
||||||
|
runs:
|
||||||
|
using: "composite"
|
||||||
|
steps:
|
||||||
|
- name: Generate parallelization matrix
|
||||||
|
id: generate_matrix
|
||||||
|
shell: bash
|
||||||
|
run: |-
|
||||||
|
json_array="{\"include\": ["
|
||||||
|
for ((i = 1; i <= ${{ inputs.count }}; i++)); do
|
||||||
|
json_array+="{\"id\":\"$i\"},"
|
||||||
|
done
|
||||||
|
json_array=${json_array%,}
|
||||||
|
json_array+=" ]}"
|
||||||
|
echo "json=$json_array" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "json=$json_array"
|
|
@ -0,0 +1,38 @@
|
||||||
|
name: save_logs_and_results
|
||||||
|
inputs:
|
||||||
|
folder:
|
||||||
|
required: false
|
||||||
|
default: "log"
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- uses: actions/upload-artifact@v4.6.0
|
||||||
|
name: Upload logs
|
||||||
|
with:
|
||||||
|
name: ${{ inputs.folder }}
|
||||||
|
if-no-files-found: ignore
|
||||||
|
path: |
|
||||||
|
src/test/**/proxy.output
|
||||||
|
src/test/**/results/
|
||||||
|
src/test/**/tmp_check/master/log
|
||||||
|
src/test/**/tmp_check/worker.57638/log
|
||||||
|
src/test/**/tmp_check/worker.57637/log
|
||||||
|
src/test/**/*.diffs
|
||||||
|
src/test/**/out/ddls.sql
|
||||||
|
src/test/**/out/queries.sql
|
||||||
|
src/test/**/logfile_*
|
||||||
|
/tmp/pg_upgrade_newData_logs
|
||||||
|
- name: Publish regression.diffs
|
||||||
|
run: |-
|
||||||
|
diffs="$(find src/test/regress -name "*.diffs" -exec cat {} \;)"
|
||||||
|
if ! [ -z "$diffs" ]; then
|
||||||
|
echo '```diff' >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo -E "$diffs" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo '```' >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo -E $diffs
|
||||||
|
fi
|
||||||
|
shell: bash
|
||||||
|
- name: Print stack traces
|
||||||
|
run: "./ci/print_stack_trace.sh"
|
||||||
|
if: failure()
|
||||||
|
shell: bash
|
|
@ -0,0 +1,35 @@
|
||||||
|
name: setup_extension
|
||||||
|
inputs:
|
||||||
|
pg_major:
|
||||||
|
required: false
|
||||||
|
skip_installation:
|
||||||
|
required: false
|
||||||
|
default: false
|
||||||
|
type: boolean
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- name: Expose $PG_MAJOR to Github Env
|
||||||
|
run: |-
|
||||||
|
if [ -z "${{ inputs.pg_major }}" ]; then
|
||||||
|
echo "PG_MAJOR=${PG_MAJOR}" >> $GITHUB_ENV
|
||||||
|
else
|
||||||
|
echo "PG_MAJOR=${{ inputs.pg_major }}" >> $GITHUB_ENV
|
||||||
|
fi
|
||||||
|
shell: bash
|
||||||
|
- uses: actions/download-artifact@v4.1.8
|
||||||
|
with:
|
||||||
|
name: build-${{ env.PG_MAJOR }}
|
||||||
|
- name: Install Extension
|
||||||
|
if: ${{ inputs.skip_installation == 'false' }}
|
||||||
|
run: tar xfv "install-$PG_MAJOR.tar" --directory /
|
||||||
|
shell: bash
|
||||||
|
- name: Configure
|
||||||
|
run: |-
|
||||||
|
chown -R circleci .
|
||||||
|
git config --global --add safe.directory ${GITHUB_WORKSPACE}
|
||||||
|
gosu circleci ./configure --without-pg-version-check
|
||||||
|
shell: bash
|
||||||
|
- name: Enable core dumps
|
||||||
|
run: ulimit -c unlimited
|
||||||
|
shell: bash
|
|
@ -0,0 +1,27 @@
|
||||||
|
name: coverage
|
||||||
|
inputs:
|
||||||
|
flags:
|
||||||
|
required: false
|
||||||
|
codecov_token:
|
||||||
|
required: true
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- uses: codecov/codecov-action@v3
|
||||||
|
with:
|
||||||
|
flags: ${{ inputs.flags }}
|
||||||
|
token: ${{ inputs.codecov_token }}
|
||||||
|
verbose: true
|
||||||
|
gcov: true
|
||||||
|
- name: Create codeclimate coverage
|
||||||
|
run: |-
|
||||||
|
lcov --directory . --capture --output-file lcov.info
|
||||||
|
lcov --remove lcov.info -o lcov.info '/usr/*'
|
||||||
|
sed "s=^SF:$PWD/=SF:=g" -i lcov.info # relative pats are required by codeclimate
|
||||||
|
mkdir -p /tmp/codeclimate
|
||||||
|
cc-test-reporter format-coverage -t lcov -o /tmp/codeclimate/${{ inputs.flags }}.json lcov.info
|
||||||
|
shell: bash
|
||||||
|
- uses: actions/upload-artifact@v4.6.0
|
||||||
|
with:
|
||||||
|
path: "/tmp/codeclimate/*.json"
|
||||||
|
name: codeclimate-${{ inputs.flags }}
|
|
@ -32,7 +32,10 @@ python3 -m pip install -r tools/packaging_automation/requirements.txt
|
||||||
echo "Package type: ${package_type}"
|
echo "Package type: ${package_type}"
|
||||||
echo "OS version: $(get_rpm_os_version)"
|
echo "OS version: $(get_rpm_os_version)"
|
||||||
|
|
||||||
# if os version is centos 7 or oracle linux 7, then remove urllib3 with pip uninstall and install urllib3<2.0.0 with pip install
|
# For RHEL 7, we need to install urllib3<2 due to below execution error
|
||||||
|
# ImportError: urllib3 v2.0 only supports OpenSSL 1.1.1+, currently the 'ssl'
|
||||||
|
# module is compiled with 'OpenSSL 1.0.2k-fips 26 Jan 2017'.
|
||||||
|
# See: https://github.com/urllib3/urllib3/issues/2168
|
||||||
if [[ ${package_type} == "rpm" && $(get_rpm_os_version) == 7* ]]; then
|
if [[ ${package_type} == "rpm" && $(get_rpm_os_version) == 7* ]]; then
|
||||||
python3 -m pip uninstall -y urllib3
|
python3 -m pip uninstall -y urllib3
|
||||||
python3 -m pip install 'urllib3<2'
|
python3 -m pip install 'urllib3<2'
|
||||||
|
|
|
@ -0,0 +1,545 @@
|
||||||
|
name: Build & Test
|
||||||
|
run-name: Build & Test - ${{ github.event.pull_request.title || github.ref_name }}
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
skip_test_flakyness:
|
||||||
|
required: false
|
||||||
|
default: false
|
||||||
|
type: boolean
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- "main"
|
||||||
|
- "release-*"
|
||||||
|
pull_request:
|
||||||
|
types: [opened, reopened,synchronize]
|
||||||
|
merge_group:
|
||||||
|
jobs:
|
||||||
|
# Since GHA does not interpolate env varibles in matrix context, we need to
|
||||||
|
# define them in a separate job and use them in other jobs.
|
||||||
|
params:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
name: Initialize parameters
|
||||||
|
outputs:
|
||||||
|
build_image_name: "ghcr.io/citusdata/extbuilder"
|
||||||
|
test_image_name: "ghcr.io/citusdata/exttester"
|
||||||
|
citusupgrade_image_name: "ghcr.io/citusdata/citusupgradetester"
|
||||||
|
fail_test_image_name: "ghcr.io/citusdata/failtester"
|
||||||
|
pgupgrade_image_name: "ghcr.io/citusdata/pgupgradetester"
|
||||||
|
style_checker_image_name: "ghcr.io/citusdata/stylechecker"
|
||||||
|
style_checker_tools_version: "0.8.18"
|
||||||
|
sql_snapshot_pg_version: "17.5"
|
||||||
|
image_suffix: "-dev-d28f316"
|
||||||
|
pg15_version: '{ "major": "15", "full": "15.13" }'
|
||||||
|
pg16_version: '{ "major": "16", "full": "16.9" }'
|
||||||
|
pg17_version: '{ "major": "17", "full": "17.5" }'
|
||||||
|
upgrade_pg_versions: "15.13-16.9-17.5"
|
||||||
|
steps:
|
||||||
|
# Since GHA jobs need at least one step we use a noop step here.
|
||||||
|
- name: Set up parameters
|
||||||
|
run: echo 'noop'
|
||||||
|
check-sql-snapshots:
|
||||||
|
needs: params
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: ${{ needs.params.outputs.build_image_name }}:${{ needs.params.outputs.sql_snapshot_pg_version }}${{ needs.params.outputs.image_suffix }}
|
||||||
|
options: --user root
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Check Snapshots
|
||||||
|
run: |
|
||||||
|
git config --global --add safe.directory ${GITHUB_WORKSPACE}
|
||||||
|
ci/check_sql_snapshots.sh
|
||||||
|
check-style:
|
||||||
|
needs: params
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: ${{ needs.params.outputs.style_checker_image_name }}:${{ needs.params.outputs.style_checker_tools_version }}${{ needs.params.outputs.image_suffix }}
|
||||||
|
steps:
|
||||||
|
- name: Check Snapshots
|
||||||
|
run: |
|
||||||
|
git config --global --add safe.directory ${GITHUB_WORKSPACE}
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Check C Style
|
||||||
|
run: citus_indent --check
|
||||||
|
- name: Check Python style
|
||||||
|
run: black --check .
|
||||||
|
- name: Check Python import order
|
||||||
|
run: isort --check .
|
||||||
|
- name: Check Python lints
|
||||||
|
run: flake8 .
|
||||||
|
- name: Fix whitespace
|
||||||
|
run: ci/editorconfig.sh && git diff --exit-code
|
||||||
|
- name: Remove useless declarations
|
||||||
|
run: ci/remove_useless_declarations.sh && git diff --cached --exit-code
|
||||||
|
- name: Sort and group includes
|
||||||
|
run: ci/sort_and_group_includes.sh && git diff --exit-code
|
||||||
|
- name: Normalize test output
|
||||||
|
run: ci/normalize_expected.sh && git diff --exit-code
|
||||||
|
- name: Check for C-style comments in migration files
|
||||||
|
run: ci/disallow_c_comments_in_migrations.sh && git diff --exit-code
|
||||||
|
- name: 'Check for comment--cached ns that start with # character in spec files'
|
||||||
|
run: ci/disallow_hash_comments_in_spec_files.sh && git diff --exit-code
|
||||||
|
- name: Check for gitignore entries .for source files
|
||||||
|
run: ci/fix_gitignore.sh && git diff --exit-code
|
||||||
|
- name: Check for lengths of changelog entries
|
||||||
|
run: ci/disallow_long_changelog_entries.sh
|
||||||
|
- name: Check for banned C API usage
|
||||||
|
run: ci/banned.h.sh
|
||||||
|
- name: Check for tests missing in schedules
|
||||||
|
run: ci/check_all_tests_are_run.sh
|
||||||
|
- name: Check if all CI scripts are actually run
|
||||||
|
run: ci/check_all_ci_scripts_are_run.sh
|
||||||
|
- name: Check if all GUCs are sorted alphabetically
|
||||||
|
run: ci/check_gucs_are_alphabetically_sorted.sh
|
||||||
|
- name: Check for missing downgrade scripts
|
||||||
|
run: ci/check_migration_files.sh
|
||||||
|
build:
|
||||||
|
needs: params
|
||||||
|
name: Build for PG${{ fromJson(matrix.pg_version).major }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
image_name:
|
||||||
|
- ${{ needs.params.outputs.build_image_name }}
|
||||||
|
image_suffix:
|
||||||
|
- ${{ needs.params.outputs.image_suffix}}
|
||||||
|
pg_version:
|
||||||
|
- ${{ needs.params.outputs.pg15_version }}
|
||||||
|
- ${{ needs.params.outputs.pg16_version }}
|
||||||
|
- ${{ needs.params.outputs.pg17_version }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: "${{ matrix.image_name }}:${{ fromJson(matrix.pg_version).full }}${{ matrix.image_suffix }}"
|
||||||
|
options: --user root
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Expose $PG_MAJOR to Github Env
|
||||||
|
run: echo "PG_MAJOR=${PG_MAJOR}" >> $GITHUB_ENV
|
||||||
|
shell: bash
|
||||||
|
- name: Build
|
||||||
|
run: "./ci/build-citus.sh"
|
||||||
|
shell: bash
|
||||||
|
- uses: actions/upload-artifact@v4.6.0
|
||||||
|
with:
|
||||||
|
name: build-${{ env.PG_MAJOR }}
|
||||||
|
path: |-
|
||||||
|
./build-${{ env.PG_MAJOR }}/*
|
||||||
|
./install-${{ env.PG_MAJOR }}.tar
|
||||||
|
test-citus:
|
||||||
|
name: PG${{ fromJson(matrix.pg_version).major }} - ${{ matrix.make }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
suite:
|
||||||
|
- regress
|
||||||
|
image_name:
|
||||||
|
- ${{ needs.params.outputs.test_image_name }}
|
||||||
|
pg_version:
|
||||||
|
- ${{ needs.params.outputs.pg15_version }}
|
||||||
|
- ${{ needs.params.outputs.pg16_version }}
|
||||||
|
- ${{ needs.params.outputs.pg17_version }}
|
||||||
|
make:
|
||||||
|
- check-split
|
||||||
|
- check-multi
|
||||||
|
- check-multi-1
|
||||||
|
- check-multi-mx
|
||||||
|
- check-vanilla
|
||||||
|
- check-isolation
|
||||||
|
- check-operations
|
||||||
|
- check-follower-cluster
|
||||||
|
- check-columnar
|
||||||
|
- check-columnar-isolation
|
||||||
|
- check-enterprise
|
||||||
|
- check-enterprise-isolation
|
||||||
|
- check-enterprise-isolation-logicalrep-1
|
||||||
|
- check-enterprise-isolation-logicalrep-2
|
||||||
|
- check-enterprise-isolation-logicalrep-3
|
||||||
|
include:
|
||||||
|
- make: check-failure
|
||||||
|
pg_version: ${{ needs.params.outputs.pg15_version }}
|
||||||
|
suite: regress
|
||||||
|
image_name: ${{ needs.params.outputs.fail_test_image_name }}
|
||||||
|
- make: check-failure
|
||||||
|
pg_version: ${{ needs.params.outputs.pg16_version }}
|
||||||
|
suite: regress
|
||||||
|
image_name: ${{ needs.params.outputs.fail_test_image_name }}
|
||||||
|
- make: check-failure
|
||||||
|
pg_version: ${{ needs.params.outputs.pg17_version }}
|
||||||
|
suite: regress
|
||||||
|
image_name: ${{ needs.params.outputs.fail_test_image_name }}
|
||||||
|
- make: check-enterprise-failure
|
||||||
|
pg_version: ${{ needs.params.outputs.pg15_version }}
|
||||||
|
suite: regress
|
||||||
|
image_name: ${{ needs.params.outputs.fail_test_image_name }}
|
||||||
|
- make: check-enterprise-failure
|
||||||
|
pg_version: ${{ needs.params.outputs.pg16_version }}
|
||||||
|
suite: regress
|
||||||
|
image_name: ${{ needs.params.outputs.fail_test_image_name }}
|
||||||
|
- make: check-enterprise-failure
|
||||||
|
pg_version: ${{ needs.params.outputs.pg17_version }}
|
||||||
|
suite: regress
|
||||||
|
image_name: ${{ needs.params.outputs.fail_test_image_name }}
|
||||||
|
- make: check-pytest
|
||||||
|
pg_version: ${{ needs.params.outputs.pg15_version }}
|
||||||
|
suite: regress
|
||||||
|
image_name: ${{ needs.params.outputs.fail_test_image_name }}
|
||||||
|
- make: check-pytest
|
||||||
|
pg_version: ${{ needs.params.outputs.pg16_version }}
|
||||||
|
suite: regress
|
||||||
|
image_name: ${{ needs.params.outputs.fail_test_image_name }}
|
||||||
|
- make: check-pytest
|
||||||
|
pg_version: ${{ needs.params.outputs.pg17_version }}
|
||||||
|
suite: regress
|
||||||
|
image_name: ${{ needs.params.outputs.fail_test_image_name }}
|
||||||
|
- make: installcheck
|
||||||
|
suite: cdc
|
||||||
|
image_name: ${{ needs.params.outputs.test_image_name }}
|
||||||
|
pg_version: ${{ needs.params.outputs.pg15_version }}
|
||||||
|
- make: installcheck
|
||||||
|
suite: cdc
|
||||||
|
image_name: ${{ needs.params.outputs.test_image_name }}
|
||||||
|
pg_version: ${{ needs.params.outputs.pg16_version }}
|
||||||
|
- make: installcheck
|
||||||
|
suite: cdc
|
||||||
|
image_name: ${{ needs.params.outputs.test_image_name }}
|
||||||
|
pg_version: ${{ needs.params.outputs.pg17_version }}
|
||||||
|
- make: check-query-generator
|
||||||
|
pg_version: ${{ needs.params.outputs.pg15_version }}
|
||||||
|
suite: regress
|
||||||
|
image_name: ${{ needs.params.outputs.fail_test_image_name }}
|
||||||
|
- make: check-query-generator
|
||||||
|
pg_version: ${{ needs.params.outputs.pg16_version }}
|
||||||
|
suite: regress
|
||||||
|
image_name: ${{ needs.params.outputs.fail_test_image_name }}
|
||||||
|
- make: check-query-generator
|
||||||
|
pg_version: ${{ needs.params.outputs.pg17_version }}
|
||||||
|
suite: regress
|
||||||
|
image_name: ${{ needs.params.outputs.fail_test_image_name }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: "${{ matrix.image_name }}:${{ fromJson(matrix.pg_version).full }}${{ needs.params.outputs.image_suffix }}"
|
||||||
|
options: --user root --dns=8.8.8.8
|
||||||
|
# Due to Github creates a default network for each job, we need to use
|
||||||
|
# --dns= to have similar DNS settings as our other CI systems or local
|
||||||
|
# machines. Otherwise, we may see different results.
|
||||||
|
needs:
|
||||||
|
- params
|
||||||
|
- build
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: "./.github/actions/setup_extension"
|
||||||
|
- name: Run Test
|
||||||
|
run: gosu circleci make -C src/test/${{ matrix.suite }} ${{ matrix.make }}
|
||||||
|
timeout-minutes: 20
|
||||||
|
- uses: "./.github/actions/save_logs_and_results"
|
||||||
|
if: always()
|
||||||
|
with:
|
||||||
|
folder: ${{ fromJson(matrix.pg_version).major }}_${{ matrix.make }}
|
||||||
|
- uses: "./.github/actions/upload_coverage"
|
||||||
|
if: always()
|
||||||
|
with:
|
||||||
|
flags: ${{ env.PG_MAJOR }}_${{ matrix.suite }}_${{ matrix.make }}
|
||||||
|
codecov_token: ${{ secrets.CODECOV_TOKEN }}
|
||||||
|
test-arbitrary-configs:
|
||||||
|
name: PG${{ fromJson(matrix.pg_version).major }} - check-arbitrary-configs-${{ matrix.parallel }}
|
||||||
|
runs-on: ["self-hosted", "1ES.Pool=1es-gha-citusdata-pool"]
|
||||||
|
container:
|
||||||
|
image: "${{ matrix.image_name }}:${{ fromJson(matrix.pg_version).full }}${{ needs.params.outputs.image_suffix }}"
|
||||||
|
options: --user root
|
||||||
|
needs:
|
||||||
|
- params
|
||||||
|
- build
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
image_name:
|
||||||
|
- ${{ needs.params.outputs.fail_test_image_name }}
|
||||||
|
pg_version:
|
||||||
|
- ${{ needs.params.outputs.pg15_version }}
|
||||||
|
- ${{ needs.params.outputs.pg16_version }}
|
||||||
|
- ${{ needs.params.outputs.pg17_version }}
|
||||||
|
parallel: [0,1,2,3,4,5] # workaround for running 6 parallel jobs
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: "./.github/actions/setup_extension"
|
||||||
|
- name: Test arbitrary configs
|
||||||
|
run: |-
|
||||||
|
# we use parallel jobs to split the tests into 6 parts and run them in parallel
|
||||||
|
# the script below extracts the tests for the current job
|
||||||
|
N=6 # Total number of jobs (see matrix.parallel)
|
||||||
|
X=${{ matrix.parallel }} # Current job number
|
||||||
|
TESTS=$(src/test/regress/citus_tests/print_test_names.py |
|
||||||
|
tr '\n' ',' | awk -v N="$N" -v X="$X" -F, '{
|
||||||
|
split("", parts)
|
||||||
|
for (i = 1; i <= NF; i++) {
|
||||||
|
parts[i % N] = parts[i % N] $i ","
|
||||||
|
}
|
||||||
|
print substr(parts[X], 1, length(parts[X])-1)
|
||||||
|
}')
|
||||||
|
echo $TESTS
|
||||||
|
gosu circleci \
|
||||||
|
make -C src/test/regress \
|
||||||
|
check-arbitrary-configs parallel=4 CONFIGS=$TESTS
|
||||||
|
- uses: "./.github/actions/save_logs_and_results"
|
||||||
|
if: always()
|
||||||
|
with:
|
||||||
|
folder: ${{ env.PG_MAJOR }}_arbitrary_configs_${{ matrix.parallel }}
|
||||||
|
- uses: "./.github/actions/upload_coverage"
|
||||||
|
if: always()
|
||||||
|
with:
|
||||||
|
flags: ${{ env.PG_MAJOR }}_arbitrary_configs_${{ matrix.parallel }}
|
||||||
|
codecov_token: ${{ secrets.CODECOV_TOKEN }}
|
||||||
|
test-pg-upgrade:
|
||||||
|
name: PG${{ matrix.old_pg_major }}-PG${{ matrix.new_pg_major }} - check-pg-upgrade
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: "${{ needs.params.outputs.pgupgrade_image_name }}:${{ needs.params.outputs.upgrade_pg_versions }}${{ needs.params.outputs.image_suffix }}"
|
||||||
|
options: --user root
|
||||||
|
needs:
|
||||||
|
- params
|
||||||
|
- build
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- old_pg_major: 15
|
||||||
|
new_pg_major: 16
|
||||||
|
- old_pg_major: 16
|
||||||
|
new_pg_major: 17
|
||||||
|
- old_pg_major: 15
|
||||||
|
new_pg_major: 17
|
||||||
|
env:
|
||||||
|
old_pg_major: ${{ matrix.old_pg_major }}
|
||||||
|
new_pg_major: ${{ matrix.new_pg_major }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: "./.github/actions/setup_extension"
|
||||||
|
with:
|
||||||
|
pg_major: "${{ env.old_pg_major }}"
|
||||||
|
- uses: "./.github/actions/setup_extension"
|
||||||
|
with:
|
||||||
|
pg_major: "${{ env.new_pg_major }}"
|
||||||
|
- name: Install and test postgres upgrade
|
||||||
|
run: |-
|
||||||
|
gosu circleci \
|
||||||
|
make -C src/test/regress \
|
||||||
|
check-pg-upgrade \
|
||||||
|
old-bindir=/usr/lib/postgresql/${{ env.old_pg_major }}/bin \
|
||||||
|
new-bindir=/usr/lib/postgresql/${{ env.new_pg_major }}/bin
|
||||||
|
- name: Copy pg_upgrade logs for newData dir
|
||||||
|
run: |-
|
||||||
|
mkdir -p /tmp/pg_upgrade_newData_logs
|
||||||
|
if ls src/test/regress/tmp_upgrade/newData/*.log 1> /dev/null 2>&1; then
|
||||||
|
cp src/test/regress/tmp_upgrade/newData/*.log /tmp/pg_upgrade_newData_logs
|
||||||
|
fi
|
||||||
|
if: failure()
|
||||||
|
- uses: "./.github/actions/save_logs_and_results"
|
||||||
|
if: always()
|
||||||
|
with:
|
||||||
|
folder: ${{ env.old_pg_major }}_${{ env.new_pg_major }}_upgrade
|
||||||
|
- uses: "./.github/actions/upload_coverage"
|
||||||
|
if: always()
|
||||||
|
with:
|
||||||
|
flags: ${{ env.old_pg_major }}_${{ env.new_pg_major }}_upgrade
|
||||||
|
codecov_token: ${{ secrets.CODECOV_TOKEN }}
|
||||||
|
test-citus-upgrade:
|
||||||
|
name: PG${{ fromJson(needs.params.outputs.pg15_version).major }} - check-citus-upgrade
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: "${{ needs.params.outputs.citusupgrade_image_name }}:${{ fromJson(needs.params.outputs.pg15_version).full }}${{ needs.params.outputs.image_suffix }}"
|
||||||
|
options: --user root
|
||||||
|
needs:
|
||||||
|
- params
|
||||||
|
- build
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: "./.github/actions/setup_extension"
|
||||||
|
with:
|
||||||
|
skip_installation: true
|
||||||
|
- name: Install and test citus upgrade
|
||||||
|
run: |-
|
||||||
|
# run make check-citus-upgrade for all citus versions
|
||||||
|
# the image has ${CITUS_VERSIONS} set with all verions it contains the binaries of
|
||||||
|
for citus_version in ${CITUS_VERSIONS}; do \
|
||||||
|
gosu circleci \
|
||||||
|
make -C src/test/regress \
|
||||||
|
check-citus-upgrade \
|
||||||
|
bindir=/usr/lib/postgresql/${PG_MAJOR}/bin \
|
||||||
|
citus-old-version=${citus_version} \
|
||||||
|
citus-pre-tar=/install-pg${PG_MAJOR}-citus${citus_version}.tar \
|
||||||
|
citus-post-tar=${GITHUB_WORKSPACE}/install-$PG_MAJOR.tar; \
|
||||||
|
done;
|
||||||
|
# run make check-citus-upgrade-mixed for all citus versions
|
||||||
|
# the image has ${CITUS_VERSIONS} set with all verions it contains the binaries of
|
||||||
|
for citus_version in ${CITUS_VERSIONS}; do \
|
||||||
|
gosu circleci \
|
||||||
|
make -C src/test/regress \
|
||||||
|
check-citus-upgrade-mixed \
|
||||||
|
citus-old-version=${citus_version} \
|
||||||
|
bindir=/usr/lib/postgresql/${PG_MAJOR}/bin \
|
||||||
|
citus-pre-tar=/install-pg${PG_MAJOR}-citus${citus_version}.tar \
|
||||||
|
citus-post-tar=${GITHUB_WORKSPACE}/install-$PG_MAJOR.tar; \
|
||||||
|
done;
|
||||||
|
- uses: "./.github/actions/save_logs_and_results"
|
||||||
|
if: always()
|
||||||
|
with:
|
||||||
|
folder: ${{ env.PG_MAJOR }}_citus_upgrade
|
||||||
|
- uses: "./.github/actions/upload_coverage"
|
||||||
|
if: always()
|
||||||
|
with:
|
||||||
|
flags: ${{ env.PG_MAJOR }}_citus_upgrade
|
||||||
|
codecov_token: ${{ secrets.CODECOV_TOKEN }}
|
||||||
|
upload-coverage:
|
||||||
|
if: always()
|
||||||
|
env:
|
||||||
|
CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: ${{ needs.params.outputs.test_image_name }}:${{ fromJson(needs.params.outputs.pg17_version).full }}${{ needs.params.outputs.image_suffix }}
|
||||||
|
needs:
|
||||||
|
- params
|
||||||
|
- test-citus
|
||||||
|
- test-arbitrary-configs
|
||||||
|
- test-citus-upgrade
|
||||||
|
- test-pg-upgrade
|
||||||
|
steps:
|
||||||
|
- uses: actions/download-artifact@v4.1.8
|
||||||
|
with:
|
||||||
|
pattern: codeclimate*
|
||||||
|
path: codeclimate
|
||||||
|
merge-multiple: true
|
||||||
|
- name: Upload coverage results to Code Climate
|
||||||
|
run: |-
|
||||||
|
cc-test-reporter sum-coverage codeclimate/*.json -o total.json
|
||||||
|
cc-test-reporter upload-coverage -i total.json
|
||||||
|
ch_benchmark:
|
||||||
|
name: CH Benchmark
|
||||||
|
if: startsWith(github.ref, 'refs/heads/ch_benchmark/')
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs:
|
||||||
|
- build
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: azure/login@v1
|
||||||
|
with:
|
||||||
|
creds: ${{ secrets.AZURE_CREDENTIALS }}
|
||||||
|
- name: install dependencies and run ch_benchmark tests
|
||||||
|
uses: azure/CLI@v1
|
||||||
|
with:
|
||||||
|
inlineScript: |
|
||||||
|
cd ./src/test/hammerdb
|
||||||
|
chmod +x run_hammerdb.sh
|
||||||
|
run_hammerdb.sh citusbot_ch_benchmark_rg
|
||||||
|
tpcc_benchmark:
|
||||||
|
name: TPCC Benchmark
|
||||||
|
if: startsWith(github.ref, 'refs/heads/tpcc_benchmark/')
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs:
|
||||||
|
- build
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: azure/login@v1
|
||||||
|
with:
|
||||||
|
creds: ${{ secrets.AZURE_CREDENTIALS }}
|
||||||
|
- name: install dependencies and run tpcc_benchmark tests
|
||||||
|
uses: azure/CLI@v1
|
||||||
|
with:
|
||||||
|
inlineScript: |
|
||||||
|
cd ./src/test/hammerdb
|
||||||
|
chmod +x run_hammerdb.sh
|
||||||
|
run_hammerdb.sh citusbot_tpcc_benchmark_rg
|
||||||
|
prepare_parallelization_matrix_32:
|
||||||
|
name: Prepare parallelization matrix
|
||||||
|
if: ${{ needs.test-flakyness-pre.outputs.tests != ''}}
|
||||||
|
needs: test-flakyness-pre
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
json: ${{ steps.parallelization.outputs.json }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: "./.github/actions/parallelization"
|
||||||
|
id: parallelization
|
||||||
|
with:
|
||||||
|
count: 32
|
||||||
|
test-flakyness-pre:
|
||||||
|
name: Detect regression tests need to be ran
|
||||||
|
if: ${{ !inputs.skip_test_flakyness }}}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: build
|
||||||
|
outputs:
|
||||||
|
tests: ${{ steps.detect-regression-tests.outputs.tests }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Detect regression tests need to be ran
|
||||||
|
id: detect-regression-tests
|
||||||
|
run: |-
|
||||||
|
detected_changes=$(git diff origin/main... --name-only --diff-filter=AM | (grep 'src/test/regress/sql/.*\.sql\|src/test/regress/spec/.*\.spec\|src/test/regress/citus_tests/test/test_.*\.py' || true))
|
||||||
|
tests=${detected_changes}
|
||||||
|
|
||||||
|
# split the tests to be skipped --today we only skip upgrade tests
|
||||||
|
skipped_tests=""
|
||||||
|
not_skipped_tests=""
|
||||||
|
for test in $tests; do
|
||||||
|
if [[ $test =~ ^src/test/regress/sql/upgrade_ ]]; then
|
||||||
|
skipped_tests="$skipped_tests $test"
|
||||||
|
else
|
||||||
|
not_skipped_tests="$not_skipped_tests $test"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ ! -z "$skipped_tests" ]; then
|
||||||
|
echo "Skipped tests " $skipped_tests
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$not_skipped_tests" ]; then
|
||||||
|
echo "Not detected any tests that flaky test detection should run"
|
||||||
|
else
|
||||||
|
echo "Detected tests " $not_skipped_tests
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo 'tests<<EOF' >> $GITHUB_OUTPUT
|
||||||
|
echo "$not_skipped_tests" >> "$GITHUB_OUTPUT"
|
||||||
|
echo 'EOF' >> $GITHUB_OUTPUT
|
||||||
|
test-flakyness:
|
||||||
|
if: ${{ needs.test-flakyness-pre.outputs.tests != ''}}
|
||||||
|
name: Test flakyness
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: ${{ needs.params.outputs.fail_test_image_name }}:${{ fromJson(needs.params.outputs.pg17_version).full }}${{ needs.params.outputs.image_suffix }}
|
||||||
|
options: --user root
|
||||||
|
env:
|
||||||
|
runs: 8
|
||||||
|
needs:
|
||||||
|
- params
|
||||||
|
- build
|
||||||
|
- test-flakyness-pre
|
||||||
|
- prepare_parallelization_matrix_32
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix: ${{ fromJson(needs.prepare_parallelization_matrix_32.outputs.json) }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/download-artifact@v4.1.8
|
||||||
|
- uses: "./.github/actions/setup_extension"
|
||||||
|
- name: Run minimal tests
|
||||||
|
run: |-
|
||||||
|
tests="${{ needs.test-flakyness-pre.outputs.tests }}"
|
||||||
|
tests_array=($tests)
|
||||||
|
for test in "${tests_array[@]}"
|
||||||
|
do
|
||||||
|
test_name=$(echo "$test" | sed -r "s/.+\/(.+)\..+/\1/")
|
||||||
|
gosu circleci src/test/regress/citus_tests/run_test.py $test_name --repeat ${{ env.runs }} --use-whole-schedule-line
|
||||||
|
done
|
||||||
|
shell: bash
|
||||||
|
- uses: "./.github/actions/save_logs_and_results"
|
||||||
|
if: always()
|
||||||
|
with:
|
||||||
|
folder: test_flakyness_parallel_${{ matrix.id }}
|
|
@ -21,10 +21,10 @@ jobs:
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@v2
|
uses: github/codeql-action/init@v3
|
||||||
with:
|
with:
|
||||||
languages: ${{ matrix.language }}
|
languages: ${{ matrix.language }}
|
||||||
|
|
||||||
|
@ -76,4 +76,4 @@ jobs:
|
||||||
sudo make install-all
|
sudo make install-all
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@v2
|
uses: github/codeql-action/analyze@v3
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
name: "Build devcontainer"
|
||||||
|
|
||||||
|
# Since building of containers can be quite time consuming, and take up some storage,
|
||||||
|
# there is no need to finish a build for a tag if new changes are concurrently being made.
|
||||||
|
# This cancels any previous builds for the same tag, and only the latest one will be kept.
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
paths:
|
||||||
|
- ".devcontainer/**"
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
docker:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
|
attestations: write
|
||||||
|
id-token: write
|
||||||
|
steps:
|
||||||
|
-
|
||||||
|
name: Docker meta
|
||||||
|
id: meta
|
||||||
|
uses: docker/metadata-action@v5
|
||||||
|
with:
|
||||||
|
images: |
|
||||||
|
ghcr.io/citusdata/citus-devcontainer
|
||||||
|
tags: |
|
||||||
|
type=ref,event=branch
|
||||||
|
type=sha
|
||||||
|
-
|
||||||
|
name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v2
|
||||||
|
-
|
||||||
|
name: 'Login to GitHub Container Registry'
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{github.actor}}
|
||||||
|
password: ${{secrets.GITHUB_TOKEN}}
|
||||||
|
-
|
||||||
|
name: Build and push
|
||||||
|
uses: docker/build-push-action@v5
|
||||||
|
with:
|
||||||
|
context: "{{defaultContext}}:.devcontainer"
|
||||||
|
push: true
|
||||||
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
cache-from: type=gha
|
||||||
|
cache-to: type=gha,mode=max
|
|
@ -0,0 +1,79 @@
|
||||||
|
name: Flaky test debugging
|
||||||
|
run-name: Flaky test debugging - ${{ inputs.flaky_test }} (${{ inputs.flaky_test_runs_per_job }}x${{ inputs.flaky_test_parallel_jobs }})
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
flaky_test:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
description: Test to run
|
||||||
|
flaky_test_runs_per_job:
|
||||||
|
required: false
|
||||||
|
default: 8
|
||||||
|
type: number
|
||||||
|
description: Number of times to run the test
|
||||||
|
flaky_test_parallel_jobs:
|
||||||
|
required: false
|
||||||
|
default: 32
|
||||||
|
type: number
|
||||||
|
description: Number of parallel jobs to run
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: Build Citus
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: ${{ vars.build_image_name }}:${{ vars.pg15_version }}${{ vars.image_suffix }}
|
||||||
|
options: --user root
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Configure, Build, and Install
|
||||||
|
run: |
|
||||||
|
echo "PG_MAJOR=${PG_MAJOR}" >> $GITHUB_ENV
|
||||||
|
./ci/build-citus.sh
|
||||||
|
shell: bash
|
||||||
|
- uses: actions/upload-artifact@v4.6.0
|
||||||
|
with:
|
||||||
|
name: build-${{ env.PG_MAJOR }}
|
||||||
|
path: |-
|
||||||
|
./build-${{ env.PG_MAJOR }}/*
|
||||||
|
./install-${{ env.PG_MAJOR }}.tar
|
||||||
|
prepare_parallelization_matrix:
|
||||||
|
name: Prepare parallelization matrix
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
json: ${{ steps.parallelization.outputs.json }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: "./.github/actions/parallelization"
|
||||||
|
id: parallelization
|
||||||
|
with:
|
||||||
|
count: ${{ inputs.flaky_test_parallel_jobs }}
|
||||||
|
test_flakyness:
|
||||||
|
name: Test flakyness
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: ${{ vars.fail_test_image_name }}:${{ vars.pg15_version }}${{ vars.image_suffix }}
|
||||||
|
options: --user root
|
||||||
|
needs:
|
||||||
|
[build, prepare_parallelization_matrix]
|
||||||
|
env:
|
||||||
|
test: "${{ inputs.flaky_test }}"
|
||||||
|
runs: "${{ inputs.flaky_test_runs_per_job }}"
|
||||||
|
skip: false
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix: ${{ fromJson(needs.prepare_parallelization_matrix.outputs.json) }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: "./.github/actions/setup_extension"
|
||||||
|
- name: Run minimal tests
|
||||||
|
run: |-
|
||||||
|
gosu circleci src/test/regress/citus_tests/run_test.py ${{ env.test }} --repeat ${{ env.runs }} --use-whole-schedule-line
|
||||||
|
shell: bash
|
||||||
|
- uses: "./.github/actions/save_logs_and_results"
|
||||||
|
if: always()
|
||||||
|
with:
|
||||||
|
folder: check_flakyness_parallel_${{ matrix.id }}
|
|
@ -3,6 +3,7 @@ name: Build tests in packaging images
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
types: [opened, reopened,synchronize]
|
types: [opened, reopened,synchronize]
|
||||||
|
merge_group:
|
||||||
|
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
|
@ -18,20 +19,22 @@ jobs:
|
||||||
pg_versions: ${{ steps.get-postgres-versions.outputs.pg_versions }}
|
pg_versions: ${{ steps.get-postgres-versions.outputs.pg_versions }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 2
|
fetch-depth: 2
|
||||||
- name: Get Postgres Versions
|
- name: Get Postgres Versions
|
||||||
id: get-postgres-versions
|
id: get-postgres-versions
|
||||||
run: |
|
run: |
|
||||||
# Postgres versions are stored in .circleci/config.yml file in "build-[pg-version] format. Below command
|
set -euxo pipefail
|
||||||
# extracts the versions and get the unique values.
|
# Postgres versions are stored in .github/workflows/build_and_test.yml
|
||||||
pg_versions=`grep -Eo 'build-[[:digit:]]{2}' .circleci/config.yml|sed -e "s/^build-//"|sort|uniq|tr '\n' ','| head -c -1`
|
# file in json strings with major and full keys.
|
||||||
|
# Below command extracts the versions and get the unique values.
|
||||||
|
pg_versions=$(cat .github/workflows/build_and_test.yml | grep -oE '"major": "[0-9]+", "full": "[0-9.]+"' | sed -E 's/"major": "([0-9]+)", "full": "([0-9.]+)"/\1/g' | sort | uniq | tr '\n', ',')
|
||||||
pg_versions_array="[ ${pg_versions} ]"
|
pg_versions_array="[ ${pg_versions} ]"
|
||||||
echo "Supported PG Versions: ${pg_versions_array}"
|
echo "Supported PG Versions: ${pg_versions_array}"
|
||||||
# Below line is needed to set the output variable to be used in the next job
|
# Below line is needed to set the output variable to be used in the next job
|
||||||
echo "pg_versions=${pg_versions_array}" >> $GITHUB_OUTPUT
|
echo "pg_versions=${pg_versions_array}" >> $GITHUB_OUTPUT
|
||||||
|
shell: bash
|
||||||
rpm_build_tests:
|
rpm_build_tests:
|
||||||
name: rpm_build_tests
|
name: rpm_build_tests
|
||||||
needs: get_postgres_versions_from_file
|
needs: get_postgres_versions_from_file
|
||||||
|
@ -44,9 +47,7 @@ jobs:
|
||||||
# For this reason, we need to use a "matrix" to generate names of
|
# For this reason, we need to use a "matrix" to generate names of
|
||||||
# rpm images, e.g. citus/packaging:centos-7-pg12
|
# rpm images, e.g. citus/packaging:centos-7-pg12
|
||||||
packaging_docker_image:
|
packaging_docker_image:
|
||||||
- oraclelinux-7
|
|
||||||
- oraclelinux-8
|
- oraclelinux-8
|
||||||
- centos-7
|
|
||||||
- almalinux-8
|
- almalinux-8
|
||||||
- almalinux-9
|
- almalinux-9
|
||||||
POSTGRES_VERSION: ${{ fromJson(needs.get_postgres_versions_from_file.outputs.pg_versions) }}
|
POSTGRES_VERSION: ${{ fromJson(needs.get_postgres_versions_from_file.outputs.pg_versions) }}
|
||||||
|
@ -57,7 +58,7 @@ jobs:
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Set Postgres and python parameters for rpm based distros
|
- name: Set Postgres and python parameters for rpm based distros
|
||||||
run: |
|
run: |
|
||||||
|
@ -99,11 +100,6 @@ jobs:
|
||||||
PACKAGING_DOCKER_IMAGE: ${{ matrix.packaging_docker_image }}
|
PACKAGING_DOCKER_IMAGE: ${{ matrix.packaging_docker_image }}
|
||||||
run: |
|
run: |
|
||||||
echo "Postgres version: ${POSTGRES_VERSION}"
|
echo "Postgres version: ${POSTGRES_VERSION}"
|
||||||
|
|
||||||
## Install required packages to execute packaging tools for rpm based distros
|
|
||||||
yum install python3-pip python3-devel postgresql-devel -y
|
|
||||||
python3 -m pip install wheel
|
|
||||||
|
|
||||||
./.github/packaging/validate_build_output.sh "rpm"
|
./.github/packaging/validate_build_output.sh "rpm"
|
||||||
|
|
||||||
deb_build_tests:
|
deb_build_tests:
|
||||||
|
@ -120,7 +116,6 @@ jobs:
|
||||||
# for each deb based image and we use POSTGRES_VERSION to set
|
# for each deb based image and we use POSTGRES_VERSION to set
|
||||||
# PG_CONFIG variable in each of those runs.
|
# PG_CONFIG variable in each of those runs.
|
||||||
packaging_docker_image:
|
packaging_docker_image:
|
||||||
- debian-buster-all
|
|
||||||
- debian-bookworm-all
|
- debian-bookworm-all
|
||||||
- debian-bullseye-all
|
- debian-bullseye-all
|
||||||
- ubuntu-focal-all
|
- ubuntu-focal-all
|
||||||
|
@ -134,7 +129,7 @@ jobs:
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Set pg_config path and python parameters for deb based distros
|
- name: Set pg_config path and python parameters for deb based distros
|
||||||
run: |
|
run: |
|
||||||
|
@ -179,9 +174,4 @@ jobs:
|
||||||
PACKAGING_DOCKER_IMAGE: ${{ matrix.packaging_docker_image }}
|
PACKAGING_DOCKER_IMAGE: ${{ matrix.packaging_docker_image }}
|
||||||
run: |
|
run: |
|
||||||
echo "Postgres version: ${POSTGRES_VERSION}"
|
echo "Postgres version: ${POSTGRES_VERSION}"
|
||||||
|
|
||||||
apt-get update -y
|
|
||||||
## Install required packages to execute packaging tools for deb based distros
|
|
||||||
apt-get install python3-dev python3-pip -y
|
|
||||||
apt-get purge -y python3-yaml
|
|
||||||
./.github/packaging/validate_build_output.sh "deb"
|
./.github/packaging/validate_build_output.sh "deb"
|
||||||
|
|
|
@ -55,3 +55,6 @@ lib*.pc
|
||||||
# style related temporary outputs
|
# style related temporary outputs
|
||||||
*.uncrustify
|
*.uncrustify
|
||||||
.venv
|
.venv
|
||||||
|
|
||||||
|
# added output when modifying check_gucs_are_alphabetically_sorted.sh
|
||||||
|
guc.out
|
||||||
|
|
406
CHANGELOG.md
|
@ -1,3 +1,405 @@
|
||||||
|
### citus v13.1.0 (May 30th, 2025) ###
|
||||||
|
|
||||||
|
* Adds `citus_stat_counters` view that can be used to query
|
||||||
|
stat counters that Citus collects while the feature is enabled, which is
|
||||||
|
controlled by citus.enable_stat_counters. `citus_stat_counters()` can be
|
||||||
|
used to query the stat counters for the provided database oid and
|
||||||
|
`citus_stat_counters_reset()` can be used to reset them for the provided
|
||||||
|
database oid or for the current database if nothing or 0 is provided (#7917)
|
||||||
|
|
||||||
|
* Adds `citus_nodes` view that displays the node name, port role, and "active"
|
||||||
|
for nodes in the cluster (#7968)
|
||||||
|
|
||||||
|
* Adds `citus_is_primary_node()` UDF to determine if the current node is a
|
||||||
|
primary node in the cluster (#7720)
|
||||||
|
|
||||||
|
* Adds support for propagating `GRANT/REVOKE` rights on table columns (#7918)
|
||||||
|
|
||||||
|
* Adds support for propagating `REASSIGN OWNED BY` commands (#7319)
|
||||||
|
|
||||||
|
* Adds support for propagating `CREATE`/`DROP` database from all nodes (#7240,
|
||||||
|
#7253, #7359)
|
||||||
|
|
||||||
|
* Propagates `SECURITY LABEL ON ROLE` statement from any node (#7508)
|
||||||
|
|
||||||
|
* Adds support for issuing role management commands from worker nodes (#7278)
|
||||||
|
|
||||||
|
* Adds support for propagating `ALTER USER RENAME` commands (#7204)
|
||||||
|
|
||||||
|
* Adds support for propagating `ALTER DATABASE <db_name> SET ..` commands
|
||||||
|
(#7181)
|
||||||
|
|
||||||
|
* Adds support for propagating `SECURITY LABEL` on tables and columns (#7956)
|
||||||
|
|
||||||
|
* Adds support for propagating `COMMENT ON <database>/<role>` commands (#7388)
|
||||||
|
|
||||||
|
* Moves some of the internal citus functions from `pg_catalog` to
|
||||||
|
`citus_internal` schema (#7473, #7470, #7466, 7456, 7450)
|
||||||
|
|
||||||
|
* Adjusts `max_prepared_transactions` only when it's set to default on PG >= 16
|
||||||
|
(#7712)
|
||||||
|
|
||||||
|
* Adds skip_qualify_public param to shard_name() UDF to allow qualifying for
|
||||||
|
"public" schema when needed (#8014)
|
||||||
|
|
||||||
|
* Allows `citus_*_size` on indexes on a distributed tables (#7271)
|
||||||
|
|
||||||
|
* Allows `GRANT ADMIN` to now also be `INHERIT` or `SET` in support of PG16
|
||||||
|
|
||||||
|
* Makes sure `worker_copy_table_to_node` errors out with Citus tables (#7662)
|
||||||
|
|
||||||
|
* Adds information to explain output when using
|
||||||
|
`citus.explain_distributed_queries=false` (#7412)
|
||||||
|
|
||||||
|
* Logs username in the failed connection message (#7432)
|
||||||
|
|
||||||
|
* Makes sure to avoid incorrectly pushing-down the outer joins between
|
||||||
|
distributed tables and recurring relations (like reference tables, local
|
||||||
|
tables and `VALUES(..)` etc.) prior to PG 17 (#7937)
|
||||||
|
|
||||||
|
* Prevents incorrectly pushing `nextval()` call down to workers to avoid using
|
||||||
|
incorrect sequence value for some types of `INSERT .. SELECT`s (#7976)
|
||||||
|
|
||||||
|
* Makes sure to prevent `INSERT INTO ... SELECT` queries involving subfield or
|
||||||
|
sublink, to avoid crashes (#7912)
|
||||||
|
|
||||||
|
* Makes sure to take improvement_threshold into the account
|
||||||
|
in `citus_add_rebalance_strategy()` (#7247)
|
||||||
|
|
||||||
|
* Makes sure to disallow creating a replicated distributed
|
||||||
|
table concurrently (#7219)
|
||||||
|
|
||||||
|
* Fixes a bug that causes omitting `CASCADE` clause for the commands sent to
|
||||||
|
workers for `REVOKE` commands on tables (#7958)
|
||||||
|
|
||||||
|
* Fixes an issue detected using address sanitizer (#7948, #7949)
|
||||||
|
|
||||||
|
* Fixes a bug in deparsing of shard query in case of "output-table column" name
|
||||||
|
conflict (#7932)
|
||||||
|
|
||||||
|
* Fixes a crash in columnar custom scan that happens when a columnar table is
|
||||||
|
used in a join (#7703)
|
||||||
|
|
||||||
|
* Fixes `MERGE` command when insert value does not have source distributed
|
||||||
|
column (#7627)
|
||||||
|
|
||||||
|
* Fixes performance issue when using `\d tablename` on a server with many
|
||||||
|
tables (#7577)
|
||||||
|
|
||||||
|
* Fixes performance issue in `GetForeignKeyOids` on systems with many
|
||||||
|
constraints (#7580)
|
||||||
|
|
||||||
|
* Fixes performance issue when distributing a table that depends on an
|
||||||
|
extension (#7574)
|
||||||
|
|
||||||
|
* Fixes performance issue when creating distributed tables if many already
|
||||||
|
exist (#7575)
|
||||||
|
|
||||||
|
* Fixes a crash caused by some form of `ALTER TABLE ADD COLUMN` statements. When
|
||||||
|
adding multiple columns, if one of the `ADD COLUMN` statements contains a
|
||||||
|
`FOREIGN` constraint ommitting the referenced
|
||||||
|
columns in the statement, a `SEGFAULT` occurs (#7522)
|
||||||
|
|
||||||
|
* Fixes assertion failure in maintenance daemon during Citus upgrades (#7537)
|
||||||
|
|
||||||
|
* Fixes segmentation fault when using `CASE WHEN` in `DO` block functions
|
||||||
|
(#7554)
|
||||||
|
|
||||||
|
* Fixes undefined behavior in `master_disable_node` due to argument mismatch
|
||||||
|
(#7492)
|
||||||
|
|
||||||
|
* Fixes incorrect propagating of `GRANTED BY` and `CASCADE/RESTRICT` clauses
|
||||||
|
for `REVOKE` statements (#7451)
|
||||||
|
|
||||||
|
* Fixes the incorrect column count after `ALTER TABLE` (#7379)
|
||||||
|
|
||||||
|
* Fixes timeout when underlying socket is changed for an inter-node connection
|
||||||
|
(#7377)
|
||||||
|
|
||||||
|
* Fixes memory leaks (#7441, #7440)
|
||||||
|
|
||||||
|
* Fixes leaking of memory and memory contexts when tracking foreign keys between
|
||||||
|
Citus tables (#7236)
|
||||||
|
|
||||||
|
* Fixes a potential segfault for background rebalancer (#7694)
|
||||||
|
|
||||||
|
* Fixes potential `NULL` dereference in casual clocks (#7704)
|
||||||
|
|
||||||
|
### citus v13.0.4 (May 29th, 2025) ###
|
||||||
|
|
||||||
|
* Fixes an issue detected using address sanitizer (#7966)
|
||||||
|
|
||||||
|
* Error out for queries with outer joins and pseudoconstant quals in versions
|
||||||
|
prior to PG 17 (#7937)
|
||||||
|
|
||||||
|
### citus v12.1.8 (May 29, 2025) ###
|
||||||
|
|
||||||
|
* Fixes a crash in left outer joins that can happen when there is an an
|
||||||
|
aggregate on a column from the inner side of the join (#7904)
|
||||||
|
|
||||||
|
* Fixes an issue detected using address sanitizer (#7965)
|
||||||
|
|
||||||
|
* Fixes a crash when executing a prepared CALL, which is not pure SQL but
|
||||||
|
available with some drivers like npgsql and jpgdbc (#7288)
|
||||||
|
|
||||||
|
### citus v13.0.3 (March 20th, 2025) ###
|
||||||
|
|
||||||
|
* Fixes a version bump issue in 13.0.2
|
||||||
|
|
||||||
|
### citus v13.0.2 (March 12th, 2025) ###
|
||||||
|
|
||||||
|
* Fixes a crash in columnar custom scan that happens when a columnar table is
|
||||||
|
used in a join. (#7647)
|
||||||
|
|
||||||
|
* Fixes a bug that breaks `UPDATE SET (...) = (SELECT some_func(),... )`
|
||||||
|
type of queries on Citus tables (#7914)
|
||||||
|
|
||||||
|
* Fixes a planning error caused by a redundant WHERE clause (#7907)
|
||||||
|
|
||||||
|
* Fixes a crash in left outer joins that can happen when there is an aggregate
|
||||||
|
on a column from the inner side of the join. (#7901)
|
||||||
|
|
||||||
|
* Fixes deadlock with transaction recovery that is possible during Citus
|
||||||
|
upgrades. (#7910)
|
||||||
|
|
||||||
|
* Fixes a bug that prevents inserting into Citus tables that uses
|
||||||
|
a GENERATED ALWAYS AS IDENTITY column. (#7920)
|
||||||
|
|
||||||
|
* Ensures that a MERGE command on a distributed table with a WHEN NOT MATCHED BY
|
||||||
|
SOURCE clause runs against all shards of the distributed table. (#7900)
|
||||||
|
|
||||||
|
* Fixes a bug that breaks router updates on distributed tables
|
||||||
|
when a reference table is used in the subquery (#7897)
|
||||||
|
|
||||||
|
### citus v12.1.7 (Feb 6, 2025) ###
|
||||||
|
|
||||||
|
* Fixes a crash that happens because of unsafe catalog access when re-assigning
|
||||||
|
the global pid after `application_name` changes (#7791)
|
||||||
|
|
||||||
|
* Prevents crashes when another extension skips executing the
|
||||||
|
`ClientAuthentication_hook` of Citus. (#7836)
|
||||||
|
|
||||||
|
### citus v13.0.1 (February 4th, 2025) ###
|
||||||
|
|
||||||
|
* Drops support for PostgreSQL 14 (#7753)
|
||||||
|
|
||||||
|
### citus v13.0.0 (January 22, 2025) ###
|
||||||
|
|
||||||
|
* Adds support for PostgreSQL 17 (#7699, #7661)
|
||||||
|
|
||||||
|
* Adds `JSON_TABLE()` support in distributed queries (#7816)
|
||||||
|
|
||||||
|
* Propagates `MERGE ... WHEN NOT MATCHED BY SOURCE` (#7807)
|
||||||
|
|
||||||
|
* Propagates `MEMORY` and `SERIALIZE` options of `EXPLAIN` (#7802)
|
||||||
|
|
||||||
|
* Adds support for identity columns in distributed partitioned tables (#7785)
|
||||||
|
|
||||||
|
* Allows specifying an access method for distributed partitioned tables (#7818)
|
||||||
|
|
||||||
|
* Allows exclusion constraints on distributed partitioned tables (#7733)
|
||||||
|
|
||||||
|
* Allows configuring sslnegotiation using `citus.node_conn_info` (#7821)
|
||||||
|
|
||||||
|
* Avoids wal receiver timeouts during large shard splits (#7229)
|
||||||
|
|
||||||
|
* Fixes a bug causing incorrect writing of data to target `MERGE` repartition
|
||||||
|
command (#7659)
|
||||||
|
|
||||||
|
* Fixes a crash that happens because of unsafe catalog access when re-assigning
|
||||||
|
the global pid after `application_name` changes (#7791)
|
||||||
|
|
||||||
|
* Fixes incorrect `VALID UNTIL` setting assumption made for roles when syncing
|
||||||
|
them to new nodes (#7534)
|
||||||
|
|
||||||
|
* Fixes segfault when calling distributed procedure with a parameterized
|
||||||
|
distribution argument (#7242)
|
||||||
|
|
||||||
|
* Fixes server crash when trying to execute `activate_node_snapshot()` on a
|
||||||
|
single-node cluster (#7552)
|
||||||
|
|
||||||
|
* Improves `citus_move_shard_placement()` to fail early if there is a new node
|
||||||
|
without reference tables yet (#7467)
|
||||||
|
|
||||||
|
### citus v12.1.6 (Nov 14, 2024) ###
|
||||||
|
|
||||||
|
* Propagates `SECURITY LABEL .. ON ROLE` statements (#7304)
|
||||||
|
|
||||||
|
* Fixes crash caused by running queries with window partition (#7718)
|
||||||
|
|
||||||
|
### citus v12.1.5 (July 17, 2024) ###
|
||||||
|
|
||||||
|
* Adds support for MERGE commands with single shard distributed target tables
|
||||||
|
(#7643)
|
||||||
|
|
||||||
|
* Fixes an error with MERGE commands when insert value does not have source
|
||||||
|
distribution column (#7627)
|
||||||
|
|
||||||
|
### citus v12.1.4 (May 28, 2024) ###
|
||||||
|
|
||||||
|
* Adds null check for node in HasRangeTableRef (#7604)
|
||||||
|
|
||||||
|
### citus v12.1.3 (April 18, 2024) ###
|
||||||
|
|
||||||
|
* Allows overwriting host name for all inter-node connections by
|
||||||
|
supporting "host" parameter in citus.node_conninfo (#7541)
|
||||||
|
|
||||||
|
* Avoids distributed deadlocks by changing the order in which the locks are
|
||||||
|
acquired for the target and reference tables (#7542)
|
||||||
|
|
||||||
|
* Fixes a performance issue when distributing a table that depends on an
|
||||||
|
extension (#7574)
|
||||||
|
|
||||||
|
* Fixes a performance issue when using "\d tablename" on a server with
|
||||||
|
many tables (#7577)
|
||||||
|
|
||||||
|
* Fixes a crash caused by some form of ALTER TABLE ADD COLUMN
|
||||||
|
statements. When adding multiple columns, if one of the ADD COLUMN
|
||||||
|
statements contains a FOREIGN constraint omitting the referenced
|
||||||
|
columns in the statement, a SEGFAULT was occurring. (#7522)
|
||||||
|
|
||||||
|
* Fixes a performance issue when creating distributed tables if many
|
||||||
|
already exist (#7575, #7579)
|
||||||
|
|
||||||
|
* Fixes a bug when hostname in pg_dist_node resolves to multiple IPs
|
||||||
|
(#7377)
|
||||||
|
|
||||||
|
* Fixes performance issue when tracking foreign key constraints on
|
||||||
|
systems with many constraints (#7578)
|
||||||
|
|
||||||
|
* Fixes segmentation fault when using CASE WHEN in DO block within
|
||||||
|
functions. (#7554)
|
||||||
|
|
||||||
|
* Fixes undefined behavior in master_disable_node due to argument
|
||||||
|
mismatch (#7492)
|
||||||
|
|
||||||
|
* Fixes some potential bugs by correctly marking some variables as
|
||||||
|
volatile (#7570)
|
||||||
|
|
||||||
|
* Logs username in the failed connection message (#7432)
|
||||||
|
|
||||||
|
### citus v11.0.10 (February 15, 2024) ###
|
||||||
|
|
||||||
|
* Removes pg_send_cancellation and all references (#7135)
|
||||||
|
|
||||||
|
### citus v12.1.2 (February 12, 2024) ###
|
||||||
|
|
||||||
|
* Fixes the incorrect column count after ALTER TABLE (#7379)
|
||||||
|
|
||||||
|
### citus v12.0.1 (July 11, 2023) ###
|
||||||
|
|
||||||
|
* Fixes incorrect default value assumption for VACUUM(PROCESS_TOAST) #7122)
|
||||||
|
|
||||||
|
* Fixes a bug that causes an unexpected error when adding a column
|
||||||
|
with a NULL constraint (#7093)
|
||||||
|
|
||||||
|
* Fixes a bug that could cause COPY logic to skip data in case of OOM (#7152)
|
||||||
|
|
||||||
|
* Fixes a bug with deleting colocation groups (#6929)
|
||||||
|
|
||||||
|
* Fixes memory and memory contexts leaks in Foreign Constraint Graphs (#7236)
|
||||||
|
|
||||||
|
* Fixes shard size bug with too many shards (#7018)
|
||||||
|
|
||||||
|
* Fixes the incorrect column count after ALTER TABLE (#7379)
|
||||||
|
|
||||||
|
* Improves citus_tables view performance (#7050)
|
||||||
|
|
||||||
|
* Makes sure to disallow creating a replicated distributed table
|
||||||
|
concurrently (#7219)
|
||||||
|
|
||||||
|
* Removes pg_send_cancellation and all references (#7135)
|
||||||
|
|
||||||
|
### citus v11.3.1 (February 12, 2024) ###
|
||||||
|
|
||||||
|
* Disallows MERGE when the query prunes down to zero shards (#6946)
|
||||||
|
|
||||||
|
* Fixes a bug related to non-existent objects in DDL commands (#6984)
|
||||||
|
|
||||||
|
* Fixes a bug that could cause COPY logic to skip data in case of OOM (#7152)
|
||||||
|
|
||||||
|
* Fixes a bug with deleting colocation groups (#6929)
|
||||||
|
|
||||||
|
* Fixes incorrect results on fetching scrollable with hold cursors (#7014)
|
||||||
|
|
||||||
|
* Fixes memory and memory context leaks in Foreign Constraint Graphs (#7236)
|
||||||
|
|
||||||
|
* Fixes replicate reference tables task fail when user is superuser (#6930)
|
||||||
|
|
||||||
|
* Fixes the incorrect column count after ALTER TABLE (#7379)
|
||||||
|
|
||||||
|
* Improves citus_shard_sizes performance (#7050)
|
||||||
|
|
||||||
|
* Makes sure to disallow creating a replicated distributed table
|
||||||
|
concurrently (#7219)
|
||||||
|
|
||||||
|
* Removes pg_send_cancellation and all references (#7135)
|
||||||
|
|
||||||
|
### citus v11.2.2 (February 12, 2024) ###
|
||||||
|
|
||||||
|
* Fixes a bug in background shard rebalancer where the replicate
|
||||||
|
reference tables task fails if the current user is not a superuser (#6930)
|
||||||
|
|
||||||
|
* Fixes a bug related to non-existent objects in DDL commands (#6984)
|
||||||
|
|
||||||
|
* Fixes a bug that could cause COPY logic to skip data in case of OOM (#7152)
|
||||||
|
|
||||||
|
* Fixes a bug with deleting colocation groups (#6929)
|
||||||
|
|
||||||
|
* Fixes incorrect results on fetching scrollable with hold cursors (#7014)
|
||||||
|
|
||||||
|
* Fixes memory and memory context leaks in Foreign Constraint Graphs (#7236)
|
||||||
|
|
||||||
|
* Fixes the incorrect column count after ALTER TABLE (#7379)
|
||||||
|
|
||||||
|
* Improves failure handling of distributed execution (#7090)
|
||||||
|
|
||||||
|
* Makes sure to disallow creating a replicated distributed table
|
||||||
|
concurrently (#7219)
|
||||||
|
|
||||||
|
* Removes pg_send_cancellation (#7135)
|
||||||
|
|
||||||
|
### citus v11.1.7 (February 12, 2024) ###
|
||||||
|
|
||||||
|
* Fixes memory and memory context leaks in Foreign Constraint Graphs (#7236)
|
||||||
|
|
||||||
|
* Fixes a bug related to non-existent objects in DDL commands (#6984)
|
||||||
|
|
||||||
|
* Fixes a bug that could cause COPY logic to skip data in case of OOM (#7152)
|
||||||
|
|
||||||
|
* Fixes a bug with deleting colocation groups (#6929)
|
||||||
|
|
||||||
|
* Fixes incorrect results on fetching scrollable with hold cursors (#7014)
|
||||||
|
|
||||||
|
* Fixes the incorrect column count after ALTER TABLE (#7379)
|
||||||
|
|
||||||
|
* Improves failure handling of distributed execution (#7090)
|
||||||
|
|
||||||
|
* Makes sure to disallow creating a replicated distributed table
|
||||||
|
concurrently (#7219)
|
||||||
|
|
||||||
|
* Removes pg_send_cancellation and all references (#7135)
|
||||||
|
|
||||||
|
### citus v11.0.9 (February 12, 2024) ###
|
||||||
|
|
||||||
|
* Fixes a bug that could cause COPY logic to skip data in case of OOM (#7152)
|
||||||
|
|
||||||
|
* Fixes a bug with deleting colocation groups (#6929)
|
||||||
|
|
||||||
|
* Fixes memory and memory context leaks in Foreign Constraint Graphs (#7236)
|
||||||
|
|
||||||
|
* Fixes the incorrect column count after ALTER TABLE (#7462)
|
||||||
|
|
||||||
|
* Improve failure handling of distributed execution (#7090)
|
||||||
|
|
||||||
|
### citus v12.1.1 (November 9, 2023) ###
|
||||||
|
|
||||||
|
* Fixes leaking of memory and memory contexts in Citus foreign key cache
|
||||||
|
(#7236)
|
||||||
|
|
||||||
|
* Makes sure to disallow creating a replicated distributed table concurrently
|
||||||
|
(#7219)
|
||||||
|
|
||||||
### citus v12.1.0 (September 12, 2023) ###
|
### citus v12.1.0 (September 12, 2023) ###
|
||||||
|
|
||||||
* Adds support for PostgreSQL 16.0 (#7173)
|
* Adds support for PostgreSQL 16.0 (#7173)
|
||||||
|
@ -5,8 +407,8 @@
|
||||||
* Add `citus_schema_move()` function which moves tables within a
|
* Add `citus_schema_move()` function which moves tables within a
|
||||||
distributed schema to another node (#7180)
|
distributed schema to another node (#7180)
|
||||||
|
|
||||||
* Adds `citus_pause_node()` UDF that allows pausing the node with given id
|
* Adds `citus_pause_node_within_txn()` UDF that allows pausing the node with
|
||||||
(#7089)
|
given id (#7089)
|
||||||
|
|
||||||
* Makes sure to enforce shard level colocation with the GUC
|
* Makes sure to enforce shard level colocation with the GUC
|
||||||
`citus.enable_non_colocated_router_query_pushdown` (#7076)
|
`citus.enable_non_colocated_router_query_pushdown` (#7076)
|
||||||
|
|
121
CONTRIBUTING.md
|
@ -11,6 +11,52 @@ sign a Contributor License Agreement (CLA). For an explanation of
|
||||||
why we ask this as well as instructions for how to proceed, see the
|
why we ask this as well as instructions for how to proceed, see the
|
||||||
[Microsoft CLA](https://cla.opensource.microsoft.com/).
|
[Microsoft CLA](https://cla.opensource.microsoft.com/).
|
||||||
|
|
||||||
|
### Devcontainer / Github Codespaces
|
||||||
|
|
||||||
|
The easiest way to start contributing is via our devcontainer. This container works both locally in visual studio code with docker-desktop/docker-for-mac as well as [Github Codespaces](https://github.com/features/codespaces). To open the project in vscode you will need the [Dev Containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers). For codespaces you will need to [create a new codespace](https://codespace.new/citusdata/citus).
|
||||||
|
|
||||||
|
With the extension installed you can run the following from the command pallet to get started
|
||||||
|
|
||||||
|
```
|
||||||
|
> Dev Containers: Clone Repository in Container Volume...
|
||||||
|
```
|
||||||
|
|
||||||
|
In the subsequent popup paste the url to the repo and hit enter.
|
||||||
|
|
||||||
|
```
|
||||||
|
https://github.com/citusdata/citus
|
||||||
|
```
|
||||||
|
|
||||||
|
This will create an isolated Workspace in vscode, complete with all tools required to build, test and run the Citus extension. We keep this container up to date with the supported postgres versions as well as the exact versions of tooling we use.
|
||||||
|
|
||||||
|
To quickly start we suggest splitting your terminal once to have two shells. The left one in the `/workspaces/citus`, the second one changed to `/data`. The left terminal will be used to interact with the project, the right one with a testing cluster.
|
||||||
|
|
||||||
|
To get citus installed from source we run `make install -s` in the first terminal. Once installed you can start a Citus cluster in the second terminal via `citus_dev make citus`. The cluster will run in the background, and can be interacted with via `citus_dev`. To get an overview of the available commands.
|
||||||
|
|
||||||
|
With the Citus cluster running you can connect to the coordinator in the first terminal via `psql -p9700`. Because the coordinator is the most common entrypoint the `PGPORT` environment is set accordingly, so a simple `psql` will connect directly to the coordinator.
|
||||||
|
|
||||||
|
### Debugging in the VS code
|
||||||
|
|
||||||
|
1. Start Debugging: Press F5 in VS Code to start debugging. When prompted, you'll need to attach the debugger to the appropriate PostgreSQL process.
|
||||||
|
|
||||||
|
2. Identify the Process: If you're running a psql command, take note of the PID that appears in your psql prompt. For example:
|
||||||
|
```
|
||||||
|
[local] citus@citus:9700 (PID: 5436)=#
|
||||||
|
```
|
||||||
|
This PID (5436 in this case) indicates the process that you should attach the debugger to.
|
||||||
|
If you are uncertain about which process to attach, you can list all running PostgreSQL processes using the following command:
|
||||||
|
```
|
||||||
|
ps aux | grep postgres
|
||||||
|
```
|
||||||
|
|
||||||
|
Look for the process associated with the PID you noted. For example:
|
||||||
|
```
|
||||||
|
citus 5436 0.0 0.0 0 0 ? S 14:00 0:00 postgres: citus citus
|
||||||
|
```
|
||||||
|
4. Attach the Debugger: Once you've identified the correct PID, select that process when prompted in VS Code to attach the debugger. You should now be able to debug the PostgreSQL session tied to the psql command.
|
||||||
|
|
||||||
|
5. Set Breakpoints and Debug: With the debugger attached, you can set breakpoints within the code. This allows you to step through the code execution, inspect variables, and fully debug the PostgreSQL instance running in your container.
|
||||||
|
|
||||||
### Getting and building
|
### Getting and building
|
||||||
|
|
||||||
[PostgreSQL documentation](https://www.postgresql.org/support/versioning/) has a
|
[PostgreSQL documentation](https://www.postgresql.org/support/versioning/) has a
|
||||||
|
@ -41,6 +87,8 @@ that are missing in earlier minor versions.
|
||||||
|
|
||||||
cd citus
|
cd citus
|
||||||
./configure
|
./configure
|
||||||
|
# If you have already installed the project, you need to clean it first
|
||||||
|
make clean
|
||||||
make
|
make
|
||||||
make install
|
make install
|
||||||
# Optionally, you might instead want to use `make install-all`
|
# Optionally, you might instead want to use `make install-all`
|
||||||
|
@ -79,6 +127,8 @@ that are missing in earlier minor versions.
|
||||||
git clone https://github.com/citusdata/citus.git
|
git clone https://github.com/citusdata/citus.git
|
||||||
cd citus
|
cd citus
|
||||||
./configure
|
./configure
|
||||||
|
# If you have already installed the project previously, you need to clean it first
|
||||||
|
make clean
|
||||||
make
|
make
|
||||||
sudo make install
|
sudo make install
|
||||||
# Optionally, you might instead want to use `sudo make install-all`
|
# Optionally, you might instead want to use `sudo make install-all`
|
||||||
|
@ -129,6 +179,8 @@ that are missing in earlier minor versions.
|
||||||
git clone https://github.com/citusdata/citus.git
|
git clone https://github.com/citusdata/citus.git
|
||||||
cd citus
|
cd citus
|
||||||
PG_CONFIG=/usr/pgsql-14/bin/pg_config ./configure
|
PG_CONFIG=/usr/pgsql-14/bin/pg_config ./configure
|
||||||
|
# If you have already installed the project previously, you need to clean it first
|
||||||
|
make clean
|
||||||
make
|
make
|
||||||
sudo make install
|
sudo make install
|
||||||
# Optionally, you might instead want to use `sudo make install-all`
|
# Optionally, you might instead want to use `sudo make install-all`
|
||||||
|
@ -145,43 +197,7 @@ that are missing in earlier minor versions.
|
||||||
|
|
||||||
### Following our coding conventions
|
### Following our coding conventions
|
||||||
|
|
||||||
CircleCI will automatically reject any PRs which do not follow our coding
|
Our coding conventions are documented in [STYLEGUIDE.md](STYLEGUIDE.md).
|
||||||
conventions. The easiest way to ensure your PR adheres to those conventions is
|
|
||||||
to use the [citus_indent](https://github.com/citusdata/tools/tree/develop/uncrustify)
|
|
||||||
tool. This tool uses `uncrustify` under the hood.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Uncrustify changes the way it formats code every release a bit. To make sure
|
|
||||||
# everyone formats consistently we use version 0.68.1:
|
|
||||||
curl -L https://github.com/uncrustify/uncrustify/archive/uncrustify-0.68.1.tar.gz | tar xz
|
|
||||||
cd uncrustify-uncrustify-0.68.1/
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
cmake ..
|
|
||||||
make -j5
|
|
||||||
sudo make install
|
|
||||||
cd ../..
|
|
||||||
|
|
||||||
git clone https://github.com/citusdata/tools.git
|
|
||||||
cd tools
|
|
||||||
make uncrustify/.install
|
|
||||||
```
|
|
||||||
|
|
||||||
Once you've done that, you can run the `make reindent` command from the top
|
|
||||||
directory to recursively check and correct the style of any source files in the
|
|
||||||
current directory. Under the hood, `make reindent` will run `citus_indent` and
|
|
||||||
some other style corrections for you.
|
|
||||||
|
|
||||||
You can also run the following in the directory of this repository to
|
|
||||||
automatically format all the files that you have changed before committing:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cat > .git/hooks/pre-commit << __EOF__
|
|
||||||
#!/bin/bash
|
|
||||||
citus_indent --check --diff || { citus_indent --diff; exit 1; }
|
|
||||||
__EOF__
|
|
||||||
chmod +x .git/hooks/pre-commit
|
|
||||||
```
|
|
||||||
|
|
||||||
### Making SQL changes
|
### Making SQL changes
|
||||||
|
|
||||||
|
@ -234,3 +250,34 @@ Any other SQL you can put directly in the main sql file, e.g.
|
||||||
### Running tests
|
### Running tests
|
||||||
|
|
||||||
See [`src/test/regress/README.md`](https://github.com/citusdata/citus/blob/master/src/test/regress/README.md)
|
See [`src/test/regress/README.md`](https://github.com/citusdata/citus/blob/master/src/test/regress/README.md)
|
||||||
|
|
||||||
|
### Documentation
|
||||||
|
|
||||||
|
User-facing documentation is published on [docs.citusdata.com](https://docs.citusdata.com/). When adding a new feature, function, or setting, you can open a pull request or issue against the [Citus docs repo](https://github.com/citusdata/citus_docs/).
|
||||||
|
|
||||||
|
Detailed descriptions of the implementation for Citus developers are provided in the [Citus Technical Documentation](src/backend/distributed/README.md). It is currently a single file for ease of searching. Please update the documentation if you make any changes that affect the design or add major new features.
|
||||||
|
|
||||||
|
# Making a pull request ready for reviews
|
||||||
|
|
||||||
|
Asking for help and asking for reviews are two different things. When you're asking for help, you're asking for someone to help you with something that you're not expected to know.
|
||||||
|
|
||||||
|
But when you're asking for a review, you're asking for someone to review your work and provide feedback. So, when you're asking for a review, you're expected to make sure that:
|
||||||
|
|
||||||
|
* Your changes don't perform **unnecessary line addition / deletions / style changes on unrelated files / lines**.
|
||||||
|
|
||||||
|
* All CI jobs are **passing**, including **style checks** and **flaky test detection jobs**. Note that if you're an external contributor, you don't have to wait CI jobs to run (and finish) because they don't get automatically triggered for external contributors.
|
||||||
|
|
||||||
|
* Your PR has necessary amount of **tests** and that they're passing.
|
||||||
|
|
||||||
|
* You separated as much as possible work into **separate PRs**, e.g., a prerequisite bugfix, a refactoring etc..
|
||||||
|
|
||||||
|
* Your PR doesn't introduce a typo or something that you can easily fix yourself.
|
||||||
|
|
||||||
|
* After all CI jobs pass, code-coverage measurement job (CodeCov as of today) then kicks in. That's why it's important to make the **tests passing** first. At that point, you're expected to check **CodeCov annotations** that can be seen in the **Files Changed** tab and expected to make sure that it doesn't complain about any lines that are not covered. For example, it's ok if CodeCov complains about an `ereport()` call that you put for an "unexpected-but-better-than-crashing" case, but it's not ok if it complains about an uncovered `if` branch that you added.
|
||||||
|
|
||||||
|
* And finally, perform a **self-review** to make sure that:
|
||||||
|
* Code and code-comments reflects the idea **without requiring an extra explanation** via a chat message / email / PR comment.
|
||||||
|
This is important because we don't expect developers to reach out to author / read about the whole discussion in the PR to understand the idea behind a commit merged into `main` branch.
|
||||||
|
* PR description is clear enough.
|
||||||
|
* If-and-only-if you're **introducing a user facing change / bugfix**, your PR has a line that starts with `DESCRIPTION: <Present simple tense word that starts with a capital letter, e.g., Adds support for / Fixes / Disallows>`.
|
||||||
|
* **Commit messages** are clear enough if the commits are doing logically different things.
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
# Devcontainer
|
||||||
|
|
||||||
|
## Coredumps
|
||||||
|
When postgres/citus crashes, there is the option to create a coredump. This is useful for debugging the issue. Coredumps are enabled in the devcontainer by default. However, not all environments are configured correctly out of the box. The most important configuration that is not standardized is the `core_pattern`. The configuration can be verified from the container, however, you cannot change this setting from inside the container as the filesystem containing this setting is in read only mode while inside the container.
|
||||||
|
|
||||||
|
To verify if corefiles are written run the following command in a terminal. This shows the filename pattern with which the corefile will be written.
|
||||||
|
```bash
|
||||||
|
cat /proc/sys/kernel/core_pattern
|
||||||
|
```
|
||||||
|
|
||||||
|
This should be configured with a relative path or simply a simple filename, such as `core`. When your environment shows an absolute path you will need to change this setting. How to change this setting depends highly on the underlying system as the setting needs to be changed on the kernel of the host running the container.
|
||||||
|
|
||||||
|
You can put any pattern in `/proc/sys/kernel/core_pattern` as you see fit. eg. You can add the PID to the core pattern in one of two ways;
|
||||||
|
- You either include `%p` in the core_pattern. This gets substituted with the PID of the crashing process.
|
||||||
|
- Alternatively you could set `/proc/sys/kernel/core_uses_pid` to `1` in the same way as you set `core_pattern`. This will append the PID to the corefile if `%p` is not explicitly contained in the core_pattern.
|
||||||
|
|
||||||
|
When a coredump is written you can use the debug/launch configuration `Open core file` which is preconfigured in the devcontainer. This will open a fileprompt that lists all coredumps that are found in your workspace. When you want to debug coredumps from `citus_dev` that are run in your `/data` directory, you can add the data directory to your workspace. In the command pallet of vscode you can run `>Workspace: Add Folder to Workspace...` and select the `/data` directory. This will allow you to open the coredumps from the `/data` directory in the `Open core file` debug configuration.
|
||||||
|
|
||||||
|
### Windows (docker desktop)
|
||||||
|
When running in docker desktop on windows you will most likely need to change this setting. The linux guest in WSL2 that runs your container is the `docker-desktop` environment. The easiest way to get onto the host, where you can change this setting, is to open a powershell window and verify you have the docker-desktop environment listed.
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
wsl --list
|
||||||
|
```
|
||||||
|
|
||||||
|
Among others this should list both `docker-desktop` and `docker-desktop-data`. You can then open a shell in the `docker-desktop` environment.
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
wsl -d docker-desktop
|
||||||
|
```
|
||||||
|
|
||||||
|
Inside this shell you can verify that you have the right environment by running
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cat /proc/sys/kernel/core_pattern
|
||||||
|
```
|
||||||
|
|
||||||
|
This should show the same configuration as the one you see inside the devcontainer. You can then change the setting by running the following command.
|
||||||
|
This will change the setting for the current session. If you want to make the change permanent you will need to add this to a startup script.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
echo "core" > /proc/sys/kernel/core_pattern
|
||||||
|
```
|
3
Makefile
|
@ -61,6 +61,7 @@ check-style:
|
||||||
|
|
||||||
# depend on install-all so that downgrade scripts are installed as well
|
# depend on install-all so that downgrade scripts are installed as well
|
||||||
check: all install-all
|
check: all install-all
|
||||||
$(MAKE) -C src/test/regress check-full
|
# explicetely does not use $(MAKE) to avoid parallelism
|
||||||
|
make -C src/test/regress check
|
||||||
|
|
||||||
.PHONY: all check clean install install-downgrades install-all
|
.PHONY: all check clean install install-downgrades install-all
|
||||||
|
|
22
README.md
|
@ -1,10 +1,10 @@
|
||||||
| **<br/>The Citus database is 100% open source.<br/><img width=1000/><br/>Learn what's new in the [Citus 12.0 release blog](https://www.citusdata.com/blog/2023/07/18/citus-12-schema-based-sharding-comes-to-postgres/) and the [Citus Updates page](https://www.citusdata.com/updates/).<br/><br/>**|
|
| **<br/>The Citus database is 100% open source.<br/><img width=1000/><br/>Learn what's new in the [Citus 13.0 release blog](https://www.citusdata.com/blog/2025/02/06/distribute-postgresql-17-with-citus-13/) and the [Citus Updates page](https://www.citusdata.com/updates/).<br/><br/>**|
|
||||||
|---|
|
|---|
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
[](https://docs.citusdata.com/)
|
[](https://docs.citusdata.com/)
|
||||||
[](https://stackoverflow.com/questions/tagged/citus)
|
[](https://stackoverflow.com/questions/tagged/citus)
|
||||||
|
@ -31,7 +31,7 @@ You can use these Citus superpowers to make your Postgres database scale-out rea
|
||||||
|
|
||||||
Our [SIGMOD '21](https://2021.sigmod.org/) paper [Citus: Distributed PostgreSQL for Data-Intensive Applications](https://doi.org/10.1145/3448016.3457551) gives a more detailed look into what Citus is, how it works, and why it works that way.
|
Our [SIGMOD '21](https://2021.sigmod.org/) paper [Citus: Distributed PostgreSQL for Data-Intensive Applications](https://doi.org/10.1145/3448016.3457551) gives a more detailed look into what Citus is, how it works, and why it works that way.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
Since Citus is an extension to Postgres, you can use Citus with the latest Postgres versions. And Citus works seamlessly with the PostgreSQL tools and extensions you are already familiar with.
|
Since Citus is an extension to Postgres, you can use Citus with the latest Postgres versions. And Citus works seamlessly with the PostgreSQL tools and extensions you are already familiar with.
|
||||||
|
|
||||||
|
@ -95,14 +95,14 @@ Install packages on Ubuntu / Debian:
|
||||||
```bash
|
```bash
|
||||||
curl https://install.citusdata.com/community/deb.sh > add-citus-repo.sh
|
curl https://install.citusdata.com/community/deb.sh > add-citus-repo.sh
|
||||||
sudo bash add-citus-repo.sh
|
sudo bash add-citus-repo.sh
|
||||||
sudo apt-get -y install postgresql-15-citus-12.0
|
sudo apt-get -y install postgresql-17-citus-13.0
|
||||||
```
|
```
|
||||||
|
|
||||||
Install packages on CentOS / Red Hat:
|
Install packages on Red Hat:
|
||||||
```bash
|
```bash
|
||||||
curl https://install.citusdata.com/community/rpm.sh > add-citus-repo.sh
|
curl https://install.citusdata.com/community/rpm.sh > add-citus-repo.sh
|
||||||
sudo bash add-citus-repo.sh
|
sudo bash add-citus-repo.sh
|
||||||
sudo yum install -y citus120_15
|
sudo yum install -y citus130_17
|
||||||
```
|
```
|
||||||
|
|
||||||
To add Citus to your local PostgreSQL database, add the following to `postgresql.conf`:
|
To add Citus to your local PostgreSQL database, add the following to `postgresql.conf`:
|
||||||
|
@ -423,12 +423,14 @@ A Citus database cluster grows from a single PostgreSQL node into a cluster by a
|
||||||
|
|
||||||
Data in distributed tables is stored in “shards”, which are actually just regular PostgreSQL tables on the worker nodes. When querying a distributed table on the coordinator node, Citus will send regular SQL queries to the worker nodes. That way, all the usual PostgreSQL optimizations and extensions can automatically be used with Citus.
|
Data in distributed tables is stored in “shards”, which are actually just regular PostgreSQL tables on the worker nodes. When querying a distributed table on the coordinator node, Citus will send regular SQL queries to the worker nodes. That way, all the usual PostgreSQL optimizations and extensions can automatically be used with Citus.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
When you send a query in which all (co-located) distributed tables have the same filter on the distribution column, Citus will automatically detect that and send the whole query to the worker node that stores the data. That way, arbitrarily complex queries are supported with minimal routing overhead, which is especially useful for scaling transactional workloads. If queries do not have a specific filter, each shard is queried in parallel, which is especially useful in analytical workloads. The Citus distributed executor is adaptive and is designed to handle both query types at the same time on the same system under high concurrency, which enables large-scale mixed workloads.
|
When you send a query in which all (co-located) distributed tables have the same filter on the distribution column, Citus will automatically detect that and send the whole query to the worker node that stores the data. That way, arbitrarily complex queries are supported with minimal routing overhead, which is especially useful for scaling transactional workloads. If queries do not have a specific filter, each shard is queried in parallel, which is especially useful in analytical workloads. The Citus distributed executor is adaptive and is designed to handle both query types at the same time on the same system under high concurrency, which enables large-scale mixed workloads.
|
||||||
|
|
||||||
The schema and metadata of distributed tables and reference tables are automatically synchronized to all the nodes in the cluster. That way, you can connect to any node to run distributed queries. Schema changes and cluster administration still need to go through the coordinator.
|
The schema and metadata of distributed tables and reference tables are automatically synchronized to all the nodes in the cluster. That way, you can connect to any node to run distributed queries. Schema changes and cluster administration still need to go through the coordinator.
|
||||||
|
|
||||||
|
Detailed descriptions of the implementation for Citus developers are provided in the [Citus Technical Documentation](src/backend/distributed/README.md).
|
||||||
|
|
||||||
## When to use Citus
|
## When to use Citus
|
||||||
|
|
||||||
Citus is uniquely capable of scaling both analytical and transactional workloads with up to petabytes of data. Use cases in which Citus is commonly used:
|
Citus is uniquely capable of scaling both analytical and transactional workloads with up to petabytes of data. Use cases in which Citus is commonly used:
|
||||||
|
@ -438,21 +440,21 @@ Citus is uniquely capable of scaling both analytical and transactional workloads
|
||||||
|
|
||||||
The advanced parallel, distributed query engine in Citus combined with PostgreSQL features such as [array types](https://www.postgresql.org/docs/current/arrays.html), [JSONB](https://www.postgresql.org/docs/current/datatype-json.html), [lateral joins](https://heap.io/blog/engineering/postgresqls-powerful-new-join-type-lateral), and extensions like [HyperLogLog](https://github.com/citusdata/postgresql-hll) and [TopN](https://github.com/citusdata/postgresql-topn) allow you to build responsive analytics dashboards no matter how many customers or how much data you have.
|
The advanced parallel, distributed query engine in Citus combined with PostgreSQL features such as [array types](https://www.postgresql.org/docs/current/arrays.html), [JSONB](https://www.postgresql.org/docs/current/datatype-json.html), [lateral joins](https://heap.io/blog/engineering/postgresqls-powerful-new-join-type-lateral), and extensions like [HyperLogLog](https://github.com/citusdata/postgresql-hll) and [TopN](https://github.com/citusdata/postgresql-topn) allow you to build responsive analytics dashboards no matter how many customers or how much data you have.
|
||||||
|
|
||||||
Example real-time analytics users: [Algolia](https://www.citusdata.com/customers/algolia), [Heap](https://www.citusdata.com/customers/heap)
|
Example real-time analytics users: [Algolia](https://www.citusdata.com/customers/algolia)
|
||||||
|
|
||||||
- **[Time series data](http://docs.citusdata.com/en/stable/use_cases/timeseries.html)**:
|
- **[Time series data](http://docs.citusdata.com/en/stable/use_cases/timeseries.html)**:
|
||||||
Citus enables you to process and analyze very large amounts of time series data. The biggest Citus clusters store well over a petabyte of time series data and ingest terabytes per day.
|
Citus enables you to process and analyze very large amounts of time series data. The biggest Citus clusters store well over a petabyte of time series data and ingest terabytes per day.
|
||||||
|
|
||||||
Citus integrates seamlessly with [Postgres table partitioning](https://www.postgresql.org/docs/current/ddl-partitioning.html) and has [built-in functions for partitioning by time](https://www.citusdata.com/blog/2021/10/22/how-to-scale-postgres-for-time-series-data-with-citus/), which can speed up queries and writes on time series tables. You can take advantage of Citus’s parallel, distributed query engine for fast analytical queries, and use the built-in *columnar storage* to compress old partitions.
|
Citus integrates seamlessly with [Postgres table partitioning](https://www.postgresql.org/docs/current/ddl-partitioning.html) and has [built-in functions for partitioning by time](https://www.citusdata.com/blog/2021/10/22/how-to-scale-postgres-for-time-series-data-with-citus/), which can speed up queries and writes on time series tables. You can take advantage of Citus’s parallel, distributed query engine for fast analytical queries, and use the built-in *columnar storage* to compress old partitions.
|
||||||
|
|
||||||
Example users: [MixRank](https://www.citusdata.com/customers/mixrank), [Windows team](https://techcommunity.microsoft.com/t5/azure-database-for-postgresql/architecting-petabyte-scale-analytics-by-scaling-out-postgres-on/ba-p/969685)
|
Example users: [MixRank](https://www.citusdata.com/customers/mixrank)
|
||||||
|
|
||||||
- **[Software-as-a-service (SaaS) applications](http://docs.citusdata.com/en/stable/use_cases/multi_tenant.html)**:
|
- **[Software-as-a-service (SaaS) applications](http://docs.citusdata.com/en/stable/use_cases/multi_tenant.html)**:
|
||||||
SaaS and other multi-tenant applications need to be able to scale their database as the number of tenants/customers grows. Citus enables you to transparently shard a complex data model by the tenant dimension, so your database can grow along with your business.
|
SaaS and other multi-tenant applications need to be able to scale their database as the number of tenants/customers grows. Citus enables you to transparently shard a complex data model by the tenant dimension, so your database can grow along with your business.
|
||||||
|
|
||||||
By distributing tables along a tenant ID column and co-locating data for the same tenant, Citus can horizontally scale complex (tenant-scoped) queries, transactions, and foreign key graphs. Reference tables and distributed DDL commands make database management a breeze compared to manual sharding. On top of that, you have a built-in distributed query engine for doing cross-tenant analytics inside the database.
|
By distributing tables along a tenant ID column and co-locating data for the same tenant, Citus can horizontally scale complex (tenant-scoped) queries, transactions, and foreign key graphs. Reference tables and distributed DDL commands make database management a breeze compared to manual sharding. On top of that, you have a built-in distributed query engine for doing cross-tenant analytics inside the database.
|
||||||
|
|
||||||
Example multi-tenant SaaS users: [Copper](https://www.citusdata.com/customers/copper), [Salesloft](https://fivetran.com/case-studies/replicating-sharded-databases-a-case-study-of-salesloft-citus-data-and-fivetran), [ConvertFlow](https://www.citusdata.com/customers/convertflow)
|
Example multi-tenant SaaS users: [Salesloft](https://fivetran.com/case-studies/replicating-sharded-databases-a-case-study-of-salesloft-citus-data-and-fivetran), [ConvertFlow](https://www.citusdata.com/customers/convertflow)
|
||||||
|
|
||||||
- **[Microservices](https://docs.citusdata.com/en/stable/get_started/tutorial_microservices.html)**: Citus supports schema based sharding, which allows distributing regular database schemas across many machines. This sharding methodology fits nicely with typical Microservices architecture, where storage is fully owned by the service hence can’t share the same schema definition with other tenants. Citus allows distributing horizontally scalable state across services, solving one of the [main problems](https://stackoverflow.blog/2020/11/23/the-macro-problem-with-microservices/) of microservices.
|
- **[Microservices](https://docs.citusdata.com/en/stable/get_started/tutorial_microservices.html)**: Citus supports schema based sharding, which allows distributing regular database schemas across many machines. This sharding methodology fits nicely with typical Microservices architecture, where storage is fully owned by the service hence can’t share the same schema definition with other tenants. Citus allows distributing horizontally scalable state across services, solving one of the [main problems](https://stackoverflow.blog/2020/11/23/the-macro-problem-with-microservices/) of microservices.
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,160 @@
|
||||||
|
# Coding style
|
||||||
|
|
||||||
|
The existing code-style in our code-base is not super consistent. There are multiple reasons for that. One big reason is because our code-base is relatively old and our standards have changed over time. The second big reason is that our style-guide is different from style-guide of Postgres and some code is copied from Postgres source code and is slightly modified. The below rules are for new code. If you're changing existing code that uses a different style, use your best judgement to decide if you use the rules here or if you match the existing style.
|
||||||
|
|
||||||
|
## Using citus_indent
|
||||||
|
|
||||||
|
CI pipeline will automatically reject any PRs which do not follow our coding
|
||||||
|
conventions. The easiest way to ensure your PR adheres to those conventions is
|
||||||
|
to use the [citus_indent](https://github.com/citusdata/tools/tree/develop/uncrustify)
|
||||||
|
tool. This tool uses `uncrustify` under the hood.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Uncrustify changes the way it formats code every release a bit. To make sure
|
||||||
|
# everyone formats consistently we use version 0.68.1:
|
||||||
|
curl -L https://github.com/uncrustify/uncrustify/archive/uncrustify-0.68.1.tar.gz | tar xz
|
||||||
|
cd uncrustify-uncrustify-0.68.1/
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake ..
|
||||||
|
make -j5
|
||||||
|
sudo make install
|
||||||
|
cd ../..
|
||||||
|
|
||||||
|
git clone https://github.com/citusdata/tools.git
|
||||||
|
cd tools
|
||||||
|
make uncrustify/.install
|
||||||
|
```
|
||||||
|
|
||||||
|
Once you've done that, you can run the `make reindent` command from the top
|
||||||
|
directory to recursively check and correct the style of any source files in the
|
||||||
|
current directory. Under the hood, `make reindent` will run `citus_indent` and
|
||||||
|
some other style corrections for you.
|
||||||
|
|
||||||
|
You can also run the following in the directory of this repository to
|
||||||
|
automatically format all the files that you have changed before committing:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cat > .git/hooks/pre-commit << __EOF__
|
||||||
|
#!/bin/bash
|
||||||
|
citus_indent --check --diff || { citus_indent --diff; exit 1; }
|
||||||
|
__EOF__
|
||||||
|
chmod +x .git/hooks/pre-commit
|
||||||
|
```
|
||||||
|
|
||||||
|
## Other rules we follow that citus_indent does not enforce
|
||||||
|
|
||||||
|
* We almost always use **CamelCase**, when naming functions, variables etc., **not snake_case**.
|
||||||
|
|
||||||
|
* We also have the habits of using a **lowerCamelCase** for some variables named from their type or from their function name, as shown in the examples:
|
||||||
|
|
||||||
|
```c
|
||||||
|
bool IsCitusExtensionLoaded = false;
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
IsAlterTableRenameStmt(RenameStmt *renameStmt)
|
||||||
|
{
|
||||||
|
AlterTableCmd *alterTableCommand = NULL;
|
||||||
|
..
|
||||||
|
..
|
||||||
|
|
||||||
|
bool isAlterTableRenameStmt = false;
|
||||||
|
..
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
* We **start functions with a comment**:
|
||||||
|
|
||||||
|
```c
|
||||||
|
/*
|
||||||
|
* MyNiceFunction <something in present simple tense, e.g., processes / returns / checks / takes X as input / does Y> ..
|
||||||
|
* <some more nice words> ..
|
||||||
|
* <some more nice words> ..
|
||||||
|
*/
|
||||||
|
<static?> <return type>
|
||||||
|
MyNiceFunction(..)
|
||||||
|
{
|
||||||
|
..
|
||||||
|
..
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
* `#includes` needs to be sorted based on below ordering and then alphabetically and we should not include what we don't need in a file:
|
||||||
|
|
||||||
|
* System includes (eg. #include<...>)
|
||||||
|
* Postgres.h (eg. #include "postgres.h")
|
||||||
|
* Toplevel imports from postgres, not contained in a directory (eg. #include "miscadmin.h")
|
||||||
|
* General postgres includes (eg . #include "nodes/...")
|
||||||
|
* Toplevel citus includes, not contained in a directory (eg. #include "citus_verion.h")
|
||||||
|
* Columnar includes (eg. #include "columnar/...")
|
||||||
|
* Distributed includes (eg. #include "distributed/...")
|
||||||
|
|
||||||
|
* Comments:
|
||||||
|
```c
|
||||||
|
/* single line comments start with a lower-case */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We start multi-line comments with a capital letter
|
||||||
|
* and keep adding a star to the beginning of each line
|
||||||
|
* until we close the comment with a star and a slash.
|
||||||
|
*/
|
||||||
|
```
|
||||||
|
|
||||||
|
* Order of function implementations and their declarations in a file:
|
||||||
|
|
||||||
|
We define static functions after the functions that call them. For example:
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include<..>
|
||||||
|
#include<..>
|
||||||
|
..
|
||||||
|
..
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
..
|
||||||
|
..
|
||||||
|
} MyNiceStruct;
|
||||||
|
..
|
||||||
|
..
|
||||||
|
PG_FUNCTION_INFO_V1(my_nice_udf1);
|
||||||
|
PG_FUNCTION_INFO_V1(my_nice_udf2);
|
||||||
|
..
|
||||||
|
..
|
||||||
|
// .. somewhere on top of the file …
|
||||||
|
static void MyNiceStaticlyDeclaredFunction1(…);
|
||||||
|
static void MyNiceStaticlyDeclaredFunction2(…);
|
||||||
|
..
|
||||||
|
..
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
MyNiceFunctionExternedViaHeaderFile(..)
|
||||||
|
{
|
||||||
|
..
|
||||||
|
..
|
||||||
|
MyNiceStaticlyDeclaredFunction1(..);
|
||||||
|
..
|
||||||
|
..
|
||||||
|
MyNiceStaticlyDeclaredFunction2(..);
|
||||||
|
..
|
||||||
|
}
|
||||||
|
|
||||||
|
..
|
||||||
|
..
|
||||||
|
|
||||||
|
// we define this first because it's called by MyNiceFunctionExternedViaHeaderFile()
|
||||||
|
// before MyNiceStaticlyDeclaredFunction2()
|
||||||
|
static void
|
||||||
|
MyNiceStaticlyDeclaredFunction1(…)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
..
|
||||||
|
..
|
||||||
|
|
||||||
|
// then we define this
|
||||||
|
static void
|
||||||
|
MyNiceStaticlyDeclaredFunction2(…)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
```
|
15
ci/README.md
|
@ -385,3 +385,18 @@ definitions are in alphabetical order.
|
||||||
## `print_stack_trace.sh`
|
## `print_stack_trace.sh`
|
||||||
|
|
||||||
This script prints stack traces for failed tests, if they left core files.
|
This script prints stack traces for failed tests, if they left core files.
|
||||||
|
|
||||||
|
## `sort_and_group_includes.sh`
|
||||||
|
|
||||||
|
This script checks and fixes issues with include grouping and sorting in C files.
|
||||||
|
|
||||||
|
Includes are grouped in the following groups:
|
||||||
|
- System includes (eg. `#include <math>`)
|
||||||
|
- Postgres.h include (eg. `#include "postgres.h"`)
|
||||||
|
- Toplevel postgres includes (includes not in a directory eg. `#include "miscadmin.h`)
|
||||||
|
- Postgres includes in a directory (eg. `#include "catalog/pg_type.h"`)
|
||||||
|
- Toplevel citus includes (includes not in a directory eg. `#include "pg_version_constants.h"`)
|
||||||
|
- Columnar includes (eg. `#include "columnar/columnar.h"`)
|
||||||
|
- Distributed includes (eg. `#include "distributed/maintenanced.h"`)
|
||||||
|
|
||||||
|
Within every group the include lines are sorted alphabetically.
|
||||||
|
|
|
@ -15,9 +15,6 @@ PG_MAJOR=${PG_MAJOR:?please provide the postgres major version}
|
||||||
codename=${VERSION#*(}
|
codename=${VERSION#*(}
|
||||||
codename=${codename%)*}
|
codename=${codename%)*}
|
||||||
|
|
||||||
# get project from argument
|
|
||||||
project="${CIRCLE_PROJECT_REPONAME}"
|
|
||||||
|
|
||||||
# we'll do everything with absolute paths
|
# we'll do everything with absolute paths
|
||||||
basedir="$(pwd)"
|
basedir="$(pwd)"
|
||||||
|
|
||||||
|
@ -28,7 +25,7 @@ build_ext() {
|
||||||
pg_major="$1"
|
pg_major="$1"
|
||||||
|
|
||||||
builddir="${basedir}/build-${pg_major}"
|
builddir="${basedir}/build-${pg_major}"
|
||||||
echo "Beginning build of ${project} for PostgreSQL ${pg_major}..." >&2
|
echo "Beginning build for PostgreSQL ${pg_major}..." >&2
|
||||||
|
|
||||||
# do everything in a subdirectory to avoid clutter in current directory
|
# do everything in a subdirectory to avoid clutter in current directory
|
||||||
mkdir -p "${builddir}" && cd "${builddir}"
|
mkdir -p "${builddir}" && cd "${builddir}"
|
||||||
|
|
|
@ -14,8 +14,8 @@ ci_scripts=$(
|
||||||
grep -v -E '^(ci_helpers.sh|fix_style.sh)$'
|
grep -v -E '^(ci_helpers.sh|fix_style.sh)$'
|
||||||
)
|
)
|
||||||
for script in $ci_scripts; do
|
for script in $ci_scripts; do
|
||||||
if ! grep "\\bci/$script\\b" .circleci/config.yml > /dev/null; then
|
if ! grep "\\bci/$script\\b" -r .github > /dev/null; then
|
||||||
echo "ERROR: CI script with name \"$script\" is not actually used in .circleci/config.yml"
|
echo "ERROR: CI script with name \"$script\" is not actually used in .github folder"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
if ! grep "^## \`$script\`\$" ci/README.md > /dev/null; then
|
if ! grep "^## \`$script\`\$" ci/README.md > /dev/null; then
|
||||||
|
|
|
@ -1,96 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Testing this script locally requires you to set the following environment
|
|
||||||
# variables:
|
|
||||||
# CIRCLE_BRANCH, GIT_USERNAME and GIT_TOKEN
|
|
||||||
|
|
||||||
# fail if trying to reference a variable that is not set.
|
|
||||||
set -u
|
|
||||||
# exit immediately if a command fails
|
|
||||||
set -e
|
|
||||||
# Fail on pipe failures
|
|
||||||
set -o pipefail
|
|
||||||
|
|
||||||
PR_BRANCH="${CIRCLE_BRANCH}"
|
|
||||||
ENTERPRISE_REMOTE="https://${GIT_USERNAME}:${GIT_TOKEN}@github.com/citusdata/citus-enterprise"
|
|
||||||
|
|
||||||
# shellcheck disable=SC1091
|
|
||||||
source ci/ci_helpers.sh
|
|
||||||
|
|
||||||
# List executed commands. This is done so debugging this script is easier when
|
|
||||||
# it fails. It's explicitly done after git remote add so username and password
|
|
||||||
# are not shown in CI output (even though it's also filtered out by CircleCI)
|
|
||||||
set -x
|
|
||||||
|
|
||||||
check_compile () {
|
|
||||||
echo "INFO: checking if merged code can be compiled"
|
|
||||||
./configure --without-libcurl
|
|
||||||
make -j10
|
|
||||||
}
|
|
||||||
|
|
||||||
# Clone current git repo (which should be community) to a temporary working
|
|
||||||
# directory and go there
|
|
||||||
GIT_DIR_ROOT="$(git rev-parse --show-toplevel)"
|
|
||||||
TMP_GIT_DIR="$(mktemp --directory -t citus-merge-check.XXXXXXXXX)"
|
|
||||||
git clone "$GIT_DIR_ROOT" "$TMP_GIT_DIR"
|
|
||||||
cd "$TMP_GIT_DIR"
|
|
||||||
|
|
||||||
# Fails in CI without this
|
|
||||||
git config user.email "citus-bot@microsoft.com"
|
|
||||||
git config user.name "citus bot"
|
|
||||||
|
|
||||||
# Disable "set -x" temporarily, because $ENTERPRISE_REMOTE contains passwords
|
|
||||||
{ set +x ; } 2> /dev/null
|
|
||||||
git remote add enterprise "$ENTERPRISE_REMOTE"
|
|
||||||
set -x
|
|
||||||
|
|
||||||
git remote set-url --push enterprise no-pushing
|
|
||||||
|
|
||||||
# Fetch enterprise-master
|
|
||||||
git fetch enterprise enterprise-master
|
|
||||||
|
|
||||||
|
|
||||||
git checkout "enterprise/enterprise-master"
|
|
||||||
|
|
||||||
if git merge --no-commit "origin/$PR_BRANCH"; then
|
|
||||||
echo "INFO: community PR branch could be merged into enterprise-master"
|
|
||||||
# check that we can compile after the merge
|
|
||||||
if check_compile; then
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "WARN: Failed to compile after community PR branch was merged into enterprise"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# undo partial merge
|
|
||||||
git merge --abort
|
|
||||||
|
|
||||||
# If we have a conflict on enterprise merge on the master branch, we have a problem.
|
|
||||||
# Provide an error message to indicate that enterprise merge is needed to fix this check.
|
|
||||||
if [[ $PR_BRANCH = master ]]; then
|
|
||||||
echo "ERROR: Master branch has merge conflicts with enterprise-master."
|
|
||||||
echo "Try re-running this CI job after merging your changes into enterprise-master."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! git fetch enterprise "$PR_BRANCH" ; then
|
|
||||||
echo "ERROR: enterprise/$PR_BRANCH was not found and community PR branch could not be merged into enterprise-master"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Show the top commit of the enterprise PR branch to make debugging easier
|
|
||||||
git log -n 1 "enterprise/$PR_BRANCH"
|
|
||||||
|
|
||||||
# Check that this branch contains the top commit of the current community PR
|
|
||||||
# branch. If it does not it means it's not up to date with the current PR, so
|
|
||||||
# the enterprise branch should be updated.
|
|
||||||
if ! git merge-base --is-ancestor "origin/$PR_BRANCH" "enterprise/$PR_BRANCH" ; then
|
|
||||||
echo "ERROR: enterprise/$PR_BRANCH is not up to date with community PR branch"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Now check if we can merge the enterprise PR into enterprise-master without
|
|
||||||
# issues.
|
|
||||||
git merge --no-commit "enterprise/$PR_BRANCH"
|
|
||||||
# check that we can compile after the merge
|
|
||||||
check_compile
|
|
|
@ -4,7 +4,22 @@ set -euo pipefail
|
||||||
# shellcheck disable=SC1091
|
# shellcheck disable=SC1091
|
||||||
source ci/ci_helpers.sh
|
source ci/ci_helpers.sh
|
||||||
|
|
||||||
# extract citus gucs in the form of "citus.X"
|
# Find the line that exactly matches "RegisterCitusConfigVariables(void)" in
|
||||||
grep -o -E "(\.*\"citus.\w+\")," src/backend/distributed/shared_library_init.c > gucs.out
|
# shared_library_init.c. grep command returns something like
|
||||||
sort -c gucs.out
|
# "934:RegisterCitusConfigVariables(void)" and we extract the line number
|
||||||
|
# with cut.
|
||||||
|
RegisterCitusConfigVariables_begin_linenumber=$(grep -n "^RegisterCitusConfigVariables(void)$" src/backend/distributed/shared_library_init.c | cut -d: -f1)
|
||||||
|
|
||||||
|
# Consider the lines starting from $RegisterCitusConfigVariables_begin_linenumber,
|
||||||
|
# grep the first line that starts with "}" and extract the line number with cut
|
||||||
|
# as in the previous step.
|
||||||
|
RegisterCitusConfigVariables_length=$(tail -n +$RegisterCitusConfigVariables_begin_linenumber src/backend/distributed/shared_library_init.c | grep -n -m 1 "^}$" | cut -d: -f1)
|
||||||
|
|
||||||
|
# extract the function definition of RegisterCitusConfigVariables into a temp file
|
||||||
|
tail -n +$RegisterCitusConfigVariables_begin_linenumber src/backend/distributed/shared_library_init.c | head -n $(($RegisterCitusConfigVariables_length)) > RegisterCitusConfigVariables_func_def.out
|
||||||
|
|
||||||
|
# extract citus gucs in the form of <tab><tab>"citus.X"
|
||||||
|
grep -P "^[\t][\t]\"citus\.[a-zA-Z_0-9]+\"" RegisterCitusConfigVariables_func_def.out > gucs.out
|
||||||
|
LC_COLLATE=C sort -c gucs.out
|
||||||
rm gucs.out
|
rm gucs.out
|
||||||
|
rm RegisterCitusConfigVariables_func_def.out
|
||||||
|
|
|
@ -19,3 +19,4 @@ ci/disallow_long_changelog_entries.sh
|
||||||
ci/normalize_expected.sh
|
ci/normalize_expected.sh
|
||||||
ci/fix_gitignore.sh
|
ci/fix_gitignore.sh
|
||||||
ci/print_stack_trace.sh
|
ci/print_stack_trace.sh
|
||||||
|
ci/sort_and_group_includes.sh
|
||||||
|
|
|
@ -0,0 +1,157 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
easy command line to run against all citus-style checked files:
|
||||||
|
|
||||||
|
$ git ls-files \
|
||||||
|
| git check-attr --stdin citus-style \
|
||||||
|
| grep 'citus-style: set' \
|
||||||
|
| awk '{print $1}' \
|
||||||
|
| cut -d':' -f1 \
|
||||||
|
| xargs -n1 ./ci/include_grouping.py
|
||||||
|
"""
|
||||||
|
|
||||||
|
import collections
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def main(args):
|
||||||
|
if len(args) < 2:
|
||||||
|
print("Usage: include_grouping.py <file>")
|
||||||
|
return
|
||||||
|
|
||||||
|
file = args[1]
|
||||||
|
if not os.path.isfile(file):
|
||||||
|
sys.exit(f"File '{file}' does not exist")
|
||||||
|
|
||||||
|
with open(file, "r") as in_file:
|
||||||
|
with open(file + ".tmp", "w") as out_file:
|
||||||
|
includes = []
|
||||||
|
skipped_lines = []
|
||||||
|
|
||||||
|
# This calls print_sorted_includes on a set of consecutive #include lines.
|
||||||
|
# This implicitly keeps separation of any #include lines that are contained in
|
||||||
|
# an #ifdef, because it will order the #include lines inside and after the
|
||||||
|
# #ifdef completely separately.
|
||||||
|
for line in in_file:
|
||||||
|
# if a line starts with #include we don't want to print it yet, instead we
|
||||||
|
# want to collect all consecutive #include lines
|
||||||
|
if line.startswith("#include"):
|
||||||
|
includes.append(line)
|
||||||
|
skipped_lines = []
|
||||||
|
continue
|
||||||
|
|
||||||
|
# if we have collected any #include lines, we want to print them sorted
|
||||||
|
# before printing the current line. However, if the current line is empty
|
||||||
|
# we want to perform a lookahead to see if the next line is an #include.
|
||||||
|
# To maintain any separation between #include lines and their subsequent
|
||||||
|
# lines we keep track of all lines we have skipped inbetween.
|
||||||
|
if len(includes) > 0:
|
||||||
|
if len(line.strip()) == 0:
|
||||||
|
skipped_lines.append(line)
|
||||||
|
continue
|
||||||
|
|
||||||
|
# we have includes that need to be grouped before printing the current
|
||||||
|
# line.
|
||||||
|
print_sorted_includes(includes, file=out_file)
|
||||||
|
includes = []
|
||||||
|
|
||||||
|
# print any skipped lines
|
||||||
|
print("".join(skipped_lines), end="", file=out_file)
|
||||||
|
skipped_lines = []
|
||||||
|
|
||||||
|
print(line, end="", file=out_file)
|
||||||
|
|
||||||
|
# move out_file to file
|
||||||
|
os.rename(file + ".tmp", file)
|
||||||
|
|
||||||
|
|
||||||
|
def print_sorted_includes(includes, file=sys.stdout):
|
||||||
|
default_group_key = 1
|
||||||
|
groups = collections.defaultdict(set)
|
||||||
|
|
||||||
|
# define the groups that we separate correctly. The matchers are tested in the order
|
||||||
|
# of their priority field. The first matcher that matches the include is used to
|
||||||
|
# assign the include to a group.
|
||||||
|
# The groups are printed in the order of their group_key.
|
||||||
|
matchers = [
|
||||||
|
{
|
||||||
|
"name": "system includes",
|
||||||
|
"matcher": lambda x: x.startswith("<"),
|
||||||
|
"group_key": -2,
|
||||||
|
"priority": 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "toplevel postgres includes",
|
||||||
|
"matcher": lambda x: "/" not in x,
|
||||||
|
"group_key": 0,
|
||||||
|
"priority": 9,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "postgres.h",
|
||||||
|
"matcher": lambda x: x.strip() in ['"postgres.h"'],
|
||||||
|
"group_key": -1,
|
||||||
|
"priority": -1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "toplevel citus inlcudes",
|
||||||
|
"matcher": lambda x: x.strip()
|
||||||
|
in [
|
||||||
|
'"citus_version.h"',
|
||||||
|
'"pg_version_compat.h"',
|
||||||
|
'"pg_version_constants.h"',
|
||||||
|
],
|
||||||
|
"group_key": 3,
|
||||||
|
"priority": 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "columnar includes",
|
||||||
|
"matcher": lambda x: x.startswith('"columnar/'),
|
||||||
|
"group_key": 4,
|
||||||
|
"priority": 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "distributed includes",
|
||||||
|
"matcher": lambda x: x.startswith('"distributed/'),
|
||||||
|
"group_key": 5,
|
||||||
|
"priority": 1,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
matchers.sort(key=lambda x: x["priority"])
|
||||||
|
|
||||||
|
# throughout our codebase we have some includes where either postgres or citus
|
||||||
|
# includes are wrongfully included with the syntax for system includes. Before we
|
||||||
|
# try to match those we will change the <> to "" to make them match our system. This
|
||||||
|
# will also rewrite the include to the correct syntax.
|
||||||
|
common_system_include_error_prefixes = ["<nodes/", "<distributed/"]
|
||||||
|
|
||||||
|
# assign every include to a group
|
||||||
|
for include in includes:
|
||||||
|
# extract the group key from the include
|
||||||
|
include_content = include.split(" ")[1]
|
||||||
|
|
||||||
|
# fix common system includes which are secretly postgres or citus includes
|
||||||
|
for common_prefix in common_system_include_error_prefixes:
|
||||||
|
if include_content.startswith(common_prefix):
|
||||||
|
include_content = '"' + include_content.strip()[1:-1] + '"'
|
||||||
|
include = include.split(" ")[0] + " " + include_content + "\n"
|
||||||
|
break
|
||||||
|
|
||||||
|
group_key = default_group_key
|
||||||
|
for matcher in matchers:
|
||||||
|
if matcher["matcher"](include_content):
|
||||||
|
group_key = matcher["group_key"]
|
||||||
|
break
|
||||||
|
|
||||||
|
groups[group_key].add(include)
|
||||||
|
|
||||||
|
# iterate over all groups in the natural order of its keys
|
||||||
|
for i, group in enumerate(sorted(groups.items())):
|
||||||
|
if i > 0:
|
||||||
|
print(file=file)
|
||||||
|
includes = group[1]
|
||||||
|
print("".join(sorted(includes)), end="", file=file)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main(sys.argv)
|
|
@ -0,0 +1,12 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
# shellcheck disable=SC1091
|
||||||
|
source ci/ci_helpers.sh
|
||||||
|
|
||||||
|
git ls-files \
|
||||||
|
| git check-attr --stdin citus-style \
|
||||||
|
| grep 'citus-style: set' \
|
||||||
|
| awk '{print $1}' \
|
||||||
|
| cut -d':' -f1 \
|
||||||
|
| xargs -n1 ./ci/include_grouping.py
|
|
@ -1,6 +1,6 @@
|
||||||
#! /bin/sh
|
#! /bin/sh
|
||||||
# Guess values for system-dependent variables and create Makefiles.
|
# Guess values for system-dependent variables and create Makefiles.
|
||||||
# Generated by GNU Autoconf 2.69 for Citus 12.1devel.
|
# Generated by GNU Autoconf 2.69 for Citus 13.2devel.
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
|
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
|
||||||
|
@ -579,8 +579,8 @@ MAKEFLAGS=
|
||||||
# Identity of this package.
|
# Identity of this package.
|
||||||
PACKAGE_NAME='Citus'
|
PACKAGE_NAME='Citus'
|
||||||
PACKAGE_TARNAME='citus'
|
PACKAGE_TARNAME='citus'
|
||||||
PACKAGE_VERSION='12.1devel'
|
PACKAGE_VERSION='13.2devel'
|
||||||
PACKAGE_STRING='Citus 12.1devel'
|
PACKAGE_STRING='Citus 13.2devel'
|
||||||
PACKAGE_BUGREPORT=''
|
PACKAGE_BUGREPORT=''
|
||||||
PACKAGE_URL=''
|
PACKAGE_URL=''
|
||||||
|
|
||||||
|
@ -1262,7 +1262,7 @@ if test "$ac_init_help" = "long"; then
|
||||||
# Omit some internal or obsolete options to make the list less imposing.
|
# Omit some internal or obsolete options to make the list less imposing.
|
||||||
# This message is too long to be a string in the A/UX 3.1 sh.
|
# This message is too long to be a string in the A/UX 3.1 sh.
|
||||||
cat <<_ACEOF
|
cat <<_ACEOF
|
||||||
\`configure' configures Citus 12.1devel to adapt to many kinds of systems.
|
\`configure' configures Citus 13.2devel to adapt to many kinds of systems.
|
||||||
|
|
||||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||||
|
|
||||||
|
@ -1324,7 +1324,7 @@ fi
|
||||||
|
|
||||||
if test -n "$ac_init_help"; then
|
if test -n "$ac_init_help"; then
|
||||||
case $ac_init_help in
|
case $ac_init_help in
|
||||||
short | recursive ) echo "Configuration of Citus 12.1devel:";;
|
short | recursive ) echo "Configuration of Citus 13.2devel:";;
|
||||||
esac
|
esac
|
||||||
cat <<\_ACEOF
|
cat <<\_ACEOF
|
||||||
|
|
||||||
|
@ -1429,7 +1429,7 @@ fi
|
||||||
test -n "$ac_init_help" && exit $ac_status
|
test -n "$ac_init_help" && exit $ac_status
|
||||||
if $ac_init_version; then
|
if $ac_init_version; then
|
||||||
cat <<\_ACEOF
|
cat <<\_ACEOF
|
||||||
Citus configure 12.1devel
|
Citus configure 13.2devel
|
||||||
generated by GNU Autoconf 2.69
|
generated by GNU Autoconf 2.69
|
||||||
|
|
||||||
Copyright (C) 2012 Free Software Foundation, Inc.
|
Copyright (C) 2012 Free Software Foundation, Inc.
|
||||||
|
@ -1912,7 +1912,7 @@ cat >config.log <<_ACEOF
|
||||||
This file contains any messages produced by compilers while
|
This file contains any messages produced by compilers while
|
||||||
running configure, to aid debugging if configure makes a mistake.
|
running configure, to aid debugging if configure makes a mistake.
|
||||||
|
|
||||||
It was created by Citus $as_me 12.1devel, which was
|
It was created by Citus $as_me 13.2devel, which was
|
||||||
generated by GNU Autoconf 2.69. Invocation command line was
|
generated by GNU Autoconf 2.69. Invocation command line was
|
||||||
|
|
||||||
$ $0 $@
|
$ $0 $@
|
||||||
|
@ -2588,7 +2588,7 @@ fi
|
||||||
if test "$with_pg_version_check" = no; then
|
if test "$with_pg_version_check" = no; then
|
||||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: building against PostgreSQL $version_num (skipped compatibility check)" >&5
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: building against PostgreSQL $version_num (skipped compatibility check)" >&5
|
||||||
$as_echo "$as_me: building against PostgreSQL $version_num (skipped compatibility check)" >&6;}
|
$as_echo "$as_me: building against PostgreSQL $version_num (skipped compatibility check)" >&6;}
|
||||||
elif test "$version_num" != '14' -a "$version_num" != '15' -a "$version_num" != '16'; then
|
elif test "$version_num" != '15' -a "$version_num" != '16' -a "$version_num" != '17'; then
|
||||||
as_fn_error $? "Citus is not compatible with the detected PostgreSQL version ${version_num}." "$LINENO" 5
|
as_fn_error $? "Citus is not compatible with the detected PostgreSQL version ${version_num}." "$LINENO" 5
|
||||||
else
|
else
|
||||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: building against PostgreSQL $version_num" >&5
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: building against PostgreSQL $version_num" >&5
|
||||||
|
@ -5393,7 +5393,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
|
||||||
# report actual input values of CONFIG_FILES etc. instead of their
|
# report actual input values of CONFIG_FILES etc. instead of their
|
||||||
# values after options handling.
|
# values after options handling.
|
||||||
ac_log="
|
ac_log="
|
||||||
This file was extended by Citus $as_me 12.1devel, which was
|
This file was extended by Citus $as_me 13.2devel, which was
|
||||||
generated by GNU Autoconf 2.69. Invocation command line was
|
generated by GNU Autoconf 2.69. Invocation command line was
|
||||||
|
|
||||||
CONFIG_FILES = $CONFIG_FILES
|
CONFIG_FILES = $CONFIG_FILES
|
||||||
|
@ -5455,7 +5455,7 @@ _ACEOF
|
||||||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||||
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
|
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
|
||||||
ac_cs_version="\\
|
ac_cs_version="\\
|
||||||
Citus config.status 12.1devel
|
Citus config.status 13.2devel
|
||||||
configured by $0, generated by GNU Autoconf 2.69,
|
configured by $0, generated by GNU Autoconf 2.69,
|
||||||
with options \\"\$ac_cs_config\\"
|
with options \\"\$ac_cs_config\\"
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
# everyone needing autoconf installed, the resulting files are checked
|
# everyone needing autoconf installed, the resulting files are checked
|
||||||
# into the SCM.
|
# into the SCM.
|
||||||
|
|
||||||
AC_INIT([Citus], [12.1devel])
|
AC_INIT([Citus], [13.2devel])
|
||||||
AC_COPYRIGHT([Copyright (c) Citus Data, Inc.])
|
AC_COPYRIGHT([Copyright (c) Citus Data, Inc.])
|
||||||
|
|
||||||
# we'll need sed and awk for some of the version commands
|
# we'll need sed and awk for some of the version commands
|
||||||
|
@ -80,7 +80,7 @@ AC_SUBST(with_pg_version_check)
|
||||||
|
|
||||||
if test "$with_pg_version_check" = no; then
|
if test "$with_pg_version_check" = no; then
|
||||||
AC_MSG_NOTICE([building against PostgreSQL $version_num (skipped compatibility check)])
|
AC_MSG_NOTICE([building against PostgreSQL $version_num (skipped compatibility check)])
|
||||||
elif test "$version_num" != '14' -a "$version_num" != '15' -a "$version_num" != '16'; then
|
elif test "$version_num" != '15' -a "$version_num" != '16' -a "$version_num" != '17'; then
|
||||||
AC_MSG_ERROR([Citus is not compatible with the detected PostgreSQL version ${version_num}.])
|
AC_MSG_ERROR([Citus is not compatible with the detected PostgreSQL version ${version_num}.])
|
||||||
else
|
else
|
||||||
AC_MSG_NOTICE([building against PostgreSQL $version_num])
|
AC_MSG_NOTICE([building against PostgreSQL $version_num])
|
||||||
|
|
After Width: | Height: | Size: 95 KiB |
Before Width: | Height: | Size: 94 KiB After Width: | Height: | Size: 94 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 102 KiB |
After Width: | Height: | Size: 29 KiB |
After Width: | Height: | Size: 69 KiB |
After Width: | Height: | Size: 111 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 168 KiB |
|
@ -1,6 +1,6 @@
|
||||||
# Columnar extension
|
# Columnar extension
|
||||||
comment = 'Citus Columnar extension'
|
comment = 'Citus Columnar extension'
|
||||||
default_version = '11.3-1'
|
default_version = '12.2-1'
|
||||||
module_pathname = '$libdir/citus_columnar'
|
module_pathname = '$libdir/citus_columnar'
|
||||||
relocatable = false
|
relocatable = false
|
||||||
schema = pg_catalog
|
schema = pg_catalog
|
||||||
|
|
|
@ -11,16 +11,18 @@
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "postgres.h"
|
|
||||||
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "postgres.h"
|
||||||
|
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
|
|
||||||
#include "utils/guc.h"
|
#include "utils/guc.h"
|
||||||
#include "utils/rel.h"
|
#include "utils/rel.h"
|
||||||
|
|
||||||
#include "citus_version.h"
|
#include "citus_version.h"
|
||||||
|
|
||||||
#include "columnar/columnar.h"
|
#include "columnar/columnar.h"
|
||||||
#include "columnar/columnar_tableam.h"
|
#include "columnar/columnar_tableam.h"
|
||||||
|
|
||||||
|
|
|
@ -13,12 +13,13 @@
|
||||||
*/
|
*/
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
#include "citus_version.h"
|
|
||||||
#include "common/pg_lzcompress.h"
|
#include "common/pg_lzcompress.h"
|
||||||
#include "lib/stringinfo.h"
|
#include "lib/stringinfo.h"
|
||||||
|
|
||||||
|
#include "citus_version.h"
|
||||||
|
#include "pg_version_constants.h"
|
||||||
|
|
||||||
#include "columnar/columnar_compression.h"
|
#include "columnar/columnar_compression.h"
|
||||||
#include "distributed/pg_version_constants.h"
|
|
||||||
|
|
||||||
#if HAVE_CITUS_LIBLZ4
|
#if HAVE_CITUS_LIBLZ4
|
||||||
#include <lz4.h>
|
#include <lz4.h>
|
||||||
|
|
|
@ -10,18 +10,17 @@
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "citus_version.h"
|
#include <math.h>
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
#include <math.h>
|
#include "miscadmin.h"
|
||||||
|
|
||||||
#include "access/amapi.h"
|
#include "access/amapi.h"
|
||||||
#include "access/skey.h"
|
#include "access/skey.h"
|
||||||
#include "catalog/pg_am.h"
|
#include "catalog/pg_am.h"
|
||||||
#include "catalog/pg_statistic.h"
|
#include "catalog/pg_statistic.h"
|
||||||
#include "commands/defrem.h"
|
#include "commands/defrem.h"
|
||||||
#include "miscadmin.h"
|
|
||||||
#include "nodes/extensible.h"
|
#include "nodes/extensible.h"
|
||||||
#include "nodes/makefuncs.h"
|
#include "nodes/makefuncs.h"
|
||||||
#include "nodes/nodeFuncs.h"
|
#include "nodes/nodeFuncs.h"
|
||||||
|
@ -44,10 +43,13 @@
|
||||||
#include "utils/selfuncs.h"
|
#include "utils/selfuncs.h"
|
||||||
#include "utils/spccache.h"
|
#include "utils/spccache.h"
|
||||||
|
|
||||||
|
#include "citus_version.h"
|
||||||
|
|
||||||
#include "columnar/columnar.h"
|
#include "columnar/columnar.h"
|
||||||
#include "columnar/columnar_customscan.h"
|
#include "columnar/columnar_customscan.h"
|
||||||
#include "columnar/columnar_metadata.h"
|
#include "columnar/columnar_metadata.h"
|
||||||
#include "columnar/columnar_tableam.h"
|
#include "columnar/columnar_tableam.h"
|
||||||
|
|
||||||
#include "distributed/listutils.h"
|
#include "distributed/listutils.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -361,7 +363,7 @@ ColumnarGetRelationInfoHook(PlannerInfo *root, Oid relationObjectId,
|
||||||
|
|
||||||
/* disable index-only scan */
|
/* disable index-only scan */
|
||||||
IndexOptInfo *indexOptInfo = NULL;
|
IndexOptInfo *indexOptInfo = NULL;
|
||||||
foreach_ptr(indexOptInfo, rel->indexlist)
|
foreach_declared_ptr(indexOptInfo, rel->indexlist)
|
||||||
{
|
{
|
||||||
memset(indexOptInfo->canreturn, false, indexOptInfo->ncolumns * sizeof(bool));
|
memset(indexOptInfo->canreturn, false, indexOptInfo->ncolumns * sizeof(bool));
|
||||||
}
|
}
|
||||||
|
@ -379,7 +381,7 @@ RemovePathsByPredicate(RelOptInfo *rel, PathPredicate removePathPredicate)
|
||||||
List *filteredPathList = NIL;
|
List *filteredPathList = NIL;
|
||||||
|
|
||||||
Path *path = NULL;
|
Path *path = NULL;
|
||||||
foreach_ptr(path, rel->pathlist)
|
foreach_declared_ptr(path, rel->pathlist)
|
||||||
{
|
{
|
||||||
if (!removePathPredicate(path))
|
if (!removePathPredicate(path))
|
||||||
{
|
{
|
||||||
|
@ -426,7 +428,7 @@ static void
|
||||||
CostColumnarPaths(PlannerInfo *root, RelOptInfo *rel, Oid relationId)
|
CostColumnarPaths(PlannerInfo *root, RelOptInfo *rel, Oid relationId)
|
||||||
{
|
{
|
||||||
Path *path = NULL;
|
Path *path = NULL;
|
||||||
foreach_ptr(path, rel->pathlist)
|
foreach_declared_ptr(path, rel->pathlist)
|
||||||
{
|
{
|
||||||
if (IsA(path, IndexPath))
|
if (IsA(path, IndexPath))
|
||||||
{
|
{
|
||||||
|
@ -781,7 +783,7 @@ ExtractPushdownClause(PlannerInfo *root, RelOptInfo *rel, Node *node)
|
||||||
List *pushdownableArgs = NIL;
|
List *pushdownableArgs = NIL;
|
||||||
|
|
||||||
Node *boolExprArg = NULL;
|
Node *boolExprArg = NULL;
|
||||||
foreach_ptr(boolExprArg, boolExpr->args)
|
foreach_declared_ptr(boolExprArg, boolExpr->args)
|
||||||
{
|
{
|
||||||
Expr *pushdownableArg = ExtractPushdownClause(root, rel,
|
Expr *pushdownableArg = ExtractPushdownClause(root, rel,
|
||||||
(Node *) boolExprArg);
|
(Node *) boolExprArg);
|
||||||
|
@ -1049,6 +1051,15 @@ FindCandidateRelids(PlannerInfo *root, RelOptInfo *rel, List *joinClauses)
|
||||||
|
|
||||||
candidateRelids = bms_del_members(candidateRelids, rel->relids);
|
candidateRelids = bms_del_members(candidateRelids, rel->relids);
|
||||||
candidateRelids = bms_del_members(candidateRelids, rel->lateral_relids);
|
candidateRelids = bms_del_members(candidateRelids, rel->lateral_relids);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For the relevant PG16 commit requiring this addition:
|
||||||
|
* postgres/postgres@2489d76
|
||||||
|
*/
|
||||||
|
#if PG_VERSION_NUM >= PG_VERSION_16
|
||||||
|
candidateRelids = bms_del_members(candidateRelids, root->outer_join_rels);
|
||||||
|
#endif
|
||||||
|
|
||||||
return candidateRelids;
|
return candidateRelids;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1310,11 +1321,8 @@ AddColumnarScanPath(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte,
|
||||||
|
|
||||||
cpath->methods = &ColumnarScanPathMethods;
|
cpath->methods = &ColumnarScanPathMethods;
|
||||||
|
|
||||||
#if (PG_VERSION_NUM >= PG_VERSION_15)
|
|
||||||
|
|
||||||
/* necessary to avoid extra Result node in PG15 */
|
/* necessary to avoid extra Result node in PG15 */
|
||||||
cpath->flags = CUSTOMPATH_SUPPORT_PROJECTION;
|
cpath->flags = CUSTOMPATH_SUPPORT_PROJECTION;
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* populate generic path information
|
* populate generic path information
|
||||||
|
@ -1548,7 +1556,7 @@ ColumnarPerStripeScanCost(RelOptInfo *rel, Oid relationId, int numberOfColumnsRe
|
||||||
uint32 maxColumnCount = 0;
|
uint32 maxColumnCount = 0;
|
||||||
uint64 totalStripeSize = 0;
|
uint64 totalStripeSize = 0;
|
||||||
StripeMetadata *stripeMetadata = NULL;
|
StripeMetadata *stripeMetadata = NULL;
|
||||||
foreach_ptr(stripeMetadata, stripeList)
|
foreach_declared_ptr(stripeMetadata, stripeList)
|
||||||
{
|
{
|
||||||
totalStripeSize += stripeMetadata->dataLength;
|
totalStripeSize += stripeMetadata->dataLength;
|
||||||
maxColumnCount = Max(maxColumnCount, stripeMetadata->columnCount);
|
maxColumnCount = Max(maxColumnCount, stripeMetadata->columnCount);
|
||||||
|
@ -1922,11 +1930,6 @@ ColumnarScan_EndCustomScan(CustomScanState *node)
|
||||||
*/
|
*/
|
||||||
TableScanDesc scanDesc = node->ss.ss_currentScanDesc;
|
TableScanDesc scanDesc = node->ss.ss_currentScanDesc;
|
||||||
|
|
||||||
/*
|
|
||||||
* Free the exprcontext
|
|
||||||
*/
|
|
||||||
ExecFreeExprContext(&node->ss.ps);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* clean out the tuple table
|
* clean out the tuple table
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -11,12 +11,12 @@
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
#include "funcapi.h"
|
#include "funcapi.h"
|
||||||
|
#include "miscadmin.h"
|
||||||
|
|
||||||
#include "access/nbtree.h"
|
#include "access/nbtree.h"
|
||||||
#include "access/table.h"
|
#include "access/table.h"
|
||||||
#include "catalog/pg_am.h"
|
#include "catalog/pg_am.h"
|
||||||
#include "catalog/pg_type.h"
|
#include "catalog/pg_type.h"
|
||||||
#include "distributed/pg_version_constants.h"
|
|
||||||
#include "miscadmin.h"
|
|
||||||
#include "storage/fd.h"
|
#include "storage/fd.h"
|
||||||
#include "storage/smgr.h"
|
#include "storage/smgr.h"
|
||||||
#include "utils/guc.h"
|
#include "utils/guc.h"
|
||||||
|
@ -25,6 +25,8 @@
|
||||||
#include "utils/tuplestore.h"
|
#include "utils/tuplestore.h"
|
||||||
|
|
||||||
#include "pg_version_compat.h"
|
#include "pg_version_compat.h"
|
||||||
|
#include "pg_version_constants.h"
|
||||||
|
|
||||||
#include "columnar/columnar.h"
|
#include "columnar/columnar.h"
|
||||||
#include "columnar/columnar_storage.h"
|
#include "columnar/columnar_storage.h"
|
||||||
#include "columnar/columnar_version_compat.h"
|
#include "columnar/columnar_version_compat.h"
|
||||||
|
|
|
@ -19,48 +19,51 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
|
#include "miscadmin.h"
|
||||||
|
#include "port.h"
|
||||||
#include "safe_lib.h"
|
#include "safe_lib.h"
|
||||||
|
|
||||||
#include "citus_version.h"
|
|
||||||
#include "columnar/columnar.h"
|
|
||||||
#include "columnar/columnar_storage.h"
|
|
||||||
#include "columnar/columnar_version_compat.h"
|
|
||||||
#include "distributed/listutils.h"
|
|
||||||
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include "access/heapam.h"
|
#include "access/heapam.h"
|
||||||
#include "access/htup_details.h"
|
#include "access/htup_details.h"
|
||||||
#include "access/nbtree.h"
|
#include "access/nbtree.h"
|
||||||
#include "access/xact.h"
|
#include "access/xact.h"
|
||||||
#include "catalog/indexing.h"
|
#include "catalog/indexing.h"
|
||||||
#include "catalog/pg_namespace.h"
|
|
||||||
#include "catalog/pg_collation.h"
|
|
||||||
#include "catalog/pg_type.h"
|
|
||||||
#include "catalog/namespace.h"
|
#include "catalog/namespace.h"
|
||||||
|
#include "catalog/pg_collation.h"
|
||||||
|
#include "catalog/pg_namespace.h"
|
||||||
|
#include "catalog/pg_type.h"
|
||||||
#include "commands/defrem.h"
|
#include "commands/defrem.h"
|
||||||
#include "commands/sequence.h"
|
#include "commands/sequence.h"
|
||||||
#include "commands/trigger.h"
|
#include "commands/trigger.h"
|
||||||
#include "executor/executor.h"
|
#include "executor/executor.h"
|
||||||
#include "executor/spi.h"
|
#include "executor/spi.h"
|
||||||
#include "miscadmin.h"
|
|
||||||
#include "nodes/execnodes.h"
|
|
||||||
#include "lib/stringinfo.h"
|
#include "lib/stringinfo.h"
|
||||||
#if PG_VERSION_NUM >= PG_VERSION_16
|
#include "nodes/execnodes.h"
|
||||||
#include "parser/parse_relation.h"
|
|
||||||
#endif
|
|
||||||
#include "port.h"
|
|
||||||
#include "storage/fd.h"
|
#include "storage/fd.h"
|
||||||
#include "storage/lmgr.h"
|
#include "storage/lmgr.h"
|
||||||
#include "storage/procarray.h"
|
#include "storage/procarray.h"
|
||||||
#include "storage/smgr.h"
|
#include "storage/smgr.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "utils/fmgroids.h"
|
#include "utils/fmgroids.h"
|
||||||
#include "utils/memutils.h"
|
|
||||||
#include "utils/lsyscache.h"
|
#include "utils/lsyscache.h"
|
||||||
|
#include "utils/memutils.h"
|
||||||
#include "utils/rel.h"
|
#include "utils/rel.h"
|
||||||
|
|
||||||
|
#include "citus_version.h"
|
||||||
|
#include "pg_version_constants.h"
|
||||||
|
|
||||||
|
#include "columnar/columnar.h"
|
||||||
|
#include "columnar/columnar_storage.h"
|
||||||
|
#include "columnar/columnar_version_compat.h"
|
||||||
|
|
||||||
|
#include "distributed/listutils.h"
|
||||||
|
|
||||||
#if PG_VERSION_NUM >= PG_VERSION_16
|
#if PG_VERSION_NUM >= PG_VERSION_16
|
||||||
|
#include "parser/parse_relation.h"
|
||||||
#include "storage/relfilelocator.h"
|
#include "storage/relfilelocator.h"
|
||||||
#include "utils/relfilenumbermap.h"
|
#include "utils/relfilenumbermap.h"
|
||||||
#else
|
#else
|
||||||
|
@ -1682,7 +1685,7 @@ DeleteTupleAndEnforceConstraints(ModifyState *state, HeapTuple heapTuple)
|
||||||
simple_heap_delete(state->rel, tid);
|
simple_heap_delete(state->rel, tid);
|
||||||
|
|
||||||
/* execute AFTER ROW DELETE Triggers to enforce constraints */
|
/* execute AFTER ROW DELETE Triggers to enforce constraints */
|
||||||
ExecARDeleteTriggers_compat(estate, resultRelInfo, tid, NULL, NULL, false);
|
ExecARDeleteTriggers(estate, resultRelInfo, tid, NULL, NULL, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2038,7 +2041,7 @@ GetHighestUsedRowNumber(uint64 storageId)
|
||||||
List *stripeMetadataList = ReadDataFileStripeList(storageId,
|
List *stripeMetadataList = ReadDataFileStripeList(storageId,
|
||||||
GetTransactionSnapshot());
|
GetTransactionSnapshot());
|
||||||
StripeMetadata *stripeMetadata = NULL;
|
StripeMetadata *stripeMetadata = NULL;
|
||||||
foreach_ptr(stripeMetadata, stripeMetadataList)
|
foreach_declared_ptr(stripeMetadata, stripeMetadataList)
|
||||||
{
|
{
|
||||||
highestRowNumber = Max(highestRowNumber,
|
highestRowNumber = Max(highestRowNumber,
|
||||||
StripeGetHighestRowNumber(stripeMetadata));
|
StripeGetHighestRowNumber(stripeMetadata));
|
||||||
|
|
|
@ -22,16 +22,15 @@
|
||||||
#include "access/xact.h"
|
#include "access/xact.h"
|
||||||
#include "catalog/pg_am.h"
|
#include "catalog/pg_am.h"
|
||||||
#include "commands/defrem.h"
|
#include "commands/defrem.h"
|
||||||
#include "distributed/listutils.h"
|
|
||||||
#include "nodes/makefuncs.h"
|
#include "nodes/makefuncs.h"
|
||||||
#include "nodes/nodeFuncs.h"
|
#include "nodes/nodeFuncs.h"
|
||||||
#include "optimizer/optimizer.h"
|
|
||||||
#include "optimizer/clauses.h"
|
#include "optimizer/clauses.h"
|
||||||
|
#include "optimizer/optimizer.h"
|
||||||
#include "optimizer/restrictinfo.h"
|
#include "optimizer/restrictinfo.h"
|
||||||
#include "storage/fd.h"
|
#include "storage/fd.h"
|
||||||
#include "utils/guc.h"
|
#include "utils/guc.h"
|
||||||
#include "utils/memutils.h"
|
|
||||||
#include "utils/lsyscache.h"
|
#include "utils/lsyscache.h"
|
||||||
|
#include "utils/memutils.h"
|
||||||
#include "utils/rel.h"
|
#include "utils/rel.h"
|
||||||
|
|
||||||
#include "columnar/columnar.h"
|
#include "columnar/columnar.h"
|
||||||
|
@ -39,6 +38,8 @@
|
||||||
#include "columnar/columnar_tableam.h"
|
#include "columnar/columnar_tableam.h"
|
||||||
#include "columnar/columnar_version_compat.h"
|
#include "columnar/columnar_version_compat.h"
|
||||||
|
|
||||||
|
#include "distributed/listutils.h"
|
||||||
|
|
||||||
#define UNEXPECTED_STRIPE_READ_ERR_MSG \
|
#define UNEXPECTED_STRIPE_READ_ERR_MSG \
|
||||||
"attempted to read an unexpected stripe while reading columnar " \
|
"attempted to read an unexpected stripe while reading columnar " \
|
||||||
"table %s, stripe with id=" UINT64_FORMAT " is not flushed"
|
"table %s, stripe with id=" UINT64_FORMAT " is not flushed"
|
||||||
|
@ -879,7 +880,7 @@ ReadChunkGroupNextRow(ChunkGroupReadState *chunkGroupReadState, Datum *columnVal
|
||||||
memset(columnNulls, true, sizeof(bool) * chunkGroupReadState->columnCount);
|
memset(columnNulls, true, sizeof(bool) * chunkGroupReadState->columnCount);
|
||||||
|
|
||||||
int attno;
|
int attno;
|
||||||
foreach_int(attno, chunkGroupReadState->projectedColumnList)
|
foreach_declared_int(attno, chunkGroupReadState->projectedColumnList)
|
||||||
{
|
{
|
||||||
const ChunkData *chunkGroupData = chunkGroupReadState->chunkGroupData;
|
const ChunkData *chunkGroupData = chunkGroupReadState->chunkGroupData;
|
||||||
const int rowIndex = chunkGroupReadState->currentRow;
|
const int rowIndex = chunkGroupReadState->currentRow;
|
||||||
|
@ -1488,7 +1489,7 @@ ProjectedColumnMask(uint32 columnCount, List *projectedColumnList)
|
||||||
bool *projectedColumnMask = palloc0(columnCount * sizeof(bool));
|
bool *projectedColumnMask = palloc0(columnCount * sizeof(bool));
|
||||||
int attno;
|
int attno;
|
||||||
|
|
||||||
foreach_int(attno, projectedColumnList)
|
foreach_declared_int(attno, projectedColumnList)
|
||||||
{
|
{
|
||||||
/* attno is 1-indexed; projectedColumnMask is 0-indexed */
|
/* attno is 1-indexed; projectedColumnMask is 0-indexed */
|
||||||
int columnIndex = attno - 1;
|
int columnIndex = attno - 1;
|
||||||
|
|
|
@ -36,11 +36,11 @@
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
|
#include "miscadmin.h"
|
||||||
#include "safe_lib.h"
|
#include "safe_lib.h"
|
||||||
|
|
||||||
#include "access/generic_xlog.h"
|
#include "access/generic_xlog.h"
|
||||||
#include "catalog/storage.h"
|
#include "catalog/storage.h"
|
||||||
#include "miscadmin.h"
|
|
||||||
#include "storage/bufmgr.h"
|
#include "storage/bufmgr.h"
|
||||||
#include "storage/lmgr.h"
|
#include "storage/lmgr.h"
|
||||||
|
|
||||||
|
|
|
@ -1,42 +1,38 @@
|
||||||
#include "citus_version.h"
|
#include <math.h>
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
|
#include "pgstat.h"
|
||||||
|
#include "safe_lib.h"
|
||||||
|
|
||||||
|
#include "access/detoast.h"
|
||||||
#include "access/genam.h"
|
#include "access/genam.h"
|
||||||
#include "access/heapam.h"
|
#include "access/heapam.h"
|
||||||
#include "access/multixact.h"
|
#include "access/multixact.h"
|
||||||
#include "access/rewriteheap.h"
|
#include "access/rewriteheap.h"
|
||||||
#include "access/tableam.h"
|
#include "access/tableam.h"
|
||||||
#include "access/tsmapi.h"
|
#include "access/tsmapi.h"
|
||||||
#include "access/detoast.h"
|
|
||||||
#include "access/xact.h"
|
#include "access/xact.h"
|
||||||
#include "catalog/catalog.h"
|
#include "catalog/catalog.h"
|
||||||
#include "catalog/index.h"
|
#include "catalog/index.h"
|
||||||
#include "catalog/namespace.h"
|
#include "catalog/namespace.h"
|
||||||
#include "catalog/objectaccess.h"
|
#include "catalog/objectaccess.h"
|
||||||
#include "catalog/pg_am.h"
|
#include "catalog/pg_am.h"
|
||||||
|
#include "catalog/pg_extension.h"
|
||||||
#include "catalog/pg_publication.h"
|
#include "catalog/pg_publication.h"
|
||||||
#include "catalog/pg_trigger.h"
|
#include "catalog/pg_trigger.h"
|
||||||
#include "catalog/pg_extension.h"
|
|
||||||
#include "catalog/storage.h"
|
#include "catalog/storage.h"
|
||||||
#include "catalog/storage_xlog.h"
|
#include "catalog/storage_xlog.h"
|
||||||
#include "commands/defrem.h"
|
#include "commands/defrem.h"
|
||||||
|
#include "commands/extension.h"
|
||||||
#include "commands/progress.h"
|
#include "commands/progress.h"
|
||||||
#include "commands/vacuum.h"
|
#include "commands/vacuum.h"
|
||||||
#include "commands/extension.h"
|
|
||||||
#include "executor/executor.h"
|
#include "executor/executor.h"
|
||||||
#include "nodes/makefuncs.h"
|
#include "nodes/makefuncs.h"
|
||||||
#include "optimizer/plancat.h"
|
#include "optimizer/plancat.h"
|
||||||
#include "pg_version_compat.h"
|
|
||||||
#include "pgstat.h"
|
|
||||||
#include "safe_lib.h"
|
|
||||||
#include "storage/bufmgr.h"
|
#include "storage/bufmgr.h"
|
||||||
#include "storage/bufpage.h"
|
#include "storage/bufpage.h"
|
||||||
#include "storage/bufmgr.h"
|
|
||||||
#include "storage/lmgr.h"
|
#include "storage/lmgr.h"
|
||||||
#include "storage/predicate.h"
|
#include "storage/predicate.h"
|
||||||
#include "storage/procarray.h"
|
#include "storage/procarray.h"
|
||||||
|
@ -44,17 +40,22 @@
|
||||||
#include "tcop/utility.h"
|
#include "tcop/utility.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "utils/fmgroids.h"
|
#include "utils/fmgroids.h"
|
||||||
|
#include "utils/lsyscache.h"
|
||||||
#include "utils/memutils.h"
|
#include "utils/memutils.h"
|
||||||
#include "utils/pg_rusage.h"
|
#include "utils/pg_rusage.h"
|
||||||
#include "utils/rel.h"
|
#include "utils/rel.h"
|
||||||
#include "utils/relcache.h"
|
#include "utils/relcache.h"
|
||||||
#include "utils/lsyscache.h"
|
|
||||||
#include "utils/syscache.h"
|
#include "utils/syscache.h"
|
||||||
|
|
||||||
|
#include "citus_version.h"
|
||||||
|
#include "pg_version_compat.h"
|
||||||
|
|
||||||
#include "columnar/columnar.h"
|
#include "columnar/columnar.h"
|
||||||
#include "columnar/columnar_customscan.h"
|
#include "columnar/columnar_customscan.h"
|
||||||
#include "columnar/columnar_storage.h"
|
#include "columnar/columnar_storage.h"
|
||||||
#include "columnar/columnar_tableam.h"
|
#include "columnar/columnar_tableam.h"
|
||||||
#include "columnar/columnar_version_compat.h"
|
#include "columnar/columnar_version_compat.h"
|
||||||
|
|
||||||
#include "distributed/listutils.h"
|
#include "distributed/listutils.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -876,7 +877,7 @@ columnar_relation_set_new_filelocator(Relation rel,
|
||||||
|
|
||||||
*freezeXid = RecentXmin;
|
*freezeXid = RecentXmin;
|
||||||
*minmulti = GetOldestMultiXactId();
|
*minmulti = GetOldestMultiXactId();
|
||||||
SMgrRelation srel = RelationCreateStorage_compat(*newrlocator, persistence, true);
|
SMgrRelation srel = RelationCreateStorage(*newrlocator, persistence, true);
|
||||||
|
|
||||||
ColumnarStorageInit(srel, ColumnarMetadataNewStorageId());
|
ColumnarStorageInit(srel, ColumnarMetadataNewStorageId());
|
||||||
InitColumnarOptions(rel->rd_id);
|
InitColumnarOptions(rel->rd_id);
|
||||||
|
@ -1423,15 +1424,32 @@ ConditionalLockRelationWithTimeout(Relation rel, LOCKMODE lockMode, int timeout,
|
||||||
|
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
columnar_scan_analyze_next_block(TableScanDesc scan, BlockNumber blockno,
|
columnar_scan_analyze_next_block(TableScanDesc scan,
|
||||||
|
#if PG_VERSION_NUM >= PG_VERSION_17
|
||||||
|
ReadStream *stream)
|
||||||
|
#else
|
||||||
|
BlockNumber blockno,
|
||||||
BufferAccessStrategy bstrategy)
|
BufferAccessStrategy bstrategy)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Our access method is not pages based, i.e. tuples are not confined
|
* Our access method is not pages based, i.e. tuples are not confined
|
||||||
* to pages boundaries. So not much to do here. We return true anyway
|
* to pages boundaries. So not much to do here. We return true anyway
|
||||||
* so acquire_sample_rows() in analyze.c would call our
|
* so acquire_sample_rows() in analyze.c would call our
|
||||||
* columnar_scan_analyze_next_tuple() callback.
|
* columnar_scan_analyze_next_tuple() callback.
|
||||||
|
* In PG17, we return false in case there is no buffer left, since
|
||||||
|
* the outer loop changed in acquire_sample_rows(), and it is
|
||||||
|
* expected for the scan_analyze_next_block function to check whether
|
||||||
|
* there are any blocks left in the block sampler.
|
||||||
*/
|
*/
|
||||||
|
#if PG_VERSION_NUM >= PG_VERSION_17
|
||||||
|
Buffer buf = read_stream_next_buffer(stream, NULL);
|
||||||
|
if (!BufferIsValid(buf))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ReleaseBuffer(buf);
|
||||||
|
#endif
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2227,7 +2245,6 @@ ColumnarProcessAlterTable(AlterTableStmt *alterTableStmt, List **columnarOptions
|
||||||
columnarRangeVar = alterTableStmt->relation;
|
columnarRangeVar = alterTableStmt->relation;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if PG_VERSION_NUM >= PG_VERSION_15
|
|
||||||
else if (alterTableCmd->subtype == AT_SetAccessMethod)
|
else if (alterTableCmd->subtype == AT_SetAccessMethod)
|
||||||
{
|
{
|
||||||
if (columnarRangeVar || *columnarOptions)
|
if (columnarRangeVar || *columnarOptions)
|
||||||
|
@ -2238,14 +2255,15 @@ ColumnarProcessAlterTable(AlterTableStmt *alterTableStmt, List **columnarOptions
|
||||||
"Specify SET ACCESS METHOD before storage parameters, or use separate ALTER TABLE commands.")));
|
"Specify SET ACCESS METHOD before storage parameters, or use separate ALTER TABLE commands.")));
|
||||||
}
|
}
|
||||||
|
|
||||||
destIsColumnar = (strcmp(alterTableCmd->name, COLUMNAR_AM_NAME) == 0);
|
destIsColumnar = (strcmp(alterTableCmd->name ? alterTableCmd->name :
|
||||||
|
default_table_access_method,
|
||||||
|
COLUMNAR_AM_NAME) == 0);
|
||||||
|
|
||||||
if (srcIsColumnar && !destIsColumnar)
|
if (srcIsColumnar && !destIsColumnar)
|
||||||
{
|
{
|
||||||
DeleteColumnarTableOptions(RelationGetRelid(rel), true);
|
DeleteColumnarTableOptions(RelationGetRelid(rel), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* PG_VERSION_15 */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
relation_close(rel, NoLock);
|
relation_close(rel, NoLock);
|
||||||
|
@ -2629,21 +2647,12 @@ ColumnarCheckLogicalReplication(Relation rel)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if PG_VERSION_NUM >= PG_VERSION_15
|
|
||||||
{
|
{
|
||||||
PublicationDesc pubdesc;
|
PublicationDesc pubdesc;
|
||||||
|
|
||||||
RelationBuildPublicationDesc(rel, &pubdesc);
|
RelationBuildPublicationDesc(rel, &pubdesc);
|
||||||
pubActionInsert = pubdesc.pubactions.pubinsert;
|
pubActionInsert = pubdesc.pubactions.pubinsert;
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
if (rel->rd_pubactions == NULL)
|
|
||||||
{
|
|
||||||
GetRelationPublicationActions(rel);
|
|
||||||
Assert(rel->rd_pubactions != NULL);
|
|
||||||
}
|
|
||||||
pubActionInsert = rel->rd_pubactions->pubinsert;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (pubActionInsert)
|
if (pubActionInsert)
|
||||||
{
|
{
|
||||||
|
@ -2945,7 +2954,7 @@ MajorVersionsCompatibleColumnar(char *leftVersion, char *rightVersion)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
rightComparisionLimit = strlen(leftVersion);
|
rightComparisionLimit = strlen(rightVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* we can error out early if hypens are not in the same position */
|
/* we can error out early if hypens are not in the same position */
|
||||||
|
@ -3020,6 +3029,8 @@ AvailableExtensionVersionColumnar(void)
|
||||||
|
|
||||||
ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
||||||
errmsg("citus extension is not found")));
|
errmsg("citus extension is not found")));
|
||||||
|
|
||||||
|
return NULL; /* keep compiler happy */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -3082,7 +3093,7 @@ DefElem *
|
||||||
GetExtensionOption(List *extensionOptions, const char *defname)
|
GetExtensionOption(List *extensionOptions, const char *defname)
|
||||||
{
|
{
|
||||||
DefElem *defElement = NULL;
|
DefElem *defElement = NULL;
|
||||||
foreach_ptr(defElement, extensionOptions)
|
foreach_declared_ptr(defElement, extensionOptions)
|
||||||
{
|
{
|
||||||
if (IsA(defElement, DefElem) &&
|
if (IsA(defElement, DefElem) &&
|
||||||
strncmp(defElement->defname, defname, NAMEDATALEN) == 0)
|
strncmp(defElement->defname, defname, NAMEDATALEN) == 0)
|
||||||
|
|
|
@ -16,18 +16,25 @@
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
|
#include "miscadmin.h"
|
||||||
#include "safe_lib.h"
|
#include "safe_lib.h"
|
||||||
|
|
||||||
#include "access/heapam.h"
|
#include "access/heapam.h"
|
||||||
#include "access/nbtree.h"
|
#include "access/nbtree.h"
|
||||||
#include "catalog/pg_am.h"
|
#include "catalog/pg_am.h"
|
||||||
#include "miscadmin.h"
|
|
||||||
#include "pg_version_compat.h"
|
|
||||||
#include "storage/fd.h"
|
#include "storage/fd.h"
|
||||||
#include "storage/smgr.h"
|
#include "storage/smgr.h"
|
||||||
#include "utils/guc.h"
|
#include "utils/guc.h"
|
||||||
#include "utils/memutils.h"
|
#include "utils/memutils.h"
|
||||||
#include "utils/rel.h"
|
#include "utils/rel.h"
|
||||||
|
|
||||||
|
#include "pg_version_compat.h"
|
||||||
|
#include "pg_version_constants.h"
|
||||||
|
|
||||||
|
#include "columnar/columnar.h"
|
||||||
|
#include "columnar/columnar_storage.h"
|
||||||
|
#include "columnar/columnar_version_compat.h"
|
||||||
|
|
||||||
#if PG_VERSION_NUM >= PG_VERSION_16
|
#if PG_VERSION_NUM >= PG_VERSION_16
|
||||||
#include "storage/relfilelocator.h"
|
#include "storage/relfilelocator.h"
|
||||||
#include "utils/relfilenumbermap.h"
|
#include "utils/relfilenumbermap.h"
|
||||||
|
@ -35,10 +42,6 @@
|
||||||
#include "utils/relfilenodemap.h"
|
#include "utils/relfilenodemap.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "columnar/columnar.h"
|
|
||||||
#include "columnar/columnar_storage.h"
|
|
||||||
#include "columnar/columnar_version_compat.h"
|
|
||||||
|
|
||||||
struct ColumnarWriteState
|
struct ColumnarWriteState
|
||||||
{
|
{
|
||||||
TupleDesc tupleDescriptor;
|
TupleDesc tupleDescriptor;
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
-- citus_columnar--11.3-1--12.2-1
|
|
@ -0,0 +1 @@
|
||||||
|
-- citus_columnar--12.2-1--11.3-1
|
|
@ -1,21 +1,17 @@
|
||||||
|
|
||||||
#include "citus_version.h"
|
|
||||||
|
|
||||||
#include "postgres.h"
|
|
||||||
#include "columnar/columnar.h"
|
|
||||||
|
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
|
#include "postgres.h"
|
||||||
|
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
|
#include "pgstat.h"
|
||||||
|
|
||||||
#include "access/genam.h"
|
#include "access/genam.h"
|
||||||
#include "access/heapam.h"
|
#include "access/heapam.h"
|
||||||
|
#include "access/heaptoast.h"
|
||||||
#include "access/multixact.h"
|
#include "access/multixact.h"
|
||||||
#include "access/rewriteheap.h"
|
#include "access/rewriteheap.h"
|
||||||
#include "access/tsmapi.h"
|
#include "access/tsmapi.h"
|
||||||
#include "access/heaptoast.h"
|
|
||||||
#include "common/hashfn.h"
|
|
||||||
#include "access/xact.h"
|
#include "access/xact.h"
|
||||||
#include "catalog/catalog.h"
|
#include "catalog/catalog.h"
|
||||||
#include "catalog/index.h"
|
#include "catalog/index.h"
|
||||||
|
@ -26,14 +22,12 @@
|
||||||
#include "catalog/storage_xlog.h"
|
#include "catalog/storage_xlog.h"
|
||||||
#include "commands/progress.h"
|
#include "commands/progress.h"
|
||||||
#include "commands/vacuum.h"
|
#include "commands/vacuum.h"
|
||||||
|
#include "common/hashfn.h"
|
||||||
#include "executor/executor.h"
|
#include "executor/executor.h"
|
||||||
#include "nodes/makefuncs.h"
|
#include "nodes/makefuncs.h"
|
||||||
#include "optimizer/plancat.h"
|
#include "optimizer/plancat.h"
|
||||||
#include "pg_version_compat.h"
|
|
||||||
#include "pgstat.h"
|
|
||||||
#include "storage/bufmgr.h"
|
#include "storage/bufmgr.h"
|
||||||
#include "storage/bufpage.h"
|
#include "storage/bufpage.h"
|
||||||
#include "storage/bufmgr.h"
|
|
||||||
#include "storage/lmgr.h"
|
#include "storage/lmgr.h"
|
||||||
#include "storage/predicate.h"
|
#include "storage/predicate.h"
|
||||||
#include "storage/procarray.h"
|
#include "storage/procarray.h"
|
||||||
|
@ -44,6 +38,10 @@
|
||||||
#include "utils/rel.h"
|
#include "utils/rel.h"
|
||||||
#include "utils/syscache.h"
|
#include "utils/syscache.h"
|
||||||
|
|
||||||
|
#include "citus_version.h"
|
||||||
|
#include "pg_version_compat.h"
|
||||||
|
|
||||||
|
#include "columnar/columnar.h"
|
||||||
#include "columnar/columnar_customscan.h"
|
#include "columnar/columnar_customscan.h"
|
||||||
#include "columnar/columnar_tableam.h"
|
#include "columnar/columnar_tableam.h"
|
||||||
#include "columnar/columnar_version_compat.h"
|
#include "columnar/columnar_version_compat.h"
|
||||||
|
|
|
@ -18,7 +18,7 @@ generated_downgrade_sql_files += $(patsubst %,$(citus_abs_srcdir)/build/sql/%,$(
|
||||||
DATA_built = $(generated_sql_files)
|
DATA_built = $(generated_sql_files)
|
||||||
|
|
||||||
# directories with source files
|
# directories with source files
|
||||||
SUBDIRS = . commands connection ddl deparser executor metadata operations planner progress relay safeclib shardsplit test transaction utils worker clock
|
SUBDIRS = . commands connection ddl deparser executor metadata operations planner progress relay safeclib shardsplit stats test transaction utils worker clock
|
||||||
# enterprise modules
|
# enterprise modules
|
||||||
SUBDIRS += replication
|
SUBDIRS += replication
|
||||||
|
|
||||||
|
|
|
@ -14,11 +14,6 @@ override CPPFLAGS += -DDECODER=\"$(DECODER)\" -I$(citus_abs_top_srcdir)/include
|
||||||
|
|
||||||
install: install-cdc
|
install: install-cdc
|
||||||
|
|
||||||
clean: clean-cdc
|
|
||||||
|
|
||||||
install-cdc:
|
install-cdc:
|
||||||
mkdir -p '$(citus_decoders_dir)'
|
mkdir -p '$(citus_decoders_dir)'
|
||||||
$(INSTALL_SHLIB) citus_$(DECODER).so '$(citus_decoders_dir)/$(DECODER).so'
|
$(INSTALL_SHLIB) citus_$(DECODER)$(DLSUFFIX) '$(citus_decoders_dir)/$(DECODER)$(DLSUFFIX)'
|
||||||
|
|
||||||
clean-cdc:
|
|
||||||
rm -f '$(DESTDIR)$(datadir)/$(datamoduledir)/citus_decoders/$(DECODER).so'
|
|
||||||
|
|
|
@ -8,8 +8,9 @@
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "cdc_decoder_utils.h"
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
|
#include "cdc_decoder_utils.h"
|
||||||
#include "fmgr.h"
|
#include "fmgr.h"
|
||||||
|
|
||||||
#include "access/genam.h"
|
#include "access/genam.h"
|
||||||
|
@ -21,6 +22,8 @@
|
||||||
#include "utils/rel.h"
|
#include "utils/rel.h"
|
||||||
#include "utils/typcache.h"
|
#include "utils/typcache.h"
|
||||||
|
|
||||||
|
#include "pg_version_constants.h"
|
||||||
|
|
||||||
PG_MODULE_MAGIC;
|
PG_MODULE_MAGIC;
|
||||||
|
|
||||||
extern void _PG_output_plugin_init(OutputPluginCallbacks *cb);
|
extern void _PG_output_plugin_init(OutputPluginCallbacks *cb);
|
||||||
|
@ -434,6 +437,74 @@ TranslateChangesIfSchemaChanged(Relation sourceRelation, Relation targetRelation
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if PG_VERSION_NUM >= PG_VERSION_17
|
||||||
|
|
||||||
|
/* Check the ReorderBufferChange's action type and handle them accordingly.*/
|
||||||
|
switch (change->action)
|
||||||
|
{
|
||||||
|
case REORDER_BUFFER_CHANGE_INSERT:
|
||||||
|
{
|
||||||
|
/* For insert action, only new tuple should always be translated*/
|
||||||
|
HeapTuple sourceRelationNewTuple = change->data.tp.newtuple;
|
||||||
|
HeapTuple targetRelationNewTuple = GetTupleForTargetSchemaForCdc(
|
||||||
|
sourceRelationNewTuple, sourceRelationDesc, targetRelationDesc);
|
||||||
|
change->data.tp.newtuple = targetRelationNewTuple;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For update changes both old and new tuples need to be translated for target relation
|
||||||
|
* if the REPLICA IDENTITY is set to FULL. Otherwise, only the new tuple needs to be
|
||||||
|
* translated for target relation.
|
||||||
|
*/
|
||||||
|
case REORDER_BUFFER_CHANGE_UPDATE:
|
||||||
|
{
|
||||||
|
/* For update action, new tuple should always be translated*/
|
||||||
|
/* Get the new tuple from the ReorderBufferChange, and translate it to target relation. */
|
||||||
|
HeapTuple sourceRelationNewTuple = change->data.tp.newtuple;
|
||||||
|
HeapTuple targetRelationNewTuple = GetTupleForTargetSchemaForCdc(
|
||||||
|
sourceRelationNewTuple, sourceRelationDesc, targetRelationDesc);
|
||||||
|
change->data.tp.newtuple = targetRelationNewTuple;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Format oldtuple according to the target relation. If the column values of replica
|
||||||
|
* identiy change, then the old tuple is non-null and needs to be formatted according
|
||||||
|
* to the target relation schema.
|
||||||
|
*/
|
||||||
|
if (change->data.tp.oldtuple != NULL)
|
||||||
|
{
|
||||||
|
HeapTuple sourceRelationOldTuple = change->data.tp.oldtuple;
|
||||||
|
HeapTuple targetRelationOldTuple = GetTupleForTargetSchemaForCdc(
|
||||||
|
sourceRelationOldTuple,
|
||||||
|
sourceRelationDesc,
|
||||||
|
targetRelationDesc);
|
||||||
|
|
||||||
|
change->data.tp.oldtuple = targetRelationOldTuple;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case REORDER_BUFFER_CHANGE_DELETE:
|
||||||
|
{
|
||||||
|
/* For delete action, only old tuple should be translated*/
|
||||||
|
HeapTuple sourceRelationOldTuple = change->data.tp.oldtuple;
|
||||||
|
HeapTuple targetRelationOldTuple = GetTupleForTargetSchemaForCdc(
|
||||||
|
sourceRelationOldTuple,
|
||||||
|
sourceRelationDesc,
|
||||||
|
targetRelationDesc);
|
||||||
|
|
||||||
|
change->data.tp.oldtuple = targetRelationOldTuple;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
/* Do nothing for other action types. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
|
||||||
/* Check the ReorderBufferChange's action type and handle them accordingly.*/
|
/* Check the ReorderBufferChange's action type and handle them accordingly.*/
|
||||||
switch (change->action)
|
switch (change->action)
|
||||||
{
|
{
|
||||||
|
@ -498,4 +569,5 @@ TranslateChangesIfSchemaChanged(Relation sourceRelation, Relation targetRelation
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,18 +8,21 @@
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
#include "commands/extension.h"
|
|
||||||
|
#include "cdc_decoder_utils.h"
|
||||||
#include "fmgr.h"
|
#include "fmgr.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
|
|
||||||
#include "access/genam.h"
|
#include "access/genam.h"
|
||||||
#include "access/heapam.h"
|
#include "access/heapam.h"
|
||||||
|
#include "catalog/pg_namespace.h"
|
||||||
|
#include "commands/extension.h"
|
||||||
#include "common/hashfn.h"
|
#include "common/hashfn.h"
|
||||||
#include "common/string.h"
|
#include "common/string.h"
|
||||||
#include "utils/fmgroids.h"
|
#include "utils/fmgroids.h"
|
||||||
#include "utils/typcache.h"
|
|
||||||
#include "utils/lsyscache.h"
|
#include "utils/lsyscache.h"
|
||||||
#include "catalog/pg_namespace.h"
|
#include "utils/typcache.h"
|
||||||
#include "cdc_decoder_utils.h"
|
|
||||||
#include "distributed/pg_dist_partition.h"
|
#include "distributed/pg_dist_partition.h"
|
||||||
#include "distributed/pg_dist_shard.h"
|
#include "distributed/pg_dist_shard.h"
|
||||||
#include "distributed/relay_utility.h"
|
#include "distributed/relay_utility.h"
|
||||||
|
|
|
@ -12,9 +12,11 @@
|
||||||
#define CITUS_CDC_DECODER_H
|
#define CITUS_CDC_DECODER_H
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
#include "fmgr.h"
|
|
||||||
#include "replication/logical.h"
|
|
||||||
#include "c.h"
|
#include "c.h"
|
||||||
|
#include "fmgr.h"
|
||||||
|
|
||||||
|
#include "replication/logical.h"
|
||||||
|
|
||||||
#define InvalidRepOriginId 0
|
#define InvalidRepOriginId 0
|
||||||
#define INVALID_SHARD_ID 0
|
#define INVALID_SHARD_ID 0
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Citus extension
|
# Citus extension
|
||||||
comment = 'Citus distributed database'
|
comment = 'Citus distributed database'
|
||||||
default_version = '12.1-1'
|
default_version = '13.2-1'
|
||||||
module_pathname = '$libdir/citus'
|
module_pathname = '$libdir/citus'
|
||||||
relocatable = false
|
relocatable = false
|
||||||
schema = pg_catalog
|
schema = pg_catalog
|
||||||
|
|
|
@ -11,36 +11,37 @@
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
#include "miscadmin.h"
|
|
||||||
#include "fmgr.h"
|
#include "fmgr.h"
|
||||||
#include "funcapi.h"
|
#include "funcapi.h"
|
||||||
#include "libpq-fe.h"
|
#include "libpq-fe.h"
|
||||||
|
#include "miscadmin.h"
|
||||||
|
|
||||||
#include "utils/builtins.h"
|
|
||||||
#include "utils/datum.h"
|
|
||||||
#include "utils/numeric.h"
|
|
||||||
#include "utils/typcache.h"
|
|
||||||
#include "nodes/pg_list.h"
|
|
||||||
#include "catalog/namespace.h"
|
#include "catalog/namespace.h"
|
||||||
#include "commands/extension.h"
|
#include "commands/extension.h"
|
||||||
#include "commands/sequence.h"
|
#include "commands/sequence.h"
|
||||||
#include "executor/spi.h"
|
#include "executor/spi.h"
|
||||||
|
#include "nodes/pg_list.h"
|
||||||
#include "postmaster/postmaster.h"
|
#include "postmaster/postmaster.h"
|
||||||
#include "storage/ipc.h"
|
#include "storage/ipc.h"
|
||||||
#include "storage/lwlock.h"
|
#include "storage/lwlock.h"
|
||||||
|
#include "storage/s_lock.h"
|
||||||
#include "storage/shmem.h"
|
#include "storage/shmem.h"
|
||||||
#include "storage/spin.h"
|
#include "storage/spin.h"
|
||||||
#include "storage/s_lock.h"
|
#include "utils/builtins.h"
|
||||||
|
#include "utils/datum.h"
|
||||||
|
#include "utils/numeric.h"
|
||||||
|
#include "utils/typcache.h"
|
||||||
|
|
||||||
#include "distributed/causal_clock.h"
|
#include "distributed/causal_clock.h"
|
||||||
#include "distributed/listutils.h"
|
|
||||||
#include "distributed/lock_graph.h"
|
|
||||||
#include "distributed/local_executor.h"
|
|
||||||
#include "distributed/metadata_cache.h"
|
|
||||||
#include "distributed/remote_commands.h"
|
|
||||||
#include "distributed/placement_connection.h"
|
|
||||||
#include "distributed/coordinator_protocol.h"
|
|
||||||
#include "distributed/citus_safe_lib.h"
|
#include "distributed/citus_safe_lib.h"
|
||||||
|
#include "distributed/coordinator_protocol.h"
|
||||||
|
#include "distributed/listutils.h"
|
||||||
|
#include "distributed/local_executor.h"
|
||||||
|
#include "distributed/lock_graph.h"
|
||||||
|
#include "distributed/metadata_cache.h"
|
||||||
|
#include "distributed/placement_connection.h"
|
||||||
|
#include "distributed/remote_commands.h"
|
||||||
|
|
||||||
#define SAVE_AND_PERSIST(c) \
|
#define SAVE_AND_PERSIST(c) \
|
||||||
do { \
|
do { \
|
||||||
|
@ -144,17 +145,6 @@ LogicalClockShmemSize(void)
|
||||||
void
|
void
|
||||||
InitializeClusterClockMem(void)
|
InitializeClusterClockMem(void)
|
||||||
{
|
{
|
||||||
/* On PG 15 and above, we use shmem_request_hook_type */
|
|
||||||
#if PG_VERSION_NUM < PG_VERSION_15
|
|
||||||
|
|
||||||
/* allocate shared memory for pre PG-15 versions */
|
|
||||||
if (!IsUnderPostmaster)
|
|
||||||
{
|
|
||||||
RequestAddinShmemSpace(LogicalClockShmemSize());
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
prev_shmem_startup_hook = shmem_startup_hook;
|
prev_shmem_startup_hook = shmem_startup_hook;
|
||||||
shmem_startup_hook = LogicalClockShmemInit;
|
shmem_startup_hook = LogicalClockShmemInit;
|
||||||
}
|
}
|
||||||
|
@ -327,7 +317,7 @@ GetHighestClockInTransaction(List *nodeConnectionList)
|
||||||
{
|
{
|
||||||
MultiConnection *connection = NULL;
|
MultiConnection *connection = NULL;
|
||||||
|
|
||||||
foreach_ptr(connection, nodeConnectionList)
|
foreach_declared_ptr(connection, nodeConnectionList)
|
||||||
{
|
{
|
||||||
int querySent =
|
int querySent =
|
||||||
SendRemoteCommand(connection, "SELECT citus_get_node_clock();");
|
SendRemoteCommand(connection, "SELECT citus_get_node_clock();");
|
||||||
|
@ -348,7 +338,7 @@ GetHighestClockInTransaction(List *nodeConnectionList)
|
||||||
globalClockValue->counter)));
|
globalClockValue->counter)));
|
||||||
|
|
||||||
/* fetch the results and pick the highest clock value of all the nodes */
|
/* fetch the results and pick the highest clock value of all the nodes */
|
||||||
foreach_ptr(connection, nodeConnectionList)
|
foreach_declared_ptr(connection, nodeConnectionList)
|
||||||
{
|
{
|
||||||
bool raiseInterrupts = true;
|
bool raiseInterrupts = true;
|
||||||
|
|
||||||
|
@ -396,7 +386,7 @@ AdjustClocksToTransactionHighest(List *nodeConnectionList,
|
||||||
|
|
||||||
/* Set the clock value on participating worker nodes */
|
/* Set the clock value on participating worker nodes */
|
||||||
appendStringInfo(queryToSend,
|
appendStringInfo(queryToSend,
|
||||||
"SELECT pg_catalog.citus_internal_adjust_local_clock_to_remote"
|
"SELECT citus_internal.adjust_local_clock_to_remote"
|
||||||
"('(%lu, %u)'::pg_catalog.cluster_clock);",
|
"('(%lu, %u)'::pg_catalog.cluster_clock);",
|
||||||
transactionClockValue->logical, transactionClockValue->counter);
|
transactionClockValue->logical, transactionClockValue->counter);
|
||||||
|
|
||||||
|
@ -430,6 +420,11 @@ PrepareAndSetTransactionClock(void)
|
||||||
MultiConnection *connection = dlist_container(MultiConnection, transactionNode,
|
MultiConnection *connection = dlist_container(MultiConnection, transactionNode,
|
||||||
iter.cur);
|
iter.cur);
|
||||||
WorkerNode *workerNode = FindWorkerNode(connection->hostname, connection->port);
|
WorkerNode *workerNode = FindWorkerNode(connection->hostname, connection->port);
|
||||||
|
if (!workerNode)
|
||||||
|
{
|
||||||
|
ereport(WARNING, errmsg("Worker node is missing"));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/* Skip the node if we already in the list */
|
/* Skip the node if we already in the list */
|
||||||
if (list_member_int(nodeList, workerNode->groupId))
|
if (list_member_int(nodeList, workerNode->groupId))
|
||||||
|
|
|
@ -34,9 +34,16 @@
|
||||||
#include "catalog/pg_am.h"
|
#include "catalog/pg_am.h"
|
||||||
#include "catalog/pg_depend.h"
|
#include "catalog/pg_depend.h"
|
||||||
#include "catalog/pg_rewrite_d.h"
|
#include "catalog/pg_rewrite_d.h"
|
||||||
|
#include "commands/defrem.h"
|
||||||
|
#include "executor/spi.h"
|
||||||
|
#include "nodes/pg_list.h"
|
||||||
|
#include "utils/builtins.h"
|
||||||
|
#include "utils/lsyscache.h"
|
||||||
|
#include "utils/syscache.h"
|
||||||
|
|
||||||
#include "columnar/columnar.h"
|
#include "columnar/columnar.h"
|
||||||
#include "columnar/columnar_tableam.h"
|
#include "columnar/columnar_tableam.h"
|
||||||
#include "commands/defrem.h"
|
|
||||||
#include "distributed/colocation_utils.h"
|
#include "distributed/colocation_utils.h"
|
||||||
#include "distributed/commands.h"
|
#include "distributed/commands.h"
|
||||||
#include "distributed/commands/utility_hook.h"
|
#include "distributed/commands/utility_hook.h"
|
||||||
|
@ -57,16 +64,11 @@
|
||||||
#include "distributed/reference_table_utils.h"
|
#include "distributed/reference_table_utils.h"
|
||||||
#include "distributed/relation_access_tracking.h"
|
#include "distributed/relation_access_tracking.h"
|
||||||
#include "distributed/replication_origin_session_utils.h"
|
#include "distributed/replication_origin_session_utils.h"
|
||||||
#include "distributed/shared_library_init.h"
|
|
||||||
#include "distributed/shard_utils.h"
|
#include "distributed/shard_utils.h"
|
||||||
|
#include "distributed/shared_library_init.h"
|
||||||
#include "distributed/tenant_schema_metadata.h"
|
#include "distributed/tenant_schema_metadata.h"
|
||||||
#include "distributed/worker_protocol.h"
|
#include "distributed/worker_protocol.h"
|
||||||
#include "distributed/worker_transaction.h"
|
#include "distributed/worker_transaction.h"
|
||||||
#include "executor/spi.h"
|
|
||||||
#include "nodes/pg_list.h"
|
|
||||||
#include "utils/builtins.h"
|
|
||||||
#include "utils/lsyscache.h"
|
|
||||||
#include "utils/syscache.h"
|
|
||||||
|
|
||||||
|
|
||||||
/* Table Conversion Types */
|
/* Table Conversion Types */
|
||||||
|
@ -207,12 +209,9 @@ static void ReplaceTable(Oid sourceId, Oid targetId, List *justBeforeDropCommand
|
||||||
static bool HasAnyGeneratedStoredColumns(Oid relationId);
|
static bool HasAnyGeneratedStoredColumns(Oid relationId);
|
||||||
static List * GetNonGeneratedStoredColumnNameList(Oid relationId);
|
static List * GetNonGeneratedStoredColumnNameList(Oid relationId);
|
||||||
static void CheckAlterDistributedTableConversionParameters(TableConversionState *con);
|
static void CheckAlterDistributedTableConversionParameters(TableConversionState *con);
|
||||||
static char * CreateWorkerChangeSequenceDependencyCommand(char *sequenceSchemaName,
|
static char * CreateWorkerChangeSequenceDependencyCommand(char *qualifiedSequeceName,
|
||||||
char *sequenceName,
|
char *qualifiedSourceName,
|
||||||
char *sourceSchemaName,
|
char *qualifiedTargetName);
|
||||||
char *sourceName,
|
|
||||||
char *targetSchemaName,
|
|
||||||
char *targetName);
|
|
||||||
static void ErrorIfMatViewSizeExceedsTheLimit(Oid matViewOid);
|
static void ErrorIfMatViewSizeExceedsTheLimit(Oid matViewOid);
|
||||||
static char * CreateMaterializedViewDDLCommand(Oid matViewOid);
|
static char * CreateMaterializedViewDDLCommand(Oid matViewOid);
|
||||||
static char * GetAccessMethodForMatViewIfExists(Oid viewOid);
|
static char * GetAccessMethodForMatViewIfExists(Oid viewOid);
|
||||||
|
@ -415,7 +414,7 @@ UndistributeTables(List *relationIdList)
|
||||||
*/
|
*/
|
||||||
List *originalForeignKeyRecreationCommands = NIL;
|
List *originalForeignKeyRecreationCommands = NIL;
|
||||||
Oid relationId = InvalidOid;
|
Oid relationId = InvalidOid;
|
||||||
foreach_oid(relationId, relationIdList)
|
foreach_declared_oid(relationId, relationIdList)
|
||||||
{
|
{
|
||||||
List *fkeyCommandsForRelation =
|
List *fkeyCommandsForRelation =
|
||||||
GetFKeyCreationCommandsRelationInvolvedWithTableType(relationId,
|
GetFKeyCreationCommandsRelationInvolvedWithTableType(relationId,
|
||||||
|
@ -789,19 +788,21 @@ ConvertTableInternal(TableConversionState *con)
|
||||||
justBeforeDropCommands = lappend(justBeforeDropCommands, detachFromParentCommand);
|
justBeforeDropCommands = lappend(justBeforeDropCommands, detachFromParentCommand);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *qualifiedRelationName = quote_qualified_identifier(con->schemaName,
|
||||||
|
con->relationName);
|
||||||
|
|
||||||
if (PartitionedTable(con->relationId))
|
if (PartitionedTable(con->relationId))
|
||||||
{
|
{
|
||||||
if (!con->suppressNoticeMessages)
|
if (!con->suppressNoticeMessages)
|
||||||
{
|
{
|
||||||
ereport(NOTICE, (errmsg("converting the partitions of %s",
|
ereport(NOTICE, (errmsg("converting the partitions of %s",
|
||||||
quote_qualified_identifier(con->schemaName,
|
qualifiedRelationName)));
|
||||||
con->relationName))));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
List *partitionList = PartitionList(con->relationId);
|
List *partitionList = PartitionList(con->relationId);
|
||||||
|
|
||||||
Oid partitionRelationId = InvalidOid;
|
Oid partitionRelationId = InvalidOid;
|
||||||
foreach_oid(partitionRelationId, partitionList)
|
foreach_declared_oid(partitionRelationId, partitionList)
|
||||||
{
|
{
|
||||||
char *tableQualifiedName = generate_qualified_relation_name(
|
char *tableQualifiedName = generate_qualified_relation_name(
|
||||||
partitionRelationId);
|
partitionRelationId);
|
||||||
|
@ -868,13 +869,11 @@ ConvertTableInternal(TableConversionState *con)
|
||||||
|
|
||||||
if (!con->suppressNoticeMessages)
|
if (!con->suppressNoticeMessages)
|
||||||
{
|
{
|
||||||
ereport(NOTICE, (errmsg("creating a new table for %s",
|
ereport(NOTICE, (errmsg("creating a new table for %s", qualifiedRelationName)));
|
||||||
quote_qualified_identifier(con->schemaName,
|
|
||||||
con->relationName))));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TableDDLCommand *tableCreationCommand = NULL;
|
TableDDLCommand *tableCreationCommand = NULL;
|
||||||
foreach_ptr(tableCreationCommand, preLoadCommands)
|
foreach_declared_ptr(tableCreationCommand, preLoadCommands)
|
||||||
{
|
{
|
||||||
Assert(CitusIsA(tableCreationCommand, TableDDLCommand));
|
Assert(CitusIsA(tableCreationCommand, TableDDLCommand));
|
||||||
|
|
||||||
|
@ -948,7 +947,7 @@ ConvertTableInternal(TableConversionState *con)
|
||||||
con->suppressNoticeMessages);
|
con->suppressNoticeMessages);
|
||||||
|
|
||||||
TableDDLCommand *tableConstructionCommand = NULL;
|
TableDDLCommand *tableConstructionCommand = NULL;
|
||||||
foreach_ptr(tableConstructionCommand, postLoadCommands)
|
foreach_declared_ptr(tableConstructionCommand, postLoadCommands)
|
||||||
{
|
{
|
||||||
Assert(CitusIsA(tableConstructionCommand, TableDDLCommand));
|
Assert(CitusIsA(tableConstructionCommand, TableDDLCommand));
|
||||||
char *tableConstructionSQL = GetTableDDLCommand(tableConstructionCommand);
|
char *tableConstructionSQL = GetTableDDLCommand(tableConstructionCommand);
|
||||||
|
@ -966,7 +965,7 @@ ConvertTableInternal(TableConversionState *con)
|
||||||
MemoryContext oldContext = MemoryContextSwitchTo(citusPerPartitionContext);
|
MemoryContext oldContext = MemoryContextSwitchTo(citusPerPartitionContext);
|
||||||
|
|
||||||
char *attachPartitionCommand = NULL;
|
char *attachPartitionCommand = NULL;
|
||||||
foreach_ptr(attachPartitionCommand, attachPartitionCommands)
|
foreach_declared_ptr(attachPartitionCommand, attachPartitionCommands)
|
||||||
{
|
{
|
||||||
MemoryContextReset(citusPerPartitionContext);
|
MemoryContextReset(citusPerPartitionContext);
|
||||||
|
|
||||||
|
@ -991,14 +990,12 @@ ConvertTableInternal(TableConversionState *con)
|
||||||
|
|
||||||
/* For now we only support cascade to colocation for alter_distributed_table UDF */
|
/* For now we only support cascade to colocation for alter_distributed_table UDF */
|
||||||
Assert(con->conversionType == ALTER_DISTRIBUTED_TABLE);
|
Assert(con->conversionType == ALTER_DISTRIBUTED_TABLE);
|
||||||
foreach_oid(colocatedTableId, con->colocatedTableList)
|
foreach_declared_oid(colocatedTableId, con->colocatedTableList)
|
||||||
{
|
{
|
||||||
if (colocatedTableId == con->relationId)
|
if (colocatedTableId == con->relationId)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
char *qualifiedRelationName = quote_qualified_identifier(con->schemaName,
|
|
||||||
con->relationName);
|
|
||||||
|
|
||||||
TableConversionParameters cascadeParam = {
|
TableConversionParameters cascadeParam = {
|
||||||
.relationId = colocatedTableId,
|
.relationId = colocatedTableId,
|
||||||
|
@ -1021,7 +1018,7 @@ ConvertTableInternal(TableConversionState *con)
|
||||||
if (con->cascadeToColocated != CASCADE_TO_COLOCATED_NO_ALREADY_CASCADED)
|
if (con->cascadeToColocated != CASCADE_TO_COLOCATED_NO_ALREADY_CASCADED)
|
||||||
{
|
{
|
||||||
char *foreignKeyCommand = NULL;
|
char *foreignKeyCommand = NULL;
|
||||||
foreach_ptr(foreignKeyCommand, foreignKeyCommands)
|
foreach_declared_ptr(foreignKeyCommand, foreignKeyCommands)
|
||||||
{
|
{
|
||||||
ExecuteQueryViaSPI(foreignKeyCommand, SPI_OK_UTILITY);
|
ExecuteQueryViaSPI(foreignKeyCommand, SPI_OK_UTILITY);
|
||||||
}
|
}
|
||||||
|
@ -1057,7 +1054,7 @@ CopyTableConversionReturnIntoCurrentContext(TableConversionReturn *tableConversi
|
||||||
tableConversionReturnCopy = palloc0(sizeof(TableConversionReturn));
|
tableConversionReturnCopy = palloc0(sizeof(TableConversionReturn));
|
||||||
List *copyForeignKeyCommands = NIL;
|
List *copyForeignKeyCommands = NIL;
|
||||||
char *foreignKeyCommand = NULL;
|
char *foreignKeyCommand = NULL;
|
||||||
foreach_ptr(foreignKeyCommand, tableConversionReturn->foreignKeyCommands)
|
foreach_declared_ptr(foreignKeyCommand, tableConversionReturn->foreignKeyCommands)
|
||||||
{
|
{
|
||||||
char *copyForeignKeyCommand = MemoryContextStrdup(CurrentMemoryContext,
|
char *copyForeignKeyCommand = MemoryContextStrdup(CurrentMemoryContext,
|
||||||
foreignKeyCommand);
|
foreignKeyCommand);
|
||||||
|
@ -1132,7 +1129,7 @@ DropIndexesNotSupportedByColumnar(Oid relationId, bool suppressNoticeMessages)
|
||||||
RelationClose(columnarRelation);
|
RelationClose(columnarRelation);
|
||||||
|
|
||||||
Oid indexId = InvalidOid;
|
Oid indexId = InvalidOid;
|
||||||
foreach_oid(indexId, indexIdList)
|
foreach_declared_oid(indexId, indexIdList)
|
||||||
{
|
{
|
||||||
char *indexAmName = GetIndexAccessMethodName(indexId);
|
char *indexAmName = GetIndexAccessMethodName(indexId);
|
||||||
if (extern_ColumnarSupportsIndexAM(indexAmName))
|
if (extern_ColumnarSupportsIndexAM(indexAmName))
|
||||||
|
@ -1392,7 +1389,7 @@ CreateTableConversion(TableConversionParameters *params)
|
||||||
* since they will be handled separately.
|
* since they will be handled separately.
|
||||||
*/
|
*/
|
||||||
Oid colocatedTableId = InvalidOid;
|
Oid colocatedTableId = InvalidOid;
|
||||||
foreach_oid(colocatedTableId, colocatedTableList)
|
foreach_declared_oid(colocatedTableId, colocatedTableList)
|
||||||
{
|
{
|
||||||
if (PartitionTable(colocatedTableId))
|
if (PartitionTable(colocatedTableId))
|
||||||
{
|
{
|
||||||
|
@ -1608,7 +1605,7 @@ DoesCascadeDropUnsupportedObject(Oid classId, Oid objectId, HTAB *nodeMap)
|
||||||
targetObjectId);
|
targetObjectId);
|
||||||
|
|
||||||
HeapTuple depTup = NULL;
|
HeapTuple depTup = NULL;
|
||||||
foreach_ptr(depTup, dependencyTupleList)
|
foreach_declared_ptr(depTup, dependencyTupleList)
|
||||||
{
|
{
|
||||||
Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
|
Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
|
||||||
|
|
||||||
|
@ -1648,7 +1645,7 @@ GetViewCreationCommandsOfTable(Oid relationId)
|
||||||
List *commands = NIL;
|
List *commands = NIL;
|
||||||
|
|
||||||
Oid viewOid = InvalidOid;
|
Oid viewOid = InvalidOid;
|
||||||
foreach_oid(viewOid, views)
|
foreach_declared_oid(viewOid, views)
|
||||||
{
|
{
|
||||||
StringInfo query = makeStringInfo();
|
StringInfo query = makeStringInfo();
|
||||||
|
|
||||||
|
@ -1686,7 +1683,7 @@ WrapTableDDLCommands(List *commandStrings)
|
||||||
List *tableDDLCommands = NIL;
|
List *tableDDLCommands = NIL;
|
||||||
|
|
||||||
char *command = NULL;
|
char *command = NULL;
|
||||||
foreach_ptr(command, commandStrings)
|
foreach_declared_ptr(command, commandStrings)
|
||||||
{
|
{
|
||||||
tableDDLCommands = lappend(tableDDLCommands, makeTableDDLCommandString(command));
|
tableDDLCommands = lappend(tableDDLCommands, makeTableDDLCommandString(command));
|
||||||
}
|
}
|
||||||
|
@ -1748,9 +1745,7 @@ CreateMaterializedViewDDLCommand(Oid matViewOid)
|
||||||
{
|
{
|
||||||
StringInfo query = makeStringInfo();
|
StringInfo query = makeStringInfo();
|
||||||
|
|
||||||
char *viewName = get_rel_name(matViewOid);
|
char *qualifiedViewName = generate_qualified_relation_name(matViewOid);
|
||||||
char *schemaName = get_namespace_name(get_rel_namespace(matViewOid));
|
|
||||||
char *qualifiedViewName = quote_qualified_identifier(schemaName, viewName);
|
|
||||||
|
|
||||||
/* here we need to get the access method of the view to recreate it */
|
/* here we need to get the access method of the view to recreate it */
|
||||||
char *accessMethodName = GetAccessMethodForMatViewIfExists(matViewOid);
|
char *accessMethodName = GetAccessMethodForMatViewIfExists(matViewOid);
|
||||||
|
@ -1799,9 +1794,8 @@ ReplaceTable(Oid sourceId, Oid targetId, List *justBeforeDropCommands,
|
||||||
bool suppressNoticeMessages)
|
bool suppressNoticeMessages)
|
||||||
{
|
{
|
||||||
char *sourceName = get_rel_name(sourceId);
|
char *sourceName = get_rel_name(sourceId);
|
||||||
char *targetName = get_rel_name(targetId);
|
char *qualifiedSourceName = generate_qualified_relation_name(sourceId);
|
||||||
Oid schemaId = get_rel_namespace(sourceId);
|
char *qualifiedTargetName = generate_qualified_relation_name(targetId);
|
||||||
char *schemaName = get_namespace_name(schemaId);
|
|
||||||
|
|
||||||
StringInfo query = makeStringInfo();
|
StringInfo query = makeStringInfo();
|
||||||
|
|
||||||
|
@ -1809,8 +1803,7 @@ ReplaceTable(Oid sourceId, Oid targetId, List *justBeforeDropCommands,
|
||||||
{
|
{
|
||||||
if (!suppressNoticeMessages)
|
if (!suppressNoticeMessages)
|
||||||
{
|
{
|
||||||
ereport(NOTICE, (errmsg("moving the data of %s",
|
ereport(NOTICE, (errmsg("moving the data of %s", qualifiedSourceName)));
|
||||||
quote_qualified_identifier(schemaName, sourceName))));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!HasAnyGeneratedStoredColumns(sourceId))
|
if (!HasAnyGeneratedStoredColumns(sourceId))
|
||||||
|
@ -1820,8 +1813,7 @@ ReplaceTable(Oid sourceId, Oid targetId, List *justBeforeDropCommands,
|
||||||
* "INSERT INTO .. SELECT *"".
|
* "INSERT INTO .. SELECT *"".
|
||||||
*/
|
*/
|
||||||
appendStringInfo(query, "INSERT INTO %s SELECT * FROM %s",
|
appendStringInfo(query, "INSERT INTO %s SELECT * FROM %s",
|
||||||
quote_qualified_identifier(schemaName, targetName),
|
qualifiedTargetName, qualifiedSourceName);
|
||||||
quote_qualified_identifier(schemaName, sourceName));
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1836,9 +1828,8 @@ ReplaceTable(Oid sourceId, Oid targetId, List *justBeforeDropCommands,
|
||||||
char *insertColumnString = StringJoin(nonStoredColumnNameList, ',');
|
char *insertColumnString = StringJoin(nonStoredColumnNameList, ',');
|
||||||
appendStringInfo(query,
|
appendStringInfo(query,
|
||||||
"INSERT INTO %s (%s) OVERRIDING SYSTEM VALUE SELECT %s FROM %s",
|
"INSERT INTO %s (%s) OVERRIDING SYSTEM VALUE SELECT %s FROM %s",
|
||||||
quote_qualified_identifier(schemaName, targetName),
|
qualifiedTargetName, insertColumnString,
|
||||||
insertColumnString, insertColumnString,
|
insertColumnString, qualifiedSourceName);
|
||||||
quote_qualified_identifier(schemaName, sourceName));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ExecuteQueryViaSPI(query->data, SPI_OK_INSERT);
|
ExecuteQueryViaSPI(query->data, SPI_OK_INSERT);
|
||||||
|
@ -1849,7 +1840,7 @@ ReplaceTable(Oid sourceId, Oid targetId, List *justBeforeDropCommands,
|
||||||
*/
|
*/
|
||||||
List *ownedSequences = getOwnedSequences_internal(sourceId, 0, DEPENDENCY_AUTO);
|
List *ownedSequences = getOwnedSequences_internal(sourceId, 0, DEPENDENCY_AUTO);
|
||||||
Oid sequenceOid = InvalidOid;
|
Oid sequenceOid = InvalidOid;
|
||||||
foreach_oid(sequenceOid, ownedSequences)
|
foreach_declared_oid(sequenceOid, ownedSequences)
|
||||||
{
|
{
|
||||||
changeDependencyFor(RelationRelationId, sequenceOid,
|
changeDependencyFor(RelationRelationId, sequenceOid,
|
||||||
RelationRelationId, sourceId, targetId);
|
RelationRelationId, sourceId, targetId);
|
||||||
|
@ -1862,14 +1853,11 @@ ReplaceTable(Oid sourceId, Oid targetId, List *justBeforeDropCommands,
|
||||||
*/
|
*/
|
||||||
if (ShouldSyncTableMetadata(targetId))
|
if (ShouldSyncTableMetadata(targetId))
|
||||||
{
|
{
|
||||||
Oid sequenceSchemaOid = get_rel_namespace(sequenceOid);
|
char *qualifiedSequenceName = generate_qualified_relation_name(sequenceOid);
|
||||||
char *sequenceSchemaName = get_namespace_name(sequenceSchemaOid);
|
|
||||||
char *sequenceName = get_rel_name(sequenceOid);
|
|
||||||
char *workerChangeSequenceDependencyCommand =
|
char *workerChangeSequenceDependencyCommand =
|
||||||
CreateWorkerChangeSequenceDependencyCommand(sequenceSchemaName,
|
CreateWorkerChangeSequenceDependencyCommand(qualifiedSequenceName,
|
||||||
sequenceName,
|
qualifiedSourceName,
|
||||||
schemaName, sourceName,
|
qualifiedTargetName);
|
||||||
schemaName, targetName);
|
|
||||||
SendCommandToWorkersWithMetadata(workerChangeSequenceDependencyCommand);
|
SendCommandToWorkersWithMetadata(workerChangeSequenceDependencyCommand);
|
||||||
}
|
}
|
||||||
else if (ShouldSyncTableMetadata(sourceId))
|
else if (ShouldSyncTableMetadata(sourceId))
|
||||||
|
@ -1885,32 +1873,30 @@ ReplaceTable(Oid sourceId, Oid targetId, List *justBeforeDropCommands,
|
||||||
}
|
}
|
||||||
|
|
||||||
char *justBeforeDropCommand = NULL;
|
char *justBeforeDropCommand = NULL;
|
||||||
foreach_ptr(justBeforeDropCommand, justBeforeDropCommands)
|
foreach_declared_ptr(justBeforeDropCommand, justBeforeDropCommands)
|
||||||
{
|
{
|
||||||
ExecuteQueryViaSPI(justBeforeDropCommand, SPI_OK_UTILITY);
|
ExecuteQueryViaSPI(justBeforeDropCommand, SPI_OK_UTILITY);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!suppressNoticeMessages)
|
if (!suppressNoticeMessages)
|
||||||
{
|
{
|
||||||
ereport(NOTICE, (errmsg("dropping the old %s",
|
ereport(NOTICE, (errmsg("dropping the old %s", qualifiedSourceName)));
|
||||||
quote_qualified_identifier(schemaName, sourceName))));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resetStringInfo(query);
|
resetStringInfo(query);
|
||||||
appendStringInfo(query, "DROP %sTABLE %s CASCADE",
|
appendStringInfo(query, "DROP %sTABLE %s CASCADE",
|
||||||
IsForeignTable(sourceId) ? "FOREIGN " : "",
|
IsForeignTable(sourceId) ? "FOREIGN " : "",
|
||||||
quote_qualified_identifier(schemaName, sourceName));
|
qualifiedSourceName);
|
||||||
ExecuteQueryViaSPI(query->data, SPI_OK_UTILITY);
|
ExecuteQueryViaSPI(query->data, SPI_OK_UTILITY);
|
||||||
|
|
||||||
if (!suppressNoticeMessages)
|
if (!suppressNoticeMessages)
|
||||||
{
|
{
|
||||||
ereport(NOTICE, (errmsg("renaming the new table to %s",
|
ereport(NOTICE, (errmsg("renaming the new table to %s", qualifiedSourceName)));
|
||||||
quote_qualified_identifier(schemaName, sourceName))));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resetStringInfo(query);
|
resetStringInfo(query);
|
||||||
appendStringInfo(query, "ALTER TABLE %s RENAME TO %s",
|
appendStringInfo(query, "ALTER TABLE %s RENAME TO %s",
|
||||||
quote_qualified_identifier(schemaName, targetName),
|
qualifiedTargetName,
|
||||||
quote_identifier(sourceName));
|
quote_identifier(sourceName));
|
||||||
ExecuteQueryViaSPI(query->data, SPI_OK_UTILITY);
|
ExecuteQueryViaSPI(query->data, SPI_OK_UTILITY);
|
||||||
}
|
}
|
||||||
|
@ -2001,7 +1987,7 @@ CheckAlterDistributedTableConversionParameters(TableConversionState *con)
|
||||||
Oid colocatedTableOid = InvalidOid;
|
Oid colocatedTableOid = InvalidOid;
|
||||||
text *colocateWithText = cstring_to_text(con->colocateWith);
|
text *colocateWithText = cstring_to_text(con->colocateWith);
|
||||||
Oid colocateWithTableOid = ResolveRelationId(colocateWithText, false);
|
Oid colocateWithTableOid = ResolveRelationId(colocateWithText, false);
|
||||||
foreach_oid(colocatedTableOid, con->colocatedTableList)
|
foreach_declared_oid(colocatedTableOid, con->colocatedTableList)
|
||||||
{
|
{
|
||||||
if (colocateWithTableOid == colocatedTableOid)
|
if (colocateWithTableOid == colocatedTableOid)
|
||||||
{
|
{
|
||||||
|
@ -2170,18 +2156,13 @@ CheckAlterDistributedTableConversionParameters(TableConversionState *con)
|
||||||
* worker_change_sequence_dependency query with the parameters.
|
* worker_change_sequence_dependency query with the parameters.
|
||||||
*/
|
*/
|
||||||
static char *
|
static char *
|
||||||
CreateWorkerChangeSequenceDependencyCommand(char *sequenceSchemaName, char *sequenceName,
|
CreateWorkerChangeSequenceDependencyCommand(char *qualifiedSequeceName,
|
||||||
char *sourceSchemaName, char *sourceName,
|
char *qualifiedSourceName,
|
||||||
char *targetSchemaName, char *targetName)
|
char *qualifiedTargetName)
|
||||||
{
|
{
|
||||||
char *qualifiedSchemaName = quote_qualified_identifier(sequenceSchemaName,
|
|
||||||
sequenceName);
|
|
||||||
char *qualifiedSourceName = quote_qualified_identifier(sourceSchemaName, sourceName);
|
|
||||||
char *qualifiedTargetName = quote_qualified_identifier(targetSchemaName, targetName);
|
|
||||||
|
|
||||||
StringInfo query = makeStringInfo();
|
StringInfo query = makeStringInfo();
|
||||||
appendStringInfo(query, "SELECT worker_change_sequence_dependency(%s, %s, %s)",
|
appendStringInfo(query, "SELECT worker_change_sequence_dependency(%s, %s, %s)",
|
||||||
quote_literal_cstr(qualifiedSchemaName),
|
quote_literal_cstr(qualifiedSequeceName),
|
||||||
quote_literal_cstr(qualifiedSourceName),
|
quote_literal_cstr(qualifiedSourceName),
|
||||||
quote_literal_cstr(qualifiedTargetName));
|
quote_literal_cstr(qualifiedTargetName));
|
||||||
|
|
||||||
|
@ -2233,7 +2214,7 @@ WillRecreateForeignKeyToReferenceTable(Oid relationId,
|
||||||
{
|
{
|
||||||
List *colocatedTableList = ColocatedTableList(relationId);
|
List *colocatedTableList = ColocatedTableList(relationId);
|
||||||
Oid colocatedTableOid = InvalidOid;
|
Oid colocatedTableOid = InvalidOid;
|
||||||
foreach_oid(colocatedTableOid, colocatedTableList)
|
foreach_declared_oid(colocatedTableOid, colocatedTableList)
|
||||||
{
|
{
|
||||||
if (HasForeignKeyToReferenceTable(colocatedTableOid))
|
if (HasForeignKeyToReferenceTable(colocatedTableOid))
|
||||||
{
|
{
|
||||||
|
@ -2261,7 +2242,7 @@ WarningsForDroppingForeignKeysWithDistributedTables(Oid relationId)
|
||||||
List *foreignKeys = list_concat(referencingForeingKeys, referencedForeignKeys);
|
List *foreignKeys = list_concat(referencingForeingKeys, referencedForeignKeys);
|
||||||
|
|
||||||
Oid foreignKeyOid = InvalidOid;
|
Oid foreignKeyOid = InvalidOid;
|
||||||
foreach_oid(foreignKeyOid, foreignKeys)
|
foreach_declared_oid(foreignKeyOid, foreignKeys)
|
||||||
{
|
{
|
||||||
ereport(WARNING, (errmsg("foreign key %s will be dropped",
|
ereport(WARNING, (errmsg("foreign key %s will be dropped",
|
||||||
get_constraint_name(foreignKeyOid))));
|
get_constraint_name(foreignKeyOid))));
|
||||||
|
|
|
@ -9,12 +9,14 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
#include "c.h"
|
#include "c.h"
|
||||||
|
|
||||||
|
#include "nodes/parsenodes.h"
|
||||||
|
|
||||||
#include "distributed/commands.h"
|
#include "distributed/commands.h"
|
||||||
#include "distributed/listutils.h"
|
#include "distributed/listutils.h"
|
||||||
#include "distributed/transaction_management.h"
|
#include "distributed/transaction_management.h"
|
||||||
#include "nodes/parsenodes.h"
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -31,7 +33,7 @@ SaveBeginCommandProperties(TransactionStmt *transactionStmt)
|
||||||
*
|
*
|
||||||
* While BEGIN can be quite frequent it will rarely have options set.
|
* While BEGIN can be quite frequent it will rarely have options set.
|
||||||
*/
|
*/
|
||||||
foreach_ptr(item, transactionStmt->options)
|
foreach_declared_ptr(item, transactionStmt->options)
|
||||||
{
|
{
|
||||||
A_Const *constant = (A_Const *) item->arg;
|
A_Const *constant = (A_Const *) item->arg;
|
||||||
|
|
||||||
|
|
|
@ -11,12 +11,23 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
#include "funcapi.h"
|
|
||||||
|
|
||||||
#include "distributed/pg_version_constants.h"
|
#include "funcapi.h"
|
||||||
|
#include "miscadmin.h"
|
||||||
|
|
||||||
#include "catalog/pg_proc.h"
|
#include "catalog/pg_proc.h"
|
||||||
#include "commands/defrem.h"
|
#include "commands/defrem.h"
|
||||||
|
#include "nodes/nodeFuncs.h"
|
||||||
|
#include "nodes/parsenodes.h"
|
||||||
|
#include "nodes/primnodes.h"
|
||||||
|
#include "optimizer/clauses.h"
|
||||||
|
#include "tcop/dest.h"
|
||||||
|
#include "utils/lsyscache.h"
|
||||||
|
#include "utils/syscache.h"
|
||||||
|
|
||||||
|
#include "pg_version_constants.h"
|
||||||
|
|
||||||
|
#include "distributed/adaptive_executor.h"
|
||||||
#include "distributed/backend_data.h"
|
#include "distributed/backend_data.h"
|
||||||
#include "distributed/citus_ruleutils.h"
|
#include "distributed/citus_ruleutils.h"
|
||||||
#include "distributed/colocation_utils.h"
|
#include "distributed/colocation_utils.h"
|
||||||
|
@ -26,27 +37,17 @@
|
||||||
#include "distributed/connection_management.h"
|
#include "distributed/connection_management.h"
|
||||||
#include "distributed/deparse_shard_query.h"
|
#include "distributed/deparse_shard_query.h"
|
||||||
#include "distributed/function_call_delegation.h"
|
#include "distributed/function_call_delegation.h"
|
||||||
#include "distributed/metadata_utility.h"
|
|
||||||
#include "distributed/metadata_cache.h"
|
#include "distributed/metadata_cache.h"
|
||||||
|
#include "distributed/metadata_utility.h"
|
||||||
#include "distributed/multi_executor.h"
|
#include "distributed/multi_executor.h"
|
||||||
#include "distributed/multi_physical_planner.h"
|
#include "distributed/multi_physical_planner.h"
|
||||||
#include "distributed/adaptive_executor.h"
|
|
||||||
#include "distributed/reference_table_utils.h"
|
#include "distributed/reference_table_utils.h"
|
||||||
#include "distributed/remote_commands.h"
|
#include "distributed/remote_commands.h"
|
||||||
#include "distributed/reference_table_utils.h"
|
|
||||||
#include "distributed/shard_pruning.h"
|
#include "distributed/shard_pruning.h"
|
||||||
#include "distributed/tuple_destination.h"
|
#include "distributed/tuple_destination.h"
|
||||||
#include "distributed/version_compat.h"
|
#include "distributed/version_compat.h"
|
||||||
#include "distributed/worker_manager.h"
|
|
||||||
#include "distributed/worker_log_messages.h"
|
#include "distributed/worker_log_messages.h"
|
||||||
#include "optimizer/clauses.h"
|
#include "distributed/worker_manager.h"
|
||||||
#include "nodes/nodeFuncs.h"
|
|
||||||
#include "nodes/parsenodes.h"
|
|
||||||
#include "nodes/primnodes.h"
|
|
||||||
#include "miscadmin.h"
|
|
||||||
#include "tcop/dest.h"
|
|
||||||
#include "utils/lsyscache.h"
|
|
||||||
#include "utils/syscache.h"
|
|
||||||
|
|
||||||
|
|
||||||
/* global variable tracking whether we are in a delegated procedure call */
|
/* global variable tracking whether we are in a delegated procedure call */
|
||||||
|
|
|
@ -12,12 +12,19 @@
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
#include "distributed/pg_version_constants.h"
|
#include "miscadmin.h"
|
||||||
|
|
||||||
#include "access/xact.h"
|
#include "access/xact.h"
|
||||||
#include "catalog/pg_constraint.h"
|
#include "catalog/pg_constraint.h"
|
||||||
#include "distributed/commands/utility_hook.h"
|
#include "executor/spi.h"
|
||||||
|
#include "utils/builtins.h"
|
||||||
|
#include "utils/lsyscache.h"
|
||||||
|
#include "utils/syscache.h"
|
||||||
|
|
||||||
|
#include "pg_version_constants.h"
|
||||||
|
|
||||||
#include "distributed/commands.h"
|
#include "distributed/commands.h"
|
||||||
|
#include "distributed/commands/utility_hook.h"
|
||||||
#include "distributed/foreign_key_relationship.h"
|
#include "distributed/foreign_key_relationship.h"
|
||||||
#include "distributed/listutils.h"
|
#include "distributed/listutils.h"
|
||||||
#include "distributed/local_executor.h"
|
#include "distributed/local_executor.h"
|
||||||
|
@ -26,11 +33,6 @@
|
||||||
#include "distributed/reference_table_utils.h"
|
#include "distributed/reference_table_utils.h"
|
||||||
#include "distributed/relation_access_tracking.h"
|
#include "distributed/relation_access_tracking.h"
|
||||||
#include "distributed/worker_protocol.h"
|
#include "distributed/worker_protocol.h"
|
||||||
#include "executor/spi.h"
|
|
||||||
#include "miscadmin.h"
|
|
||||||
#include "utils/builtins.h"
|
|
||||||
#include "utils/lsyscache.h"
|
|
||||||
#include "utils/syscache.h"
|
|
||||||
|
|
||||||
|
|
||||||
static void EnsureSequentialModeForCitusTableCascadeFunction(List *relationIdList);
|
static void EnsureSequentialModeForCitusTableCascadeFunction(List *relationIdList);
|
||||||
|
@ -166,7 +168,7 @@ GetPartitionRelationIds(List *relationIdList)
|
||||||
List *partitionRelationIdList = NIL;
|
List *partitionRelationIdList = NIL;
|
||||||
|
|
||||||
Oid relationId = InvalidOid;
|
Oid relationId = InvalidOid;
|
||||||
foreach_oid(relationId, relationIdList)
|
foreach_declared_oid(relationId, relationIdList)
|
||||||
{
|
{
|
||||||
if (PartitionTable(relationId))
|
if (PartitionTable(relationId))
|
||||||
{
|
{
|
||||||
|
@ -187,7 +189,7 @@ LockRelationsWithLockMode(List *relationIdList, LOCKMODE lockMode)
|
||||||
{
|
{
|
||||||
Oid relationId;
|
Oid relationId;
|
||||||
relationIdList = SortList(relationIdList, CompareOids);
|
relationIdList = SortList(relationIdList, CompareOids);
|
||||||
foreach_oid(relationId, relationIdList)
|
foreach_declared_oid(relationId, relationIdList)
|
||||||
{
|
{
|
||||||
LockRelationOid(relationId, lockMode);
|
LockRelationOid(relationId, lockMode);
|
||||||
}
|
}
|
||||||
|
@ -205,7 +207,7 @@ static void
|
||||||
ErrorIfConvertingMultiLevelPartitionedTable(List *relationIdList)
|
ErrorIfConvertingMultiLevelPartitionedTable(List *relationIdList)
|
||||||
{
|
{
|
||||||
Oid relationId;
|
Oid relationId;
|
||||||
foreach_oid(relationId, relationIdList)
|
foreach_declared_oid(relationId, relationIdList)
|
||||||
{
|
{
|
||||||
if (PartitionedTable(relationId) && PartitionTable(relationId))
|
if (PartitionedTable(relationId) && PartitionTable(relationId))
|
||||||
{
|
{
|
||||||
|
@ -234,7 +236,7 @@ void
|
||||||
ErrorIfAnyPartitionRelationInvolvedInNonInheritedFKey(List *relationIdList)
|
ErrorIfAnyPartitionRelationInvolvedInNonInheritedFKey(List *relationIdList)
|
||||||
{
|
{
|
||||||
Oid relationId = InvalidOid;
|
Oid relationId = InvalidOid;
|
||||||
foreach_oid(relationId, relationIdList)
|
foreach_declared_oid(relationId, relationIdList)
|
||||||
{
|
{
|
||||||
if (!PartitionTable(relationId))
|
if (!PartitionTable(relationId))
|
||||||
{
|
{
|
||||||
|
@ -298,7 +300,7 @@ bool
|
||||||
RelationIdListHasReferenceTable(List *relationIdList)
|
RelationIdListHasReferenceTable(List *relationIdList)
|
||||||
{
|
{
|
||||||
Oid relationId = InvalidOid;
|
Oid relationId = InvalidOid;
|
||||||
foreach_oid(relationId, relationIdList)
|
foreach_declared_oid(relationId, relationIdList)
|
||||||
{
|
{
|
||||||
if (IsCitusTableType(relationId, REFERENCE_TABLE))
|
if (IsCitusTableType(relationId, REFERENCE_TABLE))
|
||||||
{
|
{
|
||||||
|
@ -320,7 +322,7 @@ GetFKeyCreationCommandsForRelationIdList(List *relationIdList)
|
||||||
List *fKeyCreationCommands = NIL;
|
List *fKeyCreationCommands = NIL;
|
||||||
|
|
||||||
Oid relationId = InvalidOid;
|
Oid relationId = InvalidOid;
|
||||||
foreach_oid(relationId, relationIdList)
|
foreach_declared_oid(relationId, relationIdList)
|
||||||
{
|
{
|
||||||
List *relationFKeyCreationCommands =
|
List *relationFKeyCreationCommands =
|
||||||
GetReferencingForeignConstaintCommands(relationId);
|
GetReferencingForeignConstaintCommands(relationId);
|
||||||
|
@ -340,7 +342,7 @@ static void
|
||||||
DropRelationIdListForeignKeys(List *relationIdList, int fKeyFlags)
|
DropRelationIdListForeignKeys(List *relationIdList, int fKeyFlags)
|
||||||
{
|
{
|
||||||
Oid relationId = InvalidOid;
|
Oid relationId = InvalidOid;
|
||||||
foreach_oid(relationId, relationIdList)
|
foreach_declared_oid(relationId, relationIdList)
|
||||||
{
|
{
|
||||||
DropRelationForeignKeys(relationId, fKeyFlags);
|
DropRelationForeignKeys(relationId, fKeyFlags);
|
||||||
}
|
}
|
||||||
|
@ -397,7 +399,7 @@ GetRelationDropFkeyCommands(Oid relationId, int fKeyFlags)
|
||||||
List *relationFKeyIdList = GetForeignKeyOids(relationId, fKeyFlags);
|
List *relationFKeyIdList = GetForeignKeyOids(relationId, fKeyFlags);
|
||||||
|
|
||||||
Oid foreignKeyId;
|
Oid foreignKeyId;
|
||||||
foreach_oid(foreignKeyId, relationFKeyIdList)
|
foreach_declared_oid(foreignKeyId, relationFKeyIdList)
|
||||||
{
|
{
|
||||||
char *dropFkeyCascadeCommand = GetDropFkeyCascadeCommand(foreignKeyId);
|
char *dropFkeyCascadeCommand = GetDropFkeyCascadeCommand(foreignKeyId);
|
||||||
dropFkeyCascadeCommandList = lappend(dropFkeyCascadeCommandList,
|
dropFkeyCascadeCommandList = lappend(dropFkeyCascadeCommandList,
|
||||||
|
@ -448,7 +450,7 @@ ExecuteCascadeOperationForRelationIdList(List *relationIdList,
|
||||||
cascadeOperationType)
|
cascadeOperationType)
|
||||||
{
|
{
|
||||||
Oid relationId = InvalidOid;
|
Oid relationId = InvalidOid;
|
||||||
foreach_oid(relationId, relationIdList)
|
foreach_declared_oid(relationId, relationIdList)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* The reason behind skipping certain table types in below loop is
|
* The reason behind skipping certain table types in below loop is
|
||||||
|
@ -529,7 +531,7 @@ ExecuteAndLogUtilityCommandListInTableTypeConversionViaSPI(List *utilityCommandL
|
||||||
PG_TRY();
|
PG_TRY();
|
||||||
{
|
{
|
||||||
char *utilityCommand = NULL;
|
char *utilityCommand = NULL;
|
||||||
foreach_ptr(utilityCommand, utilityCommandList)
|
foreach_declared_ptr(utilityCommand, utilityCommandList)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* CREATE MATERIALIZED VIEW commands need to be parsed/transformed,
|
* CREATE MATERIALIZED VIEW commands need to be parsed/transformed,
|
||||||
|
@ -567,7 +569,7 @@ void
|
||||||
ExecuteAndLogUtilityCommandList(List *utilityCommandList)
|
ExecuteAndLogUtilityCommandList(List *utilityCommandList)
|
||||||
{
|
{
|
||||||
char *utilityCommand = NULL;
|
char *utilityCommand = NULL;
|
||||||
foreach_ptr(utilityCommand, utilityCommandList)
|
foreach_declared_ptr(utilityCommand, utilityCommandList)
|
||||||
{
|
{
|
||||||
ExecuteAndLogUtilityCommand(utilityCommand);
|
ExecuteAndLogUtilityCommand(utilityCommand);
|
||||||
}
|
}
|
||||||
|
@ -595,7 +597,7 @@ void
|
||||||
ExecuteForeignKeyCreateCommandList(List *ddlCommandList, bool skip_validation)
|
ExecuteForeignKeyCreateCommandList(List *ddlCommandList, bool skip_validation)
|
||||||
{
|
{
|
||||||
char *ddlCommand = NULL;
|
char *ddlCommand = NULL;
|
||||||
foreach_ptr(ddlCommand, ddlCommandList)
|
foreach_declared_ptr(ddlCommand, ddlCommandList)
|
||||||
{
|
{
|
||||||
ExecuteForeignKeyCreateCommand(ddlCommand, skip_validation);
|
ExecuteForeignKeyCreateCommand(ddlCommand, skip_validation);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
|
|
||||||
#include "access/genam.h"
|
#include "access/genam.h"
|
||||||
|
@ -25,29 +26,30 @@
|
||||||
#include "catalog/pg_constraint.h"
|
#include "catalog/pg_constraint.h"
|
||||||
#include "catalog/pg_statistic_ext.h"
|
#include "catalog/pg_statistic_ext.h"
|
||||||
#include "catalog/pg_trigger.h"
|
#include "catalog/pg_trigger.h"
|
||||||
#include "distributed/coordinator_protocol.h"
|
#include "foreign/foreign.h"
|
||||||
|
#include "utils/builtins.h"
|
||||||
|
#include "utils/fmgroids.h"
|
||||||
|
#include "utils/lsyscache.h"
|
||||||
|
#include "utils/ruleutils.h"
|
||||||
|
#include "utils/syscache.h"
|
||||||
|
|
||||||
#include "distributed/citus_ruleutils.h"
|
#include "distributed/citus_ruleutils.h"
|
||||||
#include "distributed/colocation_utils.h"
|
#include "distributed/colocation_utils.h"
|
||||||
#include "distributed/commands.h"
|
#include "distributed/commands.h"
|
||||||
#include "distributed/commands/sequence.h"
|
#include "distributed/commands/sequence.h"
|
||||||
#include "distributed/commands/utility_hook.h"
|
#include "distributed/commands/utility_hook.h"
|
||||||
#include "distributed/metadata/distobject.h"
|
#include "distributed/coordinator_protocol.h"
|
||||||
#include "distributed/metadata/dependency.h"
|
|
||||||
#include "distributed/foreign_key_relationship.h"
|
#include "distributed/foreign_key_relationship.h"
|
||||||
#include "distributed/listutils.h"
|
#include "distributed/listutils.h"
|
||||||
#include "distributed/local_executor.h"
|
#include "distributed/local_executor.h"
|
||||||
|
#include "distributed/metadata/dependency.h"
|
||||||
|
#include "distributed/metadata/distobject.h"
|
||||||
#include "distributed/metadata_sync.h"
|
#include "distributed/metadata_sync.h"
|
||||||
#include "distributed/multi_partitioning_utils.h"
|
#include "distributed/multi_partitioning_utils.h"
|
||||||
#include "distributed/namespace_utils.h"
|
#include "distributed/namespace_utils.h"
|
||||||
#include "distributed/reference_table_utils.h"
|
#include "distributed/reference_table_utils.h"
|
||||||
#include "distributed/worker_protocol.h"
|
#include "distributed/worker_protocol.h"
|
||||||
#include "distributed/worker_shard_visibility.h"
|
#include "distributed/worker_shard_visibility.h"
|
||||||
#include "utils/builtins.h"
|
|
||||||
#include "utils/fmgroids.h"
|
|
||||||
#include "utils/lsyscache.h"
|
|
||||||
#include "utils/ruleutils.h"
|
|
||||||
#include "utils/syscache.h"
|
|
||||||
#include "foreign/foreign.h"
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -586,7 +588,7 @@ ErrorIfOptionListHasNoTableName(List *optionList)
|
||||||
{
|
{
|
||||||
char *table_nameString = "table_name";
|
char *table_nameString = "table_name";
|
||||||
DefElem *option = NULL;
|
DefElem *option = NULL;
|
||||||
foreach_ptr(option, optionList)
|
foreach_declared_ptr(option, optionList)
|
||||||
{
|
{
|
||||||
char *optionName = option->defname;
|
char *optionName = option->defname;
|
||||||
if (strcmp(optionName, table_nameString) == 0)
|
if (strcmp(optionName, table_nameString) == 0)
|
||||||
|
@ -611,7 +613,7 @@ ForeignTableDropsTableNameOption(List *optionList)
|
||||||
{
|
{
|
||||||
char *table_nameString = "table_name";
|
char *table_nameString = "table_name";
|
||||||
DefElem *option = NULL;
|
DefElem *option = NULL;
|
||||||
foreach_ptr(option, optionList)
|
foreach_declared_ptr(option, optionList)
|
||||||
{
|
{
|
||||||
char *optionName = option->defname;
|
char *optionName = option->defname;
|
||||||
DefElemAction optionAction = option->defaction;
|
DefElemAction optionAction = option->defaction;
|
||||||
|
@ -730,7 +732,7 @@ UpdateAutoConvertedForConnectedRelations(List *relationIds, bool autoConverted)
|
||||||
|
|
||||||
List *relationIdList = NIL;
|
List *relationIdList = NIL;
|
||||||
Oid relid = InvalidOid;
|
Oid relid = InvalidOid;
|
||||||
foreach_oid(relid, relationIds)
|
foreach_declared_oid(relid, relationIds)
|
||||||
{
|
{
|
||||||
List *connectedRelations = GetForeignKeyConnectedRelationIdList(relid);
|
List *connectedRelations = GetForeignKeyConnectedRelationIdList(relid);
|
||||||
relationIdList = list_concat_unique_oid(relationIdList, connectedRelations);
|
relationIdList = list_concat_unique_oid(relationIdList, connectedRelations);
|
||||||
|
@ -738,7 +740,7 @@ UpdateAutoConvertedForConnectedRelations(List *relationIds, bool autoConverted)
|
||||||
|
|
||||||
relationIdList = SortList(relationIdList, CompareOids);
|
relationIdList = SortList(relationIdList, CompareOids);
|
||||||
|
|
||||||
foreach_oid(relid, relationIdList)
|
foreach_declared_oid(relid, relationIdList)
|
||||||
{
|
{
|
||||||
UpdatePgDistPartitionAutoConverted(relid, autoConverted);
|
UpdatePgDistPartitionAutoConverted(relid, autoConverted);
|
||||||
}
|
}
|
||||||
|
@ -774,7 +776,7 @@ GetShellTableDDLEventsForCitusLocalTable(Oid relationId)
|
||||||
|
|
||||||
List *shellTableDDLEvents = NIL;
|
List *shellTableDDLEvents = NIL;
|
||||||
TableDDLCommand *tableDDLCommand = NULL;
|
TableDDLCommand *tableDDLCommand = NULL;
|
||||||
foreach_ptr(tableDDLCommand, tableDDLCommands)
|
foreach_declared_ptr(tableDDLCommand, tableDDLCommands)
|
||||||
{
|
{
|
||||||
Assert(CitusIsA(tableDDLCommand, TableDDLCommand));
|
Assert(CitusIsA(tableDDLCommand, TableDDLCommand));
|
||||||
shellTableDDLEvents = lappend(shellTableDDLEvents,
|
shellTableDDLEvents = lappend(shellTableDDLEvents,
|
||||||
|
@ -861,7 +863,7 @@ RenameShardRelationConstraints(Oid shardRelationId, uint64 shardId)
|
||||||
List *constraintNameList = GetConstraintNameList(shardRelationId);
|
List *constraintNameList = GetConstraintNameList(shardRelationId);
|
||||||
|
|
||||||
char *constraintName = NULL;
|
char *constraintName = NULL;
|
||||||
foreach_ptr(constraintName, constraintNameList)
|
foreach_declared_ptr(constraintName, constraintNameList)
|
||||||
{
|
{
|
||||||
const char *commandString =
|
const char *commandString =
|
||||||
GetRenameShardConstraintCommand(shardRelationId, constraintName, shardId);
|
GetRenameShardConstraintCommand(shardRelationId, constraintName, shardId);
|
||||||
|
@ -956,7 +958,7 @@ RenameShardRelationIndexes(Oid shardRelationId, uint64 shardId)
|
||||||
List *indexOidList = GetExplicitIndexOidList(shardRelationId);
|
List *indexOidList = GetExplicitIndexOidList(shardRelationId);
|
||||||
|
|
||||||
Oid indexOid = InvalidOid;
|
Oid indexOid = InvalidOid;
|
||||||
foreach_oid(indexOid, indexOidList)
|
foreach_declared_oid(indexOid, indexOidList)
|
||||||
{
|
{
|
||||||
const char *commandString = GetRenameShardIndexCommand(indexOid, shardId);
|
const char *commandString = GetRenameShardIndexCommand(indexOid, shardId);
|
||||||
ExecuteAndLogUtilityCommand(commandString);
|
ExecuteAndLogUtilityCommand(commandString);
|
||||||
|
@ -1006,7 +1008,7 @@ RenameShardRelationStatistics(Oid shardRelationId, uint64 shardId)
|
||||||
List *statsCommandList = GetRenameStatsCommandList(statsOidList, shardId);
|
List *statsCommandList = GetRenameStatsCommandList(statsOidList, shardId);
|
||||||
|
|
||||||
char *command = NULL;
|
char *command = NULL;
|
||||||
foreach_ptr(command, statsCommandList)
|
foreach_declared_ptr(command, statsCommandList)
|
||||||
{
|
{
|
||||||
ExecuteAndLogUtilityCommand(command);
|
ExecuteAndLogUtilityCommand(command);
|
||||||
}
|
}
|
||||||
|
@ -1042,7 +1044,7 @@ RenameShardRelationNonTruncateTriggers(Oid shardRelationId, uint64 shardId)
|
||||||
List *triggerIdList = GetExplicitTriggerIdList(shardRelationId);
|
List *triggerIdList = GetExplicitTriggerIdList(shardRelationId);
|
||||||
|
|
||||||
Oid triggerId = InvalidOid;
|
Oid triggerId = InvalidOid;
|
||||||
foreach_oid(triggerId, triggerIdList)
|
foreach_declared_oid(triggerId, triggerIdList)
|
||||||
{
|
{
|
||||||
bool missingOk = false;
|
bool missingOk = false;
|
||||||
HeapTuple triggerTuple = GetTriggerTupleById(triggerId, missingOk);
|
HeapTuple triggerTuple = GetTriggerTupleById(triggerId, missingOk);
|
||||||
|
@ -1095,7 +1097,7 @@ DropRelationTruncateTriggers(Oid relationId)
|
||||||
List *triggerIdList = GetExplicitTriggerIdList(relationId);
|
List *triggerIdList = GetExplicitTriggerIdList(relationId);
|
||||||
|
|
||||||
Oid triggerId = InvalidOid;
|
Oid triggerId = InvalidOid;
|
||||||
foreach_oid(triggerId, triggerIdList)
|
foreach_declared_oid(triggerId, triggerIdList)
|
||||||
{
|
{
|
||||||
bool missingOk = false;
|
bool missingOk = false;
|
||||||
HeapTuple triggerTuple = GetTriggerTupleById(triggerId, missingOk);
|
HeapTuple triggerTuple = GetTriggerTupleById(triggerId, missingOk);
|
||||||
|
@ -1158,9 +1160,7 @@ DropIdentitiesOnTable(Oid relationId)
|
||||||
|
|
||||||
if (attributeForm->attidentity)
|
if (attributeForm->attidentity)
|
||||||
{
|
{
|
||||||
char *tableName = get_rel_name(relationId);
|
char *qualifiedTableName = generate_qualified_relation_name(relationId);
|
||||||
char *schemaName = get_namespace_name(get_rel_namespace(relationId));
|
|
||||||
char *qualifiedTableName = quote_qualified_identifier(schemaName, tableName);
|
|
||||||
|
|
||||||
StringInfo dropCommand = makeStringInfo();
|
StringInfo dropCommand = makeStringInfo();
|
||||||
|
|
||||||
|
@ -1175,7 +1175,7 @@ DropIdentitiesOnTable(Oid relationId)
|
||||||
relation_close(relation, NoLock);
|
relation_close(relation, NoLock);
|
||||||
|
|
||||||
char *dropCommand = NULL;
|
char *dropCommand = NULL;
|
||||||
foreach_ptr(dropCommand, dropCommandList)
|
foreach_declared_ptr(dropCommand, dropCommandList)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* We need to disable/enable ddl propagation for this command, to prevent
|
* We need to disable/enable ddl propagation for this command, to prevent
|
||||||
|
@ -1218,11 +1218,9 @@ DropViewsOnTable(Oid relationId)
|
||||||
List *reverseOrderedViews = ReversedOidList(views);
|
List *reverseOrderedViews = ReversedOidList(views);
|
||||||
|
|
||||||
Oid viewId = InvalidOid;
|
Oid viewId = InvalidOid;
|
||||||
foreach_oid(viewId, reverseOrderedViews)
|
foreach_declared_oid(viewId, reverseOrderedViews)
|
||||||
{
|
{
|
||||||
char *viewName = get_rel_name(viewId);
|
char *qualifiedViewName = generate_qualified_relation_name(viewId);
|
||||||
char *schemaName = get_namespace_name(get_rel_namespace(viewId));
|
|
||||||
char *qualifiedViewName = quote_qualified_identifier(schemaName, viewName);
|
|
||||||
|
|
||||||
StringInfo dropCommand = makeStringInfo();
|
StringInfo dropCommand = makeStringInfo();
|
||||||
appendStringInfo(dropCommand, "DROP %sVIEW IF EXISTS %s",
|
appendStringInfo(dropCommand, "DROP %sVIEW IF EXISTS %s",
|
||||||
|
@ -1243,7 +1241,7 @@ ReversedOidList(List *oidList)
|
||||||
{
|
{
|
||||||
List *reversed = NIL;
|
List *reversed = NIL;
|
||||||
Oid oid = InvalidOid;
|
Oid oid = InvalidOid;
|
||||||
foreach_oid(oid, oidList)
|
foreach_declared_oid(oid, oidList)
|
||||||
{
|
{
|
||||||
reversed = lcons_oid(oid, reversed);
|
reversed = lcons_oid(oid, reversed);
|
||||||
}
|
}
|
||||||
|
@ -1295,7 +1293,7 @@ GetRenameStatsCommandList(List *statsOidList, uint64 shardId)
|
||||||
{
|
{
|
||||||
List *statsCommandList = NIL;
|
List *statsCommandList = NIL;
|
||||||
Oid statsOid;
|
Oid statsOid;
|
||||||
foreach_oid(statsOid, statsOidList)
|
foreach_declared_oid(statsOid, statsOidList)
|
||||||
{
|
{
|
||||||
HeapTuple tup = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(statsOid));
|
HeapTuple tup = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(statsOid));
|
||||||
|
|
||||||
|
|
|
@ -11,14 +11,16 @@
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
#include "distributed/pg_version_constants.h"
|
#include "signal.h"
|
||||||
|
|
||||||
|
#include "lib/stringinfo.h"
|
||||||
|
|
||||||
|
#include "pg_version_constants.h"
|
||||||
|
|
||||||
#include "distributed/backend_data.h"
|
#include "distributed/backend_data.h"
|
||||||
#include "distributed/metadata_cache.h"
|
#include "distributed/metadata_cache.h"
|
||||||
#include "distributed/remote_commands.h"
|
#include "distributed/remote_commands.h"
|
||||||
#include "distributed/worker_manager.h"
|
#include "distributed/worker_manager.h"
|
||||||
#include "lib/stringinfo.h"
|
|
||||||
#include "signal.h"
|
|
||||||
|
|
||||||
static bool CitusSignalBackend(uint64 globalPID, uint64 timeout, int sig);
|
static bool CitusSignalBackend(uint64 globalPID, uint64 timeout, int sig);
|
||||||
|
|
||||||
|
|
|
@ -10,11 +10,11 @@
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
#include "distributed/pg_version_constants.h"
|
#include "catalog/namespace.h"
|
||||||
|
|
||||||
#include "commands/defrem.h"
|
#include "commands/defrem.h"
|
||||||
|
|
||||||
#include "catalog/namespace.h"
|
#include "pg_version_constants.h"
|
||||||
|
|
||||||
#include "distributed/commands.h"
|
#include "distributed/commands.h"
|
||||||
#include "distributed/commands/utility_hook.h"
|
#include "distributed/commands/utility_hook.h"
|
||||||
#include "distributed/listutils.h"
|
#include "distributed/listutils.h"
|
||||||
|
@ -115,7 +115,7 @@ static bool
|
||||||
IsClusterStmtVerbose_compat(ClusterStmt *clusterStmt)
|
IsClusterStmtVerbose_compat(ClusterStmt *clusterStmt)
|
||||||
{
|
{
|
||||||
DefElem *opt = NULL;
|
DefElem *opt = NULL;
|
||||||
foreach_ptr(opt, clusterStmt->params)
|
foreach_declared_ptr(opt, clusterStmt->params)
|
||||||
{
|
{
|
||||||
if (strcmp(opt->defname, "verbose") == 0)
|
if (strcmp(opt->defname, "verbose") == 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -10,30 +10,32 @@
|
||||||
*/
|
*/
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
#include "pg_version_compat.h"
|
#include "miscadmin.h"
|
||||||
|
|
||||||
#include "access/htup_details.h"
|
#include "access/htup_details.h"
|
||||||
#include "access/xact.h"
|
#include "access/xact.h"
|
||||||
#include "catalog/pg_collation.h"
|
#include "catalog/pg_collation.h"
|
||||||
#include "distributed/citus_safe_lib.h"
|
|
||||||
#include "distributed/commands/utility_hook.h"
|
|
||||||
#include "distributed/commands.h"
|
|
||||||
#include "distributed/deparser.h"
|
|
||||||
#include "distributed/listutils.h"
|
|
||||||
#include "distributed/metadata_utility.h"
|
|
||||||
#include "distributed/metadata/dependency.h"
|
|
||||||
#include "distributed/metadata/distobject.h"
|
|
||||||
#include "distributed/metadata_sync.h"
|
|
||||||
#include "distributed/multi_executor.h"
|
|
||||||
#include "distributed/relation_access_tracking.h"
|
|
||||||
#include "distributed/worker_create_or_replace.h"
|
|
||||||
#include "distributed/pg_version_constants.h"
|
|
||||||
#include "distributed/worker_manager.h"
|
|
||||||
#include "parser/parse_type.h"
|
#include "parser/parse_type.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "utils/lsyscache.h"
|
#include "utils/lsyscache.h"
|
||||||
#include "utils/syscache.h"
|
#include "utils/syscache.h"
|
||||||
#include "miscadmin.h"
|
|
||||||
|
#include "pg_version_compat.h"
|
||||||
|
#include "pg_version_constants.h"
|
||||||
|
|
||||||
|
#include "distributed/citus_safe_lib.h"
|
||||||
|
#include "distributed/commands.h"
|
||||||
|
#include "distributed/commands/utility_hook.h"
|
||||||
|
#include "distributed/deparser.h"
|
||||||
|
#include "distributed/listutils.h"
|
||||||
|
#include "distributed/metadata/dependency.h"
|
||||||
|
#include "distributed/metadata/distobject.h"
|
||||||
|
#include "distributed/metadata_sync.h"
|
||||||
|
#include "distributed/metadata_utility.h"
|
||||||
|
#include "distributed/multi_executor.h"
|
||||||
|
#include "distributed/relation_access_tracking.h"
|
||||||
|
#include "distributed/worker_create_or_replace.h"
|
||||||
|
#include "distributed/worker_manager.h"
|
||||||
|
|
||||||
|
|
||||||
static char * CreateCollationDDLInternal(Oid collationId, Oid *collowner,
|
static char * CreateCollationDDLInternal(Oid collationId, Oid *collowner,
|
||||||
|
@ -66,8 +68,6 @@ CreateCollationDDLInternal(Oid collationId, Oid *collowner, char **quotedCollati
|
||||||
char *collcollate;
|
char *collcollate;
|
||||||
char *collctype;
|
char *collctype;
|
||||||
|
|
||||||
#if PG_VERSION_NUM >= PG_VERSION_15
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In PG15, there is an added option to use ICU as global locale provider.
|
* In PG15, there is an added option to use ICU as global locale provider.
|
||||||
* pg_collation has three locale-related fields: collcollate and collctype,
|
* pg_collation has three locale-related fields: collcollate and collctype,
|
||||||
|
@ -75,7 +75,7 @@ CreateCollationDDLInternal(Oid collationId, Oid *collowner, char **quotedCollati
|
||||||
* ICU-related field. Only the libc-related fields or the ICU-related field
|
* ICU-related field. Only the libc-related fields or the ICU-related field
|
||||||
* is set, never both.
|
* is set, never both.
|
||||||
*/
|
*/
|
||||||
char *colliculocale;
|
char *colllocale;
|
||||||
bool isnull;
|
bool isnull;
|
||||||
|
|
||||||
Datum datum = SysCacheGetAttr(COLLOID, heapTuple, Anum_pg_collation_collcollate,
|
Datum datum = SysCacheGetAttr(COLLOID, heapTuple, Anum_pg_collation_collcollate,
|
||||||
|
@ -99,27 +99,17 @@ CreateCollationDDLInternal(Oid collationId, Oid *collowner, char **quotedCollati
|
||||||
collctype = NULL;
|
collctype = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
datum = SysCacheGetAttr(COLLOID, heapTuple, Anum_pg_collation_colliculocale, &isnull);
|
datum = SysCacheGetAttr(COLLOID, heapTuple, Anum_pg_collation_colllocale, &isnull);
|
||||||
if (!isnull)
|
if (!isnull)
|
||||||
{
|
{
|
||||||
colliculocale = TextDatumGetCString(datum);
|
colllocale = TextDatumGetCString(datum);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
colliculocale = NULL;
|
colllocale = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Assert((collcollate && collctype) || colliculocale);
|
Assert((collcollate && collctype) || colllocale);
|
||||||
#else
|
|
||||||
|
|
||||||
/*
|
|
||||||
* In versions before 15, collcollate and collctype were type "name". Use
|
|
||||||
* pstrdup() to match the interface of 15 so that we consistently free the
|
|
||||||
* result later.
|
|
||||||
*/
|
|
||||||
collcollate = pstrdup(NameStr(collationForm->collcollate));
|
|
||||||
collctype = pstrdup(NameStr(collationForm->collctype));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (collowner != NULL)
|
if (collowner != NULL)
|
||||||
{
|
{
|
||||||
|
@ -130,6 +120,7 @@ CreateCollationDDLInternal(Oid collationId, Oid *collowner, char **quotedCollati
|
||||||
char *schemaName = get_namespace_name(collnamespace);
|
char *schemaName = get_namespace_name(collnamespace);
|
||||||
*quotedCollationName = quote_qualified_identifier(schemaName, collname);
|
*quotedCollationName = quote_qualified_identifier(schemaName, collname);
|
||||||
const char *providerString =
|
const char *providerString =
|
||||||
|
collprovider == COLLPROVIDER_BUILTIN ? "builtin" :
|
||||||
collprovider == COLLPROVIDER_DEFAULT ? "default" :
|
collprovider == COLLPROVIDER_DEFAULT ? "default" :
|
||||||
collprovider == COLLPROVIDER_ICU ? "icu" :
|
collprovider == COLLPROVIDER_ICU ? "icu" :
|
||||||
collprovider == COLLPROVIDER_LIBC ? "libc" : NULL;
|
collprovider == COLLPROVIDER_LIBC ? "libc" : NULL;
|
||||||
|
@ -144,13 +135,12 @@ CreateCollationDDLInternal(Oid collationId, Oid *collowner, char **quotedCollati
|
||||||
"CREATE COLLATION %s (provider = '%s'",
|
"CREATE COLLATION %s (provider = '%s'",
|
||||||
*quotedCollationName, providerString);
|
*quotedCollationName, providerString);
|
||||||
|
|
||||||
#if PG_VERSION_NUM >= PG_VERSION_15
|
if (colllocale)
|
||||||
if (colliculocale)
|
|
||||||
{
|
{
|
||||||
appendStringInfo(&collationNameDef,
|
appendStringInfo(&collationNameDef,
|
||||||
", locale = %s",
|
", locale = %s",
|
||||||
quote_literal_cstr(colliculocale));
|
quote_literal_cstr(colllocale));
|
||||||
pfree(colliculocale);
|
pfree(colllocale);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -170,24 +160,7 @@ CreateCollationDDLInternal(Oid collationId, Oid *collowner, char **quotedCollati
|
||||||
pfree(collcollate);
|
pfree(collcollate);
|
||||||
pfree(collctype);
|
pfree(collctype);
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
if (strcmp(collcollate, collctype) == 0)
|
|
||||||
{
|
|
||||||
appendStringInfo(&collationNameDef,
|
|
||||||
", locale = %s",
|
|
||||||
quote_literal_cstr(collcollate));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
appendStringInfo(&collationNameDef,
|
|
||||||
", lc_collate = %s, lc_ctype = %s",
|
|
||||||
quote_literal_cstr(collcollate),
|
|
||||||
quote_literal_cstr(collctype));
|
|
||||||
}
|
|
||||||
|
|
||||||
pfree(collcollate);
|
|
||||||
pfree(collctype);
|
|
||||||
#endif
|
|
||||||
#if PG_VERSION_NUM >= PG_VERSION_16
|
#if PG_VERSION_NUM >= PG_VERSION_16
|
||||||
char *collicurules = NULL;
|
char *collicurules = NULL;
|
||||||
datum = SysCacheGetAttr(COLLOID, heapTuple, Anum_pg_collation_collicurules, &isnull);
|
datum = SysCacheGetAttr(COLLOID, heapTuple, Anum_pg_collation_collicurules, &isnull);
|
||||||
|
|
|
@ -0,0 +1,131 @@
|
||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* comment.c
|
||||||
|
* Commands to interact with the comments for all database
|
||||||
|
* object types.
|
||||||
|
*
|
||||||
|
* Copyright (c) Citus Data, Inc.
|
||||||
|
*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "postgres.h"
|
||||||
|
|
||||||
|
#include "access/genam.h"
|
||||||
|
#include "access/htup_details.h"
|
||||||
|
#include "access/table.h"
|
||||||
|
#include "catalog/pg_shdescription.h"
|
||||||
|
#include "nodes/parsenodes.h"
|
||||||
|
#include "utils/builtins.h"
|
||||||
|
#include "utils/fmgroids.h"
|
||||||
|
#include "utils/rel.h"
|
||||||
|
|
||||||
|
#include "distributed/comment.h"
|
||||||
|
|
||||||
|
static char * GetCommentForObject(Oid classOid, Oid objectOid);
|
||||||
|
|
||||||
|
|
||||||
|
List *
|
||||||
|
GetCommentPropagationCommands(Oid classOid, Oid objOoid, char *objectName, ObjectType
|
||||||
|
objectType)
|
||||||
|
{
|
||||||
|
List *commands = NIL;
|
||||||
|
|
||||||
|
StringInfo commentStmt = makeStringInfo();
|
||||||
|
|
||||||
|
/* Get the comment for the database */
|
||||||
|
char *comment = GetCommentForObject(classOid, objOoid);
|
||||||
|
char const *commentObjectType = ObjectTypeNames[objectType];
|
||||||
|
|
||||||
|
/* Create the SQL command to propagate the comment to other nodes */
|
||||||
|
if (comment != NULL)
|
||||||
|
{
|
||||||
|
appendStringInfo(commentStmt, "COMMENT ON %s %s IS %s;", commentObjectType,
|
||||||
|
quote_identifier(objectName),
|
||||||
|
quote_literal_cstr(comment));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Add the command to the list */
|
||||||
|
if (commentStmt->len > 0)
|
||||||
|
{
|
||||||
|
commands = list_make1(commentStmt->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return commands;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static char *
|
||||||
|
GetCommentForObject(Oid classOid, Oid objectOid)
|
||||||
|
{
|
||||||
|
HeapTuple tuple;
|
||||||
|
char *comment = NULL;
|
||||||
|
|
||||||
|
/* Open pg_shdescription catalog */
|
||||||
|
Relation shdescRelation = table_open(SharedDescriptionRelationId, AccessShareLock);
|
||||||
|
|
||||||
|
/* Scan the table */
|
||||||
|
ScanKeyData scanKey[2];
|
||||||
|
|
||||||
|
ScanKeyInit(&scanKey[0],
|
||||||
|
Anum_pg_shdescription_objoid,
|
||||||
|
BTEqualStrategyNumber, F_OIDEQ,
|
||||||
|
ObjectIdGetDatum(objectOid));
|
||||||
|
ScanKeyInit(&scanKey[1],
|
||||||
|
Anum_pg_shdescription_classoid,
|
||||||
|
BTEqualStrategyNumber, F_OIDEQ,
|
||||||
|
ObjectIdGetDatum(classOid));
|
||||||
|
bool indexOk = true;
|
||||||
|
int scanKeyCount = 2;
|
||||||
|
SysScanDesc scan = systable_beginscan(shdescRelation, SharedDescriptionObjIndexId,
|
||||||
|
indexOk, NULL, scanKeyCount,
|
||||||
|
scanKey);
|
||||||
|
if ((tuple = systable_getnext(scan)) != NULL)
|
||||||
|
{
|
||||||
|
bool isNull = false;
|
||||||
|
|
||||||
|
TupleDesc tupdesc = RelationGetDescr(shdescRelation);
|
||||||
|
|
||||||
|
Datum descDatum = heap_getattr(tuple, Anum_pg_shdescription_description, tupdesc,
|
||||||
|
&isNull);
|
||||||
|
|
||||||
|
|
||||||
|
/* Add the command to the list */
|
||||||
|
if (!isNull)
|
||||||
|
{
|
||||||
|
comment = TextDatumGetCString(descDatum);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
comment = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* End the scan and close the catalog */
|
||||||
|
systable_endscan(scan);
|
||||||
|
table_close(shdescRelation, AccessShareLock);
|
||||||
|
|
||||||
|
return comment;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CommentObjectAddress resolves the ObjectAddress for the object
|
||||||
|
* on which the comment is placed. Optionally errors if the object does not
|
||||||
|
* exist based on the missing_ok flag passed in by the caller.
|
||||||
|
*/
|
||||||
|
List *
|
||||||
|
CommentObjectAddress(Node *node, bool missing_ok, bool isPostprocess)
|
||||||
|
{
|
||||||
|
CommentStmt *stmt = castNode(CommentStmt, node);
|
||||||
|
Relation relation;
|
||||||
|
|
||||||
|
ObjectAddress objectAddress = get_object_address(stmt->objtype, stmt->object,
|
||||||
|
&relation, AccessExclusiveLock,
|
||||||
|
missing_ok);
|
||||||
|
|
||||||
|
ObjectAddress *objectAddressCopy = palloc0(sizeof(ObjectAddress));
|
||||||
|
*objectAddressCopy = objectAddress;
|
||||||
|
return list_make1(objectAddressCopy);
|
||||||
|
}
|
|
@ -23,9 +23,9 @@
|
||||||
#include "distributed/commands/utility_hook.h"
|
#include "distributed/commands/utility_hook.h"
|
||||||
#include "distributed/deparser.h"
|
#include "distributed/deparser.h"
|
||||||
#include "distributed/listutils.h"
|
#include "distributed/listutils.h"
|
||||||
#include "distributed/metadata_sync.h"
|
|
||||||
#include "distributed/metadata/dependency.h"
|
#include "distributed/metadata/dependency.h"
|
||||||
#include "distributed/metadata/distobject.h"
|
#include "distributed/metadata/distobject.h"
|
||||||
|
#include "distributed/metadata_sync.h"
|
||||||
#include "distributed/multi_executor.h"
|
#include "distributed/multi_executor.h"
|
||||||
#include "distributed/worker_transaction.h"
|
#include "distributed/worker_transaction.h"
|
||||||
|
|
||||||
|
@ -235,7 +235,7 @@ PreprocessDropDistributedObjectStmt(Node *node, const char *queryString,
|
||||||
List *distributedObjects = NIL;
|
List *distributedObjects = NIL;
|
||||||
List *distributedObjectAddresses = NIL;
|
List *distributedObjectAddresses = NIL;
|
||||||
Node *object = NULL;
|
Node *object = NULL;
|
||||||
foreach_ptr(object, stmt->objects)
|
foreach_declared_ptr(object, stmt->objects)
|
||||||
{
|
{
|
||||||
/* TODO understand if the lock should be sth else */
|
/* TODO understand if the lock should be sth else */
|
||||||
Relation rel = NULL; /* not used, but required to pass to get_object_address */
|
Relation rel = NULL; /* not used, but required to pass to get_object_address */
|
||||||
|
@ -267,7 +267,7 @@ PreprocessDropDistributedObjectStmt(Node *node, const char *queryString,
|
||||||
* remove the entries for the distributed objects on dropping
|
* remove the entries for the distributed objects on dropping
|
||||||
*/
|
*/
|
||||||
ObjectAddress *address = NULL;
|
ObjectAddress *address = NULL;
|
||||||
foreach_ptr(address, distributedObjectAddresses)
|
foreach_declared_ptr(address, distributedObjectAddresses)
|
||||||
{
|
{
|
||||||
UnmarkObjectDistributed(address);
|
UnmarkObjectDistributed(address);
|
||||||
}
|
}
|
||||||
|
@ -303,7 +303,7 @@ DropTextSearchDictObjectAddress(Node *node, bool missing_ok, bool isPostprocess)
|
||||||
List *objectAddresses = NIL;
|
List *objectAddresses = NIL;
|
||||||
|
|
||||||
List *objNameList = NIL;
|
List *objNameList = NIL;
|
||||||
foreach_ptr(objNameList, stmt->objects)
|
foreach_declared_ptr(objNameList, stmt->objects)
|
||||||
{
|
{
|
||||||
Oid tsdictOid = get_ts_dict_oid(objNameList, missing_ok);
|
Oid tsdictOid = get_ts_dict_oid(objNameList, missing_ok);
|
||||||
|
|
||||||
|
@ -328,7 +328,7 @@ DropTextSearchConfigObjectAddress(Node *node, bool missing_ok, bool isPostproces
|
||||||
List *objectAddresses = NIL;
|
List *objectAddresses = NIL;
|
||||||
|
|
||||||
List *objNameList = NIL;
|
List *objNameList = NIL;
|
||||||
foreach_ptr(objNameList, stmt->objects)
|
foreach_declared_ptr(objNameList, stmt->objects)
|
||||||
{
|
{
|
||||||
Oid tsconfigOid = get_ts_config_oid(objNameList, missing_ok);
|
Oid tsconfigOid = get_ts_config_oid(objNameList, missing_ok);
|
||||||
|
|
||||||
|
|
|
@ -9,10 +9,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
#include "miscadmin.h"
|
|
||||||
|
|
||||||
#include "distributed/pg_version_constants.h"
|
#include "miscadmin.h"
|
||||||
#include "distributed/commands/utility_hook.h"
|
|
||||||
|
|
||||||
#include "access/genam.h"
|
#include "access/genam.h"
|
||||||
#include "access/hash.h"
|
#include "access/hash.h"
|
||||||
|
@ -24,6 +22,7 @@
|
||||||
#include "catalog/dependency.h"
|
#include "catalog/dependency.h"
|
||||||
#include "catalog/index.h"
|
#include "catalog/index.h"
|
||||||
#include "catalog/pg_am.h"
|
#include "catalog/pg_am.h"
|
||||||
|
#include "catalog/pg_attrdef.h"
|
||||||
#include "catalog/pg_attribute.h"
|
#include "catalog/pg_attribute.h"
|
||||||
#include "catalog/pg_enum.h"
|
#include "catalog/pg_enum.h"
|
||||||
#include "catalog/pg_extension.h"
|
#include "catalog/pg_extension.h"
|
||||||
|
@ -37,42 +36,6 @@
|
||||||
#include "commands/sequence.h"
|
#include "commands/sequence.h"
|
||||||
#include "commands/tablecmds.h"
|
#include "commands/tablecmds.h"
|
||||||
#include "commands/trigger.h"
|
#include "commands/trigger.h"
|
||||||
#include "distributed/commands/multi_copy.h"
|
|
||||||
#include "distributed/citus_ruleutils.h"
|
|
||||||
#include "distributed/colocation_utils.h"
|
|
||||||
#include "distributed/commands.h"
|
|
||||||
#include "distributed/deparser.h"
|
|
||||||
#include "distributed/distributed_execution_locks.h"
|
|
||||||
#include "distributed/distribution_column.h"
|
|
||||||
#include "distributed/listutils.h"
|
|
||||||
#include "distributed/local_executor.h"
|
|
||||||
#include "distributed/metadata_utility.h"
|
|
||||||
#include "distributed/coordinator_protocol.h"
|
|
||||||
#include "distributed/metadata/dependency.h"
|
|
||||||
#include "distributed/metadata/distobject.h"
|
|
||||||
#include "distributed/metadata_cache.h"
|
|
||||||
#include "distributed/metadata_sync.h"
|
|
||||||
#include "distributed/multi_executor.h"
|
|
||||||
#include "distributed/multi_logical_planner.h"
|
|
||||||
#include "distributed/multi_partitioning_utils.h"
|
|
||||||
#include "distributed/pg_dist_colocation.h"
|
|
||||||
#include "distributed/pg_dist_partition.h"
|
|
||||||
#include "distributed/reference_table_utils.h"
|
|
||||||
#include "distributed/relation_access_tracking.h"
|
|
||||||
#include "distributed/remote_commands.h"
|
|
||||||
#include "distributed/replicate_none_dist_table_shard.h"
|
|
||||||
#include "distributed/resource_lock.h"
|
|
||||||
#include "distributed/shard_cleaner.h"
|
|
||||||
#include "distributed/shard_rebalancer.h"
|
|
||||||
#include "distributed/shard_split.h"
|
|
||||||
#include "distributed/shard_transfer.h"
|
|
||||||
#include "distributed/shared_library_init.h"
|
|
||||||
#include "distributed/shard_rebalancer.h"
|
|
||||||
#include "distributed/worker_protocol.h"
|
|
||||||
#include "distributed/worker_shard_visibility.h"
|
|
||||||
#include "distributed/worker_transaction.h"
|
|
||||||
#include "distributed/utils/distribution_column_map.h"
|
|
||||||
#include "distributed/version_compat.h"
|
|
||||||
#include "executor/executor.h"
|
#include "executor/executor.h"
|
||||||
#include "executor/spi.h"
|
#include "executor/spi.h"
|
||||||
#include "nodes/execnodes.h"
|
#include "nodes/execnodes.h"
|
||||||
|
@ -88,12 +51,52 @@
|
||||||
#include "tcop/pquery.h"
|
#include "tcop/pquery.h"
|
||||||
#include "tcop/tcopprot.h"
|
#include "tcop/tcopprot.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
|
#include "utils/fmgroids.h"
|
||||||
|
#include "utils/inval.h"
|
||||||
#include "utils/lsyscache.h"
|
#include "utils/lsyscache.h"
|
||||||
#include "utils/memutils.h"
|
#include "utils/memutils.h"
|
||||||
#include "utils/rel.h"
|
#include "utils/rel.h"
|
||||||
#include "utils/snapmgr.h"
|
#include "utils/snapmgr.h"
|
||||||
#include "utils/syscache.h"
|
#include "utils/syscache.h"
|
||||||
#include "utils/inval.h"
|
|
||||||
|
#include "pg_version_constants.h"
|
||||||
|
|
||||||
|
#include "distributed/citus_ruleutils.h"
|
||||||
|
#include "distributed/colocation_utils.h"
|
||||||
|
#include "distributed/commands.h"
|
||||||
|
#include "distributed/commands/multi_copy.h"
|
||||||
|
#include "distributed/commands/utility_hook.h"
|
||||||
|
#include "distributed/coordinator_protocol.h"
|
||||||
|
#include "distributed/deparser.h"
|
||||||
|
#include "distributed/distributed_execution_locks.h"
|
||||||
|
#include "distributed/distribution_column.h"
|
||||||
|
#include "distributed/listutils.h"
|
||||||
|
#include "distributed/local_executor.h"
|
||||||
|
#include "distributed/metadata/dependency.h"
|
||||||
|
#include "distributed/metadata/distobject.h"
|
||||||
|
#include "distributed/metadata_cache.h"
|
||||||
|
#include "distributed/metadata_sync.h"
|
||||||
|
#include "distributed/metadata_utility.h"
|
||||||
|
#include "distributed/multi_executor.h"
|
||||||
|
#include "distributed/multi_logical_planner.h"
|
||||||
|
#include "distributed/multi_partitioning_utils.h"
|
||||||
|
#include "distributed/pg_dist_colocation.h"
|
||||||
|
#include "distributed/pg_dist_partition.h"
|
||||||
|
#include "distributed/reference_table_utils.h"
|
||||||
|
#include "distributed/relation_access_tracking.h"
|
||||||
|
#include "distributed/remote_commands.h"
|
||||||
|
#include "distributed/replicate_none_dist_table_shard.h"
|
||||||
|
#include "distributed/resource_lock.h"
|
||||||
|
#include "distributed/shard_cleaner.h"
|
||||||
|
#include "distributed/shard_rebalancer.h"
|
||||||
|
#include "distributed/shard_split.h"
|
||||||
|
#include "distributed/shard_transfer.h"
|
||||||
|
#include "distributed/shared_library_init.h"
|
||||||
|
#include "distributed/utils/distribution_column_map.h"
|
||||||
|
#include "distributed/version_compat.h"
|
||||||
|
#include "distributed/worker_protocol.h"
|
||||||
|
#include "distributed/worker_shard_visibility.h"
|
||||||
|
#include "distributed/worker_transaction.h"
|
||||||
|
|
||||||
|
|
||||||
/* common params that apply to all Citus table types */
|
/* common params that apply to all Citus table types */
|
||||||
|
@ -167,12 +170,10 @@ static void EnsureDistributedSequencesHaveOneType(Oid relationId,
|
||||||
static void CopyLocalDataIntoShards(Oid distributedTableId);
|
static void CopyLocalDataIntoShards(Oid distributedTableId);
|
||||||
static List * TupleDescColumnNameList(TupleDesc tupleDescriptor);
|
static List * TupleDescColumnNameList(TupleDesc tupleDescriptor);
|
||||||
|
|
||||||
#if (PG_VERSION_NUM >= PG_VERSION_15)
|
|
||||||
static bool DistributionColumnUsesNumericColumnNegativeScale(TupleDesc relationDesc,
|
static bool DistributionColumnUsesNumericColumnNegativeScale(TupleDesc relationDesc,
|
||||||
Var *distributionColumn);
|
Var *distributionColumn);
|
||||||
static int numeric_typmod_scale(int32 typmod);
|
static int numeric_typmod_scale(int32 typmod);
|
||||||
static bool is_valid_numeric_typmod(int32 typmod);
|
static bool is_valid_numeric_typmod(int32 typmod);
|
||||||
#endif
|
|
||||||
|
|
||||||
static bool DistributionColumnUsesGeneratedStoredColumn(TupleDesc relationDesc,
|
static bool DistributionColumnUsesGeneratedStoredColumn(TupleDesc relationDesc,
|
||||||
Var *distributionColumn);
|
Var *distributionColumn);
|
||||||
|
@ -445,6 +446,19 @@ CreateDistributedTableConcurrently(Oid relationId, char *distributionColumnName,
|
||||||
if (!IsColocateWithDefault(colocateWithTableName) && !IsColocateWithNone(
|
if (!IsColocateWithDefault(colocateWithTableName) && !IsColocateWithNone(
|
||||||
colocateWithTableName))
|
colocateWithTableName))
|
||||||
{
|
{
|
||||||
|
if (replicationModel != REPLICATION_MODEL_STREAMING)
|
||||||
|
{
|
||||||
|
ereport(ERROR, (errmsg("cannot create distributed table "
|
||||||
|
"concurrently because Citus allows "
|
||||||
|
"concurrent table distribution only when "
|
||||||
|
"citus.shard_replication_factor = 1"),
|
||||||
|
errhint("table %s is requested to be colocated "
|
||||||
|
"with %s which has "
|
||||||
|
"citus.shard_replication_factor > 1",
|
||||||
|
get_rel_name(relationId),
|
||||||
|
colocateWithTableName)));
|
||||||
|
}
|
||||||
|
|
||||||
EnsureColocateWithTableIsValid(relationId, distributionMethod,
|
EnsureColocateWithTableIsValid(relationId, distributionMethod,
|
||||||
distributionColumnName,
|
distributionColumnName,
|
||||||
colocateWithTableName);
|
colocateWithTableName);
|
||||||
|
@ -818,7 +832,7 @@ HashSplitPointsForShardList(List *shardList)
|
||||||
List *splitPointList = NIL;
|
List *splitPointList = NIL;
|
||||||
|
|
||||||
ShardInterval *shardInterval = NULL;
|
ShardInterval *shardInterval = NULL;
|
||||||
foreach_ptr(shardInterval, shardList)
|
foreach_declared_ptr(shardInterval, shardList)
|
||||||
{
|
{
|
||||||
int32 shardMaxValue = DatumGetInt32(shardInterval->maxValue);
|
int32 shardMaxValue = DatumGetInt32(shardInterval->maxValue);
|
||||||
|
|
||||||
|
@ -874,7 +888,7 @@ WorkerNodesForShardList(List *shardList)
|
||||||
List *nodeIdList = NIL;
|
List *nodeIdList = NIL;
|
||||||
|
|
||||||
ShardInterval *shardInterval = NULL;
|
ShardInterval *shardInterval = NULL;
|
||||||
foreach_ptr(shardInterval, shardList)
|
foreach_declared_ptr(shardInterval, shardList)
|
||||||
{
|
{
|
||||||
WorkerNode *workerNode = ActiveShardPlacementWorkerNode(shardInterval->shardId);
|
WorkerNode *workerNode = ActiveShardPlacementWorkerNode(shardInterval->shardId);
|
||||||
nodeIdList = lappend_int(nodeIdList, workerNode->nodeId);
|
nodeIdList = lappend_int(nodeIdList, workerNode->nodeId);
|
||||||
|
@ -1309,10 +1323,7 @@ CreateCitusTable(Oid relationId, CitusTableType tableType,
|
||||||
{
|
{
|
||||||
List *partitionList = PartitionList(relationId);
|
List *partitionList = PartitionList(relationId);
|
||||||
Oid partitionRelationId = InvalidOid;
|
Oid partitionRelationId = InvalidOid;
|
||||||
Oid namespaceId = get_rel_namespace(relationId);
|
char *parentRelationName = generate_qualified_relation_name(relationId);
|
||||||
char *schemaName = get_namespace_name(namespaceId);
|
|
||||||
char *relationName = get_rel_name(relationId);
|
|
||||||
char *parentRelationName = quote_qualified_identifier(schemaName, relationName);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* when there are many partitions, each call to CreateDistributedTable
|
* when there are many partitions, each call to CreateDistributedTable
|
||||||
|
@ -1324,7 +1335,7 @@ CreateCitusTable(Oid relationId, CitusTableType tableType,
|
||||||
ALLOCSET_DEFAULT_SIZES);
|
ALLOCSET_DEFAULT_SIZES);
|
||||||
MemoryContext oldContext = MemoryContextSwitchTo(citusPartitionContext);
|
MemoryContext oldContext = MemoryContextSwitchTo(citusPartitionContext);
|
||||||
|
|
||||||
foreach_oid(partitionRelationId, partitionList)
|
foreach_declared_oid(partitionRelationId, partitionList)
|
||||||
{
|
{
|
||||||
MemoryContextReset(citusPartitionContext);
|
MemoryContextReset(citusPartitionContext);
|
||||||
|
|
||||||
|
@ -1538,7 +1549,7 @@ ConvertCitusLocalTableToTableType(Oid relationId, CitusTableType tableType,
|
||||||
MemoryContext oldContext = MemoryContextSwitchTo(citusPartitionContext);
|
MemoryContext oldContext = MemoryContextSwitchTo(citusPartitionContext);
|
||||||
|
|
||||||
Oid partitionRelationId = InvalidOid;
|
Oid partitionRelationId = InvalidOid;
|
||||||
foreach_oid(partitionRelationId, partitionList)
|
foreach_declared_oid(partitionRelationId, partitionList)
|
||||||
{
|
{
|
||||||
MemoryContextReset(citusPartitionContext);
|
MemoryContextReset(citusPartitionContext);
|
||||||
|
|
||||||
|
@ -1685,52 +1696,39 @@ PropagatePrerequisiteObjectsForDistributedTable(Oid relationId)
|
||||||
void
|
void
|
||||||
EnsureSequenceTypeSupported(Oid seqOid, Oid attributeTypeId, Oid ownerRelationId)
|
EnsureSequenceTypeSupported(Oid seqOid, Oid attributeTypeId, Oid ownerRelationId)
|
||||||
{
|
{
|
||||||
List *citusTableIdList = CitusTableTypeIdList(ANY_CITUS_TABLE_TYPE);
|
Oid attrDefOid;
|
||||||
citusTableIdList = list_append_unique_oid(citusTableIdList, ownerRelationId);
|
List *attrDefOids = GetAttrDefsFromSequence(seqOid);
|
||||||
|
|
||||||
Oid citusTableId = InvalidOid;
|
foreach_declared_oid(attrDefOid, attrDefOids)
|
||||||
foreach_oid(citusTableId, citusTableIdList)
|
|
||||||
{
|
{
|
||||||
List *seqInfoList = NIL;
|
ObjectAddress columnAddress = GetAttrDefaultColumnAddress(attrDefOid);
|
||||||
GetDependentSequencesWithRelation(citusTableId, &seqInfoList, 0, DEPENDENCY_AUTO);
|
|
||||||
|
|
||||||
SequenceInfo *seqInfo = NULL;
|
/*
|
||||||
foreach_ptr(seqInfo, seqInfoList)
|
* If another distributed table is using the same sequence
|
||||||
|
* in one of its column defaults, make sure the types of the
|
||||||
|
* columns match.
|
||||||
|
*
|
||||||
|
* We skip non-distributed tables, but we need to check the current
|
||||||
|
* table as it might reference the same sequence multiple times.
|
||||||
|
*/
|
||||||
|
if (columnAddress.objectId != ownerRelationId &&
|
||||||
|
!IsCitusTable(columnAddress.objectId))
|
||||||
{
|
{
|
||||||
AttrNumber currentAttnum = seqInfo->attributeNumber;
|
continue;
|
||||||
Oid currentSeqOid = seqInfo->sequenceOid;
|
}
|
||||||
|
Oid currentAttributeTypId = GetAttributeTypeOid(columnAddress.objectId,
|
||||||
if (!seqInfo->isNextValDefault)
|
columnAddress.objectSubId);
|
||||||
{
|
if (attributeTypeId != currentAttributeTypId)
|
||||||
/*
|
{
|
||||||
* If a sequence is not on the nextval, we don't need any check.
|
char *sequenceName = generate_qualified_relation_name(
|
||||||
* This is a dependent sequence via ALTER SEQUENCE .. OWNED BY col
|
seqOid);
|
||||||
*/
|
char *citusTableName =
|
||||||
continue;
|
generate_qualified_relation_name(columnAddress.objectId);
|
||||||
}
|
ereport(ERROR, (errmsg(
|
||||||
|
"The sequence %s is already used for a different"
|
||||||
/*
|
" type in column %d of the table %s",
|
||||||
* If another distributed table is using the same sequence
|
sequenceName, columnAddress.objectSubId,
|
||||||
* in one of its column defaults, make sure the types of the
|
citusTableName)));
|
||||||
* columns match
|
|
||||||
*/
|
|
||||||
if (currentSeqOid == seqOid)
|
|
||||||
{
|
|
||||||
Oid currentAttributeTypId = GetAttributeTypeOid(citusTableId,
|
|
||||||
currentAttnum);
|
|
||||||
if (attributeTypeId != currentAttributeTypId)
|
|
||||||
{
|
|
||||||
char *sequenceName = generate_qualified_relation_name(
|
|
||||||
seqOid);
|
|
||||||
char *citusTableName =
|
|
||||||
generate_qualified_relation_name(citusTableId);
|
|
||||||
ereport(ERROR, (errmsg(
|
|
||||||
"The sequence %s is already used for a different"
|
|
||||||
" type in column %d of the table %s",
|
|
||||||
sequenceName, currentAttnum,
|
|
||||||
citusTableName)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1783,7 +1781,7 @@ static void
|
||||||
EnsureDistributedSequencesHaveOneType(Oid relationId, List *seqInfoList)
|
EnsureDistributedSequencesHaveOneType(Oid relationId, List *seqInfoList)
|
||||||
{
|
{
|
||||||
SequenceInfo *seqInfo = NULL;
|
SequenceInfo *seqInfo = NULL;
|
||||||
foreach_ptr(seqInfo, seqInfoList)
|
foreach_declared_ptr(seqInfo, seqInfoList)
|
||||||
{
|
{
|
||||||
if (!seqInfo->isNextValDefault)
|
if (!seqInfo->isNextValDefault)
|
||||||
{
|
{
|
||||||
|
@ -2114,8 +2112,6 @@ EnsureRelationCanBeDistributed(Oid relationId, Var *distributionColumn,
|
||||||
"AS (...) STORED.")));
|
"AS (...) STORED.")));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if (PG_VERSION_NUM >= PG_VERSION_15)
|
|
||||||
|
|
||||||
/* verify target relation is not distributed by a column of type numeric with negative scale */
|
/* verify target relation is not distributed by a column of type numeric with negative scale */
|
||||||
if (distributionMethod != DISTRIBUTE_BY_NONE &&
|
if (distributionMethod != DISTRIBUTE_BY_NONE &&
|
||||||
DistributionColumnUsesNumericColumnNegativeScale(relationDesc,
|
DistributionColumnUsesNumericColumnNegativeScale(relationDesc,
|
||||||
|
@ -2126,7 +2122,6 @@ EnsureRelationCanBeDistributed(Oid relationId, Var *distributionColumn,
|
||||||
errdetail("Distribution column must not use numeric type "
|
errdetail("Distribution column must not use numeric type "
|
||||||
"with negative scale")));
|
"with negative scale")));
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/* check for support function needed by specified partition method */
|
/* check for support function needed by specified partition method */
|
||||||
if (distributionMethod == DISTRIBUTE_BY_HASH)
|
if (distributionMethod == DISTRIBUTE_BY_HASH)
|
||||||
|
@ -2732,11 +2727,15 @@ CopyFromLocalTableIntoDistTable(Oid localTableId, Oid distributedTableId)
|
||||||
ExprContext *econtext = GetPerTupleExprContext(estate);
|
ExprContext *econtext = GetPerTupleExprContext(estate);
|
||||||
econtext->ecxt_scantuple = slot;
|
econtext->ecxt_scantuple = slot;
|
||||||
const bool nonPublishableData = false;
|
const bool nonPublishableData = false;
|
||||||
|
|
||||||
|
/* we don't track query counters when distributing a table */
|
||||||
|
const bool trackQueryCounters = false;
|
||||||
DestReceiver *copyDest =
|
DestReceiver *copyDest =
|
||||||
(DestReceiver *) CreateCitusCopyDestReceiver(distributedTableId,
|
(DestReceiver *) CreateCitusCopyDestReceiver(distributedTableId,
|
||||||
columnNameList,
|
columnNameList,
|
||||||
partitionColumnIndex,
|
partitionColumnIndex,
|
||||||
estate, NULL, nonPublishableData);
|
estate, NULL, nonPublishableData,
|
||||||
|
trackQueryCounters);
|
||||||
|
|
||||||
/* initialise state for writing to shards, we'll open connections on demand */
|
/* initialise state for writing to shards, we'll open connections on demand */
|
||||||
copyDest->rStartup(copyDest, 0, sourceTupleDescriptor);
|
copyDest->rStartup(copyDest, 0, sourceTupleDescriptor);
|
||||||
|
@ -2844,8 +2843,6 @@ TupleDescColumnNameList(TupleDesc tupleDescriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if (PG_VERSION_NUM >= PG_VERSION_15)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* is_valid_numeric_typmod checks if the typmod value is valid
|
* is_valid_numeric_typmod checks if the typmod value is valid
|
||||||
*
|
*
|
||||||
|
@ -2895,8 +2892,6 @@ DistributionColumnUsesNumericColumnNegativeScale(TupleDesc relationDesc,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DistributionColumnUsesGeneratedStoredColumn returns whether a given relation uses
|
* DistributionColumnUsesGeneratedStoredColumn returns whether a given relation uses
|
||||||
* GENERATED ALWAYS AS (...) STORED on distribution column
|
* GENERATED ALWAYS AS (...) STORED on distribution column
|
||||||
|
|
|
@ -11,33 +11,99 @@
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
|
#include "miscadmin.h"
|
||||||
|
|
||||||
|
#include "access/genam.h"
|
||||||
|
#include "access/heapam.h"
|
||||||
#include "access/htup_details.h"
|
#include "access/htup_details.h"
|
||||||
|
#include "access/table.h"
|
||||||
#include "access/xact.h"
|
#include "access/xact.h"
|
||||||
#include "catalog/objectaddress.h"
|
#include "catalog/objectaddress.h"
|
||||||
|
#include "catalog/pg_collation.h"
|
||||||
#include "catalog/pg_database.h"
|
#include "catalog/pg_database.h"
|
||||||
|
#include "catalog/pg_database_d.h"
|
||||||
|
#include "catalog/pg_tablespace.h"
|
||||||
#include "commands/dbcommands.h"
|
#include "commands/dbcommands.h"
|
||||||
#include "miscadmin.h"
|
#include "commands/defrem.h"
|
||||||
#include "nodes/parsenodes.h"
|
#include "nodes/parsenodes.h"
|
||||||
|
#include "utils/builtins.h"
|
||||||
|
#include "utils/fmgroids.h"
|
||||||
|
#include "utils/lsyscache.h"
|
||||||
|
#include "utils/rel.h"
|
||||||
|
#include "utils/relcache.h"
|
||||||
#include "utils/syscache.h"
|
#include "utils/syscache.h"
|
||||||
|
|
||||||
|
#include "distributed/adaptive_executor.h"
|
||||||
#include "distributed/commands.h"
|
#include "distributed/commands.h"
|
||||||
|
#include "distributed/commands/serialize_distributed_ddls.h"
|
||||||
#include "distributed/commands/utility_hook.h"
|
#include "distributed/commands/utility_hook.h"
|
||||||
|
#include "distributed/comment.h"
|
||||||
|
#include "distributed/deparse_shard_query.h"
|
||||||
#include "distributed/deparser.h"
|
#include "distributed/deparser.h"
|
||||||
|
#include "distributed/listutils.h"
|
||||||
|
#include "distributed/local_executor.h"
|
||||||
|
#include "distributed/metadata/distobject.h"
|
||||||
#include "distributed/metadata_sync.h"
|
#include "distributed/metadata_sync.h"
|
||||||
#include "distributed/metadata_utility.h"
|
#include "distributed/metadata_utility.h"
|
||||||
#include "distributed/multi_executor.h"
|
#include "distributed/multi_executor.h"
|
||||||
#include "distributed/relation_access_tracking.h"
|
#include "distributed/relation_access_tracking.h"
|
||||||
|
#include "distributed/shard_cleaner.h"
|
||||||
|
#include "distributed/worker_protocol.h"
|
||||||
#include "distributed/worker_transaction.h"
|
#include "distributed/worker_transaction.h"
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Used to save original name of the database before it is replaced with a
|
||||||
|
* temporary name for failure handling purposes in PreprocessCreateDatabaseStmt().
|
||||||
|
*/
|
||||||
|
static char *CreateDatabaseCommandOriginalDbName = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The format string used when creating a temporary databases for failure
|
||||||
|
* handling purposes.
|
||||||
|
*
|
||||||
|
* The fields are as follows to ensure using a unique name for each temporary
|
||||||
|
* database:
|
||||||
|
* - operationId: The operation id returned by RegisterOperationNeedingCleanup().
|
||||||
|
* - groupId: The group id of the worker node where CREATE DATABASE command
|
||||||
|
* is issued from.
|
||||||
|
*/
|
||||||
|
#define TEMP_DATABASE_NAME_FMT "citus_temp_database_%lu_%d"
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DatabaseCollationInfo is used to store collation related information of a database.
|
||||||
|
*/
|
||||||
|
typedef struct DatabaseCollationInfo
|
||||||
|
{
|
||||||
|
char *datcollate;
|
||||||
|
char *datctype;
|
||||||
|
char *daticulocale;
|
||||||
|
char *datcollversion;
|
||||||
|
|
||||||
|
#if PG_VERSION_NUM >= PG_VERSION_16
|
||||||
|
char *daticurules;
|
||||||
|
#endif
|
||||||
|
} DatabaseCollationInfo;
|
||||||
|
|
||||||
|
static char * GenerateCreateDatabaseStatementFromPgDatabase(Form_pg_database
|
||||||
|
databaseForm);
|
||||||
|
static DatabaseCollationInfo GetDatabaseCollation(Oid dbOid);
|
||||||
static AlterOwnerStmt * RecreateAlterDatabaseOwnerStmt(Oid databaseOid);
|
static AlterOwnerStmt * RecreateAlterDatabaseOwnerStmt(Oid databaseOid);
|
||||||
static Oid get_database_owner(Oid db_oid);
|
static char * GetLocaleProviderString(char datlocprovider);
|
||||||
List * PreprocessGrantOnDatabaseStmt(Node *node, const char *queryString,
|
static char * GetTablespaceName(Oid tablespaceOid);
|
||||||
ProcessUtilityContext processUtilityContext);
|
static ObjectAddress * GetDatabaseAddressFromDatabaseName(char *databaseName,
|
||||||
|
bool missingOk);
|
||||||
|
|
||||||
|
static List * FilterDistributedDatabases(List *databases);
|
||||||
|
static Oid get_database_owner(Oid dbId);
|
||||||
|
|
||||||
|
|
||||||
/* controlled via GUC */
|
/* controlled via GUC */
|
||||||
|
bool EnableCreateDatabasePropagation = false;
|
||||||
bool EnableAlterDatabaseOwner = true;
|
bool EnableAlterDatabaseOwner = true;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* AlterDatabaseOwnerObjectAddress returns the ObjectAddress of the database that is the
|
* AlterDatabaseOwnerObjectAddress returns the ObjectAddress of the database that is the
|
||||||
* object of the AlterOwnerStmt. Errors if missing_ok is false.
|
* object of the AlterOwnerStmt. Errors if missing_ok is false.
|
||||||
|
@ -94,13 +160,13 @@ RecreateAlterDatabaseOwnerStmt(Oid databaseOid)
|
||||||
* get_database_owner returns the Oid of the role owning the database
|
* get_database_owner returns the Oid of the role owning the database
|
||||||
*/
|
*/
|
||||||
static Oid
|
static Oid
|
||||||
get_database_owner(Oid db_oid)
|
get_database_owner(Oid dbId)
|
||||||
{
|
{
|
||||||
HeapTuple tuple = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(db_oid));
|
HeapTuple tuple = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(dbId));
|
||||||
if (!HeapTupleIsValid(tuple))
|
if (!HeapTupleIsValid(tuple))
|
||||||
{
|
{
|
||||||
ereport(ERROR, (errcode(ERRCODE_UNDEFINED_DATABASE),
|
ereport(ERROR, (errcode(ERRCODE_UNDEFINED_DATABASE),
|
||||||
errmsg("database with OID %u does not exist", db_oid)));
|
errmsg("database with OID %u does not exist", dbId)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Oid dba = ((Form_pg_database) GETSTRUCT(tuple))->datdba;
|
Oid dba = ((Form_pg_database) GETSTRUCT(tuple))->datdba;
|
||||||
|
@ -130,17 +196,23 @@ PreprocessGrantOnDatabaseStmt(Node *node, const char *queryString,
|
||||||
GrantStmt *stmt = castNode(GrantStmt, node);
|
GrantStmt *stmt = castNode(GrantStmt, node);
|
||||||
Assert(stmt->objtype == OBJECT_DATABASE);
|
Assert(stmt->objtype == OBJECT_DATABASE);
|
||||||
|
|
||||||
List *databaseList = stmt->objects;
|
List *distributedDatabases = FilterDistributedDatabases(stmt->objects);
|
||||||
|
|
||||||
if (list_length(databaseList) == 0)
|
if (list_length(distributedDatabases) == 0)
|
||||||
{
|
{
|
||||||
return NIL;
|
return NIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
EnsureCoordinator();
|
EnsureCoordinator();
|
||||||
|
|
||||||
|
List *originalObjects = stmt->objects;
|
||||||
|
|
||||||
|
stmt->objects = distributedDatabases;
|
||||||
|
|
||||||
char *sql = DeparseTreeNode((Node *) stmt);
|
char *sql = DeparseTreeNode((Node *) stmt);
|
||||||
|
|
||||||
|
stmt->objects = originalObjects;
|
||||||
|
|
||||||
List *commands = list_make3(DISABLE_DDL_PROPAGATION,
|
List *commands = list_make3(DISABLE_DDL_PROPAGATION,
|
||||||
(void *) sql,
|
(void *) sql,
|
||||||
ENABLE_DDL_PROPAGATION);
|
ENABLE_DDL_PROPAGATION);
|
||||||
|
@ -149,23 +221,196 @@ PreprocessGrantOnDatabaseStmt(Node *node, const char *queryString,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FilterDistributedDatabases filters the database list and returns the distributed ones,
|
||||||
|
* as a list.
|
||||||
|
*/
|
||||||
|
static List *
|
||||||
|
FilterDistributedDatabases(List *databases)
|
||||||
|
{
|
||||||
|
List *distributedDatabases = NIL;
|
||||||
|
String *databaseName = NULL;
|
||||||
|
foreach_declared_ptr(databaseName, databases)
|
||||||
|
{
|
||||||
|
bool missingOk = true;
|
||||||
|
ObjectAddress *dbAddress =
|
||||||
|
GetDatabaseAddressFromDatabaseName(strVal(databaseName), missingOk);
|
||||||
|
if (IsAnyObjectDistributed(list_make1(dbAddress)))
|
||||||
|
{
|
||||||
|
distributedDatabases = lappend(distributedDatabases, databaseName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return distributedDatabases;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IsSetTablespaceStatement returns true if the statement is a SET TABLESPACE statement,
|
||||||
|
* false otherwise.
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
IsSetTablespaceStatement(AlterDatabaseStmt *stmt)
|
||||||
|
{
|
||||||
|
DefElem *def = NULL;
|
||||||
|
foreach_declared_ptr(def, stmt->options)
|
||||||
|
{
|
||||||
|
if (strcmp(def->defname, "tablespace") == 0)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* PreprocessAlterDatabaseStmt is executed before the statement is applied to the local
|
* PreprocessAlterDatabaseStmt is executed before the statement is applied to the local
|
||||||
* postgres instance.
|
* postgres instance.
|
||||||
*
|
*
|
||||||
* In this stage we can prepare the commands that need to be run on all workers to grant
|
* In this stage we can prepare the commands that need to be run on all workers to grant
|
||||||
* on databases.
|
* on databases.
|
||||||
|
*
|
||||||
|
* We also serialize database commands globally by acquiring a Citus specific advisory
|
||||||
|
* lock based on OCLASS_DATABASE on the first primary worker node.
|
||||||
*/
|
*/
|
||||||
List *
|
List *
|
||||||
PreprocessAlterDatabaseStmt(Node *node, const char *queryString,
|
PreprocessAlterDatabaseStmt(Node *node, const char *queryString,
|
||||||
ProcessUtilityContext processUtilityContext)
|
ProcessUtilityContext processUtilityContext)
|
||||||
{
|
{
|
||||||
if (!ShouldPropagate())
|
bool missingOk = false;
|
||||||
|
AlterDatabaseStmt *stmt = castNode(AlterDatabaseStmt, node);
|
||||||
|
ObjectAddress *dbAddress = GetDatabaseAddressFromDatabaseName(stmt->dbname,
|
||||||
|
missingOk);
|
||||||
|
|
||||||
|
if (!ShouldPropagate() || !IsAnyObjectDistributed(list_make1(dbAddress)))
|
||||||
{
|
{
|
||||||
return NIL;
|
return NIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
AlterDatabaseStmt *stmt = castNode(AlterDatabaseStmt, node);
|
EnsureCoordinator();
|
||||||
|
SerializeDistributedDDLsOnObjectClassObject(OCLASS_DATABASE, stmt->dbname);
|
||||||
|
|
||||||
|
char *sql = DeparseTreeNode((Node *) stmt);
|
||||||
|
|
||||||
|
List *commands = list_make3(DISABLE_DDL_PROPAGATION,
|
||||||
|
sql,
|
||||||
|
ENABLE_DDL_PROPAGATION);
|
||||||
|
|
||||||
|
if (IsSetTablespaceStatement(stmt))
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Set tablespace does not work inside a transaction.Therefore, we need to use
|
||||||
|
* NontransactionalNodeDDLTask to run the command on the workers outside
|
||||||
|
* the transaction block.
|
||||||
|
*/
|
||||||
|
bool warnForPartialFailure = true;
|
||||||
|
return NontransactionalNodeDDLTaskList(NON_COORDINATOR_NODES, commands,
|
||||||
|
warnForPartialFailure);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return NodeDDLTaskList(NON_COORDINATOR_NODES, commands);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PreprocessAlterDatabaseRefreshCollStmt is executed before the statement is applied to
|
||||||
|
* the local postgres instance.
|
||||||
|
*
|
||||||
|
* In this stage we can prepare the commands that need to be run on all workers to grant
|
||||||
|
* on databases.
|
||||||
|
*
|
||||||
|
* We also serialize database commands globally by acquiring a Citus specific advisory
|
||||||
|
* lock based on OCLASS_DATABASE on the first primary worker node.
|
||||||
|
*/
|
||||||
|
List *
|
||||||
|
PreprocessAlterDatabaseRefreshCollStmt(Node *node, const char *queryString,
|
||||||
|
ProcessUtilityContext processUtilityContext)
|
||||||
|
{
|
||||||
|
bool missingOk = true;
|
||||||
|
AlterDatabaseRefreshCollStmt *stmt = castNode(AlterDatabaseRefreshCollStmt, node);
|
||||||
|
ObjectAddress *dbAddress = GetDatabaseAddressFromDatabaseName(stmt->dbname,
|
||||||
|
missingOk);
|
||||||
|
|
||||||
|
if (!ShouldPropagate() || !IsAnyObjectDistributed(list_make1(dbAddress)))
|
||||||
|
{
|
||||||
|
return NIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
EnsureCoordinator();
|
||||||
|
SerializeDistributedDDLsOnObjectClassObject(OCLASS_DATABASE, stmt->dbname);
|
||||||
|
|
||||||
|
char *sql = DeparseTreeNode((Node *) stmt);
|
||||||
|
|
||||||
|
List *commands = list_make3(DISABLE_DDL_PROPAGATION,
|
||||||
|
(void *) sql,
|
||||||
|
ENABLE_DDL_PROPAGATION);
|
||||||
|
|
||||||
|
return NodeDDLTaskList(NON_COORDINATOR_NODES, commands);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PreprocessAlterDatabaseRenameStmt is executed before the statement is applied to
|
||||||
|
* the local postgres instance.
|
||||||
|
*
|
||||||
|
* We also serialize database commands globally by acquiring a Citus specific advisory
|
||||||
|
* lock based on OCLASS_DATABASE on the first primary worker node.
|
||||||
|
*
|
||||||
|
* We acquire this lock here instead of PostprocessAlterDatabaseRenameStmt because the
|
||||||
|
* command renames the database and SerializeDistributedDDLsOnObjectClass resolves the
|
||||||
|
* object on workers based on database name. For this reason, we need to acquire the lock
|
||||||
|
* before the command is applied to the local postgres instance.
|
||||||
|
*/
|
||||||
|
List *
|
||||||
|
PreprocessAlterDatabaseRenameStmt(Node *node, const char *queryString,
|
||||||
|
ProcessUtilityContext processUtilityContext)
|
||||||
|
{
|
||||||
|
bool missingOk = true;
|
||||||
|
RenameStmt *stmt = castNode(RenameStmt, node);
|
||||||
|
ObjectAddress *dbAddress = GetDatabaseAddressFromDatabaseName(stmt->subname,
|
||||||
|
missingOk);
|
||||||
|
|
||||||
|
if (!ShouldPropagate() || !IsAnyObjectDistributed(list_make1(dbAddress)))
|
||||||
|
{
|
||||||
|
return NIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
EnsureCoordinator();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Different than other ALTER DATABASE commands, we first acquire a lock
|
||||||
|
* by providing InvalidOid because we want ALTER TABLE .. RENAME TO ..
|
||||||
|
* commands to block not only with ALTER DATABASE operations but also
|
||||||
|
* with CREATE DATABASE operations because they might cause name conflicts
|
||||||
|
* and that could also cause deadlocks too.
|
||||||
|
*/
|
||||||
|
SerializeDistributedDDLsOnObjectClass(OCLASS_DATABASE);
|
||||||
|
SerializeDistributedDDLsOnObjectClassObject(OCLASS_DATABASE, stmt->subname);
|
||||||
|
|
||||||
|
return NIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PostprocessAlterDatabaseRenameStmt is executed after the statement is applied to the local
|
||||||
|
* postgres instance. In this stage we prepare ALTER DATABASE RENAME statement to be run on
|
||||||
|
* all workers.
|
||||||
|
*/
|
||||||
|
List *
|
||||||
|
PostprocessAlterDatabaseRenameStmt(Node *node, const char *queryString)
|
||||||
|
{
|
||||||
|
bool missingOk = false;
|
||||||
|
RenameStmt *stmt = castNode(RenameStmt, node);
|
||||||
|
ObjectAddress *dbAddress = GetDatabaseAddressFromDatabaseName(stmt->newname,
|
||||||
|
missingOk);
|
||||||
|
|
||||||
|
if (!ShouldPropagate() || !IsAnyObjectDistributed(list_make1(dbAddress)))
|
||||||
|
{
|
||||||
|
return NIL;
|
||||||
|
}
|
||||||
|
|
||||||
EnsureCoordinator();
|
EnsureCoordinator();
|
||||||
|
|
||||||
|
@ -179,27 +424,32 @@ PreprocessAlterDatabaseStmt(Node *node, const char *queryString,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if PG_VERSION_NUM >= PG_VERSION_15
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* PreprocessAlterDatabaseSetStmt is executed before the statement is applied to the local
|
* PreprocessAlterDatabaseSetStmt is executed before the statement is applied to the local
|
||||||
* postgres instance.
|
* postgres instance.
|
||||||
*
|
*
|
||||||
* In this stage we can prepare the commands that need to be run on all workers to grant
|
* In this stage we can prepare the commands that need to be run on all workers to grant
|
||||||
* on databases.
|
* on databases.
|
||||||
|
*
|
||||||
|
* We also serialize database commands globally by acquiring a Citus specific advisory
|
||||||
|
* lock based on OCLASS_DATABASE on the first primary worker node.
|
||||||
*/
|
*/
|
||||||
List *
|
List *
|
||||||
PreprocessAlterDatabaseRefreshCollStmt(Node *node, const char *queryString,
|
PreprocessAlterDatabaseSetStmt(Node *node, const char *queryString,
|
||||||
ProcessUtilityContext processUtilityContext)
|
ProcessUtilityContext processUtilityContext)
|
||||||
{
|
{
|
||||||
if (!ShouldPropagate())
|
AlterDatabaseSetStmt *stmt = castNode(AlterDatabaseSetStmt, node);
|
||||||
|
|
||||||
|
bool missingOk = true;
|
||||||
|
ObjectAddress *dbAddress = GetDatabaseAddressFromDatabaseName(stmt->dbname,
|
||||||
|
missingOk);
|
||||||
|
if (!ShouldPropagate() || !IsAnyObjectDistributed(list_make1(dbAddress)))
|
||||||
{
|
{
|
||||||
return NIL;
|
return NIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
AlterDatabaseRefreshCollStmt *stmt = castNode(AlterDatabaseRefreshCollStmt, node);
|
|
||||||
|
|
||||||
EnsureCoordinator();
|
EnsureCoordinator();
|
||||||
|
SerializeDistributedDDLsOnObjectClassObject(OCLASS_DATABASE, stmt->dbname);
|
||||||
|
|
||||||
char *sql = DeparseTreeNode((Node *) stmt);
|
char *sql = DeparseTreeNode((Node *) stmt);
|
||||||
|
|
||||||
|
@ -211,4 +461,540 @@ PreprocessAlterDatabaseRefreshCollStmt(Node *node, const char *queryString,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PreprocessCreateDatabaseStmt is executed before the statement is applied to the local
|
||||||
|
* Postgres instance.
|
||||||
|
*
|
||||||
|
* In this stage, we perform validations that we want to ensure before delegating to
|
||||||
|
* previous utility hooks because it might not be convenient to throw an error in an
|
||||||
|
* implicit transaction that creates a database. Also in this stage, we save the original
|
||||||
|
* database name and replace dbname field with a temporary name for failure handling
|
||||||
|
* purposes. We let Postgres create the database with the temporary name, insert a cleanup
|
||||||
|
* record for the temporary database name on all nodes and let PostprocessCreateDatabaseStmt()
|
||||||
|
* to return the distributed DDL job that both creates the database with the temporary name
|
||||||
|
* and then renames it back to its original name.
|
||||||
|
*
|
||||||
|
* We also serialize database commands globally by acquiring a Citus specific advisory
|
||||||
|
* lock based on OCLASS_DATABASE on the first primary worker node.
|
||||||
|
*/
|
||||||
|
List *
|
||||||
|
PreprocessCreateDatabaseStmt(Node *node, const char *queryString,
|
||||||
|
ProcessUtilityContext processUtilityContext)
|
||||||
|
{
|
||||||
|
if (!EnableCreateDatabasePropagation || !ShouldPropagate())
|
||||||
|
{
|
||||||
|
return NIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
EnsureCoordinatorIsInMetadata();
|
||||||
|
|
||||||
|
CreatedbStmt *stmt = castNode(CreatedbStmt, node);
|
||||||
|
EnsureSupportedCreateDatabaseCommand(stmt);
|
||||||
|
|
||||||
|
SerializeDistributedDDLsOnObjectClass(OCLASS_DATABASE);
|
||||||
|
|
||||||
|
OperationId operationId = RegisterOperationNeedingCleanup();
|
||||||
|
|
||||||
|
char *tempDatabaseName = psprintf(TEMP_DATABASE_NAME_FMT,
|
||||||
|
operationId, GetLocalGroupId());
|
||||||
|
|
||||||
|
List *remoteNodes = TargetWorkerSetNodeList(ALL_SHARD_NODES, RowShareLock);
|
||||||
|
WorkerNode *remoteNode = NULL;
|
||||||
|
foreach_declared_ptr(remoteNode, remoteNodes)
|
||||||
|
{
|
||||||
|
InsertCleanupRecordOutsideTransaction(
|
||||||
|
CLEANUP_OBJECT_DATABASE,
|
||||||
|
pstrdup(quote_identifier(tempDatabaseName)),
|
||||||
|
remoteNode->groupId,
|
||||||
|
CLEANUP_ON_FAILURE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
CreateDatabaseCommandOriginalDbName = stmt->dbname;
|
||||||
|
stmt->dbname = tempDatabaseName;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Delete cleanup records in the same transaction so that if the current
|
||||||
|
* transactions fails for some reason, then the cleanup records won't be
|
||||||
|
* deleted. In the happy path, we will delete the cleanup records without
|
||||||
|
* deferring them to the background worker.
|
||||||
|
*/
|
||||||
|
FinalizeOperationNeedingCleanupOnSuccess("create database");
|
||||||
|
|
||||||
|
return NIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PostprocessCreateDatabaseStmt is executed after the statement is applied to the local
|
||||||
|
* postgres instance.
|
||||||
|
*
|
||||||
|
* In this stage, we first rename the temporary database back to its original name for
|
||||||
|
* local node and then return a list of distributed DDL jobs to create the database with
|
||||||
|
* the temporary name and then to rename it back to its original name. That way, if CREATE
|
||||||
|
* DATABASE fails on any of the nodes, the temporary database will be cleaned up by the
|
||||||
|
* cleanup records that we inserted in PreprocessCreateDatabaseStmt() and in case of a
|
||||||
|
* failure, we won't leak any databases called as the name that user intended to use for
|
||||||
|
* the database.
|
||||||
|
*/
|
||||||
|
List *
|
||||||
|
PostprocessCreateDatabaseStmt(Node *node, const char *queryString)
|
||||||
|
{
|
||||||
|
if (!EnableCreateDatabasePropagation || !ShouldPropagate())
|
||||||
|
{
|
||||||
|
return NIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
EnsurePropagationToCoordinator();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Given that CREATE DATABASE doesn't support "IF NOT EXISTS" and we're
|
||||||
|
* in the post-process, database must exist, hence missingOk = false.
|
||||||
|
*/
|
||||||
|
bool missingOk = false;
|
||||||
|
bool isPostProcess = true;
|
||||||
|
List *addresses = GetObjectAddressListFromParseTree(node, missingOk,
|
||||||
|
isPostProcess);
|
||||||
|
EnsureAllObjectDependenciesExistOnAllNodes(addresses);
|
||||||
|
|
||||||
|
char *createDatabaseCommand = DeparseTreeNode(node);
|
||||||
|
|
||||||
|
List *createDatabaseCommands = list_make3(DISABLE_DDL_PROPAGATION,
|
||||||
|
(void *) createDatabaseCommand,
|
||||||
|
ENABLE_DDL_PROPAGATION);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Since the CREATE DATABASE statements cannot be executed in a transaction
|
||||||
|
* block, we need to use NontransactionalNodeDDLTaskList() to send the CREATE
|
||||||
|
* DATABASE statement to the workers.
|
||||||
|
*/
|
||||||
|
bool warnForPartialFailure = false;
|
||||||
|
List *createDatabaseDDLJobList =
|
||||||
|
NontransactionalNodeDDLTaskList(REMOTE_NODES, createDatabaseCommands,
|
||||||
|
warnForPartialFailure);
|
||||||
|
|
||||||
|
CreatedbStmt *stmt = castNode(CreatedbStmt, node);
|
||||||
|
|
||||||
|
char *renameDatabaseCommand =
|
||||||
|
psprintf("ALTER DATABASE %s RENAME TO %s",
|
||||||
|
quote_identifier(stmt->dbname),
|
||||||
|
quote_identifier(CreateDatabaseCommandOriginalDbName));
|
||||||
|
|
||||||
|
List *renameDatabaseCommands = list_make3(DISABLE_DDL_PROPAGATION,
|
||||||
|
renameDatabaseCommand,
|
||||||
|
ENABLE_DDL_PROPAGATION);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We use NodeDDLTaskList() to send the RENAME DATABASE statement to the
|
||||||
|
* workers because we want to execute it in a coordinated transaction.
|
||||||
|
*/
|
||||||
|
List *renameDatabaseDDLJobList =
|
||||||
|
NodeDDLTaskList(REMOTE_NODES, renameDatabaseCommands);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Temporarily disable citus.enable_ddl_propagation before issuing
|
||||||
|
* rename command locally because we don't want to execute it on remote
|
||||||
|
* nodes yet. We will execute it on remote nodes by returning it as a
|
||||||
|
* distributed DDL job.
|
||||||
|
*
|
||||||
|
* The reason why we don't want to execute it on remote nodes yet is that
|
||||||
|
* the database is not created on remote nodes yet.
|
||||||
|
*/
|
||||||
|
int saveNestLevel = NewGUCNestLevel();
|
||||||
|
set_config_option("citus.enable_ddl_propagation", "off",
|
||||||
|
(superuser() ? PGC_SUSET : PGC_USERSET), PGC_S_SESSION,
|
||||||
|
GUC_ACTION_LOCAL, true, 0, false);
|
||||||
|
|
||||||
|
ExecuteUtilityCommand(renameDatabaseCommand);
|
||||||
|
|
||||||
|
AtEOXact_GUC(true, saveNestLevel);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Restore the original database name because MarkObjectDistributed()
|
||||||
|
* resolves oid of the object based on the database name and is called
|
||||||
|
* after executing the distributed DDL job that renames temporary database.
|
||||||
|
*/
|
||||||
|
stmt->dbname = CreateDatabaseCommandOriginalDbName;
|
||||||
|
|
||||||
|
return list_concat(createDatabaseDDLJobList, renameDatabaseDDLJobList);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PreprocessDropDatabaseStmt is executed before the statement is applied to the local
|
||||||
|
* postgres instance. In this stage we can prepare the commands that need to be run on
|
||||||
|
* all workers to drop the database.
|
||||||
|
*
|
||||||
|
* We also serialize database commands globally by acquiring a Citus specific advisory
|
||||||
|
* lock based on OCLASS_DATABASE on the first primary worker node.
|
||||||
|
*/
|
||||||
|
List *
|
||||||
|
PreprocessDropDatabaseStmt(Node *node, const char *queryString,
|
||||||
|
ProcessUtilityContext processUtilityContext)
|
||||||
|
{
|
||||||
|
if (!EnableCreateDatabasePropagation || !ShouldPropagate())
|
||||||
|
{
|
||||||
|
return NIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
EnsurePropagationToCoordinator();
|
||||||
|
|
||||||
|
DropdbStmt *stmt = (DropdbStmt *) node;
|
||||||
|
|
||||||
|
bool isPostProcess = false;
|
||||||
|
List *addresses = GetObjectAddressListFromParseTree(node, stmt->missing_ok,
|
||||||
|
isPostProcess);
|
||||||
|
|
||||||
|
if (list_length(addresses) != 1)
|
||||||
|
{
|
||||||
|
ereport(ERROR, (errmsg("unexpected number of objects found when "
|
||||||
|
"executing DROP DATABASE command")));
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectAddress *address = (ObjectAddress *) linitial(addresses);
|
||||||
|
if (address->objectId == InvalidOid || !IsAnyObjectDistributed(list_make1(address)))
|
||||||
|
{
|
||||||
|
return NIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
SerializeDistributedDDLsOnObjectClassObject(OCLASS_DATABASE, stmt->dbname);
|
||||||
|
|
||||||
|
char *dropDatabaseCommand = DeparseTreeNode(node);
|
||||||
|
|
||||||
|
List *dropDatabaseCommands = list_make3(DISABLE_DDL_PROPAGATION,
|
||||||
|
(void *) dropDatabaseCommand,
|
||||||
|
ENABLE_DDL_PROPAGATION);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Due to same reason stated in PostprocessCreateDatabaseStmt(), we need to
|
||||||
|
* use NontransactionalNodeDDLTaskList() to send the DROP DATABASE statement
|
||||||
|
* to the workers.
|
||||||
|
*/
|
||||||
|
bool warnForPartialFailure = true;
|
||||||
|
List *dropDatabaseDDLJobList =
|
||||||
|
NontransactionalNodeDDLTaskList(REMOTE_NODES, dropDatabaseCommands,
|
||||||
|
warnForPartialFailure);
|
||||||
|
return dropDatabaseDDLJobList;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DropDatabaseStmtObjectAddress gets the ObjectAddress of the database that is the
|
||||||
|
* object of the DropdbStmt.
|
||||||
|
*/
|
||||||
|
List *
|
||||||
|
DropDatabaseStmtObjectAddress(Node *node, bool missingOk, bool isPostprocess)
|
||||||
|
{
|
||||||
|
DropdbStmt *stmt = castNode(DropdbStmt, node);
|
||||||
|
ObjectAddress *dbAddress = GetDatabaseAddressFromDatabaseName(stmt->dbname,
|
||||||
|
missingOk);
|
||||||
|
return list_make1(dbAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CreateDatabaseStmtObjectAddress gets the ObjectAddress of the database that is the
|
||||||
|
* object of the CreatedbStmt.
|
||||||
|
*/
|
||||||
|
List *
|
||||||
|
CreateDatabaseStmtObjectAddress(Node *node, bool missingOk, bool isPostprocess)
|
||||||
|
{
|
||||||
|
CreatedbStmt *stmt = castNode(CreatedbStmt, node);
|
||||||
|
ObjectAddress *dbAddress = GetDatabaseAddressFromDatabaseName(stmt->dbname,
|
||||||
|
missingOk);
|
||||||
|
return list_make1(dbAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* EnsureSupportedCreateDatabaseCommand validates the options provided for the CREATE
|
||||||
|
* DATABASE command.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* stmt: A CreatedbStmt struct representing a CREATE DATABASE command.
|
||||||
|
* The options field is a list of DefElem structs, each representing an option.
|
||||||
|
*
|
||||||
|
* Currently, this function checks for the following:
|
||||||
|
* - The "oid" option is not supported.
|
||||||
|
* - The "template" option is only supported with the value "template1".
|
||||||
|
* - The "strategy" option is only supported with the value "wal_log".
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
EnsureSupportedCreateDatabaseCommand(CreatedbStmt *stmt)
|
||||||
|
{
|
||||||
|
DefElem *option = NULL;
|
||||||
|
foreach_declared_ptr(option, stmt->options)
|
||||||
|
{
|
||||||
|
if (strcmp(option->defname, "oid") == 0)
|
||||||
|
{
|
||||||
|
ereport(ERROR,
|
||||||
|
errmsg("CREATE DATABASE option \"%s\" is not supported",
|
||||||
|
option->defname));
|
||||||
|
}
|
||||||
|
|
||||||
|
char *optionValue = defGetString(option);
|
||||||
|
|
||||||
|
if (strcmp(option->defname, "template") == 0 &&
|
||||||
|
strcmp(optionValue, "template1") != 0)
|
||||||
|
{
|
||||||
|
ereport(ERROR, errmsg("Only template1 is supported as template "
|
||||||
|
"parameter for CREATE DATABASE"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(option->defname, "strategy") == 0 &&
|
||||||
|
strcmp(optionValue, "wal_log") != 0)
|
||||||
|
{
|
||||||
|
ereport(ERROR, errmsg("Only wal_log is supported as strategy "
|
||||||
|
"parameter for CREATE DATABASE"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GetDatabaseAddressFromDatabaseName gets the database name and returns the ObjectAddress
|
||||||
|
* of the database.
|
||||||
|
*/
|
||||||
|
static ObjectAddress *
|
||||||
|
GetDatabaseAddressFromDatabaseName(char *databaseName, bool missingOk)
|
||||||
|
{
|
||||||
|
Oid databaseOid = get_database_oid(databaseName, missingOk);
|
||||||
|
ObjectAddress *dbObjectAddress = palloc0(sizeof(ObjectAddress));
|
||||||
|
ObjectAddressSet(*dbObjectAddress, DatabaseRelationId, databaseOid);
|
||||||
|
return dbObjectAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GetTablespaceName gets the tablespace oid and returns the tablespace name.
|
||||||
|
*/
|
||||||
|
static char *
|
||||||
|
GetTablespaceName(Oid tablespaceOid)
|
||||||
|
{
|
||||||
|
HeapTuple tuple = SearchSysCache1(TABLESPACEOID, ObjectIdGetDatum(tablespaceOid));
|
||||||
|
if (!HeapTupleIsValid(tuple))
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Form_pg_tablespace tablespaceForm = (Form_pg_tablespace) GETSTRUCT(tuple);
|
||||||
|
char *tablespaceName = pstrdup(NameStr(tablespaceForm->spcname));
|
||||||
|
|
||||||
|
ReleaseSysCache(tuple);
|
||||||
|
|
||||||
|
return tablespaceName;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GetDatabaseMetadataSyncCommands returns a list of sql statements
|
||||||
|
* for the given database id. The list contains the database ddl command,
|
||||||
|
* grant commands and comment propagation commands.
|
||||||
|
*/
|
||||||
|
List *
|
||||||
|
GetDatabaseMetadataSyncCommands(Oid dbOid)
|
||||||
|
{
|
||||||
|
char *databaseName = get_database_name(dbOid);
|
||||||
|
char *databaseDDLCommand = CreateDatabaseDDLCommand(dbOid);
|
||||||
|
|
||||||
|
List *ddlCommands = list_make1(databaseDDLCommand);
|
||||||
|
|
||||||
|
List *grantDDLCommands = GrantOnDatabaseDDLCommands(dbOid);
|
||||||
|
List *commentDDLCommands = GetCommentPropagationCommands(DatabaseRelationId, dbOid,
|
||||||
|
databaseName,
|
||||||
|
OBJECT_DATABASE);
|
||||||
|
|
||||||
|
ddlCommands = list_concat(ddlCommands, grantDDLCommands);
|
||||||
|
ddlCommands = list_concat(ddlCommands, commentDDLCommands);
|
||||||
|
|
||||||
|
return ddlCommands;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GetDatabaseCollation gets oid of a database and returns all the collation related information
|
||||||
|
* We need this method since collation related info in Form_pg_database is not accessible.
|
||||||
|
*/
|
||||||
|
static DatabaseCollationInfo
|
||||||
|
GetDatabaseCollation(Oid dbOid)
|
||||||
|
{
|
||||||
|
DatabaseCollationInfo info;
|
||||||
|
memset(&info, 0, sizeof(DatabaseCollationInfo));
|
||||||
|
|
||||||
|
Relation rel = table_open(DatabaseRelationId, AccessShareLock);
|
||||||
|
HeapTuple tup = get_catalog_object_by_oid(rel, Anum_pg_database_oid, dbOid);
|
||||||
|
if (!HeapTupleIsValid(tup))
|
||||||
|
{
|
||||||
|
elog(ERROR, "cache lookup failed for database %u", dbOid);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isNull = false;
|
||||||
|
|
||||||
|
TupleDesc tupdesc = RelationGetDescr(rel);
|
||||||
|
|
||||||
|
Datum collationDatum = heap_getattr(tup, Anum_pg_database_datcollate, tupdesc,
|
||||||
|
&isNull);
|
||||||
|
info.datcollate = TextDatumGetCString(collationDatum);
|
||||||
|
|
||||||
|
Datum ctypeDatum = heap_getattr(tup, Anum_pg_database_datctype, tupdesc, &isNull);
|
||||||
|
info.datctype = TextDatumGetCString(ctypeDatum);
|
||||||
|
|
||||||
|
Datum icuLocaleDatum = heap_getattr(tup, Anum_pg_database_datlocale, tupdesc,
|
||||||
|
&isNull);
|
||||||
|
if (!isNull)
|
||||||
|
{
|
||||||
|
info.daticulocale = TextDatumGetCString(icuLocaleDatum);
|
||||||
|
}
|
||||||
|
|
||||||
|
Datum collverDatum = heap_getattr(tup, Anum_pg_database_datcollversion, tupdesc,
|
||||||
|
&isNull);
|
||||||
|
if (!isNull)
|
||||||
|
{
|
||||||
|
info.datcollversion = TextDatumGetCString(collverDatum);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if PG_VERSION_NUM >= PG_VERSION_16
|
||||||
|
Datum icurulesDatum = heap_getattr(tup, Anum_pg_database_daticurules, tupdesc,
|
||||||
|
&isNull);
|
||||||
|
if (!isNull)
|
||||||
|
{
|
||||||
|
info.daticurules = TextDatumGetCString(icurulesDatum);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
table_close(rel, AccessShareLock);
|
||||||
|
heap_freetuple(tup);
|
||||||
|
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GetLocaleProviderString gets the datlocprovider stored in pg_database
|
||||||
|
* and returns the string representation of the datlocprovider
|
||||||
|
*/
|
||||||
|
static char *
|
||||||
|
GetLocaleProviderString(char datlocprovider)
|
||||||
|
{
|
||||||
|
switch (datlocprovider)
|
||||||
|
{
|
||||||
|
case 'c':
|
||||||
|
{
|
||||||
|
return "libc";
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'i':
|
||||||
|
{
|
||||||
|
return "icu";
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
ereport(ERROR, (errmsg("unexpected datlocprovider value: %c",
|
||||||
|
datlocprovider)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GenerateCreateDatabaseStatementFromPgDatabase gets the pg_database tuple and returns the
|
||||||
|
* CREATE DATABASE statement that can be used to create given database.
|
||||||
|
*
|
||||||
|
* Note that this doesn't deparse OID of the database and this is not a
|
||||||
|
* problem as we anyway don't allow specifying custom OIDs for databases
|
||||||
|
* when creating them.
|
||||||
|
*/
|
||||||
|
static char *
|
||||||
|
GenerateCreateDatabaseStatementFromPgDatabase(Form_pg_database databaseForm)
|
||||||
|
{
|
||||||
|
DatabaseCollationInfo collInfo = GetDatabaseCollation(databaseForm->oid);
|
||||||
|
|
||||||
|
StringInfoData str;
|
||||||
|
initStringInfo(&str);
|
||||||
|
|
||||||
|
appendStringInfo(&str, "CREATE DATABASE %s",
|
||||||
|
quote_identifier(NameStr(databaseForm->datname)));
|
||||||
|
|
||||||
|
appendStringInfo(&str, " CONNECTION LIMIT %d", databaseForm->datconnlimit);
|
||||||
|
|
||||||
|
appendStringInfo(&str, " ALLOW_CONNECTIONS = %s",
|
||||||
|
quote_literal_cstr(databaseForm->datallowconn ? "true" : "false"));
|
||||||
|
|
||||||
|
appendStringInfo(&str, " IS_TEMPLATE = %s",
|
||||||
|
quote_literal_cstr(databaseForm->datistemplate ? "true" : "false"));
|
||||||
|
|
||||||
|
appendStringInfo(&str, " LC_COLLATE = %s",
|
||||||
|
quote_literal_cstr(collInfo.datcollate));
|
||||||
|
|
||||||
|
appendStringInfo(&str, " LC_CTYPE = %s", quote_literal_cstr(collInfo.datctype));
|
||||||
|
|
||||||
|
appendStringInfo(&str, " OWNER = %s",
|
||||||
|
quote_identifier(GetUserNameFromId(databaseForm->datdba, false)));
|
||||||
|
|
||||||
|
appendStringInfo(&str, " TABLESPACE = %s",
|
||||||
|
quote_identifier(GetTablespaceName(databaseForm->dattablespace)));
|
||||||
|
|
||||||
|
appendStringInfo(&str, " ENCODING = %s",
|
||||||
|
quote_literal_cstr(pg_encoding_to_char(databaseForm->encoding)));
|
||||||
|
|
||||||
|
if (collInfo.datcollversion != NULL)
|
||||||
|
{
|
||||||
|
appendStringInfo(&str, " COLLATION_VERSION = %s",
|
||||||
|
quote_identifier(collInfo.datcollversion));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (collInfo.daticulocale != NULL)
|
||||||
|
{
|
||||||
|
appendStringInfo(&str, " ICU_LOCALE = %s", quote_identifier(
|
||||||
|
collInfo.daticulocale));
|
||||||
|
}
|
||||||
|
|
||||||
|
appendStringInfo(&str, " LOCALE_PROVIDER = %s",
|
||||||
|
quote_identifier(GetLocaleProviderString(
|
||||||
|
databaseForm->datlocprovider)));
|
||||||
|
|
||||||
|
#if PG_VERSION_NUM >= PG_VERSION_16
|
||||||
|
if (collInfo.daticurules != NULL)
|
||||||
|
{
|
||||||
|
appendStringInfo(&str, " ICU_RULES = %s", quote_identifier(
|
||||||
|
collInfo.daticurules));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return str.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CreateDatabaseDDLCommand returns a CREATE DATABASE command to create given
|
||||||
|
* database
|
||||||
|
*
|
||||||
|
* Command is wrapped by citus_internal_database_command() UDF
|
||||||
|
* to avoid from transaction block restrictions that apply to database commands.
|
||||||
|
*/
|
||||||
|
char *
|
||||||
|
CreateDatabaseDDLCommand(Oid dbId)
|
||||||
|
{
|
||||||
|
HeapTuple tuple = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(dbId));
|
||||||
|
if (!HeapTupleIsValid(tuple))
|
||||||
|
{
|
||||||
|
ereport(ERROR, (errcode(ERRCODE_UNDEFINED_DATABASE),
|
||||||
|
errmsg("database with OID %u does not exist", dbId)));
|
||||||
|
}
|
||||||
|
|
||||||
|
Form_pg_database databaseForm = (Form_pg_database) GETSTRUCT(tuple);
|
||||||
|
|
||||||
|
char *createStmt = GenerateCreateDatabaseStatementFromPgDatabase(databaseForm);
|
||||||
|
|
||||||
|
StringInfo outerDbStmt = makeStringInfo();
|
||||||
|
|
||||||
|
/* Generate the CREATE DATABASE statement */
|
||||||
|
appendStringInfo(outerDbStmt,
|
||||||
|
"SELECT citus_internal.database_command(%s)",
|
||||||
|
quote_literal_cstr(createStmt));
|
||||||
|
|
||||||
|
ReleaseSysCache(tuple);
|
||||||
|
|
||||||
|
return outerDbStmt->data;
|
||||||
|
}
|
||||||
|
|
|
@ -10,9 +10,14 @@
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
|
#include "miscadmin.h"
|
||||||
|
|
||||||
#include "catalog/dependency.h"
|
#include "catalog/dependency.h"
|
||||||
#include "catalog/objectaddress.h"
|
#include "catalog/objectaddress.h"
|
||||||
#include "commands/extension.h"
|
#include "commands/extension.h"
|
||||||
|
#include "storage/lmgr.h"
|
||||||
|
#include "utils/lsyscache.h"
|
||||||
|
|
||||||
#include "distributed/commands.h"
|
#include "distributed/commands.h"
|
||||||
#include "distributed/commands/utility_hook.h"
|
#include "distributed/commands/utility_hook.h"
|
||||||
#include "distributed/connection_management.h"
|
#include "distributed/connection_management.h"
|
||||||
|
@ -25,57 +30,147 @@
|
||||||
#include "distributed/remote_commands.h"
|
#include "distributed/remote_commands.h"
|
||||||
#include "distributed/worker_manager.h"
|
#include "distributed/worker_manager.h"
|
||||||
#include "distributed/worker_transaction.h"
|
#include "distributed/worker_transaction.h"
|
||||||
#include "miscadmin.h"
|
|
||||||
#include "storage/lmgr.h"
|
typedef enum RequiredObjectSet
|
||||||
#include "utils/lsyscache.h"
|
{
|
||||||
|
REQUIRE_ONLY_DEPENDENCIES = 1,
|
||||||
|
REQUIRE_OBJECT_AND_DEPENDENCIES = 2,
|
||||||
|
} RequiredObjectSet;
|
||||||
|
|
||||||
|
|
||||||
static void EnsureDependenciesCanBeDistributed(const ObjectAddress *relationAddress);
|
static void EnsureDependenciesCanBeDistributed(const ObjectAddress *relationAddress);
|
||||||
static void ErrorIfCircularDependencyExists(const ObjectAddress *objectAddress);
|
static void ErrorIfCircularDependencyExists(const ObjectAddress *objectAddress);
|
||||||
static int ObjectAddressComparator(const void *a, const void *b);
|
static int ObjectAddressComparator(const void *a, const void *b);
|
||||||
static void EnsureDependenciesExistOnAllNodes(const ObjectAddress *target);
|
static void EnsureDependenciesExistOnAllNodes(const ObjectAddress *target);
|
||||||
|
static void EnsureRequiredObjectSetExistOnAllNodes(const ObjectAddress *target,
|
||||||
|
RequiredObjectSet requiredObjectSet);
|
||||||
static List * GetDependencyCreateDDLCommands(const ObjectAddress *dependency);
|
static List * GetDependencyCreateDDLCommands(const ObjectAddress *dependency);
|
||||||
static bool ShouldPropagateObject(const ObjectAddress *address);
|
static bool ShouldPropagateObject(const ObjectAddress *address);
|
||||||
static char * DropTableIfExistsCommand(Oid relationId);
|
static char * DropTableIfExistsCommand(Oid relationId);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* EnsureDependenciesExistOnAllNodes finds all the dependencies that we support and makes
|
* EnsureObjectAndDependenciesExistOnAllNodes is a wrapper around
|
||||||
* sure these are available on all workers. If not available they will be created on the
|
* EnsureRequiredObjectSetExistOnAllNodes to ensure the "object itself" (together
|
||||||
* workers via a separate session that will be committed directly so that the objects are
|
* with its dependencies) is available on all nodes.
|
||||||
* visible to potentially multiple sessions creating the shards.
|
*
|
||||||
|
* Different than EnsureDependenciesExistOnAllNodes, we return early if the
|
||||||
|
* target object is distributed already.
|
||||||
|
*
|
||||||
|
* The reason why we don't do the same in EnsureDependenciesExistOnAllNodes
|
||||||
|
* is that it's is used when altering an object too and hence the target object
|
||||||
|
* may instantly have a dependency that needs to be propagated now. For example,
|
||||||
|
* when "GRANT non_dist_role TO dist_role" is executed, we need to propagate
|
||||||
|
* "non_dist_role" to all nodes before propagating the "GRANT" command itself.
|
||||||
|
* For this reason, we call EnsureDependenciesExistOnAllNodes for "dist_role"
|
||||||
|
* and it would automatically discover that "non_dist_role" is a dependency of
|
||||||
|
* "dist_role" and propagate it beforehand.
|
||||||
|
*
|
||||||
|
* However, when we're requested to create the target object itself (and
|
||||||
|
* implicitly its dependencies), we're sure that we're not altering the target
|
||||||
|
* object itself, hence we can return early if the target object is already
|
||||||
|
* distributed. This is the case, for example, when
|
||||||
|
* "REASSIGN OWNED BY dist_role TO non_dist_role" is executed. In that case,
|
||||||
|
* "non_dist_role" is not a dependency of "dist_role" but we want to distribute
|
||||||
|
* "non_dist_role" beforehand and we call this function for "non_dist_role",
|
||||||
|
* not for "dist_role".
|
||||||
|
*
|
||||||
|
* See EnsureRequiredObjectExistOnAllNodes to learn more about how this
|
||||||
|
* function deals with an object created within the same transaction.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
EnsureObjectAndDependenciesExistOnAllNodes(const ObjectAddress *target)
|
||||||
|
{
|
||||||
|
if (IsAnyObjectDistributed(list_make1((ObjectAddress *) target)))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
EnsureRequiredObjectSetExistOnAllNodes(target, REQUIRE_OBJECT_AND_DEPENDENCIES);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* EnsureDependenciesExistOnAllNodes is a wrapper around
|
||||||
|
* EnsureRequiredObjectSetExistOnAllNodes to ensure "all dependencies" of given
|
||||||
|
* object --but not the object itself-- are available on all nodes.
|
||||||
|
*
|
||||||
|
* See EnsureRequiredObjectSetExistOnAllNodes to learn more about how this
|
||||||
|
* function deals with an object created within the same transaction.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
EnsureDependenciesExistOnAllNodes(const ObjectAddress *target)
|
||||||
|
{
|
||||||
|
EnsureRequiredObjectSetExistOnAllNodes(target, REQUIRE_ONLY_DEPENDENCIES);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* EnsureRequiredObjectSetExistOnAllNodes finds all the dependencies that we support and makes
|
||||||
|
* sure these are available on all nodes if required object set is REQUIRE_ONLY_DEPENDENCIES.
|
||||||
|
* Otherwise, i.e., if required object set is REQUIRE_OBJECT_AND_DEPENDENCIES, then this
|
||||||
|
* function creates the object itself on all nodes too. This function ensures that each
|
||||||
|
* of the dependencies are supported by Citus but doesn't check the same for the target
|
||||||
|
* object itself (when REQUIRE_OBJECT_AND_DEPENDENCIES) is provided because we assume that
|
||||||
|
* callers don't call this function for an unsupported function at all.
|
||||||
|
*
|
||||||
|
* If not available, they will be created on the nodes via a separate session that will be
|
||||||
|
* committed directly so that the objects are visible to potentially multiple sessions creating
|
||||||
|
* the shards.
|
||||||
*
|
*
|
||||||
* Note; only the actual objects are created via a separate session, the records to
|
* Note; only the actual objects are created via a separate session, the records to
|
||||||
* pg_dist_object are created in this session. As a side effect the objects could be
|
* pg_dist_object are created in this session. As a side effect the objects could be
|
||||||
* created on the workers without a catalog entry. Updates to the objects on the coordinator
|
* created on the nodes without a catalog entry. Updates to the objects on local node
|
||||||
* are not propagated to the workers until the record is visible on the coordinator.
|
* are not propagated to the remote nodes until the record is visible on local node.
|
||||||
*
|
*
|
||||||
* This is solved by creating the dependencies in an idempotent manner, either via
|
* This is solved by creating the dependencies in an idempotent manner, either via
|
||||||
* postgres native CREATE IF NOT EXISTS, or citus helper functions.
|
* postgres native CREATE IF NOT EXISTS, or citus helper functions.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
EnsureDependenciesExistOnAllNodes(const ObjectAddress *target)
|
EnsureRequiredObjectSetExistOnAllNodes(const ObjectAddress *target,
|
||||||
|
RequiredObjectSet requiredObjectSet)
|
||||||
{
|
{
|
||||||
List *dependenciesWithCommands = NIL;
|
Assert(requiredObjectSet == REQUIRE_ONLY_DEPENDENCIES ||
|
||||||
|
requiredObjectSet == REQUIRE_OBJECT_AND_DEPENDENCIES);
|
||||||
|
|
||||||
|
|
||||||
|
List *objectsWithCommands = NIL;
|
||||||
List *ddlCommands = NULL;
|
List *ddlCommands = NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If there is any unsupported dependency or circular dependency exists, Citus can
|
* If there is any unsupported dependency or circular dependency exists, Citus can
|
||||||
* not ensure dependencies will exist on all nodes.
|
* not ensure dependencies will exist on all nodes.
|
||||||
|
*
|
||||||
|
* Note that we don't check whether "target" is distributable (in case
|
||||||
|
* REQUIRE_OBJECT_AND_DEPENDENCIES is provided) because we expect callers
|
||||||
|
* to not even call this function if Citus doesn't know how to propagate
|
||||||
|
* "target" object itself.
|
||||||
*/
|
*/
|
||||||
EnsureDependenciesCanBeDistributed(target);
|
EnsureDependenciesCanBeDistributed(target);
|
||||||
|
|
||||||
/* collect all dependencies in creation order and get their ddl commands */
|
/* collect all dependencies in creation order and get their ddl commands */
|
||||||
List *dependencies = GetDependenciesForObject(target);
|
List *objectsToBeCreated = GetDependenciesForObject(target);
|
||||||
ObjectAddress *dependency = NULL;
|
|
||||||
foreach_ptr(dependency, dependencies)
|
/*
|
||||||
|
* Append the target object to make sure that it's created after its
|
||||||
|
* dependencies are created, if requested.
|
||||||
|
*/
|
||||||
|
if (requiredObjectSet == REQUIRE_OBJECT_AND_DEPENDENCIES)
|
||||||
{
|
{
|
||||||
List *dependencyCommands = GetDependencyCreateDDLCommands(dependency);
|
ObjectAddress *targetCopy = palloc(sizeof(ObjectAddress));
|
||||||
|
*targetCopy = *target;
|
||||||
|
|
||||||
|
objectsToBeCreated = lappend(objectsToBeCreated, targetCopy);
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectAddress *object = NULL;
|
||||||
|
foreach_declared_ptr(object, objectsToBeCreated)
|
||||||
|
{
|
||||||
|
List *dependencyCommands = GetDependencyCreateDDLCommands(object);
|
||||||
ddlCommands = list_concat(ddlCommands, dependencyCommands);
|
ddlCommands = list_concat(ddlCommands, dependencyCommands);
|
||||||
|
|
||||||
/* create a new list with dependencies that actually created commands */
|
/* create a new list with objects that actually created commands */
|
||||||
if (list_length(dependencyCommands) > 0)
|
if (list_length(dependencyCommands) > 0)
|
||||||
{
|
{
|
||||||
dependenciesWithCommands = lappend(dependenciesWithCommands, dependency);
|
objectsWithCommands = lappend(objectsWithCommands, object);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (list_length(ddlCommands) <= 0)
|
if (list_length(ddlCommands) <= 0)
|
||||||
|
@ -95,29 +190,31 @@ EnsureDependenciesExistOnAllNodes(const ObjectAddress *target)
|
||||||
* either get it now, or get it in citus_add_node after this transaction finishes and
|
* either get it now, or get it in citus_add_node after this transaction finishes and
|
||||||
* the pg_dist_object record becomes visible.
|
* the pg_dist_object record becomes visible.
|
||||||
*/
|
*/
|
||||||
List *workerNodeList = ActivePrimaryNonCoordinatorNodeList(RowShareLock);
|
List *remoteNodeList = ActivePrimaryRemoteNodeList(RowShareLock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Lock dependent objects explicitly to make sure same DDL command won't be sent
|
* Lock objects to be created explicitly to make sure same DDL command won't be sent
|
||||||
* multiple times from parallel sessions.
|
* multiple times from parallel sessions.
|
||||||
*
|
*
|
||||||
* Sort dependencies that will be created on workers to not to have any deadlock
|
* Sort the objects that will be created on workers to not to have any deadlock
|
||||||
* issue if different sessions are creating different objects.
|
* issue if different sessions are creating different objects.
|
||||||
*/
|
*/
|
||||||
List *addressSortedDependencies = SortList(dependenciesWithCommands,
|
List *addressSortedDependencies = SortList(objectsWithCommands,
|
||||||
ObjectAddressComparator);
|
ObjectAddressComparator);
|
||||||
foreach_ptr(dependency, addressSortedDependencies)
|
foreach_declared_ptr(object, addressSortedDependencies)
|
||||||
{
|
{
|
||||||
LockDatabaseObject(dependency->classId, dependency->objectId,
|
LockDatabaseObject(object->classId, object->objectId,
|
||||||
dependency->objectSubId, ExclusiveLock);
|
object->objectSubId, ExclusiveLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We need to propagate dependencies via the current user's metadata connection if
|
* We need to propagate objects via the current user's metadata connection if
|
||||||
* any dependency for the target is created in the current transaction. Our assumption
|
* any of the objects that we're interested in are created in the current transaction.
|
||||||
* is that if we rely on a dependency created in the current transaction, then the
|
* Our assumption is that if we rely on an object created in the current transaction,
|
||||||
* current user, most probably, has permissions to create the target object as well.
|
* then the current user, most probably, has permissions to create the target object
|
||||||
|
* as well.
|
||||||
|
*
|
||||||
* Note that, user still may not be able to create the target due to no permissions
|
* Note that, user still may not be able to create the target due to no permissions
|
||||||
* for any of its dependencies. But this is ok since it should be rare.
|
* for any of its dependencies. But this is ok since it should be rare.
|
||||||
*
|
*
|
||||||
|
@ -125,14 +222,25 @@ EnsureDependenciesExistOnAllNodes(const ObjectAddress *target)
|
||||||
* have visibility issues since propagated dependencies would be invisible to
|
* have visibility issues since propagated dependencies would be invisible to
|
||||||
* the separate connection until we locally commit.
|
* the separate connection until we locally commit.
|
||||||
*/
|
*/
|
||||||
if (HasAnyDependencyInPropagatedObjects(target))
|
List *createdObjectList = GetAllSupportedDependenciesForObject(target);
|
||||||
|
|
||||||
|
/* consider target as well if we're requested to create it too */
|
||||||
|
if (requiredObjectSet == REQUIRE_OBJECT_AND_DEPENDENCIES)
|
||||||
{
|
{
|
||||||
SendCommandListToWorkersWithMetadata(ddlCommands);
|
ObjectAddress *targetCopy = palloc(sizeof(ObjectAddress));
|
||||||
|
*targetCopy = *target;
|
||||||
|
|
||||||
|
createdObjectList = lappend(createdObjectList, targetCopy);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HasAnyObjectInPropagatedObjects(createdObjectList))
|
||||||
|
{
|
||||||
|
SendCommandListToRemoteNodesWithMetadata(ddlCommands);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
WorkerNode *workerNode = NULL;
|
WorkerNode *workerNode = NULL;
|
||||||
foreach_ptr(workerNode, workerNodeList)
|
foreach_declared_ptr(workerNode, remoteNodeList)
|
||||||
{
|
{
|
||||||
const char *nodeName = workerNode->workerName;
|
const char *nodeName = workerNode->workerName;
|
||||||
uint32 nodePort = workerNode->workerPort;
|
uint32 nodePort = workerNode->workerPort;
|
||||||
|
@ -144,11 +252,11 @@ EnsureDependenciesExistOnAllNodes(const ObjectAddress *target)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We do this after creating the objects on the workers, we make sure
|
* We do this after creating the objects on remote nodes, we make sure
|
||||||
* that objects have been created on worker nodes before marking them
|
* that objects have been created on remote nodes before marking them
|
||||||
* distributed, so MarkObjectDistributed wouldn't fail.
|
* distributed, so MarkObjectDistributed wouldn't fail.
|
||||||
*/
|
*/
|
||||||
foreach_ptr(dependency, dependenciesWithCommands)
|
foreach_declared_ptr(object, objectsWithCommands)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* pg_dist_object entries must be propagated with the super user, since
|
* pg_dist_object entries must be propagated with the super user, since
|
||||||
|
@ -158,7 +266,7 @@ EnsureDependenciesExistOnAllNodes(const ObjectAddress *target)
|
||||||
* Only dependent object's metadata should be propagated with super user.
|
* Only dependent object's metadata should be propagated with super user.
|
||||||
* Metadata of the table itself must be propagated with the current user.
|
* Metadata of the table itself must be propagated with the current user.
|
||||||
*/
|
*/
|
||||||
MarkObjectDistributedViaSuperUser(dependency);
|
MarkObjectDistributedViaSuperUser(object);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,7 +279,7 @@ void
|
||||||
EnsureAllObjectDependenciesExistOnAllNodes(const List *targets)
|
EnsureAllObjectDependenciesExistOnAllNodes(const List *targets)
|
||||||
{
|
{
|
||||||
ObjectAddress *target = NULL;
|
ObjectAddress *target = NULL;
|
||||||
foreach_ptr(target, targets)
|
foreach_declared_ptr(target, targets)
|
||||||
{
|
{
|
||||||
EnsureDependenciesExistOnAllNodes(target);
|
EnsureDependenciesExistOnAllNodes(target);
|
||||||
}
|
}
|
||||||
|
@ -228,7 +336,7 @@ DeferErrorIfCircularDependencyExists(const ObjectAddress *objectAddress)
|
||||||
List *dependencies = GetAllDependenciesForObject(objectAddress);
|
List *dependencies = GetAllDependenciesForObject(objectAddress);
|
||||||
|
|
||||||
ObjectAddress *dependency = NULL;
|
ObjectAddress *dependency = NULL;
|
||||||
foreach_ptr(dependency, dependencies)
|
foreach_declared_ptr(dependency, dependencies)
|
||||||
{
|
{
|
||||||
if (dependency->classId == objectAddress->classId &&
|
if (dependency->classId == objectAddress->classId &&
|
||||||
dependency->objectId == objectAddress->objectId &&
|
dependency->objectId == objectAddress->objectId &&
|
||||||
|
@ -316,7 +424,7 @@ GetDistributableDependenciesForObject(const ObjectAddress *target)
|
||||||
|
|
||||||
/* filter the ones that can be distributed */
|
/* filter the ones that can be distributed */
|
||||||
ObjectAddress *dependency = NULL;
|
ObjectAddress *dependency = NULL;
|
||||||
foreach_ptr(dependency, dependencies)
|
foreach_declared_ptr(dependency, dependencies)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* TODO: maybe we can optimize the logic applied in below line. Actually we
|
* TODO: maybe we can optimize the logic applied in below line. Actually we
|
||||||
|
@ -400,7 +508,7 @@ GetDependencyCreateDDLCommands(const ObjectAddress *dependency)
|
||||||
INCLUDE_IDENTITY,
|
INCLUDE_IDENTITY,
|
||||||
creatingShellTableOnRemoteNode);
|
creatingShellTableOnRemoteNode);
|
||||||
TableDDLCommand *tableDDLCommand = NULL;
|
TableDDLCommand *tableDDLCommand = NULL;
|
||||||
foreach_ptr(tableDDLCommand, tableDDLCommands)
|
foreach_declared_ptr(tableDDLCommand, tableDDLCommands)
|
||||||
{
|
{
|
||||||
Assert(CitusIsA(tableDDLCommand, TableDDLCommand));
|
Assert(CitusIsA(tableDDLCommand, TableDDLCommand));
|
||||||
commandList = lappend(commandList, GetTableDDLCommand(
|
commandList = lappend(commandList, GetTableDDLCommand(
|
||||||
|
@ -457,16 +565,29 @@ GetDependencyCreateDDLCommands(const ObjectAddress *dependency)
|
||||||
|
|
||||||
case OCLASS_DATABASE:
|
case OCLASS_DATABASE:
|
||||||
{
|
{
|
||||||
List *databaseDDLCommands = NIL;
|
/*
|
||||||
|
* For the database where Citus is installed, only propagate the ownership of the
|
||||||
/* only propagate the ownership of the database when the feature is on */
|
* database, only when the feature is on.
|
||||||
if (EnableAlterDatabaseOwner)
|
*
|
||||||
|
* This is because this database must exist on all nodes already so we shouldn't
|
||||||
|
* need to "CREATE" it on other nodes. However, we still need to correctly reflect
|
||||||
|
* its owner on other nodes too.
|
||||||
|
*/
|
||||||
|
if (dependency->objectId == MyDatabaseId && EnableAlterDatabaseOwner)
|
||||||
{
|
{
|
||||||
List *ownerDDLCommands = DatabaseOwnerDDLCommands(dependency);
|
return DatabaseOwnerDDLCommands(dependency);
|
||||||
databaseDDLCommands = list_concat(databaseDDLCommands, ownerDDLCommands);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return databaseDDLCommands;
|
/*
|
||||||
|
* For the other databases, create the database on all nodes, only when the feature
|
||||||
|
* is on.
|
||||||
|
*/
|
||||||
|
if (dependency->objectId != MyDatabaseId && EnableCreateDatabasePropagation)
|
||||||
|
{
|
||||||
|
return GetDatabaseMetadataSyncCommands(dependency->objectId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
case OCLASS_PROC:
|
case OCLASS_PROC:
|
||||||
|
@ -562,7 +683,7 @@ GetAllDependencyCreateDDLCommands(const List *dependencies)
|
||||||
List *commands = NIL;
|
List *commands = NIL;
|
||||||
|
|
||||||
ObjectAddress *dependency = NULL;
|
ObjectAddress *dependency = NULL;
|
||||||
foreach_ptr(dependency, dependencies)
|
foreach_declared_ptr(dependency, dependencies)
|
||||||
{
|
{
|
||||||
commands = list_concat(commands, GetDependencyCreateDDLCommands(dependency));
|
commands = list_concat(commands, GetDependencyCreateDDLCommands(dependency));
|
||||||
}
|
}
|
||||||
|
@ -710,7 +831,7 @@ bool
|
||||||
ShouldPropagateAnyObject(List *addresses)
|
ShouldPropagateAnyObject(List *addresses)
|
||||||
{
|
{
|
||||||
ObjectAddress *address = NULL;
|
ObjectAddress *address = NULL;
|
||||||
foreach_ptr(address, addresses)
|
foreach_declared_ptr(address, addresses)
|
||||||
{
|
{
|
||||||
if (ShouldPropagateObject(address))
|
if (ShouldPropagateObject(address))
|
||||||
{
|
{
|
||||||
|
@ -732,7 +853,7 @@ FilterObjectAddressListByPredicate(List *objectAddressList, AddressPredicate pre
|
||||||
List *result = NIL;
|
List *result = NIL;
|
||||||
|
|
||||||
ObjectAddress *address = NULL;
|
ObjectAddress *address = NULL;
|
||||||
foreach_ptr(address, objectAddressList)
|
foreach_declared_ptr(address, objectAddressList)
|
||||||
{
|
{
|
||||||
if (predicate(address))
|
if (predicate(address))
|
||||||
{
|
{
|
||||||
|
|
|
@ -12,11 +12,13 @@
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
|
#include "pg_version_constants.h"
|
||||||
|
|
||||||
#include "distributed/commands.h"
|
#include "distributed/commands.h"
|
||||||
#include "distributed/deparser.h"
|
|
||||||
#include "distributed/pg_version_constants.h"
|
|
||||||
#include "distributed/version_compat.h"
|
|
||||||
#include "distributed/commands/utility_hook.h"
|
#include "distributed/commands/utility_hook.h"
|
||||||
|
#include "distributed/comment.h"
|
||||||
|
#include "distributed/deparser.h"
|
||||||
|
#include "distributed/version_compat.h"
|
||||||
|
|
||||||
static DistributeObjectOps NoDistributeOps = {
|
static DistributeObjectOps NoDistributeOps = {
|
||||||
.deparse = NULL,
|
.deparse = NULL,
|
||||||
|
@ -150,6 +152,17 @@ static DistributeObjectOps Any_AlterRole = {
|
||||||
.address = AlterRoleStmtObjectAddress,
|
.address = AlterRoleStmtObjectAddress,
|
||||||
.markDistributed = false,
|
.markDistributed = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static DistributeObjectOps Any_AlterRoleRename = {
|
||||||
|
.deparse = DeparseRenameRoleStmt,
|
||||||
|
.qualify = NULL,
|
||||||
|
.preprocess = PreprocessAlterRoleRenameStmt,
|
||||||
|
.postprocess = NULL,
|
||||||
|
.operationType = DIST_OPS_ALTER,
|
||||||
|
.address = RenameRoleStmtObjectAddress,
|
||||||
|
.markDistributed = false,
|
||||||
|
};
|
||||||
|
|
||||||
static DistributeObjectOps Any_AlterRoleSet = {
|
static DistributeObjectOps Any_AlterRoleSet = {
|
||||||
.deparse = DeparseAlterRoleSetStmt,
|
.deparse = DeparseAlterRoleSetStmt,
|
||||||
.qualify = QualifyAlterRoleSetStmt,
|
.qualify = QualifyAlterRoleSetStmt,
|
||||||
|
@ -263,6 +276,17 @@ static DistributeObjectOps Any_CreateRole = {
|
||||||
.address = CreateRoleStmtObjectAddress,
|
.address = CreateRoleStmtObjectAddress,
|
||||||
.markDistributed = true,
|
.markDistributed = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static DistributeObjectOps Any_ReassignOwned = {
|
||||||
|
.deparse = DeparseReassignOwnedStmt,
|
||||||
|
.qualify = NULL,
|
||||||
|
.preprocess = NULL,
|
||||||
|
.postprocess = PostprocessReassignOwnedStmt,
|
||||||
|
.operationType = DIST_OPS_ALTER,
|
||||||
|
.address = NULL,
|
||||||
|
.markDistributed = false,
|
||||||
|
};
|
||||||
|
|
||||||
static DistributeObjectOps Any_DropOwned = {
|
static DistributeObjectOps Any_DropOwned = {
|
||||||
.deparse = DeparseDropOwnedStmt,
|
.deparse = DeparseDropOwnedStmt,
|
||||||
.qualify = NULL,
|
.qualify = NULL,
|
||||||
|
@ -281,6 +305,17 @@ static DistributeObjectOps Any_DropRole = {
|
||||||
.address = NULL,
|
.address = NULL,
|
||||||
.markDistributed = false,
|
.markDistributed = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static DistributeObjectOps Role_Comment = {
|
||||||
|
.deparse = DeparseCommentStmt,
|
||||||
|
.qualify = NULL,
|
||||||
|
.preprocess = PreprocessAlterDistributedObjectStmt,
|
||||||
|
.postprocess = NULL,
|
||||||
|
.objectType = OBJECT_DATABASE,
|
||||||
|
.operationType = DIST_OPS_ALTER,
|
||||||
|
.address = CommentObjectAddress,
|
||||||
|
.markDistributed = false,
|
||||||
|
};
|
||||||
static DistributeObjectOps Any_CreateForeignServer = {
|
static DistributeObjectOps Any_CreateForeignServer = {
|
||||||
.deparse = DeparseCreateForeignServerStmt,
|
.deparse = DeparseCreateForeignServerStmt,
|
||||||
.qualify = NULL,
|
.qualify = NULL,
|
||||||
|
@ -363,6 +398,42 @@ static DistributeObjectOps Any_Rename = {
|
||||||
.address = NULL,
|
.address = NULL,
|
||||||
.markDistributed = false,
|
.markDistributed = false,
|
||||||
};
|
};
|
||||||
|
static DistributeObjectOps Any_SecLabel = {
|
||||||
|
.deparse = NULL,
|
||||||
|
.qualify = NULL,
|
||||||
|
.preprocess = NULL,
|
||||||
|
.postprocess = PostprocessAnySecLabelStmt,
|
||||||
|
.operationType = DIST_OPS_ALTER,
|
||||||
|
.address = SecLabelStmtObjectAddress,
|
||||||
|
.markDistributed = false,
|
||||||
|
};
|
||||||
|
static DistributeObjectOps Role_SecLabel = {
|
||||||
|
.deparse = DeparseRoleSecLabelStmt,
|
||||||
|
.qualify = NULL,
|
||||||
|
.preprocess = NULL,
|
||||||
|
.postprocess = PostprocessRoleSecLabelStmt,
|
||||||
|
.operationType = DIST_OPS_ALTER,
|
||||||
|
.address = SecLabelStmtObjectAddress,
|
||||||
|
.markDistributed = false,
|
||||||
|
};
|
||||||
|
static DistributeObjectOps Table_SecLabel = {
|
||||||
|
.deparse = DeparseTableSecLabelStmt,
|
||||||
|
.qualify = NULL,
|
||||||
|
.preprocess = NULL,
|
||||||
|
.postprocess = PostprocessTableOrColumnSecLabelStmt,
|
||||||
|
.operationType = DIST_OPS_ALTER,
|
||||||
|
.address = SecLabelStmtObjectAddress,
|
||||||
|
.markDistributed = false,
|
||||||
|
};
|
||||||
|
static DistributeObjectOps Column_SecLabel = {
|
||||||
|
.deparse = DeparseColumnSecLabelStmt,
|
||||||
|
.qualify = NULL,
|
||||||
|
.preprocess = NULL,
|
||||||
|
.postprocess = PostprocessTableOrColumnSecLabelStmt,
|
||||||
|
.operationType = DIST_OPS_ALTER,
|
||||||
|
.address = SecLabelStmtObjectAddress,
|
||||||
|
.markDistributed = false,
|
||||||
|
};
|
||||||
static DistributeObjectOps Attribute_Rename = {
|
static DistributeObjectOps Attribute_Rename = {
|
||||||
.deparse = DeparseRenameAttributeStmt,
|
.deparse = DeparseRenameAttributeStmt,
|
||||||
.qualify = QualifyRenameAttributeStmt,
|
.qualify = QualifyRenameAttributeStmt,
|
||||||
|
@ -455,7 +526,28 @@ static DistributeObjectOps Database_Alter = {
|
||||||
.markDistributed = false,
|
.markDistributed = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
#if PG_VERSION_NUM >= PG_VERSION_15
|
static DistributeObjectOps Database_Create = {
|
||||||
|
.deparse = DeparseCreateDatabaseStmt,
|
||||||
|
.qualify = NULL,
|
||||||
|
.preprocess = PreprocessCreateDatabaseStmt,
|
||||||
|
.postprocess = PostprocessCreateDatabaseStmt,
|
||||||
|
.objectType = OBJECT_DATABASE,
|
||||||
|
.operationType = DIST_OPS_CREATE,
|
||||||
|
.address = CreateDatabaseStmtObjectAddress,
|
||||||
|
.markDistributed = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
static DistributeObjectOps Database_Drop = {
|
||||||
|
.deparse = DeparseDropDatabaseStmt,
|
||||||
|
.qualify = NULL,
|
||||||
|
.preprocess = PreprocessDropDatabaseStmt,
|
||||||
|
.postprocess = NULL,
|
||||||
|
.objectType = OBJECT_DATABASE,
|
||||||
|
.operationType = DIST_OPS_DROP,
|
||||||
|
.address = DropDatabaseStmtObjectAddress,
|
||||||
|
.markDistributed = false,
|
||||||
|
};
|
||||||
|
|
||||||
static DistributeObjectOps Database_RefreshColl = {
|
static DistributeObjectOps Database_RefreshColl = {
|
||||||
.deparse = DeparseAlterDatabaseRefreshCollStmt,
|
.deparse = DeparseAlterDatabaseRefreshCollStmt,
|
||||||
.qualify = NULL,
|
.qualify = NULL,
|
||||||
|
@ -466,7 +558,39 @@ static DistributeObjectOps Database_RefreshColl = {
|
||||||
.address = NULL,
|
.address = NULL,
|
||||||
.markDistributed = false,
|
.markDistributed = false,
|
||||||
};
|
};
|
||||||
#endif
|
|
||||||
|
static DistributeObjectOps Database_Set = {
|
||||||
|
.deparse = DeparseAlterDatabaseSetStmt,
|
||||||
|
.qualify = NULL,
|
||||||
|
.preprocess = PreprocessAlterDatabaseSetStmt,
|
||||||
|
.postprocess = NULL,
|
||||||
|
.objectType = OBJECT_DATABASE,
|
||||||
|
.operationType = DIST_OPS_ALTER,
|
||||||
|
.address = NULL,
|
||||||
|
.markDistributed = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
static DistributeObjectOps Database_Comment = {
|
||||||
|
.deparse = DeparseCommentStmt,
|
||||||
|
.qualify = NULL,
|
||||||
|
.preprocess = PreprocessAlterDistributedObjectStmt,
|
||||||
|
.postprocess = NULL,
|
||||||
|
.objectType = OBJECT_DATABASE,
|
||||||
|
.operationType = DIST_OPS_ALTER,
|
||||||
|
.address = CommentObjectAddress,
|
||||||
|
.markDistributed = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
static DistributeObjectOps Database_Rename = {
|
||||||
|
.deparse = DeparseAlterDatabaseRenameStmt,
|
||||||
|
.qualify = NULL,
|
||||||
|
.preprocess = PreprocessAlterDatabaseRenameStmt,
|
||||||
|
.postprocess = PostprocessAlterDatabaseRenameStmt,
|
||||||
|
.objectType = OBJECT_DATABASE,
|
||||||
|
.operationType = DIST_OPS_ALTER,
|
||||||
|
.address = NULL,
|
||||||
|
.markDistributed = false,
|
||||||
|
};
|
||||||
|
|
||||||
static DistributeObjectOps Domain_Alter = {
|
static DistributeObjectOps Domain_Alter = {
|
||||||
.deparse = DeparseAlterDomainStmt,
|
.deparse = DeparseAlterDomainStmt,
|
||||||
|
@ -827,7 +951,6 @@ static DistributeObjectOps Sequence_AlterOwner = {
|
||||||
.address = AlterSequenceOwnerStmtObjectAddress,
|
.address = AlterSequenceOwnerStmtObjectAddress,
|
||||||
.markDistributed = false,
|
.markDistributed = false,
|
||||||
};
|
};
|
||||||
#if (PG_VERSION_NUM >= PG_VERSION_15)
|
|
||||||
static DistributeObjectOps Sequence_AlterPersistence = {
|
static DistributeObjectOps Sequence_AlterPersistence = {
|
||||||
.deparse = DeparseAlterSequencePersistenceStmt,
|
.deparse = DeparseAlterSequencePersistenceStmt,
|
||||||
.qualify = QualifyAlterSequencePersistenceStmt,
|
.qualify = QualifyAlterSequencePersistenceStmt,
|
||||||
|
@ -837,7 +960,6 @@ static DistributeObjectOps Sequence_AlterPersistence = {
|
||||||
.address = AlterSequencePersistenceStmtObjectAddress,
|
.address = AlterSequencePersistenceStmtObjectAddress,
|
||||||
.markDistributed = false,
|
.markDistributed = false,
|
||||||
};
|
};
|
||||||
#endif
|
|
||||||
static DistributeObjectOps Sequence_Drop = {
|
static DistributeObjectOps Sequence_Drop = {
|
||||||
.deparse = DeparseDropSequenceStmt,
|
.deparse = DeparseDropSequenceStmt,
|
||||||
.qualify = QualifyDropSequenceStmt,
|
.qualify = QualifyDropSequenceStmt,
|
||||||
|
@ -896,13 +1018,18 @@ static DistributeObjectOps TextSearchConfig_AlterOwner = {
|
||||||
.markDistributed = false,
|
.markDistributed = false,
|
||||||
};
|
};
|
||||||
static DistributeObjectOps TextSearchConfig_Comment = {
|
static DistributeObjectOps TextSearchConfig_Comment = {
|
||||||
.deparse = DeparseTextSearchConfigurationCommentStmt,
|
.deparse = DeparseCommentStmt,
|
||||||
|
|
||||||
|
/* TODO: When adding new comment types we should create an abstracted
|
||||||
|
* qualify function, just like we have an abstract deparse
|
||||||
|
* and adress function
|
||||||
|
*/
|
||||||
.qualify = QualifyTextSearchConfigurationCommentStmt,
|
.qualify = QualifyTextSearchConfigurationCommentStmt,
|
||||||
.preprocess = PreprocessAlterDistributedObjectStmt,
|
.preprocess = PreprocessAlterDistributedObjectStmt,
|
||||||
.postprocess = NULL,
|
.postprocess = NULL,
|
||||||
.objectType = OBJECT_TSCONFIGURATION,
|
.objectType = OBJECT_TSCONFIGURATION,
|
||||||
.operationType = DIST_OPS_ALTER,
|
.operationType = DIST_OPS_ALTER,
|
||||||
.address = TextSearchConfigurationCommentObjectAddress,
|
.address = CommentObjectAddress,
|
||||||
.markDistributed = false,
|
.markDistributed = false,
|
||||||
};
|
};
|
||||||
static DistributeObjectOps TextSearchConfig_Define = {
|
static DistributeObjectOps TextSearchConfig_Define = {
|
||||||
|
@ -965,13 +1092,13 @@ static DistributeObjectOps TextSearchDict_AlterOwner = {
|
||||||
.markDistributed = false,
|
.markDistributed = false,
|
||||||
};
|
};
|
||||||
static DistributeObjectOps TextSearchDict_Comment = {
|
static DistributeObjectOps TextSearchDict_Comment = {
|
||||||
.deparse = DeparseTextSearchDictionaryCommentStmt,
|
.deparse = DeparseCommentStmt,
|
||||||
.qualify = QualifyTextSearchDictionaryCommentStmt,
|
.qualify = QualifyTextSearchDictionaryCommentStmt,
|
||||||
.preprocess = PreprocessAlterDistributedObjectStmt,
|
.preprocess = PreprocessAlterDistributedObjectStmt,
|
||||||
.postprocess = NULL,
|
.postprocess = NULL,
|
||||||
.objectType = OBJECT_TSDICTIONARY,
|
.objectType = OBJECT_TSDICTIONARY,
|
||||||
.operationType = DIST_OPS_ALTER,
|
.operationType = DIST_OPS_ALTER,
|
||||||
.address = TextSearchDictCommentObjectAddress,
|
.address = CommentObjectAddress,
|
||||||
.markDistributed = false,
|
.markDistributed = false,
|
||||||
};
|
};
|
||||||
static DistributeObjectOps TextSearchDict_Define = {
|
static DistributeObjectOps TextSearchDict_Define = {
|
||||||
|
@ -1289,7 +1416,7 @@ static DistributeObjectOps View_Rename = {
|
||||||
static DistributeObjectOps Trigger_Rename = {
|
static DistributeObjectOps Trigger_Rename = {
|
||||||
.deparse = NULL,
|
.deparse = NULL,
|
||||||
.qualify = NULL,
|
.qualify = NULL,
|
||||||
.preprocess = PreprocessAlterTriggerRenameStmt,
|
.preprocess = NULL,
|
||||||
.operationType = DIST_OPS_ALTER,
|
.operationType = DIST_OPS_ALTER,
|
||||||
.postprocess = PostprocessAlterTriggerRenameStmt,
|
.postprocess = PostprocessAlterTriggerRenameStmt,
|
||||||
.address = NULL,
|
.address = NULL,
|
||||||
|
@ -1311,13 +1438,27 @@ GetDistributeObjectOps(Node *node)
|
||||||
return &Database_Alter;
|
return &Database_Alter;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if PG_VERSION_NUM >= PG_VERSION_15
|
case T_CreatedbStmt:
|
||||||
|
{
|
||||||
|
return &Database_Create;
|
||||||
|
}
|
||||||
|
|
||||||
|
case T_DropdbStmt:
|
||||||
|
{
|
||||||
|
return &Database_Drop;
|
||||||
|
}
|
||||||
|
|
||||||
case T_AlterDatabaseRefreshCollStmt:
|
case T_AlterDatabaseRefreshCollStmt:
|
||||||
{
|
{
|
||||||
return &Database_RefreshColl;
|
return &Database_RefreshColl;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
case T_AlterDatabaseSetStmt:
|
||||||
|
{
|
||||||
|
return &Database_Set;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
case T_AlterDomainStmt:
|
case T_AlterDomainStmt:
|
||||||
{
|
{
|
||||||
return &Domain_Alter;
|
return &Domain_Alter;
|
||||||
|
@ -1602,7 +1743,6 @@ GetDistributeObjectOps(Node *node)
|
||||||
|
|
||||||
case OBJECT_SEQUENCE:
|
case OBJECT_SEQUENCE:
|
||||||
{
|
{
|
||||||
#if (PG_VERSION_NUM >= PG_VERSION_15)
|
|
||||||
ListCell *cmdCell = NULL;
|
ListCell *cmdCell = NULL;
|
||||||
foreach(cmdCell, stmt->cmds)
|
foreach(cmdCell, stmt->cmds)
|
||||||
{
|
{
|
||||||
|
@ -1630,7 +1770,6 @@ GetDistributeObjectOps(Node *node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Prior to PG15, the only Alter Table statement
|
* Prior to PG15, the only Alter Table statement
|
||||||
|
@ -1687,6 +1826,16 @@ GetDistributeObjectOps(Node *node)
|
||||||
return &TextSearchDict_Comment;
|
return &TextSearchDict_Comment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case OBJECT_DATABASE:
|
||||||
|
{
|
||||||
|
return &Database_Comment;
|
||||||
|
}
|
||||||
|
|
||||||
|
case OBJECT_ROLE:
|
||||||
|
{
|
||||||
|
return &Role_Comment;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
return &NoDistributeOps;
|
return &NoDistributeOps;
|
||||||
|
@ -1796,6 +1945,11 @@ GetDistributeObjectOps(Node *node)
|
||||||
return &Any_DropOwned;
|
return &Any_DropOwned;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case T_ReassignOwnedStmt:
|
||||||
|
{
|
||||||
|
return &Any_ReassignOwned;
|
||||||
|
}
|
||||||
|
|
||||||
case T_DropStmt:
|
case T_DropStmt:
|
||||||
{
|
{
|
||||||
DropStmt *stmt = castNode(DropStmt, node);
|
DropStmt *stmt = castNode(DropStmt, node);
|
||||||
|
@ -1990,6 +2144,31 @@ GetDistributeObjectOps(Node *node)
|
||||||
return &Vacuum_Analyze;
|
return &Vacuum_Analyze;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case T_SecLabelStmt:
|
||||||
|
{
|
||||||
|
SecLabelStmt *stmt = castNode(SecLabelStmt, node);
|
||||||
|
switch (stmt->objtype)
|
||||||
|
{
|
||||||
|
case OBJECT_ROLE:
|
||||||
|
{
|
||||||
|
return &Role_SecLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
case OBJECT_TABLE:
|
||||||
|
{
|
||||||
|
return &Table_SecLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
case OBJECT_COLUMN:
|
||||||
|
{
|
||||||
|
return &Column_SecLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return &Any_SecLabel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
case T_RenameStmt:
|
case T_RenameStmt:
|
||||||
{
|
{
|
||||||
RenameStmt *stmt = castNode(RenameStmt, node);
|
RenameStmt *stmt = castNode(RenameStmt, node);
|
||||||
|
@ -2010,6 +2189,11 @@ GetDistributeObjectOps(Node *node)
|
||||||
return &Collation_Rename;
|
return &Collation_Rename;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case OBJECT_DATABASE:
|
||||||
|
{
|
||||||
|
return &Database_Rename;
|
||||||
|
}
|
||||||
|
|
||||||
case OBJECT_DOMAIN:
|
case OBJECT_DOMAIN:
|
||||||
{
|
{
|
||||||
return &Domain_Rename;
|
return &Domain_Rename;
|
||||||
|
@ -2040,6 +2224,11 @@ GetDistributeObjectOps(Node *node)
|
||||||
return &Publication_Rename;
|
return &Publication_Rename;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case OBJECT_ROLE:
|
||||||
|
{
|
||||||
|
return &Any_AlterRoleRename;
|
||||||
|
}
|
||||||
|
|
||||||
case OBJECT_ROUTINE:
|
case OBJECT_ROUTINE:
|
||||||
{
|
{
|
||||||
return &Routine_Rename;
|
return &Routine_Rename;
|
||||||
|
|
|
@ -210,7 +210,7 @@ MakeCollateClauseFromOid(Oid collationOid)
|
||||||
getObjectIdentityParts(&collateAddress, &objName, &objArgs, false);
|
getObjectIdentityParts(&collateAddress, &objName, &objArgs, false);
|
||||||
|
|
||||||
char *name = NULL;
|
char *name = NULL;
|
||||||
foreach_ptr(name, objName)
|
foreach_declared_ptr(name, objName)
|
||||||
{
|
{
|
||||||
collateClause->collname = lappend(collateClause->collname, makeString(name));
|
collateClause->collname = lappend(collateClause->collname, makeString(name));
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,20 +9,21 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
|
|
||||||
|
#include "utils/builtins.h"
|
||||||
|
#include "utils/lsyscache.h"
|
||||||
|
|
||||||
#include "distributed/colocation_utils.h"
|
#include "distributed/colocation_utils.h"
|
||||||
#include "distributed/commands/utility_hook.h"
|
|
||||||
#include "distributed/commands.h"
|
#include "distributed/commands.h"
|
||||||
#include "distributed/metadata_utility.h"
|
#include "distributed/commands/utility_hook.h"
|
||||||
#include "distributed/coordinator_protocol.h"
|
#include "distributed/coordinator_protocol.h"
|
||||||
#include "distributed/metadata_sync.h"
|
#include "distributed/metadata_sync.h"
|
||||||
|
#include "distributed/metadata_utility.h"
|
||||||
#include "distributed/multi_partitioning_utils.h"
|
#include "distributed/multi_partitioning_utils.h"
|
||||||
#include "distributed/tenant_schema_metadata.h"
|
#include "distributed/tenant_schema_metadata.h"
|
||||||
#include "distributed/worker_transaction.h"
|
#include "distributed/worker_transaction.h"
|
||||||
#include "utils/builtins.h"
|
|
||||||
#include "utils/lsyscache.h"
|
|
||||||
|
|
||||||
|
|
||||||
/* local function forward declarations */
|
/* local function forward declarations */
|
||||||
|
|
|
@ -12,32 +12,35 @@
|
||||||
|
|
||||||
#include "access/genam.h"
|
#include "access/genam.h"
|
||||||
#include "access/xact.h"
|
#include "access/xact.h"
|
||||||
#include "citus_version.h"
|
|
||||||
#include "catalog/dependency.h"
|
#include "catalog/dependency.h"
|
||||||
#include "catalog/pg_depend.h"
|
#include "catalog/pg_depend.h"
|
||||||
#include "catalog/pg_extension_d.h"
|
#include "catalog/pg_extension_d.h"
|
||||||
#include "columnar/columnar.h"
|
|
||||||
#include "catalog/pg_foreign_data_wrapper.h"
|
#include "catalog/pg_foreign_data_wrapper.h"
|
||||||
#include "commands/defrem.h"
|
#include "commands/defrem.h"
|
||||||
#include "commands/extension.h"
|
#include "commands/extension.h"
|
||||||
|
#include "foreign/foreign.h"
|
||||||
|
#include "nodes/makefuncs.h"
|
||||||
|
#include "utils/builtins.h"
|
||||||
|
#include "utils/fmgroids.h"
|
||||||
|
#include "utils/lsyscache.h"
|
||||||
|
#include "utils/syscache.h"
|
||||||
|
|
||||||
|
#include "citus_version.h"
|
||||||
|
|
||||||
|
#include "columnar/columnar.h"
|
||||||
|
|
||||||
#include "distributed/citus_ruleutils.h"
|
#include "distributed/citus_ruleutils.h"
|
||||||
#include "distributed/commands.h"
|
#include "distributed/commands.h"
|
||||||
#include "distributed/commands/utility_hook.h"
|
#include "distributed/commands/utility_hook.h"
|
||||||
|
#include "distributed/coordinator_protocol.h"
|
||||||
#include "distributed/deparser.h"
|
#include "distributed/deparser.h"
|
||||||
#include "distributed/listutils.h"
|
#include "distributed/listutils.h"
|
||||||
#include "distributed/coordinator_protocol.h"
|
|
||||||
#include "distributed/metadata_sync.h"
|
|
||||||
#include "distributed/metadata/dependency.h"
|
#include "distributed/metadata/dependency.h"
|
||||||
#include "distributed/metadata/distobject.h"
|
#include "distributed/metadata/distobject.h"
|
||||||
|
#include "distributed/metadata_sync.h"
|
||||||
#include "distributed/multi_executor.h"
|
#include "distributed/multi_executor.h"
|
||||||
#include "distributed/relation_access_tracking.h"
|
#include "distributed/relation_access_tracking.h"
|
||||||
#include "distributed/transaction_management.h"
|
#include "distributed/transaction_management.h"
|
||||||
#include "foreign/foreign.h"
|
|
||||||
#include "nodes/makefuncs.h"
|
|
||||||
#include "utils/lsyscache.h"
|
|
||||||
#include "utils/builtins.h"
|
|
||||||
#include "utils/fmgroids.h"
|
|
||||||
#include "utils/syscache.h"
|
|
||||||
|
|
||||||
|
|
||||||
/* Local functions forward declarations for helper functions */
|
/* Local functions forward declarations for helper functions */
|
||||||
|
@ -271,7 +274,7 @@ PreprocessDropExtensionStmt(Node *node, const char *queryString,
|
||||||
|
|
||||||
/* unmark each distributed extension */
|
/* unmark each distributed extension */
|
||||||
ObjectAddress *address = NULL;
|
ObjectAddress *address = NULL;
|
||||||
foreach_ptr(address, distributedExtensionAddresses)
|
foreach_declared_ptr(address, distributedExtensionAddresses)
|
||||||
{
|
{
|
||||||
UnmarkObjectDistributed(address);
|
UnmarkObjectDistributed(address);
|
||||||
}
|
}
|
||||||
|
@ -310,7 +313,7 @@ FilterDistributedExtensions(List *extensionObjectList)
|
||||||
List *extensionNameList = NIL;
|
List *extensionNameList = NIL;
|
||||||
|
|
||||||
String *objectName = NULL;
|
String *objectName = NULL;
|
||||||
foreach_ptr(objectName, extensionObjectList)
|
foreach_declared_ptr(objectName, extensionObjectList)
|
||||||
{
|
{
|
||||||
const char *extensionName = strVal(objectName);
|
const char *extensionName = strVal(objectName);
|
||||||
const bool missingOk = true;
|
const bool missingOk = true;
|
||||||
|
@ -348,7 +351,7 @@ ExtensionNameListToObjectAddressList(List *extensionObjectList)
|
||||||
List *extensionObjectAddressList = NIL;
|
List *extensionObjectAddressList = NIL;
|
||||||
|
|
||||||
String *objectName;
|
String *objectName;
|
||||||
foreach_ptr(objectName, extensionObjectList)
|
foreach_declared_ptr(objectName, extensionObjectList)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* We set missingOk to false as we assume all the objects in
|
* We set missingOk to false as we assume all the objects in
|
||||||
|
@ -524,7 +527,7 @@ MarkExistingObjectDependenciesDistributedIfSupported()
|
||||||
List *citusTableIdList = CitusTableTypeIdList(ANY_CITUS_TABLE_TYPE);
|
List *citusTableIdList = CitusTableTypeIdList(ANY_CITUS_TABLE_TYPE);
|
||||||
|
|
||||||
Oid citusTableId = InvalidOid;
|
Oid citusTableId = InvalidOid;
|
||||||
foreach_oid(citusTableId, citusTableIdList)
|
foreach_declared_oid(citusTableId, citusTableIdList)
|
||||||
{
|
{
|
||||||
if (!ShouldMarkRelationDistributed(citusTableId))
|
if (!ShouldMarkRelationDistributed(citusTableId))
|
||||||
{
|
{
|
||||||
|
@ -568,7 +571,7 @@ MarkExistingObjectDependenciesDistributedIfSupported()
|
||||||
*/
|
*/
|
||||||
List *viewList = GetAllViews();
|
List *viewList = GetAllViews();
|
||||||
Oid viewOid = InvalidOid;
|
Oid viewOid = InvalidOid;
|
||||||
foreach_oid(viewOid, viewList)
|
foreach_declared_oid(viewOid, viewList)
|
||||||
{
|
{
|
||||||
if (!ShouldMarkRelationDistributed(viewOid))
|
if (!ShouldMarkRelationDistributed(viewOid))
|
||||||
{
|
{
|
||||||
|
@ -602,7 +605,7 @@ MarkExistingObjectDependenciesDistributedIfSupported()
|
||||||
List *distributedObjectAddressList = GetDistributedObjectAddressList();
|
List *distributedObjectAddressList = GetDistributedObjectAddressList();
|
||||||
|
|
||||||
ObjectAddress *distributedObjectAddress = NULL;
|
ObjectAddress *distributedObjectAddress = NULL;
|
||||||
foreach_ptr(distributedObjectAddress, distributedObjectAddressList)
|
foreach_declared_ptr(distributedObjectAddress, distributedObjectAddressList)
|
||||||
{
|
{
|
||||||
List *distributableDependencyObjectAddresses =
|
List *distributableDependencyObjectAddresses =
|
||||||
GetDistributableDependenciesForObject(distributedObjectAddress);
|
GetDistributableDependenciesForObject(distributedObjectAddress);
|
||||||
|
@ -624,7 +627,7 @@ MarkExistingObjectDependenciesDistributedIfSupported()
|
||||||
SetLocalEnableMetadataSync(false);
|
SetLocalEnableMetadataSync(false);
|
||||||
|
|
||||||
ObjectAddress *objectAddress = NULL;
|
ObjectAddress *objectAddress = NULL;
|
||||||
foreach_ptr(objectAddress, uniqueObjectAddresses)
|
foreach_declared_ptr(objectAddress, uniqueObjectAddresses)
|
||||||
{
|
{
|
||||||
MarkObjectDistributed(objectAddress);
|
MarkObjectDistributed(objectAddress);
|
||||||
}
|
}
|
||||||
|
@ -773,7 +776,7 @@ PreprocessCreateExtensionStmtForCitusColumnar(Node *parsetree)
|
||||||
/*create extension citus version xxx*/
|
/*create extension citus version xxx*/
|
||||||
if (newVersionValue)
|
if (newVersionValue)
|
||||||
{
|
{
|
||||||
char *newVersion = strdup(defGetString(newVersionValue));
|
char *newVersion = pstrdup(defGetString(newVersionValue));
|
||||||
versionNumber = GetExtensionVersionNumber(newVersion);
|
versionNumber = GetExtensionVersionNumber(newVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -793,7 +796,7 @@ PreprocessCreateExtensionStmtForCitusColumnar(Node *parsetree)
|
||||||
Oid citusOid = get_extension_oid("citus", true);
|
Oid citusOid = get_extension_oid("citus", true);
|
||||||
if (citusOid != InvalidOid)
|
if (citusOid != InvalidOid)
|
||||||
{
|
{
|
||||||
char *curCitusVersion = strdup(get_extension_version(citusOid));
|
char *curCitusVersion = pstrdup(get_extension_version(citusOid));
|
||||||
int curCitusVersionNum = GetExtensionVersionNumber(curCitusVersion);
|
int curCitusVersionNum = GetExtensionVersionNumber(curCitusVersion);
|
||||||
if (curCitusVersionNum < 1110)
|
if (curCitusVersionNum < 1110)
|
||||||
{
|
{
|
||||||
|
@ -828,7 +831,7 @@ IsDropCitusExtensionStmt(Node *parseTree)
|
||||||
|
|
||||||
/* now that we have a DropStmt, check if citus extension is among the objects to dropped */
|
/* now that we have a DropStmt, check if citus extension is among the objects to dropped */
|
||||||
String *objectName;
|
String *objectName;
|
||||||
foreach_ptr(objectName, dropStmt->objects)
|
foreach_declared_ptr(objectName, dropStmt->objects)
|
||||||
{
|
{
|
||||||
const char *extensionName = strVal(objectName);
|
const char *extensionName = strVal(objectName);
|
||||||
|
|
||||||
|
@ -888,7 +891,7 @@ PreprocessAlterExtensionCitusStmtForCitusColumnar(Node *parseTree)
|
||||||
if (newVersionValue)
|
if (newVersionValue)
|
||||||
{
|
{
|
||||||
char *newVersion = defGetString(newVersionValue);
|
char *newVersion = defGetString(newVersionValue);
|
||||||
double newVersionNumber = GetExtensionVersionNumber(strdup(newVersion));
|
double newVersionNumber = GetExtensionVersionNumber(pstrdup(newVersion));
|
||||||
|
|
||||||
/*alter extension citus update to version >= 11.1-1, and no citus_columnar installed */
|
/*alter extension citus update to version >= 11.1-1, and no citus_columnar installed */
|
||||||
if (newVersionNumber >= 1110 && citusColumnarOid == InvalidOid)
|
if (newVersionNumber >= 1110 && citusColumnarOid == InvalidOid)
|
||||||
|
@ -932,7 +935,7 @@ PostprocessAlterExtensionCitusStmtForCitusColumnar(Node *parseTree)
|
||||||
if (newVersionValue)
|
if (newVersionValue)
|
||||||
{
|
{
|
||||||
char *newVersion = defGetString(newVersionValue);
|
char *newVersion = defGetString(newVersionValue);
|
||||||
double newVersionNumber = GetExtensionVersionNumber(strdup(newVersion));
|
double newVersionNumber = GetExtensionVersionNumber(pstrdup(newVersion));
|
||||||
if (newVersionNumber >= 1110 && citusColumnarOid != InvalidOid)
|
if (newVersionNumber >= 1110 && citusColumnarOid != InvalidOid)
|
||||||
{
|
{
|
||||||
/*upgrade citus, after "ALTER EXTENSION citus update to xxx" updates citus_columnar Y to version Z. */
|
/*upgrade citus, after "ALTER EXTENSION citus update to xxx" updates citus_columnar Y to version Z. */
|
||||||
|
@ -1058,7 +1061,7 @@ GenerateGrantCommandsOnExtensionDependentFDWs(Oid extensionId)
|
||||||
List *FDWOids = GetDependentFDWsToExtension(extensionId);
|
List *FDWOids = GetDependentFDWsToExtension(extensionId);
|
||||||
|
|
||||||
Oid FDWOid = InvalidOid;
|
Oid FDWOid = InvalidOid;
|
||||||
foreach_oid(FDWOid, FDWOids)
|
foreach_declared_oid(FDWOid, FDWOids)
|
||||||
{
|
{
|
||||||
Acl *aclEntry = GetPrivilegesForFDW(FDWOid);
|
Acl *aclEntry = GetPrivilegesForFDW(FDWOid);
|
||||||
|
|
||||||
|
@ -1090,33 +1093,26 @@ List *
|
||||||
GetDependentFDWsToExtension(Oid extensionId)
|
GetDependentFDWsToExtension(Oid extensionId)
|
||||||
{
|
{
|
||||||
List *extensionFDWs = NIL;
|
List *extensionFDWs = NIL;
|
||||||
ScanKeyData key[3];
|
ScanKeyData key[1];
|
||||||
int scanKeyCount = 3;
|
|
||||||
HeapTuple tup;
|
HeapTuple tup;
|
||||||
|
|
||||||
Relation pgDepend = table_open(DependRelationId, AccessShareLock);
|
Relation pgDepend = table_open(DependRelationId, AccessShareLock);
|
||||||
|
|
||||||
ScanKeyInit(&key[0],
|
ScanKeyInit(&key[0],
|
||||||
Anum_pg_depend_refclassid,
|
|
||||||
BTEqualStrategyNumber, F_OIDEQ,
|
|
||||||
ObjectIdGetDatum(ExtensionRelationId));
|
|
||||||
ScanKeyInit(&key[1],
|
|
||||||
Anum_pg_depend_refobjid,
|
|
||||||
BTEqualStrategyNumber, F_OIDEQ,
|
|
||||||
ObjectIdGetDatum(extensionId));
|
|
||||||
ScanKeyInit(&key[2],
|
|
||||||
Anum_pg_depend_classid,
|
Anum_pg_depend_classid,
|
||||||
BTEqualStrategyNumber, F_OIDEQ,
|
BTEqualStrategyNumber, F_OIDEQ,
|
||||||
ObjectIdGetDatum(ForeignDataWrapperRelationId));
|
ObjectIdGetDatum(ForeignDataWrapperRelationId));
|
||||||
|
|
||||||
SysScanDesc scan = systable_beginscan(pgDepend, InvalidOid, false,
|
SysScanDesc scan = systable_beginscan(pgDepend, DependDependerIndexId, true,
|
||||||
NULL, scanKeyCount, key);
|
NULL, lengthof(key), key);
|
||||||
|
|
||||||
while (HeapTupleIsValid(tup = systable_getnext(scan)))
|
while (HeapTupleIsValid(tup = systable_getnext(scan)))
|
||||||
{
|
{
|
||||||
Form_pg_depend pgDependEntry = (Form_pg_depend) GETSTRUCT(tup);
|
Form_pg_depend pgDependEntry = (Form_pg_depend) GETSTRUCT(tup);
|
||||||
|
|
||||||
if (pgDependEntry->deptype == DEPENDENCY_EXTENSION)
|
if (pgDependEntry->deptype == DEPENDENCY_EXTENSION &&
|
||||||
|
pgDependEntry->refclassid == ExtensionRelationId &&
|
||||||
|
pgDependEntry->refobjid == extensionId)
|
||||||
{
|
{
|
||||||
extensionFDWs = lappend_oid(extensionFDWs, pgDependEntry->objid);
|
extensionFDWs = lappend_oid(extensionFDWs, pgDependEntry->objid);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,27 +12,16 @@
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
#include "distributed/pg_version_constants.h"
|
#include "miscadmin.h"
|
||||||
|
|
||||||
|
#include "access/genam.h"
|
||||||
#include "access/htup_details.h"
|
#include "access/htup_details.h"
|
||||||
#include "access/sysattr.h"
|
#include "access/sysattr.h"
|
||||||
#include "access/xact.h"
|
#include "access/xact.h"
|
||||||
#include "catalog/namespace.h"
|
#include "catalog/namespace.h"
|
||||||
#include "catalog/pg_constraint.h"
|
#include "catalog/pg_constraint.h"
|
||||||
#include "access/genam.h"
|
#include "catalog/pg_depend.h"
|
||||||
#include "catalog/pg_type.h"
|
#include "catalog/pg_type.h"
|
||||||
#include "distributed/colocation_utils.h"
|
|
||||||
#include "distributed/commands.h"
|
|
||||||
#include "distributed/commands/sequence.h"
|
|
||||||
#include "distributed/coordinator_protocol.h"
|
|
||||||
#include "distributed/listutils.h"
|
|
||||||
#include "distributed/coordinator_protocol.h"
|
|
||||||
#include "distributed/multi_join_order.h"
|
|
||||||
#include "distributed/namespace_utils.h"
|
|
||||||
#include "distributed/reference_table_utils.h"
|
|
||||||
#include "distributed/utils/array_type.h"
|
|
||||||
#include "distributed/version_compat.h"
|
|
||||||
#include "miscadmin.h"
|
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "utils/fmgroids.h"
|
#include "utils/fmgroids.h"
|
||||||
#include "utils/inval.h"
|
#include "utils/inval.h"
|
||||||
|
@ -42,6 +31,20 @@
|
||||||
#include "utils/ruleutils.h"
|
#include "utils/ruleutils.h"
|
||||||
#include "utils/syscache.h"
|
#include "utils/syscache.h"
|
||||||
|
|
||||||
|
#include "pg_version_constants.h"
|
||||||
|
|
||||||
|
#include "distributed/colocation_utils.h"
|
||||||
|
#include "distributed/commands.h"
|
||||||
|
#include "distributed/commands/sequence.h"
|
||||||
|
#include "distributed/coordinator_protocol.h"
|
||||||
|
#include "distributed/hash_helpers.h"
|
||||||
|
#include "distributed/listutils.h"
|
||||||
|
#include "distributed/multi_join_order.h"
|
||||||
|
#include "distributed/namespace_utils.h"
|
||||||
|
#include "distributed/reference_table_utils.h"
|
||||||
|
#include "distributed/utils/array_type.h"
|
||||||
|
#include "distributed/version_compat.h"
|
||||||
|
|
||||||
|
|
||||||
#define BehaviorIsRestrictOrNoAction(x) \
|
#define BehaviorIsRestrictOrNoAction(x) \
|
||||||
((x) == FKCONSTR_ACTION_NOACTION || (x) == FKCONSTR_ACTION_RESTRICT)
|
((x) == FKCONSTR_ACTION_NOACTION || (x) == FKCONSTR_ACTION_RESTRICT)
|
||||||
|
@ -199,7 +202,7 @@ ErrorIfUnsupportedForeignConstraintExists(Relation relation, char referencingDis
|
||||||
List *foreignKeyOids = GetForeignKeyOids(referencingTableId, flags);
|
List *foreignKeyOids = GetForeignKeyOids(referencingTableId, flags);
|
||||||
|
|
||||||
Oid foreignKeyOid = InvalidOid;
|
Oid foreignKeyOid = InvalidOid;
|
||||||
foreach_oid(foreignKeyOid, foreignKeyOids)
|
foreach_declared_oid(foreignKeyOid, foreignKeyOids)
|
||||||
{
|
{
|
||||||
HeapTuple heapTuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(foreignKeyOid));
|
HeapTuple heapTuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(foreignKeyOid));
|
||||||
|
|
||||||
|
@ -411,7 +414,7 @@ ForeignKeySetsNextValColumnToDefault(HeapTuple pgConstraintTuple)
|
||||||
|
|
||||||
List *setDefaultAttrs = ForeignKeyGetDefaultingAttrs(pgConstraintTuple);
|
List *setDefaultAttrs = ForeignKeyGetDefaultingAttrs(pgConstraintTuple);
|
||||||
AttrNumber setDefaultAttr = InvalidAttrNumber;
|
AttrNumber setDefaultAttr = InvalidAttrNumber;
|
||||||
foreach_int(setDefaultAttr, setDefaultAttrs)
|
foreach_declared_int(setDefaultAttr, setDefaultAttrs)
|
||||||
{
|
{
|
||||||
if (ColumnDefaultsToNextVal(pgConstraintForm->conrelid, setDefaultAttr))
|
if (ColumnDefaultsToNextVal(pgConstraintForm->conrelid, setDefaultAttr))
|
||||||
{
|
{
|
||||||
|
@ -464,7 +467,6 @@ ForeignKeyGetDefaultingAttrs(HeapTuple pgConstraintTuple)
|
||||||
}
|
}
|
||||||
|
|
||||||
List *onDeleteSetDefColumnList = NIL;
|
List *onDeleteSetDefColumnList = NIL;
|
||||||
#if PG_VERSION_NUM >= PG_VERSION_15
|
|
||||||
Datum onDeleteSetDefColumnsDatum = SysCacheGetAttr(CONSTROID, pgConstraintTuple,
|
Datum onDeleteSetDefColumnsDatum = SysCacheGetAttr(CONSTROID, pgConstraintTuple,
|
||||||
Anum_pg_constraint_confdelsetcols,
|
Anum_pg_constraint_confdelsetcols,
|
||||||
&isNull);
|
&isNull);
|
||||||
|
@ -479,7 +481,6 @@ ForeignKeyGetDefaultingAttrs(HeapTuple pgConstraintTuple)
|
||||||
onDeleteSetDefColumnList =
|
onDeleteSetDefColumnList =
|
||||||
IntegerArrayTypeToList(DatumGetArrayTypeP(onDeleteSetDefColumnsDatum));
|
IntegerArrayTypeToList(DatumGetArrayTypeP(onDeleteSetDefColumnsDatum));
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
if (list_length(onDeleteSetDefColumnList) == 0)
|
if (list_length(onDeleteSetDefColumnList) == 0)
|
||||||
{
|
{
|
||||||
|
@ -724,7 +725,7 @@ ColumnAppearsInForeignKeyToReferenceTable(char *columnName, Oid relationId)
|
||||||
GetForeignKeyIdsForColumn(columnName, relationId, searchForeignKeyColumnFlags);
|
GetForeignKeyIdsForColumn(columnName, relationId, searchForeignKeyColumnFlags);
|
||||||
|
|
||||||
Oid foreignKeyId = InvalidOid;
|
Oid foreignKeyId = InvalidOid;
|
||||||
foreach_oid(foreignKeyId, foreignKeyIdsColumnAppeared)
|
foreach_declared_oid(foreignKeyId, foreignKeyIdsColumnAppeared)
|
||||||
{
|
{
|
||||||
Oid referencedTableId = GetReferencedTableId(foreignKeyId);
|
Oid referencedTableId = GetReferencedTableId(foreignKeyId);
|
||||||
if (IsCitusTableType(referencedTableId, REFERENCE_TABLE))
|
if (IsCitusTableType(referencedTableId, REFERENCE_TABLE))
|
||||||
|
@ -898,7 +899,7 @@ GetForeignConstraintCommandsInternal(Oid relationId, int flags)
|
||||||
int saveNestLevel = PushEmptySearchPath();
|
int saveNestLevel = PushEmptySearchPath();
|
||||||
|
|
||||||
Oid foreignKeyOid = InvalidOid;
|
Oid foreignKeyOid = InvalidOid;
|
||||||
foreach_oid(foreignKeyOid, foreignKeyOids)
|
foreach_declared_oid(foreignKeyOid, foreignKeyOids)
|
||||||
{
|
{
|
||||||
char *statementDef = pg_get_constraintdef_command(foreignKeyOid);
|
char *statementDef = pg_get_constraintdef_command(foreignKeyOid);
|
||||||
|
|
||||||
|
@ -1154,7 +1155,7 @@ static Oid
|
||||||
FindForeignKeyOidWithName(List *foreignKeyOids, const char *inputConstraintName)
|
FindForeignKeyOidWithName(List *foreignKeyOids, const char *inputConstraintName)
|
||||||
{
|
{
|
||||||
Oid foreignKeyOid = InvalidOid;
|
Oid foreignKeyOid = InvalidOid;
|
||||||
foreach_oid(foreignKeyOid, foreignKeyOids)
|
foreach_declared_oid(foreignKeyOid, foreignKeyOids)
|
||||||
{
|
{
|
||||||
char *constraintName = get_constraint_name(foreignKeyOid);
|
char *constraintName = get_constraint_name(foreignKeyOid);
|
||||||
|
|
||||||
|
@ -1197,6 +1198,114 @@ TableHasExternalForeignKeys(Oid relationId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ForeignConstraintMatchesFlags is a function with logic that's very specific
|
||||||
|
* to GetForeignKeyOids. There's no reason to use it in any other context.
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
ForeignConstraintMatchesFlags(Form_pg_constraint constraintForm,
|
||||||
|
int flags)
|
||||||
|
{
|
||||||
|
if (constraintForm->contype != CONSTRAINT_FOREIGN)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool inheritedConstraint = OidIsValid(constraintForm->conparentid);
|
||||||
|
if (inheritedConstraint)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* We only consider the constraints that are explicitly created on
|
||||||
|
* the table as we already process the constraints from parent tables
|
||||||
|
* implicitly when a command is issued
|
||||||
|
*/
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool excludeSelfReference = (flags & EXCLUDE_SELF_REFERENCES);
|
||||||
|
bool isSelfReference = (constraintForm->conrelid == constraintForm->confrelid);
|
||||||
|
if (excludeSelfReference && isSelfReference)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Oid otherTableId = InvalidOid;
|
||||||
|
if (flags & INCLUDE_REFERENCING_CONSTRAINTS)
|
||||||
|
{
|
||||||
|
otherTableId = constraintForm->confrelid;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
otherTableId = constraintForm->conrelid;
|
||||||
|
}
|
||||||
|
|
||||||
|
return IsTableTypeIncluded(otherTableId, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GetForeignKeyOidsForReferencedTable returns a list of foreign key OIDs that
|
||||||
|
* reference the relationId and match the given flags.
|
||||||
|
*
|
||||||
|
* This is separated from GetForeignKeyOids because we need to scan pg_depend
|
||||||
|
* instead of pg_constraint directly. The reason for this is that there is no
|
||||||
|
* index on the confrelid of pg_constraint, so searching by that column
|
||||||
|
* requires a seqscan.
|
||||||
|
*/
|
||||||
|
static List *
|
||||||
|
GetForeignKeyOidsForReferencedTable(Oid relationId, int flags)
|
||||||
|
{
|
||||||
|
HTAB *foreignKeyOidsSet = CreateSimpleHashSetWithName(
|
||||||
|
Oid, "ReferencingForeignKeyOidsSet");
|
||||||
|
List *foreignKeyOidsList = NIL;
|
||||||
|
ScanKeyData key[2];
|
||||||
|
HeapTuple dependTup;
|
||||||
|
Relation depRel = table_open(DependRelationId, AccessShareLock);
|
||||||
|
|
||||||
|
ScanKeyInit(&key[0],
|
||||||
|
Anum_pg_depend_refclassid,
|
||||||
|
BTEqualStrategyNumber, F_OIDEQ,
|
||||||
|
ObjectIdGetDatum(RelationRelationId));
|
||||||
|
ScanKeyInit(&key[1],
|
||||||
|
Anum_pg_depend_refobjid,
|
||||||
|
BTEqualStrategyNumber, F_OIDEQ,
|
||||||
|
ObjectIdGetDatum(relationId));
|
||||||
|
SysScanDesc scan = systable_beginscan(depRel, DependReferenceIndexId, true,
|
||||||
|
NULL, lengthof(key), key);
|
||||||
|
while (HeapTupleIsValid(dependTup = systable_getnext(scan)))
|
||||||
|
{
|
||||||
|
Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(dependTup);
|
||||||
|
|
||||||
|
if (deprec->classid != ConstraintRelationId ||
|
||||||
|
deprec->deptype != DEPENDENCY_NORMAL ||
|
||||||
|
hash_search(foreignKeyOidsSet, &deprec->objid, HASH_FIND, NULL))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HeapTuple constraintTup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(
|
||||||
|
deprec->objid));
|
||||||
|
if (!HeapTupleIsValid(constraintTup)) /* can happen during DROP TABLE */
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Form_pg_constraint constraint = (Form_pg_constraint) GETSTRUCT(constraintTup);
|
||||||
|
if (constraint->confrelid == relationId &&
|
||||||
|
ForeignConstraintMatchesFlags(constraint, flags))
|
||||||
|
{
|
||||||
|
foreignKeyOidsList = lappend_oid(foreignKeyOidsList, constraint->oid);
|
||||||
|
hash_search(foreignKeyOidsSet, &constraint->oid, HASH_ENTER, NULL);
|
||||||
|
}
|
||||||
|
ReleaseSysCache(constraintTup);
|
||||||
|
}
|
||||||
|
systable_endscan(scan);
|
||||||
|
table_close(depRel, AccessShareLock);
|
||||||
|
return foreignKeyOidsList;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* GetForeignKeyOids takes in a relationId, and returns a list of OIDs for
|
* GetForeignKeyOids takes in a relationId, and returns a list of OIDs for
|
||||||
* foreign constraints that the relation with relationId is involved according
|
* foreign constraints that the relation with relationId is involved according
|
||||||
|
@ -1206,9 +1315,8 @@ TableHasExternalForeignKeys(Oid relationId)
|
||||||
List *
|
List *
|
||||||
GetForeignKeyOids(Oid relationId, int flags)
|
GetForeignKeyOids(Oid relationId, int flags)
|
||||||
{
|
{
|
||||||
AttrNumber pgConstraintTargetAttrNumber = InvalidAttrNumber;
|
bool extractReferencing PG_USED_FOR_ASSERTS_ONLY = (flags &
|
||||||
|
INCLUDE_REFERENCING_CONSTRAINTS);
|
||||||
bool extractReferencing = (flags & INCLUDE_REFERENCING_CONSTRAINTS);
|
|
||||||
bool extractReferenced = (flags & INCLUDE_REFERENCED_CONSTRAINTS);
|
bool extractReferenced = (flags & INCLUDE_REFERENCED_CONSTRAINTS);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1219,22 +1327,10 @@ GetForeignKeyOids(Oid relationId, int flags)
|
||||||
Assert(!(extractReferencing && extractReferenced));
|
Assert(!(extractReferencing && extractReferenced));
|
||||||
Assert(extractReferencing || extractReferenced);
|
Assert(extractReferencing || extractReferenced);
|
||||||
|
|
||||||
bool useIndex = false;
|
if (extractReferenced)
|
||||||
Oid indexOid = InvalidOid;
|
|
||||||
|
|
||||||
if (extractReferencing)
|
|
||||||
{
|
{
|
||||||
pgConstraintTargetAttrNumber = Anum_pg_constraint_conrelid;
|
return GetForeignKeyOidsForReferencedTable(relationId, flags);
|
||||||
|
|
||||||
useIndex = true;
|
|
||||||
indexOid = ConstraintRelidTypidNameIndexId;
|
|
||||||
}
|
}
|
||||||
else if (extractReferenced)
|
|
||||||
{
|
|
||||||
pgConstraintTargetAttrNumber = Anum_pg_constraint_confrelid;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool excludeSelfReference = (flags & EXCLUDE_SELF_REFERENCES);
|
|
||||||
|
|
||||||
List *foreignKeyOids = NIL;
|
List *foreignKeyOids = NIL;
|
||||||
|
|
||||||
|
@ -1242,62 +1338,22 @@ GetForeignKeyOids(Oid relationId, int flags)
|
||||||
int scanKeyCount = 1;
|
int scanKeyCount = 1;
|
||||||
|
|
||||||
Relation pgConstraint = table_open(ConstraintRelationId, AccessShareLock);
|
Relation pgConstraint = table_open(ConstraintRelationId, AccessShareLock);
|
||||||
ScanKeyInit(&scanKey[0], pgConstraintTargetAttrNumber,
|
ScanKeyInit(&scanKey[0], Anum_pg_constraint_conrelid,
|
||||||
BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(relationId));
|
BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(relationId));
|
||||||
SysScanDesc scanDescriptor = systable_beginscan(pgConstraint, indexOid, useIndex,
|
|
||||||
|
SysScanDesc scanDescriptor = systable_beginscan(pgConstraint,
|
||||||
|
ConstraintRelidTypidNameIndexId, true,
|
||||||
NULL, scanKeyCount, scanKey);
|
NULL, scanKeyCount, scanKey);
|
||||||
|
|
||||||
HeapTuple heapTuple = systable_getnext(scanDescriptor);
|
HeapTuple heapTuple;
|
||||||
while (HeapTupleIsValid(heapTuple))
|
while (HeapTupleIsValid(heapTuple = systable_getnext(scanDescriptor)))
|
||||||
{
|
{
|
||||||
Form_pg_constraint constraintForm = (Form_pg_constraint) GETSTRUCT(heapTuple);
|
Form_pg_constraint constraintForm = (Form_pg_constraint) GETSTRUCT(heapTuple);
|
||||||
|
|
||||||
if (constraintForm->contype != CONSTRAINT_FOREIGN)
|
if (ForeignConstraintMatchesFlags(constraintForm, flags))
|
||||||
{
|
{
|
||||||
heapTuple = systable_getnext(scanDescriptor);
|
foreignKeyOids = lappend_oid(foreignKeyOids, constraintForm->oid);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool inheritedConstraint = OidIsValid(constraintForm->conparentid);
|
|
||||||
if (inheritedConstraint)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* We only consider the constraints that are explicitly created on
|
|
||||||
* the table as we already process the constraints from parent tables
|
|
||||||
* implicitly when a command is issued
|
|
||||||
*/
|
|
||||||
heapTuple = systable_getnext(scanDescriptor);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Oid constraintId = constraintForm->oid;
|
|
||||||
|
|
||||||
bool isSelfReference = (constraintForm->conrelid == constraintForm->confrelid);
|
|
||||||
if (excludeSelfReference && isSelfReference)
|
|
||||||
{
|
|
||||||
heapTuple = systable_getnext(scanDescriptor);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Oid otherTableId = InvalidOid;
|
|
||||||
if (extractReferencing)
|
|
||||||
{
|
|
||||||
otherTableId = constraintForm->confrelid;
|
|
||||||
}
|
|
||||||
else if (extractReferenced)
|
|
||||||
{
|
|
||||||
otherTableId = constraintForm->conrelid;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!IsTableTypeIncluded(otherTableId, flags))
|
|
||||||
{
|
|
||||||
heapTuple = systable_getnext(scanDescriptor);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreignKeyOids = lappend_oid(foreignKeyOids, constraintId);
|
|
||||||
|
|
||||||
heapTuple = systable_getnext(scanDescriptor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
systable_endscan(scanDescriptor);
|
systable_endscan(scanDescriptor);
|
||||||
|
@ -1414,7 +1470,7 @@ RelationInvolvedInAnyNonInheritedForeignKeys(Oid relationId)
|
||||||
List *foreignKeysRelationInvolved = list_concat(referencingForeignKeys,
|
List *foreignKeysRelationInvolved = list_concat(referencingForeignKeys,
|
||||||
referencedForeignKeys);
|
referencedForeignKeys);
|
||||||
Oid foreignKeyId = InvalidOid;
|
Oid foreignKeyId = InvalidOid;
|
||||||
foreach_oid(foreignKeyId, foreignKeysRelationInvolved)
|
foreach_declared_oid(foreignKeyId, foreignKeysRelationInvolved)
|
||||||
{
|
{
|
||||||
HeapTuple heapTuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(foreignKeyId));
|
HeapTuple heapTuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(foreignKeyId));
|
||||||
if (!HeapTupleIsValid(heapTuple))
|
if (!HeapTupleIsValid(heapTuple))
|
||||||
|
|
|
@ -11,17 +11,18 @@
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
#include "catalog/pg_foreign_data_wrapper.h"
|
#include "catalog/pg_foreign_data_wrapper.h"
|
||||||
#include "distributed/commands/utility_hook.h"
|
|
||||||
#include "distributed/commands.h"
|
|
||||||
#include "distributed/deparser.h"
|
|
||||||
#include "distributed/listutils.h"
|
|
||||||
#include "distributed/metadata_sync.h"
|
|
||||||
#include "distributed/metadata/distobject.h"
|
|
||||||
#include "foreign/foreign.h"
|
#include "foreign/foreign.h"
|
||||||
#include "nodes/makefuncs.h"
|
#include "nodes/makefuncs.h"
|
||||||
#include "nodes/parsenodes.h"
|
#include "nodes/parsenodes.h"
|
||||||
#include "utils/syscache.h"
|
#include "utils/syscache.h"
|
||||||
|
|
||||||
|
#include "distributed/commands.h"
|
||||||
|
#include "distributed/commands/utility_hook.h"
|
||||||
|
#include "distributed/deparser.h"
|
||||||
|
#include "distributed/listutils.h"
|
||||||
|
#include "distributed/metadata/distobject.h"
|
||||||
|
#include "distributed/metadata_sync.h"
|
||||||
|
|
||||||
static bool NameListHasFDWOwnedByDistributedExtension(List *FDWNames);
|
static bool NameListHasFDWOwnedByDistributedExtension(List *FDWNames);
|
||||||
static ObjectAddress GetObjectAddressByFDWName(char *FDWName, bool missing_ok);
|
static ObjectAddress GetObjectAddressByFDWName(char *FDWName, bool missing_ok);
|
||||||
|
|
||||||
|
@ -85,7 +86,7 @@ static bool
|
||||||
NameListHasFDWOwnedByDistributedExtension(List *FDWNames)
|
NameListHasFDWOwnedByDistributedExtension(List *FDWNames)
|
||||||
{
|
{
|
||||||
String *FDWValue = NULL;
|
String *FDWValue = NULL;
|
||||||
foreach_ptr(FDWValue, FDWNames)
|
foreach_declared_ptr(FDWValue, FDWNames)
|
||||||
{
|
{
|
||||||
/* captures the extension address during lookup */
|
/* captures the extension address during lookup */
|
||||||
ObjectAddress *extensionAddress = palloc0(sizeof(ObjectAddress));
|
ObjectAddress *extensionAddress = palloc0(sizeof(ObjectAddress));
|
||||||
|
|
|
@ -9,11 +9,18 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
|
|
||||||
#include "catalog/pg_foreign_server.h"
|
#include "catalog/pg_foreign_server.h"
|
||||||
#include "distributed/commands/utility_hook.h"
|
#include "foreign/foreign.h"
|
||||||
|
#include "nodes/makefuncs.h"
|
||||||
|
#include "nodes/parsenodes.h"
|
||||||
|
#include "nodes/primnodes.h"
|
||||||
|
#include "utils/builtins.h"
|
||||||
|
|
||||||
#include "distributed/commands.h"
|
#include "distributed/commands.h"
|
||||||
|
#include "distributed/commands/utility_hook.h"
|
||||||
#include "distributed/deparser.h"
|
#include "distributed/deparser.h"
|
||||||
#include "distributed/listutils.h"
|
#include "distributed/listutils.h"
|
||||||
#include "distributed/log_utils.h"
|
#include "distributed/log_utils.h"
|
||||||
|
@ -21,11 +28,6 @@
|
||||||
#include "distributed/metadata_sync.h"
|
#include "distributed/metadata_sync.h"
|
||||||
#include "distributed/multi_executor.h"
|
#include "distributed/multi_executor.h"
|
||||||
#include "distributed/worker_transaction.h"
|
#include "distributed/worker_transaction.h"
|
||||||
#include "foreign/foreign.h"
|
|
||||||
#include "nodes/makefuncs.h"
|
|
||||||
#include "nodes/parsenodes.h"
|
|
||||||
#include "nodes/primnodes.h"
|
|
||||||
#include "utils/builtins.h"
|
|
||||||
|
|
||||||
static char * GetForeignServerAlterOwnerCommand(Oid serverId);
|
static char * GetForeignServerAlterOwnerCommand(Oid serverId);
|
||||||
static Node * RecreateForeignServerStmt(Oid serverId);
|
static Node * RecreateForeignServerStmt(Oid serverId);
|
||||||
|
@ -227,7 +229,7 @@ RecreateForeignServerStmt(Oid serverId)
|
||||||
|
|
||||||
int location = -1;
|
int location = -1;
|
||||||
DefElem *option = NULL;
|
DefElem *option = NULL;
|
||||||
foreach_ptr(option, server->options)
|
foreach_declared_ptr(option, server->options)
|
||||||
{
|
{
|
||||||
DefElem *copyOption = makeDefElem(option->defname, option->arg, location);
|
DefElem *copyOption = makeDefElem(option->defname, option->arg, location);
|
||||||
createStmt->options = lappend(createStmt->options, copyOption);
|
createStmt->options = lappend(createStmt->options, copyOption);
|
||||||
|
@ -245,7 +247,7 @@ static bool
|
||||||
NameListHasDistributedServer(List *serverNames)
|
NameListHasDistributedServer(List *serverNames)
|
||||||
{
|
{
|
||||||
String *serverValue = NULL;
|
String *serverValue = NULL;
|
||||||
foreach_ptr(serverValue, serverNames)
|
foreach_declared_ptr(serverValue, serverNames)
|
||||||
{
|
{
|
||||||
List *addresses = GetObjectAddressByServerName(strVal(serverValue), false);
|
List *addresses = GetObjectAddressByServerName(strVal(serverValue), false);
|
||||||
|
|
||||||
|
|
|
@ -18,43 +18,19 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
#include "miscadmin.h"
|
|
||||||
#include "funcapi.h"
|
|
||||||
|
|
||||||
#include "distributed/pg_version_constants.h"
|
#include "funcapi.h"
|
||||||
|
#include "miscadmin.h"
|
||||||
|
|
||||||
#include "access/genam.h"
|
#include "access/genam.h"
|
||||||
#include "access/htup_details.h"
|
#include "access/htup_details.h"
|
||||||
#include "access/xact.h"
|
#include "access/xact.h"
|
||||||
#include "catalog/pg_aggregate.h"
|
|
||||||
#include "catalog/dependency.h"
|
#include "catalog/dependency.h"
|
||||||
#include "catalog/namespace.h"
|
#include "catalog/namespace.h"
|
||||||
|
#include "catalog/pg_aggregate.h"
|
||||||
#include "catalog/pg_proc.h"
|
#include "catalog/pg_proc.h"
|
||||||
#include "catalog/pg_type.h"
|
#include "catalog/pg_type.h"
|
||||||
#include "commands/extension.h"
|
#include "commands/extension.h"
|
||||||
#include "distributed/citus_depended_object.h"
|
|
||||||
#include "distributed/citus_ruleutils.h"
|
|
||||||
#include "distributed/citus_safe_lib.h"
|
|
||||||
#include "distributed/colocation_utils.h"
|
|
||||||
#include "distributed/commands.h"
|
|
||||||
#include "distributed/commands/utility_hook.h"
|
|
||||||
#include "distributed/deparser.h"
|
|
||||||
#include "distributed/listutils.h"
|
|
||||||
#include "distributed/maintenanced.h"
|
|
||||||
#include "distributed/metadata_utility.h"
|
|
||||||
#include "distributed/metadata/dependency.h"
|
|
||||||
#include "distributed/coordinator_protocol.h"
|
|
||||||
#include "distributed/metadata/distobject.h"
|
|
||||||
#include "distributed/metadata/pg_dist_object.h"
|
|
||||||
#include "distributed/metadata_sync.h"
|
|
||||||
#include "distributed/multi_executor.h"
|
|
||||||
#include "distributed/namespace_utils.h"
|
|
||||||
#include "distributed/pg_dist_node.h"
|
|
||||||
#include "distributed/reference_table_utils.h"
|
|
||||||
#include "distributed/relation_access_tracking.h"
|
|
||||||
#include "distributed/version_compat.h"
|
|
||||||
#include "distributed/worker_create_or_replace.h"
|
|
||||||
#include "distributed/worker_transaction.h"
|
|
||||||
#include "nodes/makefuncs.h"
|
#include "nodes/makefuncs.h"
|
||||||
#include "parser/parse_coerce.h"
|
#include "parser/parse_coerce.h"
|
||||||
#include "parser/parse_type.h"
|
#include "parser/parse_type.h"
|
||||||
|
@ -63,8 +39,34 @@
|
||||||
#include "utils/fmgroids.h"
|
#include "utils/fmgroids.h"
|
||||||
#include "utils/fmgrprotos.h"
|
#include "utils/fmgrprotos.h"
|
||||||
#include "utils/lsyscache.h"
|
#include "utils/lsyscache.h"
|
||||||
#include "utils/syscache.h"
|
|
||||||
#include "utils/regproc.h"
|
#include "utils/regproc.h"
|
||||||
|
#include "utils/syscache.h"
|
||||||
|
|
||||||
|
#include "pg_version_constants.h"
|
||||||
|
|
||||||
|
#include "distributed/citus_depended_object.h"
|
||||||
|
#include "distributed/citus_ruleutils.h"
|
||||||
|
#include "distributed/citus_safe_lib.h"
|
||||||
|
#include "distributed/colocation_utils.h"
|
||||||
|
#include "distributed/commands.h"
|
||||||
|
#include "distributed/commands/utility_hook.h"
|
||||||
|
#include "distributed/coordinator_protocol.h"
|
||||||
|
#include "distributed/deparser.h"
|
||||||
|
#include "distributed/listutils.h"
|
||||||
|
#include "distributed/maintenanced.h"
|
||||||
|
#include "distributed/metadata/dependency.h"
|
||||||
|
#include "distributed/metadata/distobject.h"
|
||||||
|
#include "distributed/metadata/pg_dist_object.h"
|
||||||
|
#include "distributed/metadata_sync.h"
|
||||||
|
#include "distributed/metadata_utility.h"
|
||||||
|
#include "distributed/multi_executor.h"
|
||||||
|
#include "distributed/namespace_utils.h"
|
||||||
|
#include "distributed/pg_dist_node.h"
|
||||||
|
#include "distributed/reference_table_utils.h"
|
||||||
|
#include "distributed/relation_access_tracking.h"
|
||||||
|
#include "distributed/version_compat.h"
|
||||||
|
#include "distributed/worker_create_or_replace.h"
|
||||||
|
#include "distributed/worker_transaction.h"
|
||||||
|
|
||||||
#define DISABLE_LOCAL_CHECK_FUNCTION_BODIES "SET LOCAL check_function_bodies TO off;"
|
#define DISABLE_LOCAL_CHECK_FUNCTION_BODIES "SET LOCAL check_function_bodies TO off;"
|
||||||
#define RESET_CHECK_FUNCTION_BODIES "RESET check_function_bodies;"
|
#define RESET_CHECK_FUNCTION_BODIES "RESET check_function_bodies;"
|
||||||
|
@ -254,7 +256,7 @@ create_distributed_function(PG_FUNCTION_ARGS)
|
||||||
createFunctionSQL, alterFunctionOwnerSQL);
|
createFunctionSQL, alterFunctionOwnerSQL);
|
||||||
List *grantDDLCommands = GrantOnFunctionDDLCommands(funcOid);
|
List *grantDDLCommands = GrantOnFunctionDDLCommands(funcOid);
|
||||||
char *grantOnFunctionSQL = NULL;
|
char *grantOnFunctionSQL = NULL;
|
||||||
foreach_ptr(grantOnFunctionSQL, grantDDLCommands)
|
foreach_declared_ptr(grantOnFunctionSQL, grantDDLCommands)
|
||||||
{
|
{
|
||||||
appendStringInfo(&ddlCommand, ";%s", grantOnFunctionSQL);
|
appendStringInfo(&ddlCommand, ";%s", grantOnFunctionSQL);
|
||||||
}
|
}
|
||||||
|
@ -368,7 +370,7 @@ ErrorIfAnyNodeDoesNotHaveMetadata(void)
|
||||||
ActivePrimaryNonCoordinatorNodeList(ShareLock);
|
ActivePrimaryNonCoordinatorNodeList(ShareLock);
|
||||||
|
|
||||||
WorkerNode *workerNode = NULL;
|
WorkerNode *workerNode = NULL;
|
||||||
foreach_ptr(workerNode, workerNodeList)
|
foreach_declared_ptr(workerNode, workerNodeList)
|
||||||
{
|
{
|
||||||
if (!workerNode->hasMetadata)
|
if (!workerNode->hasMetadata)
|
||||||
{
|
{
|
||||||
|
@ -883,6 +885,7 @@ UpdateFunctionDistributionInfo(const ObjectAddress *distAddress,
|
||||||
|
|
||||||
char *workerPgDistObjectUpdateCommand =
|
char *workerPgDistObjectUpdateCommand =
|
||||||
MarkObjectsDistributedCreateCommand(objectAddressList,
|
MarkObjectsDistributedCreateCommand(objectAddressList,
|
||||||
|
NIL,
|
||||||
distArgumentIndexList,
|
distArgumentIndexList,
|
||||||
colocationIdList,
|
colocationIdList,
|
||||||
forceDelegationList);
|
forceDelegationList);
|
||||||
|
@ -978,7 +981,6 @@ GetAggregateDDLCommand(const RegProcedure funcOid, bool useCreateOrReplace)
|
||||||
char *argmodes = NULL;
|
char *argmodes = NULL;
|
||||||
int insertorderbyat = -1;
|
int insertorderbyat = -1;
|
||||||
int argsprinted = 0;
|
int argsprinted = 0;
|
||||||
int inputargno = 0;
|
|
||||||
|
|
||||||
HeapTuple proctup = SearchSysCache1(PROCOID, funcOid);
|
HeapTuple proctup = SearchSysCache1(PROCOID, funcOid);
|
||||||
if (!HeapTupleIsValid(proctup))
|
if (!HeapTupleIsValid(proctup))
|
||||||
|
@ -1058,7 +1060,6 @@ GetAggregateDDLCommand(const RegProcedure funcOid, bool useCreateOrReplace)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inputargno++; /* this is a 1-based counter */
|
|
||||||
if (argsprinted == insertorderbyat)
|
if (argsprinted == insertorderbyat)
|
||||||
{
|
{
|
||||||
appendStringInfoString(&buf, " ORDER BY ");
|
appendStringInfoString(&buf, " ORDER BY ");
|
||||||
|
@ -1475,7 +1476,7 @@ CreateFunctionStmtObjectAddress(Node *node, bool missing_ok, bool isPostprocess)
|
||||||
objectWithArgs->objname = stmt->funcname;
|
objectWithArgs->objname = stmt->funcname;
|
||||||
|
|
||||||
FunctionParameter *funcParam = NULL;
|
FunctionParameter *funcParam = NULL;
|
||||||
foreach_ptr(funcParam, stmt->parameters)
|
foreach_declared_ptr(funcParam, stmt->parameters)
|
||||||
{
|
{
|
||||||
if (ShouldAddFunctionSignature(funcParam->mode))
|
if (ShouldAddFunctionSignature(funcParam->mode))
|
||||||
{
|
{
|
||||||
|
@ -1518,7 +1519,7 @@ DefineAggregateStmtObjectAddress(Node *node, bool missing_ok, bool isPostprocess
|
||||||
if (stmt->args != NIL)
|
if (stmt->args != NIL)
|
||||||
{
|
{
|
||||||
FunctionParameter *funcParam = NULL;
|
FunctionParameter *funcParam = NULL;
|
||||||
foreach_ptr(funcParam, linitial(stmt->args))
|
foreach_declared_ptr(funcParam, linitial(stmt->args))
|
||||||
{
|
{
|
||||||
objectWithArgs->objargs = lappend(objectWithArgs->objargs,
|
objectWithArgs->objargs = lappend(objectWithArgs->objargs,
|
||||||
funcParam->argType);
|
funcParam->argType);
|
||||||
|
@ -1527,7 +1528,7 @@ DefineAggregateStmtObjectAddress(Node *node, bool missing_ok, bool isPostprocess
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DefElem *defItem = NULL;
|
DefElem *defItem = NULL;
|
||||||
foreach_ptr(defItem, stmt->definition)
|
foreach_declared_ptr(defItem, stmt->definition)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* If no explicit args are given, pg includes basetype in the signature.
|
* If no explicit args are given, pg includes basetype in the signature.
|
||||||
|
@ -1932,7 +1933,7 @@ static void
|
||||||
ErrorIfUnsupportedAlterFunctionStmt(AlterFunctionStmt *stmt)
|
ErrorIfUnsupportedAlterFunctionStmt(AlterFunctionStmt *stmt)
|
||||||
{
|
{
|
||||||
DefElem *action = NULL;
|
DefElem *action = NULL;
|
||||||
foreach_ptr(action, stmt->actions)
|
foreach_declared_ptr(action, stmt->actions)
|
||||||
{
|
{
|
||||||
if (strcmp(action->defname, "set") == 0)
|
if (strcmp(action->defname, "set") == 0)
|
||||||
{
|
{
|
||||||
|
@ -2039,7 +2040,7 @@ PreprocessGrantOnFunctionStmt(Node *node, const char *queryString,
|
||||||
|
|
||||||
List *grantFunctionList = NIL;
|
List *grantFunctionList = NIL;
|
||||||
ObjectAddress *functionAddress = NULL;
|
ObjectAddress *functionAddress = NULL;
|
||||||
foreach_ptr(functionAddress, distributedFunctions)
|
foreach_declared_ptr(functionAddress, distributedFunctions)
|
||||||
{
|
{
|
||||||
ObjectWithArgs *distFunction = ObjectWithArgsFromOid(
|
ObjectWithArgs *distFunction = ObjectWithArgsFromOid(
|
||||||
functionAddress->objectId);
|
functionAddress->objectId);
|
||||||
|
@ -2082,7 +2083,7 @@ PostprocessGrantOnFunctionStmt(Node *node, const char *queryString)
|
||||||
}
|
}
|
||||||
|
|
||||||
ObjectAddress *functionAddress = NULL;
|
ObjectAddress *functionAddress = NULL;
|
||||||
foreach_ptr(functionAddress, distributedFunctions)
|
foreach_declared_ptr(functionAddress, distributedFunctions)
|
||||||
{
|
{
|
||||||
EnsureAllObjectDependenciesExistOnAllNodes(list_make1(functionAddress));
|
EnsureAllObjectDependenciesExistOnAllNodes(list_make1(functionAddress));
|
||||||
}
|
}
|
||||||
|
@ -2119,7 +2120,7 @@ FilterDistributedFunctions(GrantStmt *grantStmt)
|
||||||
|
|
||||||
/* iterate over all namespace names provided to get their oid's */
|
/* iterate over all namespace names provided to get their oid's */
|
||||||
String *namespaceValue = NULL;
|
String *namespaceValue = NULL;
|
||||||
foreach_ptr(namespaceValue, grantStmt->objects)
|
foreach_declared_ptr(namespaceValue, grantStmt->objects)
|
||||||
{
|
{
|
||||||
char *nspname = strVal(namespaceValue);
|
char *nspname = strVal(namespaceValue);
|
||||||
bool missing_ok = false;
|
bool missing_ok = false;
|
||||||
|
@ -2131,7 +2132,7 @@ FilterDistributedFunctions(GrantStmt *grantStmt)
|
||||||
* iterate over all distributed functions to filter the ones
|
* iterate over all distributed functions to filter the ones
|
||||||
* that belong to one of the namespaces from above
|
* that belong to one of the namespaces from above
|
||||||
*/
|
*/
|
||||||
foreach_ptr(distributedFunction, distributedFunctionList)
|
foreach_declared_ptr(distributedFunction, distributedFunctionList)
|
||||||
{
|
{
|
||||||
Oid namespaceOid = get_func_namespace(distributedFunction->objectId);
|
Oid namespaceOid = get_func_namespace(distributedFunction->objectId);
|
||||||
|
|
||||||
|
@ -2150,7 +2151,7 @@ FilterDistributedFunctions(GrantStmt *grantStmt)
|
||||||
{
|
{
|
||||||
bool missingOk = false;
|
bool missingOk = false;
|
||||||
ObjectWithArgs *objectWithArgs = NULL;
|
ObjectWithArgs *objectWithArgs = NULL;
|
||||||
foreach_ptr(objectWithArgs, grantStmt->objects)
|
foreach_declared_ptr(objectWithArgs, grantStmt->objects)
|
||||||
{
|
{
|
||||||
ObjectAddress *functionAddress = palloc0(sizeof(ObjectAddress));
|
ObjectAddress *functionAddress = palloc0(sizeof(ObjectAddress));
|
||||||
functionAddress->classId = ProcedureRelationId;
|
functionAddress->classId = ProcedureRelationId;
|
||||||
|
|
|
@ -10,16 +10,18 @@
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
#include "distributed/citus_ruleutils.h"
|
|
||||||
#include "distributed/commands.h"
|
|
||||||
#include "distributed/commands/utility_hook.h"
|
|
||||||
#include "distributed/metadata/distobject.h"
|
|
||||||
#include "distributed/metadata_cache.h"
|
|
||||||
#include "distributed/version_compat.h"
|
|
||||||
#include "lib/stringinfo.h"
|
#include "lib/stringinfo.h"
|
||||||
#include "nodes/parsenodes.h"
|
#include "nodes/parsenodes.h"
|
||||||
#include "utils/lsyscache.h"
|
#include "utils/lsyscache.h"
|
||||||
|
|
||||||
|
#include "distributed/citus_ruleutils.h"
|
||||||
|
#include "distributed/commands.h"
|
||||||
|
#include "distributed/commands/utility_hook.h"
|
||||||
|
#include "distributed/deparser.h"
|
||||||
|
#include "distributed/metadata/distobject.h"
|
||||||
|
#include "distributed/metadata_cache.h"
|
||||||
|
#include "distributed/version_compat.h"
|
||||||
|
|
||||||
|
|
||||||
/* Local functions forward declarations for helper functions */
|
/* Local functions forward declarations for helper functions */
|
||||||
static List * CollectGrantTableIdList(GrantStmt *grantStmt);
|
static List * CollectGrantTableIdList(GrantStmt *grantStmt);
|
||||||
|
@ -31,7 +33,6 @@ static List * CollectGrantTableIdList(GrantStmt *grantStmt);
|
||||||
* needed during the worker node portion of DDL execution before returning the
|
* needed during the worker node portion of DDL execution before returning the
|
||||||
* DDLJobs in a List. If no distributed table is involved, this returns NIL.
|
* DDLJobs in a List. If no distributed table is involved, this returns NIL.
|
||||||
*
|
*
|
||||||
* NB: So far column level privileges are not supported.
|
|
||||||
*/
|
*/
|
||||||
List *
|
List *
|
||||||
PreprocessGrantStmt(Node *node, const char *queryString,
|
PreprocessGrantStmt(Node *node, const char *queryString,
|
||||||
|
@ -69,9 +70,12 @@ PreprocessGrantStmt(Node *node, const char *queryString,
|
||||||
return NIL;
|
return NIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EnsureCoordinator();
|
||||||
|
|
||||||
/* deparse the privileges */
|
/* deparse the privileges */
|
||||||
if (grantStmt->privileges == NIL)
|
if (grantStmt->privileges == NIL)
|
||||||
{
|
{
|
||||||
|
/* this is used for table level only */
|
||||||
appendStringInfo(&privsString, "ALL");
|
appendStringInfo(&privsString, "ALL");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -87,18 +91,44 @@ PreprocessGrantStmt(Node *node, const char *queryString,
|
||||||
{
|
{
|
||||||
appendStringInfoString(&privsString, ", ");
|
appendStringInfoString(&privsString, ", ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (priv->priv_name)
|
||||||
|
{
|
||||||
|
appendStringInfo(&privsString, "%s", priv->priv_name);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* ALL can only be set alone.
|
||||||
|
* And ALL is not added as a keyword in priv_name by parser, but
|
||||||
|
* because there are column(s) defined, a grantStmt->privileges is
|
||||||
|
* defined. So we need to handle this special case here (see if
|
||||||
|
* condition above).
|
||||||
|
*/
|
||||||
|
else if (isFirst)
|
||||||
|
{
|
||||||
|
/* this is used for column level only */
|
||||||
|
appendStringInfo(&privsString, "ALL");
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Instead of relying only on the syntax check done by Postgres and
|
||||||
|
* adding an assert here, add a default ERROR if ALL is not first
|
||||||
|
* and no priv_name is defined.
|
||||||
|
*/
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR),
|
||||||
|
errmsg("Cannot parse GRANT/REVOKE privileges")));
|
||||||
|
}
|
||||||
|
|
||||||
isFirst = false;
|
isFirst = false;
|
||||||
|
|
||||||
if (priv->cols != NIL)
|
if (priv->cols != NIL)
|
||||||
{
|
{
|
||||||
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
StringInfoData colsString;
|
||||||
errmsg("grant/revoke on column list is currently "
|
initStringInfo(&colsString);
|
||||||
"unsupported")));
|
|
||||||
|
AppendColumnNameList(&colsString, priv->cols);
|
||||||
|
appendStringInfo(&privsString, "%s", colsString.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
Assert(priv->priv_name != NULL);
|
|
||||||
|
|
||||||
appendStringInfo(&privsString, "%s", priv->priv_name);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,6 +182,15 @@ PreprocessGrantStmt(Node *node, const char *queryString,
|
||||||
appendStringInfo(&ddlString, "REVOKE %s%s ON %s FROM %s",
|
appendStringInfo(&ddlString, "REVOKE %s%s ON %s FROM %s",
|
||||||
grantOption, privsString.data, targetString.data,
|
grantOption, privsString.data, targetString.data,
|
||||||
granteesString.data);
|
granteesString.data);
|
||||||
|
|
||||||
|
if (grantStmt->behavior == DROP_CASCADE)
|
||||||
|
{
|
||||||
|
appendStringInfoString(&ddlString, " CASCADE");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
appendStringInfoString(&ddlString, " RESTRICT");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DDLJob *ddlJob = palloc0(sizeof(DDLJob));
|
DDLJob *ddlJob = palloc0(sizeof(DDLJob));
|
||||||
|
|
|
@ -10,7 +10,8 @@
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
#include "distributed/pg_version_constants.h"
|
#include "miscadmin.h"
|
||||||
|
|
||||||
#include "access/genam.h"
|
#include "access/genam.h"
|
||||||
#include "access/htup_details.h"
|
#include "access/htup_details.h"
|
||||||
#include "access/xact.h"
|
#include "access/xact.h"
|
||||||
|
@ -18,32 +19,9 @@
|
||||||
#include "catalog/index.h"
|
#include "catalog/index.h"
|
||||||
#include "catalog/namespace.h"
|
#include "catalog/namespace.h"
|
||||||
#include "catalog/pg_class.h"
|
#include "catalog/pg_class.h"
|
||||||
#if PG_VERSION_NUM >= PG_VERSION_16
|
|
||||||
#include "catalog/pg_namespace.h"
|
|
||||||
#endif
|
|
||||||
#include "commands/defrem.h"
|
#include "commands/defrem.h"
|
||||||
#include "commands/tablecmds.h"
|
#include "commands/tablecmds.h"
|
||||||
#include "distributed/citus_ruleutils.h"
|
|
||||||
#include "distributed/commands.h"
|
|
||||||
#include "distributed/commands/utility_hook.h"
|
|
||||||
#include "distributed/deparse_shard_query.h"
|
|
||||||
#include "distributed/deparser.h"
|
|
||||||
#include "distributed/distributed_planner.h"
|
|
||||||
#include "distributed/listutils.h"
|
|
||||||
#include "distributed/local_executor.h"
|
|
||||||
#include "distributed/coordinator_protocol.h"
|
|
||||||
#include "distributed/metadata_cache.h"
|
|
||||||
#include "distributed/multi_executor.h"
|
|
||||||
#include "distributed/multi_physical_planner.h"
|
|
||||||
#include "distributed/multi_partitioning_utils.h"
|
|
||||||
#include "distributed/namespace_utils.h"
|
|
||||||
#include "distributed/resource_lock.h"
|
|
||||||
#include "distributed/relation_access_tracking.h"
|
|
||||||
#include "distributed/relation_utils.h"
|
|
||||||
#include "distributed/version_compat.h"
|
|
||||||
#include "distributed/worker_manager.h"
|
|
||||||
#include "lib/stringinfo.h"
|
#include "lib/stringinfo.h"
|
||||||
#include "miscadmin.h"
|
|
||||||
#include "nodes/parsenodes.h"
|
#include "nodes/parsenodes.h"
|
||||||
#include "parser/parse_utilcmd.h"
|
#include "parser/parse_utilcmd.h"
|
||||||
#include "storage/lmgr.h"
|
#include "storage/lmgr.h"
|
||||||
|
@ -53,6 +31,32 @@
|
||||||
#include "utils/lsyscache.h"
|
#include "utils/lsyscache.h"
|
||||||
#include "utils/syscache.h"
|
#include "utils/syscache.h"
|
||||||
|
|
||||||
|
#include "pg_version_constants.h"
|
||||||
|
|
||||||
|
#include "distributed/citus_ruleutils.h"
|
||||||
|
#include "distributed/commands.h"
|
||||||
|
#include "distributed/commands/utility_hook.h"
|
||||||
|
#include "distributed/coordinator_protocol.h"
|
||||||
|
#include "distributed/deparse_shard_query.h"
|
||||||
|
#include "distributed/deparser.h"
|
||||||
|
#include "distributed/distributed_planner.h"
|
||||||
|
#include "distributed/listutils.h"
|
||||||
|
#include "distributed/local_executor.h"
|
||||||
|
#include "distributed/metadata_cache.h"
|
||||||
|
#include "distributed/multi_executor.h"
|
||||||
|
#include "distributed/multi_partitioning_utils.h"
|
||||||
|
#include "distributed/multi_physical_planner.h"
|
||||||
|
#include "distributed/namespace_utils.h"
|
||||||
|
#include "distributed/relation_access_tracking.h"
|
||||||
|
#include "distributed/relation_utils.h"
|
||||||
|
#include "distributed/resource_lock.h"
|
||||||
|
#include "distributed/version_compat.h"
|
||||||
|
#include "distributed/worker_manager.h"
|
||||||
|
|
||||||
|
#if PG_VERSION_NUM >= PG_VERSION_16
|
||||||
|
#include "catalog/pg_namespace.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* Local functions forward declarations for helper functions */
|
/* Local functions forward declarations for helper functions */
|
||||||
static void ErrorIfCreateIndexHasTooManyColumns(IndexStmt *createIndexStatement);
|
static void ErrorIfCreateIndexHasTooManyColumns(IndexStmt *createIndexStatement);
|
||||||
|
@ -180,6 +184,8 @@ PreprocessIndexStmt(Node *node, const char *createIndexCommand,
|
||||||
return NIL;
|
return NIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EnsureCoordinator();
|
||||||
|
|
||||||
if (createIndexStatement->idxname == NULL)
|
if (createIndexStatement->idxname == NULL)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -331,7 +337,7 @@ ExecuteFunctionOnEachTableIndex(Oid relationId, PGIndexProcessor pgIndexProcesso
|
||||||
|
|
||||||
List *indexIdList = RelationGetIndexList(relation);
|
List *indexIdList = RelationGetIndexList(relation);
|
||||||
Oid indexId = InvalidOid;
|
Oid indexId = InvalidOid;
|
||||||
foreach_oid(indexId, indexIdList)
|
foreach_declared_oid(indexId, indexIdList)
|
||||||
{
|
{
|
||||||
HeapTuple indexTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexId));
|
HeapTuple indexTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexId));
|
||||||
if (!HeapTupleIsValid(indexTuple))
|
if (!HeapTupleIsValid(indexTuple))
|
||||||
|
@ -487,6 +493,7 @@ GenerateCreateIndexDDLJob(IndexStmt *createIndexStatement, const char *createInd
|
||||||
ddlJob->startNewTransaction = createIndexStatement->concurrent;
|
ddlJob->startNewTransaction = createIndexStatement->concurrent;
|
||||||
ddlJob->metadataSyncCommand = createIndexCommand;
|
ddlJob->metadataSyncCommand = createIndexCommand;
|
||||||
ddlJob->taskList = CreateIndexTaskList(createIndexStatement);
|
ddlJob->taskList = CreateIndexTaskList(createIndexStatement);
|
||||||
|
ddlJob->warnForPartialFailure = true;
|
||||||
|
|
||||||
return ddlJob;
|
return ddlJob;
|
||||||
}
|
}
|
||||||
|
@ -646,6 +653,7 @@ PreprocessReindexStmt(Node *node, const char *reindexCommand,
|
||||||
"concurrently");
|
"concurrently");
|
||||||
ddlJob->metadataSyncCommand = reindexCommand;
|
ddlJob->metadataSyncCommand = reindexCommand;
|
||||||
ddlJob->taskList = CreateReindexTaskList(relationId, reindexStatement);
|
ddlJob->taskList = CreateReindexTaskList(relationId, reindexStatement);
|
||||||
|
ddlJob->warnForPartialFailure = true;
|
||||||
|
|
||||||
ddlJobs = list_make1(ddlJob);
|
ddlJobs = list_make1(ddlJob);
|
||||||
}
|
}
|
||||||
|
@ -700,7 +708,7 @@ PreprocessDropIndexStmt(Node *node, const char *dropIndexCommand,
|
||||||
|
|
||||||
/* check if any of the indexes being dropped belong to a distributed table */
|
/* check if any of the indexes being dropped belong to a distributed table */
|
||||||
List *objectNameList = NULL;
|
List *objectNameList = NULL;
|
||||||
foreach_ptr(objectNameList, dropIndexStatement->objects)
|
foreach_declared_ptr(objectNameList, dropIndexStatement->objects)
|
||||||
{
|
{
|
||||||
struct DropRelationCallbackState state;
|
struct DropRelationCallbackState state;
|
||||||
uint32 rvrFlags = RVR_MISSING_OK;
|
uint32 rvrFlags = RVR_MISSING_OK;
|
||||||
|
@ -774,6 +782,7 @@ PreprocessDropIndexStmt(Node *node, const char *dropIndexCommand,
|
||||||
ddlJob->metadataSyncCommand = dropIndexCommand;
|
ddlJob->metadataSyncCommand = dropIndexCommand;
|
||||||
ddlJob->taskList = DropIndexTaskList(distributedRelationId, distributedIndexId,
|
ddlJob->taskList = DropIndexTaskList(distributedRelationId, distributedIndexId,
|
||||||
dropIndexStatement);
|
dropIndexStatement);
|
||||||
|
ddlJob->warnForPartialFailure = true;
|
||||||
|
|
||||||
ddlJobs = list_make1(ddlJob);
|
ddlJobs = list_make1(ddlJob);
|
||||||
}
|
}
|
||||||
|
@ -871,7 +880,7 @@ ErrorIfUnsupportedAlterIndexStmt(AlterTableStmt *alterTableStatement)
|
||||||
/* error out if any of the subcommands are unsupported */
|
/* error out if any of the subcommands are unsupported */
|
||||||
List *commandList = alterTableStatement->cmds;
|
List *commandList = alterTableStatement->cmds;
|
||||||
AlterTableCmd *command = NULL;
|
AlterTableCmd *command = NULL;
|
||||||
foreach_ptr(command, commandList)
|
foreach_declared_ptr(command, commandList)
|
||||||
{
|
{
|
||||||
AlterTableType alterTableType = command->subtype;
|
AlterTableType alterTableType = command->subtype;
|
||||||
|
|
||||||
|
@ -923,7 +932,7 @@ CreateIndexTaskList(IndexStmt *indexStmt)
|
||||||
LockShardListMetadata(shardIntervalList, ShareLock);
|
LockShardListMetadata(shardIntervalList, ShareLock);
|
||||||
|
|
||||||
ShardInterval *shardInterval = NULL;
|
ShardInterval *shardInterval = NULL;
|
||||||
foreach_ptr(shardInterval, shardIntervalList)
|
foreach_declared_ptr(shardInterval, shardIntervalList)
|
||||||
{
|
{
|
||||||
uint64 shardId = shardInterval->shardId;
|
uint64 shardId = shardInterval->shardId;
|
||||||
|
|
||||||
|
@ -938,7 +947,7 @@ CreateIndexTaskList(IndexStmt *indexStmt)
|
||||||
task->dependentTaskList = NULL;
|
task->dependentTaskList = NULL;
|
||||||
task->anchorShardId = shardId;
|
task->anchorShardId = shardId;
|
||||||
task->taskPlacementList = ActiveShardPlacementList(shardId);
|
task->taskPlacementList = ActiveShardPlacementList(shardId);
|
||||||
task->cannotBeExecutedInTransction = indexStmt->concurrent;
|
task->cannotBeExecutedInTransaction = indexStmt->concurrent;
|
||||||
|
|
||||||
taskList = lappend(taskList, task);
|
taskList = lappend(taskList, task);
|
||||||
|
|
||||||
|
@ -968,7 +977,7 @@ CreateReindexTaskList(Oid relationId, ReindexStmt *reindexStmt)
|
||||||
LockShardListMetadata(shardIntervalList, ShareLock);
|
LockShardListMetadata(shardIntervalList, ShareLock);
|
||||||
|
|
||||||
ShardInterval *shardInterval = NULL;
|
ShardInterval *shardInterval = NULL;
|
||||||
foreach_ptr(shardInterval, shardIntervalList)
|
foreach_declared_ptr(shardInterval, shardIntervalList)
|
||||||
{
|
{
|
||||||
uint64 shardId = shardInterval->shardId;
|
uint64 shardId = shardInterval->shardId;
|
||||||
|
|
||||||
|
@ -983,7 +992,7 @@ CreateReindexTaskList(Oid relationId, ReindexStmt *reindexStmt)
|
||||||
task->dependentTaskList = NULL;
|
task->dependentTaskList = NULL;
|
||||||
task->anchorShardId = shardId;
|
task->anchorShardId = shardId;
|
||||||
task->taskPlacementList = ActiveShardPlacementList(shardId);
|
task->taskPlacementList = ActiveShardPlacementList(shardId);
|
||||||
task->cannotBeExecutedInTransction =
|
task->cannotBeExecutedInTransaction =
|
||||||
IsReindexWithParam_compat(reindexStmt, "concurrently");
|
IsReindexWithParam_compat(reindexStmt, "concurrently");
|
||||||
|
|
||||||
taskList = lappend(taskList, task);
|
taskList = lappend(taskList, task);
|
||||||
|
@ -1106,6 +1115,7 @@ RangeVarCallbackForReindexIndex(const RangeVar *relation, Oid relId, Oid oldRelI
|
||||||
char relkind;
|
char relkind;
|
||||||
struct ReindexIndexCallbackState *state = arg;
|
struct ReindexIndexCallbackState *state = arg;
|
||||||
LOCKMODE table_lockmode;
|
LOCKMODE table_lockmode;
|
||||||
|
Oid table_oid;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Lock level here should match table lock in reindex_index() for
|
* Lock level here should match table lock in reindex_index() for
|
||||||
|
@ -1143,13 +1153,24 @@ RangeVarCallbackForReindexIndex(const RangeVar *relation, Oid relId, Oid oldRelI
|
||||||
errmsg("\"%s\" is not an index", relation->relname)));
|
errmsg("\"%s\" is not an index", relation->relname)));
|
||||||
|
|
||||||
/* Check permissions */
|
/* Check permissions */
|
||||||
|
|
||||||
|
#if PG_VERSION_NUM >= PG_VERSION_17
|
||||||
|
table_oid = IndexGetRelation(relId, true);
|
||||||
|
if (OidIsValid(table_oid))
|
||||||
|
{
|
||||||
|
AclResult aclresult = pg_class_aclcheck(table_oid, GetUserId(), ACL_MAINTAIN);
|
||||||
|
if (aclresult != ACLCHECK_OK)
|
||||||
|
aclcheck_error(aclresult, OBJECT_INDEX, relation->relname);
|
||||||
|
}
|
||||||
|
#else
|
||||||
if (!object_ownercheck(RelationRelationId, relId, GetUserId()))
|
if (!object_ownercheck(RelationRelationId, relId, GetUserId()))
|
||||||
aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_INDEX, relation->relname);
|
aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_INDEX, relation->relname);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Lock heap before index to avoid deadlock. */
|
/* Lock heap before index to avoid deadlock. */
|
||||||
if (relId != oldRelId)
|
if (relId != oldRelId)
|
||||||
{
|
{
|
||||||
Oid table_oid = IndexGetRelation(relId, true);
|
table_oid = IndexGetRelation(relId, true);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the OID isn't valid, it means the index was concurrently
|
* If the OID isn't valid, it means the index was concurrently
|
||||||
|
@ -1217,7 +1238,7 @@ ErrorIfUnsupportedIndexStmt(IndexStmt *createIndexStatement)
|
||||||
Var *partitionKey = DistPartitionKeyOrError(relationId);
|
Var *partitionKey = DistPartitionKeyOrError(relationId);
|
||||||
List *indexParameterList = createIndexStatement->indexParams;
|
List *indexParameterList = createIndexStatement->indexParams;
|
||||||
IndexElem *indexElement = NULL;
|
IndexElem *indexElement = NULL;
|
||||||
foreach_ptr(indexElement, indexParameterList)
|
foreach_declared_ptr(indexElement, indexParameterList)
|
||||||
{
|
{
|
||||||
const char *columnName = indexElement->name;
|
const char *columnName = indexElement->name;
|
||||||
|
|
||||||
|
@ -1286,7 +1307,7 @@ DropIndexTaskList(Oid relationId, Oid indexId, DropStmt *dropStmt)
|
||||||
LockShardListMetadata(shardIntervalList, ShareLock);
|
LockShardListMetadata(shardIntervalList, ShareLock);
|
||||||
|
|
||||||
ShardInterval *shardInterval = NULL;
|
ShardInterval *shardInterval = NULL;
|
||||||
foreach_ptr(shardInterval, shardIntervalList)
|
foreach_declared_ptr(shardInterval, shardIntervalList)
|
||||||
{
|
{
|
||||||
uint64 shardId = shardInterval->shardId;
|
uint64 shardId = shardInterval->shardId;
|
||||||
char *shardIndexName = pstrdup(indexName);
|
char *shardIndexName = pstrdup(indexName);
|
||||||
|
@ -1309,7 +1330,7 @@ DropIndexTaskList(Oid relationId, Oid indexId, DropStmt *dropStmt)
|
||||||
task->dependentTaskList = NULL;
|
task->dependentTaskList = NULL;
|
||||||
task->anchorShardId = shardId;
|
task->anchorShardId = shardId;
|
||||||
task->taskPlacementList = ActiveShardPlacementList(shardId);
|
task->taskPlacementList = ActiveShardPlacementList(shardId);
|
||||||
task->cannotBeExecutedInTransction = dropStmt->concurrent;
|
task->cannotBeExecutedInTransaction = dropStmt->concurrent;
|
||||||
|
|
||||||
taskList = lappend(taskList, task);
|
taskList = lappend(taskList, task);
|
||||||
|
|
||||||
|
|
|
@ -19,24 +19,27 @@
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "postgres.h"
|
|
||||||
#include "commands/copy.h"
|
|
||||||
#include "catalog/namespace.h"
|
|
||||||
#include "parser/parse_relation.h"
|
|
||||||
#include "utils/lsyscache.h"
|
|
||||||
#include "nodes/makefuncs.h"
|
|
||||||
#include "safe_lib.h"
|
|
||||||
#include <netinet/in.h> /* for htons */
|
#include <netinet/in.h> /* for htons */
|
||||||
|
|
||||||
#include "distributed/transmit.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
|
#include "safe_lib.h"
|
||||||
|
|
||||||
|
#include "catalog/namespace.h"
|
||||||
|
#include "commands/copy.h"
|
||||||
|
#include "nodes/makefuncs.h"
|
||||||
|
#include "parser/parse_relation.h"
|
||||||
|
#include "utils/lsyscache.h"
|
||||||
|
|
||||||
#include "distributed/commands/multi_copy.h"
|
#include "distributed/commands/multi_copy.h"
|
||||||
#include "distributed/intermediate_results.h"
|
#include "distributed/intermediate_results.h"
|
||||||
#include "distributed/multi_partitioning_utils.h"
|
|
||||||
#include "distributed/local_executor.h"
|
#include "distributed/local_executor.h"
|
||||||
#include "distributed/local_multi_copy.h"
|
#include "distributed/local_multi_copy.h"
|
||||||
#include "distributed/shard_utils.h"
|
#include "distributed/multi_partitioning_utils.h"
|
||||||
#include "distributed/version_compat.h"
|
|
||||||
#include "distributed/replication_origin_session_utils.h"
|
#include "distributed/replication_origin_session_utils.h"
|
||||||
|
#include "distributed/shard_utils.h"
|
||||||
|
#include "distributed/transmit.h"
|
||||||
|
#include "distributed/version_compat.h"
|
||||||
|
|
||||||
/* managed via GUC, default is 512 kB */
|
/* managed via GUC, default is 512 kB */
|
||||||
int LocalCopyFlushThresholdByte = 512 * 1024;
|
int LocalCopyFlushThresholdByte = 512 * 1024;
|
||||||
|
|
|
@ -43,19 +43,18 @@
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "postgres.h"
|
|
||||||
#include "libpq-fe.h"
|
|
||||||
#include "miscadmin.h"
|
|
||||||
#include "pgstat.h"
|
|
||||||
|
|
||||||
#include <arpa/inet.h> /* for htons */
|
#include <arpa/inet.h> /* for htons */
|
||||||
#include <netinet/in.h> /* for htons */
|
#include <netinet/in.h> /* for htons */
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "distributed/pg_version_constants.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
|
#include "libpq-fe.h"
|
||||||
|
#include "miscadmin.h"
|
||||||
|
#include "pgstat.h"
|
||||||
|
|
||||||
#include "access/htup_details.h"
|
|
||||||
#include "access/htup.h"
|
#include "access/htup.h"
|
||||||
|
#include "access/htup_details.h"
|
||||||
#include "access/sdir.h"
|
#include "access/sdir.h"
|
||||||
#include "access/sysattr.h"
|
#include "access/sysattr.h"
|
||||||
#include "access/xact.h"
|
#include "access/xact.h"
|
||||||
|
@ -65,41 +64,8 @@
|
||||||
#include "commands/copy.h"
|
#include "commands/copy.h"
|
||||||
#include "commands/defrem.h"
|
#include "commands/defrem.h"
|
||||||
#include "commands/progress.h"
|
#include "commands/progress.h"
|
||||||
#include "distributed/citus_safe_lib.h"
|
|
||||||
#include "distributed/commands/multi_copy.h"
|
|
||||||
#include "distributed/commands/utility_hook.h"
|
|
||||||
#include "distributed/intermediate_results.h"
|
|
||||||
#include "distributed/listutils.h"
|
|
||||||
#include "distributed/local_executor.h"
|
|
||||||
#include "distributed/log_utils.h"
|
|
||||||
#include "distributed/coordinator_protocol.h"
|
|
||||||
#include "distributed/metadata_cache.h"
|
|
||||||
#include "distributed/multi_executor.h"
|
|
||||||
#include "distributed/multi_partitioning_utils.h"
|
|
||||||
#include "distributed/multi_physical_planner.h"
|
|
||||||
#include "distributed/multi_router_planner.h"
|
|
||||||
#include "distributed/multi_executor.h"
|
|
||||||
#include "distributed/listutils.h"
|
|
||||||
#include "distributed/locally_reserved_shared_connections.h"
|
|
||||||
#include "distributed/placement_connection.h"
|
|
||||||
#include "distributed/relation_access_tracking.h"
|
|
||||||
#if PG_VERSION_NUM >= PG_VERSION_16
|
|
||||||
#include "distributed/relation_utils.h"
|
|
||||||
#endif
|
|
||||||
#include "distributed/remote_commands.h"
|
|
||||||
#include "distributed/remote_transaction.h"
|
|
||||||
#include "distributed/replication_origin_session_utils.h"
|
|
||||||
#include "distributed/resource_lock.h"
|
|
||||||
#include "distributed/shard_pruning.h"
|
|
||||||
#include "distributed/shared_connection_stats.h"
|
|
||||||
#include "distributed/version_compat.h"
|
|
||||||
#include "distributed/worker_protocol.h"
|
|
||||||
#include "distributed/local_multi_copy.h"
|
|
||||||
#include "distributed/hash_helpers.h"
|
|
||||||
#include "distributed/transmit.h"
|
|
||||||
#include "executor/executor.h"
|
#include "executor/executor.h"
|
||||||
#include "foreign/foreign.h"
|
#include "foreign/foreign.h"
|
||||||
|
|
||||||
#include "libpq/libpq.h"
|
#include "libpq/libpq.h"
|
||||||
#include "libpq/pqformat.h"
|
#include "libpq/pqformat.h"
|
||||||
#include "nodes/makefuncs.h"
|
#include "nodes/makefuncs.h"
|
||||||
|
@ -110,9 +76,44 @@
|
||||||
#include "tsearch/ts_locale.h"
|
#include "tsearch/ts_locale.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "utils/lsyscache.h"
|
#include "utils/lsyscache.h"
|
||||||
|
#include "utils/memutils.h"
|
||||||
#include "utils/rel.h"
|
#include "utils/rel.h"
|
||||||
#include "utils/syscache.h"
|
#include "utils/syscache.h"
|
||||||
#include "utils/memutils.h"
|
|
||||||
|
#include "pg_version_constants.h"
|
||||||
|
|
||||||
|
#include "distributed/citus_safe_lib.h"
|
||||||
|
#include "distributed/commands/multi_copy.h"
|
||||||
|
#include "distributed/commands/utility_hook.h"
|
||||||
|
#include "distributed/coordinator_protocol.h"
|
||||||
|
#include "distributed/hash_helpers.h"
|
||||||
|
#include "distributed/intermediate_results.h"
|
||||||
|
#include "distributed/listutils.h"
|
||||||
|
#include "distributed/local_executor.h"
|
||||||
|
#include "distributed/local_multi_copy.h"
|
||||||
|
#include "distributed/locally_reserved_shared_connections.h"
|
||||||
|
#include "distributed/log_utils.h"
|
||||||
|
#include "distributed/metadata_cache.h"
|
||||||
|
#include "distributed/multi_executor.h"
|
||||||
|
#include "distributed/multi_partitioning_utils.h"
|
||||||
|
#include "distributed/multi_physical_planner.h"
|
||||||
|
#include "distributed/multi_router_planner.h"
|
||||||
|
#include "distributed/placement_connection.h"
|
||||||
|
#include "distributed/relation_access_tracking.h"
|
||||||
|
#include "distributed/remote_commands.h"
|
||||||
|
#include "distributed/remote_transaction.h"
|
||||||
|
#include "distributed/replication_origin_session_utils.h"
|
||||||
|
#include "distributed/resource_lock.h"
|
||||||
|
#include "distributed/shard_pruning.h"
|
||||||
|
#include "distributed/shared_connection_stats.h"
|
||||||
|
#include "distributed/stats/stat_counters.h"
|
||||||
|
#include "distributed/transmit.h"
|
||||||
|
#include "distributed/version_compat.h"
|
||||||
|
#include "distributed/worker_protocol.h"
|
||||||
|
|
||||||
|
#if PG_VERSION_NUM >= PG_VERSION_16
|
||||||
|
#include "distributed/relation_utils.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* constant used in binary protocol */
|
/* constant used in binary protocol */
|
||||||
|
@ -301,6 +302,7 @@ static SelectStmt * CitusCopySelect(CopyStmt *copyStatement);
|
||||||
static void CitusCopyTo(CopyStmt *copyStatement, QueryCompletion *completionTag);
|
static void CitusCopyTo(CopyStmt *copyStatement, QueryCompletion *completionTag);
|
||||||
static int64 ForwardCopyDataFromConnection(CopyOutState copyOutState,
|
static int64 ForwardCopyDataFromConnection(CopyOutState copyOutState,
|
||||||
MultiConnection *connection);
|
MultiConnection *connection);
|
||||||
|
static void ErrorIfCopyHasOnErrorLogVerbosity(CopyStmt *copyStatement);
|
||||||
|
|
||||||
/* Private functions copied and adapted from copy.c in PostgreSQL */
|
/* Private functions copied and adapted from copy.c in PostgreSQL */
|
||||||
static void SendCopyBegin(CopyOutState cstate);
|
static void SendCopyBegin(CopyOutState cstate);
|
||||||
|
@ -346,6 +348,7 @@ static LocalCopyStatus GetLocalCopyStatus(void);
|
||||||
static bool ShardIntervalListHasLocalPlacements(List *shardIntervalList);
|
static bool ShardIntervalListHasLocalPlacements(List *shardIntervalList);
|
||||||
static void LogLocalCopyToRelationExecution(uint64 shardId);
|
static void LogLocalCopyToRelationExecution(uint64 shardId);
|
||||||
static void LogLocalCopyToFileExecution(uint64 shardId);
|
static void LogLocalCopyToFileExecution(uint64 shardId);
|
||||||
|
static void ErrorIfMergeInCopy(CopyStmt *copyStatement);
|
||||||
|
|
||||||
|
|
||||||
/* exports for SQL callable functions */
|
/* exports for SQL callable functions */
|
||||||
|
@ -497,10 +500,14 @@ CopyToExistingShards(CopyStmt *copyStatement, QueryCompletion *completionTag)
|
||||||
|
|
||||||
/* set up the destination for the COPY */
|
/* set up the destination for the COPY */
|
||||||
const bool publishableData = true;
|
const bool publishableData = true;
|
||||||
|
|
||||||
|
/* we want to track query counters for "COPY (to) distributed-table .." commands */
|
||||||
|
const bool trackQueryCounters = true;
|
||||||
CitusCopyDestReceiver *copyDest = CreateCitusCopyDestReceiver(tableId, columnNameList,
|
CitusCopyDestReceiver *copyDest = CreateCitusCopyDestReceiver(tableId, columnNameList,
|
||||||
partitionColumnIndex,
|
partitionColumnIndex,
|
||||||
executorState, NULL,
|
executorState, NULL,
|
||||||
publishableData);
|
publishableData,
|
||||||
|
trackQueryCounters);
|
||||||
|
|
||||||
/* if the user specified an explicit append-to_shard option, write to it */
|
/* if the user specified an explicit append-to_shard option, write to it */
|
||||||
uint64 appendShardId = ProcessAppendToShardOption(tableId, copyStatement);
|
uint64 appendShardId = ProcessAppendToShardOption(tableId, copyStatement);
|
||||||
|
@ -1875,11 +1882,15 @@ CopyFlushOutput(CopyOutState cstate, char *start, char *pointer)
|
||||||
* of intermediate results that are co-located with the actual table.
|
* of intermediate results that are co-located with the actual table.
|
||||||
* The names of the intermediate results with be of the form:
|
* The names of the intermediate results with be of the form:
|
||||||
* intermediateResultIdPrefix_<shardid>
|
* intermediateResultIdPrefix_<shardid>
|
||||||
|
*
|
||||||
|
* If trackQueryCounters is true, the COPY will increment the query stat
|
||||||
|
* counters as needed at the end of the COPY.
|
||||||
*/
|
*/
|
||||||
CitusCopyDestReceiver *
|
CitusCopyDestReceiver *
|
||||||
CreateCitusCopyDestReceiver(Oid tableId, List *columnNameList, int partitionColumnIndex,
|
CreateCitusCopyDestReceiver(Oid tableId, List *columnNameList, int partitionColumnIndex,
|
||||||
EState *executorState,
|
EState *executorState,
|
||||||
char *intermediateResultIdPrefix, bool isPublishable)
|
char *intermediateResultIdPrefix, bool isPublishable,
|
||||||
|
bool trackQueryCounters)
|
||||||
{
|
{
|
||||||
CitusCopyDestReceiver *copyDest = (CitusCopyDestReceiver *) palloc0(
|
CitusCopyDestReceiver *copyDest = (CitusCopyDestReceiver *) palloc0(
|
||||||
sizeof(CitusCopyDestReceiver));
|
sizeof(CitusCopyDestReceiver));
|
||||||
|
@ -1899,6 +1910,7 @@ CreateCitusCopyDestReceiver(Oid tableId, List *columnNameList, int partitionColu
|
||||||
copyDest->colocatedIntermediateResultIdPrefix = intermediateResultIdPrefix;
|
copyDest->colocatedIntermediateResultIdPrefix = intermediateResultIdPrefix;
|
||||||
copyDest->memoryContext = CurrentMemoryContext;
|
copyDest->memoryContext = CurrentMemoryContext;
|
||||||
copyDest->isPublishable = isPublishable;
|
copyDest->isPublishable = isPublishable;
|
||||||
|
copyDest->trackQueryCounters = trackQueryCounters;
|
||||||
|
|
||||||
return copyDest;
|
return copyDest;
|
||||||
}
|
}
|
||||||
|
@ -1957,7 +1969,7 @@ ShardIntervalListHasLocalPlacements(List *shardIntervalList)
|
||||||
{
|
{
|
||||||
int32 localGroupId = GetLocalGroupId();
|
int32 localGroupId = GetLocalGroupId();
|
||||||
ShardInterval *shardInterval = NULL;
|
ShardInterval *shardInterval = NULL;
|
||||||
foreach_ptr(shardInterval, shardIntervalList)
|
foreach_declared_ptr(shardInterval, shardIntervalList)
|
||||||
{
|
{
|
||||||
if (ActiveShardPlacementOnGroup(localGroupId, shardInterval->shardId) != NULL)
|
if (ActiveShardPlacementOnGroup(localGroupId, shardInterval->shardId) != NULL)
|
||||||
{
|
{
|
||||||
|
@ -2452,7 +2464,7 @@ ProcessAppendToShardOption(Oid relationId, CopyStmt *copyStatement)
|
||||||
bool appendToShardSet = false;
|
bool appendToShardSet = false;
|
||||||
|
|
||||||
DefElem *defel = NULL;
|
DefElem *defel = NULL;
|
||||||
foreach_ptr(defel, copyStatement->options)
|
foreach_declared_ptr(defel, copyStatement->options)
|
||||||
{
|
{
|
||||||
if (strncmp(defel->defname, APPEND_TO_SHARD_OPTION, NAMEDATALEN) == 0)
|
if (strncmp(defel->defname, APPEND_TO_SHARD_OPTION, NAMEDATALEN) == 0)
|
||||||
{
|
{
|
||||||
|
@ -2547,12 +2559,8 @@ ShardIdForTuple(CitusCopyDestReceiver *copyDest, Datum *columnValues, bool *colu
|
||||||
|
|
||||||
if (columnNulls[partitionColumnIndex])
|
if (columnNulls[partitionColumnIndex])
|
||||||
{
|
{
|
||||||
Oid relationId = copyDest->distributedRelationId;
|
char *qualifiedTableName = generate_qualified_relation_name(
|
||||||
char *relationName = get_rel_name(relationId);
|
copyDest->distributedRelationId);
|
||||||
Oid schemaOid = get_rel_namespace(relationId);
|
|
||||||
char *schemaName = get_namespace_name(schemaOid);
|
|
||||||
char *qualifiedTableName = quote_qualified_identifier(schemaName,
|
|
||||||
relationName);
|
|
||||||
|
|
||||||
ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
|
ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
|
||||||
errmsg("the partition column of table %s cannot be NULL",
|
errmsg("the partition column of table %s cannot be NULL",
|
||||||
|
@ -2572,7 +2580,7 @@ ShardIdForTuple(CitusCopyDestReceiver *copyDest, Datum *columnValues, bool *colu
|
||||||
* Find the shard interval and id for the partition column value for
|
* Find the shard interval and id for the partition column value for
|
||||||
* non-reference tables.
|
* non-reference tables.
|
||||||
*
|
*
|
||||||
* For reference table, this function blindly returns the tables single
|
* For reference table, and single shard distributed table this function blindly returns the tables single
|
||||||
* shard.
|
* shard.
|
||||||
*/
|
*/
|
||||||
ShardInterval *shardInterval = FindShardInterval(partitionColumnValue, cacheEntry);
|
ShardInterval *shardInterval = FindShardInterval(partitionColumnValue, cacheEntry);
|
||||||
|
@ -2589,8 +2597,9 @@ ShardIdForTuple(CitusCopyDestReceiver *copyDest, Datum *columnValues, bool *colu
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CitusCopyDestReceiverShutdown implements the rShutdown interface of
|
* CitusCopyDestReceiverShutdown implements the rShutdown interface of
|
||||||
* CitusCopyDestReceiver. It ends the COPY on all the open connections and closes
|
* CitusCopyDestReceiver. It ends the COPY on all the open connections, closes
|
||||||
* the relation.
|
* the relation and increments the query stat counters based on the shards
|
||||||
|
* copied into if requested.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
CitusCopyDestReceiverShutdown(DestReceiver *destReceiver)
|
CitusCopyDestReceiverShutdown(DestReceiver *destReceiver)
|
||||||
|
@ -2601,6 +2610,26 @@ CitusCopyDestReceiverShutdown(DestReceiver *destReceiver)
|
||||||
ListCell *connectionStateCell = NULL;
|
ListCell *connectionStateCell = NULL;
|
||||||
Relation distributedRelation = copyDest->distributedRelation;
|
Relation distributedRelation = copyDest->distributedRelation;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Increment the query stat counters based on the shards copied into
|
||||||
|
* if requested.
|
||||||
|
*/
|
||||||
|
if (copyDest->trackQueryCounters)
|
||||||
|
{
|
||||||
|
int copiedShardCount =
|
||||||
|
copyDest->shardStateHash ?
|
||||||
|
hash_get_num_entries(copyDest->shardStateHash) :
|
||||||
|
0;
|
||||||
|
if (copiedShardCount <= 1)
|
||||||
|
{
|
||||||
|
IncrementStatCounterForMyDb(STAT_QUERY_EXECUTION_SINGLE_SHARD);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
IncrementStatCounterForMyDb(STAT_QUERY_EXECUTION_MULTI_SHARD);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
List *connectionStateList = ConnectionStateList(connectionStateHash);
|
List *connectionStateList = ConnectionStateList(connectionStateHash);
|
||||||
|
|
||||||
FinishLocalColocatedIntermediateFiles(copyDest);
|
FinishLocalColocatedIntermediateFiles(copyDest);
|
||||||
|
@ -2667,7 +2696,6 @@ CreateLocalColocatedIntermediateFile(CitusCopyDestReceiver *copyDest,
|
||||||
CreateIntermediateResultsDirectory();
|
CreateIntermediateResultsDirectory();
|
||||||
|
|
||||||
const int fileFlags = (O_CREAT | O_RDWR | O_TRUNC);
|
const int fileFlags = (O_CREAT | O_RDWR | O_TRUNC);
|
||||||
const int fileMode = (S_IRUSR | S_IWUSR);
|
|
||||||
|
|
||||||
StringInfo filePath = makeStringInfo();
|
StringInfo filePath = makeStringInfo();
|
||||||
appendStringInfo(filePath, "%s_%ld", copyDest->colocatedIntermediateResultIdPrefix,
|
appendStringInfo(filePath, "%s_%ld", copyDest->colocatedIntermediateResultIdPrefix,
|
||||||
|
@ -2675,7 +2703,7 @@ CreateLocalColocatedIntermediateFile(CitusCopyDestReceiver *copyDest,
|
||||||
|
|
||||||
const char *fileName = QueryResultFileName(filePath->data);
|
const char *fileName = QueryResultFileName(filePath->data);
|
||||||
shardState->fileDest =
|
shardState->fileDest =
|
||||||
FileCompatFromFileStart(FileOpenForTransmit(fileName, fileFlags, fileMode));
|
FileCompatFromFileStart(FileOpenForTransmit(fileName, fileFlags));
|
||||||
|
|
||||||
CopyOutState localFileCopyOutState = shardState->copyOutState;
|
CopyOutState localFileCopyOutState = shardState->copyOutState;
|
||||||
bool isBinaryCopy = localFileCopyOutState->binary;
|
bool isBinaryCopy = localFileCopyOutState->binary;
|
||||||
|
@ -2828,6 +2856,70 @@ CopyStatementHasFormat(CopyStmt *copyStatement, char *formatName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ErrorIfCopyHasOnErrorLogVerbosity errors out if the COPY statement
|
||||||
|
* has on_error option or log_verbosity option specified
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
ErrorIfCopyHasOnErrorLogVerbosity(CopyStmt *copyStatement)
|
||||||
|
{
|
||||||
|
#if PG_VERSION_NUM >= PG_VERSION_17
|
||||||
|
bool log_verbosity = false;
|
||||||
|
foreach_ptr(DefElem, option, copyStatement->options)
|
||||||
|
{
|
||||||
|
if (strcmp(option->defname, "on_error") == 0)
|
||||||
|
{
|
||||||
|
ereport(ERROR, (errmsg(
|
||||||
|
"Citus does not support COPY FROM with ON_ERROR option.")));
|
||||||
|
}
|
||||||
|
else if (strcmp(option->defname, "log_verbosity") == 0)
|
||||||
|
{
|
||||||
|
log_verbosity = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Given that log_verbosity is currently used in COPY FROM
|
||||||
|
* when ON_ERROR option is set to ignore, it makes more
|
||||||
|
* sense to error out for ON_ERROR option first. For this reason,
|
||||||
|
* we don't error out in the previous loop directly.
|
||||||
|
* Relevant PG17 commit: https://github.com/postgres/postgres/commit/f5a227895
|
||||||
|
*/
|
||||||
|
if (log_verbosity)
|
||||||
|
{
|
||||||
|
ereport(ERROR, (errmsg(
|
||||||
|
"Citus does not support COPY FROM with LOG_VERBOSITY option.")));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ErrorIfMergeInCopy Raises an exception if the MERGE is called in the COPY
|
||||||
|
* where Citus tables are involved, as we don't support this yet
|
||||||
|
* Relevant PG17 commit: c649fa24a
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
ErrorIfMergeInCopy(CopyStmt *copyStatement)
|
||||||
|
{
|
||||||
|
#if PG_VERSION_NUM < 170000
|
||||||
|
return;
|
||||||
|
#else
|
||||||
|
if (!copyStatement->relation && (IsA(copyStatement->query, MergeStmt)))
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* This path is currently not reachable because Merge in COPY can
|
||||||
|
* only work with a RETURNING clause, and a RETURNING check
|
||||||
|
* will error out sooner for Citus
|
||||||
|
*/
|
||||||
|
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||||
|
errmsg("MERGE with Citus tables "
|
||||||
|
"is not yet supported in COPY")));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ProcessCopyStmt handles Citus specific concerns for COPY like supporting
|
* ProcessCopyStmt handles Citus specific concerns for COPY like supporting
|
||||||
* COPYing from distributed tables and preventing unsupported actions. The
|
* COPYing from distributed tables and preventing unsupported actions. The
|
||||||
|
@ -2865,6 +2957,8 @@ ProcessCopyStmt(CopyStmt *copyStatement, QueryCompletion *completionTag, const
|
||||||
*/
|
*/
|
||||||
if (copyStatement->relation != NULL)
|
if (copyStatement->relation != NULL)
|
||||||
{
|
{
|
||||||
|
ErrorIfMergeInCopy(copyStatement);
|
||||||
|
|
||||||
bool isFrom = copyStatement->is_from;
|
bool isFrom = copyStatement->is_from;
|
||||||
|
|
||||||
/* consider using RangeVarGetRelidExtended to check perms before locking */
|
/* consider using RangeVarGetRelidExtended to check perms before locking */
|
||||||
|
@ -2902,6 +2996,8 @@ ProcessCopyStmt(CopyStmt *copyStatement, QueryCompletion *completionTag, const
|
||||||
"Citus does not support COPY FROM with WHERE")));
|
"Citus does not support COPY FROM with WHERE")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ErrorIfCopyHasOnErrorLogVerbosity(copyStatement);
|
||||||
|
|
||||||
/* check permissions, we're bypassing postgres' normal checks */
|
/* check permissions, we're bypassing postgres' normal checks */
|
||||||
CheckCopyPermissions(copyStatement);
|
CheckCopyPermissions(copyStatement);
|
||||||
CitusCopyFrom(copyStatement, completionTag);
|
CitusCopyFrom(copyStatement, completionTag);
|
||||||
|
@ -3076,6 +3172,15 @@ CitusCopyTo(CopyStmt *copyStatement, QueryCompletion *completionTag)
|
||||||
|
|
||||||
SendCopyEnd(copyOutState);
|
SendCopyEnd(copyOutState);
|
||||||
|
|
||||||
|
if (list_length(shardIntervalList) <= 1)
|
||||||
|
{
|
||||||
|
IncrementStatCounterForMyDb(STAT_QUERY_EXECUTION_SINGLE_SHARD);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
IncrementStatCounterForMyDb(STAT_QUERY_EXECUTION_MULTI_SHARD);
|
||||||
|
}
|
||||||
|
|
||||||
table_close(distributedRelation, AccessShareLock);
|
table_close(distributedRelation, AccessShareLock);
|
||||||
|
|
||||||
if (completionTag != NULL)
|
if (completionTag != NULL)
|
||||||
|
|