From a0e3d84f2c401dfae2832c970dd3ad250a0bf688 Mon Sep 17 00:00:00 2001 From: Greg Burd Date: Wed, 2 Jul 2025 07:17:55 -0400 Subject: [PATCH 1/3] dev setup v14 --- .clang-format | 71 ++ .clangd | 89 ++ .envrc | 9 + .gdbinit | 2 + .gitignore | 8 + .idea/.gitignore | 8 + .idea/editor.xml | 580 +++++++++++++ .idea/inspectionProfiles/Project_Default.xml | 7 + .idea/misc.xml | 18 + .idea/prettier.xml | 6 + .idea/vcs.xml | 6 + .vscode/launch.json | 22 + .vscode/settings.json | 5 + flake.lock | 78 ++ flake.nix | 45 + glibc-no-fortify-warning.patch | 24 + pg-aliases.sh | 304 +++++++ shell.nix | 820 +++++++++++++++++++ src/test/regress/pg_regress.c | 2 +- src/tools/pgindent/pgindent | 2 +- 20 files changed, 2104 insertions(+), 2 deletions(-) create mode 100644 .clang-format create mode 100644 .clangd create mode 100644 .envrc create mode 100644 .gdbinit create mode 100644 .idea/.gitignore create mode 100644 .idea/editor.xml create mode 100644 .idea/inspectionProfiles/Project_Default.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/prettier.xml create mode 100644 .idea/vcs.xml create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json create mode 100644 flake.lock create mode 100644 flake.nix create mode 100644 glibc-no-fortify-warning.patch create mode 100644 pg-aliases.sh create mode 100644 shell.nix diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000000000..2f786ac8eef05 --- /dev/null +++ b/.clang-format @@ -0,0 +1,71 @@ +# the official .clang-format style for https://github.com/taocpp +# +# clang-format-4.0 -i -style=file $(find -name '[^.]*.[hc]pp') + +Language: Cpp +Standard: Cpp11 + +AccessModifierOffset: -3 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlinesLeft: false +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: Empty +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: true +BinPackArguments: false +BinPackParameters: false +BraceWrapping: + AfterClass: true + AfterControlStatement: false + AfterEnum : true + AfterFunction : true + AfterNamespace : true + AfterStruct : true + AfterUnion : true + BeforeCatch : true + BeforeElse : true + IndentBraces : false +BreakBeforeBinaryOperators: All +BreakBeforeBraces: Custom +BreakBeforeTernaryOperators: false +BreakStringLiterals: false +BreakConstructorInitializersBeforeComma: false +ColumnLimit: 0 +ConstructorInitializerAllOnOneLineOrOnePerLine: true +ConstructorInitializerIndentWidth: 3 +ContinuationIndentWidth: 3 +Cpp11BracedListStyle: false +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +IndentCaseLabels: true +IndentWidth: 3 +IndentWrappedFunctionNames: false +KeepEmptyLinesAtTheStartOfBlocks: true +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: All +PointerAlignment: Left +ReflowComments: false +SortIncludes: true +SpaceAfterCStyleCast: false +SpaceAfterTemplateKeyword: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: Never +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 2 +SpacesInAngles: true +SpacesInCStyleCastParentheses: false +SpacesInContainerLiterals: true +SpacesInParentheses: true +SpacesInSquareBrackets: true +TabWidth: 8 +UseTab: Never diff --git a/.clangd b/.clangd new file mode 100644 index 0000000000000..500c5d0d258d6 --- /dev/null +++ b/.clangd @@ -0,0 +1,89 @@ +Diagnostics: + MissingIncludes: None +InlayHints: + Enabled: true + ParameterNames: true + DeducedTypes: true +CompileFlags: + CompilationDatabase: build/ # Search build/ directory for compile_commands.json + Remove: [ -Werror ] + Add: + - -DDEBUG + - -DLOCAL + - -DPGDLLIMPORT= + - -DPIC + - -O2 + - -Wall + - -Wcast-function-type + - -Wconversion + - -Wdeclaration-after-statement + - -Wendif-labels + - -Werror=vla + - -Wextra + - -Wfloat-equal + - -Wformat-security + - -Wimplicit-fallthrough=3 + - -Wmissing-format-attribute + - -Wmissing-prototypes + - -Wno-format-truncation + - -Wno-sign-conversion + - -Wno-stringop-truncation + - -Wno-unused-const-variable + - -Wpointer-arith + - -Wshadow + - -Wshadow=compatible-local + - -fPIC + - -fexcess-precision=standard + - -fno-strict-aliasing + - -fvisibility=hidden + - -fwrapv + - -g + - -std=c11 + - -I. + - -I../../../../src/include +# gcc -E -v -xc++ /dev/null +# - -I/nix/store/l2sgvfcyqc1bgnzpz86qw5pjq99j8vlw-libtool-2.5.4/include +# - -I/nix/store/n087ac9g368fbl6h57a2mdd741lshzrc-file-5.46-dev/include +# - -I/nix/store/p7z72c2s722pbw31jmm3y0nwypksb5fj-gnumake-4.4.1/include +# - -I/nix/store/wzwlizg15dwh6x0h3ckjmibdblfkfdzf-flex-2.6.4/include +# - -I/nix/store/8nh579b2yl3sz2yfwyjc9ksb0jb7kwf5-libxslt-1.1.43-dev/include +# - -I/nix/store/cisb0723v3pgp74f2lj07z5d6w3j77sl-libxml2-2.13.8-dev/include +# - -I/nix/store/245c5yscaxyxi49fz9ys1i1apy5s2igz-valgrind-3.24.0-dev/include +# - -I/nix/store/nmxr110602fvajr9ax8d65ac1g40vx1a-curl-8.13.0-dev/include +# - -I/nix/store/slqvy0fgnwmvaq3bxmrvqclph8x909i2-brotli-1.1.0-dev/include +# - -I/nix/store/lchvccw6zl1z1wmhqayixcjcqyhqvyj7-krb5-1.21.3-dev/include +# - -I/nix/store/hybw3vnacqmm68fskbcchrbmj0h4ffv2-nghttp2-1.65.0-dev/include +# - -I/nix/store/2m0s7qxq2kgclyh6cfbflpxm65aga2h4-libidn2-2.3.8-dev/include +# - -I/nix/store/kcgqglb4iax0zh5jlrxmjdik93wlgsrq-openssl-3.4.1-dev/include +# - -I/nix/store/8mlcjg5js2r0zrpdjlfaxax6hyvppgz5-libpsl-0.21.5-dev/include +# - -I/nix/store/1nygjgimkj4wnmydzd6brsw6m0rd7gmx-libssh2-1.11.1-dev/include +# - -I/nix/store/cbdvjyn19y77m8l06n089x30v7irqz3j-zlib-1.3.1-dev/include +# - -I/nix/store/x10zhllc0rhk1s1mhjvsrzvbg55802gj-zstd-1.5.7-dev/include +# - -I/nix/store/8w718rm43x7z73xhw9d6vh8s4snrq67h-python3-3.12.10/include +# - -I/nix/store/1lrgn56jw2yww4bxj0frpgvahqh9i7gl-perf-linux-6.12.35/include +# - -I/nix/store/j87n5xqfj6c03633g7l95lfjq5ynml13-gdb-16.2/include +# - -I/nix/store/ih8dkkw9r7zx5fxg3arh53qc9zs422d1-llvm-21.1.0-dev/include +# - -I/nix/store/rz4bmcm8dwsy7ylx6rhffkwkqn6n8srn-ncurses-6.5-dev/include +# - -I/nix/store/29mcvdnd9s6sp46cjmqm0pfg4xs56rik-zlib-1.3.1-dev/include +# - -I/nix/store/42288hw25sc2gchgc5jp4wfgwisa0nxm-lldb-21.1.0-dev/include +# - -I/nix/store/wpfdp7vzd7h7ahnmp4rvxfcklg4viknl-tcl-8.6.15/include +# - -I/nix/store/4sq2x2770k0xrjshdi6piqrazqjfi5s4-readline-8.2p13-dev/include +# - -I/nix/store/myw381bc9yqd709hpray9lp7l98qmlm1-ncurses-6.5-dev/include +# - -I/nix/store/dvhx24q4icrig4q1v1lp7kzi3izd5jmb-icu4c-76.1-dev/include +# - -I/nix/store/7ld4hdn561a4vkk5hrkdhq8r6rxw8shl-lz4-1.10.0-dev/include +# - -I/nix/store/fnzbi6b8q79faggzj53paqi7igr091w0-util-linux-minimal-2.41-dev/include +# - -I/nix/store/vrdwlbzr74ibnzcli2yl1nxg9jqmr237-linux-pam-1.6.1/include +# - -I/nix/store/qizipyz9y17nr4w4gmxvwd3x4k0bp2rh-libxcrypt-4.4.38/include +# - -I/nix/store/7z8illxfqr4mvwh4l3inik6vdh12jx09-numactl-2.0.18-dev/include +# - -I/nix/store/f6lmz5inbk7qjc79099q4jvgzih7zbhy-openldap-2.6.9-dev/include +# - -I/nix/store/28vmjd90wzd6gij5a1nfj4nqaw191cfg-liburing-2.9-dev/include +# - -I/nix/store/75cyhmjxzx8z7v2z8vrmrydwraf00wyi-libselinux-3.8.1-dev/include +# - -I/nix/store/r25srliigrrv5q3n7y8ms6z10spvjcd9-glibc-2.40-66-dev/include +# - -I/nix/store/ldp1izmflvc74bd4n2svhrd5xrz61wyi-lld-21.1.0-dev/include +# - -I/nix/store/wd5cm50kmlw8n9mq6l1mkvpp8g443a1g-compiler-rt-libc-21.1.0-dev/include +# - -I/nix/store/9ds850ifd4jwcccpp3v14818kk74ldf2-gcc-14.2.1.20250322/include/c++/14.2.1.20250322/ +# - -I/nix/store/9ds850ifd4jwcccpp3v14818kk74ldf2-gcc-14.2.1.20250322/include/c++/14.2.1.20250322//x86_64-unknown-linux-gnu +# - -I/nix/store/9ds850ifd4jwcccpp3v14818kk74ldf2-gcc-14.2.1.20250322/include/c++/14.2.1.20250322//backward +# - -I/nix/store/9ds850ifd4jwcccpp3v14818kk74ldf2-gcc-14.2.1.20250322/lib/gcc/x86_64-unknown-linux-gnu/14.2.1/include +# - -I/nix/store/9ds850ifd4jwcccpp3v14818kk74ldf2-gcc-14.2.1.20250322/include +# - -I/nix/store/9ds850ifd4jwcccpp3v14818kk74ldf2-gcc-14.2.1.20250322/lib/gcc/x86_64-unknown-linux-gnu/14.2.1/include-fixed diff --git a/.envrc b/.envrc new file mode 100644 index 0000000000000..c2f6763607e61 --- /dev/null +++ b/.envrc @@ -0,0 +1,9 @@ +watch_file flake.nix +use flake + +#export MESON_EXTRA_SETUP="-Db_coverage=true" +#export GENINFO_OPTIONS="--ignore-errors inconsistent,gcov" +#export LCOV_OPTIONS="--ignore-errors inconsistent,gcov" + +export CFLAGS="-Wall -Wextra -Wconversion -Wdouble-promotion -Wno-unused-parameter -Wno-unused-function -Wno-sign-conversion -fsanitize-trap --werror" +# -fsanitize=undefined,address,undefined,thread diff --git a/.gdbinit b/.gdbinit new file mode 100644 index 0000000000000..0a548eb87cdf7 --- /dev/null +++ b/.gdbinit @@ -0,0 +1,2 @@ +set tui tab-width 4 +set tui mouse-events off diff --git a/.gitignore b/.gitignore index 4e911395fe3ba..8e429d66ca41f 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,11 @@ lib*.pc /Release/ /tmp_install/ /portlock/ + +build/ +install/ +test-db/ +.direnv/ +.cache/ +.history + diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000000000..13566b81b018a --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/editor.xml b/.idea/editor.xml new file mode 100644 index 0000000000000..1f0ef49b4faf4 --- /dev/null +++ b/.idea/editor.xml @@ -0,0 +1,580 @@ + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000000000..9c69411050eac --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000000000..53624c9e1f9ab --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,18 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/prettier.xml b/.idea/prettier.xml new file mode 100644 index 0000000000000..b0c1c68fbbad6 --- /dev/null +++ b/.idea/prettier.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000000000..35eb1ddfbbc02 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000000000..f5d97424c5047 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,22 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "(gdb) Attach Postgres", + "type": "cppdbg", + "request": "attach", + "program": "${workspaceRoot}/install/bin/postgres", + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ], + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000000..cc8a64fa9fa85 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.associations": { + "syscache.h": "c" + } +} \ No newline at end of file diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000000000..a609589066525 --- /dev/null +++ b/flake.lock @@ -0,0 +1,78 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1751211869, + "narHash": "sha256-1Cu92i1KSPbhPCKxoiVG5qnoRiKTgR5CcGSRyLpOd7Y=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "b43c397f6c213918d6cfe6e3550abfe79b5d1c51", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-25.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-unstable": { + "locked": { + "lastModified": 1757651841, + "narHash": "sha256-Lh9QoMzTjY/O4LqNwcm6s/WSYStDmCH6f3V/izwlkHc=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "ad4e6dd68c30bc8bd1860a27bc6f0c485bd7f3b6", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs", + "nixpkgs-unstable": "nixpkgs-unstable" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000000000..709d13737ee5a --- /dev/null +++ b/flake.nix @@ -0,0 +1,45 @@ +{ + description = "PostgreSQL development environment"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05"; + nixpkgs-unstable.url = "github:nixos/nixpkgs/nixpkgs-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + }; + + outputs = { + self, + nixpkgs, + nixpkgs-unstable, + flake-utils, + }: + flake-utils.lib.eachDefaultSystem ( + system: let + pkgs = import nixpkgs { + inherit system; + config.allowUnfree = true; + }; + pkgs-unstable = import nixpkgs-unstable { + inherit system; + config.allowUnfree = true; + }; + + shellConfig = import ./shell.nix {inherit pkgs pkgs-unstable system;}; + in { + formatter = pkgs.alejandra; + devShells = { + default = shellConfig.devShell; + gcc = shellConfig.devShell; + clang = shellConfig.clangDevShell; + gcc-musl = shellConfig.muslDevShell; + clang-musl = shellConfig.clangMuslDevShell; + }; + + packages = { + inherit (shellConfig) gdbConfig flameGraphScript pgbenchScript; + }; + + environment.localBinInPath = true; + } + ); +} diff --git a/glibc-no-fortify-warning.patch b/glibc-no-fortify-warning.patch new file mode 100644 index 0000000000000..681e678e67ee3 --- /dev/null +++ b/glibc-no-fortify-warning.patch @@ -0,0 +1,24 @@ +From 130c231020f97e5eb878cc9fdb2bd9b186a5aa04 Mon Sep 17 00:00:00 2001 +From: Greg Burd +Date: Fri, 24 Oct 2025 11:58:24 -0400 +Subject: [PATCH] no warnings with -O0 and fortify source please + +--- + include/features.h | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/include/features.h b/include/features.h +index 673c4036..a02c8a3f 100644 +--- a/include/features.h ++++ b/include/features.h +@@ -432,7 +432,6 @@ + + #if defined _FORTIFY_SOURCE && _FORTIFY_SOURCE > 0 + # if !defined __OPTIMIZE__ || __OPTIMIZE__ <= 0 +-# warning _FORTIFY_SOURCE requires compiling with optimization (-O) + # elif !__GNUC_PREREQ (4, 1) + # warning _FORTIFY_SOURCE requires GCC 4.1 or later + # elif _FORTIFY_SOURCE > 2 && (__glibc_clang_prereq (9, 0) \ +-- +2.50.1 + diff --git a/pg-aliases.sh b/pg-aliases.sh new file mode 100644 index 0000000000000..80c5a67853c15 --- /dev/null +++ b/pg-aliases.sh @@ -0,0 +1,304 @@ +# PostgreSQL Development Aliases + +# Build system management +pg_clean_for_compiler() { + local current_compiler="$(basename $CC)" + local build_dir="$PG_BUILD_DIR" + + if [ -f "$build_dir/compile_commands.json" ]; then + local last_compiler=$(grep -o '/[^/]*/bin/[gc]cc\|/[^/]*/bin/clang' "$build_dir/compile_commands.json" | head -1 | xargs basename 2>/dev/null || echo "unknown") + + if [ "$last_compiler" != "$current_compiler" ] && [ "$last_compiler" != "unknown" ]; then + echo "Detected compiler change from $last_compiler to $current_compiler" + echo "Cleaning build directory..." + rm -rf "$build_dir" + mkdir -p "$build_dir" + fi + fi + + mkdir -p "$build_dir" + echo "$current_compiler" >"$build_dir/.compiler_used" +} + +# Core PostgreSQL commands +alias pg-setup=' + if [ -z "$PERL_CORE_DIR" ]; then + echo "Error: Could not find perl CORE directory" >&2 + return 1 + fi + + pg_clean_for_compiler + + echo "=== PostgreSQL Build Configuration ===" + echo "Compiler: $CC" + echo "LLVM: $(llvm-config --version 2>/dev/null || echo 'disabled')" + echo "Source: $PG_SOURCE_DIR" + echo "Build: $PG_BUILD_DIR" + echo "Install: $PG_INSTALL_DIR" + echo "======================================" + # --fatal-meson-warnings + + env CFLAGS="-I$PERL_CORE_DIR $CFLAGS" \ + LDFLAGS="-L$PERL_CORE_DIR -lperl $LDFLAGS" \ + meson setup $MESON_EXTRA_SETUP \ + --reconfigure \ + -Db_coverage=false \ + -Db_lundef=false \ + -Dcassert=true \ + -Ddebug=true \ + -Ddocs_html_style=website \ + -Ddocs_pdf=enabled \ + -Dicu=enabled \ + -Dinjection_points=true \ + -Dldap=enabled \ + -Dlibcurl=enabled \ + -Dlibxml=enabled \ + -Dlibxslt=enabled \ + -Dllvm=auto \ + -Dlz4=enabled \ + -Dnls=enabled \ + -Doptimization=g \ + -Dplperl=enabled \ + -Dplpython=enabled \ + -Dpltcl=enabled \ + -Dreadline=enabled \ + -Dssl=openssl \ + -Dtap_tests=enabled \ + -Duuid=e2fs \ + -Dzstd=enabled \ + --prefix="$PG_INSTALL_DIR" \ + "$PG_BUILD_DIR" \ + "$PG_SOURCE_DIR"' + +alias pg-compdb='compdb -p build/ list > compile_commands.json' +alias pg-build='meson compile -C "$PG_BUILD_DIR"' +alias pg-install='meson install -C "$PG_BUILD_DIR"' +alias pg-test='meson test -q --print-errorlogs -C "$PG_BUILD_DIR"' + +# Clean commands +alias pg-clean='ninja -C "$PG_BUILD_DIR" clean' +alias pg-full-clean='rm -rf "$PG_BUILD_DIR" "$PG_INSTALL_DIR" && echo "Build and install directories cleaned"' + +# Database management +alias pg-init='rm -rf "$PG_DATA_DIR" && "$PG_INSTALL_DIR/bin/initdb" --debug --no-clean "$PG_DATA_DIR"' +alias pg-start='"$PG_INSTALL_DIR/bin/postgres" -D "$PG_DATA_DIR" -k "$PG_DATA_DIR"' +alias pg-stop='pkill -f "postgres.*-D.*$PG_DATA_DIR" || true' +alias pg-restart='pg-stop && sleep 2 && pg-start' +alias pg-status='pgrep -f "postgres.*-D.*$PG_DATA_DIR" && echo "PostgreSQL is running" || echo "PostgreSQL is not running"' + +# Client connections +alias pg-psql='"$PG_INSTALL_DIR/bin/psql" -h "$PG_DATA_DIR" postgres' +alias pg-createdb='"$PG_INSTALL_DIR/bin/createdb" -h "$PG_DATA_DIR"' +alias pg-dropdb='"$PG_INSTALL_DIR/bin/dropdb" -h "$PG_DATA_DIR"' + +# Debugging +alias pg-debug-gdb='gdb -x "$GDBINIT" "$PG_INSTALL_DIR/bin/postgres"' +alias pg-debug-lldb='lldb "$PG_INSTALL_DIR/bin/postgres"' +alias pg-debug=' + if command -v gdb >/dev/null 2>&1; then + pg-debug-gdb + elif command -v lldb >/dev/null 2>&1; then + pg-debug-lldb + else + echo "No debugger available (gdb or lldb required)" + fi' + +# Attach to running process +alias pg-attach-gdb=' + PG_PID=$(pgrep -f "postgres.*-D.*$PG_DATA_DIR" | head -1) + if [ -n "$PG_PID" ]; then + echo "Attaching GDB to PostgreSQL process $PG_PID" + gdb -x "$GDBINIT" -p "$PG_PID" + else + echo "No PostgreSQL process found" + fi' + +alias pg-attach-lldb=' + PG_PID=$(pgrep -f "postgres.*-D.*$PG_DATA_DIR" | head -1) + if [ -n "$PG_PID" ]; then + echo "Attaching LLDB to PostgreSQL process $PG_PID" + lldb -p "$PG_PID" + else + echo "No PostgreSQL process found" + fi' + +alias pg-attach=' + if command -v gdb >/dev/null 2>&1; then + pg-attach-gdb + elif command -v lldb >/dev/null 2>&1; then + pg-attach-lldb + else + echo "No debugger available (gdb or lldb required)" + fi' + +# Performance profiling and analysis +alias pg-valgrind='valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all "$PG_INSTALL_DIR/bin/postgres" -D "$PG_DATA_DIR"' +alias pg-strace='strace -f -o /tmp/postgres.strace "$PG_INSTALL_DIR/bin/postgres" -D "$PG_DATA_DIR"' + +# Flame graph generation +alias pg-flame='pg-flame-generate' +alias pg-flame-30='pg-flame-generate 30' +alias pg-flame-60='pg-flame-generate 60' +alias pg-flame-120='pg-flame-generate 120' + +# Custom flame graph with specific duration and output +pg-flame-custom() { + local duration=${1:-30} + local output_dir=${2:-$PG_FLAME_DIR} + echo "Generating flame graph for ${duration}s, output to: $output_dir" + pg-flame-generate "$duration" "$output_dir" +} + +# Benchmarking with pgbench +alias pg-bench='pg-bench-run' +alias pg-bench-quick='pg-bench-run 5 1 100 1 30 select-only' +alias pg-bench-standard='pg-bench-run 10 2 1000 10 60 tpcb-like' +alias pg-bench-heavy='pg-bench-run 50 4 5000 100 300 tpcb-like' +alias pg-bench-readonly='pg-bench-run 20 4 2000 50 120 select-only' + +# Custom benchmark function +pg-bench-custom() { + local clients=${1:-10} + local threads=${2:-2} + local transactions=${3:-1000} + local scale=${4:-10} + local duration=${5:-60} + local test_type=${6:-tpcb-like} + + echo "Running custom benchmark:" + echo " Clients: $clients, Threads: $threads" + echo " Transactions: $transactions, Scale: $scale" + echo " Duration: ${duration}s, Type: $test_type" + + pg-bench-run "$clients" "$threads" "$transactions" "$scale" "$duration" "$test_type" +} + +# Benchmark with flame graph +pg-bench-flame() { + local duration=${1:-60} + local clients=${2:-10} + local scale=${3:-10} + + echo "Running benchmark with flame graph generation" + echo "Duration: ${duration}s, Clients: $clients, Scale: $scale" + + # Start benchmark in background + pg-bench-run "$clients" 2 1000 "$scale" "$duration" tpcb-like & + local bench_pid=$! + + # Wait a bit for benchmark to start + sleep 5 + + # Generate flame graph for most of the benchmark duration + local flame_duration=$((duration - 10)) + if [ $flame_duration -gt 10 ]; then + pg-flame-generate "$flame_duration" & + local flame_pid=$! + fi + + # Wait for benchmark to complete + wait $bench_pid + + # Wait for flame graph if it was started + if [ -n "${flame_pid:-}" ]; then + wait $flame_pid + fi + + echo "Benchmark and flame graph generation completed" +} + +# Performance monitoring +alias pg-perf='perf top -p $(pgrep -f "postgres.*-D.*$PG_DATA_DIR" | head -1)' +alias pg-htop='htop -p $(pgrep -f "postgres.*-D.*$PG_DATA_DIR" | tr "\n" "," | sed "s/,$//")' + +# System performance stats during PostgreSQL operation +pg-stats() { + local duration=${1:-30} + echo "Collecting system stats for ${duration}s..." + + iostat -x 1 "$duration" >"$PG_BENCH_DIR/iostat_$(date +%Y%m%d_%H%M%S).log" & + vmstat 1 "$duration" >"$PG_BENCH_DIR/vmstat_$(date +%Y%m%d_%H%M%S).log" & + + wait + echo "System stats saved to $PG_BENCH_DIR" +} + +# Development helpers +pg-format() { + local since=${1:-HEAD} + + if [ ! -f "$PG_SOURCE_DIR/src/tools/pgindent/pgindent" ]; then + echo "Error: pgindent not found at $PG_SOURCE_DIR/src/tools/pgindent/pgindent" + else + + modified_files=$(git diff --name-only "${since}" | grep -E "\.c$|\.h$") + + if [ -z "$modified_files" ]; then + echo "No modified .c or .h files found" + else + + echo "Formatting modified files with pgindent:" + for file in $modified_files; do + if [ -f "$file" ]; then + echo " Formatting: $file" + "$PG_SOURCE_DIR/src/tools/pgindent/pgindent" "$file" + else + echo " Warning: File not found: $file" + fi + done + + echo "Checking files for whitespace:" + git diff --check "${since}" + fi + fi +} + +alias pg-tidy='find "$PG_SOURCE_DIR" -name "*.c" | head -10 | xargs clang-tidy' + +# Log management +alias pg-log='tail -f "$PG_DATA_DIR/log/postgresql-$(date +%Y-%m-%d).log" 2>/dev/null || echo "No log file found"' +alias pg-log-errors='grep -i error "$PG_DATA_DIR/log/"*.log 2>/dev/null || echo "No error logs found"' + +# Build logs +alias pg-build-log='cat "$PG_BUILD_DIR/meson-logs/meson-log.txt"' +alias pg-build-errors='grep -i error "$PG_BUILD_DIR/meson-logs/meson-log.txt" 2>/dev/null || echo "No build errors found"' + +# Results viewing +alias pg-bench-results='ls -la "$PG_BENCH_DIR" && echo "Latest results:" && tail -20 "$PG_BENCH_DIR"/results_*.txt 2>/dev/null | tail -20' +alias pg-flame-results='ls -la "$PG_FLAME_DIR" && echo "Open flame graphs with: firefox $PG_FLAME_DIR/*.svg"' + +# Clean up old results +pg-clean-results() { + local days=${1:-7} + echo "Cleaning benchmark and flame graph results older than $days days..." + find "$PG_BENCH_DIR" -type f -mtime +$days -delete 2>/dev/null || true + find "$PG_FLAME_DIR" -type f -mtime +$days -delete 2>/dev/null || true + echo "Cleanup completed" +} + +# Information +alias pg-info=' + echo "=== PostgreSQL Development Environment ===" + echo "Source: $PG_SOURCE_DIR" + echo "Build: $PG_BUILD_DIR" + echo "Install: $PG_INSTALL_DIR" + echo "Data: $PG_DATA_DIR" + echo "Benchmarks: $PG_BENCH_DIR" + echo "Flame graphs: $PG_FLAME_DIR" + echo "Compiler: $CC" + echo "" + echo "Available commands:" + echo " Setup: pg-setup, pg-build, pg-install" + echo " Database: pg-init, pg-start, pg-stop, pg-psql" + echo " Debug: pg-debug, pg-attach, pg-valgrind" + echo " Performance: pg-flame, pg-bench, pg-perf" + echo " Benchmarks: pg-bench-quick, pg-bench-standard, pg-bench-heavy" + echo " Flame graphs: pg-flame-30, pg-flame-60, pg-flame-custom" + echo " Combined: pg-bench-flame" + echo " Results: pg-bench-results, pg-flame-results" + echo " Logs: pg-log, pg-build-log" + echo " Clean: pg-clean, pg-full-clean, pg-clean-results" + echo " Code quality: pg-format, pg-tidy" + echo "=========================================="' + +echo "PostgreSQL aliases loaded. Run 'pg-info' for available commands." diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000000000..130d5b21986b2 --- /dev/null +++ b/shell.nix @@ -0,0 +1,820 @@ +{ + pkgs, + pkgs-unstable, + system, +}: let + # Create a patched glibc only for the dev shell + patchedGlibc = pkgs.glibc.overrideAttrs (oldAttrs: { + patches = (oldAttrs.patches or []) ++ [ + ./glibc-no-fortify-warning.patch + ]; + }); + + llvmPkgs = pkgs-unstable.llvmPackages_21; + + # Configuration constants + config = { + pgSourceDir = "$PWD"; + pgBuildDir = "$PWD/build"; + pgInstallDir = "$PWD/install"; + pgDataDir = "/tmp/test-db-$(basename $PWD)"; + pgBenchDir = "/tmp/pgbench-results-$(basename $PWD)"; + pgFlameDir = "/tmp/flame-graphs-$(basename $PWD)"; + }; + + # Single dependency function that can be used for all environments + getPostgreSQLDeps = muslLibs: + with pkgs; + [ + # Build system (always use host tools) + pkgs-unstable.meson + pkgs-unstable.ninja + pkg-config + autoconf + libtool + git + which + binutils + gnumake + + # Parser/lexer tools + bison + flex + + # Documentation + docbook_xml_dtd_45 + docbook-xsl-nons + fop + gettext + libxslt + libxml2 + + # Development tools (always use host tools) + coreutils + shellcheck + ripgrep + valgrind + curl + uv + pylint + black + lcov + strace + ltrace + perf-tools + linuxPackages.perf + flamegraph + htop + iotop + sysstat + ccache + cppcheck + compdb + + # GCC/GDB +# pkgs-unstable.gcc15 + gcc + gdb + + # LLVM toolchain + llvmPkgs.llvm + llvmPkgs.llvm.dev + llvmPkgs.clang-tools + llvmPkgs.lldb + + # Language support + (perl.withPackages (ps: with ps; [IPCRun])) + (python3.withPackages (ps: with ps; [requests browser-cookie3])) + tcl + ] + ++ ( + if muslLibs + then [ + # Musl target libraries for cross-compilation + pkgs.pkgsMusl.readline + pkgs.pkgsMusl.zlib + pkgs.pkgsMusl.openssl + pkgs.pkgsMusl.icu + pkgs.pkgsMusl.lz4 + pkgs.pkgsMusl.zstd + pkgs.pkgsMusl.libuuid + pkgs.pkgsMusl.libkrb5 + pkgs.pkgsMusl.linux-pam + pkgs.pkgsMusl.libxcrypt + ] + else [ + # Glibc target libraries + readline + zlib + openssl + icu + lz4 + zstd + libuuid + libkrb5 + linux-pam + libxcrypt + numactl + openldap + liburing + libselinux + patchedGlibc + glibcInfo + glibc.dev + ] + ); + + # GDB configuration for PostgreSQL debugging + gdbConfig = pkgs.writeText "gdbinit-postgres" '' + # PostgreSQL-specific GDB configuration + + # Pretty-print PostgreSQL data structures + define print_node + if $arg0 + printf "Node type: %s\n", nodeTagNames[$arg0->type] + print *$arg0 + else + printf "NULL node\n" + end + end + document print_node + Print a PostgreSQL Node with type information + Usage: print_node + end + + define print_list + set $list = (List*)$arg0 + if $list + printf "List length: %d\n", $list->length + set $cell = $list->head + set $i = 0 + while $cell && $i < $list->length + printf " [%d]: ", $i + print_node $cell->data.ptr_value + set $cell = $cell->next + set $i = $i + 1 + end + else + printf "NULL list\n" + end + end + document print_list + Print a PostgreSQL List structure + Usage: print_list + end + + define print_query + set $query = (Query*)$arg0 + if $query + printf "Query type: %d, command type: %d\n", $query->querySource, $query->commandType + print *$query + else + printf "NULL query\n" + end + end + document print_query + Print a PostgreSQL Query structure + Usage: print_query + end + + define print_relcache + set $rel = (Relation)$arg0 + if $rel + printf "Relation: %s.%s (OID: %u)\n", $rel->rd_rel->relnamespace, $rel->rd_rel->relname.data, $rel->rd_id + printf " natts: %d, relkind: %c\n", $rel->rd_rel->relnatts, $rel->rd_rel->relkind + else + printf "NULL relation\n" + end + end + document print_relcache + Print relation cache entry information + Usage: print_relcache + end + + define print_tupdesc + set $desc = (TupleDesc)$arg0 + if $desc + printf "TupleDesc: %d attributes\n", $desc->natts + set $i = 0 + while $i < $desc->natts + set $attr = $desc->attrs[$i] + printf " [%d]: %s (type: %u, len: %d)\n", $i, $attr->attname.data, $attr->atttypid, $attr->attlen + set $i = $i + 1 + end + else + printf "NULL tuple descriptor\n" + end + end + document print_tupdesc + Print tuple descriptor information + Usage: print_tupdesc + end + + define print_slot + set $slot = (TupleTableSlot*)$arg0 + if $slot + printf "TupleTableSlot: %s\n", $slot->tts_ops->name + printf " empty: %d, shouldFree: %d\n", $slot->tts_empty, $slot->tts_shouldFree + if $slot->tts_tupleDescriptor + print_tupdesc $slot->tts_tupleDescriptor + end + else + printf "NULL slot\n" + end + end + document print_slot + Print tuple table slot information + Usage: print_slot + end + + # Memory context debugging + define print_mcxt + set $context = (MemoryContext)$arg0 + if $context + printf "MemoryContext: %s\n", $context->name + printf " type: %s, parent: %p\n", $context->methods->name, $context->parent + printf " total: %zu, free: %zu\n", $context->mem_allocated, $context->freep - $context->freeptr + else + printf "NULL memory context\n" + end + end + document print_mcxt + Print memory context information + Usage: print_mcxt + end + + # Process debugging + define print_proc + set $proc = (PGPROC*)$arg0 + if $proc + printf "PGPROC: pid=%d, database=%u\n", $proc->pid, $proc->databaseId + printf " waiting: %d, waitStatus: %d\n", $proc->waiting, $proc->waitStatus + else + printf "NULL process\n" + end + end + document print_proc + Print process information + Usage: print_proc + end + + # Set useful defaults + set print pretty on + set print object on + set print static-members off + set print vtbl on + set print demangle on + set demangle-style gnu-v3 + set print sevenbit-strings off + set history save on + set history size 1000 + set history filename ~/.gdb_history_postgres + + # Common breakpoints for PostgreSQL debugging + define pg_break_common + break elog + break errfinish + break ExceptionalCondition + break ProcessInterrupts + end + document pg_break_common + Set common PostgreSQL debugging breakpoints + end + + printf "PostgreSQL GDB configuration loaded.\n" + printf "Available commands: print_node, print_list, print_query, print_relcache,\n" + printf " print_tupdesc, print_slot, print_mcxt, print_proc, pg_break_common\n" + ''; + + # Flame graph generation script + flameGraphScript = pkgs.writeScriptBin "pg-flame-generate" '' + #!${pkgs.bash}/bin/bash + set -euo pipefail + + DURATION=''${1:-30} + OUTPUT_DIR=''${2:-${config.pgFlameDir}} + TIMESTAMP=$(date +%Y%m%d_%H%M%S) + + mkdir -p "$OUTPUT_DIR" + + echo "Generating flame graph for PostgreSQL (duration: ''${DURATION}s)" + + # Find PostgreSQL processes + PG_PIDS=$(pgrep -f "postgres.*-D.*${config.pgDataDir}" || true) + + if [ -z "$PG_PIDS" ]; then + echo "Error: No PostgreSQL processes found" + exit 1 + fi + + echo "Found PostgreSQL processes: $PG_PIDS" + + # Record perf data + PERF_DATA="$OUTPUT_DIR/perf_$TIMESTAMP.data" + echo "Recording perf data to $PERF_DATA" + + ${pkgs.linuxPackages.perf}/bin/perf record \ + -F 997 \ + -g \ + --call-graph dwarf \ + -p "$(echo $PG_PIDS | tr ' ' ',')" \ + -o "$PERF_DATA" \ + sleep "$DURATION" + + # Generate flame graph + FLAME_SVG="$OUTPUT_DIR/postgres_flame_$TIMESTAMP.svg" + echo "Generating flame graph: $FLAME_SVG" + + ${pkgs.linuxPackages.perf}/bin/perf script -i "$PERF_DATA" | \ + ${pkgs.flamegraph}/bin/stackcollapse-perf.pl | \ + ${pkgs.flamegraph}/bin/flamegraph.pl \ + --title "PostgreSQL Flame Graph ($TIMESTAMP)" \ + --width 1200 \ + --height 800 \ + > "$FLAME_SVG" + + echo "Flame graph generated: $FLAME_SVG" + echo "Perf data saved: $PERF_DATA" + + # Generate summary report + REPORT="$OUTPUT_DIR/report_$TIMESTAMP.txt" + echo "Generating performance report: $REPORT" + + { + echo "PostgreSQL Performance Analysis Report" + echo "Generated: $(date)" + echo "Duration: ''${DURATION}s" + echo "Processes: $PG_PIDS" + echo "" + echo "=== Top Functions ===" + ${pkgs.linuxPackages.perf}/bin/perf report -i "$PERF_DATA" --stdio --sort comm,dso,symbol | head -50 + echo "" + echo "=== Call Graph ===" + ${pkgs.linuxPackages.perf}/bin/perf report -i "$PERF_DATA" --stdio -g --sort comm,dso,symbol | head -100 + } > "$REPORT" + + echo "Report generated: $REPORT" + echo "" + echo "Files created:" + echo " Flame graph: $FLAME_SVG" + echo " Perf data: $PERF_DATA" + echo " Report: $REPORT" + ''; + + # pgbench wrapper script + pgbenchScript = pkgs.writeScriptBin "pg-bench-run" '' + #!${pkgs.bash}/bin/bash + set -euo pipefail + + # Default parameters + CLIENTS=''${1:-10} + THREADS=''${2:-2} + TRANSACTIONS=''${3:-1000} + SCALE=''${4:-10} + DURATION=''${5:-60} + TEST_TYPE=''${6:-tpcb-like} + + OUTPUT_DIR="${config.pgBenchDir}" + TIMESTAMP=$(date +%Y%m%d_%H%M%S) + + mkdir -p "$OUTPUT_DIR" + + echo "=== PostgreSQL Benchmark Configuration ===" + echo "Clients: $CLIENTS" + echo "Threads: $THREADS" + echo "Transactions: $TRANSACTIONS" + echo "Scale factor: $SCALE" + echo "Duration: ''${DURATION}s" + echo "Test type: $TEST_TYPE" + echo "Output directory: $OUTPUT_DIR" + echo "============================================" + + # Check if PostgreSQL is running + if ! pgrep -f "postgres.*-D.*${config.pgDataDir}" >/dev/null; then + echo "Error: PostgreSQL is not running. Start it with 'pg-start'" + exit 1 + fi + + PGBENCH="${config.pgInstallDir}/bin/pgbench" + PSQL="${config.pgInstallDir}/bin/psql" + CREATEDB="${config.pgInstallDir}/bin/createdb" + DROPDB="${config.pgInstallDir}/bin/dropdb" + + DB_NAME="pgbench_test_$TIMESTAMP" + RESULTS_FILE="$OUTPUT_DIR/results_$TIMESTAMP.txt" + LOG_FILE="$OUTPUT_DIR/pgbench_$TIMESTAMP.log" + + echo "Creating test database: $DB_NAME" + "$CREATEDB" -h "${config.pgDataDir}" "$DB_NAME" || { + echo "Failed to create database" + exit 1 + } + + # Initialize pgbench tables + echo "Initializing pgbench tables (scale factor: $SCALE)" + "$PGBENCH" -h "${config.pgDataDir}" -i -s "$SCALE" "$DB_NAME" || { + echo "Failed to initialize pgbench tables" + "$DROPDB" -h "${config.pgDataDir}" "$DB_NAME" 2>/dev/null || true + exit 1 + } + + # Run benchmark based on test type + echo "Running benchmark..." + + case "$TEST_TYPE" in + "tpcb-like"|"default") + BENCH_ARGS="" + ;; + "select-only") + BENCH_ARGS="-S" + ;; + "simple-update") + BENCH_ARGS="-N" + ;; + "read-write") + BENCH_ARGS="-b select-only@70 -b tpcb-like@30" + ;; + *) + echo "Unknown test type: $TEST_TYPE" + echo "Available types: tpcb-like, select-only, simple-update, read-write" + "$DROPDB" -h "${config.pgDataDir}" "$DB_NAME" 2>/dev/null || true + exit 1 + ;; + esac + + { + echo "PostgreSQL Benchmark Results" + echo "Generated: $(date)" + echo "Test type: $TEST_TYPE" + echo "Clients: $CLIENTS, Threads: $THREADS" + echo "Transactions: $TRANSACTIONS, Duration: ''${DURATION}s" + echo "Scale factor: $SCALE" + echo "Database: $DB_NAME" + echo "" + echo "=== System Information ===" + echo "CPU: $(nproc) cores" + echo "Memory: $(free -h | grep '^Mem:' | awk '{print $2}')" + echo "Compiler: $CC" + echo "PostgreSQL version: $("$PSQL" --no-psqlrc -h "${config.pgDataDir}" -d "$DB_NAME" -t -c "SELECT version();" | head -1)" + echo "" + echo "=== Benchmark Results ===" + } > "$RESULTS_FILE" + + # Run the actual benchmark + "$PGBENCH" \ + -h "${config.pgDataDir}" \ + -c "$CLIENTS" \ + -j "$THREADS" \ + -T "$DURATION" \ + -P 5 \ + --log \ + --log-prefix="$OUTPUT_DIR/pgbench_$TIMESTAMP" \ + $BENCH_ARGS \ + "$DB_NAME" 2>&1 | tee -a "$RESULTS_FILE" + + # Collect additional statistics + { + echo "" + echo "=== Database Statistics ===" + "$PSQL" --no-psqlrc -h "${config.pgDataDir}" -d "$DB_NAME" -c " + SELECT + schemaname, + relname, + n_tup_ins as inserts, + n_tup_upd as updates, + n_tup_del as deletes, + n_live_tup as live_tuples, + n_dead_tup as dead_tuples + FROM pg_stat_user_tables; + " + + echo "" + echo "=== Index Statistics ===" + "$PSQL" --no-psqlrc -h "${config.pgDataDir}" -d "$DB_NAME" -c " + SELECT + schemaname, + relname, + indexrelname, + idx_scan, + idx_tup_read, + idx_tup_fetch + FROM pg_stat_user_indexes; + " + } >> "$RESULTS_FILE" + + # Clean up + echo "Cleaning up test database: $DB_NAME" + "$DROPDB" -h "${config.pgDataDir}" "$DB_NAME" 2>/dev/null || true + + echo "" + echo "Benchmark completed!" + echo "Results saved to: $RESULTS_FILE" + echo "Transaction logs: $OUTPUT_DIR/pgbench_$TIMESTAMP*" + + # Show summary + echo "" + echo "=== Quick Summary ===" + grep -E "(tps|latency)" "$RESULTS_FILE" | tail -5 + ''; + + # Development shell (GCC + glibc) + devShell = pkgs.mkShell { + name = "postgresql-dev"; + buildInputs = + (getPostgreSQLDeps false) + ++ [ + flameGraphScript + pgbenchScript + ]; + + shellHook = let + icon = "f121"; + in '' + # History configuration + export HISTFILE=.history + export HISTSIZE=1000000 + export HISTFILESIZE=1000000 + + # Clean environment + unset LD_LIBRARY_PATH LD_PRELOAD LIBRARY_PATH C_INCLUDE_PATH CPLUS_INCLUDE_PATH + + # Essential tools in PATH + export PATH="${pkgs.which}/bin:${pkgs.coreutils}/bin:$PATH" + export PS1="$(echo -e '\u${icon}') {\[$(tput sgr0)\]\[\033[38;5;228m\]\w\[$(tput sgr0)\]\[\033[38;5;15m\]} ($(git rev-parse --abbrev-ref HEAD)) \\$ \[$(tput sgr0)\]" + + # Ccache configuration + export PATH=${pkgs.ccache}/bin:$PATH + export CCACHE_COMPILERCHECK=content + export CCACHE_DIR=$HOME/.ccache/pg/$(basename $PWD) + mkdir -p "$CCACHE_DIR" + + # LLVM configuration + export LLVM_CONFIG="${llvmPkgs.llvm}/bin/llvm-config" + export PATH="${llvmPkgs.llvm}/bin:$PATH" + export PKG_CONFIG_PATH="${llvmPkgs.llvm.dev}/lib/pkgconfig:$PKG_CONFIG_PATH" + export LLVM_DIR="${llvmPkgs.llvm.dev}/lib/cmake/llvm" + export LLVM_ROOT="${llvmPkgs.llvm}" + + # Development tools in PATH + export PATH=${pkgs.clang-tools}/bin:$PATH + export PATH=${pkgs.cppcheck}/bin:$PATH + + # PosgreSQL Development CFLAGS + # -DRELCACHE_FORCE_RELEASE -DCATCACHE_FORCE_RELEASE -fno-omit-frame-pointer -fno-stack-protector -DUSE_VALGRIND + export CFLAGS="" + export CXXFLAGS="" + + # Python UV + UV_PYTHON_DOWNLOADS=never + + # GCC configuration (default compiler) + export CC="${pkgs.gcc}/bin/gcc" + export CXX="${pkgs.gcc}/bin/g++" + + # PostgreSQL environment + export PG_SOURCE_DIR="${config.pgSourceDir}" + export PG_BUILD_DIR="${config.pgBuildDir}" + export PG_INSTALL_DIR="${config.pgInstallDir}" + export PG_DATA_DIR="${config.pgDataDir}" + export PG_BENCH_DIR="${config.pgBenchDir}" + export PG_FLAME_DIR="${config.pgFlameDir}" + export PERL_CORE_DIR=$(find ${pkgs.perl} -maxdepth 5 -path "*/CORE" -type d) + + # GDB configuration + export GDBINIT="${gdbConfig}" + + # Performance tools in PATH + export PATH="${flameGraphScript}/bin:${pgbenchScript}/bin:$PATH" + + # Create output directories + mkdir -p "$PG_BENCH_DIR" "$PG_FLAME_DIR" + + # Compiler verification + echo "Environment configured:" + echo " Compiler: $CC" + echo " libc: glibc" + echo " LLVM: $(llvm-config --version 2>/dev/null || echo 'not available')" + + # Load PostgreSQL development aliases + if [ -f ./pg-aliases.sh ]; then + source ./pg-aliases.sh + else + echo "Warning: pg-aliases.sh not found in current directory" + fi + + echo "" + echo "PostgreSQL Development Environment Ready (GCC + glibc)" + echo "Run 'pg-info' for available commands" + ''; + }; + + # Clang + glibc variant + clangDevShell = pkgs.mkShell { + name = "postgresql-clang-glibc"; + buildInputs = + (getPostgreSQLDeps false) + ++ [ + llvmPkgs.clang + llvmPkgs.lld + llvmPkgs.compiler-rt + flameGraphScript + pgbenchScript + ]; + + shellHook = let + icon = "f121"; + in '' + # History configuration + export HISTFILE=.history + export HISTSIZE=1000000 + export HISTFILESIZE=1000000 + + # Clean environment + unset LD_LIBRARY_PATH LD_PRELOAD LIBRARY_PATH C_INCLUDE_PATH CPLUS_INCLUDE_PATH + + # Essential tools in PATH + export PATH="${pkgs.which}/bin:${pkgs.coreutils}/bin:$PATH" + export PS1="$(echo -e '\u${icon}') {\[$(tput sgr0)\]\[\033[38;5;228m\]\w\[$(tput sgr0)\]\[\033[38;5;15m\]} ($(git rev-parse --abbrev-ref HEAD)) \\$ \[$(tput sgr0)\]" + + # Ccache configuration + export PATH=${pkgs.ccache}/bin:$PATH + export CCACHE_COMPILERCHECK=content + export CCACHE_DIR=$HOME/.ccache_pg_dev_clang + mkdir -p "$CCACHE_DIR" + + # LLVM configuration + export LLVM_CONFIG="${llvmPkgs.llvm}/bin/llvm-config" + export PATH="${llvmPkgs.llvm}/bin:$PATH" + export PKG_CONFIG_PATH="${llvmPkgs.llvm.dev}/lib/pkgconfig:$PKG_CONFIG_PATH" + export LLVM_DIR="${llvmPkgs.llvm.dev}/lib/cmake/llvm" + export LLVM_ROOT="${llvmPkgs.llvm}" + + # Development tools in PATH + export PATH=${pkgs.clang-tools}/bin:$PATH + export PATH=${pkgs.cppcheck}/bin:$PATH + + # Clang + glibc configuration - use system linker instead of LLD for compatibility + export CC="${llvmPkgs.clang}/bin/clang" + export CXX="${llvmPkgs.clang}/bin/clang++" + + # Use system linker and standard runtime + #export CFLAGS="" + #export CXXFLAGS="" + #export LDFLAGS="" + + # PostgreSQL environment + export PG_SOURCE_DIR="${config.pgSourceDir}" + export PG_BUILD_DIR="${config.pgBuildDir}" + export PG_INSTALL_DIR="${config.pgInstallDir}" + export PG_DATA_DIR="${config.pgDataDir}" + export PG_BENCH_DIR="${config.pgBenchDir}" + export PG_FLAME_DIR="${config.pgFlameDir}" + export PERL_CORE_DIR=$(find ${pkgs.perl} -maxdepth 5 -path "*/CORE" -type d) + + # GDB configuration + export GDBINIT="${gdbConfig}" + + # Performance tools in PATH + export PATH="${flameGraphScript}/bin:${pgbenchScript}/bin:$PATH" + + # Create output directories + mkdir -p "$PG_BENCH_DIR" "$PG_FLAME_DIR" + + # Compiler verification + echo "Environment configured:" + echo " Compiler: $CC" + echo " libc: glibc" + echo " LLVM: $(llvm-config --version 2>/dev/null || echo 'not available')" + + # Load PostgreSQL development aliases + if [ -f ./pg-aliases.sh ]; then + source ./pg-aliases.sh + else + echo "Warning: pg-aliases.sh not found in current directory" + fi + + echo "" + echo "PostgreSQL Development Environment Ready (Clang + glibc)" + echo "Run 'pg-info' for available commands" + ''; + }; + + # GCC + musl variant (cross-compilation) + muslDevShell = pkgs.mkShell { + name = "postgresql-gcc-musl"; + buildInputs = + (getPostgreSQLDeps true) + ++ [ + pkgs.gcc + flameGraphScript + pgbenchScript + ]; + + shellHook = '' + # Same base configuration as main shell + export HISTFILE=.history + export HISTSIZE=1000000 + export HISTFILESIZE=1000000 + + unset LD_LIBRARY_PATH LD_PRELOAD LIBRARY_PATH C_INCLUDE_PATH CPLUS_INCLUDE_PATH + + export PATH="${pkgs.which}/bin:${pkgs.coreutils}/bin:$PATH" + + # Cross-compilation to musl + export CC="${pkgs.gcc}/bin/gcc" + export CXX="${pkgs.gcc}/bin/g++" + + # Point to musl libraries for linking + export PKG_CONFIG_PATH="${pkgs.pkgsMusl.openssl.dev}/lib/pkgconfig:${pkgs.pkgsMusl.zlib.dev}/lib/pkgconfig:${pkgs.pkgsMusl.icu.dev}/lib/pkgconfig" + export CFLAGS="-ggdb -Og -fno-omit-frame-pointer -DUSE_VALGRIND -D_FORTIFY_SOURCE=1 -I${pkgs.pkgsMusl.stdenv.cc.libc}/include" + export CXXFLAGS="-ggdb -Og -fno-omit-frame-pointer -DUSE_VALGRIND -D_FORTIFY_SOURCE=1 -I${pkgs.pkgsMusl.stdenv.cc.libc}/include" + export LDFLAGS="-L${pkgs.pkgsMusl.stdenv.cc.libc}/lib -static-libgcc" + + # PostgreSQL environment + export PG_SOURCE_DIR="${config.pgSourceDir}" + export PG_BUILD_DIR="${config.pgBuildDir}" + export PG_INSTALL_DIR="${config.pgInstallDir}" + export PG_DATA_DIR="${config.pgDataDir}" + export PG_BENCH_DIR="${config.pgBenchDir}" + export PG_FLAME_DIR="${config.pgFlameDir}" + export PERL_CORE_DIR=$(find ${pkgs.perl} -maxdepth 5 -path "*/CORE" -type d) + + export GDBINIT="${gdbConfig}" + export PATH="${flameGraphScript}/bin:${pgbenchScript}/bin:$PATH" + + mkdir -p "$PG_BENCH_DIR" "$PG_FLAME_DIR" + + echo "GCC + musl environment configured" + echo " Compiler: $CC" + echo " LibC: musl (cross-compilation)" + + if [ -f ./pg-aliases.sh ]; then + source ./pg-aliases.sh + fi + + echo "PostgreSQL Development Environment Ready (GCC + musl)" + ''; + }; + + # Clang + musl variant (cross-compilation) + clangMuslDevShell = pkgs.mkShell { + name = "postgresql-clang-musl"; + buildInputs = + (getPostgreSQLDeps true) + ++ [ + llvmPkgs.clang + llvmPkgs.lld + flameGraphScript + pgbenchScript + ]; + + shellHook = let + icon = "f121"; + in '' + export HISTFILE=.history + export HISTSIZE=1000000 + export HISTFILESIZE=1000000 + + unset LD_LIBRARY_PATH LD_PRELOAD LIBRARY_PATH C_INCLUDE_PATH CPLUS_INCLUDE_PATH + + export PATH="${pkgs.which}/bin:${pkgs.coreutils}/bin:$PATH" + export PS1="$(echo -e '\u${icon}') {\[$(tput sgr0)\]\[\033[38;5;228m\]\w\[$(tput sgr0)\]\[\033[38;5;15m\]} ($(git rev-parse --abbrev-ref HEAD)) \\$ \[$(tput sgr0)\]" + + # Cross-compilation to musl with clang + export CC="${llvmPkgs.clang}/bin/clang" + export CXX="${llvmPkgs.clang}/bin/clang++" + + # Point to musl libraries for linking + export PKG_CONFIG_PATH="${pkgs.pkgsMusl.openssl.dev}/lib/pkgconfig:${pkgs.pkgsMusl.zlib.dev}/lib/pkgconfig:${pkgs.pkgsMusl.icu.dev}/lib/pkgconfig" + export CFLAGS="--target=x86_64-linux-musl -ggdb -Og -fno-omit-frame-pointer -DUSE_VALGRIND -D_FORTIFY_SOURCE=1 -I${pkgs.pkgsMusl.stdenv.cc.libc}/include" + export CXXFLAGS="--target=x86_64-linux-musl -ggdb -Og -fno-omit-frame-pointer -DUSE_VALGRIND -D_FORTIFY_SOURCE=1 -I${pkgs.pkgsMusl.stdenv.cc.libc}/include" + export LDFLAGS="--target=x86_64-linux-musl -L${pkgs.pkgsMusl.stdenv.cc.libc}/lib -fuse-ld=lld" + + # PostgreSQL environment + export PG_SOURCE_DIR="${config.pgSourceDir}" + export PG_BUILD_DIR="${config.pgBuildDir}" + export PG_INSTALL_DIR="${config.pgInstallDir}" + export PG_DATA_DIR="${config.pgDataDir}" + export PG_BENCH_DIR="${config.pgBenchDir}" + export PG_FLAME_DIR="${config.pgFlameDir}" + export PERL_CORE_DIR=$(find ${pkgs.perl} -maxdepth 5 -path "*/CORE" -type d) + + export GDBINIT="${gdbConfig}" + export PATH="${flameGraphScript}/bin:${pgbenchScript}/bin:$PATH" + + mkdir -p "$PG_BENCH_DIR" "$PG_FLAME_DIR" + + echo "Clang + musl environment configured" + echo " Compiler: $CC" + echo " LibC: musl (cross-compilation)" + + if [ -f ./pg-aliases.sh ]; then + source ./pg-aliases.sh + fi + + echo "PostgreSQL Development Environment Ready (Clang + musl)" + ''; + }; +in { + inherit devShell clangDevShell muslDevShell clangMuslDevShell gdbConfig flameGraphScript pgbenchScript; +} diff --git a/src/test/regress/pg_regress.c b/src/test/regress/pg_regress.c index efc41fca2ba79..0a8fc7f181c25 100644 --- a/src/test/regress/pg_regress.c +++ b/src/test/regress/pg_regress.c @@ -1232,7 +1232,7 @@ spawn_process(const char *cmdline) char *cmdline2; cmdline2 = psprintf("exec %s", cmdline); - execl(shellprog, shellprog, "-c", cmdline2, (char *) NULL); + execlp(shellprog, shellprog, "-c", cmdline2, (char *) NULL); /* Not using the normal bail() here as we want _exit */ bail_noatexit("could not exec \"%s\": %m", shellprog); } diff --git a/src/tools/pgindent/pgindent b/src/tools/pgindent/pgindent index d14da3f01a995..18ef572a8be6c 100755 --- a/src/tools/pgindent/pgindent +++ b/src/tools/pgindent/pgindent @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/bin/env perl # Copyright (c) 2021-2025, PostgreSQL Global Development Group From 113d72ca94ff38fb1c1531affdfb8fcee873cfe8 Mon Sep 17 00:00:00 2001 From: Greg Burd Date: Fri, 14 Nov 2025 08:02:31 -0500 Subject: [PATCH 2/3] Refactor how we form HeapTuples for CatalogTuple(Insert|Update) This commit provides a set of macros that should be used when inserting or updating tuples before calling CatalogTupleUpdate() or CatalogTupleInsert(). Historically there have been two methods for accomplishing this task; Form/GETSTRUCT, and values/nulls/replaces. This new method provides a more intuitive and less error-prone approach without changing the fundamentals of the process. In addition, it is now possible to retain knowledge of the set of mutated attributes when working with catalog tuples. This isn't used in practice (yet), but could be a way to avoid the overhead of HeapDetermineColumnsInfo() in heap_update() where (while holding a lock) we re-discover that set by comparing old/new HeapTuple datums when trying to find what indexed attributes have new values and prevent HOT updates. The "Form/GETSTRUCT" model allows for direct access to the tuple data that is then modified, copied, and then updated via CatalogTupleUpdate(). Old: Form_pg_index relform = (Form_pg_index) GETSTRUCT(tuple); relform->inisclustered = false; CatalogTupleUpdate(pg_index, &tuple->t_self, tuple); New: Bitmapset *updated = NULL; Form_pg_index relform = (Form_pg_index) GETSTRUCT(tuple); HeapTupleUpdateField(pg_index, indisclustered, false, indexForm, updated); CatalogTupleUpdate(pg_index, &indexTuple->t_self, indexTuple, updated, NULL); bms_free(updated); The "values/nulls/replaces" model collects the necessary information to either update or create a heap tuple using heap_modify_tuple() or heap_form_tuple() or sometimes heap_modify_tuple_by_cols(). While all those functions remain unchanged now the prefered function for catalog tuple modification is heap_update_tuple(). Old: bool nulls[Natts_pg_type]; bool replaces[Natts_pg_type]; Datum values[Natts_pg_type]; values[Anum_pg_type_typtype - 1] = CharGetDatum(typeType); nulls[Anum_pg_type_typdefaultbin - 1] = true; replaces[Anum_pg_type_oid - 1] = false; tup = heap_modify_tuple(tuple, desc, values, nulls, replaces); CatalogTupleUpdate(pg_type_desc, &tuple->t_self, tuple); New: Datum values[Natts_pg_type] = {0}; bool nulls[Natts_pg_type] = {false}; Bitmapset *updated = NULL; HeapTupleUpdateValue(pg_type, typtype, CharGetDatum(typeType), values, nulls, updated); HeapTupleUpdateValueNull(pg_type, typdefaultbin, values, nulls, updated); HeapTupleSetColumnNotUpdated(pg_type, oid, updated); tup = heap_update_tuple(tuple, desc, values, nulls, updated); CatalogTupleUpdate(pg_type_desc, &tuple->t_self, tuple, updated, NULL); In addition CatalogTupleUpdate and CatalogTupleInsert now have an optional argument for the CatalogIndexState, when not provided it is created and then released for the caller. The heap_update_tuple() function is functionally equivalent to heap_modify_tuple(), but takes a Bitmapset called "updated" rather than an array of bool generally called "replaces" as a method for indicating what was modified. Additionally, this new function tries to balance the tradeoffs of calling heap_getattr() versus heap_deform_tuple() based on the ratio of attributes updated and their known runtime complexities. Both paths are functionally equivalent. The changes also include initialization of the values/nulls arrays rather than loops or memset(). Some effort was also given to unify naming of these variables and their order so as to lower cognitive overhead. There is no impact to non-catalog related paths. --- src/backend/access/common/heaptuple.c | 119 +++++++++++ src/backend/catalog/indexing.c | 138 ++++++------- src/backend/catalog/pg_aggregate.c | 74 +++---- src/backend/catalog/pg_constraint.c | 131 ++++++------ src/backend/commands/alter.c | 60 +++--- src/backend/commands/analyze.c | 74 +++---- src/backend/statistics/attribute_stats.c | 241 +++++++++++------------ src/include/access/htup.h | 61 ++++++ src/include/access/htup_details.h | 8 + src/include/catalog/indexing.h | 17 +- 10 files changed, 550 insertions(+), 373 deletions(-) diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c index 74a52d8706771..364f03b043eb5 100644 --- a/src/backend/access/common/heaptuple.c +++ b/src/backend/access/common/heaptuple.c @@ -1325,6 +1325,125 @@ heap_modify_tuple_by_cols(HeapTuple tuple, return newTuple; } +/* + * heap_update_tuple + * Form a new tuple from an old tuple and a set of replacement values. + * + * Creates a new HeapTuple by selectively replacing attributes from the original + * tuple with new values. The 'updated' Bitmapset specifies which attributes + * (by attribute number, 1-based adjusted by FirstLowInvalidHeapAttributeNumber) + * should be replaced with corresponding entries from new_values and new_isnull + * arrays (0-based indices). + * + * Performance strategy: + * - If updating many attributes (> 2*natts/3), use heap_getattr() to extract + * only the few non-updated attributes. This is O(k*n) where k is the number + * of non-updated attributes, which is small when updating many. + * - If updating few attributes (<= 2*natts/3), use heap_deform_tuple() to + * extract all attributes at once (O(n)), then replace the updated ones. + * This avoids the O(n^2) cost of many heap_getattr() calls. + * + * The threshold of 2*natts/3 balances the fixed O(n) cost of heap_deform_tuple + * against the variable O(k*n) cost of heap_getattr, where k = natts - num_updated. + */ +HeapTuple +heap_update_tuple(HeapTuple tuple, + TupleDesc desc, + const Datum *new_values, + const bool *new_nulls, + const Bitmapset *updated) +{ + int natts = desc->natts; + int num_updated; + Datum *values; + bool *nulls; + HeapTuple new_tuple; + + Assert(!bms_is_empty(updated)); + + num_updated = bms_num_members(updated); + Assert(num_updated <= natts); + + values = (Datum *) palloc0(natts * sizeof(Datum)); + nulls = (bool *) palloc0(natts * sizeof(bool)); + + /* + * Choose strategy based on update density. When updating most attributes, + * it's cheaper to extract the few unchanged ones individually. + */ + if (num_updated > (2 * natts) / 3) + { + /* Updating many: use heap_getattr for the few non-updated attributes */ + for (int i = 0; i < natts; i++) + { + /* + * Convert array index to attribute number, then to bitmapset + * member. Array index i (0-based) -> attnum (1-based) -> bms + * member. + */ + AttrNumber attnum = i + 1; + int member = attnum - FirstLowInvalidHeapAttributeNumber; + + if (bms_is_member(member, updated)) + { + /* Use replacement value */ + if (unlikely(!new_values || !new_nulls)) + values[i] = heap_getattr(tuple, attnum, desc, &nulls[i]); + + if (likely(new_values)) + values[i] = new_values[i]; + + if (likely(new_nulls)) + nulls[i] = new_nulls[i]; + } + else + { + /* Extract original value using heap_getattr (1-based) */ + values[i] = heap_getattr(tuple, attnum, desc, &nulls[i]); + } + } + } + else + { + int member = -1; + + /* Updating few: deform entire tuple, then replace updated attributes */ + heap_deform_tuple(tuple, desc, values, nulls); + + while ((member = bms_next_member(updated, member)) >= 0) + { + /* + * Convert bitmapset member to attribute number, then to array + * index. bms_member -> attnum (1-based) -> array index i + * (0-based). + */ + AttrNumber attnum = member + FirstLowInvalidHeapAttributeNumber; + int i = attnum - 1; + + Assert(i >= 0 && i < natts); + + if (likely(new_values)) + values[i] = new_values[i]; + + if (likely(new_nulls)) + nulls[i] = new_nulls[i]; + } + } + + /* Create the new tuple */ + new_tuple = heap_form_tuple(desc, values, nulls); + + pfree(values); + pfree(nulls); + + /* Preserve tuple identity and location information from the original */ + new_tuple->t_data->t_ctid = tuple->t_data->t_ctid; + new_tuple->t_self = tuple->t_self; + new_tuple->t_tableOid = tuple->t_tableOid; + + return new_tuple; +} + /* * heap_deform_tuple * Given a tuple, extract data into values/isnull arrays; this is diff --git a/src/backend/catalog/indexing.c b/src/backend/catalog/indexing.c index 004c5121000fe..f35c1b6cd882a 100644 --- a/src/backend/catalog/indexing.c +++ b/src/backend/catalog/indexing.c @@ -225,58 +225,67 @@ CatalogTupleCheckConstraints(Relation heapRel, HeapTuple tup) * * This is a convenience routine for the common case of inserting a single * tuple in a system catalog; it inserts a new heap tuple, keeping indexes - * current. Avoid using it for multiple tuples, since opening the indexes - * and building the index info structures is moderately expensive. - * (Use CatalogTupleInsertWithInfo in such cases.) + * current. + * + * If 'indstate' is NULL, the function opens and closes the indexes internally. + * This is convenient for single-tuple updates but has overhead from opening the + * indexes and building index info structures. + * + * If 'indstate' is provided (non-NULL), it is used directly without opening or + * closing indexes. This allows callers to amortize index management costs across + * multiple tuple updates. Callers must use CatalogOpenIndexes() before the first + * update and CatalogCloseIndexes() after the last update. + * + * XXX: At some point we might cache the CatalogIndexState data somewhere (perhaps + * in the relcache) so that callers needn't trouble over this. */ void -CatalogTupleInsert(Relation heapRel, HeapTuple tup) +CatalogTupleInsert(Relation heapRel, HeapTuple tup, + CatalogIndexState indstate) { - CatalogIndexState indstate; - - CatalogTupleCheckConstraints(heapRel, tup); - - indstate = CatalogOpenIndexes(heapRel); + bool close_indexes = false; - simple_heap_insert(heapRel, tup); - - CatalogIndexInsert(indstate, tup, TU_All); - CatalogCloseIndexes(indstate); -} + /* Open indexes if not provided by caller */ + if (indstate == NULL) + { + indstate = CatalogOpenIndexes(heapRel); + close_indexes = true; + } -/* - * CatalogTupleInsertWithInfo - as above, but with caller-supplied index info - * - * This should be used when it's important to amortize CatalogOpenIndexes/ - * CatalogCloseIndexes work across multiple insertions. At some point we - * might cache the CatalogIndexState data somewhere (perhaps in the relcache) - * so that callers needn't trouble over this ... but we don't do so today. - */ -void -CatalogTupleInsertWithInfo(Relation heapRel, HeapTuple tup, - CatalogIndexState indstate) -{ CatalogTupleCheckConstraints(heapRel, tup); simple_heap_insert(heapRel, tup); CatalogIndexInsert(indstate, tup, TU_All); + + /* Close indexes only if we opened them ourselves */ + if (close_indexes) + CatalogCloseIndexes(indstate); } /* - * CatalogTuplesMultiInsertWithInfo - as above, but for multiple tuples + * CatalogTuplesMultiInsert - as above, but for multiple tuples * * Insert multiple tuples into the given catalog relation at once, with an * amortized cost of CatalogOpenIndexes. */ void -CatalogTuplesMultiInsertWithInfo(Relation heapRel, TupleTableSlot **slot, - int ntuples, CatalogIndexState indstate) +CatalogTuplesMultiInsert(Relation heapRel, TupleTableSlot **slot, + int ntuples, CatalogIndexState indstate) { + bool close_indexes = false; + /* Nothing to do */ if (ntuples <= 0) return; + /* Open indexes if not provided by caller */ + if (indstate == NULL) + { + indstate = CatalogOpenIndexes(heapRel); + close_indexes = true; + } + heap_multi_insert(heapRel, slot, ntuples, GetCurrentCommandId(true), 0, NULL); @@ -296,6 +305,10 @@ CatalogTuplesMultiInsertWithInfo(Relation heapRel, TupleTableSlot **slot, if (should_free) heap_freetuple(tuple); } + + /* Close indexes only if we opened them ourselves */ + if (close_indexes) + CatalogCloseIndexes(indstate); } /* @@ -303,47 +316,45 @@ CatalogTuplesMultiInsertWithInfo(Relation heapRel, TupleTableSlot **slot, * * Update the tuple identified by "otid", replacing it with the data in "tup". * - * This is a convenience routine for the common case of updating a single - * tuple in a system catalog; it updates one heap tuple, keeping indexes - * current. Avoid using it for multiple tuples, since opening the indexes - * and building the index info structures is moderately expensive. - * (Use CatalogTupleUpdateWithInfo in such cases.) + * This function updates a heap tuple in a system catalog and keeps its indexes + * current. The 'updated' bitmapset specifies which columns were modified, using + * the same encoding as HeapDetermineColumnsInfo(). + * + * If 'indstate' is NULL, the function opens and closes the indexes internally. + * This is convenient for single-tuple updates but has overhead from opening the + * indexes and building index info structures. + * + * If 'indstate' is provided (non-NULL), it is used directly without opening or + * closing indexes. This allows callers to amortize index management costs across + * multiple tuple updates. Callers must use CatalogOpenIndexes() before the first + * update and CatalogCloseIndexes() after the last update. + * + * XXX: At some point we might cache the CatalogIndexState data somewhere (perhaps + * in the relcache) so that callers needn't trouble over this. */ void -CatalogTupleUpdate(Relation heapRel, const ItemPointerData *otid, HeapTuple tup) +CatalogTupleUpdate(Relation heapRel, const ItemPointerData *otid, HeapTuple tuple, + const Bitmapset *updated, CatalogIndexState indstate) { - CatalogIndexState indstate; TU_UpdateIndexes updateIndexes = TU_All; + bool close_indexes = false; - CatalogTupleCheckConstraints(heapRel, tup); - - indstate = CatalogOpenIndexes(heapRel); - - simple_heap_update(heapRel, otid, tup, &updateIndexes); - - CatalogIndexInsert(indstate, tup, updateIndexes); - CatalogCloseIndexes(indstate); -} + CatalogTupleCheckConstraints(heapRel, tuple); -/* - * CatalogTupleUpdateWithInfo - as above, but with caller-supplied index info - * - * This should be used when it's important to amortize CatalogOpenIndexes/ - * CatalogCloseIndexes work across multiple updates. At some point we - * might cache the CatalogIndexState data somewhere (perhaps in the relcache) - * so that callers needn't trouble over this ... but we don't do so today. - */ -void -CatalogTupleUpdateWithInfo(Relation heapRel, const ItemPointerData *otid, HeapTuple tup, - CatalogIndexState indstate) -{ - TU_UpdateIndexes updateIndexes = TU_All; + /* Open indexes if not provided by caller */ + if (indstate == NULL) + { + indstate = CatalogOpenIndexes(heapRel); + close_indexes = true; + } - CatalogTupleCheckConstraints(heapRel, tup); + simple_heap_update(heapRel, otid, tuple, &updateIndexes); - simple_heap_update(heapRel, otid, tup, &updateIndexes); + CatalogIndexInsert(indstate, tuple, updateIndexes); - CatalogIndexInsert(indstate, tup, updateIndexes); + /* Close indexes only if we opened them ourselves */ + if (close_indexes) + CatalogCloseIndexes(indstate); } /* @@ -355,11 +366,6 @@ CatalogTupleUpdateWithInfo(Relation heapRel, const ItemPointerData *otid, HeapTu * cleanup will be done later by VACUUM. However, callers of this function * shouldn't have to know that; we'd like a uniform abstraction for all * catalog tuple changes. Hence, provide this currently-trivial wrapper. - * - * The abstraction is a bit leaky in that we don't provide an optimized - * CatalogTupleDeleteWithInfo version, because there is currently nothing to - * optimize. If we ever need that, rather than touching a lot of call sites, - * it might be better to do something about caching CatalogIndexState. */ void CatalogTupleDelete(Relation heapRel, const ItemPointerData *tid) diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c index a1cb5719a0c6d..ddfa94b3abaf3 100644 --- a/src/backend/catalog/pg_aggregate.c +++ b/src/backend/catalog/pg_aggregate.c @@ -79,9 +79,9 @@ AggregateCreate(const char *aggName, Relation aggdesc; HeapTuple tup; HeapTuple oldtup; - bool nulls[Natts_pg_aggregate]; - Datum values[Natts_pg_aggregate]; - bool replaces[Natts_pg_aggregate]; + bool nulls[Natts_pg_aggregate] = {false}; + Datum values[Natts_pg_aggregate] = {0}; + Bitmapset *updated = NULL; Form_pg_proc proc; Oid transfn; Oid finalfn = InvalidOid; /* can be omitted */ @@ -102,7 +102,6 @@ AggregateCreate(const char *aggName, Oid procOid; TupleDesc tupDesc; char *detailmsg; - int i; ObjectAddress myself, referenced; ObjectAddresses *addrs; @@ -584,7 +583,7 @@ AggregateCreate(const char *aggName, /* * permission checks on used types */ - for (i = 0; i < numArgs; i++) + for (int i = 0; i < numArgs; i++) { aclresult = object_aclcheck(TypeRelationId, aggArgTypes[i], GetUserId(), ACL_USAGE); if (aclresult != ACLCHECK_OK) @@ -651,40 +650,34 @@ AggregateCreate(const char *aggName, tupDesc = aggdesc->rd_att; /* initialize nulls and values */ - for (i = 0; i < Natts_pg_aggregate; i++) - { - nulls[i] = false; - values[i] = (Datum) 0; - replaces[i] = true; - } - values[Anum_pg_aggregate_aggfnoid - 1] = ObjectIdGetDatum(procOid); - values[Anum_pg_aggregate_aggkind - 1] = CharGetDatum(aggKind); - values[Anum_pg_aggregate_aggnumdirectargs - 1] = Int16GetDatum(numDirectArgs); - values[Anum_pg_aggregate_aggtransfn - 1] = ObjectIdGetDatum(transfn); - values[Anum_pg_aggregate_aggfinalfn - 1] = ObjectIdGetDatum(finalfn); - values[Anum_pg_aggregate_aggcombinefn - 1] = ObjectIdGetDatum(combinefn); - values[Anum_pg_aggregate_aggserialfn - 1] = ObjectIdGetDatum(serialfn); - values[Anum_pg_aggregate_aggdeserialfn - 1] = ObjectIdGetDatum(deserialfn); - values[Anum_pg_aggregate_aggmtransfn - 1] = ObjectIdGetDatum(mtransfn); - values[Anum_pg_aggregate_aggminvtransfn - 1] = ObjectIdGetDatum(minvtransfn); - values[Anum_pg_aggregate_aggmfinalfn - 1] = ObjectIdGetDatum(mfinalfn); - values[Anum_pg_aggregate_aggfinalextra - 1] = BoolGetDatum(finalfnExtraArgs); - values[Anum_pg_aggregate_aggmfinalextra - 1] = BoolGetDatum(mfinalfnExtraArgs); - values[Anum_pg_aggregate_aggfinalmodify - 1] = CharGetDatum(finalfnModify); - values[Anum_pg_aggregate_aggmfinalmodify - 1] = CharGetDatum(mfinalfnModify); - values[Anum_pg_aggregate_aggsortop - 1] = ObjectIdGetDatum(sortop); - values[Anum_pg_aggregate_aggtranstype - 1] = ObjectIdGetDatum(aggTransType); - values[Anum_pg_aggregate_aggtransspace - 1] = Int32GetDatum(aggTransSpace); - values[Anum_pg_aggregate_aggmtranstype - 1] = ObjectIdGetDatum(aggmTransType); - values[Anum_pg_aggregate_aggmtransspace - 1] = Int32GetDatum(aggmTransSpace); + HeapTupleUpdateValue(pg_aggregate, aggfnoid, ObjectIdGetDatum(procOid), values, nulls, updated); + HeapTupleUpdateValue(pg_aggregate, aggkind, CharGetDatum(aggKind), values, nulls, updated); + HeapTupleUpdateValue(pg_aggregate, aggnumdirectargs, Int16GetDatum(numDirectArgs), values, nulls, updated); + HeapTupleUpdateValue(pg_aggregate, aggtransfn, ObjectIdGetDatum(transfn), values, nulls, updated); + HeapTupleUpdateValue(pg_aggregate, aggfinalfn, ObjectIdGetDatum(finalfn), values, nulls, updated); + HeapTupleUpdateValue(pg_aggregate, aggcombinefn, ObjectIdGetDatum(combinefn), values, nulls, updated); + HeapTupleUpdateValue(pg_aggregate, aggserialfn, ObjectIdGetDatum(serialfn), values, nulls, updated); + HeapTupleUpdateValue(pg_aggregate, aggdeserialfn, ObjectIdGetDatum(deserialfn), values, nulls, updated); + HeapTupleUpdateValue(pg_aggregate, aggmtransfn, ObjectIdGetDatum(mtransfn), values, nulls, updated); + HeapTupleUpdateValue(pg_aggregate, aggminvtransfn, ObjectIdGetDatum(minvtransfn), values, nulls, updated); + HeapTupleUpdateValue(pg_aggregate, aggmfinalfn, ObjectIdGetDatum(mfinalfn), values, nulls, updated); + HeapTupleUpdateValue(pg_aggregate, aggfinalextra, BoolGetDatum(finalfnExtraArgs), values, nulls, updated); + HeapTupleUpdateValue(pg_aggregate, aggmfinalextra, BoolGetDatum(mfinalfnExtraArgs), values, nulls, updated); + HeapTupleUpdateValue(pg_aggregate, aggfinalmodify, CharGetDatum(finalfnModify), values, nulls, updated); + HeapTupleUpdateValue(pg_aggregate, aggmfinalmodify, CharGetDatum(mfinalfnModify), values, nulls, updated); + HeapTupleUpdateValue(pg_aggregate, aggsortop, ObjectIdGetDatum(sortop), values, nulls, updated); + HeapTupleUpdateValue(pg_aggregate, aggtranstype, ObjectIdGetDatum(aggTransType), values, nulls, updated); + HeapTupleUpdateValue(pg_aggregate, aggtransspace, Int32GetDatum(aggTransSpace), values, nulls, updated); + HeapTupleUpdateValue(pg_aggregate, aggmtranstype, ObjectIdGetDatum(aggmTransType), values, nulls, updated); + HeapTupleUpdateValue(pg_aggregate, aggmtransspace, Int32GetDatum(aggmTransSpace), values, nulls, updated); if (agginitval) - values[Anum_pg_aggregate_agginitval - 1] = CStringGetTextDatum(agginitval); + HeapTupleUpdateValue(pg_aggregate, agginitval, CStringGetTextDatum(agginitval), values, nulls, updated); else - nulls[Anum_pg_aggregate_agginitval - 1] = true; + HeapTupleUpdateValueNull(pg_aggregate, agginitval, values, nulls, updated); if (aggminitval) - values[Anum_pg_aggregate_aggminitval - 1] = CStringGetTextDatum(aggminitval); + HeapTupleUpdateValue(pg_aggregate, aggminitval, CStringGetTextDatum(aggminitval), values, nulls, updated); else - nulls[Anum_pg_aggregate_aggminitval - 1] = true; + HeapTupleUpdateValueNull(pg_aggregate, aggminitval, values, nulls, updated); if (replace) oldtup = SearchSysCache1(AGGFNOID, ObjectIdGetDatum(procOid)); @@ -717,20 +710,17 @@ AggregateCreate(const char *aggName, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("cannot change number of direct arguments of an aggregate function"))); - replaces[Anum_pg_aggregate_aggfnoid - 1] = false; - replaces[Anum_pg_aggregate_aggkind - 1] = false; - replaces[Anum_pg_aggregate_aggnumdirectargs - 1] = false; - - tup = heap_modify_tuple(oldtup, tupDesc, values, nulls, replaces); - CatalogTupleUpdate(aggdesc, &tup->t_self, tup); + tup = heap_update_tuple(oldtup, tupDesc, values, nulls, updated); + CatalogTupleUpdate(aggdesc, &tup->t_self, tup, updated, NULL); ReleaseSysCache(oldtup); } else { tup = heap_form_tuple(tupDesc, values, nulls); - CatalogTupleInsert(aggdesc, tup); + CatalogTupleInsert(aggdesc, tup, NULL); } + bms_free(updated); table_close(aggdesc, RowExclusiveLock); /* diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c index 9944e4bd2d10e..855bdf4601534 100644 --- a/src/backend/catalog/pg_constraint.c +++ b/src/backend/catalog/pg_constraint.c @@ -85,8 +85,8 @@ CreateConstraintEntry(const char *constraintName, Relation conDesc; Oid conOid; HeapTuple tup; - bool nulls[Natts_pg_constraint]; - Datum values[Natts_pg_constraint]; + Datum values[Natts_pg_constraint] = {0}; + bool nulls[Natts_pg_constraint] = {false}; ArrayType *conkeyArray; ArrayType *confkeyArray; ArrayType *conpfeqopArray; @@ -184,70 +184,70 @@ CreateConstraintEntry(const char *constraintName, conOid = GetNewOidWithIndex(conDesc, ConstraintOidIndexId, Anum_pg_constraint_oid); - values[Anum_pg_constraint_oid - 1] = ObjectIdGetDatum(conOid); - values[Anum_pg_constraint_conname - 1] = NameGetDatum(&cname); - values[Anum_pg_constraint_connamespace - 1] = ObjectIdGetDatum(constraintNamespace); - values[Anum_pg_constraint_contype - 1] = CharGetDatum(constraintType); - values[Anum_pg_constraint_condeferrable - 1] = BoolGetDatum(isDeferrable); - values[Anum_pg_constraint_condeferred - 1] = BoolGetDatum(isDeferred); - values[Anum_pg_constraint_conenforced - 1] = BoolGetDatum(isEnforced); - values[Anum_pg_constraint_convalidated - 1] = BoolGetDatum(isValidated); - values[Anum_pg_constraint_conrelid - 1] = ObjectIdGetDatum(relId); - values[Anum_pg_constraint_contypid - 1] = ObjectIdGetDatum(domainId); - values[Anum_pg_constraint_conindid - 1] = ObjectIdGetDatum(indexRelId); - values[Anum_pg_constraint_conparentid - 1] = ObjectIdGetDatum(parentConstrId); - values[Anum_pg_constraint_confrelid - 1] = ObjectIdGetDatum(foreignRelId); - values[Anum_pg_constraint_confupdtype - 1] = CharGetDatum(foreignUpdateType); - values[Anum_pg_constraint_confdeltype - 1] = CharGetDatum(foreignDeleteType); - values[Anum_pg_constraint_confmatchtype - 1] = CharGetDatum(foreignMatchType); - values[Anum_pg_constraint_conislocal - 1] = BoolGetDatum(conIsLocal); - values[Anum_pg_constraint_coninhcount - 1] = Int16GetDatum(conInhCount); - values[Anum_pg_constraint_connoinherit - 1] = BoolGetDatum(conNoInherit); - values[Anum_pg_constraint_conperiod - 1] = BoolGetDatum(conPeriod); + HeapTupleSetValue(pg_constraint, oid, ObjectIdGetDatum(conOid), values); + HeapTupleSetValue(pg_constraint, conname, NameGetDatum(&cname), values); + HeapTupleSetValue(pg_constraint, connamespace, ObjectIdGetDatum(constraintNamespace), values); + HeapTupleSetValue(pg_constraint, contype, CharGetDatum(constraintType), values); + HeapTupleSetValue(pg_constraint, condeferrable, BoolGetDatum(isDeferrable), values); + HeapTupleSetValue(pg_constraint, condeferred, BoolGetDatum(isDeferred), values); + HeapTupleSetValue(pg_constraint, conenforced, BoolGetDatum(isEnforced), values); + HeapTupleSetValue(pg_constraint, convalidated, BoolGetDatum(isValidated), values); + HeapTupleSetValue(pg_constraint, conrelid, ObjectIdGetDatum(relId), values); + HeapTupleSetValue(pg_constraint, contypid, ObjectIdGetDatum(domainId), values); + HeapTupleSetValue(pg_constraint, conindid, ObjectIdGetDatum(indexRelId), values); + HeapTupleSetValue(pg_constraint, conparentid, ObjectIdGetDatum(parentConstrId), values); + HeapTupleSetValue(pg_constraint, confrelid, ObjectIdGetDatum(foreignRelId), values); + HeapTupleSetValue(pg_constraint, confupdtype, CharGetDatum(foreignUpdateType), values); + HeapTupleSetValue(pg_constraint, confdeltype, CharGetDatum(foreignDeleteType), values); + HeapTupleSetValue(pg_constraint, confmatchtype, CharGetDatum(foreignMatchType), values); + HeapTupleSetValue(pg_constraint, conislocal, BoolGetDatum(conIsLocal), values); + HeapTupleSetValue(pg_constraint, coninhcount, Int16GetDatum(conInhCount), values); + HeapTupleSetValue(pg_constraint, connoinherit, BoolGetDatum(conNoInherit), values); + HeapTupleSetValue(pg_constraint, conperiod, BoolGetDatum(conPeriod), values); if (conkeyArray) - values[Anum_pg_constraint_conkey - 1] = PointerGetDatum(conkeyArray); + HeapTupleSetValue(pg_constraint, conkey, PointerGetDatum(conkeyArray), values); else - nulls[Anum_pg_constraint_conkey - 1] = true; + HeapTupleSetValueNull(pg_constraint, conkey, values, nulls); if (confkeyArray) - values[Anum_pg_constraint_confkey - 1] = PointerGetDatum(confkeyArray); + HeapTupleSetValue(pg_constraint, confkey, PointerGetDatum(confkeyArray), values); else - nulls[Anum_pg_constraint_confkey - 1] = true; + HeapTupleSetValueNull(pg_constraint, confkey, values, nulls); if (conpfeqopArray) - values[Anum_pg_constraint_conpfeqop - 1] = PointerGetDatum(conpfeqopArray); + HeapTupleSetValue(pg_constraint, conpfeqop, PointerGetDatum(conpfeqopArray), values); else - nulls[Anum_pg_constraint_conpfeqop - 1] = true; + HeapTupleSetValueNull(pg_constraint, conpfeqop, values, nulls); if (conppeqopArray) - values[Anum_pg_constraint_conppeqop - 1] = PointerGetDatum(conppeqopArray); + HeapTupleSetValue(pg_constraint, conppeqop, PointerGetDatum(conppeqopArray), values); else - nulls[Anum_pg_constraint_conppeqop - 1] = true; + HeapTupleSetValueNull(pg_constraint, conppeqop, values, nulls); if (conffeqopArray) - values[Anum_pg_constraint_conffeqop - 1] = PointerGetDatum(conffeqopArray); + HeapTupleSetValue(pg_constraint, conffeqop, PointerGetDatum(conffeqopArray), values); else - nulls[Anum_pg_constraint_conffeqop - 1] = true; + HeapTupleSetValueNull(pg_constraint, conffeqop, values, nulls); if (confdelsetcolsArray) - values[Anum_pg_constraint_confdelsetcols - 1] = PointerGetDatum(confdelsetcolsArray); + HeapTupleSetValue(pg_constraint, confdelsetcols, PointerGetDatum(confdelsetcolsArray), values); else - nulls[Anum_pg_constraint_confdelsetcols - 1] = true; + HeapTupleSetValueNull(pg_constraint, confdelsetcols, values, nulls); if (conexclopArray) - values[Anum_pg_constraint_conexclop - 1] = PointerGetDatum(conexclopArray); + HeapTupleSetValue(pg_constraint, conexclop, PointerGetDatum(conexclopArray), values); else - nulls[Anum_pg_constraint_conexclop - 1] = true; + HeapTupleSetValueNull(pg_constraint, conexclop, values, nulls); if (conBin) - values[Anum_pg_constraint_conbin - 1] = CStringGetTextDatum(conBin); + HeapTupleSetValue(pg_constraint, conbin, CStringGetTextDatum(conBin), values); else - nulls[Anum_pg_constraint_conbin - 1] = true; + HeapTupleSetValueNull(pg_constraint, conbin, values, nulls); tup = heap_form_tuple(RelationGetDescr(conDesc), values, nulls); - CatalogTupleInsert(conDesc, tup); + CatalogTupleInsert(conDesc, tup, NULL); ObjectAddressSet(conobject, ConstraintRelationId, conOid); @@ -748,7 +748,7 @@ AdjustNotNullInheritance(Oid relid, AttrNumber attnum, { Relation pg_constraint; Form_pg_constraint conform; - bool changed = false; + Bitmapset *updated = NULL; pg_constraint = table_open(ConstraintRelationId, RowExclusiveLock); conform = (Form_pg_constraint) GETSTRUCT(tup); @@ -784,19 +784,21 @@ AdjustNotNullInheritance(Oid relid, AttrNumber attnum, ereport(ERROR, errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("too many inheritance parents")); - changed = true; + HeapTupleMarkColumnUpdated(pg_constraint, coninhcount, updated); } else if (!conform->conislocal) { - conform->conislocal = true; - changed = true; + HeapTupleUpdateField(pg_constraint, conislocal, true, conform, updated); } - if (changed) - CatalogTupleUpdate(pg_constraint, &tup->t_self, tup); + if (!bms_is_empty(updated)) + { + CatalogTupleUpdate(pg_constraint, &tup->t_self, tup, updated, NULL); + } table_close(pg_constraint, RowExclusiveLock); + bms_free(updated); return true; } @@ -928,6 +930,7 @@ RemoveConstraintById(Oid conId) Relation pgrel; HeapTuple relTup; Form_pg_class classForm; + Bitmapset *updated = NULL; pgrel = table_open(RelationRelationId, RowExclusiveLock); relTup = SearchSysCacheCopy1(RELOID, @@ -938,14 +941,14 @@ RemoveConstraintById(Oid conId) classForm = (Form_pg_class) GETSTRUCT(relTup); if (classForm->relchecks > 0) - classForm->relchecks--; + HeapTupleUpdateField(pg_class, relchecks, classForm->relchecks - 1, classForm, updated); else /* should not happen */ elog(WARNING, "relation \"%s\" has relchecks = %d", RelationGetRelationName(rel), classForm->relchecks); - CatalogTupleUpdate(pgrel, &relTup->t_self, relTup); - + CatalogTupleUpdate(pgrel, &relTup->t_self, relTup, updated, NULL); + bms_free(updated); heap_freetuple(relTup); table_close(pgrel, RowExclusiveLock); @@ -990,6 +993,7 @@ RenameConstraintById(Oid conId, const char *newname) Relation conDesc; HeapTuple tuple; Form_pg_constraint con; + Bitmapset *updated = NULL; conDesc = table_open(ConstraintRelationId, RowExclusiveLock); @@ -1020,11 +1024,13 @@ RenameConstraintById(Oid conId, const char *newname) /* OK, do the rename --- tuple is a copy, so OK to scribble on it */ namestrcpy(&(con->conname), newname); + HeapTupleMarkColumnUpdated(pg_constraint, conname, updated); - CatalogTupleUpdate(conDesc, &tuple->t_self, tuple); + CatalogTupleUpdate(conDesc, &tuple->t_self, tuple, updated, NULL); InvokeObjectPostAlterHook(ConstraintRelationId, conId, 0); + bms_free(updated); heap_freetuple(tuple); table_close(conDesc, RowExclusiveLock); } @@ -1072,15 +1078,17 @@ AlterConstraintNamespaces(Oid ownerId, Oid oldNspId, /* Don't update if the object is already part of the namespace */ if (conform->connamespace == oldNspId && oldNspId != newNspId) { + Bitmapset *updated = NULL; + tup = heap_copytuple(tup); conform = (Form_pg_constraint) GETSTRUCT(tup); - conform->connamespace = newNspId; - - CatalogTupleUpdate(conRel, &tup->t_self, tup); + HeapTupleUpdateField(pg_constraint, connamespace, newNspId, conform, updated); + CatalogTupleUpdate(conRel, &tup->t_self, tup, updated, NULL); + bms_free(updated); /* - * Note: currently, the constraint will not have its own + * NOTE: currently, the constraint will not have its own * dependency on the namespace, so we don't need to do * changeDependencyFor(). */ @@ -1116,6 +1124,7 @@ ConstraintSetParentConstraint(Oid childConstrId, newtup; ObjectAddress depender; ObjectAddress referenced; + Bitmapset *updated = NULL; constrRel = table_open(ConstraintRelationId, RowExclusiveLock); tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(childConstrId)); @@ -1131,16 +1140,17 @@ ConstraintSetParentConstraint(Oid childConstrId, elog(ERROR, "constraint %u already has a parent constraint", childConstrId); - constrForm->conislocal = false; + HeapTupleUpdateField(pg_constraint, conislocal, false, constrForm, updated); if (pg_add_s16_overflow(constrForm->coninhcount, 1, &constrForm->coninhcount)) ereport(ERROR, errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("too many inheritance parents")); - constrForm->conparentid = parentConstrId; + HeapTupleMarkColumnUpdated(pg_constraint, coninhcount, updated); + HeapTupleUpdateField(pg_constraint, conparentid, parentConstrId, constrForm, updated); - CatalogTupleUpdate(constrRel, &tuple->t_self, newtup); + CatalogTupleUpdate(constrRel, &tuple->t_self, newtup, updated, NULL); ObjectAddressSet(depender, ConstraintRelationId, childConstrId); @@ -1152,14 +1162,14 @@ ConstraintSetParentConstraint(Oid childConstrId, } else { - constrForm->coninhcount--; - constrForm->conislocal = true; - constrForm->conparentid = InvalidOid; + HeapTupleUpdateField(pg_constraint, coninhcount, constrForm->coninhcount - 1, constrForm, updated); + HeapTupleUpdateField(pg_constraint, conislocal, true, constrForm, updated); + HeapTupleUpdateField(pg_constraint, conparentid, InvalidOid, constrForm, updated); /* Make sure there's no further inheritance. */ Assert(constrForm->coninhcount == 0); - CatalogTupleUpdate(constrRel, &tuple->t_self, newtup); + CatalogTupleUpdate(constrRel, &tuple->t_self, newtup, updated, NULL); deleteDependencyRecordsForClass(ConstraintRelationId, childConstrId, ConstraintRelationId, @@ -1169,6 +1179,7 @@ ConstraintSetParentConstraint(Oid childConstrId, DEPENDENCY_PARTITION_SEC); } + bms_free(updated); ReleaseSysCache(tuple); table_close(constrRel, RowExclusiveLock); } diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c index cb75e11fced62..f5f8ec791c30a 100644 --- a/src/backend/commands/alter.c +++ b/src/backend/commands/alter.c @@ -180,7 +180,7 @@ AlterObjectRename_internal(Relation rel, Oid objectId, const char *new_name) AclResult aclresult; Datum *values; bool *nulls; - bool *replaces; + Bitmapset *updated = NULL; NameData nameattrdata; oldtup = SearchSysCache1(oidCacheId, ObjectIdGetDatum(objectId)); @@ -326,15 +326,21 @@ AlterObjectRename_internal(Relation rel, Oid objectId, const char *new_name) /* Build modified tuple */ values = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(Datum)); nulls = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(bool)); - replaces = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(bool)); + + /* + * NOTE: We can't use the HeapTupleMarkColumnUpdated() macro here because + * 'Anum_name' isn't a table/column name, it's a index for the relation + * passed into the function as an argument. + */ namestrcpy(&nameattrdata, new_name); values[Anum_name - 1] = NameGetDatum(&nameattrdata); - replaces[Anum_name - 1] = true; - newtup = heap_modify_tuple(oldtup, RelationGetDescr(rel), - values, nulls, replaces); + updated = bms_add_member(updated, Anum_name - FirstLowInvalidHeapAttributeNumber); + + newtup = heap_update_tuple(oldtup, RelationGetDescr(rel), + values, nulls, updated); /* Perform actual update */ - CatalogTupleUpdate(rel, &oldtup->t_self, newtup); + CatalogTupleUpdate(rel, &oldtup->t_self, newtup, updated, NULL); InvokeObjectPostAlterHook(classId, objectId, 0); @@ -357,7 +363,7 @@ AlterObjectRename_internal(Relation rel, Oid objectId, const char *new_name) /* Release memory */ pfree(values); pfree(nulls); - pfree(replaces); + bms_free(updated); heap_freetuple(newtup); ReleaseSysCache(oldtup); @@ -705,7 +711,7 @@ AlterObjectNamespace_internal(Relation rel, Oid objid, Oid nspOid) newtup; Datum *values; bool *nulls; - bool *replaces; + Bitmapset *updated = NULL; tup = SearchSysCacheCopy1(oidCacheId, ObjectIdGetDatum(objid)); if (!HeapTupleIsValid(tup)) /* should not happen */ @@ -804,19 +810,21 @@ AlterObjectNamespace_internal(Relation rel, Oid objid, Oid nspOid) /* Build modified tuple */ values = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(Datum)); nulls = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(bool)); - replaces = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(bool)); + + /* NOTE: Don't use the HeapTupleMarkColumnUpdated() macro here either. */ values[Anum_namespace - 1] = ObjectIdGetDatum(nspOid); - replaces[Anum_namespace - 1] = true; - newtup = heap_modify_tuple(tup, RelationGetDescr(rel), - values, nulls, replaces); + updated = bms_add_member(updated, Anum_namespace - FirstLowInvalidHeapAttributeNumber); + + newtup = heap_update_tuple(tup, RelationGetDescr(rel), + values, nulls, updated); /* Perform actual update */ - CatalogTupleUpdate(rel, &tup->t_self, newtup); + CatalogTupleUpdate(rel, &tup->t_self, newtup, updated, NULL); /* Release memory */ pfree(values); pfree(nulls); - pfree(replaces); + bms_free(updated); /* update dependency to point to the new schema */ if (changeDependencyFor(classId, objid, @@ -967,7 +975,7 @@ AlterObjectOwner_internal(Oid classId, Oid objectId, Oid new_ownerId) HeapTuple newtup; Datum *values; bool *nulls; - bool *replaces; + Bitmapset *updated = NULL; /* Superusers can bypass permission checks */ if (!superuser()) @@ -1014,9 +1022,12 @@ AlterObjectOwner_internal(Oid classId, Oid objectId, Oid new_ownerId) nattrs = RelationGetNumberOfAttributes(rel); values = palloc0(nattrs * sizeof(Datum)); nulls = palloc0(nattrs * sizeof(bool)); - replaces = palloc0(nattrs * sizeof(bool)); + + /* + * NOTE: Don't use the HeapTupleMarkColumnUpdated() macro here either. + */ values[Anum_owner - 1] = ObjectIdGetDatum(new_ownerId); - replaces[Anum_owner - 1] = true; + updated = bms_add_member(updated, Anum_owner - FirstLowInvalidHeapAttributeNumber); /* * Determine the modified ACL for the new owner. This is only @@ -1032,16 +1043,21 @@ AlterObjectOwner_internal(Oid classId, Oid objectId, Oid new_ownerId) newAcl = aclnewowner(DatumGetAclP(datum), old_ownerId, new_ownerId); + + /* + * NOTE: Don't use the HeapTupleMarkColumnUpdated() macro here + * either. + */ values[Anum_acl - 1] = PointerGetDatum(newAcl); - replaces[Anum_acl - 1] = true; + updated = bms_add_member(updated, Anum_acl - FirstLowInvalidHeapAttributeNumber); } } - newtup = heap_modify_tuple(oldtup, RelationGetDescr(rel), - values, nulls, replaces); + newtup = heap_update_tuple(oldtup, RelationGetDescr(rel), + values, nulls, updated); /* Perform actual update */ - CatalogTupleUpdate(rel, &newtup->t_self, newtup); + CatalogTupleUpdate(rel, &newtup->t_self, newtup, updated, NULL); UnlockTuple(rel, &oldtup->t_self, InplaceUpdateTupleLock); @@ -1051,7 +1067,7 @@ AlterObjectOwner_internal(Oid classId, Oid objectId, Oid new_ownerId) /* Release memory */ pfree(values); pfree(nulls); - pfree(replaces); + bms_free(updated); } else UnlockTuple(rel, &oldtup->t_self, InplaceUpdateTupleLock); diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c index 25089fae3e006..a412b78929daf 100644 --- a/src/backend/commands/analyze.c +++ b/src/backend/commands/analyze.c @@ -12,6 +12,7 @@ * *------------------------------------------------------------------------- */ +#include "catalog/pg_statistic_d.h" #include "postgres.h" #include @@ -1668,48 +1669,34 @@ update_attstats(Oid relid, bool inh, int natts, VacAttrStats **vacattrstats) VacAttrStats *stats = vacattrstats[attno]; HeapTuple stup, oldtup; - int i, - k, + int k, n; - Datum values[Natts_pg_statistic]; - bool nulls[Natts_pg_statistic]; - bool replaces[Natts_pg_statistic]; + Datum values[Natts_pg_statistic] = {0}; + bool nulls[Natts_pg_statistic] = {false}; + Bitmapset *updated = NULL; /* Ignore attr if we weren't able to collect stats */ if (!stats->stats_valid) continue; - /* - * Construct a new pg_statistic tuple - */ - for (i = 0; i < Natts_pg_statistic; ++i) - { - nulls[i] = false; - replaces[i] = true; - } + /* Construct a new pg_statistic tuple */ + HeapTupleUpdateSetAllColumnsUpdated(pg_statistic, updated); + HeapTupleSetValue(pg_statistic, starelid, ObjectIdGetDatum(relid), values); + HeapTupleSetValue(pg_statistic, staattnum, Int16GetDatum(stats->tupattnum), values); + HeapTupleSetValue(pg_statistic, stainherit, BoolGetDatum(inh), values); + HeapTupleSetValue(pg_statistic, stanullfrac, Float4GetDatum(stats->stanullfrac), values); + HeapTupleSetValue(pg_statistic, stawidth, Int32GetDatum(stats->stawidth), values); + HeapTupleSetValue(pg_statistic, stadistinct, Float4GetDatum(stats->stadistinct), values); - values[Anum_pg_statistic_starelid - 1] = ObjectIdGetDatum(relid); - values[Anum_pg_statistic_staattnum - 1] = Int16GetDatum(stats->tupattnum); - values[Anum_pg_statistic_stainherit - 1] = BoolGetDatum(inh); - values[Anum_pg_statistic_stanullfrac - 1] = Float4GetDatum(stats->stanullfrac); - values[Anum_pg_statistic_stawidth - 1] = Int32GetDatum(stats->stawidth); - values[Anum_pg_statistic_stadistinct - 1] = Float4GetDatum(stats->stadistinct); - i = Anum_pg_statistic_stakind1 - 1; for (k = 0; k < STATISTIC_NUM_SLOTS; k++) - { - values[i++] = Int16GetDatum(stats->stakind[k]); /* stakindN */ - } - i = Anum_pg_statistic_staop1 - 1; + HeapTupleSetValue(pg_statistic, stakind1 + k, Int16GetDatum(stats->stakind[k]), values); + for (k = 0; k < STATISTIC_NUM_SLOTS; k++) - { - values[i++] = ObjectIdGetDatum(stats->staop[k]); /* staopN */ - } - i = Anum_pg_statistic_stacoll1 - 1; + HeapTupleSetValue(pg_statistic, staop1 + k, ObjectIdGetDatum(stats->staop[k]), values); + for (k = 0; k < STATISTIC_NUM_SLOTS; k++) - { - values[i++] = ObjectIdGetDatum(stats->stacoll[k]); /* stacollN */ - } - i = Anum_pg_statistic_stanumbers1 - 1; + HeapTupleSetValue(pg_statistic, stacoll1 + k, ObjectIdGetDatum(stats->stacoll[k]), values); + for (k = 0; k < STATISTIC_NUM_SLOTS; k++) { if (stats->stanumbers[k] != NULL) @@ -1721,15 +1708,12 @@ update_attstats(Oid relid, bool inh, int natts, VacAttrStats **vacattrstats) for (n = 0; n < nnum; n++) numdatums[n] = Float4GetDatum(stats->stanumbers[k][n]); arry = construct_array_builtin(numdatums, nnum, FLOAT4OID); - values[i++] = PointerGetDatum(arry); /* stanumbersN */ + HeapTupleSetValue(pg_statistic, stanumbers1 + k, PointerGetDatum(arry), values); } else - { - nulls[i] = true; - values[i++] = (Datum) 0; - } + HeapTupleSetFieldNull(pg_statistic, stanumbers1, (nulls + k)); } - i = Anum_pg_statistic_stavalues1 - 1; + for (k = 0; k < STATISTIC_NUM_SLOTS; k++) { if (stats->stavalues[k] != NULL) @@ -1742,12 +1726,11 @@ update_attstats(Oid relid, bool inh, int natts, VacAttrStats **vacattrstats) stats->statyplen[k], stats->statypbyval[k], stats->statypalign[k]); - values[i++] = PointerGetDatum(arry); /* stavaluesN */ + HeapTupleSetValue(pg_statistic, stavalues1, PointerGetDatum(arry), (values + k)); } else { - nulls[i] = true; - values[i++] = (Datum) 0; + HeapTupleSetFieldNull(pg_statistic, stavalues1, (nulls + k)); } } @@ -1764,22 +1747,23 @@ update_attstats(Oid relid, bool inh, int natts, VacAttrStats **vacattrstats) if (HeapTupleIsValid(oldtup)) { /* Yes, replace it */ - stup = heap_modify_tuple(oldtup, + stup = heap_update_tuple(oldtup, RelationGetDescr(sd), values, nulls, - replaces); + updated); ReleaseSysCache(oldtup); - CatalogTupleUpdateWithInfo(sd, &stup->t_self, stup, indstate); + CatalogTupleUpdate(sd, &stup->t_self, stup, updated, indstate); } else { /* No, insert new tuple */ stup = heap_form_tuple(RelationGetDescr(sd), values, nulls); - CatalogTupleInsertWithInfo(sd, stup, indstate); + CatalogTupleInsert(sd, stup, NULL); } heap_freetuple(stup); + bms_free(updated); } if (indstate != NULL) diff --git a/src/backend/statistics/attribute_stats.c b/src/backend/statistics/attribute_stats.c index ef4d768feab7e..817db4cdefb3e 100644 --- a/src/backend/statistics/attribute_stats.c +++ b/src/backend/statistics/attribute_stats.c @@ -18,6 +18,7 @@ #include "postgres.h" #include "access/heapam.h" +#include "access/htup.h" #include "catalog/indexing.h" #include "catalog/namespace.h" #include "catalog/pg_collation.h" @@ -120,15 +121,15 @@ static bool get_elem_stat_type(Oid atttypid, char atttyptype, Oid *elemtypid, Oid *elem_eq_opr); static Datum text_to_stavalues(const char *staname, FmgrInfo *array_in, Datum d, Oid typid, int32 typmod, bool *ok); -static void set_stats_slot(Datum *values, bool *nulls, bool *replaces, - int16 stakind, Oid staop, Oid stacoll, - Datum stanumbers, bool stanumbers_isnull, - Datum stavalues, bool stavalues_isnull); +static Bitmapset *set_stats_slot(Datum *values, bool *nulls, Bitmapset *updated, + int16 stakind, Oid staop, Oid stacoll, + Datum stanumbers, bool stanumbers_isnull, + Datum stavalues, bool stavalues_isnull); static void upsert_pg_statistic(Relation starel, HeapTuple oldtup, - const Datum *values, const bool *nulls, const bool *replaces); + const Datum *values, const bool *nulls, const Bitmapset *updated); static bool delete_pg_statistic(Oid reloid, AttrNumber attnum, bool stainherit); -static void init_empty_stats_tuple(Oid reloid, int16 attnum, bool inherited, - Datum *values, bool *nulls, bool *replaces); +static Bitmapset *init_empty_stats_tuple(Oid reloid, int16 attnum, bool inherited, + Datum *values, bool *nulls, Bitmapset *updated); /* * Insert or Update Attribute Statistics @@ -184,9 +185,8 @@ attribute_statistics_update(FunctionCallInfo fcinfo) !PG_ARGISNULL(RANGE_EMPTY_FRAC_ARG); Datum values[Natts_pg_statistic] = {0}; - bool nulls[Natts_pg_statistic] = {0}; - bool replaces[Natts_pg_statistic] = {0}; - + bool nulls[Natts_pg_statistic] = {false}; + Bitmapset *updated = NULL; bool result = true; stats_check_required_arg(fcinfo, attarginfo, ATTRELSCHEMA_ARG); @@ -361,25 +361,17 @@ attribute_statistics_update(FunctionCallInfo fcinfo) if (HeapTupleIsValid(statup)) heap_deform_tuple(statup, RelationGetDescr(starel), values, nulls); else - init_empty_stats_tuple(reloid, attnum, inherited, values, nulls, - replaces); + updated = init_empty_stats_tuple(reloid, attnum, inherited, values, nulls, updated); /* if specified, set to argument values */ if (!PG_ARGISNULL(NULL_FRAC_ARG)) - { - values[Anum_pg_statistic_stanullfrac - 1] = PG_GETARG_DATUM(NULL_FRAC_ARG); - replaces[Anum_pg_statistic_stanullfrac - 1] = true; - } + HeapTupleUpdateValue(pg_statistic, stanullfrac, PG_GETARG_DATUM(NULL_FRAC_ARG), values, nulls, updated); + if (!PG_ARGISNULL(AVG_WIDTH_ARG)) - { - values[Anum_pg_statistic_stawidth - 1] = PG_GETARG_DATUM(AVG_WIDTH_ARG); - replaces[Anum_pg_statistic_stawidth - 1] = true; - } + HeapTupleUpdateValue(pg_statistic, stawidth, PG_GETARG_DATUM(AVG_WIDTH_ARG), values, nulls, updated); + if (!PG_ARGISNULL(N_DISTINCT_ARG)) - { - values[Anum_pg_statistic_stadistinct - 1] = PG_GETARG_DATUM(N_DISTINCT_ARG); - replaces[Anum_pg_statistic_stadistinct - 1] = true; - } + HeapTupleUpdateValue(pg_statistic, stadistinct, PG_GETARG_DATUM(N_DISTINCT_ARG), values, nulls, updated); /* STATISTIC_KIND_MCV */ if (do_mcv) @@ -394,10 +386,10 @@ attribute_statistics_update(FunctionCallInfo fcinfo) if (converted) { - set_stats_slot(values, nulls, replaces, - STATISTIC_KIND_MCV, - eq_opr, atttypcoll, - stanumbers, false, stavalues, false); + updated = set_stats_slot(values, nulls, updated, + STATISTIC_KIND_MCV, + eq_opr, atttypcoll, + stanumbers, false, stavalues, false); } else result = false; @@ -417,10 +409,10 @@ attribute_statistics_update(FunctionCallInfo fcinfo) if (converted) { - set_stats_slot(values, nulls, replaces, - STATISTIC_KIND_HISTOGRAM, - lt_opr, atttypcoll, - 0, true, stavalues, false); + updated = set_stats_slot(values, nulls, updated, + STATISTIC_KIND_HISTOGRAM, + lt_opr, atttypcoll, + 0, true, stavalues, false); } else result = false; @@ -433,10 +425,10 @@ attribute_statistics_update(FunctionCallInfo fcinfo) ArrayType *arry = construct_array_builtin(elems, 1, FLOAT4OID); Datum stanumbers = PointerGetDatum(arry); - set_stats_slot(values, nulls, replaces, - STATISTIC_KIND_CORRELATION, - lt_opr, atttypcoll, - stanumbers, false, 0, true); + updated = set_stats_slot(values, nulls, updated, + STATISTIC_KIND_CORRELATION, + lt_opr, atttypcoll, + stanumbers, false, 0, true); } /* STATISTIC_KIND_MCELEM */ @@ -454,10 +446,10 @@ attribute_statistics_update(FunctionCallInfo fcinfo) if (converted) { - set_stats_slot(values, nulls, replaces, - STATISTIC_KIND_MCELEM, - elem_eq_opr, atttypcoll, - stanumbers, false, stavalues, false); + updated = set_stats_slot(values, nulls, updated, + STATISTIC_KIND_MCELEM, + elem_eq_opr, atttypcoll, + stanumbers, false, stavalues, false); } else result = false; @@ -468,10 +460,10 @@ attribute_statistics_update(FunctionCallInfo fcinfo) { Datum stanumbers = PG_GETARG_DATUM(ELEM_COUNT_HISTOGRAM_ARG); - set_stats_slot(values, nulls, replaces, - STATISTIC_KIND_DECHIST, - elem_eq_opr, atttypcoll, - stanumbers, false, 0, true); + updated = set_stats_slot(values, nulls, updated, + STATISTIC_KIND_DECHIST, + elem_eq_opr, atttypcoll, + stanumbers, false, 0, true); } /* @@ -494,10 +486,10 @@ attribute_statistics_update(FunctionCallInfo fcinfo) if (converted) { - set_stats_slot(values, nulls, replaces, - STATISTIC_KIND_BOUNDS_HISTOGRAM, - InvalidOid, InvalidOid, - 0, true, stavalues, false); + updated = set_stats_slot(values, nulls, updated, + STATISTIC_KIND_BOUNDS_HISTOGRAM, + InvalidOid, InvalidOid, + 0, true, stavalues, false); } else result = false; @@ -521,20 +513,21 @@ attribute_statistics_update(FunctionCallInfo fcinfo) if (converted) { - set_stats_slot(values, nulls, replaces, - STATISTIC_KIND_RANGE_LENGTH_HISTOGRAM, - Float8LessOperator, InvalidOid, - stanumbers, false, stavalues, false); + updated = set_stats_slot(values, nulls, updated, + STATISTIC_KIND_RANGE_LENGTH_HISTOGRAM, + Float8LessOperator, InvalidOid, + stanumbers, false, stavalues, false); } else result = false; } - upsert_pg_statistic(starel, statup, values, nulls, replaces); + upsert_pg_statistic(starel, statup, values, nulls, updated); if (HeapTupleIsValid(statup)) ReleaseSysCache(statup); table_close(starel, RowExclusiveLock); + bms_free(updated); return result; } @@ -759,69 +752,63 @@ text_to_stavalues(const char *staname, FmgrInfo *array_in, Datum d, Oid typid, * Find and update the slot with the given stakind, or use the first empty * slot. */ -static void -set_stats_slot(Datum *values, bool *nulls, bool *replaces, +static Bitmapset * +set_stats_slot(Datum *values, bool *nulls, Bitmapset *updated, int16 stakind, Oid staop, Oid stacoll, Datum stanumbers, bool stanumbers_isnull, Datum stavalues, bool stavalues_isnull) { - int slotidx; + int i = 0; int first_empty = -1; - AttrNumber stakind_attnum; - AttrNumber staop_attnum; - AttrNumber stacoll_attnum; - /* find existing slot with given stakind */ - for (slotidx = 0; slotidx < STATISTIC_NUM_SLOTS; slotidx++) + /* + * NOTE: This might seem odd, to be adding 'i' to the name of the field on + * these macros, but that's what we need to do here to find the proper + * slot offset and record the proper value into the updated bitmap. + * + * Example: HeapTupleValue(pg_statistic, stakind1 + i, values); + * + * Becomes: values[Anum_pg_statistic_stakind1 + i - 1]; + * + * The result is you're indexing the i'th value, exactly what we needed. + */ + + /* Find existing slot with given stakind */ + for (i = 0; i < STATISTIC_NUM_SLOTS; i++) { - stakind_attnum = Anum_pg_statistic_stakind1 - 1 + slotidx; + Datum d = HeapTupleValue(pg_statistic, stakind1 + i, values); + int16 v = DatumGetInt16(d); + + if (first_empty < 0 && v == 0) + first_empty = i; - if (first_empty < 0 && - DatumGetInt16(values[stakind_attnum]) == 0) - first_empty = slotidx; - if (DatumGetInt16(values[stakind_attnum]) == stakind) + if (v == stakind) break; } - if (slotidx >= STATISTIC_NUM_SLOTS && first_empty >= 0) - slotidx = first_empty; + if (i >= STATISTIC_NUM_SLOTS && first_empty >= 0) + i = first_empty; - if (slotidx >= STATISTIC_NUM_SLOTS) + if (i >= STATISTIC_NUM_SLOTS) ereport(ERROR, - (errmsg("maximum number of statistics slots exceeded: %d", - slotidx + 1))); + (errmsg("maximum number of statistics slots exceeded: %d", i + 1))); - stakind_attnum = Anum_pg_statistic_stakind1 - 1 + slotidx; - staop_attnum = Anum_pg_statistic_staop1 - 1 + slotidx; - stacoll_attnum = Anum_pg_statistic_stacoll1 - 1 + slotidx; + if (DatumGetInt16(HeapTupleValue(pg_statistic, stakind1 + i, values)) != stakind) + HeapTupleUpdateValue(pg_statistic, stakind1 + i, Int16GetDatum(stakind), values, nulls, updated); + + if (DatumGetInt16(HeapTupleValue(pg_statistic, staop1 + i, values)) != staop) + HeapTupleUpdateValue(pg_statistic, staop1 + i, ObjectIdGetDatum(staop), values, nulls, updated); + + if (DatumGetInt16(HeapTupleValue(pg_statistic, stacoll1 + i, values + i)) != stacoll) + HeapTupleUpdateValue(pg_statistic, stacoll1 + i, ObjectIdGetDatum(stacoll), values, nulls, updated); - if (DatumGetInt16(values[stakind_attnum]) != stakind) - { - values[stakind_attnum] = Int16GetDatum(stakind); - replaces[stakind_attnum] = true; - } - if (DatumGetObjectId(values[staop_attnum]) != staop) - { - values[staop_attnum] = ObjectIdGetDatum(staop); - replaces[staop_attnum] = true; - } - if (DatumGetObjectId(values[stacoll_attnum]) != stacoll) - { - values[stacoll_attnum] = ObjectIdGetDatum(stacoll); - replaces[stacoll_attnum] = true; - } if (!stanumbers_isnull) - { - values[Anum_pg_statistic_stanumbers1 - 1 + slotidx] = stanumbers; - nulls[Anum_pg_statistic_stanumbers1 - 1 + slotidx] = false; - replaces[Anum_pg_statistic_stanumbers1 - 1 + slotidx] = true; - } + HeapTupleUpdateValue(pg_statistic, stanumbers1 + i, stanumbers, values, nulls, updated); + if (!stavalues_isnull) - { - values[Anum_pg_statistic_stavalues1 - 1 + slotidx] = stavalues; - nulls[Anum_pg_statistic_stavalues1 - 1 + slotidx] = false; - replaces[Anum_pg_statistic_stavalues1 - 1 + slotidx] = true; - } + HeapTupleUpdateValue(pg_statistic, stavalues1 + i, stavalues, values, nulls, updated); + + return updated; } /* @@ -829,20 +816,21 @@ set_stats_slot(Datum *values, bool *nulls, bool *replaces, */ static void upsert_pg_statistic(Relation starel, HeapTuple oldtup, - const Datum *values, const bool *nulls, const bool *replaces) + const Datum *values, const bool *nulls, const Bitmapset *updated) { HeapTuple newtup; if (HeapTupleIsValid(oldtup)) { - newtup = heap_modify_tuple(oldtup, RelationGetDescr(starel), - values, nulls, replaces); - CatalogTupleUpdate(starel, &newtup->t_self, newtup); + TupleDesc tupdesc = RelationGetDescr(starel); + + newtup = heap_update_tuple(oldtup, tupdesc, values, nulls, updated); + CatalogTupleUpdate(starel, &newtup->t_self, newtup, updated, NULL); } else { newtup = heap_form_tuple(RelationGetDescr(starel), values, nulls); - CatalogTupleInsert(starel, newtup); + CatalogTupleInsert(starel, newtup, NULL); } heap_freetuple(newtup); @@ -883,39 +871,38 @@ delete_pg_statistic(Oid reloid, AttrNumber attnum, bool stainherit) /* * Initialize values and nulls for a new stats tuple. */ -static void +static Bitmapset * init_empty_stats_tuple(Oid reloid, int16 attnum, bool inherited, - Datum *values, bool *nulls, bool *replaces) + Datum *values, bool *nulls, Bitmapset *updated) { + /* + * NOTE: It is customary to initialize the "nulls" array to all false (0) + * and later, when some field transitions from a value to NULL to mark + * that transition using the proper macro which will set the array + * position to true (1). Here we start with the assumption that all + * values will be set to NULL. + */ + HeapTupleUpdateSetAllColumnsUpdated(pg_statistic, updated); memset(nulls, true, sizeof(bool) * Natts_pg_statistic); - memset(replaces, true, sizeof(bool) * Natts_pg_statistic); /* must initialize non-NULL attributes */ + HeapTupleUpdateValue(pg_statistic, starelid, ObjectIdGetDatum(reloid), values, nulls, updated); + HeapTupleUpdateValue(pg_statistic, staattnum, Int16GetDatum(attnum), values, nulls, updated); + HeapTupleUpdateValue(pg_statistic, stainherit, BoolGetDatum(inherited), values, nulls, updated); - values[Anum_pg_statistic_starelid - 1] = ObjectIdGetDatum(reloid); - nulls[Anum_pg_statistic_starelid - 1] = false; - values[Anum_pg_statistic_staattnum - 1] = Int16GetDatum(attnum); - nulls[Anum_pg_statistic_staattnum - 1] = false; - values[Anum_pg_statistic_stainherit - 1] = BoolGetDatum(inherited); - nulls[Anum_pg_statistic_stainherit - 1] = false; - - values[Anum_pg_statistic_stanullfrac - 1] = DEFAULT_NULL_FRAC; - nulls[Anum_pg_statistic_stanullfrac - 1] = false; - values[Anum_pg_statistic_stawidth - 1] = DEFAULT_AVG_WIDTH; - nulls[Anum_pg_statistic_stawidth - 1] = false; - values[Anum_pg_statistic_stadistinct - 1] = DEFAULT_N_DISTINCT; - nulls[Anum_pg_statistic_stadistinct - 1] = false; + HeapTupleUpdateValue(pg_statistic, stanullfrac, DEFAULT_NULL_FRAC, values, nulls, updated); + HeapTupleUpdateValue(pg_statistic, stawidth, DEFAULT_AVG_WIDTH, values, nulls, updated); + HeapTupleUpdateValue(pg_statistic, stadistinct, DEFAULT_N_DISTINCT, values, nulls, updated); /* initialize stakind, staop, and stacoll slots */ - for (int slotnum = 0; slotnum < STATISTIC_NUM_SLOTS; slotnum++) + for (int i = 0; i < STATISTIC_NUM_SLOTS; i++) { - values[Anum_pg_statistic_stakind1 + slotnum - 1] = (Datum) 0; - nulls[Anum_pg_statistic_stakind1 + slotnum - 1] = false; - values[Anum_pg_statistic_staop1 + slotnum - 1] = ObjectIdGetDatum(InvalidOid); - nulls[Anum_pg_statistic_staop1 + slotnum - 1] = false; - values[Anum_pg_statistic_stacoll1 + slotnum - 1] = ObjectIdGetDatum(InvalidOid); - nulls[Anum_pg_statistic_stacoll1 + slotnum - 1] = false; + HeapTupleUpdateValue(pg_statistic, stakind1 + i, (Datum) 0, values, nulls, updated); + HeapTupleUpdateValue(pg_statistic, staop1 + i, ObjectIdGetDatum(InvalidOid), values, nulls, updated); + HeapTupleUpdateValue(pg_statistic, stacoll1 + i, ObjectIdGetDatum(InvalidOid), values, nulls, updated); } + + return updated; } /* diff --git a/src/include/access/htup.h b/src/include/access/htup.h index f6b766697e297..e67bb718efa46 100644 --- a/src/include/access/htup.h +++ b/src/include/access/htup.h @@ -14,6 +14,7 @@ #ifndef HTUP_H #define HTUP_H +#include "catalog/pg_aggregate_d.h" #include "storage/itemptr.h" /* typedefs and forward declarations for structs defined in htup_details.h */ @@ -77,6 +78,66 @@ typedef HeapTupleData *HeapTuple; */ #define HeapTupleIsValid(tuple) ((tuple) != NULL) +#define HeapTupleValue(table_name, field, values) \ + (values)[Anum_##table_name##_##field - 1] + +/* + * These are useful when forming tuples for CatalogTupleInsert() + */ + +#define HeapTupleSetField(table_name, field, value, form_ptr) \ + (form_ptr)->field = (value) + +#define HeapTupleSetFieldNull(table_name, field, nulls) \ + (nulls)[Anum_##table_name##_##field - 1] = true + +#define HeapTupleSetValue(table_name, field, value, values) \ + (values)[Anum_##table_name##_##field - 1] = (value) + +#define HeapTupleSetValueNull(table_name, field, values, nulls) \ + do { \ + (values)[Anum_##table_name##_##field - 1] = (Datum) 0; \ + (nulls)[Anum_##table_name##_##field - 1] = true; \ + } while(0) + +/* + * These are useful when forming tuples for CatalogTupleUpdate() + * + * Updated catalog tuples need to track which fields were changed when + * calling heap_update_tuple(), so we use a bitmap to keep track of that. + */ +#define HeapTupleMarkColumnUpdated(table_name, field, updated) \ + (updated) = bms_add_member((updated), \ + Anum_##table_name##_##field - FirstLowInvalidHeapAttributeNumber) + +#define HeapTupleUpdateSetAllColumnsUpdated(table_name, updated) \ + (updated) = bms_add_range((updated), 1 - FirstLowInvalidHeapAttributeNumber, \ + Natts_##table_name - FirstLowInvalidHeapAttributeNumber) + +#define HeapTupleSetColumnNotUpdated(table_name, field, updated) \ + (updated) = bms_del_member((updated), \ + Anum_##table_name##_##field - FirstLowInvalidHeapAttributeNumber) + +#define HeapTupleUpdateField(table_name, field, value, form_ptr, updated) \ + do { \ + (form_ptr)->field = (value); \ + HeapTupleMarkColumnUpdated(table_name, field, updated); \ + } while(0) + +#define HeapTupleUpdateValue(table_name, field, value, values, nulls, updated) \ + do { \ + (values)[Anum_##table_name##_##field - 1] = (Datum) (value); \ + (nulls)[Anum_##table_name##_##field - 1] = false; \ + HeapTupleMarkColumnUpdated(table_name, field, updated); \ + } while(0) + +#define HeapTupleUpdateValueNull(table_name, field, values, nulls, updated) \ + do { \ + (values)[Anum_##table_name##_##field - 1] = (Datum) 0; \ + (nulls)[Anum_##table_name##_##field - 1] = true; \ + HeapTupleMarkColumnUpdated(table_name, field, updated); \ + } while(0) + /* HeapTupleHeader functions implemented in utils/time/combocid.c */ extern CommandId HeapTupleHeaderGetCmin(const HeapTupleHeaderData *tup); extern CommandId HeapTupleHeaderGetCmax(const HeapTupleHeaderData *tup); diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h index f3593acc8c2eb..814d764ee974b 100644 --- a/src/include/access/htup_details.h +++ b/src/include/access/htup_details.h @@ -21,6 +21,9 @@ #include "storage/bufpage.h" #include "varatt.h" +/* Forward declarations */ +typedef struct Bitmapset Bitmapset; + /* * MaxTupleAttributeNumber limits the number of (user) columns in a tuple. * The key limit on this value is that the size of the fixed overhead for @@ -835,6 +838,11 @@ extern HeapTuple heap_modify_tuple_by_cols(HeapTuple tuple, const int *replCols, const Datum *replValues, const bool *replIsnull); +extern HeapTuple heap_update_tuple(HeapTuple tuple, + TupleDesc tupleDesc, + const Datum *replValues, + const bool *replIsnull, + const Bitmapset *replaces); extern void heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *values, bool *isnull); extern void heap_freetuple(HeapTuple htup); diff --git a/src/include/catalog/indexing.h b/src/include/catalog/indexing.h index 77c17d3fb7acc..685ff3d2bd176 100644 --- a/src/include/catalog/indexing.h +++ b/src/include/catalog/indexing.h @@ -37,18 +37,13 @@ typedef struct ResultRelInfo *CatalogIndexState; */ extern CatalogIndexState CatalogOpenIndexes(Relation heapRel); extern void CatalogCloseIndexes(CatalogIndexState indstate); -extern void CatalogTupleInsert(Relation heapRel, HeapTuple tup); -extern void CatalogTupleInsertWithInfo(Relation heapRel, HeapTuple tup, - CatalogIndexState indstate); -extern void CatalogTuplesMultiInsertWithInfo(Relation heapRel, - TupleTableSlot **slot, - int ntuples, - CatalogIndexState indstate); +extern void CatalogTupleInsert(Relation heapRel, HeapTuple tup, + CatalogIndexState indstate); +extern void CatalogTuplesMultiInsert(Relation heapRel, TupleTableSlot **slot, + int ntuples, CatalogIndexState indstate); extern void CatalogTupleUpdate(Relation heapRel, const ItemPointerData *otid, - HeapTuple tup); -extern void CatalogTupleUpdateWithInfo(Relation heapRel, - const ItemPointerData *otid, HeapTuple tup, - CatalogIndexState indstate); + HeapTuple tuple, const struct Bitmapset *updated, + CatalogIndexState indstate); extern void CatalogTupleDelete(Relation heapRel, const ItemPointerData *tid); #endif /* INDEXING_H */ From 85f9cb7e93cdd04dc723038eec40cbf741dcc579 Mon Sep 17 00:00:00 2001 From: Greg Burd Date: Fri, 14 Nov 2025 08:43:14 -0500 Subject: [PATCH 3/3] Update the remainder of catalog updates using the new APIs Apply all necessary changes to use the new macros for catalog tuples. This commit finishes the work started in the previous one. There should be no behavioural changes resulting from these commits. This simply provides a syntatic change with the additional ability to maintain the set of updated attributes during catalog updates. --- src/backend/catalog/aclchk.c | 159 +++--- src/backend/catalog/heap.c | 359 ++++++------- src/backend/catalog/index.c | 177 +++--- src/backend/catalog/partition.c | 5 +- src/backend/catalog/pg_attrdef.c | 35 +- src/backend/catalog/pg_cast.c | 18 +- src/backend/catalog/pg_collation.c | 40 +- src/backend/catalog/pg_conversion.c | 22 +- src/backend/catalog/pg_db_role_setting.c | 54 +- src/backend/catalog/pg_depend.c | 72 +-- src/backend/catalog/pg_enum.c | 45 +- src/backend/catalog/pg_inherits.c | 14 +- src/backend/catalog/pg_largeobject.c | 22 +- src/backend/catalog/pg_namespace.c | 24 +- src/backend/catalog/pg_operator.c | 119 ++-- src/backend/catalog/pg_parameter_acl.c | 11 +- src/backend/catalog/pg_proc.c | 110 ++-- src/backend/catalog/pg_publication.c | 36 +- src/backend/catalog/pg_range.c | 20 +- src/backend/catalog/pg_shdepend.c | 60 +-- src/backend/catalog/pg_subscription.c | 86 ++- src/backend/catalog/pg_type.c | 211 ++++---- src/backend/catalog/toasting.c | 7 +- src/backend/commands/amcmds.c | 15 +- src/backend/commands/cluster.c | 80 +-- src/backend/commands/collationcmds.c | 19 +- src/backend/commands/comment.c | 51 +- src/backend/commands/dbcommands.c | 133 +++-- src/backend/commands/event_trigger.c | 42 +- src/backend/commands/extension.c | 107 ++-- src/backend/commands/foreigncmds.c | 205 +++---- src/backend/commands/functioncmds.c | 52 +- src/backend/commands/indexcmds.c | 16 +- src/backend/commands/matview.c | 7 +- src/backend/commands/opclasscmds.c | 82 +-- src/backend/commands/operatorcmds.c | 54 +- src/backend/commands/policy.c | 98 ++-- src/backend/commands/proclang.c | 44 +- src/backend/commands/publicationcmds.c | 85 ++- src/backend/commands/schemacmds.c | 25 +- src/backend/commands/seclabel.c | 57 +- src/backend/commands/sequence.c | 32 +- src/backend/commands/statscmds.c | 50 +- src/backend/commands/subscriptioncmds.c | 187 +++---- src/backend/commands/tablecmds.c | 567 ++++++++++++-------- src/backend/commands/tablespace.c | 47 +- src/backend/commands/trigger.c | 107 ++-- src/backend/commands/tsearchcmds.c | 169 +++--- src/backend/commands/typecmds.c | 136 ++--- src/backend/commands/user.c | 228 +++----- src/backend/replication/logical/origin.c | 10 +- src/backend/replication/logical/tablesync.c | 22 +- src/backend/replication/logical/worker.c | 17 +- src/backend/rewrite/rewriteDefine.c | 59 +- src/backend/rewrite/rewriteSupport.c | 6 +- src/backend/statistics/extended_stats.c | 65 ++- src/backend/statistics/relation_stats.c | 40 +- src/backend/storage/large_object/inv_api.c | 53 +- src/backend/utils/cache/relcache.c | 20 +- 59 files changed, 2227 insertions(+), 2466 deletions(-) diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c index cd139bd65a668..3943d780a2219 100644 --- a/src/backend/catalog/aclchk.c +++ b/src/backend/catalog/aclchk.c @@ -1316,8 +1316,7 @@ SetDefaultACL(InternalDefaultACL *iacls) else { Datum values[Natts_pg_default_acl] = {0}; - bool nulls[Natts_pg_default_acl] = {0}; - bool replaces[Natts_pg_default_acl] = {0}; + bool nulls[Natts_pg_default_acl] = {false}; Oid defAclOid; if (isNew) @@ -1325,26 +1324,28 @@ SetDefaultACL(InternalDefaultACL *iacls) /* insert new entry */ defAclOid = GetNewOidWithIndex(rel, DefaultAclOidIndexId, Anum_pg_default_acl_oid); - values[Anum_pg_default_acl_oid - 1] = ObjectIdGetDatum(defAclOid); - values[Anum_pg_default_acl_defaclrole - 1] = ObjectIdGetDatum(iacls->roleid); - values[Anum_pg_default_acl_defaclnamespace - 1] = ObjectIdGetDatum(iacls->nspid); - values[Anum_pg_default_acl_defaclobjtype - 1] = CharGetDatum(objtype); - values[Anum_pg_default_acl_defaclacl - 1] = PointerGetDatum(new_acl); + HeapTupleSetValue(pg_default_acl, oid, ObjectIdGetDatum(defAclOid), values); + HeapTupleSetValue(pg_default_acl, defaclrole, ObjectIdGetDatum(iacls->roleid), values); + HeapTupleSetValue(pg_default_acl, defaclnamespace, ObjectIdGetDatum(iacls->nspid), values); + HeapTupleSetValue(pg_default_acl, defaclobjtype, CharGetDatum(objtype), values); + HeapTupleSetValue(pg_default_acl, defaclacl, PointerGetDatum(new_acl), values); newtuple = heap_form_tuple(RelationGetDescr(rel), values, nulls); - CatalogTupleInsert(rel, newtuple); + CatalogTupleInsert(rel, newtuple, NULL); } else { + Bitmapset *updated = NULL; + defAclOid = ((Form_pg_default_acl) GETSTRUCT(tuple))->oid; /* update existing entry */ - values[Anum_pg_default_acl_defaclacl - 1] = PointerGetDatum(new_acl); - replaces[Anum_pg_default_acl_defaclacl - 1] = true; + HeapTupleUpdateValue(pg_default_acl, defaclacl, PointerGetDatum(new_acl), values, nulls, updated); + + newtuple = heap_update_tuple(tuple, RelationGetDescr(rel), values, nulls, updated); + CatalogTupleUpdate(rel, &newtuple->t_self, newtuple, updated, NULL); - newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel), - values, nulls, replaces); - CatalogTupleUpdate(rel, &newtuple->t_self, newtuple); + bms_free(updated); } /* these dependencies don't change in an update */ @@ -1650,12 +1651,12 @@ ExecGrant_Attribute(InternalGrant *istmt, Oid relOid, const char *relname, bool need_update; HeapTuple newtuple; Datum values[Natts_pg_attribute] = {0}; - bool nulls[Natts_pg_attribute] = {0}; - bool replaces[Natts_pg_attribute] = {0}; + bool nulls[Natts_pg_attribute] = {false}; int noldmembers; int nnewmembers; Oid *oldmembers; Oid *newmembers; + Bitmapset *updated = NULL; attr_tuple = SearchSysCache2(ATTNUM, ObjectIdGetDatum(relOid), @@ -1742,22 +1743,21 @@ ExecGrant_Attribute(InternalGrant *istmt, Oid relOid, const char *relname, */ if (ACL_NUM(new_acl) > 0) { - values[Anum_pg_attribute_attacl - 1] = PointerGetDatum(new_acl); + HeapTupleUpdateValue(pg_attribute, attacl, PointerGetDatum(new_acl), values, nulls, updated); need_update = true; } else { - nulls[Anum_pg_attribute_attacl - 1] = true; + HeapTupleUpdateValueNull(pg_attribute, attacl, values, nulls, updated); need_update = !isNull; } - replaces[Anum_pg_attribute_attacl - 1] = true; if (need_update) { - newtuple = heap_modify_tuple(attr_tuple, RelationGetDescr(attRelation), - values, nulls, replaces); + newtuple = heap_update_tuple(attr_tuple, RelationGetDescr(attRelation), + values, nulls, updated); - CatalogTupleUpdate(attRelation, &newtuple->t_self, newtuple); + CatalogTupleUpdate(attRelation, &newtuple->t_self, newtuple, updated, NULL); /* Update initial privileges for extensions */ recordExtensionInitPriv(relOid, RelationRelationId, attnum, @@ -1773,6 +1773,7 @@ ExecGrant_Attribute(InternalGrant *istmt, Oid relOid, const char *relname, pfree(new_acl); ReleaseSysCache(attr_tuple); + bms_free(updated); } /* @@ -1960,8 +1961,8 @@ ExecGrant_Relation(InternalGrant *istmt) Oid grantorId; HeapTuple newtuple; Datum values[Natts_pg_class] = {0}; - bool nulls[Natts_pg_class] = {0}; - bool replaces[Natts_pg_class] = {0}; + bool nulls[Natts_pg_class] = {false}; + Bitmapset *updated = NULL; int nnewmembers; Oid *newmembers; ObjectType objtype; @@ -2011,13 +2012,12 @@ ExecGrant_Relation(InternalGrant *istmt) nnewmembers = aclmembers(new_acl, &newmembers); /* finished building new ACL value, now insert it */ - replaces[Anum_pg_class_relacl - 1] = true; - values[Anum_pg_class_relacl - 1] = PointerGetDatum(new_acl); + HeapTupleUpdateValue(pg_class, relacl, PointerGetDatum(new_acl), values, nulls, updated); - newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), - values, nulls, replaces); + newtuple = heap_update_tuple(tuple, RelationGetDescr(relation), + values, nulls, updated); - CatalogTupleUpdate(relation, &newtuple->t_self, newtuple); + CatalogTupleUpdate(relation, &newtuple->t_self, newtuple, updated, NULL); UnlockTuple(relation, &tuple->t_self, InplaceUpdateTupleLock); /* Update initial privileges for extensions */ @@ -2030,6 +2030,7 @@ ExecGrant_Relation(InternalGrant *istmt) nnewmembers, newmembers); pfree(new_acl); + bms_free(updated); } else UnlockTuple(relation, &tuple->t_self, InplaceUpdateTupleLock); @@ -2140,7 +2141,7 @@ ExecGrant_common(InternalGrant *istmt, Oid classid, AclMode default_privs, HeapTuple newtuple; Datum *values = palloc0_array(Datum, RelationGetDescr(relation)->natts); bool *nulls = palloc0_array(bool, RelationGetDescr(relation)->natts); - bool *replaces = palloc0_array(bool, RelationGetDescr(relation)->natts); + Bitmapset *updated = NULL; int noldmembers; int nnewmembers; Oid *oldmembers; @@ -2214,14 +2215,17 @@ ExecGrant_common(InternalGrant *istmt, Oid classid, AclMode default_privs, */ nnewmembers = aclmembers(new_acl, &newmembers); - /* finished building new ACL value, now insert it */ - replaces[get_object_attnum_acl(classid) - 1] = true; + /* + * Finished building new ACL value, now insert it. NOTE: We can't use + * the HeapTupleMarkColumnUpdated() macro here because + * get_object_attnum_acl(classid) provides an index. + */ values[get_object_attnum_acl(classid) - 1] = PointerGetDatum(new_acl); + updated = bms_add_member(updated, get_object_attnum_acl(classid) - FirstLowInvalidHeapAttributeNumber); - newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values, - nulls, replaces); + newtuple = heap_update_tuple(tuple, RelationGetDescr(relation), values, nulls, updated); - CatalogTupleUpdate(relation, &newtuple->t_self, newtuple); + CatalogTupleUpdate(relation, &newtuple->t_self, newtuple, updated, NULL); UnlockTuple(relation, &tuple->t_self, InplaceUpdateTupleLock); /* Update initial privileges for extensions */ @@ -2237,6 +2241,7 @@ ExecGrant_common(InternalGrant *istmt, Oid classid, AclMode default_privs, ReleaseSysCache(tuple); pfree(new_acl); + bms_free(updated); /* prevent error when processing duplicate objects */ CommandCounterIncrement(); @@ -2288,8 +2293,8 @@ ExecGrant_Largeobject(InternalGrant *istmt) Oid ownerId; HeapTuple newtuple; Datum values[Natts_pg_largeobject_metadata] = {0}; - bool nulls[Natts_pg_largeobject_metadata] = {0}; - bool replaces[Natts_pg_largeobject_metadata] = {0}; + bool nulls[Natts_pg_largeobject_metadata] = {false}; + Bitmapset *updated = NULL; int noldmembers; int nnewmembers; Oid *oldmembers; @@ -2367,14 +2372,12 @@ ExecGrant_Largeobject(InternalGrant *istmt) nnewmembers = aclmembers(new_acl, &newmembers); /* finished building new ACL value, now insert it */ - replaces[Anum_pg_largeobject_metadata_lomacl - 1] = true; - values[Anum_pg_largeobject_metadata_lomacl - 1] - = PointerGetDatum(new_acl); + HeapTupleUpdateValue(pg_largeobject_metadata, lomacl, PointerGetDatum(new_acl), values, nulls, updated); - newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), - values, nulls, replaces); + newtuple = heap_update_tuple(tuple, RelationGetDescr(relation), + values, nulls, updated); - CatalogTupleUpdate(relation, &newtuple->t_self, newtuple); + CatalogTupleUpdate(relation, &newtuple->t_self, newtuple, updated, NULL); /* Update initial privileges for extensions */ recordExtensionInitPriv(loid, LargeObjectRelationId, 0, new_acl); @@ -2389,6 +2392,7 @@ ExecGrant_Largeobject(InternalGrant *istmt) systable_endscan(scan); pfree(new_acl); + bms_free(updated); /* prevent error when processing duplicate objects */ CommandCounterIncrement(); @@ -2527,16 +2531,16 @@ ExecGrant_Parameter(InternalGrant *istmt) /* finished building new ACL value, now insert it */ HeapTuple newtuple; Datum values[Natts_pg_parameter_acl] = {0}; - bool nulls[Natts_pg_parameter_acl] = {0}; - bool replaces[Natts_pg_parameter_acl] = {0}; + bool nulls[Natts_pg_parameter_acl] = {false}; + Bitmapset *updated = NULL; - replaces[Anum_pg_parameter_acl_paracl - 1] = true; - values[Anum_pg_parameter_acl_paracl - 1] = PointerGetDatum(new_acl); + HeapTupleUpdateValue(pg_parameter_acl, paracl, PointerGetDatum(new_acl), values, nulls, updated); - newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), - values, nulls, replaces); + newtuple = heap_update_tuple(tuple, RelationGetDescr(relation), + values, nulls, updated); - CatalogTupleUpdate(relation, &newtuple->t_self, newtuple); + CatalogTupleUpdate(relation, &newtuple->t_self, newtuple, updated, NULL); + bms_free(updated); } /* Update initial privileges for extensions */ @@ -4667,8 +4671,8 @@ recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid, if (HeapTupleIsValid(oldtuple)) { Datum values[Natts_pg_init_privs] = {0}; - bool nulls[Natts_pg_init_privs] = {0}; - bool replace[Natts_pg_init_privs] = {0}; + bool nulls[Natts_pg_init_privs] = {false}; + Bitmapset *updated = NULL; Datum oldAclDatum; bool isNull; Acl *old_acl; @@ -4687,13 +4691,13 @@ recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid, /* If we have a new ACL to set, then update the row with it. */ if (new_acl && ACL_NUM(new_acl) != 0) { - values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl); - replace[Anum_pg_init_privs_initprivs - 1] = true; + HeapTupleUpdateValue(pg_init_privs, initprivs, PointerGetDatum(new_acl), values, nulls, updated); - oldtuple = heap_modify_tuple(oldtuple, RelationGetDescr(relation), - values, nulls, replace); + oldtuple = heap_update_tuple(oldtuple, RelationGetDescr(relation), + values, nulls, updated); - CatalogTupleUpdate(relation, &oldtuple->t_self, oldtuple); + CatalogTupleUpdate(relation, &oldtuple->t_self, oldtuple, updated, NULL); + bms_free(updated); } else { @@ -4704,7 +4708,7 @@ recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid, else { Datum values[Natts_pg_init_privs] = {0}; - bool nulls[Natts_pg_init_privs] = {0}; + bool nulls[Natts_pg_init_privs] = {false}; /* * Only add a new entry if the new ACL is non-NULL. @@ -4715,19 +4719,18 @@ recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid, if (new_acl && ACL_NUM(new_acl) != 0) { /* No entry found, so add it. */ - values[Anum_pg_init_privs_objoid - 1] = ObjectIdGetDatum(objoid); - values[Anum_pg_init_privs_classoid - 1] = ObjectIdGetDatum(classoid); - values[Anum_pg_init_privs_objsubid - 1] = Int32GetDatum(objsubid); + HeapTupleSetValue(pg_init_privs, objoid, ObjectIdGetDatum(objoid), values); + HeapTupleSetValue(pg_init_privs, classoid, ObjectIdGetDatum(classoid), values); + HeapTupleSetValue(pg_init_privs, objsubid, Int32GetDatum(objsubid), values); /* This function only handles initial privileges of extensions */ - values[Anum_pg_init_privs_privtype - 1] = - CharGetDatum(INITPRIVS_EXTENSION); + HeapTupleSetValue(pg_init_privs, privtype, CharGetDatum(INITPRIVS_EXTENSION), values); - values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl); + HeapTupleSetValue(pg_init_privs, initprivs, PointerGetDatum(new_acl), values); tuple = heap_form_tuple(RelationGetDescr(relation), values, nulls); - CatalogTupleInsert(relation, tuple); + CatalogTupleInsert(relation, tuple, NULL); /* Update pg_shdepend, too. */ noldmembers = 0; @@ -4826,16 +4829,16 @@ ReplaceRoleInInitPriv(Oid oldroleid, Oid newroleid, else { Datum values[Natts_pg_init_privs] = {0}; - bool nulls[Natts_pg_init_privs] = {0}; - bool replaces[Natts_pg_init_privs] = {0}; + bool nulls[Natts_pg_init_privs] = {false}; + Bitmapset *updated = NULL; /* Update existing entry. */ - values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl); - replaces[Anum_pg_init_privs_initprivs - 1] = true; + HeapTupleUpdateValue(pg_init_privs, initprivs, PointerGetDatum(new_acl), values, nulls, updated); - newtuple = heap_modify_tuple(oldtuple, RelationGetDescr(rel), - values, nulls, replaces); - CatalogTupleUpdate(rel, &newtuple->t_self, newtuple); + newtuple = heap_update_tuple(oldtuple, RelationGetDescr(rel), + values, nulls, updated); + CatalogTupleUpdate(rel, &newtuple->t_self, newtuple, updated, NULL); + bms_free(updated); } /* @@ -4962,16 +4965,16 @@ RemoveRoleFromInitPriv(Oid roleid, Oid classid, Oid objid, int32 objsubid) else { Datum values[Natts_pg_init_privs] = {0}; - bool nulls[Natts_pg_init_privs] = {0}; - bool replaces[Natts_pg_init_privs] = {0}; + bool nulls[Natts_pg_init_privs] = {false}; + Bitmapset *updated2 = NULL; /* Update existing entry. */ - values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl); - replaces[Anum_pg_init_privs_initprivs - 1] = true; + HeapTupleUpdateValue(pg_init_privs, initprivs, PointerGetDatum(new_acl), values, nulls, updated2); - newtuple = heap_modify_tuple(oldtuple, RelationGetDescr(rel), - values, nulls, replaces); - CatalogTupleUpdate(rel, &newtuple->t_self, newtuple); + newtuple = heap_update_tuple(oldtuple, RelationGetDescr(rel), + values, nulls, updated2); + CatalogTupleUpdate(rel, &newtuple->t_self, newtuple, updated2, NULL); + bms_free(updated2); } /* diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index fd6537567ea27..a70d61c8f6b54 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -30,6 +30,7 @@ #include "postgres.h" #include "access/genam.h" +#include "access/htup.h" #include "access/multixact.h" #include "access/relation.h" #include "access/table.h" @@ -705,7 +706,7 @@ CheckAttributeType(const char *attname, * number of elements as tupdesc or be NULL. The other variable-length fields * of pg_attribute are always initialized to null values. * - * indstate is the index state for CatalogTupleInsertWithInfo. It can be + * indstate is the index state for CatalogTupleInsert. It can be * passed as NULL, in which case we'll fetch the necessary info. (Don't do * this when inserting multiple attributes, because it's a tad more * expensive.) @@ -720,7 +721,7 @@ InsertPgAttributeTuples(Relation pg_attribute_rel, const FormExtraData_pg_attribute tupdesc_extra[], CatalogIndexState indstate) { - TupleTableSlot **slot; + TupleTableSlot **slots; TupleDesc td; int nslots; int natts = 0; @@ -732,66 +733,70 @@ InsertPgAttributeTuples(Relation pg_attribute_rel, /* Initialize the number of slots to use */ nslots = Min(tupdesc->natts, (MAX_CATALOG_MULTI_INSERT_BYTES / sizeof(FormData_pg_attribute))); - slot = palloc(sizeof(TupleTableSlot *) * nslots); + slots = palloc(sizeof(TupleTableSlot *) * nslots); for (int i = 0; i < nslots; i++) - slot[i] = MakeSingleTupleTableSlot(td, &TTSOpsHeapTuple); + slots[i] = MakeSingleTupleTableSlot(td, &TTSOpsHeapTuple); while (natts < tupdesc->natts) { + TupleTableSlot *slot = slots[slotCount]; + Datum *values = slot->tts_values; Form_pg_attribute attrs = TupleDescAttr(tupdesc, natts); const FormExtraData_pg_attribute *attrs_extra = tupdesc_extra ? &tupdesc_extra[natts] : NULL; - ExecClearTuple(slot[slotCount]); + ExecClearTuple(slot); - memset(slot[slotCount]->tts_isnull, false, - slot[slotCount]->tts_tupleDescriptor->natts * sizeof(bool)); + memset(slot->tts_isnull, false, + slot->tts_tupleDescriptor->natts * sizeof(bool)); if (new_rel_oid != InvalidOid) - slot[slotCount]->tts_values[Anum_pg_attribute_attrelid - 1] = ObjectIdGetDatum(new_rel_oid); + HeapTupleSetValue(pg_attribute, attrelid, ObjectIdGetDatum(new_rel_oid), values); else - slot[slotCount]->tts_values[Anum_pg_attribute_attrelid - 1] = ObjectIdGetDatum(attrs->attrelid); - - slot[slotCount]->tts_values[Anum_pg_attribute_attname - 1] = NameGetDatum(&attrs->attname); - slot[slotCount]->tts_values[Anum_pg_attribute_atttypid - 1] = ObjectIdGetDatum(attrs->atttypid); - slot[slotCount]->tts_values[Anum_pg_attribute_attlen - 1] = Int16GetDatum(attrs->attlen); - slot[slotCount]->tts_values[Anum_pg_attribute_attnum - 1] = Int16GetDatum(attrs->attnum); - slot[slotCount]->tts_values[Anum_pg_attribute_atttypmod - 1] = Int32GetDatum(attrs->atttypmod); - slot[slotCount]->tts_values[Anum_pg_attribute_attndims - 1] = Int16GetDatum(attrs->attndims); - slot[slotCount]->tts_values[Anum_pg_attribute_attbyval - 1] = BoolGetDatum(attrs->attbyval); - slot[slotCount]->tts_values[Anum_pg_attribute_attalign - 1] = CharGetDatum(attrs->attalign); - slot[slotCount]->tts_values[Anum_pg_attribute_attstorage - 1] = CharGetDatum(attrs->attstorage); - slot[slotCount]->tts_values[Anum_pg_attribute_attcompression - 1] = CharGetDatum(attrs->attcompression); - slot[slotCount]->tts_values[Anum_pg_attribute_attnotnull - 1] = BoolGetDatum(attrs->attnotnull); - slot[slotCount]->tts_values[Anum_pg_attribute_atthasdef - 1] = BoolGetDatum(attrs->atthasdef); - slot[slotCount]->tts_values[Anum_pg_attribute_atthasmissing - 1] = BoolGetDatum(attrs->atthasmissing); - slot[slotCount]->tts_values[Anum_pg_attribute_attidentity - 1] = CharGetDatum(attrs->attidentity); - slot[slotCount]->tts_values[Anum_pg_attribute_attgenerated - 1] = CharGetDatum(attrs->attgenerated); - slot[slotCount]->tts_values[Anum_pg_attribute_attisdropped - 1] = BoolGetDatum(attrs->attisdropped); - slot[slotCount]->tts_values[Anum_pg_attribute_attislocal - 1] = BoolGetDatum(attrs->attislocal); - slot[slotCount]->tts_values[Anum_pg_attribute_attinhcount - 1] = Int16GetDatum(attrs->attinhcount); - slot[slotCount]->tts_values[Anum_pg_attribute_attcollation - 1] = ObjectIdGetDatum(attrs->attcollation); + HeapTupleSetValue(pg_attribute, attrelid, ObjectIdGetDatum(attrs->attrelid), values); + + HeapTupleSetValue(pg_attribute, attname, NameGetDatum(&attrs->attname), values); + HeapTupleSetValue(pg_attribute, atttypid, ObjectIdGetDatum(attrs->atttypid), values); + HeapTupleSetValue(pg_attribute, attlen, Int16GetDatum(attrs->attlen), values); + HeapTupleSetValue(pg_attribute, attnum, Int16GetDatum(attrs->attnum), values); + HeapTupleSetValue(pg_attribute, atttypmod, Int32GetDatum(attrs->atttypmod), values); + HeapTupleSetValue(pg_attribute, attndims, Int16GetDatum(attrs->attndims), values); + HeapTupleSetValue(pg_attribute, attbyval, BoolGetDatum(attrs->attbyval), values); + HeapTupleSetValue(pg_attribute, attalign, CharGetDatum(attrs->attalign), values); + HeapTupleSetValue(pg_attribute, attstorage, CharGetDatum(attrs->attstorage), values); + HeapTupleSetValue(pg_attribute, attcompression, CharGetDatum(attrs->attcompression), values); + HeapTupleSetValue(pg_attribute, attnotnull, BoolGetDatum(attrs->attnotnull), values); + HeapTupleSetValue(pg_attribute, atthasdef, BoolGetDatum(attrs->atthasdef), values); + HeapTupleSetValue(pg_attribute, atthasmissing, BoolGetDatum(attrs->atthasmissing), values); + HeapTupleSetValue(pg_attribute, attidentity, CharGetDatum(attrs->attidentity), values); + HeapTupleSetValue(pg_attribute, attgenerated, CharGetDatum(attrs->attgenerated), values); + HeapTupleSetValue(pg_attribute, attisdropped, BoolGetDatum(attrs->attisdropped), values); + HeapTupleSetValue(pg_attribute, attislocal, BoolGetDatum(attrs->attislocal), values); + HeapTupleSetValue(pg_attribute, attinhcount, Int16GetDatum(attrs->attinhcount), values); + HeapTupleSetValue(pg_attribute, attcollation, ObjectIdGetDatum(attrs->attcollation), values); if (attrs_extra) { - slot[slotCount]->tts_values[Anum_pg_attribute_attstattarget - 1] = attrs_extra->attstattarget.value; - slot[slotCount]->tts_isnull[Anum_pg_attribute_attstattarget - 1] = attrs_extra->attstattarget.isnull; + HeapTupleSetValue(pg_attribute, attstattarget, attrs_extra->attstattarget.value, values); + if (attrs_extra->attstattarget.isnull) + HeapTupleSetValueNull(pg_attribute, attstattarget, values, slot->tts_isnull); - slot[slotCount]->tts_values[Anum_pg_attribute_attoptions - 1] = attrs_extra->attoptions.value; - slot[slotCount]->tts_isnull[Anum_pg_attribute_attoptions - 1] = attrs_extra->attoptions.isnull; + HeapTupleSetValue(pg_attribute, attoptions, attrs_extra->attoptions.value, values); + if (attrs_extra->attoptions.isnull) + HeapTupleSetValueNull(pg_attribute, attoptions, values, slot->tts_isnull); } else { - slot[slotCount]->tts_isnull[Anum_pg_attribute_attstattarget - 1] = true; - slot[slotCount]->tts_isnull[Anum_pg_attribute_attoptions - 1] = true; + HeapTupleSetValueNull(pg_attribute, attstattarget, values, slot->tts_isnull); + HeapTupleSetValueNull(pg_attribute, attoptions, values, slot->tts_isnull); } /* * The remaining fields are not set for new columns. */ - slot[slotCount]->tts_isnull[Anum_pg_attribute_attacl - 1] = true; - slot[slotCount]->tts_isnull[Anum_pg_attribute_attfdwoptions - 1] = true; - slot[slotCount]->tts_isnull[Anum_pg_attribute_attmissingval - 1] = true; + HeapTupleSetValueNull(pg_attribute, attacl, values, slot->tts_isnull); + HeapTupleSetValueNull(pg_attribute, attfdwoptions, values, slot->tts_isnull); + HeapTupleSetValueNull(pg_attribute, attmissingval, values, slot->tts_isnull); - ExecStoreVirtualTuple(slot[slotCount]); + ExecStoreVirtualTuple(slot); slotCount++; /* @@ -808,8 +813,7 @@ InsertPgAttributeTuples(Relation pg_attribute_rel, } /* insert the new tuples and update the indexes */ - CatalogTuplesMultiInsertWithInfo(pg_attribute_rel, slot, slotCount, - indstate); + CatalogTuplesMultiInsert(pg_attribute_rel, slots, slotCount, indstate); slotCount = 0; } @@ -819,8 +823,8 @@ InsertPgAttributeTuples(Relation pg_attribute_rel, if (close_index) CatalogCloseIndexes(indstate); for (int i = 0; i < nslots; i++) - ExecDropSingleTupleTableSlot(slot[i]); - pfree(slot); + ExecDropSingleTupleTableSlot(slots[i]); + pfree(slots); } /* -------------------------------- @@ -914,61 +918,58 @@ InsertPgClassTuple(Relation pg_class_desc, Datum reloptions) { Form_pg_class rd_rel = new_rel_desc->rd_rel; - Datum values[Natts_pg_class]; - bool nulls[Natts_pg_class]; + Datum values[Natts_pg_class] = {0}; + bool nulls[Natts_pg_class] = {false}; HeapTuple tup; /* This is a tad tedious, but way cleaner than what we used to do... */ - memset(values, 0, sizeof(values)); - memset(nulls, false, sizeof(nulls)); - - values[Anum_pg_class_oid - 1] = ObjectIdGetDatum(new_rel_oid); - values[Anum_pg_class_relname - 1] = NameGetDatum(&rd_rel->relname); - values[Anum_pg_class_relnamespace - 1] = ObjectIdGetDatum(rd_rel->relnamespace); - values[Anum_pg_class_reltype - 1] = ObjectIdGetDatum(rd_rel->reltype); - values[Anum_pg_class_reloftype - 1] = ObjectIdGetDatum(rd_rel->reloftype); - values[Anum_pg_class_relowner - 1] = ObjectIdGetDatum(rd_rel->relowner); - values[Anum_pg_class_relam - 1] = ObjectIdGetDatum(rd_rel->relam); - values[Anum_pg_class_relfilenode - 1] = ObjectIdGetDatum(rd_rel->relfilenode); - values[Anum_pg_class_reltablespace - 1] = ObjectIdGetDatum(rd_rel->reltablespace); - values[Anum_pg_class_relpages - 1] = Int32GetDatum(rd_rel->relpages); - values[Anum_pg_class_reltuples - 1] = Float4GetDatum(rd_rel->reltuples); - values[Anum_pg_class_relallvisible - 1] = Int32GetDatum(rd_rel->relallvisible); - values[Anum_pg_class_relallfrozen - 1] = Int32GetDatum(rd_rel->relallfrozen); - values[Anum_pg_class_reltoastrelid - 1] = ObjectIdGetDatum(rd_rel->reltoastrelid); - values[Anum_pg_class_relhasindex - 1] = BoolGetDatum(rd_rel->relhasindex); - values[Anum_pg_class_relisshared - 1] = BoolGetDatum(rd_rel->relisshared); - values[Anum_pg_class_relpersistence - 1] = CharGetDatum(rd_rel->relpersistence); - values[Anum_pg_class_relkind - 1] = CharGetDatum(rd_rel->relkind); - values[Anum_pg_class_relnatts - 1] = Int16GetDatum(rd_rel->relnatts); - values[Anum_pg_class_relchecks - 1] = Int16GetDatum(rd_rel->relchecks); - values[Anum_pg_class_relhasrules - 1] = BoolGetDatum(rd_rel->relhasrules); - values[Anum_pg_class_relhastriggers - 1] = BoolGetDatum(rd_rel->relhastriggers); - values[Anum_pg_class_relrowsecurity - 1] = BoolGetDatum(rd_rel->relrowsecurity); - values[Anum_pg_class_relforcerowsecurity - 1] = BoolGetDatum(rd_rel->relforcerowsecurity); - values[Anum_pg_class_relhassubclass - 1] = BoolGetDatum(rd_rel->relhassubclass); - values[Anum_pg_class_relispopulated - 1] = BoolGetDatum(rd_rel->relispopulated); - values[Anum_pg_class_relreplident - 1] = CharGetDatum(rd_rel->relreplident); - values[Anum_pg_class_relispartition - 1] = BoolGetDatum(rd_rel->relispartition); - values[Anum_pg_class_relrewrite - 1] = ObjectIdGetDatum(rd_rel->relrewrite); - values[Anum_pg_class_relfrozenxid - 1] = TransactionIdGetDatum(rd_rel->relfrozenxid); - values[Anum_pg_class_relminmxid - 1] = MultiXactIdGetDatum(rd_rel->relminmxid); + HeapTupleSetValue(pg_class, oid, ObjectIdGetDatum(new_rel_oid), values); + HeapTupleSetValue(pg_class, relname, NameGetDatum(&rd_rel->relname), values); + HeapTupleSetValue(pg_class, relnamespace, ObjectIdGetDatum(rd_rel->relnamespace), values); + HeapTupleSetValue(pg_class, reltype, ObjectIdGetDatum(rd_rel->reltype), values); + HeapTupleSetValue(pg_class, reloftype, ObjectIdGetDatum(rd_rel->reloftype), values); + HeapTupleSetValue(pg_class, relowner, ObjectIdGetDatum(rd_rel->relowner), values); + HeapTupleSetValue(pg_class, relam, ObjectIdGetDatum(rd_rel->relam), values); + HeapTupleSetValue(pg_class, relfilenode, ObjectIdGetDatum(rd_rel->relfilenode), values); + HeapTupleSetValue(pg_class, reltablespace, ObjectIdGetDatum(rd_rel->reltablespace), values); + HeapTupleSetValue(pg_class, relpages, Int32GetDatum(rd_rel->relpages), values); + HeapTupleSetValue(pg_class, reltuples, Float4GetDatum(rd_rel->reltuples), values); + HeapTupleSetValue(pg_class, relallvisible, Int32GetDatum(rd_rel->relallvisible), values); + HeapTupleSetValue(pg_class, relallfrozen, Int32GetDatum(rd_rel->relallfrozen), values); + HeapTupleSetValue(pg_class, reltoastrelid, ObjectIdGetDatum(rd_rel->reltoastrelid), values); + HeapTupleSetValue(pg_class, relhasindex, BoolGetDatum(rd_rel->relhasindex), values); + HeapTupleSetValue(pg_class, relisshared, BoolGetDatum(rd_rel->relisshared), values); + HeapTupleSetValue(pg_class, relpersistence, CharGetDatum(rd_rel->relpersistence), values); + HeapTupleSetValue(pg_class, relkind, CharGetDatum(rd_rel->relkind), values); + HeapTupleSetValue(pg_class, relnatts, Int16GetDatum(rd_rel->relnatts), values); + HeapTupleSetValue(pg_class, relchecks, Int16GetDatum(rd_rel->relchecks), values); + HeapTupleSetValue(pg_class, relhasrules, BoolGetDatum(rd_rel->relhasrules), values); + HeapTupleSetValue(pg_class, relhastriggers, BoolGetDatum(rd_rel->relhastriggers), values); + HeapTupleSetValue(pg_class, relrowsecurity, BoolGetDatum(rd_rel->relrowsecurity), values); + HeapTupleSetValue(pg_class, relforcerowsecurity, BoolGetDatum(rd_rel->relforcerowsecurity), values); + HeapTupleSetValue(pg_class, relhassubclass, BoolGetDatum(rd_rel->relhassubclass), values); + HeapTupleSetValue(pg_class, relispopulated, BoolGetDatum(rd_rel->relispopulated), values); + HeapTupleSetValue(pg_class, relreplident, CharGetDatum(rd_rel->relreplident), values); + HeapTupleSetValue(pg_class, relispartition, BoolGetDatum(rd_rel->relispartition), values); + HeapTupleSetValue(pg_class, relrewrite, ObjectIdGetDatum(rd_rel->relrewrite), values); + HeapTupleSetValue(pg_class, relfrozenxid, TransactionIdGetDatum(rd_rel->relfrozenxid), values); + HeapTupleSetValue(pg_class, relminmxid, MultiXactIdGetDatum(rd_rel->relminmxid), values); if (relacl != (Datum) 0) - values[Anum_pg_class_relacl - 1] = relacl; + HeapTupleSetValue(pg_class, relacl, relacl, values); else - nulls[Anum_pg_class_relacl - 1] = true; + HeapTupleSetValueNull(pg_class, relacl, values, nulls); if (reloptions != (Datum) 0) - values[Anum_pg_class_reloptions - 1] = reloptions; + HeapTupleSetValue(pg_class, reloptions, reloptions, values); else - nulls[Anum_pg_class_reloptions - 1] = true; + HeapTupleSetValueNull(pg_class, reloptions, values, nulls); /* relpartbound is set by updating this tuple, if necessary */ - nulls[Anum_pg_class_relpartbound - 1] = true; + HeapTupleSetValueNull(pg_class, relpartbound, values, nulls); tup = heap_form_tuple(RelationGetDescr(pg_class_desc), values, nulls); /* finally insert the new tuple, update the indexes, and clean up */ - CatalogTupleInsert(pg_class_desc, tup); + CatalogTupleInsert(pg_class_desc, tup, NULL); heap_freetuple(tup); } @@ -1687,9 +1688,8 @@ RemoveAttributeById(Oid relid, AttrNumber attnum) HeapTuple tuple; Form_pg_attribute attStruct; char newattname[NAMEDATALEN]; - Datum valuesAtt[Natts_pg_attribute] = {0}; - bool nullsAtt[Natts_pg_attribute] = {0}; - bool replacesAtt[Natts_pg_attribute] = {0}; + bool nulls[Natts_pg_attribute] = {false}; + Bitmapset *updated = NULL; /* * Grab an exclusive lock on the target table, which we will NOT release @@ -1710,7 +1710,7 @@ RemoveAttributeById(Oid relid, AttrNumber attnum) attStruct = (Form_pg_attribute) GETSTRUCT(tuple); /* Mark the attribute as dropped */ - attStruct->attisdropped = true; + HeapTupleUpdateField(pg_attribute, attisdropped, true, attStruct, updated); /* * Set the type OID to invalid. A dropped attribute's type link cannot be @@ -1720,13 +1720,13 @@ RemoveAttributeById(Oid relid, AttrNumber attnum) * the attribute's attlen and attalign. We set atttypid to zero here as a * means of catching code that incorrectly expects it to be valid. */ - attStruct->atttypid = InvalidOid; + HeapTupleUpdateField(pg_attribute, atttypid, InvalidOid, attStruct, updated); /* Remove any not-null constraint the column may have */ - attStruct->attnotnull = false; + HeapTupleUpdateField(pg_attribute, attnotnull, false, attStruct, updated); /* Unset this so no one tries to look up the generation expression */ - attStruct->attgenerated = '\0'; + HeapTupleUpdateField(pg_attribute, attgenerated, '\0', attStruct, updated); /* * Change the column name to something that isn't likely to conflict @@ -1734,29 +1734,33 @@ RemoveAttributeById(Oid relid, AttrNumber attnum) snprintf(newattname, sizeof(newattname), "........pg.dropped.%d........", attnum); namestrcpy(&(attStruct->attname), newattname); + HeapTupleMarkColumnUpdated(pg_attribute, attname, updated); /* Clear the missing value */ - attStruct->atthasmissing = false; - nullsAtt[Anum_pg_attribute_attmissingval - 1] = true; - replacesAtt[Anum_pg_attribute_attmissingval - 1] = true; + HeapTupleUpdateField(pg_attribute, atthasmissing, false, attStruct, updated); + HeapTupleSetFieldNull(pg_attribute, attmissingval, nulls); + HeapTupleMarkColumnUpdated(pg_attribute, attmissingval, updated); /* * Clear the other nullable fields. This saves some space in pg_attribute * and removes no longer useful information. */ - nullsAtt[Anum_pg_attribute_attstattarget - 1] = true; - replacesAtt[Anum_pg_attribute_attstattarget - 1] = true; - nullsAtt[Anum_pg_attribute_attacl - 1] = true; - replacesAtt[Anum_pg_attribute_attacl - 1] = true; - nullsAtt[Anum_pg_attribute_attoptions - 1] = true; - replacesAtt[Anum_pg_attribute_attoptions - 1] = true; - nullsAtt[Anum_pg_attribute_attfdwoptions - 1] = true; - replacesAtt[Anum_pg_attribute_attfdwoptions - 1] = true; + HeapTupleSetFieldNull(pg_attribute, attstattarget, nulls); + HeapTupleMarkColumnUpdated(pg_attribute, attstattarget, updated); - tuple = heap_modify_tuple(tuple, RelationGetDescr(attr_rel), - valuesAtt, nullsAtt, replacesAtt); + HeapTupleSetFieldNull(pg_attribute, attacl, nulls); + HeapTupleMarkColumnUpdated(pg_attribute, attacl, updated); - CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple); + HeapTupleSetFieldNull(pg_attribute, attoptions, nulls); + HeapTupleMarkColumnUpdated(pg_attribute, attoptions, updated); + + HeapTupleSetFieldNull(pg_attribute, attfdwoptions, nulls); + HeapTupleMarkColumnUpdated(pg_attribute, attfdwoptions, updated); + + tuple = heap_update_tuple(tuple, RelationGetDescr(attr_rel), + NULL, nulls, updated); + + CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple, updated, NULL); /* * Because updating the pg_attribute row will trigger a relcache flush for @@ -1765,10 +1769,9 @@ RemoveAttributeById(Oid relid, AttrNumber attnum) */ table_close(attr_rel, RowExclusiveLock); - RemoveStatistics(relid, attnum); - relation_close(rel, NoLock); + bms_free(updated); } /* @@ -1967,23 +1970,15 @@ RelationClearMissing(Relation rel) Oid relid = RelationGetRelid(rel); int natts = RelationGetNumberOfAttributes(rel); int attnum; - Datum repl_val[Natts_pg_attribute]; - bool repl_null[Natts_pg_attribute]; - bool repl_repl[Natts_pg_attribute]; + Datum values[Natts_pg_attribute] = {0}; + bool nulls[Natts_pg_attribute] = {false}; + Bitmapset *updated = NULL; Form_pg_attribute attrtuple; HeapTuple tuple, newtuple; - memset(repl_val, 0, sizeof(repl_val)); - memset(repl_null, false, sizeof(repl_null)); - memset(repl_repl, false, sizeof(repl_repl)); - - repl_val[Anum_pg_attribute_atthasmissing - 1] = BoolGetDatum(false); - repl_null[Anum_pg_attribute_attmissingval - 1] = true; - - repl_repl[Anum_pg_attribute_atthasmissing - 1] = true; - repl_repl[Anum_pg_attribute_attmissingval - 1] = true; - + HeapTupleUpdateValue(pg_attribute, atthasmissing, BoolGetDatum(false), values, nulls, updated); + HeapTupleUpdateValueNull(pg_attribute, attmissingval, values, nulls, updated); /* Get a lock on pg_attribute */ attr_rel = table_open(AttributeRelationId, RowExclusiveLock); @@ -2003,10 +1998,10 @@ RelationClearMissing(Relation rel) /* ignore any where atthasmissing is not true */ if (attrtuple->atthasmissing) { - newtuple = heap_modify_tuple(tuple, RelationGetDescr(attr_rel), - repl_val, repl_null, repl_repl); + newtuple = heap_update_tuple(tuple, RelationGetDescr(attr_rel), + values, nulls, updated); - CatalogTupleUpdate(attr_rel, &newtuple->t_self, newtuple); + CatalogTupleUpdate(attr_rel, &newtuple->t_self, newtuple, updated, NULL); heap_freetuple(newtuple); } @@ -2019,6 +2014,7 @@ RelationClearMissing(Relation rel) * there's nothing else to do here. */ table_close(attr_rel, RowExclusiveLock); + bms_free(updated); } /* @@ -2029,9 +2025,9 @@ RelationClearMissing(Relation rel) void StoreAttrMissingVal(Relation rel, AttrNumber attnum, Datum missingval) { - Datum valuesAtt[Natts_pg_attribute] = {0}; - bool nullsAtt[Natts_pg_attribute] = {0}; - bool replacesAtt[Natts_pg_attribute] = {0}; + Datum values[Natts_pg_attribute] = {0}; + bool nulls[Natts_pg_attribute] = {false}; + Bitmapset *updated = NULL; Relation attrrel; Form_pg_attribute attStruct; HeapTuple atttup, @@ -2060,17 +2056,15 @@ StoreAttrMissingVal(Relation rel, AttrNumber attnum, Datum missingval) attStruct->attalign)); /* Update the pg_attribute row */ - valuesAtt[Anum_pg_attribute_atthasmissing - 1] = BoolGetDatum(true); - replacesAtt[Anum_pg_attribute_atthasmissing - 1] = true; - - valuesAtt[Anum_pg_attribute_attmissingval - 1] = missingval; - replacesAtt[Anum_pg_attribute_attmissingval - 1] = true; + HeapTupleUpdateValue(pg_attribute, atthasmissing, BoolGetDatum(true), values, nulls, updated); + HeapTupleUpdateValue(pg_attribute, attmissingval, missingval, values, nulls, updated); - newtup = heap_modify_tuple(atttup, RelationGetDescr(attrrel), - valuesAtt, nullsAtt, replacesAtt); - CatalogTupleUpdate(attrrel, &newtup->t_self, newtup); + newtup = heap_update_tuple(atttup, RelationGetDescr(attrrel), + values, nulls, updated); + CatalogTupleUpdate(attrrel, &newtup->t_self, newtup, updated, NULL); /* clean up */ + bms_free(updated); ReleaseSysCache(atttup); table_close(attrrel, RowExclusiveLock); } @@ -2085,9 +2079,9 @@ StoreAttrMissingVal(Relation rel, AttrNumber attnum, Datum missingval) void SetAttrMissing(Oid relid, char *attname, char *value) { - Datum valuesAtt[Natts_pg_attribute] = {0}; - bool nullsAtt[Natts_pg_attribute] = {0}; - bool replacesAtt[Natts_pg_attribute] = {0}; + Datum values[Natts_pg_attribute] = {0}; + bool nulls[Natts_pg_attribute] = {false}; + Bitmapset *updated = NULL; Datum missingval; Form_pg_attribute attStruct; Relation attrrel, @@ -2120,16 +2114,15 @@ SetAttrMissing(Oid relid, char *attname, char *value) Int32GetDatum(attStruct->atttypmod)); /* update the tuple - set atthasmissing and attmissingval */ - valuesAtt[Anum_pg_attribute_atthasmissing - 1] = BoolGetDatum(true); - replacesAtt[Anum_pg_attribute_atthasmissing - 1] = true; - valuesAtt[Anum_pg_attribute_attmissingval - 1] = missingval; - replacesAtt[Anum_pg_attribute_attmissingval - 1] = true; + HeapTupleUpdateValue(pg_attribute, atthasmissing, BoolGetDatum(true), values, nulls, updated); + HeapTupleUpdateValue(pg_attribute, attmissingval, missingval, values, nulls, updated); - newtup = heap_modify_tuple(atttup, RelationGetDescr(attrrel), - valuesAtt, nullsAtt, replacesAtt); - CatalogTupleUpdate(attrrel, &newtup->t_self, newtup); + newtup = heap_update_tuple(atttup, RelationGetDescr(attrrel), + values, nulls, updated); + CatalogTupleUpdate(attrrel, &newtup->t_self, newtup, updated, NULL); /* clean up */ + bms_free(updated); ReleaseSysCache(atttup); table_close(attrrel, RowExclusiveLock); table_close(tablerel, AccessExclusiveLock); @@ -2719,6 +2712,7 @@ MergeWithExistingConstraint(Relation rel, const char *ccname, Node *expr, SysScanDesc conscan; ScanKeyData skey[3]; HeapTuple tup; + Bitmapset *updated = NULL; /* Search for a pg_constraint entry with same name and relation */ conDesc = table_open(ConstraintRelationId, RowExclusiveLock); @@ -2834,24 +2828,25 @@ MergeWithExistingConstraint(Relation rel, const char *ccname, Node *expr, */ if (rel->rd_rel->relispartition) { - con->coninhcount = 1; - con->conislocal = false; + HeapTupleUpdateField(pg_constraint, coninhcount, 1, con, updated); + HeapTupleUpdateField(pg_constraint, conislocal, false, con, updated); } else { if (is_local) - con->conislocal = true; + HeapTupleUpdateField(pg_constraint, conislocal, true, con, updated); else if (pg_add_s16_overflow(con->coninhcount, 1, &con->coninhcount)) ereport(ERROR, errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("too many inheritance parents")); + HeapTupleUpdateField(pg_constraint, coninhcount, con->coninhcount, con, updated); } if (is_no_inherit) { Assert(is_local); - con->connoinherit = true; + HeapTupleUpdateField(pg_constraint, connoinherit, true, con, updated); } /* @@ -2863,11 +2858,12 @@ MergeWithExistingConstraint(Relation rel, const char *ccname, Node *expr, if (is_enforced && !con->conenforced) { Assert(is_local); - con->conenforced = true; - con->convalidated = true; + HeapTupleUpdateField(pg_constraint, conenforced, true, con, updated); + HeapTupleUpdateField(pg_constraint, convalidated, true, con, updated); } - CatalogTupleUpdate(conDesc, &tup->t_self, tup); + CatalogTupleUpdate(conDesc, &tup->t_self, tup, updated, NULL); + bms_free(updated); } systable_endscan(conscan); @@ -3148,6 +3144,7 @@ SetRelationNumChecks(Relation rel, int numchecks) Relation relrel; HeapTuple reltup; Form_pg_class relStruct; + Bitmapset *updated = NULL; relrel = table_open(RelationRelationId, RowExclusiveLock); reltup = SearchSysCacheCopy1(RELOID, @@ -3159,9 +3156,10 @@ SetRelationNumChecks(Relation rel, int numchecks) if (relStruct->relchecks != numchecks) { - relStruct->relchecks = numchecks; + HeapTupleUpdateField(pg_class, relchecks, numchecks, relStruct, updated); - CatalogTupleUpdate(relrel, &reltup->t_self, reltup); + CatalogTupleUpdate(relrel, &reltup->t_self, reltup, updated, NULL); + bms_free(updated); } else { @@ -3470,7 +3468,7 @@ CopyStatistics(Oid fromrelid, Oid torelid) if (indstate == NULL) indstate = CatalogOpenIndexes(statrel); - CatalogTupleInsertWithInfo(statrel, tup, indstate); + CatalogTupleInsert(statrel, tup, indstate); heap_freetuple(tup); } @@ -3906,8 +3904,8 @@ StorePartitionKey(Relation rel, Datum partexprDatum; Relation pg_partitioned_table; HeapTuple tuple; - Datum values[Natts_pg_partitioned_table]; - bool nulls[Natts_pg_partitioned_table] = {0}; + Datum values[Natts_pg_partitioned_table] = {0}; + bool nulls[Natts_pg_partitioned_table] = {false}; ObjectAddress myself; ObjectAddress referenced; ObjectAddresses *addrs; @@ -3935,20 +3933,20 @@ StorePartitionKey(Relation rel, /* Only this can ever be NULL */ if (!partexprDatum) - nulls[Anum_pg_partitioned_table_partexprs - 1] = true; + HeapTupleSetValueNull(pg_partitioned_table, partexprs, values, nulls); - values[Anum_pg_partitioned_table_partrelid - 1] = ObjectIdGetDatum(RelationGetRelid(rel)); - values[Anum_pg_partitioned_table_partstrat - 1] = CharGetDatum(strategy); - values[Anum_pg_partitioned_table_partnatts - 1] = Int16GetDatum(partnatts); - values[Anum_pg_partitioned_table_partdefid - 1] = ObjectIdGetDatum(InvalidOid); - values[Anum_pg_partitioned_table_partattrs - 1] = PointerGetDatum(partattrs_vec); - values[Anum_pg_partitioned_table_partclass - 1] = PointerGetDatum(partopclass_vec); - values[Anum_pg_partitioned_table_partcollation - 1] = PointerGetDatum(partcollation_vec); - values[Anum_pg_partitioned_table_partexprs - 1] = partexprDatum; + HeapTupleSetValue(pg_partitioned_table, partrelid, ObjectIdGetDatum(RelationGetRelid(rel)), values); + HeapTupleSetValue(pg_partitioned_table, partstrat, CharGetDatum(strategy), values); + HeapTupleSetValue(pg_partitioned_table, partnatts, Int16GetDatum(partnatts), values); + HeapTupleSetValue(pg_partitioned_table, partdefid, ObjectIdGetDatum(InvalidOid), values); + HeapTupleSetValue(pg_partitioned_table, partattrs, PointerGetDatum(partattrs_vec), values); + HeapTupleSetValue(pg_partitioned_table, partclass, PointerGetDatum(partopclass_vec), values); + HeapTupleSetValue(pg_partitioned_table, partcollation, PointerGetDatum(partcollation_vec), values); + HeapTupleSetValue(pg_partitioned_table, partexprs, partexprDatum, values); tuple = heap_form_tuple(RelationGetDescr(pg_partitioned_table), values, nulls); - CatalogTupleInsert(pg_partitioned_table, tuple); + CatalogTupleInsert(pg_partitioned_table, tuple, NULL); table_close(pg_partitioned_table, RowExclusiveLock); /* Mark this relation as dependent on a few things as follows */ @@ -4052,9 +4050,9 @@ StorePartitionBound(Relation rel, Relation parent, PartitionBoundSpec *bound) Relation classRel; HeapTuple tuple, newtuple; - Datum new_val[Natts_pg_class]; - bool new_null[Natts_pg_class], - new_repl[Natts_pg_class]; + Datum values[Natts_pg_class] = {0}; + bool nulls[Natts_pg_class] = {false}; + Bitmapset *updated = NULL; Oid defaultPartOid; /* Update pg_class tuple */ @@ -4065,12 +4063,14 @@ StorePartitionBound(Relation rel, Relation parent, PartitionBoundSpec *bound) elog(ERROR, "cache lookup failed for relation %u", RelationGetRelid(rel)); + #ifdef USE_ASSERT_CHECKING { Form_pg_class classForm; bool isnull; classForm = (Form_pg_class) GETSTRUCT(tuple); + Assert(!classForm->relispartition); (void) SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relpartbound, &isnull); @@ -4079,26 +4079,23 @@ StorePartitionBound(Relation rel, Relation parent, PartitionBoundSpec *bound) #endif /* Fill in relpartbound value */ - memset(new_val, 0, sizeof(new_val)); - memset(new_null, false, sizeof(new_null)); - memset(new_repl, false, sizeof(new_repl)); - new_val[Anum_pg_class_relpartbound - 1] = CStringGetTextDatum(nodeToString(bound)); - new_null[Anum_pg_class_relpartbound - 1] = false; - new_repl[Anum_pg_class_relpartbound - 1] = true; - newtuple = heap_modify_tuple(tuple, RelationGetDescr(classRel), - new_val, new_null, new_repl); + HeapTupleUpdateValue(pg_class, relpartbound, CStringGetTextDatum(nodeToString(bound)), values, nulls, updated); + newtuple = heap_update_tuple(tuple, RelationGetDescr(classRel), + values, nulls, updated); + /* Also set the flag */ - ((Form_pg_class) GETSTRUCT(newtuple))->relispartition = true; + HeapTupleUpdateField(pg_class, relispartition, true, (Form_pg_class) GETSTRUCT(newtuple), updated); /* * We already checked for no inheritance children, but reset * relhassubclass in case it was left over. */ if (rel->rd_rel->relkind == RELKIND_RELATION && rel->rd_rel->relhassubclass) - ((Form_pg_class) GETSTRUCT(newtuple))->relhassubclass = false; + HeapTupleUpdateField(pg_class, relhassubclass, false, (Form_pg_class) GETSTRUCT(newtuple), updated); - CatalogTupleUpdate(classRel, &newtuple->t_self, newtuple); + CatalogTupleUpdate(classRel, &newtuple->t_self, newtuple, updated, NULL); heap_freetuple(newtuple); + bms_free(updated); table_close(classRel, RowExclusiveLock); /* diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index 5d9db167e5950..31e78342d63f8 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -579,8 +579,8 @@ UpdateIndexRelation(Oid indexoid, int2vector *indoption; Datum exprsDatum; Datum predDatum; - Datum values[Natts_pg_index]; - bool nulls[Natts_pg_index] = {0}; + Datum values[Natts_pg_index] = {0}; + bool nulls[Natts_pg_index] = {false}; Relation pg_index; HeapTuple tuple; int i; @@ -634,38 +634,38 @@ UpdateIndexRelation(Oid indexoid, /* * Build a pg_index tuple */ - values[Anum_pg_index_indexrelid - 1] = ObjectIdGetDatum(indexoid); - values[Anum_pg_index_indrelid - 1] = ObjectIdGetDatum(heapoid); - values[Anum_pg_index_indnatts - 1] = Int16GetDatum(indexInfo->ii_NumIndexAttrs); - values[Anum_pg_index_indnkeyatts - 1] = Int16GetDatum(indexInfo->ii_NumIndexKeyAttrs); - values[Anum_pg_index_indisunique - 1] = BoolGetDatum(indexInfo->ii_Unique); - values[Anum_pg_index_indnullsnotdistinct - 1] = BoolGetDatum(indexInfo->ii_NullsNotDistinct); - values[Anum_pg_index_indisprimary - 1] = BoolGetDatum(primary); - values[Anum_pg_index_indisexclusion - 1] = BoolGetDatum(isexclusion); - values[Anum_pg_index_indimmediate - 1] = BoolGetDatum(immediate); - values[Anum_pg_index_indisclustered - 1] = BoolGetDatum(false); - values[Anum_pg_index_indisvalid - 1] = BoolGetDatum(isvalid); - values[Anum_pg_index_indcheckxmin - 1] = BoolGetDatum(false); - values[Anum_pg_index_indisready - 1] = BoolGetDatum(isready); - values[Anum_pg_index_indislive - 1] = BoolGetDatum(true); - values[Anum_pg_index_indisreplident - 1] = BoolGetDatum(false); - values[Anum_pg_index_indkey - 1] = PointerGetDatum(indkey); - values[Anum_pg_index_indcollation - 1] = PointerGetDatum(indcollation); - values[Anum_pg_index_indclass - 1] = PointerGetDatum(indclass); - values[Anum_pg_index_indoption - 1] = PointerGetDatum(indoption); - values[Anum_pg_index_indexprs - 1] = exprsDatum; + HeapTupleSetValue(pg_index, indexrelid, ObjectIdGetDatum(indexoid), values); + HeapTupleSetValue(pg_index, indrelid, ObjectIdGetDatum(heapoid), values); + HeapTupleSetValue(pg_index, indnatts, Int16GetDatum(indexInfo->ii_NumIndexAttrs), values); + HeapTupleSetValue(pg_index, indnkeyatts, Int16GetDatum(indexInfo->ii_NumIndexKeyAttrs), values); + HeapTupleSetValue(pg_index, indisunique, BoolGetDatum(indexInfo->ii_Unique), values); + HeapTupleSetValue(pg_index, indnullsnotdistinct, BoolGetDatum(indexInfo->ii_NullsNotDistinct), values); + HeapTupleSetValue(pg_index, indisprimary, BoolGetDatum(primary), values); + HeapTupleSetValue(pg_index, indisexclusion, BoolGetDatum(isexclusion), values); + HeapTupleSetValue(pg_index, indimmediate, BoolGetDatum(immediate), values); + HeapTupleSetValue(pg_index, indisclustered, BoolGetDatum(false), values); + HeapTupleSetValue(pg_index, indisvalid, BoolGetDatum(isvalid), values); + HeapTupleSetValue(pg_index, indcheckxmin, BoolGetDatum(false), values); + HeapTupleSetValue(pg_index, indisready, BoolGetDatum(isready), values); + HeapTupleSetValue(pg_index, indislive, BoolGetDatum(true), values); + HeapTupleSetValue(pg_index, indisreplident, BoolGetDatum(false), values); + HeapTupleSetValue(pg_index, indkey, PointerGetDatum(indkey), values); + HeapTupleSetValue(pg_index, indcollation, PointerGetDatum(indcollation), values); + HeapTupleSetValue(pg_index, indclass, PointerGetDatum(indclass), values); + HeapTupleSetValue(pg_index, indoption, PointerGetDatum(indoption), values); + HeapTupleSetValue(pg_index, indexprs, exprsDatum, values); if (exprsDatum == (Datum) 0) - nulls[Anum_pg_index_indexprs - 1] = true; - values[Anum_pg_index_indpred - 1] = predDatum; + HeapTupleSetValueNull(pg_index, indexprs, values, nulls); + HeapTupleSetValue(pg_index, indpred, predDatum, values); if (predDatum == (Datum) 0) - nulls[Anum_pg_index_indpred - 1] = true; + HeapTupleSetValueNull(pg_index, indpred, values, nulls); tuple = heap_form_tuple(RelationGetDescr(pg_index), values, nulls); /* * insert the tuple into the pg_index catalog */ - CatalogTupleInsert(pg_index, tuple); + CatalogTupleInsert(pg_index, tuple, NULL); /* * close the relation and free the tuple @@ -1569,6 +1569,8 @@ index_concurrently_swap(Oid newIndexId, Oid oldIndexId, const char *oldName) Oid indexConstraintOid; List *constraintOids = NIL; ListCell *lc; + Bitmapset *oldUpdated = NULL; + Bitmapset *newUpdated = NULL; /* * Take a necessary lock on the old and new index before swapping them. @@ -1594,14 +1596,21 @@ index_concurrently_swap(Oid newIndexId, Oid oldIndexId, const char *oldName) /* Swap the names */ namestrcpy(&newClassForm->relname, NameStr(oldClassForm->relname)); namestrcpy(&oldClassForm->relname, oldName); + HeapTupleUpdateField(pg_class, relname, newClassForm->relname, newClassForm, newUpdated); + HeapTupleUpdateField(pg_class, relname, oldClassForm->relname, oldClassForm, oldUpdated); /* Swap the partition flags to track inheritance properly */ isPartition = newClassForm->relispartition; - newClassForm->relispartition = oldClassForm->relispartition; - oldClassForm->relispartition = isPartition; + HeapTupleUpdateField(pg_class, relispartition, oldClassForm->relispartition, newClassForm, newUpdated); + HeapTupleUpdateField(pg_class, relispartition, isPartition, oldClassForm, oldUpdated); - CatalogTupleUpdate(pg_class, &oldClassTuple->t_self, oldClassTuple); - CatalogTupleUpdate(pg_class, &newClassTuple->t_self, newClassTuple); + CatalogTupleUpdate(pg_class, &oldClassTuple->t_self, oldClassTuple, oldUpdated, NULL); + CatalogTupleUpdate(pg_class, &newClassTuple->t_self, newClassTuple, newUpdated, NULL); + + bms_free(oldUpdated); + oldUpdated = NULL; + bms_free(newUpdated); + newUpdated = NULL; heap_freetuple(oldClassTuple); heap_freetuple(newClassTuple); @@ -1625,34 +1634,39 @@ index_concurrently_swap(Oid newIndexId, Oid oldIndexId, const char *oldName) * Copy constraint flags from the old index. This is safe because the old * index guaranteed uniqueness. */ - newIndexForm->indisprimary = oldIndexForm->indisprimary; - oldIndexForm->indisprimary = false; - newIndexForm->indisexclusion = oldIndexForm->indisexclusion; - oldIndexForm->indisexclusion = false; - newIndexForm->indimmediate = oldIndexForm->indimmediate; - oldIndexForm->indimmediate = true; + HeapTupleUpdateField(pg_index, indisprimary, oldIndexForm->indisprimary, newIndexForm, newUpdated); + HeapTupleUpdateField(pg_index, indisprimary, false, oldIndexForm, oldUpdated); + HeapTupleUpdateField(pg_index, indisexclusion, oldIndexForm->indisexclusion, newIndexForm, newUpdated); + HeapTupleUpdateField(pg_index, indisexclusion, false, oldIndexForm, oldUpdated); + HeapTupleUpdateField(pg_index, indimmediate, oldIndexForm->indimmediate, newIndexForm, newUpdated); + HeapTupleUpdateField(pg_index, indimmediate, true, oldIndexForm, oldUpdated); /* Preserve indisreplident in the new index */ - newIndexForm->indisreplident = oldIndexForm->indisreplident; + HeapTupleUpdateField(pg_index, indisreplident, oldIndexForm->indisreplident, newIndexForm, newUpdated); /* Preserve indisclustered in the new index */ - newIndexForm->indisclustered = oldIndexForm->indisclustered; + HeapTupleUpdateField(pg_index, indisclustered, oldIndexForm->indisclustered, newIndexForm, newUpdated); /* * Mark the new index as valid, and the old index as invalid similarly to * what index_set_state_flags() does. */ - newIndexForm->indisvalid = true; - oldIndexForm->indisvalid = false; - oldIndexForm->indisclustered = false; - oldIndexForm->indisreplident = false; + HeapTupleUpdateField(pg_index, indisvalid, true, newIndexForm, newUpdated); + HeapTupleUpdateField(pg_index, indisvalid, false, oldIndexForm, oldUpdated); + HeapTupleUpdateField(pg_index, indisclustered, false, oldIndexForm, oldUpdated); + HeapTupleUpdateField(pg_index, indisreplident, false, oldIndexForm, oldUpdated); - CatalogTupleUpdate(pg_index, &oldIndexTuple->t_self, oldIndexTuple); - CatalogTupleUpdate(pg_index, &newIndexTuple->t_self, newIndexTuple); + CatalogTupleUpdate(pg_index, &oldIndexTuple->t_self, oldIndexTuple, oldUpdated, NULL); + CatalogTupleUpdate(pg_index, &newIndexTuple->t_self, newIndexTuple, newUpdated, NULL); heap_freetuple(oldIndexTuple); heap_freetuple(newIndexTuple); + bms_free(oldUpdated); + oldUpdated = NULL; + bms_free(newUpdated); + newUpdated = NULL; + /* * Move constraints and triggers over to the new index */ @@ -1686,9 +1700,11 @@ index_concurrently_swap(Oid newIndexId, Oid oldIndexId, const char *oldName) if (conForm->conindid == oldIndexId) { - conForm->conindid = newIndexId; + Bitmapset *updated = NULL; - CatalogTupleUpdate(pg_constraint, &constraintTuple->t_self, constraintTuple); + HeapTupleUpdateField(pg_constraint, conindid, newIndexId, conForm, updated); + CatalogTupleUpdate(pg_constraint, &constraintTuple->t_self, constraintTuple, updated, NULL); + bms_free(updated); } heap_freetuple(constraintTuple); @@ -1704,6 +1720,8 @@ index_concurrently_swap(Oid newIndexId, Oid oldIndexId, const char *oldName) while (HeapTupleIsValid((triggerTuple = systable_getnext(scan)))) { + Bitmapset *updated = NULL; + Form_pg_trigger tgForm = (Form_pg_trigger) GETSTRUCT(triggerTuple); if (tgForm->tgconstrindid != oldIndexId) @@ -1713,10 +1731,9 @@ index_concurrently_swap(Oid newIndexId, Oid oldIndexId, const char *oldName) triggerTuple = heap_copytuple(triggerTuple); tgForm = (Form_pg_trigger) GETSTRUCT(triggerTuple); - tgForm->tgconstrindid = newIndexId; - - CatalogTupleUpdate(pg_trigger, &triggerTuple->t_self, triggerTuple); - + HeapTupleUpdateField(pg_trigger, tgconstrindid, newIndexId, tgForm, updated); + CatalogTupleUpdate(pg_trigger, &triggerTuple->t_self, triggerTuple, updated, NULL); + bms_free(updated); heap_freetuple(triggerTuple); } @@ -1732,11 +1749,10 @@ index_concurrently_swap(Oid newIndexId, Oid oldIndexId, const char *oldName) SysScanDesc sd; HeapTuple tuple; Datum values[Natts_pg_description] = {0}; - bool nulls[Natts_pg_description] = {0}; - bool replaces[Natts_pg_description] = {0}; + bool nulls[Natts_pg_description] = {false}; + Bitmapset *updated = NULL; - values[Anum_pg_description_objoid - 1] = ObjectIdGetDatum(newIndexId); - replaces[Anum_pg_description_objoid - 1] = true; + HeapTupleUpdateValue(pg_description, objoid, ObjectIdGetDatum(newIndexId), values, nulls, updated); ScanKeyInit(&skey[0], Anum_pg_description_objoid, @@ -1758,15 +1774,16 @@ index_concurrently_swap(Oid newIndexId, Oid oldIndexId, const char *oldName) while ((tuple = systable_getnext(sd)) != NULL) { - tuple = heap_modify_tuple(tuple, RelationGetDescr(description), - values, nulls, replaces); - CatalogTupleUpdate(description, &tuple->t_self, tuple); + tuple = heap_update_tuple(tuple, RelationGetDescr(description), + values, nulls, updated); + CatalogTupleUpdate(description, &tuple->t_self, tuple, updated, NULL); break; /* Assume there can be only one match */ } systable_endscan(sd); table_close(description, NoLock); + bms_free(updated); } /* @@ -2061,6 +2078,7 @@ index_constraint_create(Relation heapRelation, Form_pg_index indexForm; bool dirty = false; bool marked_as_primary = false; + Bitmapset *updated = NULL; pg_index = table_open(IndexRelationId, RowExclusiveLock); @@ -2072,20 +2090,20 @@ index_constraint_create(Relation heapRelation, if (mark_as_primary && !indexForm->indisprimary) { - indexForm->indisprimary = true; + HeapTupleUpdateField(pg_index, indisprimary, true, indexForm, updated); dirty = true; marked_as_primary = true; } if (deferrable && indexForm->indimmediate) { - indexForm->indimmediate = false; + HeapTupleUpdateField(pg_index, indimmediate, false, indexForm, updated); dirty = true; } if (dirty) { - CatalogTupleUpdate(pg_index, &indexTuple->t_self, indexTuple); + CatalogTupleUpdate(pg_index, &indexTuple->t_self, indexTuple, updated, NULL); /* * When we mark an existing index as primary, force a relcache @@ -2102,6 +2120,7 @@ index_constraint_create(Relation heapRelation, heap_freetuple(indexTuple); table_close(pg_index, RowExclusiveLock); + bms_free(updated); } return myself; @@ -3130,6 +3149,7 @@ index_build(Relation heapRelation, Relation pg_index; HeapTuple indexTuple; Form_pg_index indexForm; + Bitmapset *updated = NULL; pg_index = table_open(IndexRelationId, RowExclusiveLock); @@ -3142,11 +3162,12 @@ index_build(Relation heapRelation, /* If it's a new index, indcheckxmin shouldn't be set ... */ Assert(!indexForm->indcheckxmin); - indexForm->indcheckxmin = true; - CatalogTupleUpdate(pg_index, &indexTuple->t_self, indexTuple); + HeapTupleUpdateField(pg_index, indcheckxmin, true, indexForm, updated); + CatalogTupleUpdate(pg_index, &indexTuple->t_self, indexTuple, updated, NULL); heap_freetuple(indexTuple); table_close(pg_index, RowExclusiveLock); + bms_free(updated); } /* @@ -3505,6 +3526,7 @@ index_set_state_flags(Oid indexId, IndexStateFlagsAction action) Relation pg_index; HeapTuple indexTuple; Form_pg_index indexForm; + Bitmapset *updated = NULL; /* Open pg_index and fetch a writable copy of the index's tuple */ pg_index = table_open(IndexRelationId, RowExclusiveLock); @@ -3523,14 +3545,14 @@ index_set_state_flags(Oid indexId, IndexStateFlagsAction action) Assert(indexForm->indislive); Assert(!indexForm->indisready); Assert(!indexForm->indisvalid); - indexForm->indisready = true; + HeapTupleUpdateField(pg_index, indisready, true, indexForm, updated); break; case INDEX_CREATE_SET_VALID: /* Set indisvalid during a CREATE INDEX CONCURRENTLY sequence */ Assert(indexForm->indislive); Assert(indexForm->indisready); Assert(!indexForm->indisvalid); - indexForm->indisvalid = true; + HeapTupleUpdateField(pg_index, indisvalid, true, indexForm, updated); break; case INDEX_DROP_CLEAR_VALID: @@ -3547,9 +3569,9 @@ index_set_state_flags(Oid indexId, IndexStateFlagsAction action) * set on any invalid index, so clear that flag too. For * cleanliness, also clear indisreplident. */ - indexForm->indisvalid = false; - indexForm->indisclustered = false; - indexForm->indisreplident = false; + HeapTupleUpdateField(pg_index, indisvalid, false, indexForm, updated); + HeapTupleUpdateField(pg_index, indisclustered, false, indexForm, updated); + HeapTupleUpdateField(pg_index, indisreplident, false, indexForm, updated); break; case INDEX_DROP_SET_DEAD: @@ -3563,15 +3585,16 @@ index_set_state_flags(Oid indexId, IndexStateFlagsAction action) Assert(!indexForm->indisvalid); Assert(!indexForm->indisclustered); Assert(!indexForm->indisreplident); - indexForm->indisready = false; - indexForm->indislive = false; + HeapTupleUpdateField(pg_index, indisready, false, indexForm, updated); + HeapTupleUpdateField(pg_index, indislive, false, indexForm, updated); break; } /* ... and update it */ - CatalogTupleUpdate(pg_index, &indexTuple->t_self, indexTuple); + CatalogTupleUpdate(pg_index, &indexTuple->t_self, indexTuple, updated, NULL); table_close(pg_index, RowExclusiveLock); + bms_free(updated); } @@ -3850,6 +3873,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId, HeapTuple indexTuple; Form_pg_index indexForm; bool index_bad; + Bitmapset *updated = NULL; pg_index = table_open(IndexRelationId, RowExclusiveLock); @@ -3866,13 +3890,13 @@ reindex_index(const ReindexStmt *stmt, Oid indexId, (indexForm->indcheckxmin && !indexInfo->ii_BrokenHotChain)) { if (!indexInfo->ii_BrokenHotChain) - indexForm->indcheckxmin = false; + HeapTupleUpdateField(pg_index, indcheckxmin, false, indexForm, updated); else if (index_bad) - indexForm->indcheckxmin = true; - indexForm->indisvalid = true; - indexForm->indisready = true; - indexForm->indislive = true; - CatalogTupleUpdate(pg_index, &indexTuple->t_self, indexTuple); + HeapTupleUpdateField(pg_index, indcheckxmin, true, indexForm, updated); + HeapTupleUpdateField(pg_index, indisvalid, true, indexForm, updated); + HeapTupleUpdateField(pg_index, indisready, true, indexForm, updated); + HeapTupleUpdateField(pg_index, indislive, true, indexForm, updated); + CatalogTupleUpdate(pg_index, &indexTuple->t_self, indexTuple, updated, NULL); /* * Invalidate the relcache for the table, so that after we commit @@ -3885,6 +3909,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId, } table_close(pg_index, RowExclusiveLock); + bms_free(updated); } /* Log what we did */ diff --git a/src/backend/catalog/partition.c b/src/backend/catalog/partition.c index 93d72157a46ae..bc252da565caf 100644 --- a/src/backend/catalog/partition.c +++ b/src/backend/catalog/partition.c @@ -342,6 +342,7 @@ update_default_partition_oid(Oid parentId, Oid defaultPartId) HeapTuple tuple; Relation pg_partitioned_table; Form_pg_partitioned_table part_table_form; + Bitmapset *updated = NULL; pg_partitioned_table = table_open(PartitionedRelationId, RowExclusiveLock); @@ -353,10 +354,12 @@ update_default_partition_oid(Oid parentId, Oid defaultPartId) part_table_form = (Form_pg_partitioned_table) GETSTRUCT(tuple); part_table_form->partdefid = defaultPartId; - CatalogTupleUpdate(pg_partitioned_table, &tuple->t_self, tuple); + HeapTupleMarkColumnUpdated(pg_partitioned_table, partdefid, updated); + CatalogTupleUpdate(pg_partitioned_table, &tuple->t_self, tuple, updated, NULL); heap_freetuple(tuple); table_close(pg_partitioned_table, RowExclusiveLock); + bms_free(updated); } /* diff --git a/src/backend/catalog/pg_attrdef.c b/src/backend/catalog/pg_attrdef.c index 29f5691bee9e0..04edc23024e8d 100644 --- a/src/backend/catalog/pg_attrdef.c +++ b/src/backend/catalog/pg_attrdef.c @@ -39,14 +39,12 @@ StoreAttrDefault(Relation rel, AttrNumber attnum, char *adbin; Relation adrel; HeapTuple tuple; - Datum values[Natts_pg_attrdef]; - static bool nulls[Natts_pg_attrdef] = {false, false, false, false}; + Datum values[Natts_pg_attrdef] = {0}; + bool nulls[Natts_pg_attrdef] = {false}; Relation attrrel; HeapTuple atttup; Form_pg_attribute attStruct; - Datum valuesAtt[Natts_pg_attribute] = {0}; - bool nullsAtt[Natts_pg_attribute] = {0}; - bool replacesAtt[Natts_pg_attribute] = {0}; + Bitmapset *updated = NULL; char attgenerated; Oid attrdefOid; ObjectAddress colobject, @@ -64,13 +62,13 @@ StoreAttrDefault(Relation rel, AttrNumber attnum, */ attrdefOid = GetNewOidWithIndex(adrel, AttrDefaultOidIndexId, Anum_pg_attrdef_oid); - values[Anum_pg_attrdef_oid - 1] = ObjectIdGetDatum(attrdefOid); - values[Anum_pg_attrdef_adrelid - 1] = ObjectIdGetDatum(RelationGetRelid(rel)); - values[Anum_pg_attrdef_adnum - 1] = Int16GetDatum(attnum); - values[Anum_pg_attrdef_adbin - 1] = CStringGetTextDatum(adbin); + HeapTupleSetValue(pg_attrdef, oid, ObjectIdGetDatum(attrdefOid), values); + HeapTupleSetValue(pg_attrdef, adrelid, ObjectIdGetDatum(RelationGetRelid(rel)), values); + HeapTupleSetValue(pg_attrdef, adnum, Int16GetDatum(attnum), values); + HeapTupleSetValue(pg_attrdef, adbin, CStringGetTextDatum(adbin), values); tuple = heap_form_tuple(adrel->rd_att, values, nulls); - CatalogTupleInsert(adrel, tuple); + CatalogTupleInsert(adrel, tuple, NULL); defobject.classId = AttrDefaultRelationId; defobject.objectId = attrdefOid; @@ -79,7 +77,7 @@ StoreAttrDefault(Relation rel, AttrNumber attnum, table_close(adrel, RowExclusiveLock); /* now can free some of the stuff allocated above */ - pfree(DatumGetPointer(values[Anum_pg_attrdef_adbin - 1])); + pfree(DatumGetPointer(HeapTupleValue(pg_attrdef, adbin, values))); heap_freetuple(tuple); pfree(adbin); @@ -91,22 +89,21 @@ StoreAttrDefault(Relation rel, AttrNumber attnum, atttup = SearchSysCacheCopy2(ATTNUM, ObjectIdGetDatum(RelationGetRelid(rel)), Int16GetDatum(attnum)); + if (!HeapTupleIsValid(atttup)) elog(ERROR, "cache lookup failed for attribute %d of relation %u", attnum, RelationGetRelid(rel)); + attStruct = (Form_pg_attribute) GETSTRUCT(atttup); attgenerated = attStruct->attgenerated; - valuesAtt[Anum_pg_attribute_atthasdef - 1] = BoolGetDatum(true); - replacesAtt[Anum_pg_attribute_atthasdef - 1] = true; - - atttup = heap_modify_tuple(atttup, RelationGetDescr(attrrel), - valuesAtt, nullsAtt, replacesAtt); - - CatalogTupleUpdate(attrrel, &atttup->t_self, atttup); + Assert(bms_is_empty(updated)); + HeapTupleUpdateField(pg_attribute, atthasdef, BoolGetDatum(true), attStruct, updated); + CatalogTupleUpdate(attrrel, &atttup->t_self, atttup, updated, NULL); table_close(attrrel, RowExclusiveLock); heap_freetuple(atttup); + bms_free(updated); /* * Make a dependency so that the pg_attrdef entry goes away if the column @@ -256,7 +253,7 @@ RemoveAttrDefaultById(Oid attrdefId) ((Form_pg_attribute) GETSTRUCT(tuple))->atthasdef = false; - CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple); + CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple, NULL, NULL); /* * Our update of the pg_attribute row will force a relcache rebuild, so diff --git a/src/backend/catalog/pg_cast.c b/src/backend/catalog/pg_cast.c index 1773c9c549160..8ed900c239251 100644 --- a/src/backend/catalog/pg_cast.c +++ b/src/backend/catalog/pg_cast.c @@ -53,8 +53,8 @@ CastCreate(Oid sourcetypeid, Oid targettypeid, Relation relation; HeapTuple tuple; Oid castid; - Datum values[Natts_pg_cast]; - bool nulls[Natts_pg_cast] = {0}; + Datum values[Natts_pg_cast] = {0}; + bool nulls[Natts_pg_cast] = {false}; ObjectAddress myself, referenced; ObjectAddresses *addrs; @@ -78,16 +78,16 @@ CastCreate(Oid sourcetypeid, Oid targettypeid, /* ready to go */ castid = GetNewOidWithIndex(relation, CastOidIndexId, Anum_pg_cast_oid); - values[Anum_pg_cast_oid - 1] = ObjectIdGetDatum(castid); - values[Anum_pg_cast_castsource - 1] = ObjectIdGetDatum(sourcetypeid); - values[Anum_pg_cast_casttarget - 1] = ObjectIdGetDatum(targettypeid); - values[Anum_pg_cast_castfunc - 1] = ObjectIdGetDatum(funcid); - values[Anum_pg_cast_castcontext - 1] = CharGetDatum(castcontext); - values[Anum_pg_cast_castmethod - 1] = CharGetDatum(castmethod); + HeapTupleSetValue(pg_cast, oid, ObjectIdGetDatum(castid), values); + HeapTupleSetValue(pg_cast, castsource, ObjectIdGetDatum(sourcetypeid), values); + HeapTupleSetValue(pg_cast, casttarget, ObjectIdGetDatum(targettypeid), values); + HeapTupleSetValue(pg_cast, castfunc, ObjectIdGetDatum(funcid), values); + HeapTupleSetValue(pg_cast, castcontext, CharGetDatum(castcontext), values); + HeapTupleSetValue(pg_cast, castmethod, CharGetDatum(castmethod), values); tuple = heap_form_tuple(RelationGetDescr(relation), values, nulls); - CatalogTupleInsert(relation, tuple); + CatalogTupleInsert(relation, tuple, NULL); addrs = new_object_addresses(); diff --git a/src/backend/catalog/pg_collation.c b/src/backend/catalog/pg_collation.c index 469635b35808d..e440bf577e35f 100644 --- a/src/backend/catalog/pg_collation.c +++ b/src/backend/catalog/pg_collation.c @@ -54,8 +54,8 @@ CollationCreate(const char *collname, Oid collnamespace, Relation rel; TupleDesc tupDesc; HeapTuple tup; - Datum values[Natts_pg_collation]; - bool nulls[Natts_pg_collation]; + Datum values[Natts_pg_collation] = {0}; + bool nulls[Natts_pg_collation] = {false}; NameData name_name; Oid oid; ObjectAddress myself, @@ -175,38 +175,38 @@ CollationCreate(const char *collname, Oid collnamespace, namestrcpy(&name_name, collname); oid = GetNewOidWithIndex(rel, CollationOidIndexId, Anum_pg_collation_oid); - values[Anum_pg_collation_oid - 1] = ObjectIdGetDatum(oid); - values[Anum_pg_collation_collname - 1] = NameGetDatum(&name_name); - values[Anum_pg_collation_collnamespace - 1] = ObjectIdGetDatum(collnamespace); - values[Anum_pg_collation_collowner - 1] = ObjectIdGetDatum(collowner); - values[Anum_pg_collation_collprovider - 1] = CharGetDatum(collprovider); - values[Anum_pg_collation_collisdeterministic - 1] = BoolGetDatum(collisdeterministic); - values[Anum_pg_collation_collencoding - 1] = Int32GetDatum(collencoding); + HeapTupleSetValue(pg_collation, oid, ObjectIdGetDatum(oid), values); + HeapTupleSetValue(pg_collation, collname, NameGetDatum(&name_name), values); + HeapTupleSetValue(pg_collation, collnamespace, ObjectIdGetDatum(collnamespace), values); + HeapTupleSetValue(pg_collation, collowner, ObjectIdGetDatum(collowner), values); + HeapTupleSetValue(pg_collation, collprovider, CharGetDatum(collprovider), values); + HeapTupleSetValue(pg_collation, collisdeterministic, BoolGetDatum(collisdeterministic), values); + HeapTupleSetValue(pg_collation, collencoding, Int32GetDatum(collencoding), values); if (collcollate) - values[Anum_pg_collation_collcollate - 1] = CStringGetTextDatum(collcollate); + HeapTupleSetValue(pg_collation, collcollate, CStringGetTextDatum(collcollate), values); else - nulls[Anum_pg_collation_collcollate - 1] = true; + HeapTupleSetValueNull(pg_collation, collcollate, values, nulls); if (collctype) - values[Anum_pg_collation_collctype - 1] = CStringGetTextDatum(collctype); + HeapTupleSetValue(pg_collation, collctype, CStringGetTextDatum(collctype), values); else - nulls[Anum_pg_collation_collctype - 1] = true; + HeapTupleSetValueNull(pg_collation, collctype, values, nulls); if (colllocale) - values[Anum_pg_collation_colllocale - 1] = CStringGetTextDatum(colllocale); + HeapTupleSetValue(pg_collation, colllocale, CStringGetTextDatum(colllocale), values); else - nulls[Anum_pg_collation_colllocale - 1] = true; + HeapTupleSetValueNull(pg_collation, colllocale, values, nulls); if (collicurules) - values[Anum_pg_collation_collicurules - 1] = CStringGetTextDatum(collicurules); + HeapTupleSetValue(pg_collation, collicurules, CStringGetTextDatum(collicurules), values); else - nulls[Anum_pg_collation_collicurules - 1] = true; + HeapTupleSetValueNull(pg_collation, collicurules, values, nulls); if (collversion) - values[Anum_pg_collation_collversion - 1] = CStringGetTextDatum(collversion); + HeapTupleSetValue(pg_collation, collversion, CStringGetTextDatum(collversion), values); else - nulls[Anum_pg_collation_collversion - 1] = true; + HeapTupleSetValueNull(pg_collation, collversion, values, nulls); tup = heap_form_tuple(tupDesc, values, nulls); /* insert a new tuple */ - CatalogTupleInsert(rel, tup); + CatalogTupleInsert(rel, tup, NULL); Assert(OidIsValid(oid)); /* set up dependencies for the new collation */ diff --git a/src/backend/catalog/pg_conversion.c b/src/backend/catalog/pg_conversion.c index 090f680d1908f..247486ba7dec9 100644 --- a/src/backend/catalog/pg_conversion.c +++ b/src/backend/catalog/pg_conversion.c @@ -45,8 +45,8 @@ ConversionCreate(const char *conname, Oid connamespace, TupleDesc tupDesc; HeapTuple tup; Oid oid; - bool nulls[Natts_pg_conversion]; - Datum values[Natts_pg_conversion]; + Datum values[Natts_pg_conversion] = {0}; + bool nulls[Natts_pg_conversion] = {false}; NameData cname; ObjectAddress myself, referenced; @@ -94,19 +94,19 @@ ConversionCreate(const char *conname, Oid connamespace, namestrcpy(&cname, conname); oid = GetNewOidWithIndex(rel, ConversionOidIndexId, Anum_pg_conversion_oid); - values[Anum_pg_conversion_oid - 1] = ObjectIdGetDatum(oid); - values[Anum_pg_conversion_conname - 1] = NameGetDatum(&cname); - values[Anum_pg_conversion_connamespace - 1] = ObjectIdGetDatum(connamespace); - values[Anum_pg_conversion_conowner - 1] = ObjectIdGetDatum(conowner); - values[Anum_pg_conversion_conforencoding - 1] = Int32GetDatum(conforencoding); - values[Anum_pg_conversion_contoencoding - 1] = Int32GetDatum(contoencoding); - values[Anum_pg_conversion_conproc - 1] = ObjectIdGetDatum(conproc); - values[Anum_pg_conversion_condefault - 1] = BoolGetDatum(def); + HeapTupleSetValue(pg_conversion, oid, ObjectIdGetDatum(oid), values); + HeapTupleSetValue(pg_conversion, conname, NameGetDatum(&cname), values); + HeapTupleSetValue(pg_conversion, connamespace, ObjectIdGetDatum(connamespace), values); + HeapTupleSetValue(pg_conversion, conowner, ObjectIdGetDatum(conowner), values); + HeapTupleSetValue(pg_conversion, conforencoding, Int32GetDatum(conforencoding), values); + HeapTupleSetValue(pg_conversion, contoencoding, Int32GetDatum(contoencoding), values); + HeapTupleSetValue(pg_conversion, conproc, ObjectIdGetDatum(conproc), values); + HeapTupleSetValue(pg_conversion, condefault, BoolGetDatum(def), values); tup = heap_form_tuple(tupDesc, values, nulls); /* insert a new tuple */ - CatalogTupleInsert(rel, tup); + CatalogTupleInsert(rel, tup, NULL); myself.classId = ConversionRelationId; myself.objectId = oid; diff --git a/src/backend/catalog/pg_db_role_setting.c b/src/backend/catalog/pg_db_role_setting.c index 832e49a34bea5..2e95e28c0c2ac 100644 --- a/src/backend/catalog/pg_db_role_setting.c +++ b/src/backend/catalog/pg_db_role_setting.c @@ -74,21 +74,18 @@ AlterSetting(Oid databaseid, Oid roleid, VariableSetStmt *setstmt) if (new) { - Datum repl_val[Natts_pg_db_role_setting]; - bool repl_null[Natts_pg_db_role_setting]; - bool repl_repl[Natts_pg_db_role_setting]; + Datum values[Natts_pg_db_role_setting] = {0}; + bool nulls[Natts_pg_db_role_setting] = {false}; HeapTuple newtuple; + Bitmapset *updated = NULL; - memset(repl_repl, false, sizeof(repl_repl)); + HeapTupleUpdateValue(pg_db_role_setting, setconfig, PointerGetDatum(new), values, nulls, updated); - repl_val[Anum_pg_db_role_setting_setconfig - 1] = - PointerGetDatum(new); - repl_repl[Anum_pg_db_role_setting_setconfig - 1] = true; - repl_null[Anum_pg_db_role_setting_setconfig - 1] = false; + newtuple = heap_update_tuple(tuple, RelationGetDescr(rel), + values, nulls, updated); + CatalogTupleUpdate(rel, &tuple->t_self, newtuple, updated, NULL); - newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel), - repl_val, repl_null, repl_repl); - CatalogTupleUpdate(rel, &tuple->t_self, newtuple); + bms_free(updated); } else CatalogTupleDelete(rel, &tuple->t_self); @@ -96,18 +93,14 @@ AlterSetting(Oid databaseid, Oid roleid, VariableSetStmt *setstmt) } else if (HeapTupleIsValid(tuple)) { - Datum repl_val[Natts_pg_db_role_setting]; - bool repl_null[Natts_pg_db_role_setting]; - bool repl_repl[Natts_pg_db_role_setting]; + Datum values[Natts_pg_db_role_setting] = {0}; + bool nulls[Natts_pg_db_role_setting] = {false}; + Bitmapset *updated = NULL; HeapTuple newtuple; Datum datum; bool isnull; ArrayType *a; - memset(repl_repl, false, sizeof(repl_repl)); - repl_repl[Anum_pg_db_role_setting_setconfig - 1] = true; - repl_null[Anum_pg_db_role_setting_setconfig - 1] = false; - /* Extract old value of setconfig */ datum = heap_getattr(tuple, Anum_pg_db_role_setting_setconfig, RelationGetDescr(rel), &isnull); @@ -121,12 +114,12 @@ AlterSetting(Oid databaseid, Oid roleid, VariableSetStmt *setstmt) if (a) { - repl_val[Anum_pg_db_role_setting_setconfig - 1] = - PointerGetDatum(a); + HeapTupleUpdateValue(pg_db_role_setting, setconfig, PointerGetDatum(a), values, nulls, updated); - newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel), - repl_val, repl_null, repl_repl); - CatalogTupleUpdate(rel, &tuple->t_self, newtuple); + newtuple = heap_update_tuple(tuple, RelationGetDescr(rel), + values, nulls, updated); + CatalogTupleUpdate(rel, &tuple->t_self, newtuple, updated, NULL); + bms_free(updated); } else CatalogTupleDelete(rel, &tuple->t_self); @@ -135,21 +128,18 @@ AlterSetting(Oid databaseid, Oid roleid, VariableSetStmt *setstmt) { /* non-null valuestr means it's not RESET, so insert a new tuple */ HeapTuple newtuple; - Datum values[Natts_pg_db_role_setting]; - bool nulls[Natts_pg_db_role_setting]; + Datum values[Natts_pg_db_role_setting] = {0}; + bool nulls[Natts_pg_db_role_setting] = {false}; ArrayType *a; - memset(nulls, false, sizeof(nulls)); - a = GUCArrayAdd(NULL, setstmt->name, valuestr); - values[Anum_pg_db_role_setting_setdatabase - 1] = - ObjectIdGetDatum(databaseid); - values[Anum_pg_db_role_setting_setrole - 1] = ObjectIdGetDatum(roleid); - values[Anum_pg_db_role_setting_setconfig - 1] = PointerGetDatum(a); + HeapTupleSetValue(pg_db_role_setting, setdatabase, ObjectIdGetDatum(databaseid), values); + HeapTupleSetValue(pg_db_role_setting, setrole, ObjectIdGetDatum(roleid), values); + HeapTupleSetValue(pg_db_role_setting, setconfig, PointerGetDatum(a), values); newtuple = heap_form_tuple(RelationGetDescr(rel), values, nulls); - CatalogTupleInsert(rel, newtuple); + CatalogTupleInsert(rel, newtuple, NULL); } else { diff --git a/src/backend/catalog/pg_depend.c b/src/backend/catalog/pg_depend.c index c8b11f887e274..88deac7f3bd36 100644 --- a/src/backend/catalog/pg_depend.c +++ b/src/backend/catalog/pg_depend.c @@ -61,7 +61,7 @@ recordMultipleDependencies(const ObjectAddress *depender, { Relation dependDesc; CatalogIndexState indstate; - TupleTableSlot **slot; + TupleTableSlot **slots; int i, max_slots, slot_init_count, @@ -88,7 +88,7 @@ recordMultipleDependencies(const ObjectAddress *depender, */ max_slots = Min(nreferenced, MAX_CATALOG_MULTI_INSERT_BYTES / sizeof(FormData_pg_depend)); - slot = palloc(sizeof(TupleTableSlot *) * max_slots); + slots = palloc(sizeof(TupleTableSlot *) * max_slots); /* Don't open indexes unless we need to make an update */ indstate = NULL; @@ -99,6 +99,9 @@ recordMultipleDependencies(const ObjectAddress *depender, slot_init_count = 0; for (i = 0; i < nreferenced; i++, referenced++) { + TupleTableSlot *slot; + Datum *values; + /* * If the referenced object is pinned by the system, there's no real * need to record dependencies on it. This saves lots of space in @@ -109,29 +112,32 @@ recordMultipleDependencies(const ObjectAddress *depender, if (slot_init_count < max_slots) { - slot[slot_stored_count] = MakeSingleTupleTableSlot(RelationGetDescr(dependDesc), - &TTSOpsHeapTuple); + slots[slot_stored_count] = MakeSingleTupleTableSlot(RelationGetDescr(dependDesc), + &TTSOpsHeapTuple); slot_init_count++; } - ExecClearTuple(slot[slot_stored_count]); + ExecClearTuple(slots[slot_stored_count]); + + slot = slots[slot_stored_count]; + values = slot->tts_values; /* * Record the dependency. Note we don't bother to check for duplicate * dependencies; there's no harm in them. */ - slot[slot_stored_count]->tts_values[Anum_pg_depend_refclassid - 1] = ObjectIdGetDatum(referenced->classId); - slot[slot_stored_count]->tts_values[Anum_pg_depend_refobjid - 1] = ObjectIdGetDatum(referenced->objectId); - slot[slot_stored_count]->tts_values[Anum_pg_depend_refobjsubid - 1] = Int32GetDatum(referenced->objectSubId); - slot[slot_stored_count]->tts_values[Anum_pg_depend_deptype - 1] = CharGetDatum((char) behavior); - slot[slot_stored_count]->tts_values[Anum_pg_depend_classid - 1] = ObjectIdGetDatum(depender->classId); - slot[slot_stored_count]->tts_values[Anum_pg_depend_objid - 1] = ObjectIdGetDatum(depender->objectId); - slot[slot_stored_count]->tts_values[Anum_pg_depend_objsubid - 1] = Int32GetDatum(depender->objectSubId); - - memset(slot[slot_stored_count]->tts_isnull, false, - slot[slot_stored_count]->tts_tupleDescriptor->natts * sizeof(bool)); - - ExecStoreVirtualTuple(slot[slot_stored_count]); + HeapTupleSetValue(pg_depend, refclassid, ObjectIdGetDatum(referenced->classId), values); + HeapTupleSetValue(pg_depend, refobjid, ObjectIdGetDatum(referenced->objectId), values); + HeapTupleSetValue(pg_depend, refobjsubid, Int32GetDatum(referenced->objectSubId), values); + HeapTupleSetValue(pg_depend, deptype, CharGetDatum((char) behavior), values); + HeapTupleSetValue(pg_depend, classid, ObjectIdGetDatum(depender->classId), values); + HeapTupleSetValue(pg_depend, objid, ObjectIdGetDatum(depender->objectId), values); + HeapTupleSetValue(pg_depend, objsubid, Int32GetDatum(depender->objectSubId), values); + + memset(slot->tts_isnull, false, + slot->tts_tupleDescriptor->natts * sizeof(bool)); + + ExecStoreVirtualTuple(slot); slot_stored_count++; /* If slots are full, insert a batch of tuples */ @@ -141,8 +147,7 @@ recordMultipleDependencies(const ObjectAddress *depender, if (indstate == NULL) indstate = CatalogOpenIndexes(dependDesc); - CatalogTuplesMultiInsertWithInfo(dependDesc, slot, slot_stored_count, - indstate); + CatalogTuplesMultiInsert(dependDesc, slots, slot_stored_count, indstate); slot_stored_count = 0; } } @@ -154,8 +159,7 @@ recordMultipleDependencies(const ObjectAddress *depender, if (indstate == NULL) indstate = CatalogOpenIndexes(dependDesc); - CatalogTuplesMultiInsertWithInfo(dependDesc, slot, slot_stored_count, - indstate); + CatalogTuplesMultiInsert(dependDesc, slots, slot_stored_count, indstate); } if (indstate != NULL) @@ -165,8 +169,8 @@ recordMultipleDependencies(const ObjectAddress *depender, /* Drop only the number of slots used */ for (i = 0; i < slot_init_count; i++) - ExecDropSingleTupleTableSlot(slot[i]); - pfree(slot); + ExecDropSingleTupleTableSlot(slots[i]); + pfree(slots); } /* @@ -531,14 +535,16 @@ changeDependencyFor(Oid classId, Oid objectId, CatalogTupleDelete(depRel, &tup->t_self); else { + Bitmapset *updated = NULL; + /* make a modifiable copy */ tup = heap_copytuple(tup); depform = (Form_pg_depend) GETSTRUCT(tup); - depform->refobjid = newRefObjectId; - - CatalogTupleUpdate(depRel, &tup->t_self, tup); + HeapTupleUpdateField(pg_depend, refobjid, newRefObjectId, depform, updated); + CatalogTupleUpdate(depRel, &tup->t_self, tup, updated, NULL); + bms_free(updated); heap_freetuple(tup); } @@ -588,15 +594,16 @@ changeDependenciesOf(Oid classId, Oid oldObjectId, while (HeapTupleIsValid((tup = systable_getnext(scan)))) { Form_pg_depend depform; + Bitmapset *updated = NULL; /* make a modifiable copy */ tup = heap_copytuple(tup); depform = (Form_pg_depend) GETSTRUCT(tup); - depform->objid = newObjectId; - - CatalogTupleUpdate(depRel, &tup->t_self, tup); + HeapTupleUpdateField(pg_depend, objid, newObjectId, depform, updated); + CatalogTupleUpdate(depRel, &tup->t_self, tup, updated, NULL); + bms_free(updated); heap_freetuple(tup); count++; @@ -675,15 +682,16 @@ changeDependenciesOn(Oid refClassId, Oid oldRefObjectId, else { Form_pg_depend depform; + Bitmapset *updated = NULL; /* make a modifiable copy */ tup = heap_copytuple(tup); depform = (Form_pg_depend) GETSTRUCT(tup); - depform->refobjid = newRefObjectId; - - CatalogTupleUpdate(depRel, &tup->t_self, tup); + HeapTupleUpdateField(pg_depend, refobjid, newRefObjectId, depform, updated); + CatalogTupleUpdate(depRel, &tup->t_self, tup, updated, NULL); + bms_free(updated); heap_freetuple(tup); } diff --git a/src/backend/catalog/pg_enum.c b/src/backend/catalog/pg_enum.c index da9c2a46cfaa1..be87e9ad05697 100644 --- a/src/backend/catalog/pg_enum.c +++ b/src/backend/catalog/pg_enum.c @@ -194,12 +194,12 @@ EnumValuesCreate(Oid enumTypeOid, List *vals) memset(slot[slotCount]->tts_isnull, false, slot[slotCount]->tts_tupleDescriptor->natts * sizeof(bool)); - slot[slotCount]->tts_values[Anum_pg_enum_oid - 1] = ObjectIdGetDatum(oids[elemno]); - slot[slotCount]->tts_values[Anum_pg_enum_enumtypid - 1] = ObjectIdGetDatum(enumTypeOid); - slot[slotCount]->tts_values[Anum_pg_enum_enumsortorder - 1] = Float4GetDatum(elemno + 1); + HeapTupleSetValue(pg_enum, oid, ObjectIdGetDatum(oids[elemno]), slot[slotCount]->tts_values); + HeapTupleSetValue(pg_enum, enumtypid, ObjectIdGetDatum(enumTypeOid), slot[slotCount]->tts_values); + HeapTupleSetValue(pg_enum, enumsortorder, Float4GetDatum(elemno + 1), slot[slotCount]->tts_values); namestrcpy(enumlabel, lab); - slot[slotCount]->tts_values[Anum_pg_enum_enumlabel - 1] = NameGetDatum(enumlabel); + HeapTupleSetValue(pg_enum, enumlabel, NameGetDatum(enumlabel), slot[slotCount]->tts_values); ExecStoreVirtualTuple(slot[slotCount]); slotCount++; @@ -207,8 +207,7 @@ EnumValuesCreate(Oid enumTypeOid, List *vals) /* if slots are full, insert a batch of tuples */ if (slotCount == nslots) { - CatalogTuplesMultiInsertWithInfo(pg_enum, slot, slotCount, - indstate); + CatalogTuplesMultiInsert(pg_enum, slot, slotCount, indstate); slotCount = 0; } @@ -217,10 +216,9 @@ EnumValuesCreate(Oid enumTypeOid, List *vals) /* Insert any tuples left in the buffer */ if (slotCount > 0) - CatalogTuplesMultiInsertWithInfo(pg_enum, slot, slotCount, - indstate); + CatalogTuplesMultiInsert(pg_enum, slot, slotCount, indstate); - /* clean up */ + /* Clean up */ pfree(oids); for (int i = 0; i < nslots; i++) ExecDropSingleTupleTableSlot(slot[i]); @@ -310,8 +308,8 @@ AddEnumLabel(Oid enumTypeOid, { Relation pg_enum; Oid newOid; - Datum values[Natts_pg_enum]; - bool nulls[Natts_pg_enum]; + Datum values[Natts_pg_enum] = {0}; + bool nulls[Natts_pg_enum] = {false}; NameData enumlabel; HeapTuple enum_tup; float4 newelemorder; @@ -577,13 +575,13 @@ AddEnumLabel(Oid enumTypeOid, /* Create the new pg_enum entry */ memset(nulls, false, sizeof(nulls)); - values[Anum_pg_enum_oid - 1] = ObjectIdGetDatum(newOid); - values[Anum_pg_enum_enumtypid - 1] = ObjectIdGetDatum(enumTypeOid); - values[Anum_pg_enum_enumsortorder - 1] = Float4GetDatum(newelemorder); + HeapTupleSetValue(pg_enum, oid, ObjectIdGetDatum(newOid), values); + HeapTupleSetValue(pg_enum, enumtypid, ObjectIdGetDatum(enumTypeOid), values); + HeapTupleSetValue(pg_enum, enumsortorder, Float4GetDatum(newelemorder), values); namestrcpy(&enumlabel, newVal); - values[Anum_pg_enum_enumlabel - 1] = NameGetDatum(&enumlabel); + HeapTupleSetValue(pg_enum, enumlabel, NameGetDatum(&enumlabel), values); enum_tup = heap_form_tuple(RelationGetDescr(pg_enum), values, nulls); - CatalogTupleInsert(pg_enum, enum_tup); + CatalogTupleInsert(pg_enum, enum_tup, NULL); heap_freetuple(enum_tup); table_close(pg_enum, RowExclusiveLock); @@ -629,6 +627,7 @@ RenameEnumLabel(Oid enumTypeOid, HeapTuple old_tup; bool found_new; int i; + Bitmapset *updated = NULL; /* check length of new label is ok */ if (strlen(newVal) > (NAMEDATALEN - 1)) @@ -689,9 +688,12 @@ RenameEnumLabel(Oid enumTypeOid, /* Update the pg_enum entry */ namestrcpy(&en->enumlabel, newVal); - CatalogTupleUpdate(pg_enum, &enum_tup->t_self, enum_tup); - heap_freetuple(enum_tup); + HeapTupleMarkColumnUpdated(pg_enum, enumlabel, updated); + + CatalogTupleUpdate(pg_enum, &enum_tup->t_self, enum_tup, updated, NULL); + bms_free(updated); + heap_freetuple(enum_tup); table_close(pg_enum, RowExclusiveLock); } @@ -792,9 +794,12 @@ RenumberEnumType(Relation pg_enum, HeapTuple *existing, int nelems) newsortorder = i + 1; if (en->enumsortorder != newsortorder) { - en->enumsortorder = newsortorder; + Bitmapset *updated = NULL; + + HeapTupleUpdateField(pg_enum, enumsortorder, newsortorder, en, updated); - CatalogTupleUpdate(pg_enum, &newtup->t_self, newtup); + CatalogTupleUpdate(pg_enum, &newtup->t_self, newtup, updated, NULL); + bms_free(updated); } heap_freetuple(newtup); diff --git a/src/backend/catalog/pg_inherits.c b/src/backend/catalog/pg_inherits.c index 929bb53b620fe..a4e0338b54c83 100644 --- a/src/backend/catalog/pg_inherits.c +++ b/src/backend/catalog/pg_inherits.c @@ -507,8 +507,8 @@ typeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId) void StoreSingleInheritance(Oid relationId, Oid parentOid, int32 seqNumber) { - Datum values[Natts_pg_inherits]; - bool nulls[Natts_pg_inherits]; + Datum values[Natts_pg_inherits] = {0}; + bool nulls[Natts_pg_inherits] = {false}; HeapTuple tuple; Relation inhRelation; @@ -517,16 +517,16 @@ StoreSingleInheritance(Oid relationId, Oid parentOid, int32 seqNumber) /* * Make the pg_inherits entry */ - values[Anum_pg_inherits_inhrelid - 1] = ObjectIdGetDatum(relationId); - values[Anum_pg_inherits_inhparent - 1] = ObjectIdGetDatum(parentOid); - values[Anum_pg_inherits_inhseqno - 1] = Int32GetDatum(seqNumber); - values[Anum_pg_inherits_inhdetachpending - 1] = BoolGetDatum(false); + HeapTupleSetValue(pg_inherits, inhrelid, ObjectIdGetDatum(relationId), values); + HeapTupleSetValue(pg_inherits, inhparent, ObjectIdGetDatum(parentOid), values); + HeapTupleSetValue(pg_inherits, inhseqno, Int32GetDatum(seqNumber), values); + HeapTupleSetValue(pg_inherits, inhdetachpending, BoolGetDatum(false), values); memset(nulls, 0, sizeof(nulls)); tuple = heap_form_tuple(RelationGetDescr(inhRelation), values, nulls); - CatalogTupleInsert(inhRelation, tuple); + CatalogTupleInsert(inhRelation, tuple, NULL); heap_freetuple(tuple); diff --git a/src/backend/catalog/pg_largeobject.c b/src/backend/catalog/pg_largeobject.c index 33e8fa96a65a8..e49cea5041602 100644 --- a/src/backend/catalog/pg_largeobject.c +++ b/src/backend/catalog/pg_largeobject.c @@ -39,8 +39,8 @@ LargeObjectCreate(Oid loid) Relation pg_lo_meta; HeapTuple ntup; Oid loid_new; - Datum values[Natts_pg_largeobject_metadata]; - bool nulls[Natts_pg_largeobject_metadata]; + Datum values[Natts_pg_largeobject_metadata] = {0}; + bool nulls[Natts_pg_largeobject_metadata] = {false}; Oid ownerId; Acl *lomacl; @@ -50,9 +50,6 @@ LargeObjectCreate(Oid loid) /* * Insert metadata of the largeobject */ - memset(values, 0, sizeof(values)); - memset(nulls, false, sizeof(nulls)); - if (OidIsValid(loid)) loid_new = loid; else @@ -62,20 +59,17 @@ LargeObjectCreate(Oid loid) ownerId = GetUserId(); lomacl = get_user_default_acl(OBJECT_LARGEOBJECT, ownerId, InvalidOid); - values[Anum_pg_largeobject_metadata_oid - 1] = ObjectIdGetDatum(loid_new); - values[Anum_pg_largeobject_metadata_lomowner - 1] - = ObjectIdGetDatum(ownerId); + HeapTupleSetValue(pg_largeobject_metadata, oid, ObjectIdGetDatum(loid_new), values); + HeapTupleSetValue(pg_largeobject_metadata, lomowner, ObjectIdGetDatum(ownerId), values); if (lomacl != NULL) - values[Anum_pg_largeobject_metadata_lomacl - 1] - = PointerGetDatum(lomacl); + HeapTupleSetValue(pg_largeobject_metadata, lomacl, PointerGetDatum(lomacl), values); else - nulls[Anum_pg_largeobject_metadata_lomacl - 1] = true; + HeapTupleSetValueNull(pg_largeobject_metadata, lomacl, values, nulls); - ntup = heap_form_tuple(RelationGetDescr(pg_lo_meta), - values, nulls); + ntup = heap_form_tuple(RelationGetDescr(pg_lo_meta), values, nulls); - CatalogTupleInsert(pg_lo_meta, ntup); + CatalogTupleInsert(pg_lo_meta, ntup, NULL); heap_freetuple(ntup); diff --git a/src/backend/catalog/pg_namespace.c b/src/backend/catalog/pg_namespace.c index 616bcc7852113..fa2a970108ca4 100644 --- a/src/backend/catalog/pg_namespace.c +++ b/src/backend/catalog/pg_namespace.c @@ -45,12 +45,11 @@ NamespaceCreate(const char *nspName, Oid ownerId, bool isTemp) Relation nspdesc; HeapTuple tup; Oid nspoid; - bool nulls[Natts_pg_namespace]; - Datum values[Natts_pg_namespace]; + bool nulls[Natts_pg_namespace] = {false}; + Datum values[Natts_pg_namespace] = {0}; NameData nname; TupleDesc tupDesc; ObjectAddress myself; - int i; Acl *nspacl; /* sanity checks */ @@ -72,28 +71,21 @@ NamespaceCreate(const char *nspName, Oid ownerId, bool isTemp) nspdesc = table_open(NamespaceRelationId, RowExclusiveLock); tupDesc = nspdesc->rd_att; - /* initialize nulls and values */ - for (i = 0; i < Natts_pg_namespace; i++) - { - nulls[i] = false; - values[i] = (Datum) 0; - } - nspoid = GetNewOidWithIndex(nspdesc, NamespaceOidIndexId, Anum_pg_namespace_oid); - values[Anum_pg_namespace_oid - 1] = ObjectIdGetDatum(nspoid); + HeapTupleSetValue(pg_namespace, oid, ObjectIdGetDatum(nspoid), values); namestrcpy(&nname, nspName); - values[Anum_pg_namespace_nspname - 1] = NameGetDatum(&nname); - values[Anum_pg_namespace_nspowner - 1] = ObjectIdGetDatum(ownerId); + HeapTupleSetValue(pg_namespace, nspname, NameGetDatum(&nname), values); + HeapTupleSetValue(pg_namespace, nspowner, ObjectIdGetDatum(ownerId), values); if (nspacl != NULL) - values[Anum_pg_namespace_nspacl - 1] = PointerGetDatum(nspacl); + HeapTupleSetValue(pg_namespace, nspacl, PointerGetDatum(nspacl), values); else - nulls[Anum_pg_namespace_nspacl - 1] = true; + HeapTupleSetValueNull(pg_namespace, nspacl, values, nulls); tup = heap_form_tuple(tupDesc, values, nulls); - CatalogTupleInsert(nspdesc, tup); + CatalogTupleInsert(nspdesc, tup, NULL); Assert(OidIsValid(nspoid)); table_close(nspdesc, RowExclusiveLock); diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c index 44d2ccb6788e9..2595ef1d787cd 100644 --- a/src/backend/catalog/pg_operator.c +++ b/src/backend/catalog/pg_operator.c @@ -17,6 +17,7 @@ */ #include "postgres.h" +#include "access/htup.h" #include "access/htup_details.h" #include "access/table.h" #include "access/xact.h" @@ -199,10 +200,11 @@ OperatorShellMake(const char *operatorName, Oid operatorObjectId; int i; HeapTuple tup; - Datum values[Natts_pg_operator]; - bool nulls[Natts_pg_operator]; + Datum values[Natts_pg_operator] = {0}; + bool nulls[Natts_pg_operator] = {false}; NameData oname; TupleDesc tupDesc; + Bitmapset *updated = NULL; /* * validate operator name @@ -234,22 +236,23 @@ OperatorShellMake(const char *operatorName, */ operatorObjectId = GetNewOidWithIndex(pg_operator_desc, OperatorOidIndexId, Anum_pg_operator_oid); - values[Anum_pg_operator_oid - 1] = ObjectIdGetDatum(operatorObjectId); + + HeapTupleUpdateValue(pg_operator, oid, ObjectIdGetDatum(operatorObjectId), values, nulls, updated); namestrcpy(&oname, operatorName); - values[Anum_pg_operator_oprname - 1] = NameGetDatum(&oname); - values[Anum_pg_operator_oprnamespace - 1] = ObjectIdGetDatum(operatorNamespace); - values[Anum_pg_operator_oprowner - 1] = ObjectIdGetDatum(GetUserId()); - values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? 'b' : 'l'); - values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(false); - values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(false); - values[Anum_pg_operator_oprleft - 1] = ObjectIdGetDatum(leftTypeId); - values[Anum_pg_operator_oprright - 1] = ObjectIdGetDatum(rightTypeId); - values[Anum_pg_operator_oprresult - 1] = ObjectIdGetDatum(InvalidOid); - values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(InvalidOid); - values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(InvalidOid); - values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(InvalidOid); - values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(InvalidOid); - values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(InvalidOid); + HeapTupleUpdateValue(pg_operator, oprname, NameGetDatum(&oname), values, nulls, updated); + HeapTupleUpdateValue(pg_operator, oprnamespace, ObjectIdGetDatum(operatorNamespace), values, nulls, updated); + HeapTupleUpdateValue(pg_operator, oprowner, ObjectIdGetDatum(GetUserId()), values, nulls, updated); + HeapTupleUpdateValue(pg_operator, oprkind, CharGetDatum(leftTypeId ? 'b' : 'l'), values, nulls, updated); + HeapTupleUpdateValue(pg_operator, oprcanmerge, BoolGetDatum(false), values, nulls, updated); + HeapTupleUpdateValue(pg_operator, oprcanhash, BoolGetDatum(false), values, nulls, updated); + HeapTupleUpdateValue(pg_operator, oprleft, ObjectIdGetDatum(leftTypeId), values, nulls, updated); + HeapTupleUpdateValue(pg_operator, oprright, ObjectIdGetDatum(rightTypeId), values, nulls, updated); + HeapTupleUpdateValue(pg_operator, oprresult, ObjectIdGetDatum(InvalidOid), values, nulls, updated); + HeapTupleUpdateValue(pg_operator, oprcom, ObjectIdGetDatum(InvalidOid), values, nulls, updated); + HeapTupleUpdateValue(pg_operator, oprnegate, ObjectIdGetDatum(InvalidOid), values, nulls, updated); + HeapTupleUpdateValue(pg_operator, oprcode, ObjectIdGetDatum(InvalidOid), values, nulls, updated); + HeapTupleUpdateValue(pg_operator, oprrest, ObjectIdGetDatum(InvalidOid), values, nulls, updated); + HeapTupleUpdateValue(pg_operator, oprjoin, ObjectIdGetDatum(InvalidOid), values, nulls, updated); /* * create a new operator tuple @@ -259,7 +262,7 @@ OperatorShellMake(const char *operatorName, /* * insert our "shell" operator tuple */ - CatalogTupleInsert(pg_operator_desc, tup); + CatalogTupleInsert(pg_operator_desc, tup, NULL); /* Add dependencies for the entry */ makeOperatorDependencies(tup, true, false); @@ -333,9 +336,9 @@ OperatorCreate(const char *operatorName, Relation pg_operator_desc; HeapTuple tup; bool isUpdate; - bool nulls[Natts_pg_operator]; - bool replaces[Natts_pg_operator]; - Datum values[Natts_pg_operator]; + Datum values[Natts_pg_operator] = {0}; + bool nulls[Natts_pg_operator] = {false}; + Bitmapset *updated = NULL; Oid operatorObjectId; bool operatorAlreadyDefined; Oid operResultType; @@ -343,7 +346,6 @@ OperatorCreate(const char *operatorName, negatorId; bool selfCommutator = false; NameData oname; - int i; ObjectAddress address; /* @@ -447,32 +449,25 @@ OperatorCreate(const char *operatorName, else negatorId = InvalidOid; - /* - * set up values in the operator tuple - */ - - for (i = 0; i < Natts_pg_operator; ++i) - { - values[i] = (Datum) 0; - replaces[i] = true; - nulls[i] = false; - } + /* Set up values in the operator tuple */ + HeapTupleUpdateSetAllColumnsUpdated(pg_operator, updated); + HeapTupleSetColumnNotUpdated(pg_operator, oid, updated); namestrcpy(&oname, operatorName); - values[Anum_pg_operator_oprname - 1] = NameGetDatum(&oname); - values[Anum_pg_operator_oprnamespace - 1] = ObjectIdGetDatum(operatorNamespace); - values[Anum_pg_operator_oprowner - 1] = ObjectIdGetDatum(GetUserId()); - values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? 'b' : 'l'); - values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(canMerge); - values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(canHash); - values[Anum_pg_operator_oprleft - 1] = ObjectIdGetDatum(leftTypeId); - values[Anum_pg_operator_oprright - 1] = ObjectIdGetDatum(rightTypeId); - values[Anum_pg_operator_oprresult - 1] = ObjectIdGetDatum(operResultType); - values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(commutatorId); - values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(negatorId); - values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(procedureId); - values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(restrictionId); - values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(joinId); + HeapTupleUpdateValue(pg_operator, oprname, NameGetDatum(&oname), values, nulls, updated); + HeapTupleUpdateValue(pg_operator, oprnamespace, ObjectIdGetDatum(operatorNamespace), values, nulls, updated); + HeapTupleUpdateValue(pg_operator, oprowner, ObjectIdGetDatum(GetUserId()), values, nulls, updated); + HeapTupleUpdateValue(pg_operator, oprkind, CharGetDatum(leftTypeId ? 'b' : 'l'), values, nulls, updated); + HeapTupleUpdateValue(pg_operator, oprcanmerge, BoolGetDatum(canMerge), values, nulls, updated); + HeapTupleUpdateValue(pg_operator, oprcanhash, BoolGetDatum(canHash), values, nulls, updated); + HeapTupleUpdateValue(pg_operator, oprleft, ObjectIdGetDatum(leftTypeId), values, nulls, updated); + HeapTupleUpdateValue(pg_operator, oprright, ObjectIdGetDatum(rightTypeId), values, nulls, updated); + HeapTupleUpdateValue(pg_operator, oprresult, ObjectIdGetDatum(operResultType), values, nulls, updated); + HeapTupleUpdateValue(pg_operator, oprcom, ObjectIdGetDatum(commutatorId), values, nulls, updated); + HeapTupleUpdateValue(pg_operator, oprnegate, ObjectIdGetDatum(negatorId), values, nulls, updated); + HeapTupleUpdateValue(pg_operator, oprcode, ObjectIdGetDatum(procedureId), values, nulls, updated); + HeapTupleUpdateValue(pg_operator, oprrest, ObjectIdGetDatum(restrictionId), values, nulls, updated); + HeapTupleUpdateValue(pg_operator, oprjoin, ObjectIdGetDatum(joinId), values, nulls, updated); pg_operator_desc = table_open(OperatorRelationId, RowExclusiveLock); @@ -489,14 +484,9 @@ OperatorCreate(const char *operatorName, elog(ERROR, "cache lookup failed for operator %u", operatorObjectId); - replaces[Anum_pg_operator_oid - 1] = false; - tup = heap_modify_tuple(tup, - RelationGetDescr(pg_operator_desc), - values, - nulls, - replaces); + tup = heap_update_tuple(tup, RelationGetDescr(pg_operator_desc), values, nulls, updated); - CatalogTupleUpdate(pg_operator_desc, &tup->t_self, tup); + CatalogTupleUpdate(pg_operator_desc, &tup->t_self, tup, updated, NULL); } else { @@ -505,12 +495,12 @@ OperatorCreate(const char *operatorName, operatorObjectId = GetNewOidWithIndex(pg_operator_desc, OperatorOidIndexId, Anum_pg_operator_oid); - values[Anum_pg_operator_oid - 1] = ObjectIdGetDatum(operatorObjectId); + HeapTupleUpdateValue(pg_operator, oid, ObjectIdGetDatum(operatorObjectId), values, nulls, updated); tup = heap_form_tuple(RelationGetDescr(pg_operator_desc), values, nulls); - CatalogTupleInsert(pg_operator_desc, tup); + CatalogTupleInsert(pg_operator_desc, tup, NULL); } /* Add dependencies for the entry */ @@ -536,6 +526,7 @@ OperatorCreate(const char *operatorName, /* Post creation hook for new operator */ InvokeObjectPostCreateHook(OperatorRelationId, operatorObjectId, 0); + bms_free(updated); table_close(pg_operator_desc, RowExclusiveLock); return address; @@ -708,6 +699,7 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId, bool isDelete) if (HeapTupleIsValid(tup)) { Form_pg_operator t = (Form_pg_operator) GETSTRUCT(tup); + Bitmapset *updated = NULL; bool update_commutator = false; /* @@ -717,7 +709,7 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId, bool isDelete) */ if (isDelete && OidIsValid(t->oprcom)) { - t->oprcom = InvalidOid; + HeapTupleUpdateField(pg_operator, oprcom, InvalidOid, t, updated); update_commutator = true; } else if (!isDelete && t->oprcom != baseId) @@ -745,14 +737,14 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId, bool isDelete) NameStr(t->oprname), t->oprcom))); } - t->oprcom = baseId; + HeapTupleUpdateField(pg_operator, oprcom, baseId, t, updated); update_commutator = true; } /* If any columns were found to need modification, update tuple. */ if (update_commutator) { - CatalogTupleUpdate(pg_operator_desc, &tup->t_self, tup); + CatalogTupleUpdate(pg_operator_desc, &tup->t_self, tup, updated, NULL); /* * Do CCI to make the updated tuple visible. We must do this in @@ -763,6 +755,8 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId, bool isDelete) */ CommandCounterIncrement(); } + + bms_free(updated); } /* @@ -777,6 +771,7 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId, bool isDelete) { Form_pg_operator t = (Form_pg_operator) GETSTRUCT(tup); bool update_negator = false; + Bitmapset *updated = NULL; /* * We can skip doing anything if the negator's oprnegate field is @@ -785,7 +780,7 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId, bool isDelete) */ if (isDelete && OidIsValid(t->oprnegate)) { - t->oprnegate = InvalidOid; + HeapTupleUpdateField(pg_operator, oprnegate, InvalidOid, t, updated); update_negator = true; } else if (!isDelete && t->oprnegate != baseId) @@ -813,14 +808,14 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId, bool isDelete) NameStr(t->oprname), t->oprnegate))); } - t->oprnegate = baseId; + HeapTupleUpdateField(pg_operator, oprnegate, baseId, t, updated); update_negator = true; } /* If any columns were found to need modification, update tuple. */ if (update_negator) { - CatalogTupleUpdate(pg_operator_desc, &tup->t_self, tup); + CatalogTupleUpdate(pg_operator_desc, &tup->t_self, tup, updated, NULL); /* * In the deletion case, do CCI to make the updated tuple visible. @@ -831,6 +826,8 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId, bool isDelete) if (isDelete) CommandCounterIncrement(); } + + bms_free(updated); } /* Close relation and release catalog lock. */ diff --git a/src/backend/catalog/pg_parameter_acl.c b/src/backend/catalog/pg_parameter_acl.c index dcdf49ea408d6..04e3545552db9 100644 --- a/src/backend/catalog/pg_parameter_acl.c +++ b/src/backend/catalog/pg_parameter_acl.c @@ -74,7 +74,7 @@ ParameterAclCreate(const char *parameter) TupleDesc tupDesc; HeapTuple tuple; Datum values[Natts_pg_parameter_acl] = {0}; - bool nulls[Natts_pg_parameter_acl] = {0}; + bool nulls[Natts_pg_parameter_acl] = {false}; /* * To prevent cluttering pg_parameter_acl with useless entries, insist @@ -96,12 +96,11 @@ ParameterAclCreate(const char *parameter) parameterId = GetNewOidWithIndex(rel, ParameterAclOidIndexId, Anum_pg_parameter_acl_oid); - values[Anum_pg_parameter_acl_oid - 1] = ObjectIdGetDatum(parameterId); - values[Anum_pg_parameter_acl_parname - 1] = - PointerGetDatum(cstring_to_text(parname)); - nulls[Anum_pg_parameter_acl_paracl - 1] = true; + HeapTupleSetValue(pg_parameter_acl, oid, ObjectIdGetDatum(parameterId), values); + HeapTupleSetValue(pg_parameter_acl, parname, PointerGetDatum(cstring_to_text(parname)), values); + HeapTupleSetValueNull(pg_parameter_acl, paracl, values, nulls); tuple = heap_form_tuple(tupDesc, values, nulls); - CatalogTupleInsert(rel, tuple); + CatalogTupleInsert(rel, tuple, NULL); /* Close pg_parameter_acl, but keep lock till commit. */ heap_freetuple(tuple); diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c index b89b9ccda0ed9..252a2f4aedac2 100644 --- a/src/backend/catalog/pg_proc.c +++ b/src/backend/catalog/pg_proc.c @@ -14,6 +14,7 @@ */ #include "postgres.h" +#include "access/htup.h" #include "access/htup_details.h" #include "access/table.h" #include "access/xact.h" @@ -134,9 +135,9 @@ ProcedureCreate(const char *procedureName, Relation rel; HeapTuple tup; HeapTuple oldtup; - bool nulls[Natts_pg_proc]; - Datum values[Natts_pg_proc]; - bool replaces[Natts_pg_proc]; + Datum values[Natts_pg_proc] = {0}; + bool nulls[Natts_pg_proc] = {false}; + Bitmapset *updated = NULL; NameData procname; TupleDesc tupDesc; bool is_update; @@ -316,67 +317,61 @@ ProcedureCreate(const char *procedureName, /* * All seems OK; prepare the data to be inserted into pg_proc. */ - - for (i = 0; i < Natts_pg_proc; ++i) - { - nulls[i] = false; - values[i] = (Datum) 0; - replaces[i] = true; - } + HeapTupleUpdateSetAllColumnsUpdated(pg_proc, updated); namestrcpy(&procname, procedureName); - values[Anum_pg_proc_proname - 1] = NameGetDatum(&procname); - values[Anum_pg_proc_pronamespace - 1] = ObjectIdGetDatum(procNamespace); - values[Anum_pg_proc_proowner - 1] = ObjectIdGetDatum(proowner); - values[Anum_pg_proc_prolang - 1] = ObjectIdGetDatum(languageObjectId); - values[Anum_pg_proc_procost - 1] = Float4GetDatum(procost); - values[Anum_pg_proc_prorows - 1] = Float4GetDatum(prorows); - values[Anum_pg_proc_provariadic - 1] = ObjectIdGetDatum(variadicType); - values[Anum_pg_proc_prosupport - 1] = ObjectIdGetDatum(prosupport); - values[Anum_pg_proc_prokind - 1] = CharGetDatum(prokind); - values[Anum_pg_proc_prosecdef - 1] = BoolGetDatum(security_definer); - values[Anum_pg_proc_proleakproof - 1] = BoolGetDatum(isLeakProof); - values[Anum_pg_proc_proisstrict - 1] = BoolGetDatum(isStrict); - values[Anum_pg_proc_proretset - 1] = BoolGetDatum(returnsSet); - values[Anum_pg_proc_provolatile - 1] = CharGetDatum(volatility); - values[Anum_pg_proc_proparallel - 1] = CharGetDatum(parallel); - values[Anum_pg_proc_pronargs - 1] = UInt16GetDatum(parameterCount); - values[Anum_pg_proc_pronargdefaults - 1] = UInt16GetDatum(list_length(parameterDefaults)); - values[Anum_pg_proc_prorettype - 1] = ObjectIdGetDatum(returnType); - values[Anum_pg_proc_proargtypes - 1] = PointerGetDatum(parameterTypes); + HeapTupleUpdateValue(pg_proc, proname, NameGetDatum(&procname), values, nulls, updated); + HeapTupleUpdateValue(pg_proc, pronamespace, ObjectIdGetDatum(procNamespace), values, nulls, updated); + HeapTupleUpdateValue(pg_proc, proowner, ObjectIdGetDatum(proowner), values, nulls, updated); + HeapTupleUpdateValue(pg_proc, prolang, ObjectIdGetDatum(languageObjectId), values, nulls, updated); + HeapTupleUpdateValue(pg_proc, procost, Float4GetDatum(procost), values, nulls, updated); + HeapTupleUpdateValue(pg_proc, prorows, Float4GetDatum(prorows), values, nulls, updated); + HeapTupleUpdateValue(pg_proc, provariadic, ObjectIdGetDatum(variadicType), values, nulls, updated); + HeapTupleUpdateValue(pg_proc, prosupport, ObjectIdGetDatum(prosupport), values, nulls, updated); + HeapTupleUpdateValue(pg_proc, prokind, CharGetDatum(prokind), values, nulls, updated); + HeapTupleUpdateValue(pg_proc, prosecdef, BoolGetDatum(security_definer), values, nulls, updated); + HeapTupleUpdateValue(pg_proc, proleakproof, BoolGetDatum(isLeakProof), values, nulls, updated); + HeapTupleUpdateValue(pg_proc, proisstrict, BoolGetDatum(isStrict), values, nulls, updated); + HeapTupleUpdateValue(pg_proc, proretset, BoolGetDatum(returnsSet), values, nulls, updated); + HeapTupleUpdateValue(pg_proc, provolatile, CharGetDatum(volatility), values, nulls, updated); + HeapTupleUpdateValue(pg_proc, proparallel, CharGetDatum(parallel), values, nulls, updated); + HeapTupleUpdateValue(pg_proc, pronargs, UInt16GetDatum(parameterCount), values, nulls, updated); + HeapTupleUpdateValue(pg_proc, pronargdefaults, UInt16GetDatum(list_length(parameterDefaults)), values, nulls, updated); + HeapTupleUpdateValue(pg_proc, prorettype, ObjectIdGetDatum(returnType), values, nulls, updated); + HeapTupleUpdateValue(pg_proc, proargtypes, PointerGetDatum(parameterTypes), values, nulls, updated); if (allParameterTypes != PointerGetDatum(NULL)) - values[Anum_pg_proc_proallargtypes - 1] = allParameterTypes; + HeapTupleUpdateValue(pg_proc, proallargtypes, allParameterTypes, values, nulls, updated); else - nulls[Anum_pg_proc_proallargtypes - 1] = true; + HeapTupleUpdateValueNull(pg_proc, proallargtypes, values, nulls, updated); if (parameterModes != PointerGetDatum(NULL)) - values[Anum_pg_proc_proargmodes - 1] = parameterModes; + HeapTupleUpdateValue(pg_proc, proargmodes, parameterModes, values, nulls, updated); else - nulls[Anum_pg_proc_proargmodes - 1] = true; + HeapTupleUpdateValueNull(pg_proc, proargmodes, values, nulls, updated); if (parameterNames != PointerGetDatum(NULL)) - values[Anum_pg_proc_proargnames - 1] = parameterNames; + HeapTupleUpdateValue(pg_proc, proargnames, parameterNames, values, nulls, updated); else - nulls[Anum_pg_proc_proargnames - 1] = true; + HeapTupleUpdateValueNull(pg_proc, proargnames, values, nulls, updated); if (parameterDefaults != NIL) - values[Anum_pg_proc_proargdefaults - 1] = CStringGetTextDatum(nodeToString(parameterDefaults)); + HeapTupleUpdateValue(pg_proc, proargdefaults, CStringGetTextDatum(nodeToString(parameterDefaults)), values, nulls, updated); else - nulls[Anum_pg_proc_proargdefaults - 1] = true; + HeapTupleUpdateValueNull(pg_proc, proargdefaults, values, nulls, updated); if (trftypes != PointerGetDatum(NULL)) - values[Anum_pg_proc_protrftypes - 1] = trftypes; + HeapTupleUpdateValue(pg_proc, protrftypes, trftypes, values, nulls, updated); else - nulls[Anum_pg_proc_protrftypes - 1] = true; - values[Anum_pg_proc_prosrc - 1] = CStringGetTextDatum(prosrc); + HeapTupleUpdateValueNull(pg_proc, protrftypes, values, nulls, updated); + HeapTupleUpdateValue(pg_proc, prosrc, CStringGetTextDatum(prosrc), values, nulls, updated); if (probin) - values[Anum_pg_proc_probin - 1] = CStringGetTextDatum(probin); + HeapTupleUpdateValue(pg_proc, probin, CStringGetTextDatum(probin), values, nulls, updated); else - nulls[Anum_pg_proc_probin - 1] = true; + HeapTupleUpdateValueNull(pg_proc, probin, values, nulls, updated); if (prosqlbody) - values[Anum_pg_proc_prosqlbody - 1] = CStringGetTextDatum(nodeToString(prosqlbody)); + HeapTupleUpdateValue(pg_proc, prosqlbody, CStringGetTextDatum(nodeToString(prosqlbody)), values, nulls, updated); else - nulls[Anum_pg_proc_prosqlbody - 1] = true; + HeapTupleUpdateValueNull(pg_proc, prosqlbody, values, nulls, updated); if (proconfig != PointerGetDatum(NULL)) - values[Anum_pg_proc_proconfig - 1] = proconfig; + HeapTupleUpdateValue(pg_proc, proconfig, proconfig, values, nulls, updated); else - nulls[Anum_pg_proc_proconfig - 1] = true; + HeapTupleUpdateValueNull(pg_proc, proconfig, values, nulls, updated); /* proacl will be determined later */ rel = table_open(ProcedureRelationId, RowExclusiveLock); @@ -577,13 +572,13 @@ ProcedureCreate(const char *procedureName, * Do not change existing oid, ownership or permissions, either. Note * dependency-update code below has to agree with this decision. */ - replaces[Anum_pg_proc_oid - 1] = false; - replaces[Anum_pg_proc_proowner - 1] = false; - replaces[Anum_pg_proc_proacl - 1] = false; + HeapTupleSetColumnNotUpdated(pg_proc, oid, updated); + HeapTupleSetColumnNotUpdated(pg_proc, proowner, updated); + HeapTupleSetColumnNotUpdated(pg_proc, proacl, updated); /* Okay, do it... */ - tup = heap_modify_tuple(oldtup, tupDesc, values, nulls, replaces); - CatalogTupleUpdate(rel, &tup->t_self, tup); + tup = heap_update_tuple(oldtup, tupDesc, values, nulls, updated); + CatalogTupleUpdate(rel, &tup->t_self, tup, updated, NULL); ReleaseSysCache(oldtup); is_update = true; @@ -597,18 +592,23 @@ ProcedureCreate(const char *procedureName, proacl = get_user_default_acl(OBJECT_FUNCTION, proowner, procNamespace); if (proacl != NULL) - values[Anum_pg_proc_proacl - 1] = PointerGetDatum(proacl); + HeapTupleUpdateValue(pg_proc, proacl, PointerGetDatum(proacl), values, nulls, updated); else - nulls[Anum_pg_proc_proacl - 1] = true; + HeapTupleUpdateValueNull(pg_proc, proacl, values, nulls, updated); newOid = GetNewOidWithIndex(rel, ProcedureOidIndexId, Anum_pg_proc_oid); - values[Anum_pg_proc_oid - 1] = ObjectIdGetDatum(newOid); + HeapTupleUpdateValue(pg_proc, oid, ObjectIdGetDatum(newOid), values, nulls, updated); + + /* Okay, do it... */ tup = heap_form_tuple(tupDesc, values, nulls); - CatalogTupleInsert(rel, tup); + CatalogTupleInsert(rel, tup, NULL); + is_update = false; } + bms_free(updated); + updated = NULL; retval = ((Form_pg_proc) GETSTRUCT(tup))->oid; diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c index ac2f4ee35616c..9521b7cd3a47d 100644 --- a/src/backend/catalog/pg_publication.c +++ b/src/backend/catalog/pg_publication.c @@ -433,8 +433,8 @@ publication_add_relation(Oid pubid, PublicationRelInfo *pri, { Relation rel; HeapTuple tup; - Datum values[Natts_pg_publication_rel]; - bool nulls[Natts_pg_publication_rel]; + Datum values[Natts_pg_publication_rel] = {0}; + bool nulls[Natts_pg_publication_rel] = {false}; Relation targetrel = pri->relation; Oid relid = RelationGetRelid(targetrel); Oid pubreloid; @@ -477,28 +477,26 @@ publication_add_relation(Oid pubid, PublicationRelInfo *pri, pubreloid = GetNewOidWithIndex(rel, PublicationRelObjectIndexId, Anum_pg_publication_rel_oid); - values[Anum_pg_publication_rel_oid - 1] = ObjectIdGetDatum(pubreloid); - values[Anum_pg_publication_rel_prpubid - 1] = - ObjectIdGetDatum(pubid); - values[Anum_pg_publication_rel_prrelid - 1] = - ObjectIdGetDatum(relid); + HeapTupleSetValue(pg_publication_rel, oid, ObjectIdGetDatum(pubreloid), values); + HeapTupleSetValue(pg_publication_rel, prpubid, ObjectIdGetDatum(pubid), values); + HeapTupleSetValue(pg_publication_rel, prrelid, ObjectIdGetDatum(relid), values); /* Add qualifications, if available */ if (pri->whereClause != NULL) - values[Anum_pg_publication_rel_prqual - 1] = CStringGetTextDatum(nodeToString(pri->whereClause)); + HeapTupleSetValue(pg_publication_rel, prqual, CStringGetTextDatum(nodeToString(pri->whereClause)), values); else - nulls[Anum_pg_publication_rel_prqual - 1] = true; + HeapTupleSetValueNull(pg_publication_rel, prqual, values, nulls); /* Add column list, if available */ if (pri->columns) - values[Anum_pg_publication_rel_prattrs - 1] = PointerGetDatum(attnumstoint2vector(attnums)); + HeapTupleSetValue(pg_publication_rel, prattrs, PointerGetDatum(attnumstoint2vector(attnums)), values); else - nulls[Anum_pg_publication_rel_prattrs - 1] = true; + HeapTupleSetValueNull(pg_publication_rel, prattrs, values, nulls); tup = heap_form_tuple(RelationGetDescr(rel), values, nulls); /* Insert tuple into catalog. */ - CatalogTupleInsert(rel, tup); + CatalogTupleInsert(rel, tup, NULL); heap_freetuple(tup); /* Register dependencies as needed */ @@ -674,8 +672,8 @@ publication_add_schema(Oid pubid, Oid schemaid, bool if_not_exists) { Relation rel; HeapTuple tup; - Datum values[Natts_pg_publication_namespace]; - bool nulls[Natts_pg_publication_namespace]; + Datum values[Natts_pg_publication_namespace] = {0}; + bool nulls[Natts_pg_publication_namespace] = {false}; Oid psschid; Publication *pub = GetPublication(pubid); List *schemaRels = NIL; @@ -712,16 +710,14 @@ publication_add_schema(Oid pubid, Oid schemaid, bool if_not_exists) psschid = GetNewOidWithIndex(rel, PublicationNamespaceObjectIndexId, Anum_pg_publication_namespace_oid); - values[Anum_pg_publication_namespace_oid - 1] = ObjectIdGetDatum(psschid); - values[Anum_pg_publication_namespace_pnpubid - 1] = - ObjectIdGetDatum(pubid); - values[Anum_pg_publication_namespace_pnnspid - 1] = - ObjectIdGetDatum(schemaid); + HeapTupleSetValue(pg_publication_namespace, oid, ObjectIdGetDatum(psschid), values); + HeapTupleSetValue(pg_publication_namespace, pnpubid, ObjectIdGetDatum(pubid), values); + HeapTupleSetValue(pg_publication_namespace, pnnspid, ObjectIdGetDatum(schemaid), values); tup = heap_form_tuple(RelationGetDescr(rel), values, nulls); /* Insert tuple into catalog */ - CatalogTupleInsert(rel, tup); + CatalogTupleInsert(rel, tup, NULL); heap_freetuple(tup); ObjectAddressSet(myself, PublicationNamespaceRelationId, psschid); diff --git a/src/backend/catalog/pg_range.c b/src/backend/catalog/pg_range.c index 8df73e7ab71b4..4e4d2d37d107c 100644 --- a/src/backend/catalog/pg_range.c +++ b/src/backend/catalog/pg_range.c @@ -38,8 +38,8 @@ RangeCreate(Oid rangeTypeOid, Oid rangeSubType, Oid rangeCollation, RegProcedure rangeSubDiff, Oid multirangeTypeOid) { Relation pg_range; - Datum values[Natts_pg_range]; - bool nulls[Natts_pg_range]; + Datum values[Natts_pg_range] = {0}; + bool nulls[Natts_pg_range] = {false}; HeapTuple tup; ObjectAddress myself; ObjectAddress referenced; @@ -50,17 +50,17 @@ RangeCreate(Oid rangeTypeOid, Oid rangeSubType, Oid rangeCollation, memset(nulls, 0, sizeof(nulls)); - values[Anum_pg_range_rngtypid - 1] = ObjectIdGetDatum(rangeTypeOid); - values[Anum_pg_range_rngsubtype - 1] = ObjectIdGetDatum(rangeSubType); - values[Anum_pg_range_rngcollation - 1] = ObjectIdGetDatum(rangeCollation); - values[Anum_pg_range_rngsubopc - 1] = ObjectIdGetDatum(rangeSubOpclass); - values[Anum_pg_range_rngcanonical - 1] = ObjectIdGetDatum(rangeCanonical); - values[Anum_pg_range_rngsubdiff - 1] = ObjectIdGetDatum(rangeSubDiff); - values[Anum_pg_range_rngmultitypid - 1] = ObjectIdGetDatum(multirangeTypeOid); + HeapTupleSetValue(pg_range, rngtypid, ObjectIdGetDatum(rangeTypeOid), values); + HeapTupleSetValue(pg_range, rngsubtype, ObjectIdGetDatum(rangeSubType), values); + HeapTupleSetValue(pg_range, rngcollation, ObjectIdGetDatum(rangeCollation), values); + HeapTupleSetValue(pg_range, rngsubopc, ObjectIdGetDatum(rangeSubOpclass), values); + HeapTupleSetValue(pg_range, rngcanonical, ObjectIdGetDatum(rangeCanonical), values); + HeapTupleSetValue(pg_range, rngsubdiff, ObjectIdGetDatum(rangeSubDiff), values); + HeapTupleSetValue(pg_range, rngmultitypid, ObjectIdGetDatum(multirangeTypeOid), values); tup = heap_form_tuple(RelationGetDescr(pg_range), values, nulls); - CatalogTupleInsert(pg_range, tup); + CatalogTupleInsert(pg_range, tup, NULL); heap_freetuple(tup); /* record type's dependencies on range-related items */ diff --git a/src/backend/catalog/pg_shdepend.c b/src/backend/catalog/pg_shdepend.c index 16e3e5c7457db..750f0d69e5757 100644 --- a/src/backend/catalog/pg_shdepend.c +++ b/src/backend/catalog/pg_shdepend.c @@ -273,31 +273,31 @@ shdepChangeDep(Relation sdepRel, shForm->refclassid = refclassid; shForm->refobjid = refobjid; - CatalogTupleUpdate(sdepRel, &oldtup->t_self, oldtup); + CatalogTupleUpdate(sdepRel, &oldtup->t_self, oldtup, NULL, NULL); } else { /* Need to insert new entry */ - Datum values[Natts_pg_shdepend]; - bool nulls[Natts_pg_shdepend]; + Datum values[Natts_pg_shdepend] = {0}; + bool nulls[Natts_pg_shdepend] = {false}; memset(nulls, false, sizeof(nulls)); - values[Anum_pg_shdepend_dbid - 1] = ObjectIdGetDatum(dbid); - values[Anum_pg_shdepend_classid - 1] = ObjectIdGetDatum(classid); - values[Anum_pg_shdepend_objid - 1] = ObjectIdGetDatum(objid); - values[Anum_pg_shdepend_objsubid - 1] = Int32GetDatum(objsubid); + HeapTupleSetValue(pg_shdepend, dbid, ObjectIdGetDatum(dbid), values); + HeapTupleSetValue(pg_shdepend, classid, ObjectIdGetDatum(classid), values); + HeapTupleSetValue(pg_shdepend, objid, ObjectIdGetDatum(objid), values); + HeapTupleSetValue(pg_shdepend, objsubid, Int32GetDatum(objsubid), values); - values[Anum_pg_shdepend_refclassid - 1] = ObjectIdGetDatum(refclassid); - values[Anum_pg_shdepend_refobjid - 1] = ObjectIdGetDatum(refobjid); - values[Anum_pg_shdepend_deptype - 1] = CharGetDatum(deptype); + HeapTupleSetValue(pg_shdepend, refclassid, ObjectIdGetDatum(refclassid), values); + HeapTupleSetValue(pg_shdepend, refobjid, ObjectIdGetDatum(refobjid), values); + HeapTupleSetValue(pg_shdepend, deptype, CharGetDatum(deptype), values); /* * we are reusing oldtup just to avoid declaring a new variable, but * it's certainly a new tuple */ oldtup = heap_form_tuple(RelationGetDescr(sdepRel), values, nulls); - CatalogTupleInsert(sdepRel, oldtup); + CatalogTupleInsert(sdepRel, oldtup, NULL); } if (oldtup) @@ -955,13 +955,13 @@ copyTemplateDependencies(Oid templateDbId, Oid newDbId) shdep = (Form_pg_shdepend) GETSTRUCT(tup); - slot[slot_stored_count]->tts_values[Anum_pg_shdepend_dbid - 1] = ObjectIdGetDatum(newDbId); - slot[slot_stored_count]->tts_values[Anum_pg_shdepend_classid - 1] = ObjectIdGetDatum(shdep->classid); - slot[slot_stored_count]->tts_values[Anum_pg_shdepend_objid - 1] = ObjectIdGetDatum(shdep->objid); - slot[slot_stored_count]->tts_values[Anum_pg_shdepend_objsubid - 1] = Int32GetDatum(shdep->objsubid); - slot[slot_stored_count]->tts_values[Anum_pg_shdepend_refclassid - 1] = ObjectIdGetDatum(shdep->refclassid); - slot[slot_stored_count]->tts_values[Anum_pg_shdepend_refobjid - 1] = ObjectIdGetDatum(shdep->refobjid); - slot[slot_stored_count]->tts_values[Anum_pg_shdepend_deptype - 1] = CharGetDatum(shdep->deptype); + HeapTupleSetValue(pg_shdepend, dbid, ObjectIdGetDatum(newDbId), slot[slot_stored_count]->tts_values); + HeapTupleSetValue(pg_shdepend, classid, ObjectIdGetDatum(shdep->classid), slot[slot_stored_count]->tts_values); + HeapTupleSetValue(pg_shdepend, objid, ObjectIdGetDatum(shdep->objid), slot[slot_stored_count]->tts_values); + HeapTupleSetValue(pg_shdepend, objsubid, Int32GetDatum(shdep->objsubid), slot[slot_stored_count]->tts_values); + HeapTupleSetValue(pg_shdepend, refclassid, ObjectIdGetDatum(shdep->refclassid), slot[slot_stored_count]->tts_values); + HeapTupleSetValue(pg_shdepend, refobjid, ObjectIdGetDatum(shdep->refobjid), slot[slot_stored_count]->tts_values); + HeapTupleSetValue(pg_shdepend, deptype, CharGetDatum(shdep->deptype), slot[slot_stored_count]->tts_values); ExecStoreVirtualTuple(slot[slot_stored_count]); slot_stored_count++; @@ -969,14 +969,14 @@ copyTemplateDependencies(Oid templateDbId, Oid newDbId) /* If slots are full, insert a batch of tuples */ if (slot_stored_count == max_slots) { - CatalogTuplesMultiInsertWithInfo(sdepRel, slot, slot_stored_count, indstate); + CatalogTuplesMultiInsert(sdepRel, slot, slot_stored_count, indstate); slot_stored_count = 0; } } /* Insert any tuples left in the buffer */ if (slot_stored_count > 0) - CatalogTuplesMultiInsertWithInfo(sdepRel, slot, slot_stored_count, indstate); + CatalogTuplesMultiInsert(sdepRel, slot, slot_stored_count, indstate); systable_endscan(scan); @@ -1072,8 +1072,8 @@ shdepAddDependency(Relation sdepRel, SharedDependencyType deptype) { HeapTuple tup; - Datum values[Natts_pg_shdepend]; - bool nulls[Natts_pg_shdepend]; + Datum values[Natts_pg_shdepend] = {0}; + bool nulls[Natts_pg_shdepend] = {false}; /* * Make sure the object doesn't go away while we record the dependency on @@ -1087,18 +1087,18 @@ shdepAddDependency(Relation sdepRel, /* * Form the new tuple and record the dependency. */ - values[Anum_pg_shdepend_dbid - 1] = ObjectIdGetDatum(classIdGetDbId(classId)); - values[Anum_pg_shdepend_classid - 1] = ObjectIdGetDatum(classId); - values[Anum_pg_shdepend_objid - 1] = ObjectIdGetDatum(objectId); - values[Anum_pg_shdepend_objsubid - 1] = Int32GetDatum(objsubId); + HeapTupleSetValue(pg_shdepend, dbid, ObjectIdGetDatum(classIdGetDbId(classId)), values); + HeapTupleSetValue(pg_shdepend, classid, ObjectIdGetDatum(classId), values); + HeapTupleSetValue(pg_shdepend, objid, ObjectIdGetDatum(objectId), values); + HeapTupleSetValue(pg_shdepend, objsubid, Int32GetDatum(objsubId), values); - values[Anum_pg_shdepend_refclassid - 1] = ObjectIdGetDatum(refclassId); - values[Anum_pg_shdepend_refobjid - 1] = ObjectIdGetDatum(refobjId); - values[Anum_pg_shdepend_deptype - 1] = CharGetDatum(deptype); + HeapTupleSetValue(pg_shdepend, refclassid, ObjectIdGetDatum(refclassId), values); + HeapTupleSetValue(pg_shdepend, refobjid, ObjectIdGetDatum(refobjId), values); + HeapTupleSetValue(pg_shdepend, deptype, CharGetDatum(deptype), values); tup = heap_form_tuple(sdepRel->rd_att, values, nulls); - CatalogTupleInsert(sdepRel, tup); + CatalogTupleInsert(sdepRel, tup, NULL); /* clean up */ heap_freetuple(tup); diff --git a/src/backend/catalog/pg_subscription.c b/src/backend/catalog/pg_subscription.c index 180e77e94845b..59765a8cea069 100644 --- a/src/backend/catalog/pg_subscription.c +++ b/src/backend/catalog/pg_subscription.c @@ -203,9 +203,9 @@ void DisableSubscription(Oid subid) { Relation rel; - bool nulls[Natts_pg_subscription]; - bool replaces[Natts_pg_subscription]; - Datum values[Natts_pg_subscription]; + Datum values[Natts_pg_subscription] = {0}; + bool nulls[Natts_pg_subscription] = {false}; + Bitmapset *updated = NULL; HeapTuple tup; /* Look up the subscription in the catalog */ @@ -217,19 +217,13 @@ DisableSubscription(Oid subid) LockSharedObject(SubscriptionRelationId, subid, 0, AccessShareLock); - /* Form a new tuple. */ - memset(values, 0, sizeof(values)); - memset(nulls, false, sizeof(nulls)); - memset(replaces, false, sizeof(replaces)); - /* Set the subscription to disabled. */ - values[Anum_pg_subscription_subenabled - 1] = BoolGetDatum(false); - replaces[Anum_pg_subscription_subenabled - 1] = true; + HeapTupleUpdateValue(pg_subscription, subenabled, BoolGetDatum(false), values, nulls, updated); /* Update the catalog */ - tup = heap_modify_tuple(tup, RelationGetDescr(rel), values, nulls, - replaces); - CatalogTupleUpdate(rel, &tup->t_self, tup); + tup = heap_update_tuple(tup, RelationGetDescr(rel), values, nulls, updated); + CatalogTupleUpdate(rel, &tup->t_self, tup, updated, NULL); + bms_free(updated); heap_freetuple(tup); table_close(rel, NoLock); @@ -272,8 +266,8 @@ AddSubscriptionRelState(Oid subid, Oid relid, char state, { Relation rel; HeapTuple tup; - bool nulls[Natts_pg_subscription_rel]; - Datum values[Natts_pg_subscription_rel]; + Datum values[Natts_pg_subscription_rel] = {0}; + bool nulls[Natts_pg_subscription_rel] = {false}; LockSharedObject(SubscriptionRelationId, subid, 0, AccessShareLock); @@ -288,20 +282,18 @@ AddSubscriptionRelState(Oid subid, Oid relid, char state, relid, subid); /* Form the tuple. */ - memset(values, 0, sizeof(values)); - memset(nulls, false, sizeof(nulls)); - values[Anum_pg_subscription_rel_srsubid - 1] = ObjectIdGetDatum(subid); - values[Anum_pg_subscription_rel_srrelid - 1] = ObjectIdGetDatum(relid); - values[Anum_pg_subscription_rel_srsubstate - 1] = CharGetDatum(state); + HeapTupleSetValue(pg_subscription_rel, srsubid, ObjectIdGetDatum(subid), values); + HeapTupleSetValue(pg_subscription_rel, srrelid, ObjectIdGetDatum(relid), values); + HeapTupleSetValue(pg_subscription_rel, srsubstate, CharGetDatum(state), values); if (XLogRecPtrIsValid(sublsn)) - values[Anum_pg_subscription_rel_srsublsn - 1] = LSNGetDatum(sublsn); + HeapTupleSetValue(pg_subscription_rel, srsublsn, LSNGetDatum(sublsn), values); else - nulls[Anum_pg_subscription_rel_srsublsn - 1] = true; + HeapTupleSetValueNull(pg_subscription_rel, srsublsn, values, nulls); tup = heap_form_tuple(RelationGetDescr(rel), values, nulls); /* Insert tuple into catalog. */ - CatalogTupleInsert(rel, tup); + CatalogTupleInsert(rel, tup, NULL); heap_freetuple(tup); @@ -326,9 +318,9 @@ UpdateSubscriptionRelState(Oid subid, Oid relid, char state, { Relation rel; HeapTuple tup; - bool nulls[Natts_pg_subscription_rel]; - Datum values[Natts_pg_subscription_rel]; - bool replaces[Natts_pg_subscription_rel]; + Datum values[Natts_pg_subscription_rel] = {0}; + bool nulls[Natts_pg_subscription_rel] = {false}; + Bitmapset *updated = NULL; if (already_locked) { @@ -358,27 +350,21 @@ UpdateSubscriptionRelState(Oid subid, Oid relid, char state, relid, subid); /* Update the tuple. */ - memset(values, 0, sizeof(values)); - memset(nulls, false, sizeof(nulls)); - memset(replaces, false, sizeof(replaces)); - - replaces[Anum_pg_subscription_rel_srsubstate - 1] = true; - values[Anum_pg_subscription_rel_srsubstate - 1] = CharGetDatum(state); + HeapTupleUpdateValue(pg_subscription_rel, srsubstate, CharGetDatum(state), values, nulls, updated); - replaces[Anum_pg_subscription_rel_srsublsn - 1] = true; if (XLogRecPtrIsValid(sublsn)) - values[Anum_pg_subscription_rel_srsublsn - 1] = LSNGetDatum(sublsn); + HeapTupleUpdateValue(pg_subscription_rel, srsublsn, LSNGetDatum(sublsn), values, nulls, updated); else - nulls[Anum_pg_subscription_rel_srsublsn - 1] = true; + HeapTupleUpdateValueNull(pg_subscription_rel, srsublsn, values, nulls, updated); - tup = heap_modify_tuple(tup, RelationGetDescr(rel), values, nulls, - replaces); + tup = heap_update_tuple(tup, RelationGetDescr(rel), values, nulls, updated); /* Update the catalog. */ - CatalogTupleUpdate(rel, &tup->t_self, tup); + CatalogTupleUpdate(rel, &tup->t_self, tup, updated, NULL); /* Cleanup. */ table_close(rel, NoLock); + bms_free(updated); } /* @@ -645,9 +631,9 @@ void UpdateDeadTupleRetentionStatus(Oid subid, bool active) { Relation rel; - bool nulls[Natts_pg_subscription]; - bool replaces[Natts_pg_subscription]; - Datum values[Natts_pg_subscription]; + Datum values[Natts_pg_subscription] = {0}; + bool nulls[Natts_pg_subscription] = {false}; + Bitmapset *updated = NULL; HeapTuple tup; /* Look up the subscription in the catalog */ @@ -659,20 +645,16 @@ UpdateDeadTupleRetentionStatus(Oid subid, bool active) LockSharedObject(SubscriptionRelationId, subid, 0, AccessShareLock); - /* Form a new tuple. */ - memset(values, 0, sizeof(values)); - memset(nulls, false, sizeof(nulls)); - memset(replaces, false, sizeof(replaces)); - /* Set the subscription to disabled. */ - values[Anum_pg_subscription_subretentionactive - 1] = active; - replaces[Anum_pg_subscription_subretentionactive - 1] = true; + HeapTupleUpdateValue(pg_subscription, subretentionactive, active, values, nulls, updated); /* Update the catalog */ - tup = heap_modify_tuple(tup, RelationGetDescr(rel), values, nulls, - replaces); - CatalogTupleUpdate(rel, &tup->t_self, tup); - heap_freetuple(tup); + tup = heap_update_tuple(tup, RelationGetDescr(rel), values, nulls, updated); + CatalogTupleUpdate(rel, &tup->t_self, tup, updated, NULL); + + /* Cleanup */ + bms_free(updated); + heap_freetuple(tup); table_close(rel, NoLock); } diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c index 257c7da856832..6342f9aad07fb 100644 --- a/src/backend/catalog/pg_type.c +++ b/src/backend/catalog/pg_type.c @@ -60,8 +60,8 @@ TypeShellMake(const char *typeName, Oid typeNamespace, Oid ownerId) TupleDesc tupDesc; int i; HeapTuple tup; - Datum values[Natts_pg_type]; - bool nulls[Natts_pg_type]; + Datum values[Natts_pg_type] = {0}; + bool nulls[Natts_pg_type] = {false}; Oid typoid; NameData name; ObjectAddress address; @@ -92,37 +92,37 @@ TypeShellMake(const char *typeName, Oid typeNamespace, Oid ownerId) * mistaken for a usable type. */ namestrcpy(&name, typeName); - values[Anum_pg_type_typname - 1] = NameGetDatum(&name); - values[Anum_pg_type_typnamespace - 1] = ObjectIdGetDatum(typeNamespace); - values[Anum_pg_type_typowner - 1] = ObjectIdGetDatum(ownerId); - values[Anum_pg_type_typlen - 1] = Int16GetDatum(sizeof(int32)); - values[Anum_pg_type_typbyval - 1] = BoolGetDatum(true); - values[Anum_pg_type_typtype - 1] = CharGetDatum(TYPTYPE_PSEUDO); - values[Anum_pg_type_typcategory - 1] = CharGetDatum(TYPCATEGORY_PSEUDOTYPE); - values[Anum_pg_type_typispreferred - 1] = BoolGetDatum(false); - values[Anum_pg_type_typisdefined - 1] = BoolGetDatum(false); - values[Anum_pg_type_typdelim - 1] = CharGetDatum(DEFAULT_TYPDELIM); - values[Anum_pg_type_typrelid - 1] = ObjectIdGetDatum(InvalidOid); - values[Anum_pg_type_typsubscript - 1] = ObjectIdGetDatum(InvalidOid); - values[Anum_pg_type_typelem - 1] = ObjectIdGetDatum(InvalidOid); - values[Anum_pg_type_typarray - 1] = ObjectIdGetDatum(InvalidOid); - values[Anum_pg_type_typinput - 1] = ObjectIdGetDatum(F_SHELL_IN); - values[Anum_pg_type_typoutput - 1] = ObjectIdGetDatum(F_SHELL_OUT); - values[Anum_pg_type_typreceive - 1] = ObjectIdGetDatum(InvalidOid); - values[Anum_pg_type_typsend - 1] = ObjectIdGetDatum(InvalidOid); - values[Anum_pg_type_typmodin - 1] = ObjectIdGetDatum(InvalidOid); - values[Anum_pg_type_typmodout - 1] = ObjectIdGetDatum(InvalidOid); - values[Anum_pg_type_typanalyze - 1] = ObjectIdGetDatum(InvalidOid); - values[Anum_pg_type_typalign - 1] = CharGetDatum(TYPALIGN_INT); - values[Anum_pg_type_typstorage - 1] = CharGetDatum(TYPSTORAGE_PLAIN); - values[Anum_pg_type_typnotnull - 1] = BoolGetDatum(false); - values[Anum_pg_type_typbasetype - 1] = ObjectIdGetDatum(InvalidOid); - values[Anum_pg_type_typtypmod - 1] = Int32GetDatum(-1); - values[Anum_pg_type_typndims - 1] = Int32GetDatum(0); - values[Anum_pg_type_typcollation - 1] = ObjectIdGetDatum(InvalidOid); - nulls[Anum_pg_type_typdefaultbin - 1] = true; - nulls[Anum_pg_type_typdefault - 1] = true; - nulls[Anum_pg_type_typacl - 1] = true; + HeapTupleSetValue(pg_type, typname, NameGetDatum(&name), values); + HeapTupleSetValue(pg_type, typnamespace, ObjectIdGetDatum(typeNamespace), values); + HeapTupleSetValue(pg_type, typowner, ObjectIdGetDatum(ownerId), values); + HeapTupleSetValue(pg_type, typlen, Int16GetDatum(sizeof(int32)), values); + HeapTupleSetValue(pg_type, typbyval, BoolGetDatum(true), values); + HeapTupleSetValue(pg_type, typtype, CharGetDatum(TYPTYPE_PSEUDO), values); + HeapTupleSetValue(pg_type, typcategory, CharGetDatum(TYPCATEGORY_PSEUDOTYPE), values); + HeapTupleSetValue(pg_type, typispreferred, BoolGetDatum(false), values); + HeapTupleSetValue(pg_type, typisdefined, BoolGetDatum(false), values); + HeapTupleSetValue(pg_type, typdelim, CharGetDatum(DEFAULT_TYPDELIM), values); + HeapTupleSetValue(pg_type, typrelid, ObjectIdGetDatum(InvalidOid), values); + HeapTupleSetValue(pg_type, typsubscript, ObjectIdGetDatum(InvalidOid), values); + HeapTupleSetValue(pg_type, typelem, ObjectIdGetDatum(InvalidOid), values); + HeapTupleSetValue(pg_type, typarray, ObjectIdGetDatum(InvalidOid), values); + HeapTupleSetValue(pg_type, typinput, ObjectIdGetDatum(F_SHELL_IN), values); + HeapTupleSetValue(pg_type, typoutput, ObjectIdGetDatum(F_SHELL_OUT), values); + HeapTupleSetValue(pg_type, typreceive, ObjectIdGetDatum(InvalidOid), values); + HeapTupleSetValue(pg_type, typsend, ObjectIdGetDatum(InvalidOid), values); + HeapTupleSetValue(pg_type, typmodin, ObjectIdGetDatum(InvalidOid), values); + HeapTupleSetValue(pg_type, typmodout, ObjectIdGetDatum(InvalidOid), values); + HeapTupleSetValue(pg_type, typanalyze, ObjectIdGetDatum(InvalidOid), values); + HeapTupleSetValue(pg_type, typalign, CharGetDatum(TYPALIGN_INT), values); + HeapTupleSetValue(pg_type, typstorage, CharGetDatum(TYPSTORAGE_PLAIN), values); + HeapTupleSetValue(pg_type, typnotnull, BoolGetDatum(false), values); + HeapTupleSetValue(pg_type, typbasetype, ObjectIdGetDatum(InvalidOid), values); + HeapTupleSetValue(pg_type, typtypmod, Int32GetDatum(-1), values); + HeapTupleSetValue(pg_type, typndims, Int32GetDatum(0), values); + HeapTupleSetValue(pg_type, typcollation, ObjectIdGetDatum(InvalidOid), values); + HeapTupleSetValueNull(pg_type, typdefaultbin, values, nulls); + HeapTupleSetValueNull(pg_type, typdefault, values, nulls); + HeapTupleSetValueNull(pg_type, typacl, values, nulls); /* Use binary-upgrade override for pg_type.oid? */ if (IsBinaryUpgrade) @@ -141,7 +141,7 @@ TypeShellMake(const char *typeName, Oid typeNamespace, Oid ownerId) Anum_pg_type_oid); } - values[Anum_pg_type_oid - 1] = ObjectIdGetDatum(typoid); + HeapTupleSetValue(pg_type, oid, ObjectIdGetDatum(typoid), values); /* * create a new type tuple @@ -151,7 +151,7 @@ TypeShellMake(const char *typeName, Oid typeNamespace, Oid ownerId) /* * insert the tuple in the relation and get the tuple's oid. */ - CatalogTupleInsert(pg_type_desc, tup); + CatalogTupleInsert(pg_type_desc, tup, NULL); /* * Create dependencies. We can/must skip this in bootstrap mode. @@ -229,13 +229,12 @@ TypeCreate(Oid newTypeOid, Oid typeObjectId; bool isDependentType; bool rebuildDeps = false; - Acl *typacl; + Acl *typacl = NULL; HeapTuple tup; - bool nulls[Natts_pg_type]; - bool replaces[Natts_pg_type]; - Datum values[Natts_pg_type]; + Datum values[Natts_pg_type] = {0}; + bool nulls[Natts_pg_type] = {false}; + Bitmapset *updated = NULL; NameData name; - int i; ObjectAddress address; /* @@ -334,78 +333,65 @@ TypeCreate(Oid newTypeOid, typeType == TYPTYPE_MULTIRANGE || (OidIsValid(relationOid) && relationKind != RELKIND_COMPOSITE_TYPE); - /* - * initialize arrays needed for heap_form_tuple or heap_modify_tuple - */ - for (i = 0; i < Natts_pg_type; ++i) - { - nulls[i] = false; - replaces[i] = true; - values[i] = (Datum) 0; - } + HeapTupleUpdateSetAllColumnsUpdated(pg_type, updated); - /* - * insert data values - */ + /* Insert data values */ namestrcpy(&name, typeName); - values[Anum_pg_type_typname - 1] = NameGetDatum(&name); - values[Anum_pg_type_typnamespace - 1] = ObjectIdGetDatum(typeNamespace); - values[Anum_pg_type_typowner - 1] = ObjectIdGetDatum(ownerId); - values[Anum_pg_type_typlen - 1] = Int16GetDatum(internalSize); - values[Anum_pg_type_typbyval - 1] = BoolGetDatum(passedByValue); - values[Anum_pg_type_typtype - 1] = CharGetDatum(typeType); - values[Anum_pg_type_typcategory - 1] = CharGetDatum(typeCategory); - values[Anum_pg_type_typispreferred - 1] = BoolGetDatum(typePreferred); - values[Anum_pg_type_typisdefined - 1] = BoolGetDatum(true); - values[Anum_pg_type_typdelim - 1] = CharGetDatum(typDelim); - values[Anum_pg_type_typrelid - 1] = ObjectIdGetDatum(relationOid); - values[Anum_pg_type_typsubscript - 1] = ObjectIdGetDatum(subscriptProcedure); - values[Anum_pg_type_typelem - 1] = ObjectIdGetDatum(elementType); - values[Anum_pg_type_typarray - 1] = ObjectIdGetDatum(arrayType); - values[Anum_pg_type_typinput - 1] = ObjectIdGetDatum(inputProcedure); - values[Anum_pg_type_typoutput - 1] = ObjectIdGetDatum(outputProcedure); - values[Anum_pg_type_typreceive - 1] = ObjectIdGetDatum(receiveProcedure); - values[Anum_pg_type_typsend - 1] = ObjectIdGetDatum(sendProcedure); - values[Anum_pg_type_typmodin - 1] = ObjectIdGetDatum(typmodinProcedure); - values[Anum_pg_type_typmodout - 1] = ObjectIdGetDatum(typmodoutProcedure); - values[Anum_pg_type_typanalyze - 1] = ObjectIdGetDatum(analyzeProcedure); - values[Anum_pg_type_typalign - 1] = CharGetDatum(alignment); - values[Anum_pg_type_typstorage - 1] = CharGetDatum(storage); - values[Anum_pg_type_typnotnull - 1] = BoolGetDatum(typeNotNull); - values[Anum_pg_type_typbasetype - 1] = ObjectIdGetDatum(baseType); - values[Anum_pg_type_typtypmod - 1] = Int32GetDatum(typeMod); - values[Anum_pg_type_typndims - 1] = Int32GetDatum(typNDims); - values[Anum_pg_type_typcollation - 1] = ObjectIdGetDatum(typeCollation); + HeapTupleUpdateValue(pg_type, typname, NameGetDatum(&name), values, nulls, updated); + HeapTupleUpdateValue(pg_type, typnamespace, ObjectIdGetDatum(typeNamespace), values, nulls, updated); + HeapTupleUpdateValue(pg_type, typowner, ObjectIdGetDatum(ownerId), values, nulls, updated); + HeapTupleUpdateValue(pg_type, typlen, Int16GetDatum(internalSize), values, nulls, updated); + HeapTupleUpdateValue(pg_type, typbyval, BoolGetDatum(passedByValue), values, nulls, updated); + HeapTupleUpdateValue(pg_type, typtype, CharGetDatum(typeType), values, nulls, updated); + HeapTupleUpdateValue(pg_type, typcategory, CharGetDatum(typeCategory), values, nulls, updated); + HeapTupleUpdateValue(pg_type, typispreferred, BoolGetDatum(typePreferred), values, nulls, updated); + HeapTupleUpdateValue(pg_type, typisdefined, BoolGetDatum(true), values, nulls, updated); + HeapTupleUpdateValue(pg_type, typdelim, CharGetDatum(typDelim), values, nulls, updated); + HeapTupleUpdateValue(pg_type, typrelid, ObjectIdGetDatum(relationOid), values, nulls, updated); + HeapTupleUpdateValue(pg_type, typsubscript, ObjectIdGetDatum(subscriptProcedure), values, nulls, updated); + HeapTupleUpdateValue(pg_type, typelem, ObjectIdGetDatum(elementType), values, nulls, updated); + HeapTupleUpdateValue(pg_type, typarray, ObjectIdGetDatum(arrayType), values, nulls, updated); + HeapTupleUpdateValue(pg_type, typinput, ObjectIdGetDatum(inputProcedure), values, nulls, updated); + HeapTupleUpdateValue(pg_type, typoutput, ObjectIdGetDatum(outputProcedure), values, nulls, updated); + HeapTupleUpdateValue(pg_type, typreceive, ObjectIdGetDatum(receiveProcedure), values, nulls, updated); + HeapTupleUpdateValue(pg_type, typsend, ObjectIdGetDatum(sendProcedure), values, nulls, updated); + HeapTupleUpdateValue(pg_type, typmodin, ObjectIdGetDatum(typmodinProcedure), values, nulls, updated); + HeapTupleUpdateValue(pg_type, typmodout, ObjectIdGetDatum(typmodoutProcedure), values, nulls, updated); + HeapTupleUpdateValue(pg_type, typanalyze, ObjectIdGetDatum(analyzeProcedure), values, nulls, updated); + HeapTupleUpdateValue(pg_type, typalign, CharGetDatum(alignment), values, nulls, updated); + HeapTupleUpdateValue(pg_type, typstorage, CharGetDatum(storage), values, nulls, updated); + HeapTupleUpdateValue(pg_type, typnotnull, BoolGetDatum(typeNotNull), values, nulls, updated); + HeapTupleUpdateValue(pg_type, typbasetype, ObjectIdGetDatum(baseType), values, nulls, updated); + HeapTupleUpdateValue(pg_type, typtypmod, Int32GetDatum(typeMod), values, nulls, updated); + HeapTupleUpdateValue(pg_type, typndims, Int32GetDatum(typNDims), values, nulls, updated); + HeapTupleUpdateValue(pg_type, typcollation, ObjectIdGetDatum(typeCollation), values, nulls, updated); /* - * initialize the default binary value for this type. Check for nulls of - * course. + * Initialize the default binary value for this type. */ if (defaultTypeBin) - values[Anum_pg_type_typdefaultbin - 1] = CStringGetTextDatum(defaultTypeBin); + HeapTupleUpdateValue(pg_type, typdefaultbin, CStringGetTextDatum(defaultTypeBin), values, nulls, updated); else - nulls[Anum_pg_type_typdefaultbin - 1] = true; + HeapTupleUpdateValueNull(pg_type, typdefaultbin, values, nulls, updated); /* - * initialize the default value for this type. + * Initialize the default value for this type. */ if (defaultTypeValue) - values[Anum_pg_type_typdefault - 1] = CStringGetTextDatum(defaultTypeValue); + HeapTupleUpdateValue(pg_type, typdefault, CStringGetTextDatum(defaultTypeValue), values, nulls, updated); else - nulls[Anum_pg_type_typdefault - 1] = true; + HeapTupleUpdateValueNull(pg_type, typdefault, values, nulls, updated); /* - * Initialize the type's ACL, too. But dependent types don't get one. + * Initialize the type's ACL too, but dependent types don't get one. */ - if (isDependentType) - typacl = NULL; - else - typacl = get_user_default_acl(OBJECT_TYPE, ownerId, - typeNamespace); + if (!isDependentType) + typacl = get_user_default_acl(OBJECT_TYPE, ownerId, typeNamespace); + if (typacl != NULL) - values[Anum_pg_type_typacl - 1] = PointerGetDatum(typacl); + HeapTupleUpdateValue(pg_type, typacl, PointerGetDatum(typacl), values, nulls, updated); else - nulls[Anum_pg_type_typacl - 1] = true; + HeapTupleUpdateValueNull(pg_type, typacl, values, nulls, updated); /* * open pg_type and prepare to insert or update a row. @@ -431,9 +417,7 @@ TypeCreate(Oid newTypeOid, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("type \"%s\" already exists", typeName))); - /* - * shell type must have been created by same owner - */ + /* Shell type must have been created by same owner */ if (typform->typowner != ownerId) aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_TYPE, typeName); @@ -441,18 +425,16 @@ TypeCreate(Oid newTypeOid, if (OidIsValid(newTypeOid)) elog(ERROR, "cannot assign new OID to existing shell type"); - replaces[Anum_pg_type_oid - 1] = false; + HeapTupleSetColumnNotUpdated(pg_type, oid, updated); - /* - * Okay to update existing shell type tuple - */ - tup = heap_modify_tuple(tup, + /* Okay to update existing shell type tuple */ + tup = heap_update_tuple(tup, RelationGetDescr(pg_type_desc), values, nulls, - replaces); + updated); - CatalogTupleUpdate(pg_type_desc, &tup->t_self, tup); + CatalogTupleUpdate(pg_type_desc, &tup->t_self, tup, updated, NULL); typeObjectId = typform->oid; @@ -480,12 +462,11 @@ TypeCreate(Oid newTypeOid, Anum_pg_type_oid); } - values[Anum_pg_type_oid - 1] = ObjectIdGetDatum(typeObjectId); + HeapTupleUpdateValue(pg_type, oid, ObjectIdGetDatum(typeObjectId), values, nulls, updated); - tup = heap_form_tuple(RelationGetDescr(pg_type_desc), - values, nulls); + tup = heap_form_tuple(RelationGetDescr(pg_type_desc), values, nulls); - CatalogTupleInsert(pg_type_desc, tup); + CatalogTupleInsert(pg_type_desc, tup, NULL); } /* @@ -509,9 +490,8 @@ TypeCreate(Oid newTypeOid, ObjectAddressSet(address, TypeRelationId, typeObjectId); - /* - * finish up - */ + /* Clean up */ + bms_free(updated); table_close(pg_type_desc, RowExclusiveLock); return address; @@ -765,6 +745,7 @@ RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace) Relation pg_type_desc; HeapTuple tuple; Form_pg_type typ; + Bitmapset *updated = NULL; Oid arrayOid; Oid oldTypeOid; @@ -804,12 +785,14 @@ RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace) } /* OK, do the rename --- tuple is a copy, so OK to scribble on it */ - namestrcpy(&(typ->typname), newTypeName); + namestrcpy(&typ->typname, newTypeName); + HeapTupleMarkColumnUpdated(pg_type, typname, updated); - CatalogTupleUpdate(pg_type_desc, &tuple->t_self, tuple); + CatalogTupleUpdate(pg_type_desc, &tuple->t_self, tuple, updated, NULL); InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0); + bms_free(updated); heap_freetuple(tuple); table_close(pg_type_desc, RowExclusiveLock); diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c index 874a8fc89adb3..368f8e63b0b1e 100644 --- a/src/backend/catalog/toasting.c +++ b/src/backend/catalog/toasting.c @@ -336,14 +336,17 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, if (!IsBootstrapProcessingMode()) { + Bitmapset *updated = NULL; + /* normal case, use a transactional update */ reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relOid)); if (!HeapTupleIsValid(reltup)) elog(ERROR, "cache lookup failed for relation %u", relOid); - ((Form_pg_class) GETSTRUCT(reltup))->reltoastrelid = toast_relid; + HeapTupleUpdateField(pg_class, reltoastrelid, toast_relid, (Form_pg_class) GETSTRUCT(reltup), updated); + CatalogTupleUpdate(class_rel, &reltup->t_self, reltup, updated, NULL); - CatalogTupleUpdate(class_rel, &reltup->t_self, reltup); + bms_free(updated); } else { diff --git a/src/backend/commands/amcmds.c b/src/backend/commands/amcmds.c index 58ed9d216cc01..2dca9051fa693 100644 --- a/src/backend/commands/amcmds.c +++ b/src/backend/commands/amcmds.c @@ -47,8 +47,8 @@ CreateAccessMethod(CreateAmStmt *stmt) ObjectAddress referenced; Oid amoid; Oid amhandler; - bool nulls[Natts_pg_am]; - Datum values[Natts_pg_am]; + Datum values[Natts_pg_am] = {0}; + bool nulls[Natts_pg_am] = {false}; HeapTuple tup; rel = table_open(AccessMethodRelationId, RowExclusiveLock); @@ -84,15 +84,14 @@ CreateAccessMethod(CreateAmStmt *stmt) memset(nulls, false, sizeof(nulls)); amoid = GetNewOidWithIndex(rel, AmOidIndexId, Anum_pg_am_oid); - values[Anum_pg_am_oid - 1] = ObjectIdGetDatum(amoid); - values[Anum_pg_am_amname - 1] = - DirectFunctionCall1(namein, CStringGetDatum(stmt->amname)); - values[Anum_pg_am_amhandler - 1] = ObjectIdGetDatum(amhandler); - values[Anum_pg_am_amtype - 1] = CharGetDatum(stmt->amtype); + HeapTupleSetValue(pg_am, oid, ObjectIdGetDatum(amoid), values); + HeapTupleSetValue(pg_am, amname, DirectFunctionCall1(namein, CStringGetDatum(stmt->amname)), values); + HeapTupleSetValue(pg_am, amhandler, ObjectIdGetDatum(amhandler), values); + HeapTupleSetValue(pg_am, amtype, CharGetDatum(stmt->amtype), values); tup = heap_form_tuple(RelationGetDescr(rel), values, nulls); - CatalogTupleInsert(rel, tup); + CatalogTupleInsert(rel, tup, NULL); heap_freetuple(tup); myself.classId = AccessMethodRelationId; diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c index b55221d44cd00..b596821e348f2 100644 --- a/src/backend/commands/cluster.c +++ b/src/backend/commands/cluster.c @@ -557,6 +557,7 @@ mark_index_clustered(Relation rel, Oid indexOid, bool is_internal) Form_pg_index indexForm; Relation pg_index; ListCell *index; + Bitmapset *updated = NULL; /* Disallow applying to a partitioned table */ if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) @@ -594,16 +595,16 @@ mark_index_clustered(Relation rel, Oid indexOid, bool is_internal) */ if (indexForm->indisclustered) { - indexForm->indisclustered = false; - CatalogTupleUpdate(pg_index, &indexTuple->t_self, indexTuple); + HeapTupleUpdateField(pg_index, indisclustered, false, indexForm, updated); + CatalogTupleUpdate(pg_index, &indexTuple->t_self, indexTuple, updated, NULL); } else if (thisIndexOid == indexOid) { /* this was checked earlier, but let's be real sure */ if (!indexForm->indisvalid) elog(ERROR, "cannot cluster on invalid index %u", indexOid); - indexForm->indisclustered = true; - CatalogTupleUpdate(pg_index, &indexTuple->t_self, indexTuple); + HeapTupleUpdateField(pg_index, indisclustered, true, indexForm, updated); + CatalogTupleUpdate(pg_index, &indexTuple->t_self, indexTuple, updated, NULL); } InvokeObjectPostAlterHookArg(IndexRelationId, thisIndexOid, 0, @@ -613,6 +614,7 @@ mark_index_clustered(Relation rel, Oid indexOid, bool is_internal) } table_close(pg_index, RowExclusiveLock); + bms_free(updated); } /* @@ -847,6 +849,7 @@ copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldIndex, bool verb int elevel = verbose ? INFO : DEBUG2; PGRUsage ru0; char *nspname; + Bitmapset *updated = NULL; pg_rusage_init(&ru0); @@ -1016,18 +1019,19 @@ copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldIndex, bool verb RelationGetRelid(NewHeap)); relform = (Form_pg_class) GETSTRUCT(reltup); - relform->relpages = num_pages; - relform->reltuples = num_tuples; + HeapTupleUpdateField(pg_class, relpages, num_pages, relform, updated); + HeapTupleUpdateField(pg_class, reltuples, num_tuples, relform, updated); /* Don't update the stats for pg_class. See swap_relation_files. */ if (RelationGetRelid(OldHeap) != RelationRelationId) - CatalogTupleUpdate(relRelation, &reltup->t_self, reltup); + CatalogTupleUpdate(relRelation, &reltup->t_self, reltup, updated, NULL); else CacheInvalidateRelcacheByTuple(reltup); /* Clean up. */ heap_freetuple(reltup); table_close(relRelation, RowExclusiveLock); + bms_free(updated); /* Make the update visible */ CommandCounterIncrement(); @@ -1078,6 +1082,8 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class, char swptmpchr; Oid relam1, relam2; + Bitmapset *updated1 = NULL; + Bitmapset *updated2 = NULL; /* We need writable copies of both pg_class tuples. */ relRelation = table_open(RelationRelationId, RowExclusiveLock); @@ -1107,27 +1113,27 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class, Assert(!target_is_pg_class); swaptemp = relform1->relfilenode; - relform1->relfilenode = relform2->relfilenode; - relform2->relfilenode = swaptemp; + HeapTupleUpdateField(pg_class, relfilenode, relform2->relfilenode, relform1, updated1); + HeapTupleUpdateField(pg_class, relfilenode, swaptemp, relform2, updated2); swaptemp = relform1->reltablespace; - relform1->reltablespace = relform2->reltablespace; - relform2->reltablespace = swaptemp; + HeapTupleUpdateField(pg_class, reltablespace, relform2->reltablespace, relform1, updated1); + HeapTupleUpdateField(pg_class, reltablespace, swaptemp, relform2, updated2); swaptemp = relform1->relam; - relform1->relam = relform2->relam; - relform2->relam = swaptemp; + HeapTupleUpdateField(pg_class, relam, relform2->relam, relform1, updated1); + HeapTupleUpdateField(pg_class, relam, swaptemp, relform2, updated2); swptmpchr = relform1->relpersistence; - relform1->relpersistence = relform2->relpersistence; - relform2->relpersistence = swptmpchr; + HeapTupleUpdateField(pg_class, relpersistence, relform2->relpersistence, relform1, updated1); + HeapTupleUpdateField(pg_class, relpersistence, swptmpchr, relform2, updated2); /* Also swap toast links, if we're swapping by links */ if (!swap_toast_by_content) { swaptemp = relform1->reltoastrelid; - relform1->reltoastrelid = relform2->reltoastrelid; - relform2->reltoastrelid = swaptemp; + HeapTupleUpdateField(pg_class, reltoastrelid, relform2->reltoastrelid, relform1, updated1); + HeapTupleUpdateField(pg_class, reltoastrelid, swaptemp, relform2, updated2); } } else @@ -1217,8 +1223,8 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class, { Assert(!TransactionIdIsValid(frozenXid) || TransactionIdIsNormal(frozenXid)); - relform1->relfrozenxid = frozenXid; - relform1->relminmxid = cutoffMulti; + HeapTupleUpdateField(pg_class, relfrozenxid, frozenXid, relform1, updated1); + HeapTupleUpdateField(pg_class, relminmxid, cutoffMulti, relform1, updated1); } /* swap size statistics too, since new rel has freshly-updated stats */ @@ -1229,20 +1235,20 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class, int32 swap_allfrozen; swap_pages = relform1->relpages; - relform1->relpages = relform2->relpages; - relform2->relpages = swap_pages; + HeapTupleUpdateField(pg_class, relpages, relform2->relpages, relform1, updated1); + HeapTupleUpdateField(pg_class, relpages, swap_pages, relform2, updated2); swap_tuples = relform1->reltuples; - relform1->reltuples = relform2->reltuples; - relform2->reltuples = swap_tuples; + HeapTupleUpdateField(pg_class, reltuples, relform2->reltuples, relform1, updated1); + HeapTupleUpdateField(pg_class, reltuples, swap_tuples, relform2, updated2); swap_allvisible = relform1->relallvisible; - relform1->relallvisible = relform2->relallvisible; - relform2->relallvisible = swap_allvisible; + HeapTupleUpdateField(pg_class, relallvisible, relform2->relallvisible, relform1, updated1); + HeapTupleUpdateField(pg_class, relallvisible, swap_allvisible, relform2, updated2); swap_allfrozen = relform1->relallfrozen; - relform1->relallfrozen = relform2->relallfrozen; - relform2->relallfrozen = swap_allfrozen; + HeapTupleUpdateField(pg_class, relallfrozen, relform2->relallfrozen, relform1, updated1); + HeapTupleUpdateField(pg_class, relallfrozen, swap_allfrozen, relform2, updated2); } /* @@ -1256,13 +1262,11 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class, */ if (!target_is_pg_class) { - CatalogIndexState indstate; + CatalogIndexState indstate = CatalogOpenIndexes(relRelation); + + CatalogTupleUpdate(relRelation, &reltup1->t_self, reltup1, updated1, indstate); + CatalogTupleUpdate(relRelation, &reltup2->t_self, reltup2, updated2, indstate); - indstate = CatalogOpenIndexes(relRelation); - CatalogTupleUpdateWithInfo(relRelation, &reltup1->t_self, reltup1, - indstate); - CatalogTupleUpdateWithInfo(relRelation, &reltup2->t_self, reltup2, - indstate); CatalogCloseIndexes(indstate); } else @@ -1435,6 +1439,8 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class, heap_freetuple(reltup2); table_close(relRelation, RowExclusiveLock); + bms_free(updated1); + bms_free(updated2); } /* @@ -1535,6 +1541,7 @@ finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap, Relation relRelation; HeapTuple reltup; Form_pg_class relform; + Bitmapset *updated = NULL; relRelation = table_open(RelationRelationId, RowExclusiveLock); @@ -1543,12 +1550,13 @@ finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap, elog(ERROR, "cache lookup failed for relation %u", OIDOldHeap); relform = (Form_pg_class) GETSTRUCT(reltup); - relform->relfrozenxid = frozenXid; - relform->relminmxid = cutoffMulti; + HeapTupleUpdateField(pg_class, relfrozenxid, frozenXid, relform, updated); + HeapTupleUpdateField(pg_class, relminmxid, cutoffMulti, relform, updated); - CatalogTupleUpdate(relRelation, &reltup->t_self, reltup); + CatalogTupleUpdate(relRelation, &reltup->t_self, reltup, updated, NULL); table_close(relRelation, RowExclusiveLock); + bms_free(updated); } /* Destroy new heap with old filenumber */ diff --git a/src/backend/commands/collationcmds.c b/src/backend/commands/collationcmds.c index 8acbfbbeda041..ccc6da41a40dc 100644 --- a/src/backend/commands/collationcmds.c +++ b/src/backend/commands/collationcmds.c @@ -427,6 +427,7 @@ AlterCollation(AlterCollationStmt *stmt) Oid collOid; HeapTuple tup; Form_pg_collation collForm; + Bitmapset *updated = NULL; Datum datum; bool isnull; char *oldversion; @@ -468,29 +469,22 @@ AlterCollation(AlterCollationStmt *stmt) elog(ERROR, "invalid collation version change"); else if (oldversion && newversion && strcmp(newversion, oldversion) != 0) { - bool nulls[Natts_pg_collation]; - bool replaces[Natts_pg_collation]; - Datum values[Natts_pg_collation]; + bool nulls[Natts_pg_collation] = {false}; + Datum values[Natts_pg_collation] = {0}; ereport(NOTICE, (errmsg("changing version from %s to %s", oldversion, newversion))); - memset(values, 0, sizeof(values)); - memset(nulls, false, sizeof(nulls)); - memset(replaces, false, sizeof(replaces)); + HeapTupleUpdateValue(pg_collation, collversion, CStringGetTextDatum(newversion), values, nulls, updated); - values[Anum_pg_collation_collversion - 1] = CStringGetTextDatum(newversion); - replaces[Anum_pg_collation_collversion - 1] = true; - - tup = heap_modify_tuple(tup, RelationGetDescr(rel), - values, nulls, replaces); + tup = heap_update_tuple(tup, RelationGetDescr(rel), values, nulls, updated); } else ereport(NOTICE, (errmsg("version has not changed"))); - CatalogTupleUpdate(rel, &tup->t_self, tup); + CatalogTupleUpdate(rel, &tup->t_self, tup, updated, NULL); InvokeObjectPostAlterHook(CollationRelationId, collOid, 0); @@ -498,6 +492,7 @@ AlterCollation(AlterCollationStmt *stmt) heap_freetuple(tup); table_close(rel, NoLock); + bms_free(updated); return address; } diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c index 5c783cc61f1d7..55f9ff3f3d4c2 100644 --- a/src/backend/commands/comment.c +++ b/src/backend/commands/comment.c @@ -147,10 +147,9 @@ CreateComments(Oid oid, Oid classoid, int32 subid, const char *comment) SysScanDesc sd; HeapTuple oldtuple; HeapTuple newtuple = NULL; - Datum values[Natts_pg_description]; - bool nulls[Natts_pg_description]; - bool replaces[Natts_pg_description]; - int i; + Datum values[Natts_pg_description] = {0}; + bool nulls[Natts_pg_description] = {false}; + Bitmapset *updated = NULL; /* Reduce empty-string to NULL case */ if (comment != NULL && strlen(comment) == 0) @@ -159,15 +158,10 @@ CreateComments(Oid oid, Oid classoid, int32 subid, const char *comment) /* Prepare to form or update a tuple, if necessary */ if (comment != NULL) { - for (i = 0; i < Natts_pg_description; i++) - { - nulls[i] = false; - replaces[i] = true; - } - values[Anum_pg_description_objoid - 1] = ObjectIdGetDatum(oid); - values[Anum_pg_description_classoid - 1] = ObjectIdGetDatum(classoid); - values[Anum_pg_description_objsubid - 1] = Int32GetDatum(subid); - values[Anum_pg_description_description - 1] = CStringGetTextDatum(comment); + HeapTupleUpdateValue(pg_description, objoid, ObjectIdGetDatum(oid), values, nulls, updated); + HeapTupleUpdateValue(pg_description, classoid, ObjectIdGetDatum(classoid), values, nulls, updated); + HeapTupleUpdateValue(pg_description, objsubid, Int32GetDatum(subid), values, nulls, updated); + HeapTupleUpdateValue(pg_description, description, CStringGetTextDatum(comment), values, nulls, updated); } /* Use the index to search for a matching old tuple */ @@ -198,9 +192,9 @@ CreateComments(Oid oid, Oid classoid, int32 subid, const char *comment) CatalogTupleDelete(description, &oldtuple->t_self); else { - newtuple = heap_modify_tuple(oldtuple, RelationGetDescr(description), values, - nulls, replaces); - CatalogTupleUpdate(description, &oldtuple->t_self, newtuple); + HeapTupleUpdateValue(pg_description, description, CStringGetTextDatum(comment), values, nulls, updated); + newtuple = heap_update_tuple(oldtuple, RelationGetDescr(description), values, nulls, updated); + CatalogTupleUpdate(description, &oldtuple->t_self, newtuple, updated, NULL); } break; /* Assume there can be only one match */ @@ -214,7 +208,7 @@ CreateComments(Oid oid, Oid classoid, int32 subid, const char *comment) { newtuple = heap_form_tuple(RelationGetDescr(description), values, nulls); - CatalogTupleInsert(description, newtuple); + CatalogTupleInsert(description, newtuple, NULL); } if (newtuple != NULL) @@ -223,6 +217,7 @@ CreateComments(Oid oid, Oid classoid, int32 subid, const char *comment) /* Done */ table_close(description, NoLock); + bms_free(updated); } /* @@ -242,9 +237,9 @@ CreateSharedComments(Oid oid, Oid classoid, const char *comment) SysScanDesc sd; HeapTuple oldtuple; HeapTuple newtuple = NULL; - Datum values[Natts_pg_shdescription]; - bool nulls[Natts_pg_shdescription]; - bool replaces[Natts_pg_shdescription]; + Datum values[Natts_pg_shdescription] = {0}; + bool nulls[Natts_pg_shdescription] = {false}; + Bitmapset *updated = NULL; int i; /* Reduce empty-string to NULL case */ @@ -257,11 +252,10 @@ CreateSharedComments(Oid oid, Oid classoid, const char *comment) for (i = 0; i < Natts_pg_shdescription; i++) { nulls[i] = false; - replaces[i] = true; } - values[Anum_pg_shdescription_objoid - 1] = ObjectIdGetDatum(oid); - values[Anum_pg_shdescription_classoid - 1] = ObjectIdGetDatum(classoid); - values[Anum_pg_shdescription_description - 1] = CStringGetTextDatum(comment); + HeapTupleUpdateValue(pg_shdescription, objoid, ObjectIdGetDatum(oid), values, nulls, updated); + HeapTupleUpdateValue(pg_shdescription, classoid, ObjectIdGetDatum(classoid), values, nulls, updated); + HeapTupleUpdateValue(pg_shdescription, description, CStringGetTextDatum(comment), values, nulls, updated); } /* Use the index to search for a matching old tuple */ @@ -288,9 +282,9 @@ CreateSharedComments(Oid oid, Oid classoid, const char *comment) CatalogTupleDelete(shdescription, &oldtuple->t_self); else { - newtuple = heap_modify_tuple(oldtuple, RelationGetDescr(shdescription), - values, nulls, replaces); - CatalogTupleUpdate(shdescription, &oldtuple->t_self, newtuple); + HeapTupleUpdateValue(pg_shdescription, description, CStringGetTextDatum(comment), values, nulls, updated); + newtuple = heap_update_tuple(oldtuple, RelationGetDescr(shdescription), values, nulls, updated); + CatalogTupleUpdate(shdescription, &oldtuple->t_self, newtuple, updated, NULL); } break; /* Assume there can be only one match */ @@ -304,7 +298,7 @@ CreateSharedComments(Oid oid, Oid classoid, const char *comment) { newtuple = heap_form_tuple(RelationGetDescr(shdescription), values, nulls); - CatalogTupleInsert(shdescription, newtuple); + CatalogTupleInsert(shdescription, newtuple, NULL); } if (newtuple != NULL) @@ -313,6 +307,7 @@ CreateSharedComments(Oid oid, Oid classoid, const char *comment) /* Done */ table_close(shdescription, NoLock); + bms_free(updated); } /* diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c index 4d65e8c46c21a..1784a38e13b39 100644 --- a/src/backend/commands/dbcommands.c +++ b/src/backend/commands/dbcommands.c @@ -702,8 +702,8 @@ createdb(ParseState *pstate, const CreatedbStmt *stmt) volatile Oid dst_deftablespace; Relation pg_database_rel; HeapTuple tuple; - Datum new_record[Natts_pg_database] = {0}; - bool new_record_nulls[Natts_pg_database] = {0}; + Datum values[Natts_pg_database] = {0}; + bool nulls[Natts_pg_database] = {false}; Oid dboid = InvalidOid; Oid datdba; ListCell *option; @@ -1457,45 +1457,44 @@ createdb(ParseState *pstate, const CreatedbStmt *stmt) (dblocprovider == COLLPROVIDER_LIBC && !dblocale)); /* Form tuple */ - new_record[Anum_pg_database_oid - 1] = ObjectIdGetDatum(dboid); - new_record[Anum_pg_database_datname - 1] = - DirectFunctionCall1(namein, CStringGetDatum(dbname)); - new_record[Anum_pg_database_datdba - 1] = ObjectIdGetDatum(datdba); - new_record[Anum_pg_database_encoding - 1] = Int32GetDatum(encoding); - new_record[Anum_pg_database_datlocprovider - 1] = CharGetDatum(dblocprovider); - new_record[Anum_pg_database_datistemplate - 1] = BoolGetDatum(dbistemplate); - new_record[Anum_pg_database_datallowconn - 1] = BoolGetDatum(dballowconnections); - new_record[Anum_pg_database_dathasloginevt - 1] = BoolGetDatum(src_hasloginevt); - new_record[Anum_pg_database_datconnlimit - 1] = Int32GetDatum(dbconnlimit); - new_record[Anum_pg_database_datfrozenxid - 1] = TransactionIdGetDatum(src_frozenxid); - new_record[Anum_pg_database_datminmxid - 1] = TransactionIdGetDatum(src_minmxid); - new_record[Anum_pg_database_dattablespace - 1] = ObjectIdGetDatum(dst_deftablespace); - new_record[Anum_pg_database_datcollate - 1] = CStringGetTextDatum(dbcollate); - new_record[Anum_pg_database_datctype - 1] = CStringGetTextDatum(dbctype); + HeapTupleSetValue(pg_database, oid, ObjectIdGetDatum(dboid), values); + HeapTupleSetValue(pg_database, datname, DirectFunctionCall1(namein, CStringGetDatum(dbname)), values); + HeapTupleSetValue(pg_database, datdba, ObjectIdGetDatum(datdba), values); + HeapTupleSetValue(pg_database, encoding, Int32GetDatum(encoding), values); + HeapTupleSetValue(pg_database, datlocprovider, CharGetDatum(dblocprovider), values); + HeapTupleSetValue(pg_database, datistemplate, BoolGetDatum(dbistemplate), values); + HeapTupleSetValue(pg_database, datallowconn, BoolGetDatum(dballowconnections), values); + HeapTupleSetValue(pg_database, dathasloginevt, BoolGetDatum(src_hasloginevt), values); + HeapTupleSetValue(pg_database, datconnlimit, Int32GetDatum(dbconnlimit), values); + HeapTupleSetValue(pg_database, datfrozenxid, TransactionIdGetDatum(src_frozenxid), values); + HeapTupleSetValue(pg_database, datminmxid, TransactionIdGetDatum(src_minmxid), values); + HeapTupleSetValue(pg_database, dattablespace, ObjectIdGetDatum(dst_deftablespace), values); + HeapTupleSetValue(pg_database, datcollate, CStringGetTextDatum(dbcollate), values); + HeapTupleSetValue(pg_database, datctype, CStringGetTextDatum(dbctype), values); if (dblocale) - new_record[Anum_pg_database_datlocale - 1] = CStringGetTextDatum(dblocale); + HeapTupleSetValue(pg_database, datlocale, CStringGetTextDatum(dblocale), values); else - new_record_nulls[Anum_pg_database_datlocale - 1] = true; + HeapTupleSetValueNull(pg_database, datlocale, values, nulls); if (dbicurules) - new_record[Anum_pg_database_daticurules - 1] = CStringGetTextDatum(dbicurules); + HeapTupleSetValue(pg_database, daticurules, CStringGetTextDatum(dbicurules), values); else - new_record_nulls[Anum_pg_database_daticurules - 1] = true; + HeapTupleSetValueNull(pg_database, daticurules, values, nulls); if (dbcollversion) - new_record[Anum_pg_database_datcollversion - 1] = CStringGetTextDatum(dbcollversion); + HeapTupleSetValue(pg_database, datcollversion, CStringGetTextDatum(dbcollversion), values); else - new_record_nulls[Anum_pg_database_datcollversion - 1] = true; + HeapTupleSetValueNull(pg_database, datcollversion, values, nulls); /* * We deliberately set datacl to default (NULL), rather than copying it * from the template database. Copying it would be a bad idea when the * owner is not the same as the template's owner. */ - new_record_nulls[Anum_pg_database_datacl - 1] = true; + HeapTupleSetValueNull(pg_database, datacl, values, nulls); tuple = heap_form_tuple(RelationGetDescr(pg_database_rel), - new_record, new_record_nulls); + values, nulls); - CatalogTupleInsert(pg_database_rel, tuple); + CatalogTupleInsert(pg_database_rel, tuple, NULL); /* * Now generate additional catalog entries associated with the new DB @@ -1909,6 +1908,7 @@ RenameDatabase(const char *oldname, const char *newname) int notherbackends; int npreparedxacts; ObjectAddress address; + Bitmapset *updated = NULL; /* * Look up the target database's OID, and get exclusive lock on it. We @@ -1980,8 +1980,9 @@ RenameDatabase(const char *oldname, const char *newname) if (!HeapTupleIsValid(newtup)) elog(ERROR, "cache lookup failed for database %u", db_id); otid = newtup->t_self; - namestrcpy(&(((Form_pg_database) GETSTRUCT(newtup))->datname), newname); - CatalogTupleUpdate(rel, &otid, newtup); + namestrcpy(&((Form_pg_database) GETSTRUCT(newtup))->datname, newname); + HeapTupleMarkColumnUpdated(pg_database, datname, updated); + CatalogTupleUpdate(rel, &otid, newtup, updated, NULL); UnlockTuple(rel, &otid, InplaceUpdateTupleLock); InvokeObjectPostAlterHook(DatabaseRelationId, db_id, 0); @@ -1992,6 +1993,7 @@ RenameDatabase(const char *oldname, const char *newname) * Close pg_database, but keep lock till commit. */ table_close(rel, NoLock); + bms_free(updated); return address; } @@ -2189,9 +2191,9 @@ movedb(const char *dbname, const char *tblspcname) PG_ENSURE_ERROR_CLEANUP(movedb_failure_callback, PointerGetDatum(&fparms)); { - Datum new_record[Natts_pg_database] = {0}; - bool new_record_nulls[Natts_pg_database] = {0}; - bool new_record_repl[Natts_pg_database] = {0}; + Datum values[Natts_pg_database] = {0}; + bool nulls[Natts_pg_database] = {false}; + Bitmapset *updated = NULL; /* * Copy files from the old tablespace to the new one @@ -2233,13 +2235,10 @@ movedb(const char *dbname, const char *tblspcname) errmsg("database \"%s\" does not exist", dbname))); LockTuple(pgdbrel, &oldtuple->t_self, InplaceUpdateTupleLock); - new_record[Anum_pg_database_dattablespace - 1] = ObjectIdGetDatum(dst_tblspcoid); - new_record_repl[Anum_pg_database_dattablespace - 1] = true; + HeapTupleUpdateValue(pg_database, dattablespace, ObjectIdGetDatum(dst_tblspcoid), values, nulls, updated); - newtuple = heap_modify_tuple(oldtuple, RelationGetDescr(pgdbrel), - new_record, - new_record_nulls, new_record_repl); - CatalogTupleUpdate(pgdbrel, &oldtuple->t_self, newtuple); + newtuple = heap_update_tuple(oldtuple, RelationGetDescr(pgdbrel), values, nulls, updated); + CatalogTupleUpdate(pgdbrel, &oldtuple->t_self, newtuple, updated, NULL); UnlockTuple(pgdbrel, &oldtuple->t_self, InplaceUpdateTupleLock); InvokeObjectPostAlterHook(DatabaseRelationId, db_id, 0); @@ -2267,6 +2266,7 @@ movedb(const char *dbname, const char *tblspcname) * Close pg_database, but keep lock till commit. */ table_close(pgdbrel, NoLock); + bms_free(updated); } PG_END_ENSURE_ERROR_CLEANUP(movedb_failure_callback, PointerGetDatum(&fparms)); @@ -2382,9 +2382,9 @@ AlterDatabase(ParseState *pstate, AlterDatabaseStmt *stmt, bool isTopLevel) DefElem *dallowconnections = NULL; DefElem *dconnlimit = NULL; DefElem *dtablespace = NULL; - Datum new_record[Natts_pg_database] = {0}; - bool new_record_nulls[Natts_pg_database] = {0}; - bool new_record_repl[Natts_pg_database] = {0}; + Datum values[Natts_pg_database] = {0}; + bool nulls[Natts_pg_database] = {false}; + Bitmapset *updated = NULL; /* Extract options from the statement node tree */ foreach(option, stmt->options) @@ -2503,24 +2503,16 @@ AlterDatabase(ParseState *pstate, AlterDatabaseStmt *stmt, bool isTopLevel) * Build an updated tuple, perusing the information just obtained */ if (distemplate) - { - new_record[Anum_pg_database_datistemplate - 1] = BoolGetDatum(dbistemplate); - new_record_repl[Anum_pg_database_datistemplate - 1] = true; - } + HeapTupleUpdateValue(pg_database, datistemplate, BoolGetDatum(dbistemplate), values, nulls, updated); + if (dallowconnections) - { - new_record[Anum_pg_database_datallowconn - 1] = BoolGetDatum(dballowconnections); - new_record_repl[Anum_pg_database_datallowconn - 1] = true; - } + HeapTupleUpdateValue(pg_database, datallowconn, BoolGetDatum(dballowconnections), values, nulls, updated); + if (dconnlimit) - { - new_record[Anum_pg_database_datconnlimit - 1] = Int32GetDatum(dbconnlimit); - new_record_repl[Anum_pg_database_datconnlimit - 1] = true; - } + HeapTupleUpdateValue(pg_database, datconnlimit, Int32GetDatum(dbconnlimit), values, nulls, updated); - newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel), new_record, - new_record_nulls, new_record_repl); - CatalogTupleUpdate(rel, &tuple->t_self, newtuple); + newtuple = heap_update_tuple(tuple, RelationGetDescr(rel), values, nulls, updated); + CatalogTupleUpdate(rel, &tuple->t_self, newtuple, updated, NULL); UnlockTuple(rel, &tuple->t_self, InplaceUpdateTupleLock); InvokeObjectPostAlterHook(DatabaseRelationId, dboid, 0); @@ -2529,6 +2521,7 @@ AlterDatabase(ParseState *pstate, AlterDatabaseStmt *stmt, bool isTopLevel) /* Close pg_database, but keep lock till commit */ table_close(rel, NoLock); + bms_free(updated); return dboid; } @@ -2597,22 +2590,21 @@ AlterDatabaseRefreshColl(AlterDatabaseRefreshCollStmt *stmt) elog(ERROR, "invalid collation version change"); else if (oldversion && newversion && strcmp(newversion, oldversion) != 0) { - bool nulls[Natts_pg_database] = {0}; - bool replaces[Natts_pg_database] = {0}; Datum values[Natts_pg_database] = {0}; + bool nulls[Natts_pg_database] = {false}; + Bitmapset *updated = NULL; HeapTuple newtuple; ereport(NOTICE, (errmsg("changing version from %s to %s", oldversion, newversion))); - values[Anum_pg_database_datcollversion - 1] = CStringGetTextDatum(newversion); - replaces[Anum_pg_database_datcollversion - 1] = true; + HeapTupleUpdateValue(pg_database, datcollversion, CStringGetTextDatum(newversion), values, nulls, updated); - newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel), - values, nulls, replaces); - CatalogTupleUpdate(rel, &tuple->t_self, newtuple); + newtuple = heap_update_tuple(tuple, RelationGetDescr(rel), values, nulls, updated); + CatalogTupleUpdate(rel, &tuple->t_self, newtuple, updated, NULL); heap_freetuple(newtuple); + bms_free(updated); } else ereport(NOTICE, @@ -2699,9 +2691,9 @@ AlterDatabaseOwner(const char *dbname, Oid newOwnerId) */ if (datForm->datdba != newOwnerId) { - Datum repl_val[Natts_pg_database]; - bool repl_null[Natts_pg_database] = {0}; - bool repl_repl[Natts_pg_database] = {0}; + Datum values[Natts_pg_database] = {0}; + bool nulls[Natts_pg_database] = {false}; + Bitmapset *updated = NULL; Acl *newAcl; Datum aclDatum; bool isNull; @@ -2731,8 +2723,7 @@ AlterDatabaseOwner(const char *dbname, Oid newOwnerId) LockTuple(rel, &tuple->t_self, InplaceUpdateTupleLock); - repl_repl[Anum_pg_database_datdba - 1] = true; - repl_val[Anum_pg_database_datdba - 1] = ObjectIdGetDatum(newOwnerId); + HeapTupleUpdateValue(pg_database, datdba, ObjectIdGetDatum(newOwnerId), values, nulls, updated); /* * Determine the modified ACL for the new owner. This is only @@ -2746,18 +2737,18 @@ AlterDatabaseOwner(const char *dbname, Oid newOwnerId) { newAcl = aclnewowner(DatumGetAclP(aclDatum), datForm->datdba, newOwnerId); - repl_repl[Anum_pg_database_datacl - 1] = true; - repl_val[Anum_pg_database_datacl - 1] = PointerGetDatum(newAcl); + HeapTupleUpdateValue(pg_database, datacl, PointerGetDatum(newAcl), values, nulls, updated); } - newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel), repl_val, repl_null, repl_repl); - CatalogTupleUpdate(rel, &newtuple->t_self, newtuple); + newtuple = heap_update_tuple(tuple, RelationGetDescr(rel), values, nulls, updated); + CatalogTupleUpdate(rel, &newtuple->t_self, newtuple, updated, NULL); UnlockTuple(rel, &tuple->t_self, InplaceUpdateTupleLock); heap_freetuple(newtuple); /* Update owner dependency reference */ changeDependencyOnOwner(DatabaseRelationId, db_id, newOwnerId); + bms_free(updated); } InvokeObjectPostAlterHook(DatabaseRelationId, db_id, 0); diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c index f34868da5ab94..5408e6d276027 100644 --- a/src/backend/commands/event_trigger.c +++ b/src/backend/commands/event_trigger.c @@ -280,8 +280,8 @@ insert_event_trigger_tuple(const char *trigname, const char *eventname, Oid evtO Relation tgrel; Oid trigoid; HeapTuple tuple; - Datum values[Natts_pg_event_trigger]; - bool nulls[Natts_pg_event_trigger]; + Datum values[Natts_pg_event_trigger] = {0}; + bool nulls[Natts_pg_event_trigger] = {false}; NameData evtnamedata, evteventdata; ObjectAddress myself, @@ -293,25 +293,23 @@ insert_event_trigger_tuple(const char *trigname, const char *eventname, Oid evtO /* Build the new pg_trigger tuple. */ trigoid = GetNewOidWithIndex(tgrel, EventTriggerOidIndexId, Anum_pg_event_trigger_oid); - values[Anum_pg_event_trigger_oid - 1] = ObjectIdGetDatum(trigoid); + HeapTupleSetValue(pg_event_trigger, oid, ObjectIdGetDatum(trigoid), values); memset(nulls, false, sizeof(nulls)); namestrcpy(&evtnamedata, trigname); - values[Anum_pg_event_trigger_evtname - 1] = NameGetDatum(&evtnamedata); + HeapTupleSetValue(pg_event_trigger, evtname, NameGetDatum(&evtnamedata), values); namestrcpy(&evteventdata, eventname); - values[Anum_pg_event_trigger_evtevent - 1] = NameGetDatum(&evteventdata); - values[Anum_pg_event_trigger_evtowner - 1] = ObjectIdGetDatum(evtOwner); - values[Anum_pg_event_trigger_evtfoid - 1] = ObjectIdGetDatum(funcoid); - values[Anum_pg_event_trigger_evtenabled - 1] = - CharGetDatum(TRIGGER_FIRES_ON_ORIGIN); + HeapTupleSetValue(pg_event_trigger, evtevent, NameGetDatum(&evteventdata), values); + HeapTupleSetValue(pg_event_trigger, evtowner, ObjectIdGetDatum(evtOwner), values); + HeapTupleSetValue(pg_event_trigger, evtfoid, ObjectIdGetDatum(funcoid), values); + HeapTupleSetValue(pg_event_trigger, evtenabled, CharGetDatum(TRIGGER_FIRES_ON_ORIGIN), values); if (taglist == NIL) - nulls[Anum_pg_event_trigger_evttags - 1] = true; + HeapTupleSetValueNull(pg_event_trigger, evttags, values, nulls); else - values[Anum_pg_event_trigger_evttags - 1] = - filter_list_to_array(taglist); + HeapTupleSetValue(pg_event_trigger, evttags, filter_list_to_array(taglist), values); /* Insert heap tuple. */ tuple = heap_form_tuple(tgrel->rd_att, values, nulls); - CatalogTupleInsert(tgrel, tuple); + CatalogTupleInsert(tgrel, tuple, NULL); heap_freetuple(tuple); /* @@ -394,6 +392,7 @@ SetDatabaseHasLoginEventTriggers(void) Relation pg_db = table_open(DatabaseRelationId, RowExclusiveLock); ItemPointerData otid; HeapTuple tuple; + Bitmapset *updated = NULL; /* * Use shared lock to prevent a conflict with EventTriggerOnLogin() trying @@ -411,8 +410,9 @@ SetDatabaseHasLoginEventTriggers(void) db = (Form_pg_database) GETSTRUCT(tuple); if (!db->dathasloginevt) { - db->dathasloginevt = true; - CatalogTupleUpdate(pg_db, &otid, tuple); + HeapTupleUpdateField(pg_database, dathasloginevt, true, db, updated); + CatalogTupleUpdate(pg_db, &otid, tuple, updated, NULL); + bms_free(updated); CommandCounterIncrement(); } UnlockTuple(pg_db, &otid, InplaceUpdateTupleLock); @@ -431,6 +431,7 @@ AlterEventTrigger(AlterEventTrigStmt *stmt) Oid trigoid; Form_pg_event_trigger evtForm; char tgenabled = stmt->tgenabled; + Bitmapset *updated = NULL; tgrel = table_open(EventTriggerRelationId, RowExclusiveLock); @@ -450,9 +451,10 @@ AlterEventTrigger(AlterEventTrigStmt *stmt) stmt->trigname); /* tuple is a copy, so we can modify it below */ - evtForm->evtenabled = tgenabled; + HeapTupleUpdateField(pg_event_trigger, evtenabled, tgenabled, evtForm, updated); - CatalogTupleUpdate(tgrel, &tup->t_self, tup); + CatalogTupleUpdate(tgrel, &tup->t_self, tup, updated, NULL); + bms_free(updated); /* * Login event triggers have an additional flag in pg_database to enable @@ -539,6 +541,7 @@ static void AlterEventTriggerOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId) { Form_pg_event_trigger form; + Bitmapset *updated = NULL; form = (Form_pg_event_trigger) GETSTRUCT(tup); @@ -557,8 +560,9 @@ AlterEventTriggerOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId) NameStr(form->evtname)), errhint("The owner of an event trigger must be a superuser."))); - form->evtowner = newOwnerId; - CatalogTupleUpdate(rel, &tup->t_self, tup); + HeapTupleUpdateField(pg_event_trigger, evtowner, newOwnerId, form, updated); + CatalogTupleUpdate(rel, &tup->t_self, tup, updated, NULL); + bms_free(updated); /* Update owner dependency reference */ changeDependencyOnOwner(EventTriggerRelationId, diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c index 93ef1ad106fdb..41ac7d2f9942f 100644 --- a/src/backend/commands/extension.c +++ b/src/backend/commands/extension.c @@ -2067,8 +2067,8 @@ InsertExtensionTuple(const char *extName, Oid extOwner, { Oid extensionOid; Relation rel; - Datum values[Natts_pg_extension]; - bool nulls[Natts_pg_extension]; + Datum values[Natts_pg_extension] = {0}; + bool nulls[Natts_pg_extension] = {false}; HeapTuple tuple; ObjectAddress myself; ObjectAddress nsp; @@ -2085,27 +2085,26 @@ InsertExtensionTuple(const char *extName, Oid extOwner, extensionOid = GetNewOidWithIndex(rel, ExtensionOidIndexId, Anum_pg_extension_oid); - values[Anum_pg_extension_oid - 1] = ObjectIdGetDatum(extensionOid); - values[Anum_pg_extension_extname - 1] = - DirectFunctionCall1(namein, CStringGetDatum(extName)); - values[Anum_pg_extension_extowner - 1] = ObjectIdGetDatum(extOwner); - values[Anum_pg_extension_extnamespace - 1] = ObjectIdGetDatum(schemaOid); - values[Anum_pg_extension_extrelocatable - 1] = BoolGetDatum(relocatable); - values[Anum_pg_extension_extversion - 1] = CStringGetTextDatum(extVersion); + HeapTupleSetValue(pg_extension, oid, ObjectIdGetDatum(extensionOid), values); + HeapTupleSetValue(pg_extension, extname, DirectFunctionCall1(namein, CStringGetDatum(extName)), values); + HeapTupleSetValue(pg_extension, extowner, ObjectIdGetDatum(extOwner), values); + HeapTupleSetValue(pg_extension, extnamespace, ObjectIdGetDatum(schemaOid), values); + HeapTupleSetValue(pg_extension, extrelocatable, BoolGetDatum(relocatable), values); + HeapTupleSetValue(pg_extension, extversion, CStringGetTextDatum(extVersion), values); if (extConfig == PointerGetDatum(NULL)) - nulls[Anum_pg_extension_extconfig - 1] = true; + HeapTupleSetValueNull(pg_extension, extconfig, values, nulls); else - values[Anum_pg_extension_extconfig - 1] = extConfig; + HeapTupleSetValue(pg_extension, extconfig, extConfig, values); if (extCondition == PointerGetDatum(NULL)) - nulls[Anum_pg_extension_extcondition - 1] = true; + HeapTupleSetValueNull(pg_extension, extcondition, values, nulls); else - values[Anum_pg_extension_extcondition - 1] = extCondition; + HeapTupleSetValue(pg_extension, extcondition, extCondition, values); tuple = heap_form_tuple(rel->rd_att, values, nulls); - CatalogTupleInsert(rel, tuple); + CatalogTupleInsert(rel, tuple, NULL); heap_freetuple(tuple); table_close(rel, RowExclusiveLock); @@ -2674,9 +2673,9 @@ pg_extension_config_dump(PG_FUNCTION_ARGS) int arrayLength; int arrayIndex; bool isnull; - Datum repl_val[Natts_pg_extension]; - bool repl_null[Natts_pg_extension]; - bool repl_repl[Natts_pg_extension]; + Datum values[Natts_pg_extension] = {0}; + bool nulls[Natts_pg_extension] = {false}; + Bitmapset *updated = NULL; ArrayType *a; /* @@ -2731,10 +2730,6 @@ pg_extension_config_dump(PG_FUNCTION_ARGS) elog(ERROR, "could not find tuple for extension %u", CurrentExtensionObject); - memset(repl_val, 0, sizeof(repl_val)); - memset(repl_null, false, sizeof(repl_null)); - memset(repl_repl, false, sizeof(repl_repl)); - /* Build or modify the extconfig value */ elementDatum = ObjectIdGetDatum(tableoid); @@ -2784,8 +2779,7 @@ pg_extension_config_dump(PG_FUNCTION_ARGS) true /* OID's typbyval */ , TYPALIGN_INT /* OID's typalign */ ); } - repl_val[Anum_pg_extension_extconfig - 1] = PointerGetDatum(a); - repl_repl[Anum_pg_extension_extconfig - 1] = true; + HeapTupleUpdateValue(pg_extension, extconfig, PointerGetDatum(a), values, nulls, updated); /* Build or modify the extcondition value */ elementDatum = PointerGetDatum(wherecond); @@ -2820,17 +2814,16 @@ pg_extension_config_dump(PG_FUNCTION_ARGS) false /* TEXT's typbyval */ , TYPALIGN_INT /* TEXT's typalign */ ); } - repl_val[Anum_pg_extension_extcondition - 1] = PointerGetDatum(a); - repl_repl[Anum_pg_extension_extcondition - 1] = true; + HeapTupleUpdateValue(pg_extension, extcondition, PointerGetDatum(a), values, nulls, updated); - extTup = heap_modify_tuple(extTup, RelationGetDescr(extRel), - repl_val, repl_null, repl_repl); + extTup = heap_update_tuple(extTup, RelationGetDescr(extRel), values, nulls, updated); - CatalogTupleUpdate(extRel, &extTup->t_self, extTup); + CatalogTupleUpdate(extRel, &extTup->t_self, extTup, updated, NULL); systable_endscan(extScan); table_close(extRel, RowExclusiveLock); + bms_free(updated); PG_RETURN_VOID(); } @@ -2906,9 +2899,9 @@ extension_config_remove(Oid extensionoid, Oid tableoid) int arrayLength; int arrayIndex; bool isnull; - Datum repl_val[Natts_pg_extension]; - bool repl_null[Natts_pg_extension]; - bool repl_repl[Natts_pg_extension]; + Datum values[Natts_pg_extension] = {0}; + bool nulls[Natts_pg_extension] = {false}; + Bitmapset *updated = NULL; ArrayType *a; /* Find the pg_extension tuple */ @@ -2975,14 +2968,10 @@ extension_config_remove(Oid extensionoid, Oid tableoid) } /* Modify or delete the extconfig value */ - memset(repl_val, 0, sizeof(repl_val)); - memset(repl_null, false, sizeof(repl_null)); - memset(repl_repl, false, sizeof(repl_repl)); - if (arrayLength <= 1) { /* removing only element, just set array to null */ - repl_null[Anum_pg_extension_extconfig - 1] = true; + HeapTupleUpdateValueNull(pg_extension, extconfig, values, nulls, updated); } else { @@ -2999,9 +2988,8 @@ extension_config_remove(Oid extensionoid, Oid tableoid) a = construct_array_builtin(dvalues, arrayLength - 1, OIDOID); - repl_val[Anum_pg_extension_extconfig - 1] = PointerGetDatum(a); + HeapTupleUpdateValue(pg_extension, extconfig, PointerGetDatum(a), values, nulls, updated); } - repl_repl[Anum_pg_extension_extconfig - 1] = true; /* Modify or delete the extcondition value */ arrayDatum = heap_getattr(extTup, Anum_pg_extension_extcondition, @@ -3026,7 +3014,7 @@ extension_config_remove(Oid extensionoid, Oid tableoid) if (arrayLength <= 1) { /* removing only element, just set array to null */ - repl_null[Anum_pg_extension_extcondition - 1] = true; + HeapTupleUpdateValueNull(pg_extension, extcondition, values, nulls, updated); } else { @@ -3042,19 +3030,17 @@ extension_config_remove(Oid extensionoid, Oid tableoid) dvalues[i] = dvalues[i + 1]; a = construct_array_builtin(dvalues, arrayLength - 1, TEXTOID); - - repl_val[Anum_pg_extension_extcondition - 1] = PointerGetDatum(a); + HeapTupleUpdateValue(pg_extension, extcondition, PointerGetDatum(a), values, nulls, updated); } - repl_repl[Anum_pg_extension_extcondition - 1] = true; - extTup = heap_modify_tuple(extTup, RelationGetDescr(extRel), - repl_val, repl_null, repl_repl); + extTup = heap_update_tuple(extTup, RelationGetDescr(extRel), values, nulls, updated); - CatalogTupleUpdate(extRel, &extTup->t_self, extTup); + CatalogTupleUpdate(extRel, &extTup->t_self, extTup, updated, NULL); systable_endscan(extScan); table_close(extRel, RowExclusiveLock); + bms_free(updated); } /* @@ -3072,6 +3058,7 @@ AlterExtensionNamespace(const char *extensionName, const char *newschema, Oid *o SysScanDesc extScan; HeapTuple extTup; Form_pg_extension extForm; + Bitmapset *updated = NULL; Relation depRel; SysScanDesc depScan; HeapTuple depTup; @@ -3253,11 +3240,12 @@ AlterExtensionNamespace(const char *extensionName, const char *newschema, Oid *o relation_close(depRel, AccessShareLock); /* Now adjust pg_extension.extnamespace */ - extForm->extnamespace = nspOid; + HeapTupleUpdateField(pg_extension, extnamespace, nspOid, extForm, updated); - CatalogTupleUpdate(extRel, &extTup->t_self, extTup); + CatalogTupleUpdate(extRel, &extTup->t_self, extTup, updated, NULL); table_close(extRel, RowExclusiveLock); + bms_free(updated); /* update dependency to point to the new schema */ if (changeDependencyFor(ExtensionRelationId, extensionOid, @@ -3447,9 +3435,9 @@ ApplyExtensionUpdates(Oid extensionOid, SysScanDesc extScan; HeapTuple extTup; Form_pg_extension extForm; - Datum values[Natts_pg_extension]; - bool nulls[Natts_pg_extension]; - bool repl[Natts_pg_extension]; + Datum values[Natts_pg_extension] = {0}; + bool nulls[Natts_pg_extension] = {false}; + Bitmapset *updated = NULL; ObjectAddress myself; ListCell *lc; @@ -3486,21 +3474,14 @@ ApplyExtensionUpdates(Oid extensionOid, /* * Modify extrelocatable and extversion in the pg_extension tuple */ - memset(values, 0, sizeof(values)); - memset(nulls, 0, sizeof(nulls)); - memset(repl, 0, sizeof(repl)); - - values[Anum_pg_extension_extrelocatable - 1] = - BoolGetDatum(control->relocatable); - repl[Anum_pg_extension_extrelocatable - 1] = true; - values[Anum_pg_extension_extversion - 1] = - CStringGetTextDatum(versionName); - repl[Anum_pg_extension_extversion - 1] = true; + HeapTupleUpdateValue(pg_extension, extrelocatable, BoolGetDatum(control->relocatable), values, nulls, updated); + HeapTupleUpdateValue(pg_extension, extversion, CStringGetTextDatum(versionName), values, nulls, updated); - extTup = heap_modify_tuple(extTup, RelationGetDescr(extRel), - values, nulls, repl); + extTup = heap_update_tuple(extTup, RelationGetDescr(extRel), + values, nulls, updated); - CatalogTupleUpdate(extRel, &extTup->t_self, extTup); + CatalogTupleUpdate(extRel, &extTup->t_self, extTup, updated, NULL); + bms_free(updated); systable_endscan(extScan); diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c index 536065dc515bc..571814ada29f8 100644 --- a/src/backend/commands/foreigncmds.c +++ b/src/backend/commands/foreigncmds.c @@ -216,9 +216,9 @@ static void AlterForeignDataWrapperOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId) { Form_pg_foreign_data_wrapper form; - Datum repl_val[Natts_pg_foreign_data_wrapper]; - bool repl_null[Natts_pg_foreign_data_wrapper]; - bool repl_repl[Natts_pg_foreign_data_wrapper]; + Datum values[Natts_pg_foreign_data_wrapper] = {0}; + bool nulls[Natts_pg_foreign_data_wrapper] = {false}; + Bitmapset *updated = NULL; Acl *newAcl; Datum aclDatum; bool isNull; @@ -243,11 +243,7 @@ AlterForeignDataWrapperOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerI if (form->fdwowner != newOwnerId) { - memset(repl_null, false, sizeof(repl_null)); - memset(repl_repl, false, sizeof(repl_repl)); - - repl_repl[Anum_pg_foreign_data_wrapper_fdwowner - 1] = true; - repl_val[Anum_pg_foreign_data_wrapper_fdwowner - 1] = ObjectIdGetDatum(newOwnerId); + HeapTupleUpdateValue(pg_foreign_data_wrapper, fdwowner, ObjectIdGetDatum(newOwnerId), values, nulls, updated); aclDatum = heap_getattr(tup, Anum_pg_foreign_data_wrapper_fdwacl, @@ -258,19 +254,18 @@ AlterForeignDataWrapperOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerI { newAcl = aclnewowner(DatumGetAclP(aclDatum), form->fdwowner, newOwnerId); - repl_repl[Anum_pg_foreign_data_wrapper_fdwacl - 1] = true; - repl_val[Anum_pg_foreign_data_wrapper_fdwacl - 1] = PointerGetDatum(newAcl); + HeapTupleUpdateValue(pg_foreign_data_wrapper, fdwacl, PointerGetDatum(newAcl), values, nulls, updated); } - tup = heap_modify_tuple(tup, RelationGetDescr(rel), repl_val, repl_null, - repl_repl); + tup = heap_update_tuple(tup, RelationGetDescr(rel), values, nulls, updated); - CatalogTupleUpdate(rel, &tup->t_self, tup); + CatalogTupleUpdate(rel, &tup->t_self, tup, updated, NULL); /* Update owner dependency reference */ changeDependencyOnOwner(ForeignDataWrapperRelationId, form->oid, newOwnerId); + bms_free(updated); } InvokeObjectPostAlterHook(ForeignDataWrapperRelationId, @@ -349,9 +344,9 @@ static void AlterForeignServerOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId) { Form_pg_foreign_server form; - Datum repl_val[Natts_pg_foreign_server]; - bool repl_null[Natts_pg_foreign_server]; - bool repl_repl[Natts_pg_foreign_server]; + Datum values[Natts_pg_foreign_server] = {0}; + bool nulls[Natts_pg_foreign_server] = {false}; + Bitmapset *updated = NULL; Acl *newAcl; Datum aclDatum; bool isNull; @@ -386,11 +381,7 @@ AlterForeignServerOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId) } } - memset(repl_null, false, sizeof(repl_null)); - memset(repl_repl, false, sizeof(repl_repl)); - - repl_repl[Anum_pg_foreign_server_srvowner - 1] = true; - repl_val[Anum_pg_foreign_server_srvowner - 1] = ObjectIdGetDatum(newOwnerId); + HeapTupleUpdateValue(pg_foreign_server, srvowner, ObjectIdGetDatum(newOwnerId), values, nulls, updated); aclDatum = heap_getattr(tup, Anum_pg_foreign_server_srvacl, @@ -401,18 +392,17 @@ AlterForeignServerOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId) { newAcl = aclnewowner(DatumGetAclP(aclDatum), form->srvowner, newOwnerId); - repl_repl[Anum_pg_foreign_server_srvacl - 1] = true; - repl_val[Anum_pg_foreign_server_srvacl - 1] = PointerGetDatum(newAcl); + HeapTupleUpdateValue(pg_foreign_server, srvacl, PointerGetDatum(newAcl), values, nulls, updated); } - tup = heap_modify_tuple(tup, RelationGetDescr(rel), repl_val, repl_null, - repl_repl); + tup = heap_update_tuple(tup, RelationGetDescr(rel), values, nulls, updated); - CatalogTupleUpdate(rel, &tup->t_self, tup); + CatalogTupleUpdate(rel, &tup->t_self, tup, updated, NULL); /* Update owner dependency reference */ changeDependencyOnOwner(ForeignServerRelationId, form->oid, newOwnerId); + bms_free(updated); } InvokeObjectPostAlterHook(ForeignServerRelationId, @@ -569,8 +559,8 @@ ObjectAddress CreateForeignDataWrapper(ParseState *pstate, CreateFdwStmt *stmt) { Relation rel; - Datum values[Natts_pg_foreign_data_wrapper]; - bool nulls[Natts_pg_foreign_data_wrapper]; + Datum values[Natts_pg_foreign_data_wrapper] = {0}; + bool nulls[Natts_pg_foreign_data_wrapper] = {false}; HeapTuple tuple; Oid fdwId; bool handler_given; @@ -612,20 +602,19 @@ CreateForeignDataWrapper(ParseState *pstate, CreateFdwStmt *stmt) fdwId = GetNewOidWithIndex(rel, ForeignDataWrapperOidIndexId, Anum_pg_foreign_data_wrapper_oid); - values[Anum_pg_foreign_data_wrapper_oid - 1] = ObjectIdGetDatum(fdwId); - values[Anum_pg_foreign_data_wrapper_fdwname - 1] = - DirectFunctionCall1(namein, CStringGetDatum(stmt->fdwname)); - values[Anum_pg_foreign_data_wrapper_fdwowner - 1] = ObjectIdGetDatum(ownerId); + HeapTupleSetValue(pg_foreign_data_wrapper, oid, ObjectIdGetDatum(fdwId), values); + HeapTupleSetValue(pg_foreign_data_wrapper, fdwname, DirectFunctionCall1(namein, CStringGetDatum(stmt->fdwname)), values); + HeapTupleSetValue(pg_foreign_data_wrapper, fdwowner, ObjectIdGetDatum(ownerId), values); /* Lookup handler and validator functions, if given */ parse_func_options(pstate, stmt->func_options, &handler_given, &fdwhandler, &validator_given, &fdwvalidator); - values[Anum_pg_foreign_data_wrapper_fdwhandler - 1] = ObjectIdGetDatum(fdwhandler); - values[Anum_pg_foreign_data_wrapper_fdwvalidator - 1] = ObjectIdGetDatum(fdwvalidator); + HeapTupleSetValue(pg_foreign_data_wrapper, fdwhandler, ObjectIdGetDatum(fdwhandler), values); + HeapTupleSetValue(pg_foreign_data_wrapper, fdwvalidator, ObjectIdGetDatum(fdwvalidator), values); - nulls[Anum_pg_foreign_data_wrapper_fdwacl - 1] = true; + HeapTupleSetValueNull(pg_foreign_data_wrapper, fdwacl, values, nulls); fdwoptions = transformGenericOptions(ForeignDataWrapperRelationId, PointerGetDatum(NULL), @@ -633,13 +622,13 @@ CreateForeignDataWrapper(ParseState *pstate, CreateFdwStmt *stmt) fdwvalidator); if (DatumGetPointer(fdwoptions) != NULL) - values[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = fdwoptions; + HeapTupleSetValue(pg_foreign_data_wrapper, fdwoptions, fdwoptions, values); else - nulls[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = true; + HeapTupleSetValueNull(pg_foreign_data_wrapper, fdwoptions, values, nulls); tuple = heap_form_tuple(rel->rd_att, values, nulls); - CatalogTupleInsert(rel, tuple); + CatalogTupleInsert(rel, tuple, NULL); heap_freetuple(tuple); @@ -687,9 +676,9 @@ AlterForeignDataWrapper(ParseState *pstate, AlterFdwStmt *stmt) Relation rel; HeapTuple tp; Form_pg_foreign_data_wrapper fdwForm; - Datum repl_val[Natts_pg_foreign_data_wrapper]; - bool repl_null[Natts_pg_foreign_data_wrapper]; - bool repl_repl[Natts_pg_foreign_data_wrapper]; + Datum values[Natts_pg_foreign_data_wrapper] = {0}; + bool nulls[Natts_pg_foreign_data_wrapper] = {false}; + Bitmapset *updated = NULL; Oid fdwId; bool isnull; Datum datum; @@ -720,18 +709,13 @@ AlterForeignDataWrapper(ParseState *pstate, AlterFdwStmt *stmt) fdwForm = (Form_pg_foreign_data_wrapper) GETSTRUCT(tp); fdwId = fdwForm->oid; - memset(repl_val, 0, sizeof(repl_val)); - memset(repl_null, false, sizeof(repl_null)); - memset(repl_repl, false, sizeof(repl_repl)); - parse_func_options(pstate, stmt->func_options, &handler_given, &fdwhandler, &validator_given, &fdwvalidator); if (handler_given) { - repl_val[Anum_pg_foreign_data_wrapper_fdwhandler - 1] = ObjectIdGetDatum(fdwhandler); - repl_repl[Anum_pg_foreign_data_wrapper_fdwhandler - 1] = true; + HeapTupleUpdateValue(pg_foreign_data_wrapper, fdwhandler, ObjectIdGetDatum(fdwhandler), values, nulls, updated); /* * It could be that the behavior of accessing foreign table changes @@ -743,8 +727,7 @@ AlterForeignDataWrapper(ParseState *pstate, AlterFdwStmt *stmt) if (validator_given) { - repl_val[Anum_pg_foreign_data_wrapper_fdwvalidator - 1] = ObjectIdGetDatum(fdwvalidator); - repl_repl[Anum_pg_foreign_data_wrapper_fdwvalidator - 1] = true; + HeapTupleUpdateValue(pg_foreign_data_wrapper, fdwvalidator, ObjectIdGetDatum(fdwvalidator), values, nulls, updated); /* * It could be that existing options for the FDW or dependent SERVER, @@ -784,18 +767,15 @@ AlterForeignDataWrapper(ParseState *pstate, AlterFdwStmt *stmt) fdwvalidator); if (DatumGetPointer(datum) != NULL) - repl_val[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = datum; + HeapTupleUpdateValue(pg_foreign_data_wrapper, fdwoptions, datum, values, nulls, updated); else - repl_null[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = true; - - repl_repl[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = true; + HeapTupleUpdateValueNull(pg_foreign_data_wrapper, fdwoptions, values, nulls, updated); } /* Everything looks good - update the tuple */ - tp = heap_modify_tuple(tp, RelationGetDescr(rel), - repl_val, repl_null, repl_repl); + tp = heap_update_tuple(tp, RelationGetDescr(rel), values, nulls, updated); - CatalogTupleUpdate(rel, &tp->t_self, tp); + CatalogTupleUpdate(rel, &tp->t_self, tp, updated, NULL); heap_freetuple(tp); @@ -837,6 +817,7 @@ AlterForeignDataWrapper(ParseState *pstate, AlterFdwStmt *stmt) InvokeObjectPostAlterHook(ForeignDataWrapperRelationId, fdwId, 0); table_close(rel, RowExclusiveLock); + bms_free(updated); return myself; } @@ -850,8 +831,8 @@ CreateForeignServer(CreateForeignServerStmt *stmt) { Relation rel; Datum srvoptions; - Datum values[Natts_pg_foreign_server]; - bool nulls[Natts_pg_foreign_server]; + Datum values[Natts_pg_foreign_server] = {0}; + bool nulls[Natts_pg_foreign_server] = {false}; HeapTuple tuple; Oid srvId; Oid ownerId; @@ -914,28 +895,25 @@ CreateForeignServer(CreateForeignServerStmt *stmt) srvId = GetNewOidWithIndex(rel, ForeignServerOidIndexId, Anum_pg_foreign_server_oid); - values[Anum_pg_foreign_server_oid - 1] = ObjectIdGetDatum(srvId); - values[Anum_pg_foreign_server_srvname - 1] = - DirectFunctionCall1(namein, CStringGetDatum(stmt->servername)); - values[Anum_pg_foreign_server_srvowner - 1] = ObjectIdGetDatum(ownerId); - values[Anum_pg_foreign_server_srvfdw - 1] = ObjectIdGetDatum(fdw->fdwid); + HeapTupleSetValue(pg_foreign_server, oid, ObjectIdGetDatum(srvId), values); + HeapTupleSetValue(pg_foreign_server, srvname, DirectFunctionCall1(namein, CStringGetDatum(stmt->servername)), values); + HeapTupleSetValue(pg_foreign_server, srvowner, ObjectIdGetDatum(ownerId), values); + HeapTupleSetValue(pg_foreign_server, srvfdw, ObjectIdGetDatum(fdw->fdwid), values); /* Add server type if supplied */ if (stmt->servertype) - values[Anum_pg_foreign_server_srvtype - 1] = - CStringGetTextDatum(stmt->servertype); + HeapTupleSetValue(pg_foreign_server, srvtype, CStringGetTextDatum(stmt->servertype), values); else - nulls[Anum_pg_foreign_server_srvtype - 1] = true; + HeapTupleSetValueNull(pg_foreign_server, srvtype, values, nulls); /* Add server version if supplied */ if (stmt->version) - values[Anum_pg_foreign_server_srvversion - 1] = - CStringGetTextDatum(stmt->version); + HeapTupleSetValue(pg_foreign_server, srvversion, CStringGetTextDatum(stmt->version), values); else - nulls[Anum_pg_foreign_server_srvversion - 1] = true; + HeapTupleSetValueNull(pg_foreign_server, srvversion, values, nulls); /* Start with a blank acl */ - nulls[Anum_pg_foreign_server_srvacl - 1] = true; + HeapTupleSetValueNull(pg_foreign_server, srvacl, values, nulls); /* Add server options */ srvoptions = transformGenericOptions(ForeignServerRelationId, @@ -944,13 +922,13 @@ CreateForeignServer(CreateForeignServerStmt *stmt) fdw->fdwvalidator); if (DatumGetPointer(srvoptions) != NULL) - values[Anum_pg_foreign_server_srvoptions - 1] = srvoptions; + HeapTupleSetValue(pg_foreign_server, srvoptions, srvoptions, values); else - nulls[Anum_pg_foreign_server_srvoptions - 1] = true; + HeapTupleSetValueNull(pg_foreign_server, srvoptions, values, nulls); tuple = heap_form_tuple(rel->rd_att, values, nulls); - CatalogTupleInsert(rel, tuple); + CatalogTupleInsert(rel, tuple, NULL); heap_freetuple(tuple); @@ -986,9 +964,9 @@ AlterForeignServer(AlterForeignServerStmt *stmt) { Relation rel; HeapTuple tp; - Datum repl_val[Natts_pg_foreign_server]; - bool repl_null[Natts_pg_foreign_server]; - bool repl_repl[Natts_pg_foreign_server]; + Datum values[Natts_pg_foreign_server] = {0}; + bool nulls[Natts_pg_foreign_server] = {false}; + Bitmapset *updated = NULL; Oid srvId; Form_pg_foreign_server srvForm; ObjectAddress address; @@ -1013,22 +991,15 @@ AlterForeignServer(AlterForeignServerStmt *stmt) aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_FOREIGN_SERVER, stmt->servername); - memset(repl_val, 0, sizeof(repl_val)); - memset(repl_null, false, sizeof(repl_null)); - memset(repl_repl, false, sizeof(repl_repl)); - if (stmt->has_version) { /* * Change the server VERSION string. */ if (stmt->version) - repl_val[Anum_pg_foreign_server_srvversion - 1] = - CStringGetTextDatum(stmt->version); + HeapTupleUpdateValue(pg_foreign_server, srvversion, CStringGetTextDatum(stmt->version), values, nulls, updated); else - repl_null[Anum_pg_foreign_server_srvversion - 1] = true; - - repl_repl[Anum_pg_foreign_server_srvversion - 1] = true; + HeapTupleUpdateValueNull(pg_foreign_server, srvversion, values, nulls, updated); } if (stmt->options) @@ -1052,18 +1023,15 @@ AlterForeignServer(AlterForeignServerStmt *stmt) fdw->fdwvalidator); if (DatumGetPointer(datum) != NULL) - repl_val[Anum_pg_foreign_server_srvoptions - 1] = datum; + HeapTupleUpdateValue(pg_foreign_server, srvoptions, datum, values, nulls, updated); else - repl_null[Anum_pg_foreign_server_srvoptions - 1] = true; - - repl_repl[Anum_pg_foreign_server_srvoptions - 1] = true; + HeapTupleUpdateValueNull(pg_foreign_server, srvoptions, values, nulls, updated); } /* Everything looks good - update the tuple */ - tp = heap_modify_tuple(tp, RelationGetDescr(rel), - repl_val, repl_null, repl_repl); + tp = heap_update_tuple(tp, RelationGetDescr(rel), values, nulls, updated); - CatalogTupleUpdate(rel, &tp->t_self, tp); + CatalogTupleUpdate(rel, &tp->t_self, tp, updated, NULL); InvokeObjectPostAlterHook(ForeignServerRelationId, srvId, 0); @@ -1072,6 +1040,7 @@ AlterForeignServer(AlterForeignServerStmt *stmt) heap_freetuple(tp); table_close(rel, RowExclusiveLock); + bms_free(updated); return address; } @@ -1112,8 +1081,8 @@ CreateUserMapping(CreateUserMappingStmt *stmt) { Relation rel; Datum useoptions; - Datum values[Natts_pg_user_mapping]; - bool nulls[Natts_pg_user_mapping]; + Datum values[Natts_pg_user_mapping] = {0}; + bool nulls[Natts_pg_user_mapping] = {false}; HeapTuple tuple; Oid useId; Oid umId; @@ -1177,9 +1146,9 @@ CreateUserMapping(CreateUserMappingStmt *stmt) umId = GetNewOidWithIndex(rel, UserMappingOidIndexId, Anum_pg_user_mapping_oid); - values[Anum_pg_user_mapping_oid - 1] = ObjectIdGetDatum(umId); - values[Anum_pg_user_mapping_umuser - 1] = ObjectIdGetDatum(useId); - values[Anum_pg_user_mapping_umserver - 1] = ObjectIdGetDatum(srv->serverid); + HeapTupleSetValue(pg_user_mapping, oid, ObjectIdGetDatum(umId), values); + HeapTupleSetValue(pg_user_mapping, umuser, ObjectIdGetDatum(useId), values); + HeapTupleSetValue(pg_user_mapping, umserver, ObjectIdGetDatum(srv->serverid), values); /* Add user options */ useoptions = transformGenericOptions(UserMappingRelationId, @@ -1188,13 +1157,13 @@ CreateUserMapping(CreateUserMappingStmt *stmt) fdw->fdwvalidator); if (DatumGetPointer(useoptions) != NULL) - values[Anum_pg_user_mapping_umoptions - 1] = useoptions; + HeapTupleSetValue(pg_user_mapping, umoptions, useoptions, values); else - nulls[Anum_pg_user_mapping_umoptions - 1] = true; + HeapTupleSetValueNull(pg_user_mapping, umoptions, values, nulls); tuple = heap_form_tuple(rel->rd_att, values, nulls); - CatalogTupleInsert(rel, tuple); + CatalogTupleInsert(rel, tuple, NULL); heap_freetuple(tuple); @@ -1238,9 +1207,9 @@ AlterUserMapping(AlterUserMappingStmt *stmt) { Relation rel; HeapTuple tp; - Datum repl_val[Natts_pg_user_mapping]; - bool repl_null[Natts_pg_user_mapping]; - bool repl_repl[Natts_pg_user_mapping]; + Datum values[Natts_pg_user_mapping] = {0}; + bool nulls[Natts_pg_user_mapping] = {false}; + Bitmapset *updated = NULL; Oid useId; Oid umId; ForeignServer *srv; @@ -1272,10 +1241,6 @@ AlterUserMapping(AlterUserMappingStmt *stmt) if (!HeapTupleIsValid(tp)) elog(ERROR, "cache lookup failed for user mapping %u", umId); - memset(repl_val, 0, sizeof(repl_val)); - memset(repl_null, false, sizeof(repl_null)); - memset(repl_repl, false, sizeof(repl_repl)); - if (stmt->options) { ForeignDataWrapper *fdw; @@ -1302,18 +1267,15 @@ AlterUserMapping(AlterUserMappingStmt *stmt) fdw->fdwvalidator); if (DatumGetPointer(datum) != NULL) - repl_val[Anum_pg_user_mapping_umoptions - 1] = datum; + HeapTupleUpdateValue(pg_user_mapping, umoptions, datum, values, nulls, updated); else - repl_null[Anum_pg_user_mapping_umoptions - 1] = true; - - repl_repl[Anum_pg_user_mapping_umoptions - 1] = true; + HeapTupleUpdateValueNull(pg_user_mapping, umoptions, values, nulls, updated); } /* Everything looks good - update the tuple */ - tp = heap_modify_tuple(tp, RelationGetDescr(rel), - repl_val, repl_null, repl_repl); + tp = heap_update_tuple(tp, RelationGetDescr(rel), values, nulls, updated); - CatalogTupleUpdate(rel, &tp->t_self, tp); + CatalogTupleUpdate(rel, &tp->t_self, tp, updated, NULL); InvokeObjectPostAlterHook(UserMappingRelationId, umId, 0); @@ -1323,6 +1285,7 @@ AlterUserMapping(AlterUserMappingStmt *stmt) heap_freetuple(tp); table_close(rel, RowExclusiveLock); + bms_free(updated); return address; } @@ -1416,8 +1379,8 @@ CreateForeignTable(CreateForeignTableStmt *stmt, Oid relid) { Relation ftrel; Datum ftoptions; - Datum values[Natts_pg_foreign_table]; - bool nulls[Natts_pg_foreign_table]; + Datum values[Natts_pg_foreign_table] = {0}; + bool nulls[Natts_pg_foreign_table] = {false}; HeapTuple tuple; AclResult aclresult; ObjectAddress myself; @@ -1456,8 +1419,8 @@ CreateForeignTable(CreateForeignTableStmt *stmt, Oid relid) memset(values, 0, sizeof(values)); memset(nulls, false, sizeof(nulls)); - values[Anum_pg_foreign_table_ftrelid - 1] = ObjectIdGetDatum(relid); - values[Anum_pg_foreign_table_ftserver - 1] = ObjectIdGetDatum(server->serverid); + HeapTupleSetValue(pg_foreign_table, ftrelid, ObjectIdGetDatum(relid), values); + HeapTupleSetValue(pg_foreign_table, ftserver, ObjectIdGetDatum(server->serverid), values); /* Add table generic options */ ftoptions = transformGenericOptions(ForeignTableRelationId, PointerGetDatum(NULL), @@ -1465,13 +1428,13 @@ CreateForeignTable(CreateForeignTableStmt *stmt, Oid relid) fdw->fdwvalidator); if (DatumGetPointer(ftoptions) != NULL) - values[Anum_pg_foreign_table_ftoptions - 1] = ftoptions; + HeapTupleSetValue(pg_foreign_table, ftoptions, ftoptions, values); else - nulls[Anum_pg_foreign_table_ftoptions - 1] = true; + HeapTupleSetValueNull(pg_foreign_table, ftoptions, values, nulls); tuple = heap_form_tuple(ftrel->rd_att, values, nulls); - CatalogTupleInsert(ftrel, tuple); + CatalogTupleInsert(ftrel, tuple, NULL); heap_freetuple(tuple); diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c index 0335e982b318b..b530c3aabf0e3 100644 --- a/src/backend/commands/functioncmds.c +++ b/src/backend/commands/functioncmds.c @@ -1375,6 +1375,7 @@ AlterFunction(ParseState *pstate, AlterFunctionStmt *stmt) DefElem *rows_item = NULL; DefElem *support_item = NULL; DefElem *parallel_item = NULL; + Bitmapset *updated = NULL; ObjectAddress address; rel = table_open(ProcedureRelationId, RowExclusiveLock); @@ -1489,9 +1490,8 @@ AlterFunction(ParseState *pstate, AlterFunctionStmt *stmt) Datum datum; bool isnull; ArrayType *a; - Datum repl_val[Natts_pg_proc]; - bool repl_null[Natts_pg_proc]; - bool repl_repl[Natts_pg_proc]; + Datum values[Natts_pg_proc] = {0}; + bool nulls[Natts_pg_proc] = {false}; /* extract existing proconfig setting */ datum = SysCacheGetAttr(PROCOID, tup, Anum_pg_proc_proconfig, &isnull); @@ -1501,27 +1501,19 @@ AlterFunction(ParseState *pstate, AlterFunctionStmt *stmt) a = update_proconfig_value(a, set_items); /* update the tuple */ - memset(repl_repl, false, sizeof(repl_repl)); - repl_repl[Anum_pg_proc_proconfig - 1] = true; - if (a == NULL) - { - repl_val[Anum_pg_proc_proconfig - 1] = (Datum) 0; - repl_null[Anum_pg_proc_proconfig - 1] = true; - } + HeapTupleUpdateValueNull(pg_proc, proconfig, values, nulls, updated); else - { - repl_val[Anum_pg_proc_proconfig - 1] = PointerGetDatum(a); - repl_null[Anum_pg_proc_proconfig - 1] = false; - } + HeapTupleUpdateValue(pg_proc, proconfig, PointerGetDatum(a), values, nulls, updated); - tup = heap_modify_tuple(tup, RelationGetDescr(rel), - repl_val, repl_null, repl_repl); + tup = heap_update_tuple(tup, RelationGetDescr(rel), + values, nulls, updated); } /* DO NOT put more touches of procForm below here; it's now dangling. */ /* Do the update */ - CatalogTupleUpdate(rel, &tup->t_self, tup); + CatalogTupleUpdate(rel, &tup->t_self, tup, updated, NULL); + bms_free(updated); InvokeObjectPostAlterHook(ProcedureRelationId, funcOid, 0); @@ -1838,9 +1830,9 @@ CreateTransform(CreateTransformStmt *stmt) Oid tosqlfuncid; AclResult aclresult; Form_pg_proc procstruct; - Datum values[Natts_pg_transform]; - bool nulls[Natts_pg_transform] = {0}; - bool replaces[Natts_pg_transform] = {0}; + Datum values[Natts_pg_transform] = {0}; + bool nulls[Natts_pg_transform] = {false}; + Bitmapset *updated = NULL; Oid transformid; HeapTuple tuple; HeapTuple newtuple; @@ -1941,10 +1933,10 @@ CreateTransform(CreateTransformStmt *stmt) /* * Ready to go */ - values[Anum_pg_transform_trftype - 1] = ObjectIdGetDatum(typeid); - values[Anum_pg_transform_trflang - 1] = ObjectIdGetDatum(langid); - values[Anum_pg_transform_trffromsql - 1] = ObjectIdGetDatum(fromsqlfuncid); - values[Anum_pg_transform_trftosql - 1] = ObjectIdGetDatum(tosqlfuncid); + HeapTupleUpdateValue(pg_transform, trftype, ObjectIdGetDatum(typeid), values, nulls, updated); + HeapTupleUpdateValue(pg_transform, trflang, ObjectIdGetDatum(langid), values, nulls, updated); + HeapTupleUpdateValue(pg_transform, trffromsql, ObjectIdGetDatum(fromsqlfuncid), values, nulls, updated); + HeapTupleUpdateValue(pg_transform, trftosql, ObjectIdGetDatum(tosqlfuncid), values, nulls, updated); relation = table_open(TransformRelationId, RowExclusiveLock); @@ -1962,11 +1954,8 @@ CreateTransform(CreateTransformStmt *stmt) format_type_be(typeid), stmt->lang))); - replaces[Anum_pg_transform_trffromsql - 1] = true; - replaces[Anum_pg_transform_trftosql - 1] = true; - - newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values, nulls, replaces); - CatalogTupleUpdate(relation, &newtuple->t_self, newtuple); + newtuple = heap_update_tuple(tuple, RelationGetDescr(relation), values, nulls, updated); + CatalogTupleUpdate(relation, &newtuple->t_self, newtuple, updated, NULL); transformid = form->oid; ReleaseSysCache(tuple); @@ -1976,9 +1965,9 @@ CreateTransform(CreateTransformStmt *stmt) { transformid = GetNewOidWithIndex(relation, TransformOidIndexId, Anum_pg_transform_oid); - values[Anum_pg_transform_oid - 1] = ObjectIdGetDatum(transformid); + HeapTupleUpdateValue(pg_transform, oid, ObjectIdGetDatum(transformid), values, nulls, updated); newtuple = heap_form_tuple(RelationGetDescr(relation), values, nulls); - CatalogTupleInsert(relation, newtuple); + CatalogTupleInsert(relation, newtuple, NULL); is_replace = false; } @@ -2020,6 +2009,7 @@ CreateTransform(CreateTransformStmt *stmt) InvokeObjectPostCreateHook(TransformRelationId, transformid, 0); heap_freetuple(newtuple); + bms_free(updated); table_close(relation, RowExclusiveLock); diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 5712fac36971e..26309495ba968 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -1553,6 +1553,8 @@ DefineIndex(Oid tableId, Relation pg_index = table_open(IndexRelationId, RowExclusiveLock); HeapTuple tup, newtup; + Form_pg_index indexForm; + Bitmapset *updated = NULL; tup = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexRelationId)); @@ -1560,8 +1562,10 @@ DefineIndex(Oid tableId, elog(ERROR, "cache lookup failed for index %u", indexRelationId); newtup = heap_copytuple(tup); - ((Form_pg_index) GETSTRUCT(newtup))->indisvalid = false; - CatalogTupleUpdate(pg_index, &tup->t_self, newtup); + indexForm = (Form_pg_index) GETSTRUCT(newtup); + HeapTupleUpdateField(pg_index, indisvalid, false, indexForm, updated); + CatalogTupleUpdate(pg_index, &tup->t_self, newtup, updated, NULL); + bms_free(updated); ReleaseSysCache(tup); table_close(pg_index, RowExclusiveLock); heap_freetuple(newtup); @@ -4576,6 +4580,8 @@ update_relispartition(Oid relationId, bool newval) HeapTuple tup; Relation classRel; ItemPointerData otid; + Form_pg_class classForm; + Bitmapset *updated = NULL; classRel = table_open(RelationRelationId, RowExclusiveLock); tup = SearchSysCacheLockedCopy1(RELOID, ObjectIdGetDatum(relationId)); @@ -4583,8 +4589,10 @@ update_relispartition(Oid relationId, bool newval) elog(ERROR, "cache lookup failed for relation %u", relationId); otid = tup->t_self; Assert(((Form_pg_class) GETSTRUCT(tup))->relispartition != newval); - ((Form_pg_class) GETSTRUCT(tup))->relispartition = newval; - CatalogTupleUpdate(classRel, &otid, tup); + classForm = (Form_pg_class) GETSTRUCT(tup); + HeapTupleUpdateField(pg_class, relispartition, newval, classForm, updated); + CatalogTupleUpdate(classRel, &otid, tup, updated, NULL); + bms_free(updated); UnlockTuple(classRel, &otid, InplaceUpdateTupleLock); heap_freetuple(tup); table_close(classRel, RowExclusiveLock); diff --git a/src/backend/commands/matview.c b/src/backend/commands/matview.c index ef7c0d624f139..d4da53083734f 100644 --- a/src/backend/commands/matview.c +++ b/src/backend/commands/matview.c @@ -79,6 +79,7 @@ SetMatViewPopulatedState(Relation relation, bool newstate) { Relation pgrel; HeapTuple tuple; + Bitmapset *updated = NULL; Assert(relation->rd_rel->relkind == RELKIND_MATVIEW); @@ -94,12 +95,12 @@ SetMatViewPopulatedState(Relation relation, bool newstate) elog(ERROR, "cache lookup failed for relation %u", RelationGetRelid(relation)); - ((Form_pg_class) GETSTRUCT(tuple))->relispopulated = newstate; - - CatalogTupleUpdate(pgrel, &tuple->t_self, tuple); + HeapTupleUpdateField(pg_class, relispopulated, newstate, (Form_pg_class) GETSTRUCT(tuple), updated); + CatalogTupleUpdate(pgrel, &tuple->t_self, tuple, updated, NULL); heap_freetuple(tuple); table_close(pgrel, RowExclusiveLock); + bms_free(updated); /* * Advance command counter to make the updated pg_class row locally diff --git a/src/backend/commands/opclasscmds.c b/src/backend/commands/opclasscmds.c index a6dd8eab5186b..38648c340abad 100644 --- a/src/backend/commands/opclasscmds.c +++ b/src/backend/commands/opclasscmds.c @@ -246,8 +246,8 @@ CreateOpFamily(CreateOpFamilyStmt *stmt, const char *opfname, Oid opfamilyoid; Relation rel; HeapTuple tup; - Datum values[Natts_pg_opfamily]; - bool nulls[Natts_pg_opfamily]; + Datum values[Natts_pg_opfamily] = {0}; + bool nulls[Natts_pg_opfamily] = {false}; NameData opfName; ObjectAddress myself, referenced; @@ -275,16 +275,16 @@ CreateOpFamily(CreateOpFamilyStmt *stmt, const char *opfname, opfamilyoid = GetNewOidWithIndex(rel, OpfamilyOidIndexId, Anum_pg_opfamily_oid); - values[Anum_pg_opfamily_oid - 1] = ObjectIdGetDatum(opfamilyoid); - values[Anum_pg_opfamily_opfmethod - 1] = ObjectIdGetDatum(amoid); + HeapTupleSetValue(pg_opfamily, oid, ObjectIdGetDatum(opfamilyoid), values); + HeapTupleSetValue(pg_opfamily, opfmethod, ObjectIdGetDatum(amoid), values); namestrcpy(&opfName, opfname); - values[Anum_pg_opfamily_opfname - 1] = NameGetDatum(&opfName); - values[Anum_pg_opfamily_opfnamespace - 1] = ObjectIdGetDatum(namespaceoid); - values[Anum_pg_opfamily_opfowner - 1] = ObjectIdGetDatum(GetUserId()); + HeapTupleSetValue(pg_opfamily, opfname, NameGetDatum(&opfName), values); + HeapTupleSetValue(pg_opfamily, opfnamespace, ObjectIdGetDatum(namespaceoid), values); + HeapTupleSetValue(pg_opfamily, opfowner, ObjectIdGetDatum(GetUserId()), values); tup = heap_form_tuple(rel->rd_att, values, nulls); - CatalogTupleInsert(rel, tup); + CatalogTupleInsert(rel, tup, NULL); heap_freetuple(tup); @@ -350,8 +350,8 @@ DefineOpClass(CreateOpClassStmt *stmt) HeapTuple tup; Form_pg_am amform; IndexAmRoutine *amroutine; - Datum values[Natts_pg_opclass]; - bool nulls[Natts_pg_opclass]; + Datum values[Natts_pg_opclass] = {0}; + bool nulls[Natts_pg_opclass] = {false}; AclResult aclresult; NameData opcName; ObjectAddress myself, @@ -653,20 +653,20 @@ DefineOpClass(CreateOpClassStmt *stmt) opclassoid = GetNewOidWithIndex(rel, OpclassOidIndexId, Anum_pg_opclass_oid); - values[Anum_pg_opclass_oid - 1] = ObjectIdGetDatum(opclassoid); - values[Anum_pg_opclass_opcmethod - 1] = ObjectIdGetDatum(amoid); + HeapTupleSetValue(pg_opclass, oid, ObjectIdGetDatum(opclassoid), values); + HeapTupleSetValue(pg_opclass, opcmethod, ObjectIdGetDatum(amoid), values); namestrcpy(&opcName, opcname); - values[Anum_pg_opclass_opcname - 1] = NameGetDatum(&opcName); - values[Anum_pg_opclass_opcnamespace - 1] = ObjectIdGetDatum(namespaceoid); - values[Anum_pg_opclass_opcowner - 1] = ObjectIdGetDatum(GetUserId()); - values[Anum_pg_opclass_opcfamily - 1] = ObjectIdGetDatum(opfamilyoid); - values[Anum_pg_opclass_opcintype - 1] = ObjectIdGetDatum(typeoid); - values[Anum_pg_opclass_opcdefault - 1] = BoolGetDatum(stmt->isDefault); - values[Anum_pg_opclass_opckeytype - 1] = ObjectIdGetDatum(storageoid); + HeapTupleSetValue(pg_opclass, opcname, NameGetDatum(&opcName), values); + HeapTupleSetValue(pg_opclass, opcnamespace, ObjectIdGetDatum(namespaceoid), values); + HeapTupleSetValue(pg_opclass, opcowner, ObjectIdGetDatum(GetUserId()), values); + HeapTupleSetValue(pg_opclass, opcfamily, ObjectIdGetDatum(opfamilyoid), values); + HeapTupleSetValue(pg_opclass, opcintype, ObjectIdGetDatum(typeoid), values); + HeapTupleSetValue(pg_opclass, opcdefault, BoolGetDatum(stmt->isDefault), values); + HeapTupleSetValue(pg_opclass, opckeytype, ObjectIdGetDatum(storageoid), values); tup = heap_form_tuple(rel->rd_att, values, nulls); - CatalogTupleInsert(rel, tup); + CatalogTupleInsert(rel, tup, NULL); heap_freetuple(tup); @@ -1455,8 +1455,8 @@ storeOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid, List *operators, bool isAdd) { Relation rel; - Datum values[Natts_pg_amop]; - bool nulls[Natts_pg_amop]; + Datum values[Natts_pg_amop] = {0}; + bool nulls[Natts_pg_amop] = {false}; HeapTuple tup; Oid entryoid; ObjectAddress myself, @@ -1496,19 +1496,19 @@ storeOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid, entryoid = GetNewOidWithIndex(rel, AccessMethodOperatorOidIndexId, Anum_pg_amop_oid); - values[Anum_pg_amop_oid - 1] = ObjectIdGetDatum(entryoid); - values[Anum_pg_amop_amopfamily - 1] = ObjectIdGetDatum(opfamilyoid); - values[Anum_pg_amop_amoplefttype - 1] = ObjectIdGetDatum(op->lefttype); - values[Anum_pg_amop_amoprighttype - 1] = ObjectIdGetDatum(op->righttype); - values[Anum_pg_amop_amopstrategy - 1] = Int16GetDatum(op->number); - values[Anum_pg_amop_amoppurpose - 1] = CharGetDatum(oppurpose); - values[Anum_pg_amop_amopopr - 1] = ObjectIdGetDatum(op->object); - values[Anum_pg_amop_amopmethod - 1] = ObjectIdGetDatum(amoid); - values[Anum_pg_amop_amopsortfamily - 1] = ObjectIdGetDatum(op->sortfamily); + HeapTupleSetValue(pg_amop, oid, ObjectIdGetDatum(entryoid), values); + HeapTupleSetValue(pg_amop, amopfamily, ObjectIdGetDatum(opfamilyoid), values); + HeapTupleSetValue(pg_amop, amoplefttype, ObjectIdGetDatum(op->lefttype), values); + HeapTupleSetValue(pg_amop, amoprighttype, ObjectIdGetDatum(op->righttype), values); + HeapTupleSetValue(pg_amop, amopstrategy, Int16GetDatum(op->number), values); + HeapTupleSetValue(pg_amop, amoppurpose, CharGetDatum(oppurpose), values); + HeapTupleSetValue(pg_amop, amopopr, ObjectIdGetDatum(op->object), values); + HeapTupleSetValue(pg_amop, amopmethod, ObjectIdGetDatum(amoid), values); + HeapTupleSetValue(pg_amop, amopsortfamily, ObjectIdGetDatum(op->sortfamily), values); tup = heap_form_tuple(rel->rd_att, values, nulls); - CatalogTupleInsert(rel, tup); + CatalogTupleInsert(rel, tup, NULL); heap_freetuple(tup); @@ -1585,8 +1585,8 @@ storeProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid, List *procedures, bool isAdd) { Relation rel; - Datum values[Natts_pg_amproc]; - bool nulls[Natts_pg_amproc]; + Datum values[Natts_pg_amproc] = {0}; + bool nulls[Natts_pg_amproc] = {false}; HeapTuple tup; Oid entryoid; ObjectAddress myself, @@ -1623,16 +1623,16 @@ storeProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid, entryoid = GetNewOidWithIndex(rel, AccessMethodProcedureOidIndexId, Anum_pg_amproc_oid); - values[Anum_pg_amproc_oid - 1] = ObjectIdGetDatum(entryoid); - values[Anum_pg_amproc_amprocfamily - 1] = ObjectIdGetDatum(opfamilyoid); - values[Anum_pg_amproc_amproclefttype - 1] = ObjectIdGetDatum(proc->lefttype); - values[Anum_pg_amproc_amprocrighttype - 1] = ObjectIdGetDatum(proc->righttype); - values[Anum_pg_amproc_amprocnum - 1] = Int16GetDatum(proc->number); - values[Anum_pg_amproc_amproc - 1] = ObjectIdGetDatum(proc->object); + HeapTupleSetValue(pg_amproc, oid, ObjectIdGetDatum(entryoid), values); + HeapTupleSetValue(pg_amproc, amprocfamily, ObjectIdGetDatum(opfamilyoid), values); + HeapTupleSetValue(pg_amproc, amproclefttype, ObjectIdGetDatum(proc->lefttype), values); + HeapTupleSetValue(pg_amproc, amprocrighttype, ObjectIdGetDatum(proc->righttype), values); + HeapTupleSetValue(pg_amproc, amprocnum, Int16GetDatum(proc->number), values); + HeapTupleSetValue(pg_amproc, amproc, ObjectIdGetDatum(proc->object), values); tup = heap_form_tuple(rel->rd_att, values, nulls); - CatalogTupleInsert(rel, tup); + CatalogTupleInsert(rel, tup, NULL); heap_freetuple(tup); diff --git a/src/backend/commands/operatorcmds.c b/src/backend/commands/operatorcmds.c index 673648f1fc6f5..649c37b80ae1f 100644 --- a/src/backend/commands/operatorcmds.c +++ b/src/backend/commands/operatorcmds.c @@ -466,11 +466,9 @@ AlterOperator(AlterOperatorStmt *stmt) Relation catalog; HeapTuple tup; Form_pg_operator oprForm; - int i; ListCell *pl; - Datum values[Natts_pg_operator]; - bool nulls[Natts_pg_operator]; - bool replaces[Natts_pg_operator]; + Datum values[Natts_pg_operator] = {0}; + bool nulls[Natts_pg_operator] = {false}; List *restrictionName = NIL; /* optional restrict. sel. function */ bool updateRestriction = false; Oid restrictionOid; @@ -485,6 +483,7 @@ AlterOperator(AlterOperatorStmt *stmt) bool updateMerges = false; bool canHash = false; bool updateHashes = false; + Bitmapset *updated = NULL; /* Look up the operator */ oprId = LookupOperWithArgs(stmt->opername, false); @@ -646,47 +645,27 @@ AlterOperator(AlterOperatorStmt *stmt) canHash); /* Update the tuple */ - for (i = 0; i < Natts_pg_operator; ++i) - { - values[i] = (Datum) 0; - replaces[i] = false; - nulls[i] = false; - } if (updateRestriction) - { - replaces[Anum_pg_operator_oprrest - 1] = true; - values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(restrictionOid); - } + HeapTupleUpdateValue(pg_operator, oprrest, ObjectIdGetDatum(restrictionOid), values, nulls, updated); + if (updateJoin) - { - replaces[Anum_pg_operator_oprjoin - 1] = true; - values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(joinOid); - } + HeapTupleUpdateValue(pg_operator, oprjoin, ObjectIdGetDatum(joinOid), values, nulls, updated); + if (OidIsValid(commutatorOid)) - { - replaces[Anum_pg_operator_oprcom - 1] = true; - values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(commutatorOid); - } + HeapTupleUpdateValue(pg_operator, oprcom, ObjectIdGetDatum(commutatorOid), values, nulls, updated); + if (OidIsValid(negatorOid)) - { - replaces[Anum_pg_operator_oprnegate - 1] = true; - values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(negatorOid); - } + HeapTupleUpdateValue(pg_operator, oprnegate, ObjectIdGetDatum(negatorOid), values, nulls, updated); + if (updateMerges) - { - replaces[Anum_pg_operator_oprcanmerge - 1] = true; - values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(canMerge); - } + HeapTupleUpdateValue(pg_operator, oprcanmerge, BoolGetDatum(canMerge), values, nulls, updated); + if (updateHashes) - { - replaces[Anum_pg_operator_oprcanhash - 1] = true; - values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(canHash); - } + HeapTupleUpdateValue(pg_operator, oprcanhash, BoolGetDatum(canHash), values, nulls, updated); - tup = heap_modify_tuple(tup, RelationGetDescr(catalog), - values, nulls, replaces); + tup = heap_update_tuple(tup, RelationGetDescr(catalog), values, nulls, updated); - CatalogTupleUpdate(catalog, &tup->t_self, tup); + CatalogTupleUpdate(catalog, &tup->t_self, tup, updated, NULL); address = makeOperatorDependencies(tup, false, true); @@ -696,6 +675,7 @@ AlterOperator(AlterOperatorStmt *stmt) InvokeObjectPostAlterHook(OperatorRelationId, oprId, 0); table_close(catalog, NoLock); + bms_free(updated); return address; } diff --git a/src/backend/commands/policy.c b/src/backend/commands/policy.c index 83056960fe47e..10c7857ade5cb 100644 --- a/src/backend/commands/policy.c +++ b/src/backend/commands/policy.c @@ -427,6 +427,7 @@ RemoveRoleFromObjectPolicy(Oid roleid, Oid classid, Oid policy_id) Datum *role_oids; bool attr_isnull; bool keep_policy = true; + Bitmapset *updated = NULL; int i, j; @@ -483,29 +484,19 @@ RemoveRoleFromObjectPolicy(Oid roleid, Oid classid, Oid policy_id) if (num_roles > 0) { ArrayType *role_ids; - Datum values[Natts_pg_policy]; - bool isnull[Natts_pg_policy]; - bool replaces[Natts_pg_policy]; + Datum values[Natts_pg_policy] = {0}; + bool nulls[Natts_pg_policy] = {false}; HeapTuple new_tuple; HeapTuple reltup; ObjectAddress target; ObjectAddress myself; - /* zero-clear */ - memset(values, 0, sizeof(values)); - memset(replaces, 0, sizeof(replaces)); - memset(isnull, 0, sizeof(isnull)); - /* This is the array for the new tuple */ role_ids = construct_array_builtin(role_oids, num_roles, OIDOID); - replaces[Anum_pg_policy_polroles - 1] = true; - values[Anum_pg_policy_polroles - 1] = PointerGetDatum(role_ids); - - new_tuple = heap_modify_tuple(tuple, - RelationGetDescr(pg_policy_rel), - values, isnull, replaces); - CatalogTupleUpdate(pg_policy_rel, &new_tuple->t_self, new_tuple); + HeapTupleUpdateValue(pg_policy, polroles, PointerGetDatum(role_ids), values, nulls, updated); + new_tuple = heap_update_tuple(tuple, RelationGetDescr(pg_policy_rel), values, nulls, updated); + CatalogTupleUpdate(pg_policy_rel, &new_tuple->t_self, new_tuple, updated, NULL); /* Remove all the old shared dependencies (roles) */ deleteSharedDependencyRecordsFor(PolicyRelationId, policy_id, 0); @@ -552,8 +543,8 @@ RemoveRoleFromObjectPolicy(Oid roleid, Oid classid, Oid policy_id) } /* Clean up. */ + bms_free(updated); systable_endscan(sscan); - table_close(pg_policy_rel, RowExclusiveLock); return keep_policy; @@ -584,8 +575,8 @@ CreatePolicy(CreatePolicyStmt *stmt) ScanKeyData skey[2]; SysScanDesc sscan; HeapTuple policy_tuple; - Datum values[Natts_pg_policy]; - bool isnull[Natts_pg_policy]; + Datum values[Natts_pg_policy] = {0}; + bool nulls[Natts_pg_policy] = {false}; ObjectAddress target; ObjectAddress myself; int i; @@ -619,10 +610,6 @@ CreatePolicy(CreatePolicyStmt *stmt) qual_pstate = make_parsestate(NULL); with_check_pstate = make_parsestate(NULL); - /* zero-clear */ - memset(values, 0, sizeof(values)); - memset(isnull, 0, sizeof(isnull)); - /* Get id of table. Also handles permissions checks. */ table_id = RangeVarGetRelidExtended(stmt->table, AccessExclusiveLock, 0, @@ -688,30 +675,29 @@ CreatePolicy(CreatePolicyStmt *stmt) policy_id = GetNewOidWithIndex(pg_policy_rel, PolicyOidIndexId, Anum_pg_policy_oid); - values[Anum_pg_policy_oid - 1] = ObjectIdGetDatum(policy_id); - values[Anum_pg_policy_polrelid - 1] = ObjectIdGetDatum(table_id); - values[Anum_pg_policy_polname - 1] = DirectFunctionCall1(namein, - CStringGetDatum(stmt->policy_name)); - values[Anum_pg_policy_polcmd - 1] = CharGetDatum(polcmd); - values[Anum_pg_policy_polpermissive - 1] = BoolGetDatum(stmt->permissive); - values[Anum_pg_policy_polroles - 1] = PointerGetDatum(role_ids); + HeapTupleSetValue(pg_policy, oid, ObjectIdGetDatum(policy_id), values); + HeapTupleSetValue(pg_policy, polrelid, ObjectIdGetDatum(table_id), values); + HeapTupleSetValue(pg_policy, polname, DirectFunctionCall1(namein, + CStringGetDatum(stmt->policy_name)), values); + HeapTupleSetValue(pg_policy, polcmd, CharGetDatum(polcmd), values); + HeapTupleSetValue(pg_policy, polpermissive, BoolGetDatum(stmt->permissive), values); + HeapTupleSetValue(pg_policy, polroles, PointerGetDatum(role_ids), values); /* Add qual if present. */ if (qual) - values[Anum_pg_policy_polqual - 1] = CStringGetTextDatum(nodeToString(qual)); + HeapTupleSetValue(pg_policy, polqual, CStringGetTextDatum(nodeToString(qual)), values); else - isnull[Anum_pg_policy_polqual - 1] = true; + HeapTupleSetValueNull(pg_policy, polqual, values, nulls); /* Add WITH CHECK qual if present */ if (with_check_qual) - values[Anum_pg_policy_polwithcheck - 1] = CStringGetTextDatum(nodeToString(with_check_qual)); + HeapTupleSetValue(pg_policy, polwithcheck, CStringGetTextDatum(nodeToString(with_check_qual)), values); else - isnull[Anum_pg_policy_polwithcheck - 1] = true; + HeapTupleSetValueNull(pg_policy, polwithcheck, values, nulls); - policy_tuple = heap_form_tuple(RelationGetDescr(pg_policy_rel), values, - isnull); + policy_tuple = heap_form_tuple(RelationGetDescr(pg_policy_rel), values, nulls); - CatalogTupleInsert(pg_policy_rel, policy_tuple); + CatalogTupleInsert(pg_policy_rel, policy_tuple, NULL); /* Record Dependencies */ target.classId = RelationRelationId; @@ -782,9 +768,9 @@ AlterPolicy(AlterPolicyStmt *stmt) SysScanDesc sscan; HeapTuple policy_tuple; HeapTuple new_tuple; - Datum values[Natts_pg_policy]; - bool isnull[Natts_pg_policy]; - bool replaces[Natts_pg_policy]; + Datum values[Natts_pg_policy] = {0}; + bool nulls[Natts_pg_policy] = {false}; + Bitmapset *updated = NULL; ObjectAddress target; ObjectAddress myself; Datum polcmd_datum; @@ -854,11 +840,6 @@ AlterPolicy(AlterPolicyStmt *stmt) free_parsestate(with_check_pstate); } - /* zero-clear */ - memset(values, 0, sizeof(values)); - memset(replaces, 0, sizeof(replaces)); - memset(isnull, 0, sizeof(isnull)); - /* Find policy to update. */ pg_policy_rel = table_open(PolicyRelationId, RowExclusiveLock); @@ -918,8 +899,7 @@ AlterPolicy(AlterPolicyStmt *stmt) if (role_ids != NULL) { - replaces[Anum_pg_policy_polroles - 1] = true; - values[Anum_pg_policy_polroles - 1] = PointerGetDatum(role_ids); + HeapTupleUpdateValue(pg_policy, polroles, PointerGetDatum(role_ids), values, nulls, updated); } else { @@ -953,9 +933,7 @@ AlterPolicy(AlterPolicyStmt *stmt) if (qual != NULL) { - replaces[Anum_pg_policy_polqual - 1] = true; - values[Anum_pg_policy_polqual - 1] - = CStringGetTextDatum(nodeToString(qual)); + HeapTupleUpdateValue(pg_policy, polqual, CStringGetTextDatum(nodeToString(qual)), values, nulls, updated); } else { @@ -995,9 +973,7 @@ AlterPolicy(AlterPolicyStmt *stmt) if (with_check_qual != NULL) { - replaces[Anum_pg_policy_polwithcheck - 1] = true; - values[Anum_pg_policy_polwithcheck - 1] - = CStringGetTextDatum(nodeToString(with_check_qual)); + HeapTupleUpdateValue(pg_policy, polwithcheck, CStringGetTextDatum(nodeToString(with_check_qual)), values, nulls, updated); } else { @@ -1036,10 +1012,10 @@ AlterPolicy(AlterPolicyStmt *stmt) } } - new_tuple = heap_modify_tuple(policy_tuple, + new_tuple = heap_update_tuple(policy_tuple, RelationGetDescr(pg_policy_rel), - values, isnull, replaces); - CatalogTupleUpdate(pg_policy_rel, &new_tuple->t_self, new_tuple); + values, nulls, updated); + CatalogTupleUpdate(pg_policy_rel, &new_tuple->t_self, new_tuple, updated, NULL); /* Update Dependencies. */ deleteDependencyRecordsFor(PolicyRelationId, policy_id, false); @@ -1081,6 +1057,7 @@ AlterPolicy(AlterPolicyStmt *stmt) CacheInvalidateRelcache(target_table); /* Clean up. */ + bms_free(updated); systable_endscan(sscan); relation_close(target_table, NoLock); table_close(pg_policy_rel, RowExclusiveLock); @@ -1102,6 +1079,8 @@ rename_policy(RenameStmt *stmt) ScanKeyData skey[2]; SysScanDesc sscan; HeapTuple policy_tuple; + Form_pg_policy polform; + Bitmapset *updated = NULL; ObjectAddress address; /* Get id of table. Also handles permissions checks. */ @@ -1169,11 +1148,12 @@ rename_policy(RenameStmt *stmt) opoloid = ((Form_pg_policy) GETSTRUCT(policy_tuple))->oid; policy_tuple = heap_copytuple(policy_tuple); + polform = (Form_pg_policy) GETSTRUCT(policy_tuple); + namestrcpy(&polform->polname, stmt->newname); + HeapTupleMarkColumnUpdated(pg_policy, polname, updated); - namestrcpy(&((Form_pg_policy) GETSTRUCT(policy_tuple))->polname, - stmt->newname); - - CatalogTupleUpdate(pg_policy_rel, &policy_tuple->t_self, policy_tuple); + CatalogTupleUpdate(pg_policy_rel, &policy_tuple->t_self, policy_tuple, updated, NULL); + bms_free(updated); InvokeObjectPostAlterHook(PolicyRelationId, opoloid, 0); diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c index d75e2fa74b297..1eab77755370f 100644 --- a/src/backend/commands/proclang.c +++ b/src/backend/commands/proclang.c @@ -46,9 +46,9 @@ CreateProceduralLanguage(CreatePLangStmt *stmt) Oid funcargtypes[1]; Relation rel; TupleDesc tupDesc; - Datum values[Natts_pg_language]; - bool nulls[Natts_pg_language]; - bool replaces[Natts_pg_language]; + Datum values[Natts_pg_language] = {0}; + bool nulls[Natts_pg_language] = {false}; + Bitmapset *updated = NULL; NameData langname; HeapTuple oldtup; HeapTuple tup; @@ -104,19 +104,15 @@ CreateProceduralLanguage(CreatePLangStmt *stmt) tupDesc = RelationGetDescr(rel); /* Prepare data to be inserted */ - memset(values, 0, sizeof(values)); - memset(nulls, false, sizeof(nulls)); - memset(replaces, true, sizeof(replaces)); - namestrcpy(&langname, languageName); - values[Anum_pg_language_lanname - 1] = NameGetDatum(&langname); - values[Anum_pg_language_lanowner - 1] = ObjectIdGetDatum(languageOwner); - values[Anum_pg_language_lanispl - 1] = BoolGetDatum(true); - values[Anum_pg_language_lanpltrusted - 1] = BoolGetDatum(stmt->pltrusted); - values[Anum_pg_language_lanplcallfoid - 1] = ObjectIdGetDatum(handlerOid); - values[Anum_pg_language_laninline - 1] = ObjectIdGetDatum(inlineOid); - values[Anum_pg_language_lanvalidator - 1] = ObjectIdGetDatum(valOid); - nulls[Anum_pg_language_lanacl - 1] = true; + HeapTupleUpdateValue(pg_language, lanname, NameGetDatum(&langname), values, nulls, updated); + HeapTupleUpdateValue(pg_language, lanowner, ObjectIdGetDatum(languageOwner), values, nulls, updated); + HeapTupleUpdateValue(pg_language, lanispl, BoolGetDatum(true), values, nulls, updated); + HeapTupleUpdateValue(pg_language, lanpltrusted, BoolGetDatum(stmt->pltrusted), values, nulls, updated); + HeapTupleUpdateValue(pg_language, lanplcallfoid, ObjectIdGetDatum(handlerOid), values, nulls, updated); + HeapTupleUpdateValue(pg_language, laninline, ObjectIdGetDatum(inlineOid), values, nulls, updated); + HeapTupleUpdateValue(pg_language, lanvalidator, ObjectIdGetDatum(valOid), values, nulls, updated); + HeapTupleUpdateValueNull(pg_language, lanacl, values, nulls, updated); /* Check for pre-existing definition */ oldtup = SearchSysCache1(LANGNAME, PointerGetDatum(languageName)); @@ -142,13 +138,13 @@ CreateProceduralLanguage(CreatePLangStmt *stmt) * Do not change existing oid, ownership or permissions. Note * dependency-update code below has to agree with this decision. */ - replaces[Anum_pg_language_oid - 1] = false; - replaces[Anum_pg_language_lanowner - 1] = false; - replaces[Anum_pg_language_lanacl - 1] = false; + HeapTupleSetColumnNotUpdated(pg_language, oid, updated); + HeapTupleSetColumnNotUpdated(pg_language, lanowner, updated); + HeapTupleSetColumnNotUpdated(pg_language, lanacl, updated); /* Okay, do it... */ - tup = heap_modify_tuple(oldtup, tupDesc, values, nulls, replaces); - CatalogTupleUpdate(rel, &tup->t_self, tup); + tup = heap_update_tuple(oldtup, tupDesc, values, nulls, updated); + CatalogTupleUpdate(rel, &tup->t_self, tup, updated, NULL); langoid = oldform->oid; ReleaseSysCache(oldtup); @@ -157,11 +153,10 @@ CreateProceduralLanguage(CreatePLangStmt *stmt) else { /* Creating a new language */ - langoid = GetNewOidWithIndex(rel, LanguageOidIndexId, - Anum_pg_language_oid); - values[Anum_pg_language_oid - 1] = ObjectIdGetDatum(langoid); + langoid = GetNewOidWithIndex(rel, LanguageOidIndexId, Anum_pg_language_oid); + HeapTupleUpdateValue(pg_language, oid, ObjectIdGetDatum(langoid), values, nulls, updated); tup = heap_form_tuple(tupDesc, values, nulls); - CatalogTupleInsert(rel, tup); + CatalogTupleInsert(rel, tup, NULL); is_update = false; } @@ -213,6 +208,7 @@ CreateProceduralLanguage(CreatePLangStmt *stmt) InvokeObjectPostCreateHook(LanguageRelationId, myself.objectId, 0); table_close(rel, RowExclusiveLock); + bms_free(updated); return myself; } diff --git a/src/backend/commands/publicationcmds.c b/src/backend/commands/publicationcmds.c index 1faf3a8c37283..fefce1e394c30 100644 --- a/src/backend/commands/publicationcmds.c +++ b/src/backend/commands/publicationcmds.c @@ -828,8 +828,8 @@ CreatePublication(ParseState *pstate, CreatePublicationStmt *stmt) Relation rel; ObjectAddress myself; Oid puboid; - bool nulls[Natts_pg_publication]; - Datum values[Natts_pg_publication]; + Datum values[Natts_pg_publication] = {0}; + bool nulls[Natts_pg_publication] = {false}; HeapTuple tup; bool publish_given; PublicationActions pubactions; @@ -871,9 +871,8 @@ CreatePublication(ParseState *pstate, CreatePublicationStmt *stmt) memset(values, 0, sizeof(values)); memset(nulls, false, sizeof(nulls)); - values[Anum_pg_publication_pubname - 1] = - DirectFunctionCall1(namein, CStringGetDatum(stmt->pubname)); - values[Anum_pg_publication_pubowner - 1] = ObjectIdGetDatum(GetUserId()); + HeapTupleSetValue(pg_publication, pubname, DirectFunctionCall1(namein, CStringGetDatum(stmt->pubname)), values); + HeapTupleSetValue(pg_publication, pubowner, ObjectIdGetDatum(GetUserId()), values); parse_publication_options(pstate, stmt->options, @@ -892,28 +891,20 @@ CreatePublication(ParseState *pstate, CreatePublicationStmt *stmt) puboid = GetNewOidWithIndex(rel, PublicationObjectIndexId, Anum_pg_publication_oid); - values[Anum_pg_publication_oid - 1] = ObjectIdGetDatum(puboid); - values[Anum_pg_publication_puballtables - 1] = - BoolGetDatum(stmt->for_all_tables); - values[Anum_pg_publication_puballsequences - 1] = - BoolGetDatum(stmt->for_all_sequences); - values[Anum_pg_publication_pubinsert - 1] = - BoolGetDatum(pubactions.pubinsert); - values[Anum_pg_publication_pubupdate - 1] = - BoolGetDatum(pubactions.pubupdate); - values[Anum_pg_publication_pubdelete - 1] = - BoolGetDatum(pubactions.pubdelete); - values[Anum_pg_publication_pubtruncate - 1] = - BoolGetDatum(pubactions.pubtruncate); - values[Anum_pg_publication_pubviaroot - 1] = - BoolGetDatum(publish_via_partition_root); - values[Anum_pg_publication_pubgencols - 1] = - CharGetDatum(publish_generated_columns); + HeapTupleSetValue(pg_publication, oid, ObjectIdGetDatum(puboid), values); + HeapTupleSetValue(pg_publication, puballtables, BoolGetDatum(stmt->for_all_tables), values); + HeapTupleSetValue(pg_publication, puballsequences, BoolGetDatum(stmt->for_all_sequences), values); + HeapTupleSetValue(pg_publication, pubinsert, BoolGetDatum(pubactions.pubinsert), values); + HeapTupleSetValue(pg_publication, pubupdate, BoolGetDatum(pubactions.pubupdate), values); + HeapTupleSetValue(pg_publication, pubdelete, BoolGetDatum(pubactions.pubdelete), values); + HeapTupleSetValue(pg_publication, pubtruncate, BoolGetDatum(pubactions.pubtruncate), values); + HeapTupleSetValue(pg_publication, pubviaroot, BoolGetDatum(publish_via_partition_root), values); + HeapTupleSetValue(pg_publication, pubgencols, CharGetDatum(publish_generated_columns), values); tup = heap_form_tuple(RelationGetDescr(rel), values, nulls); /* Insert tuple into catalog. */ - CatalogTupleInsert(rel, tup); + CatalogTupleInsert(rel, tup, NULL); heap_freetuple(tup); recordDependencyOnOwner(PublicationRelationId, puboid, GetUserId()); @@ -991,9 +982,9 @@ static void AlterPublicationOptions(ParseState *pstate, AlterPublicationStmt *stmt, Relation rel, HeapTuple tup) { - bool nulls[Natts_pg_publication]; - bool replaces[Natts_pg_publication]; - Datum values[Natts_pg_publication]; + Datum values[Natts_pg_publication] = {0}; + bool nulls[Natts_pg_publication] = {false}; + Bitmapset *updated = NULL; bool publish_given; PublicationActions pubactions; bool publish_via_partition_root_given; @@ -1103,42 +1094,25 @@ AlterPublicationOptions(ParseState *pstate, AlterPublicationStmt *stmt, } /* Everything ok, form a new tuple. */ - memset(values, 0, sizeof(values)); - memset(nulls, false, sizeof(nulls)); - memset(replaces, false, sizeof(replaces)); - if (publish_given) { - values[Anum_pg_publication_pubinsert - 1] = BoolGetDatum(pubactions.pubinsert); - replaces[Anum_pg_publication_pubinsert - 1] = true; - - values[Anum_pg_publication_pubupdate - 1] = BoolGetDatum(pubactions.pubupdate); - replaces[Anum_pg_publication_pubupdate - 1] = true; - - values[Anum_pg_publication_pubdelete - 1] = BoolGetDatum(pubactions.pubdelete); - replaces[Anum_pg_publication_pubdelete - 1] = true; - - values[Anum_pg_publication_pubtruncate - 1] = BoolGetDatum(pubactions.pubtruncate); - replaces[Anum_pg_publication_pubtruncate - 1] = true; + HeapTupleUpdateValue(pg_publication, pubinsert, BoolGetDatum(pubactions.pubinsert), values, nulls, updated); + HeapTupleUpdateValue(pg_publication, pubupdate, BoolGetDatum(pubactions.pubupdate), values, nulls, updated); + HeapTupleUpdateValue(pg_publication, pubdelete, BoolGetDatum(pubactions.pubdelete), values, nulls, updated); + HeapTupleUpdateValue(pg_publication, pubtruncate, BoolGetDatum(pubactions.pubtruncate), values, nulls, updated); } if (publish_via_partition_root_given) - { - values[Anum_pg_publication_pubviaroot - 1] = BoolGetDatum(publish_via_partition_root); - replaces[Anum_pg_publication_pubviaroot - 1] = true; - } + HeapTupleUpdateValue(pg_publication, pubviaroot, BoolGetDatum(publish_via_partition_root), values, nulls, updated); if (publish_generated_columns_given) - { - values[Anum_pg_publication_pubgencols - 1] = CharGetDatum(publish_generated_columns); - replaces[Anum_pg_publication_pubgencols - 1] = true; - } + HeapTupleUpdateValue(pg_publication, pubgencols, CharGetDatum(publish_generated_columns), values, nulls, updated); - tup = heap_modify_tuple(tup, RelationGetDescr(rel), values, nulls, - replaces); + tup = heap_update_tuple(tup, RelationGetDescr(rel), values, nulls, updated); /* Update the catalog. */ - CatalogTupleUpdate(rel, &tup->t_self, tup); + CatalogTupleUpdate(rel, &tup->t_self, tup, updated, NULL); + bms_free(updated); CommandCounterIncrement(); @@ -2043,6 +2017,7 @@ static void AlterPublicationOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId) { Form_pg_publication form; + Bitmapset *updated = NULL; form = (Form_pg_publication) GETSTRUCT(tup); @@ -2079,8 +2054,10 @@ AlterPublicationOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId) } } - form->pubowner = newOwnerId; - CatalogTupleUpdate(rel, &tup->t_self, tup); + HeapTupleUpdateField(pg_publication, pubowner, newOwnerId, form, updated); + CatalogTupleUpdate(rel, &tup->t_self, tup, updated, NULL); + + bms_free(updated); /* Update owner dependency reference */ changeDependencyOnOwner(PublicationRelationId, diff --git a/src/backend/commands/schemacmds.c b/src/backend/commands/schemacmds.c index 3cc1472103a7a..460e2b21fc93c 100644 --- a/src/backend/commands/schemacmds.c +++ b/src/backend/commands/schemacmds.c @@ -255,6 +255,7 @@ RenameSchema(const char *oldname, const char *newname) AclResult aclresult; ObjectAddress address; Form_pg_namespace nspform; + Bitmapset *updated = NULL; rel = table_open(NamespaceRelationId, RowExclusiveLock); @@ -292,7 +293,8 @@ RenameSchema(const char *oldname, const char *newname) /* rename */ namestrcpy(&nspform->nspname, newname); - CatalogTupleUpdate(rel, &tup->t_self, tup); + HeapTupleMarkColumnUpdated(pg_namespace, nspname, updated); + CatalogTupleUpdate(rel, &tup->t_self, tup, updated, NULL); InvokeObjectPostAlterHook(NamespaceRelationId, nspOid, 0); @@ -300,6 +302,7 @@ RenameSchema(const char *oldname, const char *newname) table_close(rel, NoLock); heap_freetuple(tup); + bms_free(updated); return address; } @@ -374,14 +377,14 @@ AlterSchemaOwner_internal(HeapTuple tup, Relation rel, Oid newOwnerId) */ if (nspForm->nspowner != newOwnerId) { - Datum repl_val[Natts_pg_namespace]; - bool repl_null[Natts_pg_namespace]; - bool repl_repl[Natts_pg_namespace]; + Datum values[Natts_pg_namespace] = {0}; + bool nulls[Natts_pg_namespace] = {false}; Acl *newAcl; Datum aclDatum; bool isNull; HeapTuple newtuple; AclResult aclresult; + Bitmapset *updated = NULL; /* Otherwise, must be owner of the existing object */ if (!object_ownercheck(NamespaceRelationId, nspForm->oid, GetUserId())) @@ -406,11 +409,7 @@ AlterSchemaOwner_internal(HeapTuple tup, Relation rel, Oid newOwnerId) aclcheck_error(aclresult, OBJECT_DATABASE, get_database_name(MyDatabaseId)); - memset(repl_null, false, sizeof(repl_null)); - memset(repl_repl, false, sizeof(repl_repl)); - - repl_repl[Anum_pg_namespace_nspowner - 1] = true; - repl_val[Anum_pg_namespace_nspowner - 1] = ObjectIdGetDatum(newOwnerId); + HeapTupleUpdateValue(pg_namespace, nspowner, ObjectIdGetDatum(newOwnerId), values, nulls, updated); /* * Determine the modified ACL for the new owner. This is only @@ -423,19 +422,19 @@ AlterSchemaOwner_internal(HeapTuple tup, Relation rel, Oid newOwnerId) { newAcl = aclnewowner(DatumGetAclP(aclDatum), nspForm->nspowner, newOwnerId); - repl_repl[Anum_pg_namespace_nspacl - 1] = true; - repl_val[Anum_pg_namespace_nspacl - 1] = PointerGetDatum(newAcl); + HeapTupleUpdateValue(pg_namespace, nspacl, PointerGetDatum(newAcl), values, nulls, updated); } - newtuple = heap_modify_tuple(tup, RelationGetDescr(rel), repl_val, repl_null, repl_repl); + newtuple = heap_update_tuple(tup, RelationGetDescr(rel), values, nulls, updated); - CatalogTupleUpdate(rel, &newtuple->t_self, newtuple); + CatalogTupleUpdate(rel, &newtuple->t_self, newtuple, updated, NULL); heap_freetuple(newtuple); /* Update owner dependency reference */ changeDependencyOnOwner(NamespaceRelationId, nspForm->oid, newOwnerId); + bms_free(updated); } InvokeObjectPostAlterHook(NamespaceRelationId, diff --git a/src/backend/commands/seclabel.c b/src/backend/commands/seclabel.c index cee5d7bbb9c7e..903e3e151d5d7 100644 --- a/src/backend/commands/seclabel.c +++ b/src/backend/commands/seclabel.c @@ -334,18 +334,16 @@ SetSharedSecurityLabel(const ObjectAddress *object, SysScanDesc scan; HeapTuple oldtup; HeapTuple newtup = NULL; - Datum values[Natts_pg_shseclabel]; - bool nulls[Natts_pg_shseclabel]; - bool replaces[Natts_pg_shseclabel]; + Datum values[Natts_pg_shseclabel] = {0}; + bool nulls[Natts_pg_shseclabel] = {false}; + Bitmapset *updated = NULL; /* Prepare to form or update a tuple, if necessary. */ - memset(nulls, false, sizeof(nulls)); - memset(replaces, false, sizeof(replaces)); - values[Anum_pg_shseclabel_objoid - 1] = ObjectIdGetDatum(object->objectId); - values[Anum_pg_shseclabel_classoid - 1] = ObjectIdGetDatum(object->classId); - values[Anum_pg_shseclabel_provider - 1] = CStringGetTextDatum(provider); + HeapTupleUpdateValue(pg_shseclabel, objoid, ObjectIdGetDatum(object->objectId), values, nulls, updated); + HeapTupleUpdateValue(pg_shseclabel, classoid, ObjectIdGetDatum(object->classId), values, nulls, updated); + HeapTupleUpdateValue(pg_shseclabel, provider, CStringGetTextDatum(provider), values, nulls, updated); if (label != NULL) - values[Anum_pg_shseclabel_label - 1] = CStringGetTextDatum(label); + HeapTupleUpdateValue(pg_shseclabel, label, CStringGetTextDatum(label), values, nulls, updated); /* Use the index to search for a matching old tuple */ ScanKeyInit(&keys[0], @@ -373,10 +371,9 @@ SetSharedSecurityLabel(const ObjectAddress *object, CatalogTupleDelete(pg_shseclabel, &oldtup->t_self); else { - replaces[Anum_pg_shseclabel_label - 1] = true; - newtup = heap_modify_tuple(oldtup, RelationGetDescr(pg_shseclabel), - values, nulls, replaces); - CatalogTupleUpdate(pg_shseclabel, &oldtup->t_self, newtup); + HeapTupleUpdateValue(pg_shseclabel, label, CStringGetTextDatum(label), values, nulls, updated); + newtup = heap_update_tuple(oldtup, RelationGetDescr(pg_shseclabel), values, nulls, updated); + CatalogTupleUpdate(pg_shseclabel, &oldtup->t_self, newtup, updated, NULL); } } systable_endscan(scan); @@ -386,13 +383,14 @@ SetSharedSecurityLabel(const ObjectAddress *object, { newtup = heap_form_tuple(RelationGetDescr(pg_shseclabel), values, nulls); - CatalogTupleInsert(pg_shseclabel, newtup); + CatalogTupleInsert(pg_shseclabel, newtup, NULL); } if (newtup != NULL) heap_freetuple(newtup); table_close(pg_shseclabel, RowExclusiveLock); + bms_free(updated); } /* @@ -409,9 +407,9 @@ SetSecurityLabel(const ObjectAddress *object, SysScanDesc scan; HeapTuple oldtup; HeapTuple newtup = NULL; - Datum values[Natts_pg_seclabel]; - bool nulls[Natts_pg_seclabel]; - bool replaces[Natts_pg_seclabel]; + Datum values[Natts_pg_seclabel] = {0}; + bool nulls[Natts_pg_seclabel] = {false}; + Bitmapset *updated = NULL; /* Shared objects have their own security label catalog. */ if (IsSharedRelation(object->classId)) @@ -421,14 +419,12 @@ SetSecurityLabel(const ObjectAddress *object, } /* Prepare to form or update a tuple, if necessary. */ - memset(nulls, false, sizeof(nulls)); - memset(replaces, false, sizeof(replaces)); - values[Anum_pg_seclabel_objoid - 1] = ObjectIdGetDatum(object->objectId); - values[Anum_pg_seclabel_classoid - 1] = ObjectIdGetDatum(object->classId); - values[Anum_pg_seclabel_objsubid - 1] = Int32GetDatum(object->objectSubId); - values[Anum_pg_seclabel_provider - 1] = CStringGetTextDatum(provider); + HeapTupleUpdateValue(pg_seclabel, objoid, ObjectIdGetDatum(object->objectId), values, nulls, updated); + HeapTupleUpdateValue(pg_seclabel, classoid, ObjectIdGetDatum(object->classId), values, nulls, updated); + HeapTupleUpdateValue(pg_seclabel, objsubid, Int32GetDatum(object->objectSubId), values, nulls, updated); + HeapTupleUpdateValue(pg_seclabel, provider, CStringGetTextDatum(provider), values, nulls, updated); if (label != NULL) - values[Anum_pg_seclabel_label - 1] = CStringGetTextDatum(label); + HeapTupleUpdateValue(pg_seclabel, label, CStringGetTextDatum(label), values, nulls, updated); /* Use the index to search for a matching old tuple */ ScanKeyInit(&keys[0], @@ -460,10 +456,9 @@ SetSecurityLabel(const ObjectAddress *object, CatalogTupleDelete(pg_seclabel, &oldtup->t_self); else { - replaces[Anum_pg_seclabel_label - 1] = true; - newtup = heap_modify_tuple(oldtup, RelationGetDescr(pg_seclabel), - values, nulls, replaces); - CatalogTupleUpdate(pg_seclabel, &oldtup->t_self, newtup); + HeapTupleUpdateValue(pg_seclabel, label, CStringGetTextDatum(label), values, nulls, updated); + newtup = heap_update_tuple(oldtup, RelationGetDescr(pg_seclabel), values, nulls, updated); + CatalogTupleUpdate(pg_seclabel, &oldtup->t_self, newtup, updated, NULL); } } systable_endscan(scan); @@ -471,9 +466,8 @@ SetSecurityLabel(const ObjectAddress *object, /* If we didn't find an old tuple, insert a new one */ if (newtup == NULL && label != NULL) { - newtup = heap_form_tuple(RelationGetDescr(pg_seclabel), - values, nulls); - CatalogTupleInsert(pg_seclabel, newtup); + newtup = heap_form_tuple(RelationGetDescr(pg_seclabel), values, nulls); + CatalogTupleInsert(pg_seclabel, newtup, NULL); } /* Update indexes, if necessary */ @@ -481,6 +475,7 @@ SetSecurityLabel(const ObjectAddress *object, heap_freetuple(newtup); table_close(pg_seclabel, RowExclusiveLock); + bms_free(updated); } /* diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c index 8d671b7a29d63..d936745d184da 100644 --- a/src/backend/commands/sequence.c +++ b/src/backend/commands/sequence.c @@ -136,8 +136,8 @@ DefineSequence(ParseState *pstate, CreateSeqStmt *seq) TupleDesc tupDesc; Datum value[SEQ_COL_LASTCOL]; bool null[SEQ_COL_LASTCOL]; - Datum pgs_values[Natts_pg_sequence]; - bool pgs_nulls[Natts_pg_sequence]; + Datum pgs_values[Natts_pg_sequence] = {0}; + bool pgs_nulls[Natts_pg_sequence] = {false}; int i; /* @@ -232,17 +232,17 @@ DefineSequence(ParseState *pstate, CreateSeqStmt *seq) memset(pgs_nulls, 0, sizeof(pgs_nulls)); - pgs_values[Anum_pg_sequence_seqrelid - 1] = ObjectIdGetDatum(seqoid); - pgs_values[Anum_pg_sequence_seqtypid - 1] = ObjectIdGetDatum(seqform.seqtypid); - pgs_values[Anum_pg_sequence_seqstart - 1] = Int64GetDatumFast(seqform.seqstart); - pgs_values[Anum_pg_sequence_seqincrement - 1] = Int64GetDatumFast(seqform.seqincrement); - pgs_values[Anum_pg_sequence_seqmax - 1] = Int64GetDatumFast(seqform.seqmax); - pgs_values[Anum_pg_sequence_seqmin - 1] = Int64GetDatumFast(seqform.seqmin); - pgs_values[Anum_pg_sequence_seqcache - 1] = Int64GetDatumFast(seqform.seqcache); - pgs_values[Anum_pg_sequence_seqcycle - 1] = BoolGetDatum(seqform.seqcycle); + HeapTupleSetValue(pg_sequence, seqrelid, ObjectIdGetDatum(seqoid), pgs_values); + HeapTupleSetValue(pg_sequence, seqtypid, ObjectIdGetDatum(seqform.seqtypid), pgs_values); + HeapTupleSetValue(pg_sequence, seqstart, Int64GetDatumFast(seqform.seqstart), pgs_values); + HeapTupleSetValue(pg_sequence, seqincrement, Int64GetDatumFast(seqform.seqincrement), pgs_values); + HeapTupleSetValue(pg_sequence, seqmax, Int64GetDatumFast(seqform.seqmax), pgs_values); + HeapTupleSetValue(pg_sequence, seqmin, Int64GetDatumFast(seqform.seqmin), pgs_values); + HeapTupleSetValue(pg_sequence, seqcache, Int64GetDatumFast(seqform.seqcache), pgs_values); + HeapTupleSetValue(pg_sequence, seqcycle, BoolGetDatum(seqform.seqcycle), pgs_values); tuple = heap_form_tuple(tupDesc, pgs_values, pgs_nulls); - CatalogTupleInsert(rel, tuple); + CatalogTupleInsert(rel, tuple, NULL); heap_freetuple(tuple); table_close(rel, RowExclusiveLock); @@ -455,6 +455,7 @@ AlterSequence(ParseState *pstate, AlterSeqStmt *stmt) bool is_called; int64 last_value; HeapTuple newdatatuple; + Bitmapset *updated = NULL; /* Open and lock sequence, and check for ownership along the way. */ relid = RangeVarGetRelidExtended(stmt->sequence, @@ -536,8 +537,15 @@ AlterSequence(ParseState *pstate, AlterSeqStmt *stmt) if (owned_by) process_owned_by(seqrel, owned_by, stmt->for_identity); + /* + * Mark all sequence columns as potentially updated since init_params can + * modify any field + */ + HeapTupleUpdateSetAllColumnsUpdated(pg_sequence, updated); + /* update the pg_sequence tuple (we could skip this in some cases...) */ - CatalogTupleUpdate(rel, &seqtuple->t_self, seqtuple); + CatalogTupleUpdate(rel, &seqtuple->t_self, seqtuple, updated, NULL); + bms_free(updated); InvokeObjectPostAlterHook(RelationRelationId, relid, 0); diff --git a/src/backend/commands/statscmds.c b/src/backend/commands/statscmds.c index 0cf0ea43f19b5..4addbed0754c6 100644 --- a/src/backend/commands/statscmds.c +++ b/src/backend/commands/statscmds.c @@ -71,8 +71,8 @@ CreateStatistics(CreateStatsStmt *stmt, bool check_rights) Oid namespaceId; Oid stxowner = GetUserId(); HeapTuple htup; - Datum values[Natts_pg_statistic_ext]; - bool nulls[Natts_pg_statistic_ext]; + Datum values[Natts_pg_statistic_ext] = {0}; + bool nulls[Natts_pg_statistic_ext] = {false}; int2vector *stxkeys; List *stxexprs = NIL; Datum exprsDatum; @@ -525,22 +525,22 @@ CreateStatistics(CreateStatsStmt *stmt, bool check_rights) statoid = GetNewOidWithIndex(statrel, StatisticExtOidIndexId, Anum_pg_statistic_ext_oid); - values[Anum_pg_statistic_ext_oid - 1] = ObjectIdGetDatum(statoid); - values[Anum_pg_statistic_ext_stxrelid - 1] = ObjectIdGetDatum(relid); - values[Anum_pg_statistic_ext_stxname - 1] = NameGetDatum(&stxname); - values[Anum_pg_statistic_ext_stxnamespace - 1] = ObjectIdGetDatum(namespaceId); - values[Anum_pg_statistic_ext_stxowner - 1] = ObjectIdGetDatum(stxowner); - values[Anum_pg_statistic_ext_stxkeys - 1] = PointerGetDatum(stxkeys); - nulls[Anum_pg_statistic_ext_stxstattarget - 1] = true; - values[Anum_pg_statistic_ext_stxkind - 1] = PointerGetDatum(stxkind); - - values[Anum_pg_statistic_ext_stxexprs - 1] = exprsDatum; + HeapTupleSetValue(pg_statistic_ext, oid, ObjectIdGetDatum(statoid), values); + HeapTupleSetValue(pg_statistic_ext, stxrelid, ObjectIdGetDatum(relid), values); + HeapTupleSetValue(pg_statistic_ext, stxname, NameGetDatum(&stxname), values); + HeapTupleSetValue(pg_statistic_ext, stxnamespace, ObjectIdGetDatum(namespaceId), values); + HeapTupleSetValue(pg_statistic_ext, stxowner, ObjectIdGetDatum(stxowner), values); + HeapTupleSetValue(pg_statistic_ext, stxkeys, PointerGetDatum(stxkeys), values); + HeapTupleSetValueNull(pg_statistic_ext, stxstattarget, values, nulls); + HeapTupleSetValue(pg_statistic_ext, stxkind, PointerGetDatum(stxkind), values); + + HeapTupleSetValue(pg_statistic_ext, stxexprs, exprsDatum, values); if (exprsDatum == (Datum) 0) - nulls[Anum_pg_statistic_ext_stxexprs - 1] = true; + HeapTupleSetValueNull(pg_statistic_ext, stxexprs, values, nulls); /* insert it into pg_statistic_ext */ htup = heap_form_tuple(statrel->rd_att, values, nulls); - CatalogTupleInsert(statrel, htup); + CatalogTupleInsert(statrel, htup, NULL); heap_freetuple(htup); relation_close(statrel, RowExclusiveLock); @@ -636,9 +636,9 @@ AlterStatistics(AlterStatsStmt *stmt) Oid stxoid; HeapTuple oldtup; HeapTuple newtup; - Datum repl_val[Natts_pg_statistic_ext]; - bool repl_null[Natts_pg_statistic_ext]; - bool repl_repl[Natts_pg_statistic_ext]; + Datum values[Natts_pg_statistic_ext] = {0}; + bool nulls[Natts_pg_statistic_ext] = {false}; + Bitmapset *updated = NULL; ObjectAddress address; int newtarget = 0; bool newtarget_default; @@ -713,23 +713,16 @@ AlterStatistics(AlterStatsStmt *stmt) aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_STATISTIC_EXT, NameListToString(stmt->defnames)); - /* Build new tuple. */ - memset(repl_val, 0, sizeof(repl_val)); - memset(repl_null, false, sizeof(repl_null)); - memset(repl_repl, false, sizeof(repl_repl)); - /* replace the stxstattarget column */ - repl_repl[Anum_pg_statistic_ext_stxstattarget - 1] = true; if (!newtarget_default) - repl_val[Anum_pg_statistic_ext_stxstattarget - 1] = Int16GetDatum(newtarget); + HeapTupleUpdateValue(pg_statistic_ext, stxstattarget, Int16GetDatum(newtarget), values, nulls, updated); else - repl_null[Anum_pg_statistic_ext_stxstattarget - 1] = true; + HeapTupleUpdateValueNull(pg_statistic_ext, stxstattarget, values, nulls, updated); - newtup = heap_modify_tuple(oldtup, RelationGetDescr(rel), - repl_val, repl_null, repl_repl); + newtup = heap_update_tuple(oldtup, RelationGetDescr(rel), values, nulls, updated); /* Update system catalog. */ - CatalogTupleUpdate(rel, &newtup->t_self, newtup); + CatalogTupleUpdate(rel, &newtup->t_self, newtup, updated, NULL); InvokeObjectPostAlterHook(StatisticExtRelationId, stxoid, 0); @@ -740,6 +733,7 @@ AlterStatistics(AlterStatsStmt *stmt) * other fields, there is no need to update dependencies. */ + bms_free(updated); heap_freetuple(newtup); ReleaseSysCache(oldtup); diff --git a/src/backend/commands/subscriptioncmds.c b/src/backend/commands/subscriptioncmds.c index 5930e8c581624..e368bfb35f747 100644 --- a/src/backend/commands/subscriptioncmds.c +++ b/src/backend/commands/subscriptioncmds.c @@ -589,8 +589,8 @@ CreateSubscription(ParseState *pstate, CreateSubscriptionStmt *stmt, Relation rel; ObjectAddress myself; Oid subid; - bool nulls[Natts_pg_subscription]; - Datum values[Natts_pg_subscription]; + Datum values[Natts_pg_subscription] = {0}; + bool nulls[Natts_pg_subscription] = {false}; Oid owner = GetUserId(); HeapTuple tup; char *conninfo; @@ -710,47 +710,35 @@ CreateSubscription(ParseState *pstate, CreateSubscriptionStmt *stmt, subid = GetNewOidWithIndex(rel, SubscriptionObjectIndexId, Anum_pg_subscription_oid); - values[Anum_pg_subscription_oid - 1] = ObjectIdGetDatum(subid); - values[Anum_pg_subscription_subdbid - 1] = ObjectIdGetDatum(MyDatabaseId); - values[Anum_pg_subscription_subskiplsn - 1] = LSNGetDatum(InvalidXLogRecPtr); - values[Anum_pg_subscription_subname - 1] = - DirectFunctionCall1(namein, CStringGetDatum(stmt->subname)); - values[Anum_pg_subscription_subowner - 1] = ObjectIdGetDatum(owner); - values[Anum_pg_subscription_subenabled - 1] = BoolGetDatum(opts.enabled); - values[Anum_pg_subscription_subbinary - 1] = BoolGetDatum(opts.binary); - values[Anum_pg_subscription_substream - 1] = CharGetDatum(opts.streaming); - values[Anum_pg_subscription_subtwophasestate - 1] = - CharGetDatum(opts.twophase ? - LOGICALREP_TWOPHASE_STATE_PENDING : - LOGICALREP_TWOPHASE_STATE_DISABLED); - values[Anum_pg_subscription_subdisableonerr - 1] = BoolGetDatum(opts.disableonerr); - values[Anum_pg_subscription_subpasswordrequired - 1] = BoolGetDatum(opts.passwordrequired); - values[Anum_pg_subscription_subrunasowner - 1] = BoolGetDatum(opts.runasowner); - values[Anum_pg_subscription_subfailover - 1] = BoolGetDatum(opts.failover); - values[Anum_pg_subscription_subretaindeadtuples - 1] = - BoolGetDatum(opts.retaindeadtuples); - values[Anum_pg_subscription_submaxretention - 1] = - Int32GetDatum(opts.maxretention); - values[Anum_pg_subscription_subretentionactive - 1] = - Int32GetDatum(opts.retaindeadtuples); - values[Anum_pg_subscription_subconninfo - 1] = - CStringGetTextDatum(conninfo); + HeapTupleSetValue(pg_subscription, oid, ObjectIdGetDatum(subid), values); + HeapTupleSetValue(pg_subscription, subdbid, ObjectIdGetDatum(MyDatabaseId), values); + HeapTupleSetValue(pg_subscription, subskiplsn, LSNGetDatum(InvalidXLogRecPtr), values); + HeapTupleSetValue(pg_subscription, subname, DirectFunctionCall1(namein, CStringGetDatum(stmt->subname)), values); + HeapTupleSetValue(pg_subscription, subowner, ObjectIdGetDatum(owner), values); + HeapTupleSetValue(pg_subscription, subenabled, BoolGetDatum(opts.enabled), values); + HeapTupleSetValue(pg_subscription, subbinary, BoolGetDatum(opts.binary), values); + HeapTupleSetValue(pg_subscription, substream, CharGetDatum(opts.streaming), values); + HeapTupleSetValue(pg_subscription, subtwophasestate, CharGetDatum(opts.twophase ? LOGICALREP_TWOPHASE_STATE_PENDING : LOGICALREP_TWOPHASE_STATE_DISABLED), values); + HeapTupleSetValue(pg_subscription, subdisableonerr, BoolGetDatum(opts.disableonerr), values); + HeapTupleSetValue(pg_subscription, subpasswordrequired, BoolGetDatum(opts.passwordrequired), values); + HeapTupleSetValue(pg_subscription, subrunasowner, BoolGetDatum(opts.runasowner), values); + HeapTupleSetValue(pg_subscription, subfailover, BoolGetDatum(opts.failover), values); + HeapTupleSetValue(pg_subscription, subretaindeadtuples, BoolGetDatum(opts.retaindeadtuples), values); + HeapTupleSetValue(pg_subscription, submaxretention, Int32GetDatum(opts.maxretention), values); + HeapTupleSetValue(pg_subscription, subretentionactive, Int32GetDatum(opts.retaindeadtuples), values); + HeapTupleSetValue(pg_subscription, subconninfo, CStringGetTextDatum(conninfo), values); if (opts.slot_name) - values[Anum_pg_subscription_subslotname - 1] = - DirectFunctionCall1(namein, CStringGetDatum(opts.slot_name)); + HeapTupleSetValue(pg_subscription, subslotname, DirectFunctionCall1(namein, CStringGetDatum(opts.slot_name)), values); else - nulls[Anum_pg_subscription_subslotname - 1] = true; - values[Anum_pg_subscription_subsynccommit - 1] = - CStringGetTextDatum(opts.synchronous_commit); - values[Anum_pg_subscription_subpublications - 1] = - publicationListToArray(publications); - values[Anum_pg_subscription_suborigin - 1] = - CStringGetTextDatum(opts.origin); + HeapTupleSetValueNull(pg_subscription, subslotname, values, nulls); + HeapTupleSetValue(pg_subscription, subsynccommit, CStringGetTextDatum(opts.synchronous_commit), values); + HeapTupleSetValue(pg_subscription, subpublications, publicationListToArray(publications), values); + HeapTupleSetValue(pg_subscription, suborigin, CStringGetTextDatum(opts.origin), values); tup = heap_form_tuple(RelationGetDescr(rel), values, nulls); /* Insert tuple into catalog. */ - CatalogTupleInsert(rel, tup); + CatalogTupleInsert(rel, tup, NULL); heap_freetuple(tup); recordDependencyOnOwner(SubscriptionRelationId, subid, owner); @@ -1335,9 +1323,8 @@ AlterSubscription(ParseState *pstate, AlterSubscriptionStmt *stmt, { Relation rel; ObjectAddress myself; - bool nulls[Natts_pg_subscription]; - bool replaces[Natts_pg_subscription]; - Datum values[Natts_pg_subscription]; + Datum values[Natts_pg_subscription] = {0}; + bool nulls[Natts_pg_subscription] = {false}; HeapTuple tup; Oid subid; bool update_tuple = false; @@ -1352,6 +1339,7 @@ AlterSubscription(ParseState *pstate, AlterSubscriptionStmt *stmt, Form_pg_subscription form; bits32 supported_opts; SubOpts opts = {0}; + Bitmapset *updated = NULL; rel = table_open(SubscriptionRelationId, RowExclusiveLock); @@ -1396,7 +1384,6 @@ AlterSubscription(ParseState *pstate, AlterSubscriptionStmt *stmt, /* Form a new tuple. */ memset(values, 0, sizeof(values)); memset(nulls, false, sizeof(nulls)); - memset(replaces, false, sizeof(replaces)); switch (stmt->kind) { @@ -1431,41 +1418,27 @@ AlterSubscription(ParseState *pstate, AlterSubscriptionStmt *stmt, "slot_name = NONE"))); if (opts.slot_name) - values[Anum_pg_subscription_subslotname - 1] = - DirectFunctionCall1(namein, CStringGetDatum(opts.slot_name)); + HeapTupleUpdateValue(pg_subscription, subslotname, + DirectFunctionCall1(namein, CStringGetDatum(opts.slot_name)), values, nulls, updated); else - nulls[Anum_pg_subscription_subslotname - 1] = true; - replaces[Anum_pg_subscription_subslotname - 1] = true; + HeapTupleUpdateValueNull(pg_subscription, subslotname, values, nulls, updated); } if (opts.synchronous_commit) - { - values[Anum_pg_subscription_subsynccommit - 1] = - CStringGetTextDatum(opts.synchronous_commit); - replaces[Anum_pg_subscription_subsynccommit - 1] = true; - } + HeapTupleUpdateValue(pg_subscription, subsynccommit, + CStringGetTextDatum(opts.synchronous_commit), values, nulls, updated); if (IsSet(opts.specified_opts, SUBOPT_BINARY)) - { - values[Anum_pg_subscription_subbinary - 1] = - BoolGetDatum(opts.binary); - replaces[Anum_pg_subscription_subbinary - 1] = true; - } + HeapTupleUpdateValue(pg_subscription, subbinary, + BoolGetDatum(opts.binary), values, nulls, updated); if (IsSet(opts.specified_opts, SUBOPT_STREAMING)) - { - values[Anum_pg_subscription_substream - 1] = - CharGetDatum(opts.streaming); - replaces[Anum_pg_subscription_substream - 1] = true; - } + HeapTupleUpdateValue(pg_subscription, substream, + CharGetDatum(opts.streaming), values, nulls, updated); if (IsSet(opts.specified_opts, SUBOPT_DISABLE_ON_ERR)) - { - values[Anum_pg_subscription_subdisableonerr - 1] - = BoolGetDatum(opts.disableonerr); - replaces[Anum_pg_subscription_subdisableonerr - 1] - = true; - } + HeapTupleUpdateValue(pg_subscription, subdisableonerr, + BoolGetDatum(opts.disableonerr), values, nulls, updated); if (IsSet(opts.specified_opts, SUBOPT_PASSWORD_REQUIRED)) { @@ -1476,18 +1449,13 @@ AlterSubscription(ParseState *pstate, AlterSubscriptionStmt *stmt, errmsg("password_required=false is superuser-only"), errhint("Subscriptions with the password_required option set to false may only be created or modified by the superuser."))); - values[Anum_pg_subscription_subpasswordrequired - 1] - = BoolGetDatum(opts.passwordrequired); - replaces[Anum_pg_subscription_subpasswordrequired - 1] - = true; + HeapTupleUpdateValue(pg_subscription, subpasswordrequired, + BoolGetDatum(opts.passwordrequired), values, nulls, updated); } if (IsSet(opts.specified_opts, SUBOPT_RUN_AS_OWNER)) - { - values[Anum_pg_subscription_subrunasowner - 1] = - BoolGetDatum(opts.runasowner); - replaces[Anum_pg_subscription_subrunasowner - 1] = true; - } + HeapTupleUpdateValue(pg_subscription, subrunasowner, + BoolGetDatum(opts.runasowner), values, nulls, updated); if (IsSet(opts.specified_opts, SUBOPT_TWOPHASE_COMMIT)) { @@ -1546,11 +1514,10 @@ AlterSubscription(ParseState *pstate, AlterSubscriptionStmt *stmt, errhint("Resolve these transactions and try again."))); /* Change system catalog accordingly */ - values[Anum_pg_subscription_subtwophasestate - 1] = - CharGetDatum(opts.twophase ? - LOGICALREP_TWOPHASE_STATE_PENDING : - LOGICALREP_TWOPHASE_STATE_DISABLED); - replaces[Anum_pg_subscription_subtwophasestate - 1] = true; + HeapTupleUpdateValue(pg_subscription, subtwophasestate, + CharGetDatum(opts.twophase ? + LOGICALREP_TWOPHASE_STATE_PENDING : + LOGICALREP_TWOPHASE_STATE_DISABLED), values, nulls, updated); } if (IsSet(opts.specified_opts, SUBOPT_FAILOVER)) @@ -1565,16 +1532,14 @@ AlterSubscription(ParseState *pstate, AlterSubscriptionStmt *stmt, CheckAlterSubOption(sub, "failover", update_failover, isTopLevel); - values[Anum_pg_subscription_subfailover - 1] = - BoolGetDatum(opts.failover); - replaces[Anum_pg_subscription_subfailover - 1] = true; + HeapTupleUpdateValue(pg_subscription, subfailover, + BoolGetDatum(opts.failover), values, nulls, updated); } if (IsSet(opts.specified_opts, SUBOPT_RETAIN_DEAD_TUPLES)) { - values[Anum_pg_subscription_subretaindeadtuples - 1] = - BoolGetDatum(opts.retaindeadtuples); - replaces[Anum_pg_subscription_subretaindeadtuples - 1] = true; + HeapTupleUpdateValue(pg_subscription, subretaindeadtuples, + BoolGetDatum(opts.retaindeadtuples), values, nulls, updated); /* * Update the retention status only if there's a change in @@ -1592,9 +1557,8 @@ AlterSubscription(ParseState *pstate, AlterSubscriptionStmt *stmt, */ if (opts.retaindeadtuples != sub->retaindeadtuples) { - values[Anum_pg_subscription_subretentionactive - 1] = - BoolGetDatum(opts.retaindeadtuples); - replaces[Anum_pg_subscription_subretentionactive - 1] = true; + HeapTupleUpdateValue(pg_subscription, subretentionactive, + BoolGetDatum(opts.retaindeadtuples), values, nulls, updated); retention_active = opts.retaindeadtuples; } @@ -1629,9 +1593,8 @@ AlterSubscription(ParseState *pstate, AlterSubscriptionStmt *stmt, if (IsSet(opts.specified_opts, SUBOPT_MAX_RETENTION_DURATION)) { - values[Anum_pg_subscription_submaxretention - 1] = - Int32GetDatum(opts.maxretention); - replaces[Anum_pg_subscription_submaxretention - 1] = true; + HeapTupleUpdateValue(pg_subscription, submaxretention, + Int32GetDatum(opts.maxretention), values, nulls, updated); max_retention = opts.maxretention; } @@ -1650,9 +1613,8 @@ AlterSubscription(ParseState *pstate, AlterSubscriptionStmt *stmt, if (IsSet(opts.specified_opts, SUBOPT_ORIGIN)) { - values[Anum_pg_subscription_suborigin - 1] = - CStringGetTextDatum(opts.origin); - replaces[Anum_pg_subscription_suborigin - 1] = true; + HeapTupleUpdateValue(pg_subscription, suborigin, + CStringGetTextDatum(opts.origin), values, nulls, updated); /* * Check if changes from different origins may be received @@ -1689,9 +1651,8 @@ AlterSubscription(ParseState *pstate, AlterSubscriptionStmt *stmt, WARNING, sub->retaindeadtuples, sub->retentionactive, false); - values[Anum_pg_subscription_subenabled - 1] = - BoolGetDatum(opts.enabled); - replaces[Anum_pg_subscription_subenabled - 1] = true; + HeapTupleUpdateValue(pg_subscription, subenabled, + BoolGetDatum(opts.enabled), values, nulls, updated); if (opts.enabled) ApplyLauncherWakeupAtCommit(); @@ -1715,9 +1676,8 @@ AlterSubscription(ParseState *pstate, AlterSubscriptionStmt *stmt, walrcv_check_conninfo(stmt->conninfo, sub->passwordrequired && !sub->ownersuperuser); - values[Anum_pg_subscription_subconninfo - 1] = - CStringGetTextDatum(stmt->conninfo); - replaces[Anum_pg_subscription_subconninfo - 1] = true; + HeapTupleUpdateValue(pg_subscription, subconninfo, + CStringGetTextDatum(stmt->conninfo), values, nulls, updated); update_tuple = true; /* @@ -1734,9 +1694,8 @@ AlterSubscription(ParseState *pstate, AlterSubscriptionStmt *stmt, parse_subscription_options(pstate, stmt->options, supported_opts, &opts); - values[Anum_pg_subscription_subpublications - 1] = - publicationListToArray(stmt->publication); - replaces[Anum_pg_subscription_subpublications - 1] = true; + HeapTupleUpdateValue(pg_subscription, subpublications, + publicationListToArray(stmt->publication), values, nulls, updated); update_tuple = true; @@ -1782,9 +1741,8 @@ AlterSubscription(ParseState *pstate, AlterSubscriptionStmt *stmt, supported_opts, &opts); publist = merge_publications(sub->publications, stmt->publication, isadd, stmt->subname); - values[Anum_pg_subscription_subpublications - 1] = - publicationListToArray(publist); - replaces[Anum_pg_subscription_subpublications - 1] = true; + HeapTupleUpdateValue(pg_subscription, subpublications, + publicationListToArray(publist), values, nulls, updated); update_tuple = true; @@ -1915,8 +1873,7 @@ AlterSubscription(ParseState *pstate, AlterSubscriptionStmt *stmt, LSN_FORMAT_ARGS(remote_lsn)))); } - values[Anum_pg_subscription_subskiplsn - 1] = LSNGetDatum(opts.lsn); - replaces[Anum_pg_subscription_subskiplsn - 1] = true; + HeapTupleUpdateValue(pg_subscription, subskiplsn, LSNGetDatum(opts.lsn), values, nulls, updated); update_tuple = true; break; @@ -1930,10 +1887,9 @@ AlterSubscription(ParseState *pstate, AlterSubscriptionStmt *stmt, /* Update the catalog if needed. */ if (update_tuple) { - tup = heap_modify_tuple(tup, RelationGetDescr(rel), values, nulls, - replaces); + tup = heap_update_tuple(tup, RelationGetDescr(rel), values, nulls, updated); - CatalogTupleUpdate(rel, &tup->t_self, tup); + CatalogTupleUpdate(rel, &tup->t_self, tup, updated, NULL); heap_freetuple(tup); } @@ -2000,6 +1956,7 @@ AlterSubscription(ParseState *pstate, AlterSubscriptionStmt *stmt, /* Wake up related replication workers to handle this change quickly. */ LogicalRepWorkersWakeupAtCommit(subid); + bms_free(updated); return myself; } @@ -2355,6 +2312,7 @@ AlterSubscriptionOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId) { Form_pg_subscription form; AclResult aclresult; + Bitmapset *updated = NULL; form = (Form_pg_subscription) GETSTRUCT(tup); @@ -2391,8 +2349,8 @@ AlterSubscriptionOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId) aclcheck_error(aclresult, OBJECT_DATABASE, get_database_name(MyDatabaseId)); - form->subowner = newOwnerId; - CatalogTupleUpdate(rel, &tup->t_self, tup); + HeapTupleUpdateField(pg_subscription, subowner, newOwnerId, form, updated); + CatalogTupleUpdate(rel, &tup->t_self, tup, updated, NULL); /* Update owner dependency reference */ changeDependencyOnOwner(SubscriptionRelationId, @@ -2405,6 +2363,7 @@ AlterSubscriptionOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId) /* Wake up related background processes to handle this change quickly. */ ApplyLauncherWakeupAtCommit(); LogicalRepWorkersWakeupAtCommit(form->oid); + bms_free(updated); } /* diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 23ebaa3f23002..c7ecb2c10cce8 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -3641,6 +3641,7 @@ SetRelationHasSubclass(Oid relationId, bool relhassubclass) Relation relationRelation; HeapTuple tuple; Form_pg_class classtuple; + Bitmapset *updated = NULL; Assert(CheckRelationOidLockedByMe(relationId, ShareUpdateExclusiveLock, false) || @@ -3658,8 +3659,8 @@ SetRelationHasSubclass(Oid relationId, bool relhassubclass) if (classtuple->relhassubclass != relhassubclass) { - classtuple->relhassubclass = relhassubclass; - CatalogTupleUpdate(relationRelation, &tuple->t_self, tuple); + HeapTupleUpdateField(pg_class, relhassubclass, relhassubclass, classtuple, updated); + CatalogTupleUpdate(relationRelation, &tuple->t_self, tuple, updated, NULL); } else { @@ -3668,6 +3669,7 @@ SetRelationHasSubclass(Oid relationId, bool relhassubclass) } heap_freetuple(tuple); + bms_free(updated); table_close(relationRelation, RowExclusiveLock); } @@ -3747,6 +3749,8 @@ SetRelationTableSpace(Relation rel, HeapTuple tuple; ItemPointerData otid; Form_pg_class rd_rel; + Bitmapset *updated = NULL; + Oid field = InvalidOid; Oid reloid = RelationGetRelid(rel); Assert(CheckRelationTableSpaceMove(rel, newTableSpaceId)); @@ -3761,11 +3765,16 @@ SetRelationTableSpace(Relation rel, rd_rel = (Form_pg_class) GETSTRUCT(tuple); /* Update the pg_class row. */ - rd_rel->reltablespace = (newTableSpaceId == MyDatabaseTableSpace) ? - InvalidOid : newTableSpaceId; + if (newTableSpaceId != MyDatabaseTableSpace) + field = newTableSpaceId; + + HeapTupleUpdateField(pg_class, reltablespace, field, rd_rel, updated); + if (RelFileNumberIsValid(newRelFilenumber)) - rd_rel->relfilenode = newRelFilenumber; - CatalogTupleUpdate(pg_class, &otid, tuple); + HeapTupleUpdateField(pg_class, relfilenode, newRelFilenumber, rd_rel, updated); + + CatalogTupleUpdate(pg_class, &otid, tuple, updated, NULL); + UnlockTuple(pg_class, &otid, InplaceUpdateTupleLock); /* @@ -3777,6 +3786,7 @@ SetRelationTableSpace(Relation rel, rd_rel->reltablespace); heap_freetuple(tuple); + bms_free(updated); table_close(pg_class, RowExclusiveLock); } @@ -3846,6 +3856,7 @@ renameatt_internal(Oid myrelid, HeapTuple atttup; Form_pg_attribute attform; AttrNumber attnum; + Bitmapset *updated = NULL; /* * Grab an exclusive lock on the target table, which we will NOT release @@ -3959,9 +3970,9 @@ renameatt_internal(Oid myrelid, (void) check_for_column_name_collision(targetrelation, newattname, false); /* apply the update */ - namestrcpy(&(attform->attname), newattname); - - CatalogTupleUpdate(attrelation, &atttup->t_self, atttup); + namestrcpy(&attform->attname, newattname); + CatalogTupleUpdate(attrelation, &atttup->t_self, atttup, updated, NULL); + bms_free(updated); InvokeObjectPostAlterHook(RelationRelationId, myrelid, attnum); @@ -4267,6 +4278,7 @@ RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, bo HeapTuple reltup; Form_pg_class relform; Oid namespaceId; + Bitmapset *updated = NULL; /* * Grab a lock on the target relation, which we will NOT release until end @@ -4312,9 +4324,11 @@ RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, bo * Update pg_class tuple with new relname. (Scribbling on reltup is OK * because it's a copy...) */ - namestrcpy(&(relform->relname), newrelname); - CatalogTupleUpdate(relrelation, &otid, reltup); + namestrcpy(&relform->relname, newrelname); + CatalogTupleUpdate(relrelation, &otid, reltup, updated, NULL); + bms_free(updated); + UnlockTuple(relrelation, &otid, InplaceUpdateTupleLock); InvokeObjectPostAlterHookArg(RelationRelationId, myrelid, 0, @@ -4357,6 +4371,7 @@ ResetRelRewrite(Oid myrelid) Relation relrelation; /* for RELATION relation */ HeapTuple reltup; Form_pg_class relform; + Bitmapset *updated = NULL; /* * Find relation's pg_class tuple. @@ -4368,13 +4383,11 @@ ResetRelRewrite(Oid myrelid) elog(ERROR, "cache lookup failed for relation %u", myrelid); relform = (Form_pg_class) GETSTRUCT(reltup); - /* - * Update pg_class tuple. - */ - relform->relrewrite = InvalidOid; - - CatalogTupleUpdate(relrelation, &reltup->t_self, reltup); + /* Update pg_class tuple */ + HeapTupleUpdateField(pg_class, relrewrite, InvalidOid, relform, updated); + CatalogTupleUpdate(relrelation, &reltup->t_self, reltup, updated, NULL); + bms_free(updated); heap_freetuple(reltup); table_close(relrelation, RowExclusiveLock); } @@ -7227,6 +7240,7 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel, AlterTableCmd *childcmd; ObjectAddress address; TupleDesc tupdesc; + Bitmapset *updated = NULL; /* since this function recurses, it could be driven to stack overflow */ check_stack_depth(); @@ -7286,8 +7300,13 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel, ereport(ERROR, errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("too many inheritance parents")); - CatalogTupleUpdate(attrdesc, &tuple->t_self, tuple); + HeapTupleMarkColumnUpdated(pg_attribute, attinhcount, updated); + + CatalogTupleUpdate(attrdesc, &tuple->t_self, tuple, updated, NULL); + + bms_free(updated); + updated = NULL; heap_freetuple(tuple); /* Inform the user about the merge */ @@ -7385,9 +7404,10 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel, /* * Update pg_class tuple as appropriate */ - relform->relnatts = newattnum; - - CatalogTupleUpdate(pgclass, &reltup->t_self, reltup); + Assert(bms_is_empty(updated)); + HeapTupleUpdateField(pg_class, relnatts, newattnum, relform, updated); + CatalogTupleUpdate(pgclass, &reltup->t_self, reltup, updated, NULL); + bms_free(updated); heap_freetuple(reltup); @@ -7851,6 +7871,7 @@ set_attnotnull(List **wqueue, Relation rel, AttrNumber attnum, { Relation attr_rel; HeapTuple tuple; + Bitmapset *updated = NULL; attr_rel = table_open(AttributeRelationId, RowExclusiveLock); @@ -7864,8 +7885,9 @@ set_attnotnull(List **wqueue, Relation rel, AttrNumber attnum, attr = (Form_pg_attribute) GETSTRUCT(tuple); - attr->attnotnull = true; - CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple); + HeapTupleUpdateField(pg_attribute, attnotnull, true, attr, updated); + CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple, updated, NULL); + bms_free(updated); /* * If the nullness isn't already proven by validated constraints, have @@ -7944,6 +7966,7 @@ ATExecSetNotNull(List **wqueue, Relation rel, char *conName, char *colName, { Form_pg_constraint conForm = (Form_pg_constraint) GETSTRUCT(tuple); bool changed = false; + Bitmapset *updated = NULL; /* * Don't let a NO INHERIT constraint be changed into inherit. @@ -7967,11 +7990,12 @@ ATExecSetNotNull(List **wqueue, Relation rel, char *conName, char *colName, ereport(ERROR, errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("too many inheritance parents")); + HeapTupleMarkColumnUpdated(pg_constraint, coninhcount, updated); changed = true; } else if (!conForm->conislocal) { - conForm->conislocal = true; + HeapTupleUpdateField(pg_constraint, conislocal, true, conForm, updated); changed = true; } else if (!conForm->convalidated) @@ -7990,7 +8014,8 @@ ATExecSetNotNull(List **wqueue, Relation rel, char *conName, char *colName, constr_rel = table_open(ConstraintRelationId, RowExclusiveLock); - CatalogTupleUpdate(constr_rel, &tuple->t_self, tuple); + CatalogTupleUpdate(constr_rel, &tuple->t_self, tuple, updated, NULL); + bms_free(updated); ObjectAddressSet(address, ConstraintRelationId, conForm->oid); table_close(constr_rel, RowExclusiveLock); } @@ -8238,6 +8263,7 @@ ATExecAddIdentity(Relation rel, const char *colName, AttrNumber attnum; ObjectAddress address; ColumnDef *cdef = castNode(ColumnDef, def); + Bitmapset *updated = NULL; bool ispartitioned; ispartitioned = (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE); @@ -8318,8 +8344,9 @@ ATExecAddIdentity(Relation rel, const char *colName, errmsg("column \"%s\" of relation \"%s\" already has a default value", colName, RelationGetRelationName(rel)))); - attTup->attidentity = cdef->identity; - CatalogTupleUpdate(attrelation, &tuple->t_self, tuple); + HeapTupleUpdateField(pg_attribute, attidentity, cdef->identity, attTup, updated); + CatalogTupleUpdate(attrelation, &tuple->t_self, tuple, updated, NULL); + bms_free(updated); InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), @@ -8432,8 +8459,11 @@ ATExecSetIdentity(Relation rel, const char *colName, Node *def, if (generatedEl) { - attTup->attidentity = defGetInt32(generatedEl); - CatalogTupleUpdate(attrelation, &tuple->t_self, tuple); + Bitmapset *updated = NULL; + + HeapTupleUpdateField(pg_attribute, attidentity, defGetInt32(generatedEl), attTup, updated); + CatalogTupleUpdate(attrelation, &tuple->t_self, tuple, updated, NULL); + bms_free(updated); InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), @@ -8488,6 +8518,7 @@ ATExecDropIdentity(Relation rel, const char *colName, bool missing_ok, LOCKMODE Oid seqid; ObjectAddress seqaddress; bool ispartitioned; + Bitmapset *updated = NULL; ispartitioned = (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE); if (ispartitioned && !recurse) @@ -8536,8 +8567,9 @@ ATExecDropIdentity(Relation rel, const char *colName, bool missing_ok, LOCKMODE } } - attTup->attidentity = '\0'; - CatalogTupleUpdate(attrelation, &tuple->t_self, tuple); + HeapTupleUpdateField(pg_attribute, attidentity, '\0', attTup, updated); + CatalogTupleUpdate(attrelation, &tuple->t_self, tuple, updated, NULL); + bms_free(updated); InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), @@ -8799,6 +8831,7 @@ ATExecDropExpression(Relation rel, const char *colName, bool missing_ok, LOCKMOD Relation attrelation; Oid attrdefoid; ObjectAddress address; + Bitmapset *updated = NULL; attrelation = table_open(AttributeRelationId, RowExclusiveLock); tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName); @@ -8852,8 +8885,9 @@ ATExecDropExpression(Relation rel, const char *colName, bool missing_ok, LOCKMOD * Mark the column as no longer generated. (The atthasdef flag needs to * get cleared too, but RemoveAttrDefault will handle that.) */ - attTup->attgenerated = '\0'; - CatalogTupleUpdate(attrelation, &tuple->t_self, tuple); + HeapTupleUpdateField(pg_attribute, attgenerated, '\0', attTup, updated); + CatalogTupleUpdate(attrelation, &tuple->t_self, tuple, updated, NULL); + bms_free(updated); InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), @@ -8905,9 +8939,9 @@ ATExecSetStatistics(Relation rel, const char *colName, int16 colNum, Node *newVa Form_pg_attribute attrtuple; AttrNumber attnum; ObjectAddress address; - Datum repl_val[Natts_pg_attribute]; - bool repl_null[Natts_pg_attribute]; - bool repl_repl[Natts_pg_attribute]; + Datum values[Natts_pg_attribute] = {0}; + bool nulls[Natts_pg_attribute] = {false}; + Bitmapset *updated = NULL; /* * We allow referencing columns by numbers only for indexes, since table @@ -9010,16 +9044,14 @@ ATExecSetStatistics(Relation rel, const char *colName, int16 colNum, Node *newVa } /* Build new tuple. */ - memset(repl_null, false, sizeof(repl_null)); - memset(repl_repl, false, sizeof(repl_repl)); if (!newtarget_default) - repl_val[Anum_pg_attribute_attstattarget - 1] = Int16GetDatum(newtarget); + HeapTupleUpdateValue(pg_attribute, attstattarget, Int16GetDatum(newtarget), values, nulls, updated); else - repl_null[Anum_pg_attribute_attstattarget - 1] = true; - repl_repl[Anum_pg_attribute_attstattarget - 1] = true; - newtuple = heap_modify_tuple(tuple, RelationGetDescr(attrelation), - repl_val, repl_null, repl_repl); - CatalogTupleUpdate(attrelation, &tuple->t_self, newtuple); + HeapTupleUpdateValueNull(pg_attribute, attstattarget, values, nulls, updated); + newtuple = heap_update_tuple(tuple, RelationGetDescr(attrelation), + values, nulls, updated); + CatalogTupleUpdate(attrelation, &tuple->t_self, newtuple, updated, NULL); + bms_free(updated); InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), @@ -9052,9 +9084,9 @@ ATExecSetOptions(Relation rel, const char *colName, Node *options, newOptions; bool isnull; ObjectAddress address; - Datum repl_val[Natts_pg_attribute]; - bool repl_null[Natts_pg_attribute]; - bool repl_repl[Natts_pg_attribute]; + Datum values[Natts_pg_attribute] = {0}; + bool nulls[Natts_pg_attribute] = {false}; + Bitmapset *updated = NULL; attrelation = table_open(AttributeRelationId, RowExclusiveLock); @@ -9084,18 +9116,17 @@ ATExecSetOptions(Relation rel, const char *colName, Node *options, (void) attribute_reloptions(newOptions, true); /* Build new tuple. */ - memset(repl_null, false, sizeof(repl_null)); - memset(repl_repl, false, sizeof(repl_repl)); if (newOptions != (Datum) 0) - repl_val[Anum_pg_attribute_attoptions - 1] = newOptions; + HeapTupleUpdateValue(pg_attribute, attoptions, newOptions, values, nulls, updated); else - repl_null[Anum_pg_attribute_attoptions - 1] = true; - repl_repl[Anum_pg_attribute_attoptions - 1] = true; - newtuple = heap_modify_tuple(tuple, RelationGetDescr(attrelation), - repl_val, repl_null, repl_repl); + HeapTupleUpdateValueNull(pg_attribute, attoptions, values, nulls, updated); + + newtuple = heap_update_tuple(tuple, RelationGetDescr(attrelation), + values, nulls, updated); /* Update system catalog. */ - CatalogTupleUpdate(attrelation, &newtuple->t_self, newtuple); + CatalogTupleUpdate(attrelation, &newtuple->t_self, newtuple, updated, NULL); + bms_free(updated); InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), @@ -9156,19 +9187,21 @@ SetIndexStorageProperties(Relation rel, Relation attrelation, if (HeapTupleIsValid(tuple)) { Form_pg_attribute attrtuple = (Form_pg_attribute) GETSTRUCT(tuple); + Bitmapset *updated = NULL; if (setstorage) - attrtuple->attstorage = newstorage; + HeapTupleUpdateField(pg_attribute, attstorage, newstorage, attrtuple, updated); if (setcompression) - attrtuple->attcompression = newcompression; + HeapTupleUpdateField(pg_attribute, attcompression, newcompression, attrtuple, updated); - CatalogTupleUpdate(attrelation, &tuple->t_self, tuple); + CatalogTupleUpdate(attrelation, &tuple->t_self, tuple, updated, NULL); InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), attrtuple->attnum); + bms_free(updated); heap_freetuple(tuple); } @@ -9189,6 +9222,7 @@ ATExecSetStorage(Relation rel, const char *colName, Node *newValue, LOCKMODE loc Form_pg_attribute attrtuple; AttrNumber attnum; ObjectAddress address; + Bitmapset *updated = NULL; attrelation = table_open(AttributeRelationId, RowExclusiveLock); @@ -9208,9 +9242,9 @@ ATExecSetStorage(Relation rel, const char *colName, Node *newValue, LOCKMODE loc errmsg("cannot alter system column \"%s\"", colName))); - attrtuple->attstorage = GetAttributeStorage(attrtuple->atttypid, strVal(newValue)); + HeapTupleUpdateField(pg_attribute, attstorage, GetAttributeStorage(attrtuple->atttypid, strVal(newValue)), attrtuple, updated); - CatalogTupleUpdate(attrelation, &tuple->t_self, tuple); + CatalogTupleUpdate(attrelation, &tuple->t_self, tuple, updated, NULL); InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), @@ -9225,6 +9259,7 @@ ATExecSetStorage(Relation rel, const char *colName, Node *newValue, LOCKMODE loc false, 0, lockmode); + bms_free(updated); heap_freetuple(tuple); table_close(attrelation, RowExclusiveLock); @@ -9418,9 +9453,11 @@ ATExecDropColumn(List **wqueue, Relation rel, const char *colName, else { /* Child column must survive my deletion */ - childatt->attinhcount--; + Bitmapset *updated = NULL; - CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple); + HeapTupleUpdateField(pg_attribute, attinhcount, childatt->attinhcount - 1, childatt, updated); + CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple, updated, NULL); + bms_free(updated); /* Make update visible */ CommandCounterIncrement(); @@ -9433,10 +9470,12 @@ ATExecDropColumn(List **wqueue, Relation rel, const char *colName, * we need to mark the inheritors' attributes as locally * defined rather than inherited. */ - childatt->attinhcount--; - childatt->attislocal = true; + Bitmapset *updated = NULL; - CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple); + HeapTupleUpdateField(pg_attribute, attinhcount, childatt->attinhcount - 1, childatt, updated); + HeapTupleUpdateField(pg_attribute, attislocal, true, childatt, updated); + CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple, updated, NULL); + bms_free(updated); /* Make update visible */ CommandCounterIncrement(); @@ -12648,16 +12687,22 @@ ATExecAlterConstrInheritability(List **wqueue, ATAlterConstraint *cmdcon, { HeapTuple childtup; Form_pg_constraint childcon; + Bitmapset *updated = NULL; childtup = findNotNullConstraint(childoid, colName); if (!childtup) elog(ERROR, "cache lookup failed for not-null constraint on column \"%s\" of relation %u", colName, childoid); + childcon = (Form_pg_constraint) GETSTRUCT(childtup); Assert(childcon->coninhcount > 0); - childcon->coninhcount--; - childcon->conislocal = true; - CatalogTupleUpdate(conrel, &childtup->t_self, childtup); + + HeapTupleUpdateField(pg_constraint, coninhcount, childcon->coninhcount - 1, childcon, updated); + HeapTupleUpdateField(pg_constraint, conislocal, true, childcon, updated); + + CatalogTupleUpdate(conrel, &childtup->t_self, childtup, updated, NULL); + + bms_free(updated); heap_freetuple(childtup); } else @@ -12702,6 +12747,7 @@ AlterConstrTriggerDeferrability(Oid conoid, Relation tgrel, Relation rel, Form_pg_trigger tgform = (Form_pg_trigger) GETSTRUCT(tgtuple); Form_pg_trigger copy_tg; HeapTuple tgCopyTuple; + Bitmapset *updated = NULL; /* * Remember OIDs of other relation(s) involved in FK constraint. @@ -12728,12 +12774,14 @@ AlterConstrTriggerDeferrability(Oid conoid, Relation tgrel, Relation rel, tgCopyTuple = heap_copytuple(tgtuple); copy_tg = (Form_pg_trigger) GETSTRUCT(tgCopyTuple); - copy_tg->tgdeferrable = deferrable; - copy_tg->tginitdeferred = initdeferred; - CatalogTupleUpdate(tgrel, &tgCopyTuple->t_self, tgCopyTuple); + HeapTupleUpdateField(pg_trigger, tgdeferrable, deferrable, copy_tg, updated); + HeapTupleUpdateField(pg_trigger, tginitdeferred, initdeferred, copy_tg, updated); + + CatalogTupleUpdate(tgrel, &tgCopyTuple->t_self, tgCopyTuple, updated, NULL); InvokeObjectPostAlterHook(TriggerRelationId, tgform->oid, 0); + bms_free(updated); heap_freetuple(tgCopyTuple); } @@ -12848,6 +12896,7 @@ AlterConstrUpdateConstraintEntry(ATAlterConstraint *cmdcon, Relation conrel, { HeapTuple copyTuple; Form_pg_constraint copy_con; + Bitmapset *updated = NULL; Assert(cmdcon->alterEnforceability || cmdcon->alterDeferrability || cmdcon->alterInheritability); @@ -12857,7 +12906,7 @@ AlterConstrUpdateConstraintEntry(ATAlterConstraint *cmdcon, Relation conrel, if (cmdcon->alterEnforceability) { - copy_con->conenforced = cmdcon->is_enforced; + HeapTupleUpdateField(pg_constraint, conenforced, cmdcon->is_enforced, copy_con, updated); /* * NB: The convalidated status is irrelevant when the constraint is @@ -12866,22 +12915,26 @@ AlterConstrUpdateConstraintEntry(ATAlterConstraint *cmdcon, Relation conrel, * ENFORCED, validation will be performed during phase 3, so it makes * sense to mark it as valid in that case. */ - copy_con->convalidated = cmdcon->is_enforced; + HeapTupleUpdateField(pg_constraint, convalidated, cmdcon->is_enforced, copy_con, updated); } + if (cmdcon->alterDeferrability) { - copy_con->condeferrable = cmdcon->deferrable; - copy_con->condeferred = cmdcon->initdeferred; + HeapTupleUpdateField(pg_constraint, condeferrable, cmdcon->deferrable, copy_con, updated); + HeapTupleUpdateField(pg_constraint, condeferred, cmdcon->initdeferred, copy_con, updated); } + if (cmdcon->alterInheritability) - copy_con->connoinherit = cmdcon->noinherit; + HeapTupleUpdateField(pg_constraint, connoinherit, cmdcon->noinherit, copy_con, updated); + + CatalogTupleUpdate(conrel, ©Tuple->t_self, copyTuple, updated, NULL); - CatalogTupleUpdate(conrel, ©Tuple->t_self, copyTuple); InvokeObjectPostAlterHook(ConstraintRelationId, copy_con->oid, 0); /* Make new constraint flags visible to others */ CacheInvalidateRelcacheByRelid(copy_con->conrelid); + bms_free(updated); heap_freetuple(copyTuple); } @@ -12994,6 +13047,7 @@ QueueFKConstraintValidation(List **wqueue, Relation conrel, Relation fkrel, AlteredTableInfo *tab; HeapTuple copyTuple; Form_pg_constraint copy_con; + Bitmapset *updated = NULL; con = (Form_pg_constraint) GETSTRUCT(contuple); Assert(con->contype == CONSTRAINT_FOREIGN); @@ -13090,11 +13144,14 @@ QueueFKConstraintValidation(List **wqueue, Relation conrel, Relation fkrel, */ copyTuple = heap_copytuple(contuple); copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple); - copy_con->convalidated = true; - CatalogTupleUpdate(conrel, ©Tuple->t_self, copyTuple); + + HeapTupleUpdateField(pg_constraint, convalidated, true, copy_con, updated); + + CatalogTupleUpdate(conrel, ©Tuple->t_self, copyTuple, updated, NULL); InvokeObjectPostAlterHook(ConstraintRelationId, con->oid, 0); + bms_free(updated); heap_freetuple(copyTuple); } @@ -13120,6 +13177,7 @@ QueueCheckConstraintValidation(List **wqueue, Relation conrel, Relation rel, NewConstraint *newcon; Datum val; char *conbin; + Bitmapset *updated = NULL; con = (Form_pg_constraint) GETSTRUCT(contuple); Assert(con->contype == CONSTRAINT_CHECK); @@ -13193,11 +13251,14 @@ QueueCheckConstraintValidation(List **wqueue, Relation conrel, Relation rel, */ copyTuple = heap_copytuple(contuple); copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple); - copy_con->convalidated = true; - CatalogTupleUpdate(conrel, ©Tuple->t_self, copyTuple); + + HeapTupleUpdateField(pg_constraint, convalidated, true, copy_con, updated); + + CatalogTupleUpdate(conrel, ©Tuple->t_self, copyTuple, updated, NULL); InvokeObjectPostAlterHook(ConstraintRelationId, con->oid, 0); + bms_free(updated); heap_freetuple(copyTuple); } @@ -13220,6 +13281,7 @@ QueueNNConstraintValidation(List **wqueue, Relation conrel, Relation rel, List *children = NIL; AttrNumber attnum; char *colname; + Bitmapset *updated = NULL; con = (Form_pg_constraint) GETSTRUCT(contuple); Assert(con->contype == CONSTRAINT_NOTNULL); @@ -13296,11 +13358,14 @@ QueueNNConstraintValidation(List **wqueue, Relation conrel, Relation rel, */ copyTuple = heap_copytuple(contuple); copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple); - copy_con->convalidated = true; - CatalogTupleUpdate(conrel, ©Tuple->t_self, copyTuple); + + HeapTupleUpdateField(pg_constraint, convalidated, true, copy_con, updated); + + CatalogTupleUpdate(conrel, ©Tuple->t_self, copyTuple, updated, NULL); InvokeObjectPostAlterHook(ConstraintRelationId, con->oid, 0); + bms_free(updated); heap_freetuple(copyTuple); } @@ -14175,8 +14240,11 @@ dropconstraint_internal(Relation rel, HeapTuple constraintTup, DropBehavior beha /* All good -- reset attnotnull if needed */ if (attForm->attnotnull) { - attForm->attnotnull = false; - CatalogTupleUpdate(attrel, &atttup->t_self, atttup); + Bitmapset *updated = NULL; + + HeapTupleUpdateField(pg_attribute, attnotnull, false, attForm, updated); + CatalogTupleUpdate(attrel, &atttup->t_self, atttup, updated, NULL); + bms_free(updated); } table_close(attrel, RowExclusiveLock); @@ -14309,11 +14377,16 @@ dropconstraint_internal(Relation rel, HeapTuple constraintTup, DropBehavior beha else { /* Child constraint must survive my deletion */ - childcon->coninhcount--; - CatalogTupleUpdate(conrel, &tuple->t_self, tuple); + Bitmapset *updated = NULL; + + HeapTupleUpdateField(pg_constraint, coninhcount, childcon->coninhcount - 1, childcon, updated); + + CatalogTupleUpdate(conrel, &tuple->t_self, tuple, updated, NULL); /* Make update visible */ CommandCounterIncrement(); + + bms_free(updated); } } else @@ -14324,14 +14397,19 @@ dropconstraint_internal(Relation rel, HeapTuple constraintTup, DropBehavior beha * mark the inheritors' constraints as locally defined rather than * inherited. */ - childcon->coninhcount--; + Bitmapset *updated = NULL; + + HeapTupleUpdateField(pg_constraint, coninhcount, childcon->coninhcount - 1, childcon, updated); + if (childcon->coninhcount == 0) - childcon->conislocal = true; + HeapTupleUpdateField(pg_constraint, conislocal, true, childcon, updated); - CatalogTupleUpdate(conrel, &tuple->t_self, tuple); + CatalogTupleUpdate(conrel, &tuple->t_self, tuple, updated, NULL); /* Make update visible */ CommandCounterIncrement(); + + bms_free(updated); } heap_freetuple(tuple); @@ -14737,6 +14815,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel, SysScanDesc scan; HeapTuple depTup; ObjectAddress address; + Bitmapset *updated = NULL; /* * Clear all the missing values if we're rewriting the table, since this @@ -14913,9 +14992,8 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel, int one = 1; bool isNull; - Datum valuesAtt[Natts_pg_attribute] = {0}; - bool nullsAtt[Natts_pg_attribute] = {0}; - bool replacesAtt[Natts_pg_attribute] = {0}; + Datum values[Natts_pg_attribute] = {0}; + bool nulls[Natts_pg_attribute] = {false}; HeapTuple newTup; missingval = array_get_element(missingval, @@ -14933,35 +15011,36 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel, tform->typbyval, tform->typalign)); - valuesAtt[Anum_pg_attribute_attmissingval - 1] = missingval; - replacesAtt[Anum_pg_attribute_attmissingval - 1] = true; - nullsAtt[Anum_pg_attribute_attmissingval - 1] = false; + HeapTupleUpdateValue(pg_attribute, attmissingval, missingval, values, nulls, updated); - newTup = heap_modify_tuple(heapTup, RelationGetDescr(attrelation), - valuesAtt, nullsAtt, replacesAtt); + newTup = heap_update_tuple(heapTup, RelationGetDescr(attrelation), + values, nulls, updated); heap_freetuple(heapTup); + bms_free(updated); + updated = NULL; + heapTup = newTup; attTup = (Form_pg_attribute) GETSTRUCT(heapTup); } } - attTup->atttypid = targettype; - attTup->atttypmod = targettypmod; - attTup->attcollation = targetcollid; + HeapTupleUpdateField(pg_attribute, atttypid, targettype, attTup, updated); + HeapTupleUpdateField(pg_attribute, atttypmod, targettypmod, attTup, updated); + HeapTupleUpdateField(pg_attribute, attcollation, targetcollid, attTup, updated); if (list_length(typeName->arrayBounds) > PG_INT16_MAX) ereport(ERROR, errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("too many array dimensions")); - attTup->attndims = list_length(typeName->arrayBounds); - attTup->attlen = tform->typlen; - attTup->attbyval = tform->typbyval; - attTup->attalign = tform->typalign; - attTup->attstorage = tform->typstorage; - attTup->attcompression = InvalidCompressionMethod; + HeapTupleUpdateField(pg_attribute, attndims, list_length(typeName->arrayBounds), attTup, updated); + HeapTupleUpdateField(pg_attribute, attlen, tform->typlen, attTup, updated); + HeapTupleUpdateField(pg_attribute, attbyval, tform->typbyval, attTup, updated); + HeapTupleUpdateField(pg_attribute, attalign, tform->typalign, attTup, updated); + HeapTupleUpdateField(pg_attribute, attstorage, tform->typstorage, attTup, updated); + HeapTupleUpdateField(pg_attribute, attcompression, InvalidCompressionMethod, attTup, updated); ReleaseSysCache(typeTuple); - CatalogTupleUpdate(attrelation, &heapTup->t_self, heapTup); + CatalogTupleUpdate(attrelation, &heapTup->t_self, heapTup, updated, NULL); table_close(attrelation, RowExclusiveLock); @@ -15021,6 +15100,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel, RelationGetRelid(rel), attnum); /* Cleanup */ + bms_free(updated); heap_freetuple(heapTup); return address; @@ -15956,9 +16036,9 @@ ATExecAlterColumnGenericOptions(Relation rel, HeapTuple tuple; HeapTuple newtuple; bool isnull; - Datum repl_val[Natts_pg_attribute]; - bool repl_null[Natts_pg_attribute]; - bool repl_repl[Natts_pg_attribute]; + Datum values[Natts_pg_attribute] = {0}; + bool nulls[Natts_pg_attribute] = {false}; + Bitmapset *updated = NULL; Datum datum; Form_pg_foreign_table fttableform; Form_pg_attribute atttableform; @@ -16000,11 +16080,6 @@ ATExecAlterColumnGenericOptions(Relation rel, errmsg("cannot alter system column \"%s\"", colName))); - /* Initialize buffers for new tuple values */ - memset(repl_val, 0, sizeof(repl_val)); - memset(repl_null, false, sizeof(repl_null)); - memset(repl_repl, false, sizeof(repl_repl)); - /* Extract the current options */ datum = SysCacheGetAttr(ATTNAME, tuple, @@ -16020,18 +16095,15 @@ ATExecAlterColumnGenericOptions(Relation rel, fdw->fdwvalidator); if (DatumGetPointer(datum) != NULL) - repl_val[Anum_pg_attribute_attfdwoptions - 1] = datum; + HeapTupleUpdateValue(pg_attribute, attfdwoptions, datum, values, nulls, updated); else - repl_null[Anum_pg_attribute_attfdwoptions - 1] = true; - - repl_repl[Anum_pg_attribute_attfdwoptions - 1] = true; + HeapTupleUpdateValueNull(pg_attribute, attfdwoptions, values, nulls, updated); /* Everything looks good - update the tuple */ + newtuple = heap_update_tuple(tuple, RelationGetDescr(attrel), + values, nulls, updated); - newtuple = heap_modify_tuple(tuple, RelationGetDescr(attrel), - repl_val, repl_null, repl_repl); - - CatalogTupleUpdate(attrel, &newtuple->t_self, newtuple); + CatalogTupleUpdate(attrel, &newtuple->t_self, newtuple, updated, NULL); InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), @@ -16043,6 +16115,7 @@ ATExecAlterColumnGenericOptions(Relation rel, table_close(attrel, RowExclusiveLock); + bms_free(updated); heap_freetuple(newtuple); return address; @@ -16169,13 +16242,13 @@ ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lock */ if (tuple_class->relowner != newOwnerId) { - Datum repl_val[Natts_pg_class]; - bool repl_null[Natts_pg_class]; - bool repl_repl[Natts_pg_class]; + Datum values[Natts_pg_class] = {0}; + bool nulls[Natts_pg_class] = {false}; Acl *newAcl; Datum aclDatum; bool isNull; HeapTuple newtuple; + Bitmapset *updated = NULL; /* skip permission checks when recursing to index or toast table */ if (!recursing) @@ -16203,11 +16276,7 @@ ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lock } } - memset(repl_null, false, sizeof(repl_null)); - memset(repl_repl, false, sizeof(repl_repl)); - - repl_repl[Anum_pg_class_relowner - 1] = true; - repl_val[Anum_pg_class_relowner - 1] = ObjectIdGetDatum(newOwnerId); + HeapTupleUpdateValue(pg_class, relowner, ObjectIdGetDatum(newOwnerId), values, nulls, updated); /* * Determine the modified ACL for the new owner. This is only @@ -16220,14 +16289,14 @@ ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lock { newAcl = aclnewowner(DatumGetAclP(aclDatum), tuple_class->relowner, newOwnerId); - repl_repl[Anum_pg_class_relacl - 1] = true; - repl_val[Anum_pg_class_relacl - 1] = PointerGetDatum(newAcl); + HeapTupleUpdateValue(pg_class, relacl, PointerGetDatum(newAcl), values, nulls, updated); } - newtuple = heap_modify_tuple(tuple, RelationGetDescr(class_rel), repl_val, repl_null, repl_repl); + newtuple = heap_update_tuple(tuple, RelationGetDescr(class_rel), values, nulls, updated); - CatalogTupleUpdate(class_rel, &newtuple->t_self, newtuple); + CatalogTupleUpdate(class_rel, &newtuple->t_self, newtuple, updated, NULL); + bms_free(updated); heap_freetuple(newtuple); /* @@ -16319,9 +16388,9 @@ change_owner_fix_column_acls(Oid relationOid, Oid oldOwnerId, Oid newOwnerId) while (HeapTupleIsValid(attributeTuple = systable_getnext(scan))) { Form_pg_attribute att = (Form_pg_attribute) GETSTRUCT(attributeTuple); - Datum repl_val[Natts_pg_attribute]; - bool repl_null[Natts_pg_attribute]; - bool repl_repl[Natts_pg_attribute]; + Datum values[Natts_pg_attribute] = {0}; + bool nulls[Natts_pg_attribute] = {false}; + Bitmapset *updated = NULL; Acl *newAcl; Datum aclDatum; bool isNull; @@ -16339,20 +16408,17 @@ change_owner_fix_column_acls(Oid relationOid, Oid oldOwnerId, Oid newOwnerId) if (isNull) continue; - memset(repl_null, false, sizeof(repl_null)); - memset(repl_repl, false, sizeof(repl_repl)); - newAcl = aclnewowner(DatumGetAclP(aclDatum), oldOwnerId, newOwnerId); - repl_repl[Anum_pg_attribute_attacl - 1] = true; - repl_val[Anum_pg_attribute_attacl - 1] = PointerGetDatum(newAcl); + HeapTupleUpdateValue(pg_attribute, attacl, PointerGetDatum(newAcl), values, nulls, updated); - newtuple = heap_modify_tuple(attributeTuple, + newtuple = heap_update_tuple(attributeTuple, RelationGetDescr(attRelation), - repl_val, repl_null, repl_repl); + values, nulls, updated); - CatalogTupleUpdate(attRelation, &newtuple->t_self, newtuple); + CatalogTupleUpdate(attRelation, &newtuple->t_self, newtuple, updated, NULL); + bms_free(updated); heap_freetuple(newtuple); } systable_endscan(scan); @@ -16521,6 +16587,7 @@ ATExecSetAccessMethodNoStorage(Relation rel, Oid newAccessMethodId) HeapTuple tuple; Form_pg_class rd_rel; Oid reloid = RelationGetRelid(rel); + Bitmapset *updated = NULL; /* * Shouldn't be called on relations having storage; these are processed in @@ -16538,17 +16605,18 @@ ATExecSetAccessMethodNoStorage(Relation rel, Oid newAccessMethodId) /* Update the pg_class row. */ oldAccessMethodId = rd_rel->relam; - rd_rel->relam = newAccessMethodId; + HeapTupleUpdateField(pg_class, relam, newAccessMethodId, rd_rel, updated); /* Leave if no update required */ if (rd_rel->relam == oldAccessMethodId) { + bms_free(updated); heap_freetuple(tuple); table_close(pg_class, RowExclusiveLock); return; } - CatalogTupleUpdate(pg_class, &tuple->t_self, tuple); + CatalogTupleUpdate(pg_class, &tuple->t_self, tuple, updated, NULL); /* * Update the dependency on the new access method. No dependency is added @@ -16596,6 +16664,7 @@ ATExecSetAccessMethodNoStorage(Relation rel, Oid newAccessMethodId) InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), 0); + bms_free(updated); heap_freetuple(tuple); table_close(pg_class, RowExclusiveLock); } @@ -16643,9 +16712,9 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation, HeapTuple newtuple; Datum datum; Datum newOptions; - Datum repl_val[Natts_pg_class]; - bool repl_null[Natts_pg_class]; - bool repl_repl[Natts_pg_class]; + Datum values[Natts_pg_class] = {0}; + bool nulls[Natts_pg_class] = {false}; + Bitmapset *updated = NULL; const char *const validnsps[] = HEAP_RELOPT_NAMESPACES; if (defList == NIL && operation != AT_ReplaceRelOptions) @@ -16747,25 +16816,23 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation, * All we need do here is update the pg_class row; the new options will be * propagated into relcaches during post-commit cache inval. */ - memset(repl_val, 0, sizeof(repl_val)); - memset(repl_null, false, sizeof(repl_null)); - memset(repl_repl, false, sizeof(repl_repl)); if (newOptions != (Datum) 0) - repl_val[Anum_pg_class_reloptions - 1] = newOptions; + HeapTupleUpdateValue(pg_class, reloptions, newOptions, values, nulls, updated); else - repl_null[Anum_pg_class_reloptions - 1] = true; + HeapTupleUpdateValueNull(pg_class, reloptions, values, nulls, updated); - repl_repl[Anum_pg_class_reloptions - 1] = true; + newtuple = heap_update_tuple(tuple, RelationGetDescr(pgclass), + values, nulls, updated); - newtuple = heap_modify_tuple(tuple, RelationGetDescr(pgclass), - repl_val, repl_null, repl_repl); + CatalogTupleUpdate(pgclass, &newtuple->t_self, newtuple, updated, NULL); - CatalogTupleUpdate(pgclass, &newtuple->t_self, newtuple); UnlockTuple(pgclass, &tuple->t_self, InplaceUpdateTupleLock); InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), 0); + bms_free(updated); + updated = NULL; heap_freetuple(newtuple); ReleaseSysCache(tuple); @@ -16807,26 +16874,25 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation, (void) heap_reloptions(RELKIND_TOASTVALUE, newOptions, true); - memset(repl_val, 0, sizeof(repl_val)); - memset(repl_null, false, sizeof(repl_null)); - memset(repl_repl, false, sizeof(repl_repl)); + memset(values, 0, sizeof(values)); + memset(nulls, false, sizeof(nulls)); + Assert(bms_is_empty(updated)); if (newOptions != (Datum) 0) - repl_val[Anum_pg_class_reloptions - 1] = newOptions; + HeapTupleUpdateValue(pg_class, reloptions, newOptions, values, nulls, updated); else - repl_null[Anum_pg_class_reloptions - 1] = true; - - repl_repl[Anum_pg_class_reloptions - 1] = true; + HeapTupleUpdateValueNull(pg_class, reloptions, values, nulls, updated); - newtuple = heap_modify_tuple(tuple, RelationGetDescr(pgclass), - repl_val, repl_null, repl_repl); + newtuple = heap_update_tuple(tuple, RelationGetDescr(pgclass), + values, nulls, updated); - CatalogTupleUpdate(pgclass, &newtuple->t_self, newtuple); + CatalogTupleUpdate(pgclass, &newtuple->t_self, newtuple, updated, NULL); InvokeObjectPostAlterHookArg(RelationRelationId, RelationGetRelid(toastrel), 0, InvalidOid, true); + bms_free(updated); heap_freetuple(newtuple); ReleaseSysCache(tuple); @@ -17498,6 +17564,7 @@ MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel, bool ispart for (AttrNumber parent_attno = 1; parent_attno <= parent_desc->natts; parent_attno++) { Form_pg_attribute parent_att = TupleDescAttr(parent_desc, parent_attno - 1); + Bitmapset *updated = NULL; char *parent_attname = NameStr(parent_att->attname); HeapTuple tuple; @@ -17582,6 +17649,8 @@ MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel, bool ispart errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("too many inheritance parents")); + HeapTupleMarkColumnUpdated(pg_attribute, attinhcount, updated); + /* * In case of partitions, we must enforce that value of attislocal * is same in all partitions. (Note: there are only inherited @@ -17590,10 +17659,12 @@ MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel, bool ispart if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) { Assert(child_att->attinhcount == 1); - child_att->attislocal = false; + HeapTupleUpdateField(pg_attribute, attislocal, false, child_att, updated); } - CatalogTupleUpdate(attrrel, &tuple->t_self, tuple); + CatalogTupleUpdate(attrrel, &tuple->t_self, tuple, updated, NULL); + + bms_free(updated); heap_freetuple(tuple); } else @@ -17656,6 +17727,7 @@ MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel) HeapTuple child_tuple; AttrNumber parent_attno; bool found = false; + Bitmapset *updated = NULL; if (parent_con->contype != CONSTRAINT_CHECK && parent_con->contype != CONSTRAINT_NOTNULL) @@ -17764,6 +17836,8 @@ MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel) errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("too many inheritance parents")); + HeapTupleMarkColumnUpdated(pg_constraint, coninhcount, updated); + /* * In case of partitions, an inherited constraint must be * inherited only once since it cannot have multiple parents and @@ -17772,10 +17846,12 @@ MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel) if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) { Assert(child_con->coninhcount == 1); - child_con->conislocal = false; + HeapTupleUpdateField(pg_constraint, conislocal, false, child_con, updated); } - CatalogTupleUpdate(constraintrel, &child_copy->t_self, child_copy); + CatalogTupleUpdate(constraintrel, &child_copy->t_self, child_copy, updated, NULL); + + bms_free(updated); heap_freetuple(child_copy); found = true; @@ -17879,6 +17955,7 @@ MarkInheritDetached(Relation child_rel, Relation parent_rel) while (HeapTupleIsValid(inheritsTuple = systable_getnext(scan))) { Form_pg_inherits inhForm; + Bitmapset *updated = NULL; inhForm = (Form_pg_inherits) GETSTRUCT(inheritsTuple); if (inhForm->inhdetachpending) @@ -17893,14 +17970,18 @@ MarkInheritDetached(Relation child_rel, Relation parent_rel) if (inhForm->inhrelid == RelationGetRelid(child_rel)) { HeapTuple newtup; + Form_pg_inherits classForm; newtup = heap_copytuple(inheritsTuple); - ((Form_pg_inherits) GETSTRUCT(newtup))->inhdetachpending = true; + classForm = (Form_pg_inherits) GETSTRUCT(newtup); + + HeapTupleUpdateField(pg_inherits, inhdetachpending, true, classForm, updated); + + CatalogTupleUpdate(catalogRelation, &inheritsTuple->t_self, newtup, updated, NULL); - CatalogTupleUpdate(catalogRelation, - &inheritsTuple->t_self, - newtup); found = true; + + bms_free(updated); heap_freetuple(newtup); /* keep looking, to ensure we catch others pending detach */ } @@ -17985,6 +18066,7 @@ RemoveInheritance(Relation child_rel, Relation parent_rel, bool expect_detached) while (HeapTupleIsValid(attributeTuple = systable_getnext(scan))) { Form_pg_attribute att = (Form_pg_attribute) GETSTRUCT(attributeTuple); + Bitmapset *updated = NULL; /* Ignore if dropped or not inherited */ if (att->attisdropped) @@ -17999,11 +18081,14 @@ RemoveInheritance(Relation child_rel, Relation parent_rel, bool expect_detached) HeapTuple copyTuple = heap_copytuple(attributeTuple); Form_pg_attribute copy_att = (Form_pg_attribute) GETSTRUCT(copyTuple); - copy_att->attinhcount--; + HeapTupleUpdateField(pg_attribute, attinhcount, copy_att->attinhcount - 1, copy_att, updated); + if (copy_att->attinhcount == 0) - copy_att->attislocal = true; + HeapTupleUpdateField(pg_attribute, attislocal, true, copy_att, updated); - CatalogTupleUpdate(catalogRelation, ©Tuple->t_self, copyTuple); + CatalogTupleUpdate(catalogRelation, ©Tuple->t_self, copyTuple, updated, NULL); + + bms_free(updated); heap_freetuple(copyTuple); } } @@ -18065,6 +18150,7 @@ RemoveInheritance(Relation child_rel, Relation parent_rel, bool expect_detached) { Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(constraintTuple); bool match = false; + Bitmapset *updated = NULL; /* * Match CHECK constraints by name, not-null constraints by column @@ -18110,11 +18196,14 @@ RemoveInheritance(Relation child_rel, Relation parent_rel, bool expect_detached) elog(ERROR, "relation %u has non-inherited constraint \"%s\"", RelationGetRelid(child_rel), NameStr(copy_con->conname)); - copy_con->coninhcount--; + HeapTupleUpdateField(pg_constraint, coninhcount, copy_con->coninhcount - 1, copy_con, updated); + if (copy_con->coninhcount == 0) - copy_con->conislocal = true; + HeapTupleUpdateField(pg_constraint, conislocal, true, copy_con, updated); - CatalogTupleUpdate(catalogRelation, ©Tuple->t_self, copyTuple); + CatalogTupleUpdate(catalogRelation, ©Tuple->t_self, copyTuple, updated, NULL); + + bms_free(updated); heap_freetuple(copyTuple); } } @@ -18220,6 +18309,7 @@ ATExecAddOf(Relation rel, const TypeName *ofTypename, LOCKMODE lockmode) ObjectAddress tableobj, typeobj; HeapTuple classtuple; + Bitmapset *updated = NULL; /* Validate the type. */ typetuple = typenameType(NULL, ofTypename, NULL); @@ -18325,11 +18415,14 @@ ATExecAddOf(Relation rel, const TypeName *ofTypename, LOCKMODE lockmode) classtuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid)); if (!HeapTupleIsValid(classtuple)) elog(ERROR, "cache lookup failed for relation %u", relid); - ((Form_pg_class) GETSTRUCT(classtuple))->reloftype = typeid; - CatalogTupleUpdate(relationRelation, &classtuple->t_self, classtuple); + + HeapTupleUpdateField(pg_class, reloftype, typeid, (Form_pg_class) GETSTRUCT(classtuple), updated); + + CatalogTupleUpdate(relationRelation, &classtuple->t_self, classtuple, updated, NULL); InvokeObjectPostAlterHook(RelationRelationId, relid, 0); + bms_free(updated); heap_freetuple(classtuple); table_close(relationRelation, RowExclusiveLock); @@ -18350,6 +18443,7 @@ ATExecDropOf(Relation rel, LOCKMODE lockmode) Oid relid = RelationGetRelid(rel); Relation relationRelation; HeapTuple tuple; + Bitmapset *updated = NULL; if (!OidIsValid(rel->rd_rel->reloftype)) ereport(ERROR, @@ -18370,11 +18464,14 @@ ATExecDropOf(Relation rel, LOCKMODE lockmode) tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid)); if (!HeapTupleIsValid(tuple)) elog(ERROR, "cache lookup failed for relation %u", relid); - ((Form_pg_class) GETSTRUCT(tuple))->reloftype = InvalidOid; - CatalogTupleUpdate(relationRelation, &tuple->t_self, tuple); + + HeapTupleUpdateField(pg_class, reloftype, InvalidOid, (Form_pg_class) GETSTRUCT(tuple), updated); + + CatalogTupleUpdate(relationRelation, &tuple->t_self, tuple, updated, NULL); InvokeObjectPostAlterHook(RelationRelationId, relid, 0); + bms_free(updated); heap_freetuple(tuple); table_close(relationRelation, RowExclusiveLock); } @@ -18412,8 +18509,11 @@ relation_mark_replica_identity(Relation rel, char ri_type, Oid indexOid, pg_class_form = (Form_pg_class) GETSTRUCT(pg_class_tuple); if (pg_class_form->relreplident != ri_type) { - pg_class_form->relreplident = ri_type; - CatalogTupleUpdate(pg_class, &pg_class_tuple->t_self, pg_class_tuple); + Bitmapset *updated = NULL; + + HeapTupleUpdateField(pg_class, relreplident, ri_type, pg_class_form, updated); + CatalogTupleUpdate(pg_class, &pg_class_tuple->t_self, pg_class_tuple, updated, NULL); + bms_free(updated); } table_close(pg_class, RowExclusiveLock); heap_freetuple(pg_class_tuple); @@ -18426,6 +18526,7 @@ relation_mark_replica_identity(Relation rel, char ri_type, Oid indexOid, { Oid thisIndexOid = lfirst_oid(index); bool dirty = false; + Bitmapset *updated = NULL; pg_index_tuple = SearchSysCacheCopy1(INDEXRELID, ObjectIdGetDatum(thisIndexOid)); @@ -18439,7 +18540,7 @@ relation_mark_replica_identity(Relation rel, char ri_type, Oid indexOid, if (!pg_index_form->indisreplident) { dirty = true; - pg_index_form->indisreplident = true; + HeapTupleUpdateField(pg_index, indisreplident, true, pg_index_form, updated); } } else @@ -18448,13 +18549,13 @@ relation_mark_replica_identity(Relation rel, char ri_type, Oid indexOid, if (pg_index_form->indisreplident) { dirty = true; - pg_index_form->indisreplident = false; + HeapTupleUpdateField(pg_index, indisreplident, false, pg_index_form, updated); } } if (dirty) { - CatalogTupleUpdate(pg_index, &pg_index_tuple->t_self, pg_index_tuple); + CatalogTupleUpdate(pg_index, &pg_index_tuple->t_self, pg_index_tuple, updated, NULL); InvokeObjectPostAlterHookArg(IndexRelationId, thisIndexOid, 0, InvalidOid, is_internal); @@ -18467,6 +18568,7 @@ relation_mark_replica_identity(Relation rel, char ri_type, Oid indexOid, */ CacheInvalidateRelcache(rel); } + bms_free(updated); heap_freetuple(pg_index_tuple); } @@ -18596,6 +18698,7 @@ ATExecSetRowSecurity(Relation rel, bool rls) Relation pg_class; Oid relid; HeapTuple tuple; + Bitmapset *updated = NULL; relid = RelationGetRelid(rel); @@ -18607,13 +18710,14 @@ ATExecSetRowSecurity(Relation rel, bool rls) if (!HeapTupleIsValid(tuple)) elog(ERROR, "cache lookup failed for relation %u", relid); - ((Form_pg_class) GETSTRUCT(tuple))->relrowsecurity = rls; - CatalogTupleUpdate(pg_class, &tuple->t_self, tuple); + HeapTupleUpdateField(pg_class, relrowsecurity, rls, (Form_pg_class) GETSTRUCT(tuple), updated); + CatalogTupleUpdate(pg_class, &tuple->t_self, tuple, updated, NULL); InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), 0); table_close(pg_class, RowExclusiveLock); + bms_free(updated); heap_freetuple(tuple); } @@ -18626,6 +18730,7 @@ ATExecForceNoForceRowSecurity(Relation rel, bool force_rls) Relation pg_class; Oid relid; HeapTuple tuple; + Bitmapset *updated = NULL; relid = RelationGetRelid(rel); @@ -18636,13 +18741,14 @@ ATExecForceNoForceRowSecurity(Relation rel, bool force_rls) if (!HeapTupleIsValid(tuple)) elog(ERROR, "cache lookup failed for relation %u", relid); - ((Form_pg_class) GETSTRUCT(tuple))->relforcerowsecurity = force_rls; - CatalogTupleUpdate(pg_class, &tuple->t_self, tuple); + HeapTupleUpdateField(pg_class, relforcerowsecurity, force_rls, (Form_pg_class) GETSTRUCT(tuple), updated); + CatalogTupleUpdate(pg_class, &tuple->t_self, tuple, updated, NULL); InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), 0); table_close(pg_class, RowExclusiveLock); + bms_free(updated); heap_freetuple(tuple); } @@ -18657,9 +18763,9 @@ ATExecGenericOptions(Relation rel, List *options) ForeignDataWrapper *fdw; HeapTuple tuple; bool isnull; - Datum repl_val[Natts_pg_foreign_table]; - bool repl_null[Natts_pg_foreign_table]; - bool repl_repl[Natts_pg_foreign_table]; + Datum values[Natts_pg_foreign_table] = {0}; + bool nulls[Natts_pg_foreign_table] = {false}; + Bitmapset *updated = NULL; Datum datum; Form_pg_foreign_table tableform; @@ -18679,10 +18785,6 @@ ATExecGenericOptions(Relation rel, List *options) server = GetForeignServer(tableform->ftserver); fdw = GetForeignDataWrapper(server->fdwid); - memset(repl_val, 0, sizeof(repl_val)); - memset(repl_null, false, sizeof(repl_null)); - memset(repl_repl, false, sizeof(repl_repl)); - /* Extract the current options */ datum = SysCacheGetAttr(FOREIGNTABLEREL, tuple, @@ -18698,18 +18800,16 @@ ATExecGenericOptions(Relation rel, List *options) fdw->fdwvalidator); if (DatumGetPointer(datum) != NULL) - repl_val[Anum_pg_foreign_table_ftoptions - 1] = datum; + HeapTupleUpdateValue(pg_foreign_table, ftoptions, datum, values, nulls, updated); else - repl_null[Anum_pg_foreign_table_ftoptions - 1] = true; - - repl_repl[Anum_pg_foreign_table_ftoptions - 1] = true; + HeapTupleUpdateValueNull(pg_foreign_table, ftoptions, values, nulls, updated); /* Everything looks good - update the tuple */ - tuple = heap_modify_tuple(tuple, RelationGetDescr(ftrel), - repl_val, repl_null, repl_repl); + tuple = heap_update_tuple(tuple, RelationGetDescr(ftrel), + values, nulls, updated); - CatalogTupleUpdate(ftrel, &tuple->t_self, tuple); + CatalogTupleUpdate(ftrel, &tuple->t_self, tuple, updated, NULL); /* * Invalidate relcache so that all sessions will refresh any cached plans @@ -18722,6 +18822,7 @@ ATExecGenericOptions(Relation rel, List *options) table_close(ftrel, RowExclusiveLock); + bms_free(updated); heap_freetuple(tuple); } @@ -18743,6 +18844,7 @@ ATExecSetCompression(Relation rel, char *compression; char cmethod; ObjectAddress address; + Bitmapset *updated = NULL; compression = strVal(newValue); @@ -18771,8 +18873,8 @@ ATExecSetCompression(Relation rel, cmethod = GetAttributeCompression(atttableform->atttypid, compression); /* update pg_attribute entry */ - atttableform->attcompression = cmethod; - CatalogTupleUpdate(attrel, &tuple->t_self, tuple); + HeapTupleUpdateField(pg_attribute, attcompression, cmethod, atttableform, updated); + CatalogTupleUpdate(attrel, &tuple->t_self, tuple, updated, NULL); InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), @@ -18787,6 +18889,7 @@ ATExecSetCompression(Relation rel, true, cmethod, lockmode); + bms_free(updated); heap_freetuple(tuple); table_close(attrel, RowExclusiveLock); @@ -19050,6 +19153,7 @@ AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Form_pg_class classForm; ObjectAddress thisobj; bool already_done = false; + Bitmapset *updated = NULL; /* no rel lock for relkind=c so use LOCKTAG_TUPLE */ classTup = SearchSysCacheLockedCopy1(RELOID, ObjectIdGetDatum(relOid)); @@ -19083,9 +19187,10 @@ AlterRelationNamespaceInternal(Relation classRel, Oid relOid, get_namespace_name(newNspOid)))); /* classTup is a copy, so OK to scribble on */ - classForm->relnamespace = newNspOid; + HeapTupleUpdateField(pg_class, relnamespace, newNspOid, classForm, updated); - CatalogTupleUpdate(classRel, &otid, classTup); + CatalogTupleUpdate(classRel, &otid, classTup, updated, NULL); + bms_free(updated); UnlockTuple(classRel, &otid, InplaceUpdateTupleLock); @@ -21077,9 +21182,9 @@ DetachPartitionFinalize(Relation rel, Relation partRel, bool concurrent, List *fks; ListCell *cell; List *indexes; - Datum new_val[Natts_pg_class]; - bool new_null[Natts_pg_class], - new_repl[Natts_pg_class]; + Datum new_val[Natts_pg_class] = {0}; + bool new_null[Natts_pg_class] = {false}; + Bitmapset *updated = NULL; HeapTuple tuple, newtuple; Relation trigrel = NULL; @@ -21329,17 +21434,13 @@ DetachPartitionFinalize(Relation rel, Relation partRel, bool concurrent, Assert(((Form_pg_class) GETSTRUCT(tuple))->relispartition); /* Clear relpartbound and reset relispartition */ - memset(new_val, 0, sizeof(new_val)); - memset(new_null, false, sizeof(new_null)); - memset(new_repl, false, sizeof(new_repl)); - new_val[Anum_pg_class_relpartbound - 1] = (Datum) 0; - new_null[Anum_pg_class_relpartbound - 1] = true; - new_repl[Anum_pg_class_relpartbound - 1] = true; - newtuple = heap_modify_tuple(tuple, RelationGetDescr(classRel), - new_val, new_null, new_repl); - - ((Form_pg_class) GETSTRUCT(newtuple))->relispartition = false; - CatalogTupleUpdate(classRel, &newtuple->t_self, newtuple); + HeapTupleUpdateValueNull(pg_class, relpartbound, new_val, new_null, updated); + newtuple = heap_update_tuple(tuple, RelationGetDescr(classRel), + new_val, new_null, updated); + + HeapTupleUpdateField(pg_class, relispartition, false, (Form_pg_class) GETSTRUCT(newtuple), updated); + CatalogTupleUpdate(classRel, &newtuple->t_self, newtuple, updated, NULL); + bms_free(updated); heap_freetuple(newtuple); table_close(classRel, RowExclusiveLock); @@ -21759,6 +21860,7 @@ validatePartitionedIndex(Relation partedIdx, Relation partedTbl) int tuples = 0; HeapTuple inhTup; bool updated = false; + Bitmapset *updated_cols = NULL; Assert(partedIdx->rd_rel->relkind == RELKIND_PARTITIONED_INDEX); @@ -21811,10 +21913,11 @@ validatePartitionedIndex(Relation partedIdx, Relation partedTbl) RelationGetRelid(partedIdx)); indexForm = (Form_pg_index) GETSTRUCT(indTup); - indexForm->indisvalid = true; + HeapTupleUpdateField(pg_index, indisvalid, true, indexForm, updated_cols); updated = true; - CatalogTupleUpdate(idxRel, &indTup->t_self, indTup); + CatalogTupleUpdate(idxRel, &indTup->t_self, indTup, updated_cols, NULL); + bms_free(updated_cols); table_close(idxRel, RowExclusiveLock); heap_freetuple(indTup); diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c index df31eace47ac9..5b89be5983c40 100644 --- a/src/backend/commands/tablespace.c +++ b/src/backend/commands/tablespace.c @@ -208,8 +208,8 @@ Oid CreateTableSpace(CreateTableSpaceStmt *stmt) { Relation rel; - Datum values[Natts_pg_tablespace]; - bool nulls[Natts_pg_tablespace] = {0}; + Datum values[Natts_pg_tablespace] = {0}; + bool nulls[Natts_pg_tablespace] = {false}; HeapTuple tuple; Oid tablespaceoid; char *location; @@ -325,12 +325,10 @@ CreateTableSpace(CreateTableSpaceStmt *stmt) else tablespaceoid = GetNewOidWithIndex(rel, TablespaceOidIndexId, Anum_pg_tablespace_oid); - values[Anum_pg_tablespace_oid - 1] = ObjectIdGetDatum(tablespaceoid); - values[Anum_pg_tablespace_spcname - 1] = - DirectFunctionCall1(namein, CStringGetDatum(stmt->tablespacename)); - values[Anum_pg_tablespace_spcowner - 1] = - ObjectIdGetDatum(ownerId); - nulls[Anum_pg_tablespace_spcacl - 1] = true; + HeapTupleSetValue(pg_tablespace, oid, ObjectIdGetDatum(tablespaceoid), values); + HeapTupleSetValue(pg_tablespace, spcname, DirectFunctionCall1(namein, CStringGetDatum(stmt->tablespacename)), values); + HeapTupleSetValue(pg_tablespace, spcowner, ObjectIdGetDatum(ownerId), values); + HeapTupleSetValueNull(pg_tablespace, spcacl, values, nulls); /* Generate new proposed spcoptions (text array) */ newOptions = transformRelOptions((Datum) 0, @@ -338,13 +336,13 @@ CreateTableSpace(CreateTableSpaceStmt *stmt) NULL, NULL, false, false); (void) tablespace_reloptions(newOptions, true); if (newOptions != (Datum) 0) - values[Anum_pg_tablespace_spcoptions - 1] = newOptions; + HeapTupleSetValue(pg_tablespace, spcoptions, newOptions, values); else - nulls[Anum_pg_tablespace_spcoptions - 1] = true; + HeapTupleSetValueNull(pg_tablespace, spcoptions, values, nulls); tuple = heap_form_tuple(rel->rd_att, values, nulls); - CatalogTupleInsert(rel, tuple); + CatalogTupleInsert(rel, tuple, NULL); heap_freetuple(tuple); @@ -937,6 +935,7 @@ RenameTableSpace(const char *oldname, const char *newname) HeapTuple newtuple; Form_pg_tablespace newform; ObjectAddress address; + Bitmapset *updated = NULL; /* Search pg_tablespace */ rel = table_open(TableSpaceRelationId, RowExclusiveLock); @@ -996,14 +995,15 @@ RenameTableSpace(const char *oldname, const char *newname) /* OK, update the entry */ namestrcpy(&(newform->spcname), newname); - - CatalogTupleUpdate(rel, &newtuple->t_self, newtuple); + HeapTupleMarkColumnUpdated(pg_tablespace, spcname, updated); + CatalogTupleUpdate(rel, &newtuple->t_self, newtuple, updated, NULL); InvokeObjectPostAlterHook(TableSpaceRelationId, tspId, 0); ObjectAddressSet(address, TableSpaceRelationId, tspId); table_close(rel, NoLock); + bms_free(updated); return address; } @@ -1021,10 +1021,10 @@ AlterTableSpaceOptions(AlterTableSpaceOptionsStmt *stmt) Oid tablespaceoid; Datum datum; Datum newOptions; - Datum repl_val[Natts_pg_tablespace]; + Datum values[Natts_pg_tablespace] = {0}; + bool nulls[Natts_pg_tablespace] = {false}; + Bitmapset *updated = NULL; bool isnull; - bool repl_null[Natts_pg_tablespace]; - bool repl_repl[Natts_pg_tablespace]; HeapTuple newtuple; /* Search pg_tablespace */ @@ -1058,26 +1058,25 @@ AlterTableSpaceOptions(AlterTableSpaceOptionsStmt *stmt) (void) tablespace_reloptions(newOptions, true); /* Build new tuple. */ - memset(repl_null, false, sizeof(repl_null)); - memset(repl_repl, false, sizeof(repl_repl)); if (newOptions != (Datum) 0) - repl_val[Anum_pg_tablespace_spcoptions - 1] = newOptions; + HeapTupleUpdateValue(pg_tablespace, spcoptions, newOptions, values, nulls, updated); else - repl_null[Anum_pg_tablespace_spcoptions - 1] = true; - repl_repl[Anum_pg_tablespace_spcoptions - 1] = true; - newtuple = heap_modify_tuple(tup, RelationGetDescr(rel), repl_val, - repl_null, repl_repl); + HeapTupleUpdateValueNull(pg_tablespace, spcoptions, values, nulls, updated); + newtuple = heap_update_tuple(tup, RelationGetDescr(rel), values, + nulls, updated); /* Update system catalog. */ - CatalogTupleUpdate(rel, &newtuple->t_self, newtuple); + CatalogTupleUpdate(rel, &newtuple->t_self, newtuple, updated, NULL); InvokeObjectPostAlterHook(TableSpaceRelationId, tablespaceoid, 0); heap_freetuple(newtuple); + bms_free(updated); /* Conclude heap scan. */ table_endscan(scandesc); table_close(rel, NoLock); + bms_free(updated); return tablespaceoid; } diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index 579ac8d76ae73..1cd1f3fc478bc 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -186,8 +186,9 @@ CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString, int2vector *tgattr; List *whenRtable; char *qual; - Datum values[Natts_pg_trigger]; - bool nulls[Natts_pg_trigger]; + Datum values[Natts_pg_trigger] = {0}; + bool nulls[Natts_pg_trigger] = {false}; + Bitmapset *updated = NULL; Relation rel; AclResult aclresult; Relation tgrel; @@ -751,8 +752,7 @@ CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString, if (!trigger_exists) { /* Generate the OID for the new trigger. */ - trigoid = GetNewOidWithIndex(tgrel, TriggerOidIndexId, - Anum_pg_trigger_oid); + trigoid = GetNewOidWithIndex(tgrel, TriggerOidIndexId, Anum_pg_trigger_oid); } else { @@ -862,22 +862,19 @@ CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString, /* * Build the new pg_trigger tuple. */ - memset(nulls, false, sizeof(nulls)); - - values[Anum_pg_trigger_oid - 1] = ObjectIdGetDatum(trigoid); - values[Anum_pg_trigger_tgrelid - 1] = ObjectIdGetDatum(RelationGetRelid(rel)); - values[Anum_pg_trigger_tgparentid - 1] = ObjectIdGetDatum(parentTriggerOid); - values[Anum_pg_trigger_tgname - 1] = DirectFunctionCall1(namein, - CStringGetDatum(trigname)); - values[Anum_pg_trigger_tgfoid - 1] = ObjectIdGetDatum(funcoid); - values[Anum_pg_trigger_tgtype - 1] = Int16GetDatum(tgtype); - values[Anum_pg_trigger_tgenabled - 1] = CharGetDatum(trigger_fires_when); - values[Anum_pg_trigger_tgisinternal - 1] = BoolGetDatum(isInternal); - values[Anum_pg_trigger_tgconstrrelid - 1] = ObjectIdGetDatum(constrrelid); - values[Anum_pg_trigger_tgconstrindid - 1] = ObjectIdGetDatum(indexOid); - values[Anum_pg_trigger_tgconstraint - 1] = ObjectIdGetDatum(constraintOid); - values[Anum_pg_trigger_tgdeferrable - 1] = BoolGetDatum(stmt->deferrable); - values[Anum_pg_trigger_tginitdeferred - 1] = BoolGetDatum(stmt->initdeferred); + HeapTupleUpdateValue(pg_trigger, oid, ObjectIdGetDatum(trigoid), values, nulls, updated); + HeapTupleUpdateValue(pg_trigger, tgrelid, ObjectIdGetDatum(RelationGetRelid(rel)), values, nulls, updated); + HeapTupleUpdateValue(pg_trigger, tgparentid, ObjectIdGetDatum(parentTriggerOid), values, nulls, updated); + HeapTupleUpdateValue(pg_trigger, tgname, DirectFunctionCall1(namein, CStringGetDatum(trigname)), values, nulls, updated); + HeapTupleUpdateValue(pg_trigger, tgfoid, ObjectIdGetDatum(funcoid), values, nulls, updated); + HeapTupleUpdateValue(pg_trigger, tgtype, Int16GetDatum(tgtype), values, nulls, updated); + HeapTupleUpdateValue(pg_trigger, tgenabled, CharGetDatum(trigger_fires_when), values, nulls, updated); + HeapTupleUpdateValue(pg_trigger, tgisinternal, BoolGetDatum(isInternal), values, nulls, updated); + HeapTupleUpdateValue(pg_trigger, tgconstrrelid, ObjectIdGetDatum(constrrelid), values, nulls, updated); + HeapTupleUpdateValue(pg_trigger, tgconstrindid, ObjectIdGetDatum(indexOid), values, nulls, updated); + HeapTupleUpdateValue(pg_trigger, tgconstraint, ObjectIdGetDatum(constraintOid), values, nulls, updated); + HeapTupleUpdateValue(pg_trigger, tgdeferrable, BoolGetDatum(stmt->deferrable), values, nulls, updated); + HeapTupleUpdateValue(pg_trigger, tginitdeferred, BoolGetDatum(stmt->initdeferred), values, nulls, updated); if (stmt->args) { @@ -912,15 +909,13 @@ CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString, } strcpy(d, "\\000"); } - values[Anum_pg_trigger_tgnargs - 1] = Int16GetDatum(nargs); - values[Anum_pg_trigger_tgargs - 1] = DirectFunctionCall1(byteain, - CStringGetDatum(args)); + HeapTupleUpdateValue(pg_trigger, tgnargs, Int16GetDatum(nargs), values, nulls, updated); + HeapTupleUpdateValue(pg_trigger, tgargs, DirectFunctionCall1(byteain, CStringGetDatum(args)), values, nulls, updated); } else { - values[Anum_pg_trigger_tgnargs - 1] = Int16GetDatum(0); - values[Anum_pg_trigger_tgargs - 1] = DirectFunctionCall1(byteain, - CStringGetDatum("")); + HeapTupleUpdateValue(pg_trigger, tgnargs, Int16GetDatum(0), values, nulls, updated); + HeapTupleUpdateValue(pg_trigger, tgargs, DirectFunctionCall1(byteain, CStringGetDatum("")), values, nulls, updated); } /* build column number array if it's a column-specific trigger */ @@ -961,24 +956,23 @@ CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString, } } tgattr = buildint2vector(columns, ncolumns); - values[Anum_pg_trigger_tgattr - 1] = PointerGetDatum(tgattr); + HeapTupleUpdateValue(pg_trigger, tgattr, PointerGetDatum(tgattr), values, nulls, updated); /* set tgqual if trigger has WHEN clause */ if (qual) - values[Anum_pg_trigger_tgqual - 1] = CStringGetTextDatum(qual); + HeapTupleUpdateValue(pg_trigger, tgqual, CStringGetTextDatum(qual), values, nulls, updated); else - nulls[Anum_pg_trigger_tgqual - 1] = true; + HeapTupleUpdateValueNull(pg_trigger, tgqual, values, nulls, updated); if (oldtablename) - values[Anum_pg_trigger_tgoldtable - 1] = DirectFunctionCall1(namein, - CStringGetDatum(oldtablename)); + HeapTupleUpdateValue(pg_trigger, tgoldtable, DirectFunctionCall1(namein, CStringGetDatum(oldtablename)), values, nulls, updated); else - nulls[Anum_pg_trigger_tgoldtable - 1] = true; + HeapTupleUpdateValueNull(pg_trigger, tgoldtable, values, nulls, updated); + if (newtablename) - values[Anum_pg_trigger_tgnewtable - 1] = DirectFunctionCall1(namein, - CStringGetDatum(newtablename)); + HeapTupleUpdateValue(pg_trigger, tgnewtable, DirectFunctionCall1(namein, CStringGetDatum(newtablename)), values, nulls, updated); else - nulls[Anum_pg_trigger_tgnewtable - 1] = true; + HeapTupleUpdateValueNull(pg_trigger, tgnewtable, values, nulls, updated); /* * Insert or replace tuple in pg_trigger. @@ -986,27 +980,29 @@ CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString, if (!trigger_exists) { tuple = heap_form_tuple(tgrel->rd_att, values, nulls); - CatalogTupleInsert(tgrel, tuple); + CatalogTupleInsert(tgrel, tuple, NULL); } else { HeapTuple newtup; newtup = heap_form_tuple(tgrel->rd_att, values, nulls); - CatalogTupleUpdate(tgrel, &tuple->t_self, newtup); + CatalogTupleUpdate(tgrel, &tuple->t_self, newtup, updated, NULL); heap_freetuple(newtup); } heap_freetuple(tuple); /* free either original or new tuple */ table_close(tgrel, RowExclusiveLock); + bms_free(updated); + updated = NULL; - pfree(DatumGetPointer(values[Anum_pg_trigger_tgname - 1])); - pfree(DatumGetPointer(values[Anum_pg_trigger_tgargs - 1])); - pfree(DatumGetPointer(values[Anum_pg_trigger_tgattr - 1])); + pfree(DatumGetPointer(HeapTupleValue(pg_trigger, tgname, values))); + pfree(DatumGetPointer(HeapTupleValue(pg_trigger, tgargs, values))); + pfree(DatumGetPointer(HeapTupleValue(pg_trigger, tgattr, values))); if (oldtablename) - pfree(DatumGetPointer(values[Anum_pg_trigger_tgoldtable - 1])); + pfree(DatumGetPointer(HeapTupleValue(pg_trigger, tgoldtable, values))); if (newtablename) - pfree(DatumGetPointer(values[Anum_pg_trigger_tgnewtable - 1])); + pfree(DatumGetPointer(HeapTupleValue(pg_trigger, tgnewtable, values))); /* * Update relation's pg_class entry; if necessary; and if not, send an SI @@ -1020,9 +1016,9 @@ CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString, RelationGetRelid(rel)); if (!((Form_pg_class) GETSTRUCT(tuple))->relhastriggers) { - ((Form_pg_class) GETSTRUCT(tuple))->relhastriggers = true; - - CatalogTupleUpdate(pgrel, &tuple->t_self, tuple); + HeapTupleUpdateField(pg_class, relhastriggers, true, (Form_pg_class) GETSTRUCT(tuple), updated); + CatalogTupleUpdate(pgrel, &tuple->t_self, tuple, updated, NULL); + bms_free(updated); CommandCounterIncrement(); } @@ -1229,6 +1225,7 @@ TriggerSetParentTrigger(Relation trigRel, newtup; ObjectAddress depender; ObjectAddress referenced; + Bitmapset *updated = NULL; /* * Find the trigger to delete. @@ -1253,9 +1250,9 @@ TriggerSetParentTrigger(Relation trigRel, elog(ERROR, "trigger %u already has a parent trigger", childTrigId); - trigForm->tgparentid = parentTrigId; + HeapTupleUpdateField(pg_trigger, tgparentid, parentTrigId, trigForm, updated); - CatalogTupleUpdate(trigRel, &tuple->t_self, newtup); + CatalogTupleUpdate(trigRel, &tuple->t_self, newtup, updated, NULL); ObjectAddressSet(depender, TriggerRelationId, childTrigId); @@ -1267,9 +1264,9 @@ TriggerSetParentTrigger(Relation trigRel, } else { - trigForm->tgparentid = InvalidOid; + HeapTupleUpdateField(pg_trigger, tgparentid, InvalidOid, trigForm, updated); - CatalogTupleUpdate(trigRel, &tuple->t_self, newtup); + CatalogTupleUpdate(trigRel, &tuple->t_self, newtup, updated, NULL); deleteDependencyRecordsForClass(TriggerRelationId, childTrigId, TriggerRelationId, @@ -1281,6 +1278,7 @@ TriggerSetParentTrigger(Relation trigRel, heap_freetuple(newtup); systable_endscan(tgscan); + bms_free(updated); } @@ -1586,6 +1584,7 @@ renametrig_internal(Relation tgrel, Relation targetrel, HeapTuple trigtup, Form_pg_trigger tgform; ScanKeyData key[2]; SysScanDesc tgscan; + Bitmapset *updated = NULL; /* If the trigger already has the new name, nothing to do. */ tgform = (Form_pg_trigger) GETSTRUCT(trigtup); @@ -1633,7 +1632,7 @@ renametrig_internal(Relation tgrel, Relation targetrel, HeapTuple trigtup, namestrcpy(&tgform->tgname, newname); - CatalogTupleUpdate(tgrel, &tuple->t_self, tuple); + CatalogTupleUpdate(tgrel, &tuple->t_self, tuple, updated, NULL); InvokeObjectPostAlterHook(TriggerRelationId, tgform->oid, 0); @@ -1643,6 +1642,7 @@ renametrig_internal(Relation tgrel, Relation targetrel, HeapTuple trigtup, * (Ideally this should happen automatically...) */ CacheInvalidateRelcache(targetrel); + bms_free(updated); } /* @@ -1784,11 +1784,12 @@ EnableDisableTrigger(Relation rel, const char *tgname, Oid tgparent, /* need to change this one ... make a copy to scribble on */ HeapTuple newtup = heap_copytuple(tuple); Form_pg_trigger newtrig = (Form_pg_trigger) GETSTRUCT(newtup); + Bitmapset *updated = NULL; - newtrig->tgenabled = fires_when; - - CatalogTupleUpdate(tgrel, &newtup->t_self, newtup); + HeapTupleUpdateField(pg_trigger, tgenabled, fires_when, newtrig, updated); + CatalogTupleUpdate(tgrel, &newtup->t_self, newtup, updated, NULL); + bms_free(updated); heap_freetuple(newtup); changed = true; diff --git a/src/backend/commands/tsearchcmds.c b/src/backend/commands/tsearchcmds.c index dc7df736fb826..eebf05c2d7961 100644 --- a/src/backend/commands/tsearchcmds.c +++ b/src/backend/commands/tsearchcmds.c @@ -187,8 +187,8 @@ DefineTSParser(List *names, List *parameters) ListCell *pl; Relation prsRel; HeapTuple tup; - Datum values[Natts_pg_ts_parser]; - bool nulls[Natts_pg_ts_parser]; + Datum values[Natts_pg_ts_parser] = {0}; + bool nulls[Natts_pg_ts_parser] = {false}; NameData pname; Oid prsOid; Oid namespaceoid; @@ -210,10 +210,10 @@ DefineTSParser(List *names, List *parameters) prsOid = GetNewOidWithIndex(prsRel, TSParserOidIndexId, Anum_pg_ts_parser_oid); - values[Anum_pg_ts_parser_oid - 1] = ObjectIdGetDatum(prsOid); + HeapTupleSetValue(pg_ts_parser, oid, ObjectIdGetDatum(prsOid), values); namestrcpy(&pname, prsname); - values[Anum_pg_ts_parser_prsname - 1] = NameGetDatum(&pname); - values[Anum_pg_ts_parser_prsnamespace - 1] = ObjectIdGetDatum(namespaceoid); + HeapTupleSetValue(pg_ts_parser, prsname, NameGetDatum(&pname), values); + HeapTupleSetValue(pg_ts_parser, prsnamespace, ObjectIdGetDatum(namespaceoid), values); /* * loop over the definition list and extract the information we need. @@ -224,28 +224,23 @@ DefineTSParser(List *names, List *parameters) if (strcmp(defel->defname, "start") == 0) { - values[Anum_pg_ts_parser_prsstart - 1] = - get_ts_parser_func(defel, Anum_pg_ts_parser_prsstart); + HeapTupleSetValue(pg_ts_parser, prsstart, get_ts_parser_func(defel, Anum_pg_ts_parser_prsstart), values); } else if (strcmp(defel->defname, "gettoken") == 0) { - values[Anum_pg_ts_parser_prstoken - 1] = - get_ts_parser_func(defel, Anum_pg_ts_parser_prstoken); + HeapTupleSetValue(pg_ts_parser, prstoken, get_ts_parser_func(defel, Anum_pg_ts_parser_prstoken), values); } else if (strcmp(defel->defname, "end") == 0) { - values[Anum_pg_ts_parser_prsend - 1] = - get_ts_parser_func(defel, Anum_pg_ts_parser_prsend); + HeapTupleSetValue(pg_ts_parser, prsend, get_ts_parser_func(defel, Anum_pg_ts_parser_prsend), values); } else if (strcmp(defel->defname, "headline") == 0) { - values[Anum_pg_ts_parser_prsheadline - 1] = - get_ts_parser_func(defel, Anum_pg_ts_parser_prsheadline); + HeapTupleSetValue(pg_ts_parser, prsheadline, get_ts_parser_func(defel, Anum_pg_ts_parser_prsheadline), values); } else if (strcmp(defel->defname, "lextypes") == 0) { - values[Anum_pg_ts_parser_prslextype - 1] = - get_ts_parser_func(defel, Anum_pg_ts_parser_prslextype); + HeapTupleSetValue(pg_ts_parser, prslextype, get_ts_parser_func(defel, Anum_pg_ts_parser_prslextype), values); } else ereport(ERROR, @@ -257,22 +252,22 @@ DefineTSParser(List *names, List *parameters) /* * Validation */ - if (!OidIsValid(DatumGetObjectId(values[Anum_pg_ts_parser_prsstart - 1]))) + if (!OidIsValid(DatumGetObjectId(HeapTupleValue(pg_ts_parser, prsstart, values)))) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("text search parser start method is required"))); - if (!OidIsValid(DatumGetObjectId(values[Anum_pg_ts_parser_prstoken - 1]))) + if (!OidIsValid(DatumGetObjectId(HeapTupleValue(pg_ts_parser, prstoken, values)))) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("text search parser gettoken method is required"))); - if (!OidIsValid(DatumGetObjectId(values[Anum_pg_ts_parser_prsend - 1]))) + if (!OidIsValid(DatumGetObjectId(HeapTupleValue(pg_ts_parser, prsend, values)))) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("text search parser end method is required"))); - if (!OidIsValid(DatumGetObjectId(values[Anum_pg_ts_parser_prslextype - 1]))) + if (!OidIsValid(DatumGetObjectId(HeapTupleValue(pg_ts_parser, prslextype, values)))) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("text search parser lextypes method is required"))); @@ -282,7 +277,7 @@ DefineTSParser(List *names, List *parameters) */ tup = heap_form_tuple(prsRel->rd_att, values, nulls); - CatalogTupleInsert(prsRel, tup); + CatalogTupleInsert(prsRel, tup, NULL); address = makeParserDependencies(tup); @@ -399,8 +394,8 @@ DefineTSDictionary(List *names, List *parameters) ListCell *pl; Relation dictRel; HeapTuple tup; - Datum values[Natts_pg_ts_dict]; - bool nulls[Natts_pg_ts_dict]; + Datum values[Natts_pg_ts_dict] = {0}; + bool nulls[Natts_pg_ts_dict] = {false}; NameData dname; Oid templId = InvalidOid; List *dictoptions = NIL; @@ -458,21 +453,20 @@ DefineTSDictionary(List *names, List *parameters) dictOid = GetNewOidWithIndex(dictRel, TSDictionaryOidIndexId, Anum_pg_ts_dict_oid); - values[Anum_pg_ts_dict_oid - 1] = ObjectIdGetDatum(dictOid); + HeapTupleSetValue(pg_ts_dict, oid, ObjectIdGetDatum(dictOid), values); namestrcpy(&dname, dictname); - values[Anum_pg_ts_dict_dictname - 1] = NameGetDatum(&dname); - values[Anum_pg_ts_dict_dictnamespace - 1] = ObjectIdGetDatum(namespaceoid); - values[Anum_pg_ts_dict_dictowner - 1] = ObjectIdGetDatum(GetUserId()); - values[Anum_pg_ts_dict_dicttemplate - 1] = ObjectIdGetDatum(templId); + HeapTupleSetValue(pg_ts_dict, dictname, NameGetDatum(&dname), values); + HeapTupleSetValue(pg_ts_dict, dictnamespace, ObjectIdGetDatum(namespaceoid), values); + HeapTupleSetValue(pg_ts_dict, dictowner, ObjectIdGetDatum(GetUserId()), values); + HeapTupleSetValue(pg_ts_dict, dicttemplate, ObjectIdGetDatum(templId), values); if (dictoptions) - values[Anum_pg_ts_dict_dictinitoption - 1] = - PointerGetDatum(serialize_deflist(dictoptions)); + HeapTupleSetValue(pg_ts_dict, dictinitoption, PointerGetDatum(serialize_deflist(dictoptions)), values); else - nulls[Anum_pg_ts_dict_dictinitoption - 1] = true; + HeapTupleSetValueNull(pg_ts_dict, dictinitoption, values, nulls); tup = heap_form_tuple(dictRel->rd_att, values, nulls); - CatalogTupleInsert(dictRel, tup); + CatalogTupleInsert(dictRel, tup, NULL); address = makeDictionaryDependencies(tup); @@ -500,9 +494,9 @@ AlterTSDictionary(AlterTSDictionaryStmt *stmt) List *dictoptions; Datum opt; bool isnull; - Datum repl_val[Natts_pg_ts_dict]; - bool repl_null[Natts_pg_ts_dict]; - bool repl_repl[Natts_pg_ts_dict]; + Datum values[Natts_pg_ts_dict] = {0}; + bool nulls[Natts_pg_ts_dict] = {false}; + Bitmapset *updated = NULL; ObjectAddress address; dictId = get_ts_dict_oid(stmt->dictname, false); @@ -564,21 +558,15 @@ AlterTSDictionary(AlterTSDictionaryStmt *stmt) /* * Looks good, update */ - memset(repl_val, 0, sizeof(repl_val)); - memset(repl_null, false, sizeof(repl_null)); - memset(repl_repl, false, sizeof(repl_repl)); - if (dictoptions) - repl_val[Anum_pg_ts_dict_dictinitoption - 1] = - PointerGetDatum(serialize_deflist(dictoptions)); + HeapTupleUpdateValue(pg_ts_dict, dictinitoption, PointerGetDatum(serialize_deflist(dictoptions)), values, nulls, updated); else - repl_null[Anum_pg_ts_dict_dictinitoption - 1] = true; - repl_repl[Anum_pg_ts_dict_dictinitoption - 1] = true; + HeapTupleUpdateValueNull(pg_ts_dict, dictinitoption, values, nulls, updated); - newtup = heap_modify_tuple(tup, RelationGetDescr(rel), - repl_val, repl_null, repl_repl); + newtup = heap_update_tuple(tup, RelationGetDescr(rel), + values, nulls, updated); - CatalogTupleUpdate(rel, &newtup->t_self, newtup); + CatalogTupleUpdate(rel, &newtup->t_self, newtup, updated, NULL); InvokeObjectPostAlterHook(TSDictionaryRelationId, dictId, 0); @@ -594,6 +582,7 @@ AlterTSDictionary(AlterTSDictionaryStmt *stmt) ReleaseSysCache(tup); table_close(rel, RowExclusiveLock); + bms_free(updated); return address; } @@ -692,8 +681,8 @@ DefineTSTemplate(List *names, List *parameters) ListCell *pl; Relation tmplRel; HeapTuple tup; - Datum values[Natts_pg_ts_template]; - bool nulls[Natts_pg_ts_template]; + Datum values[Natts_pg_ts_template] = {0}; + bool nulls[Natts_pg_ts_template] = {false}; NameData dname; int i; Oid tmplOid; @@ -719,10 +708,10 @@ DefineTSTemplate(List *names, List *parameters) tmplOid = GetNewOidWithIndex(tmplRel, TSTemplateOidIndexId, Anum_pg_ts_dict_oid); - values[Anum_pg_ts_template_oid - 1] = ObjectIdGetDatum(tmplOid); + HeapTupleSetValue(pg_ts_template, oid, ObjectIdGetDatum(tmplOid), values); namestrcpy(&dname, tmplname); - values[Anum_pg_ts_template_tmplname - 1] = NameGetDatum(&dname); - values[Anum_pg_ts_template_tmplnamespace - 1] = ObjectIdGetDatum(namespaceoid); + HeapTupleSetValue(pg_ts_template, tmplname, NameGetDatum(&dname), values); + HeapTupleSetValue(pg_ts_template, tmplnamespace, ObjectIdGetDatum(namespaceoid), values); /* * loop over the definition list and extract the information we need. @@ -733,15 +722,11 @@ DefineTSTemplate(List *names, List *parameters) if (strcmp(defel->defname, "init") == 0) { - values[Anum_pg_ts_template_tmplinit - 1] = - get_ts_template_func(defel, Anum_pg_ts_template_tmplinit); - nulls[Anum_pg_ts_template_tmplinit - 1] = false; + HeapTupleSetValue(pg_ts_template, tmplinit, get_ts_template_func(defel, Anum_pg_ts_template_tmplinit), values); } else if (strcmp(defel->defname, "lexize") == 0) { - values[Anum_pg_ts_template_tmpllexize - 1] = - get_ts_template_func(defel, Anum_pg_ts_template_tmpllexize); - nulls[Anum_pg_ts_template_tmpllexize - 1] = false; + HeapTupleSetValue(pg_ts_template, tmpllexize, get_ts_template_func(defel, Anum_pg_ts_template_tmpllexize), values); } else ereport(ERROR, @@ -753,7 +738,7 @@ DefineTSTemplate(List *names, List *parameters) /* * Validation */ - if (!OidIsValid(DatumGetObjectId(values[Anum_pg_ts_template_tmpllexize - 1]))) + if (!OidIsValid(DatumGetObjectId(HeapTupleValue(pg_ts_template, tmpllexize, values)))) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("text search template lexize method is required"))); @@ -763,7 +748,7 @@ DefineTSTemplate(List *names, List *parameters) */ tup = heap_form_tuple(tmplRel->rd_att, values, nulls); - CatalogTupleInsert(tmplRel, tup); + CatalogTupleInsert(tmplRel, tup, NULL); address = makeTSTemplateDependencies(tup); @@ -901,8 +886,8 @@ DefineTSConfiguration(List *names, List *parameters, ObjectAddress *copied) Relation cfgRel; Relation mapRel = NULL; HeapTuple tup; - Datum values[Natts_pg_ts_config]; - bool nulls[Natts_pg_ts_config]; + Datum values[Natts_pg_ts_config] = {0}; + bool nulls[Natts_pg_ts_config] = {false}; AclResult aclresult; Oid namespaceoid; char *cfgname; @@ -991,16 +976,16 @@ DefineTSConfiguration(List *names, List *parameters, ObjectAddress *copied) cfgOid = GetNewOidWithIndex(cfgRel, TSConfigOidIndexId, Anum_pg_ts_config_oid); - values[Anum_pg_ts_config_oid - 1] = ObjectIdGetDatum(cfgOid); + HeapTupleSetValue(pg_ts_config, oid, ObjectIdGetDatum(cfgOid), values); namestrcpy(&cname, cfgname); - values[Anum_pg_ts_config_cfgname - 1] = NameGetDatum(&cname); - values[Anum_pg_ts_config_cfgnamespace - 1] = ObjectIdGetDatum(namespaceoid); - values[Anum_pg_ts_config_cfgowner - 1] = ObjectIdGetDatum(GetUserId()); - values[Anum_pg_ts_config_cfgparser - 1] = ObjectIdGetDatum(prsOid); + HeapTupleSetValue(pg_ts_config, cfgname, NameGetDatum(&cname), values); + HeapTupleSetValue(pg_ts_config, cfgnamespace, ObjectIdGetDatum(namespaceoid), values); + HeapTupleSetValue(pg_ts_config, cfgowner, ObjectIdGetDatum(GetUserId()), values); + HeapTupleSetValue(pg_ts_config, cfgparser, ObjectIdGetDatum(prsOid), values); tup = heap_form_tuple(cfgRel->rd_att, values, nulls); - CatalogTupleInsert(cfgRel, tup); + CatalogTupleInsert(cfgRel, tup, NULL); if (OidIsValid(sourceOid)) { @@ -1058,10 +1043,10 @@ DefineTSConfiguration(List *names, List *parameters, ObjectAddress *copied) memset(slot[slot_stored_count]->tts_isnull, false, slot[slot_stored_count]->tts_tupleDescriptor->natts * sizeof(bool)); - slot[slot_stored_count]->tts_values[Anum_pg_ts_config_map_mapcfg - 1] = ObjectIdGetDatum(cfgOid); - slot[slot_stored_count]->tts_values[Anum_pg_ts_config_map_maptokentype - 1] = Int32GetDatum(cfgmap->maptokentype); - slot[slot_stored_count]->tts_values[Anum_pg_ts_config_map_mapseqno - 1] = Int32GetDatum(cfgmap->mapseqno); - slot[slot_stored_count]->tts_values[Anum_pg_ts_config_map_mapdict - 1] = ObjectIdGetDatum(cfgmap->mapdict); + HeapTupleSetValue(pg_ts_config_map, mapcfg, ObjectIdGetDatum(cfgOid), slot[slot_stored_count]->tts_values); + HeapTupleSetValue(pg_ts_config_map, maptokentype, Int32GetDatum(cfgmap->maptokentype), slot[slot_stored_count]->tts_values); + HeapTupleSetValue(pg_ts_config_map, mapseqno, Int32GetDatum(cfgmap->mapseqno), slot[slot_stored_count]->tts_values); + HeapTupleSetValue(pg_ts_config_map, mapdict, ObjectIdGetDatum(cfgmap->mapdict), slot[slot_stored_count]->tts_values); ExecStoreVirtualTuple(slot[slot_stored_count]); slot_stored_count++; @@ -1069,16 +1054,16 @@ DefineTSConfiguration(List *names, List *parameters, ObjectAddress *copied) /* If slots are full, insert a batch of tuples */ if (slot_stored_count == max_slots) { - CatalogTuplesMultiInsertWithInfo(mapRel, slot, slot_stored_count, - indstate); + CatalogTuplesMultiInsert(mapRel, slot, slot_stored_count, + indstate); slot_stored_count = 0; } } /* Insert any tuples left in the buffer */ if (slot_stored_count > 0) - CatalogTuplesMultiInsertWithInfo(mapRel, slot, slot_stored_count, - indstate); + CatalogTuplesMultiInsert(mapRel, slot, slot_stored_count, + indstate); for (int i = 0; i < slot_init_count; i++) ExecDropSingleTupleTableSlot(slot[i]); @@ -1402,22 +1387,18 @@ MakeConfigurationMapping(AlterTSConfigurationStmt *stmt, */ if (cfgmap->mapdict == dictOld) { - Datum repl_val[Natts_pg_ts_config_map]; - bool repl_null[Natts_pg_ts_config_map]; - bool repl_repl[Natts_pg_ts_config_map]; + Datum values[Natts_pg_ts_config_map] = {0}; + bool nulls[Natts_pg_ts_config_map] = {false}; + Bitmapset *updated = NULL; HeapTuple newtup; - memset(repl_val, 0, sizeof(repl_val)); - memset(repl_null, false, sizeof(repl_null)); - memset(repl_repl, false, sizeof(repl_repl)); - - repl_val[Anum_pg_ts_config_map_mapdict - 1] = ObjectIdGetDatum(dictNew); - repl_repl[Anum_pg_ts_config_map_mapdict - 1] = true; + HeapTupleUpdateValue(pg_ts_config_map, mapdict, ObjectIdGetDatum(dictNew), values, nulls, updated); - newtup = heap_modify_tuple(maptup, + newtup = heap_update_tuple(maptup, RelationGetDescr(relMap), - repl_val, repl_null, repl_repl); - CatalogTupleUpdateWithInfo(relMap, &newtup->t_self, newtup, indstate); + values, nulls, updated); + CatalogTupleUpdate(relMap, &newtup->t_self, newtup, updated, indstate); + bms_free(updated); } } @@ -1451,10 +1432,10 @@ MakeConfigurationMapping(AlterTSConfigurationStmt *stmt, memset(slot[slotCount]->tts_isnull, false, slot[slotCount]->tts_tupleDescriptor->natts * sizeof(bool)); - slot[slotCount]->tts_values[Anum_pg_ts_config_map_mapcfg - 1] = ObjectIdGetDatum(cfgId); - slot[slotCount]->tts_values[Anum_pg_ts_config_map_maptokentype - 1] = Int32GetDatum(ts->num); - slot[slotCount]->tts_values[Anum_pg_ts_config_map_mapseqno - 1] = Int32GetDatum(j + 1); - slot[slotCount]->tts_values[Anum_pg_ts_config_map_mapdict - 1] = ObjectIdGetDatum(dictIds[j]); + HeapTupleSetValue(pg_ts_config_map, mapcfg, ObjectIdGetDatum(cfgId), slot[slotCount]->tts_values); + HeapTupleSetValue(pg_ts_config_map, maptokentype, Int32GetDatum(ts->num), slot[slotCount]->tts_values); + HeapTupleSetValue(pg_ts_config_map, mapseqno, Int32GetDatum(j + 1), slot[slotCount]->tts_values); + HeapTupleSetValue(pg_ts_config_map, mapdict, ObjectIdGetDatum(dictIds[j]), slot[slotCount]->tts_values); ExecStoreVirtualTuple(slot[slotCount]); slotCount++; @@ -1462,8 +1443,8 @@ MakeConfigurationMapping(AlterTSConfigurationStmt *stmt, /* If slots are full, insert a batch of tuples */ if (slotCount == nslots) { - CatalogTuplesMultiInsertWithInfo(relMap, slot, slotCount, - indstate); + CatalogTuplesMultiInsert(relMap, slot, slotCount, + indstate); slotCount = 0; } } @@ -1471,8 +1452,8 @@ MakeConfigurationMapping(AlterTSConfigurationStmt *stmt, /* Insert any tuples left in the buffer */ if (slotCount > 0) - CatalogTuplesMultiInsertWithInfo(relMap, slot, slotCount, - indstate); + CatalogTuplesMultiInsert(relMap, slot, slotCount, + indstate); for (i = 0; i < nslots; i++) ExecDropSingleTupleTableSlot(slot[i]); diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index 5979580139fc6..d7fa069a17ade 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -2620,9 +2620,9 @@ AlterDomainDefault(List *names, Node *defaultRaw) Relation rel; char *defaultValue; Node *defaultExpr = NULL; /* NULL if no default specified */ - Datum new_record[Natts_pg_type] = {0}; - bool new_record_nulls[Natts_pg_type] = {0}; - bool new_record_repl[Natts_pg_type] = {0}; + Datum values[Natts_pg_type] = {0}; + bool nulls[Natts_pg_type] = {false}; + Bitmapset *updated = NULL; HeapTuple newtuple; Form_pg_type typTup; ObjectAddress address; @@ -2670,10 +2670,8 @@ AlterDomainDefault(List *names, Node *defaultRaw) { /* Default is NULL, drop it */ defaultExpr = NULL; - new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true; - new_record_repl[Anum_pg_type_typdefaultbin - 1] = true; - new_record_nulls[Anum_pg_type_typdefault - 1] = true; - new_record_repl[Anum_pg_type_typdefault - 1] = true; + HeapTupleUpdateValueNull(pg_type, typdefaultbin, values, nulls, updated); + HeapTupleUpdateValueNull(pg_type, typdefault, values, nulls, updated); } else { @@ -2688,27 +2686,21 @@ AlterDomainDefault(List *names, Node *defaultRaw) /* * Form an updated tuple with the new default and write it back. */ - new_record[Anum_pg_type_typdefaultbin - 1] = CStringGetTextDatum(nodeToString(defaultExpr)); - - new_record_repl[Anum_pg_type_typdefaultbin - 1] = true; - new_record[Anum_pg_type_typdefault - 1] = CStringGetTextDatum(defaultValue); - new_record_repl[Anum_pg_type_typdefault - 1] = true; + HeapTupleUpdateValue(pg_type, typdefaultbin, CStringGetTextDatum(nodeToString(defaultExpr)), values, nulls, updated); + HeapTupleUpdateValue(pg_type, typdefault, CStringGetTextDatum(defaultValue), values, nulls, updated); } } else { /* ALTER ... DROP DEFAULT */ - new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true; - new_record_repl[Anum_pg_type_typdefaultbin - 1] = true; - new_record_nulls[Anum_pg_type_typdefault - 1] = true; - new_record_repl[Anum_pg_type_typdefault - 1] = true; + HeapTupleUpdateValueNull(pg_type, typdefaultbin, values, nulls, updated); + HeapTupleUpdateValueNull(pg_type, typdefault, values, nulls, updated); } - newtuple = heap_modify_tuple(tup, RelationGetDescr(rel), - new_record, new_record_nulls, - new_record_repl); + newtuple = heap_update_tuple(tup, RelationGetDescr(rel), + values, nulls, updated); - CatalogTupleUpdate(rel, &tup->t_self, newtuple); + CatalogTupleUpdate(rel, &tup->t_self, newtuple, updated, NULL); /* Rebuild dependencies */ GenerateTypeDependencies(newtuple, @@ -2728,6 +2720,7 @@ AlterDomainDefault(List *names, Node *defaultRaw) /* Clean up */ table_close(rel, RowExclusiveLock); heap_freetuple(newtuple); + bms_free(updated); return address; } @@ -2748,6 +2741,7 @@ AlterDomainNotNull(List *names, bool notNull) HeapTuple tup; Form_pg_type typTup; ObjectAddress address = InvalidObjectAddress; + Bitmapset *updated = NULL; /* Make a TypeName so we can use standard type lookup machinery */ typename = makeTypeNameFromNameList(names); @@ -2803,9 +2797,9 @@ AlterDomainNotNull(List *names, bool notNull) * Okay to update pg_type row. We can scribble on typTup because it's a * copy. */ - typTup->typnotnull = notNull; + HeapTupleUpdateField(pg_type, typnotnull, notNull, typTup, updated); - CatalogTupleUpdate(typrel, &tup->t_self, tup); + CatalogTupleUpdate(typrel, &tup->t_self, tup, updated, NULL); InvokeObjectPostAlterHook(TypeRelationId, domainoid, 0); @@ -2814,6 +2808,7 @@ AlterDomainNotNull(List *names, bool notNull) /* Clean up */ heap_freetuple(tup); table_close(typrel, RowExclusiveLock); + bms_free(updated); return address; } @@ -2839,6 +2834,7 @@ AlterDomainDropConstraint(List *names, const char *constrName, HeapTuple contup; bool found = false; ObjectAddress address; + Bitmapset *updated = NULL; /* Make a TypeName so we can use standard type lookup machinery */ typename = makeTypeNameFromNameList(names); @@ -2882,8 +2878,8 @@ AlterDomainDropConstraint(List *names, const char *constrName, if (construct->contype == CONSTRAINT_NOTNULL) { - ((Form_pg_type) GETSTRUCT(tup))->typnotnull = false; - CatalogTupleUpdate(rel, &tup->t_self, tup); + HeapTupleUpdateField(pg_type, typnotnull, false, (Form_pg_type) GETSTRUCT(tup), updated); + CatalogTupleUpdate(rel, &tup->t_self, tup, updated, NULL); } conobj.classId = ConstraintRelationId; @@ -2922,6 +2918,7 @@ AlterDomainDropConstraint(List *names, const char *constrName, /* Clean up */ table_close(rel, RowExclusiveLock); + bms_free(updated); return address; } @@ -2943,6 +2940,7 @@ AlterDomainAddConstraint(List *names, Node *newConstraint, Constraint *constr; char *ccbin; ObjectAddress address = InvalidObjectAddress; + Bitmapset *updated = NULL; /* Make a TypeName so we can use standard type lookup machinery */ typename = makeTypeNameFromNameList(names); @@ -3011,14 +3009,15 @@ AlterDomainAddConstraint(List *names, Node *newConstraint, if (!constr->skip_validation) validateDomainNotNullConstraint(domainoid); - typTup->typnotnull = true; - CatalogTupleUpdate(typrel, &tup->t_self, tup); + HeapTupleUpdateField(pg_type, typnotnull, true, typTup, updated); + CatalogTupleUpdate(typrel, &tup->t_self, tup, updated, NULL); } ObjectAddressSet(address, TypeRelationId, domainoid); /* Clean up */ table_close(typrel, RowExclusiveLock); + bms_free(updated); return address; } @@ -3045,6 +3044,7 @@ AlterDomainValidateConstraint(List *names, const char *constrName) HeapTuple copyTuple; ScanKeyData skey[3]; ObjectAddress address; + Bitmapset *updated = NULL; /* Make a TypeName so we can use standard type lookup machinery */ typename = makeTypeNameFromNameList(names); @@ -3110,8 +3110,8 @@ AlterDomainValidateConstraint(List *names, const char *constrName) */ copyTuple = heap_copytuple(tuple); copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple); - copy_con->convalidated = true; - CatalogTupleUpdate(conrel, ©Tuple->t_self, copyTuple); + HeapTupleUpdateField(pg_constraint, convalidated, true, copy_con, updated); + CatalogTupleUpdate(conrel, ©Tuple->t_self, copyTuple, updated, NULL); InvokeObjectPostAlterHook(ConstraintRelationId, con->oid, 0); @@ -3125,6 +3125,7 @@ AlterDomainValidateConstraint(List *names, const char *constrName) table_close(conrel, RowExclusiveLock); ReleaseSysCache(tup); + bms_free(updated); return address; } @@ -3999,9 +4000,9 @@ AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId) Relation rel; HeapTuple tup; Form_pg_type typTup; - Datum repl_val[Natts_pg_type]; - bool repl_null[Natts_pg_type]; - bool repl_repl[Natts_pg_type]; + Datum values[Natts_pg_type] = {0}; + bool nulls[Natts_pg_type] = {false}; + Bitmapset *updated = NULL; Acl *newAcl; Datum aclDatum; bool isNull; @@ -4013,11 +4014,7 @@ AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId) elog(ERROR, "cache lookup failed for type %u", typeOid); typTup = (Form_pg_type) GETSTRUCT(tup); - memset(repl_null, false, sizeof(repl_null)); - memset(repl_repl, false, sizeof(repl_repl)); - - repl_repl[Anum_pg_type_typowner - 1] = true; - repl_val[Anum_pg_type_typowner - 1] = ObjectIdGetDatum(newOwnerId); + HeapTupleUpdateValue(pg_type, typowner, ObjectIdGetDatum(newOwnerId), values, nulls, updated); aclDatum = heap_getattr(tup, Anum_pg_type_typacl, @@ -4028,14 +4025,12 @@ AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId) { newAcl = aclnewowner(DatumGetAclP(aclDatum), typTup->typowner, newOwnerId); - repl_repl[Anum_pg_type_typacl - 1] = true; - repl_val[Anum_pg_type_typacl - 1] = PointerGetDatum(newAcl); + HeapTupleUpdateValue(pg_type, typacl, PointerGetDatum(newAcl), values, nulls, updated); } - tup = heap_modify_tuple(tup, RelationGetDescr(rel), repl_val, repl_null, - repl_repl); + tup = heap_update_tuple(tup, RelationGetDescr(rel), values, nulls, updated); - CatalogTupleUpdate(rel, &tup->t_self, tup); + CatalogTupleUpdate(rel, &tup->t_self, tup, updated, NULL); /* If it has an array type, update that too */ if (OidIsValid(typTup->typarray)) @@ -4056,6 +4051,7 @@ AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId) /* Clean up */ table_close(rel, RowExclusiveLock); + bms_free(updated); } /* @@ -4176,6 +4172,7 @@ AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, Oid arrayOid; bool isCompositeType; ObjectAddress thisobj; + Bitmapset *updated = NULL; /* * Make sure we haven't moved this object previously. @@ -4241,9 +4238,9 @@ AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, /* OK, modify the pg_type row */ /* tup is a copy, so we can scribble directly on it */ - typform->typnamespace = nspOid; + HeapTupleUpdateField(pg_type, typnamespace, nspOid, typform, updated); - CatalogTupleUpdate(rel, &tup->t_self, tup); + CatalogTupleUpdate(rel, &tup->t_self, tup, updated, NULL); } /* @@ -4307,6 +4304,7 @@ AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, true, /* errorOnTableType */ objsMoved); + bms_free(updated); return oldNspOid; } @@ -4574,9 +4572,9 @@ AlterTypeRecurse(Oid typeOid, bool isImplicitArray, HeapTuple tup, Relation catalog, AlterTypeRecurseParams *atparams) { - Datum values[Natts_pg_type]; - bool nulls[Natts_pg_type]; - bool replaces[Natts_pg_type]; + Datum values[Natts_pg_type] = {0}; + bool nulls[Natts_pg_type] = {false}; + Bitmapset *updated = NULL; HeapTuple newtup; SysScanDesc scan; ScanKeyData key[1]; @@ -4586,50 +4584,25 @@ AlterTypeRecurse(Oid typeOid, bool isImplicitArray, check_stack_depth(); /* Update the current type's tuple */ - memset(values, 0, sizeof(values)); - memset(nulls, 0, sizeof(nulls)); - memset(replaces, 0, sizeof(replaces)); - if (atparams->updateStorage) - { - replaces[Anum_pg_type_typstorage - 1] = true; - values[Anum_pg_type_typstorage - 1] = CharGetDatum(atparams->storage); - } + HeapTupleUpdateValue(pg_type, typstorage, CharGetDatum(atparams->storage), values, nulls, updated); if (atparams->updateReceive) - { - replaces[Anum_pg_type_typreceive - 1] = true; - values[Anum_pg_type_typreceive - 1] = ObjectIdGetDatum(atparams->receiveOid); - } + HeapTupleUpdateValue(pg_type, typreceive, ObjectIdGetDatum(atparams->receiveOid), values, nulls, updated); if (atparams->updateSend) - { - replaces[Anum_pg_type_typsend - 1] = true; - values[Anum_pg_type_typsend - 1] = ObjectIdGetDatum(atparams->sendOid); - } + HeapTupleUpdateValue(pg_type, typsend, ObjectIdGetDatum(atparams->sendOid), values, nulls, updated); if (atparams->updateTypmodin) - { - replaces[Anum_pg_type_typmodin - 1] = true; - values[Anum_pg_type_typmodin - 1] = ObjectIdGetDatum(atparams->typmodinOid); - } + HeapTupleUpdateValue(pg_type, typmodin, ObjectIdGetDatum(atparams->typmodinOid), values, nulls, updated); if (atparams->updateTypmodout) - { - replaces[Anum_pg_type_typmodout - 1] = true; - values[Anum_pg_type_typmodout - 1] = ObjectIdGetDatum(atparams->typmodoutOid); - } + HeapTupleUpdateValue(pg_type, typmodout, ObjectIdGetDatum(atparams->typmodoutOid), values, nulls, updated); if (atparams->updateAnalyze) - { - replaces[Anum_pg_type_typanalyze - 1] = true; - values[Anum_pg_type_typanalyze - 1] = ObjectIdGetDatum(atparams->analyzeOid); - } + HeapTupleUpdateValue(pg_type, typanalyze, ObjectIdGetDatum(atparams->analyzeOid), values, nulls, updated); if (atparams->updateSubscript) - { - replaces[Anum_pg_type_typsubscript - 1] = true; - values[Anum_pg_type_typsubscript - 1] = ObjectIdGetDatum(atparams->subscriptOid); - } + HeapTupleUpdateValue(pg_type, typsubscript, ObjectIdGetDatum(atparams->subscriptOid), values, nulls, updated); - newtup = heap_modify_tuple(tup, RelationGetDescr(catalog), - values, nulls, replaces); + newtup = heap_update_tuple(tup, RelationGetDescr(catalog), + values, nulls, updated); - CatalogTupleUpdate(catalog, &newtup->t_self, newtup); + CatalogTupleUpdate(catalog, &newtup->t_self, newtup, updated, NULL); /* Rebuild dependencies for this type */ GenerateTypeDependencies(newtup, @@ -4714,4 +4687,5 @@ AlterTypeRecurse(Oid typeOid, bool isImplicitArray, } systable_endscan(scan); + bms_free(updated); } diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c index 6ae42ea565668..2bcfb7f5bc78c 100644 --- a/src/backend/commands/user.c +++ b/src/backend/commands/user.c @@ -134,8 +134,8 @@ CreateRole(ParseState *pstate, CreateRoleStmt *stmt) Relation pg_authid_rel; TupleDesc pg_authid_dsc; HeapTuple tuple; - Datum new_record[Natts_pg_authid] = {0}; - bool new_record_nulls[Natts_pg_authid] = {0}; + Datum values[Natts_pg_authid] = {0}; + bool nulls[Natts_pg_authid] = {false}; Oid currentUserId = GetUserId(); Oid roleid; ListCell *item; @@ -405,15 +405,14 @@ CreateRole(ParseState *pstate, CreateRoleStmt *stmt) /* * Build a tuple to insert */ - new_record[Anum_pg_authid_rolname - 1] = - DirectFunctionCall1(namein, CStringGetDatum(stmt->role)); - new_record[Anum_pg_authid_rolsuper - 1] = BoolGetDatum(issuper); - new_record[Anum_pg_authid_rolinherit - 1] = BoolGetDatum(inherit); - new_record[Anum_pg_authid_rolcreaterole - 1] = BoolGetDatum(createrole); - new_record[Anum_pg_authid_rolcreatedb - 1] = BoolGetDatum(createdb); - new_record[Anum_pg_authid_rolcanlogin - 1] = BoolGetDatum(canlogin); - new_record[Anum_pg_authid_rolreplication - 1] = BoolGetDatum(isreplication); - new_record[Anum_pg_authid_rolconnlimit - 1] = Int32GetDatum(connlimit); + HeapTupleSetValue(pg_authid, rolname, DirectFunctionCall1(namein, CStringGetDatum(stmt->role)), values); + HeapTupleSetValue(pg_authid, rolsuper, BoolGetDatum(issuper), values); + HeapTupleSetValue(pg_authid, rolinherit, BoolGetDatum(inherit), values); + HeapTupleSetValue(pg_authid, rolcreaterole, BoolGetDatum(createrole), values); + HeapTupleSetValue(pg_authid, rolcreatedb, BoolGetDatum(createdb), values); + HeapTupleSetValue(pg_authid, rolcanlogin, BoolGetDatum(canlogin), values); + HeapTupleSetValue(pg_authid, rolreplication, BoolGetDatum(isreplication), values); + HeapTupleSetValue(pg_authid, rolconnlimit, Int32GetDatum(connlimit), values); if (password) { @@ -437,24 +436,24 @@ CreateRole(ParseState *pstate, CreateRoleStmt *stmt) { ereport(NOTICE, (errmsg("empty string is not a valid password, clearing password"))); - new_record_nulls[Anum_pg_authid_rolpassword - 1] = true; + HeapTupleSetValueNull(pg_authid, rolpassword, values, nulls); } else { /* Encrypt the password to the requested format. */ shadow_pass = encrypt_password(Password_encryption, stmt->role, password); - new_record[Anum_pg_authid_rolpassword - 1] = - CStringGetTextDatum(shadow_pass); + HeapTupleSetValue(pg_authid, rolpassword, CStringGetTextDatum(shadow_pass), values); } } else - new_record_nulls[Anum_pg_authid_rolpassword - 1] = true; + HeapTupleSetValueNull(pg_authid, rolpassword, values, nulls); - new_record[Anum_pg_authid_rolvaliduntil - 1] = validUntil_datum; - new_record_nulls[Anum_pg_authid_rolvaliduntil - 1] = validUntil_null; + HeapTupleSetValue(pg_authid, rolvaliduntil, validUntil_datum, values); + if (validUntil_null) + HeapTupleSetValueNull(pg_authid, rolvaliduntil, values, nulls); - new_record[Anum_pg_authid_rolbypassrls - 1] = BoolGetDatum(bypassrls); + HeapTupleSetValue(pg_authid, rolbypassrls, BoolGetDatum(bypassrls), values); /* * pg_largeobject_metadata contains pg_authid.oid's, so we use the @@ -476,14 +475,14 @@ CreateRole(ParseState *pstate, CreateRoleStmt *stmt) Anum_pg_authid_oid); } - new_record[Anum_pg_authid_oid - 1] = ObjectIdGetDatum(roleid); + HeapTupleSetValue(pg_authid, oid, ObjectIdGetDatum(roleid), values); - tuple = heap_form_tuple(pg_authid_dsc, new_record, new_record_nulls); + tuple = heap_form_tuple(pg_authid_dsc, values, nulls); /* * Insert new record in the pg_authid table */ - CatalogTupleInsert(pg_authid_rel, tuple); + CatalogTupleInsert(pg_authid_rel, tuple, NULL); /* * Advance command counter so we can see new record; else tests in @@ -618,9 +617,9 @@ CreateRole(ParseState *pstate, CreateRoleStmt *stmt) Oid AlterRole(ParseState *pstate, AlterRoleStmt *stmt) { - Datum new_record[Natts_pg_authid] = {0}; - bool new_record_nulls[Natts_pg_authid] = {0}; - bool new_record_repl[Natts_pg_authid] = {0}; + Datum values[Natts_pg_authid] = {0}; + bool nulls[Natts_pg_authid] = {false}; + Bitmapset *updated = NULL; Relation pg_authid_rel; TupleDesc pg_authid_dsc; HeapTuple tuple, @@ -870,45 +869,26 @@ AlterRole(ParseState *pstate, AlterRoleStmt *stmt) errdetail("The bootstrap superuser must have the %s attribute.", "SUPERUSER"))); - new_record[Anum_pg_authid_rolsuper - 1] = BoolGetDatum(should_be_super); - new_record_repl[Anum_pg_authid_rolsuper - 1] = true; + HeapTupleUpdateValue(pg_authid, rolsuper, BoolGetDatum(should_be_super), values, nulls, updated); } if (dinherit) - { - new_record[Anum_pg_authid_rolinherit - 1] = BoolGetDatum(boolVal(dinherit->arg)); - new_record_repl[Anum_pg_authid_rolinherit - 1] = true; - } + HeapTupleUpdateValue(pg_authid, rolinherit, BoolGetDatum(boolVal(dinherit->arg)), values, nulls, updated); if (dcreaterole) - { - new_record[Anum_pg_authid_rolcreaterole - 1] = BoolGetDatum(boolVal(dcreaterole->arg)); - new_record_repl[Anum_pg_authid_rolcreaterole - 1] = true; - } + HeapTupleUpdateValue(pg_authid, rolcreaterole, BoolGetDatum(boolVal(dcreaterole->arg)), values, nulls, updated); if (dcreatedb) - { - new_record[Anum_pg_authid_rolcreatedb - 1] = BoolGetDatum(boolVal(dcreatedb->arg)); - new_record_repl[Anum_pg_authid_rolcreatedb - 1] = true; - } + HeapTupleUpdateValue(pg_authid, rolcreatedb, BoolGetDatum(boolVal(dcreatedb->arg)), values, nulls, updated); if (dcanlogin) - { - new_record[Anum_pg_authid_rolcanlogin - 1] = BoolGetDatum(boolVal(dcanlogin->arg)); - new_record_repl[Anum_pg_authid_rolcanlogin - 1] = true; - } + HeapTupleUpdateValue(pg_authid, rolcanlogin, BoolGetDatum(boolVal(dcanlogin->arg)), values, nulls, updated); if (disreplication) - { - new_record[Anum_pg_authid_rolreplication - 1] = BoolGetDatum(boolVal(disreplication->arg)); - new_record_repl[Anum_pg_authid_rolreplication - 1] = true; - } + HeapTupleUpdateValue(pg_authid, rolreplication, BoolGetDatum(boolVal(disreplication->arg)), values, nulls, updated); if (dconnlimit) - { - new_record[Anum_pg_authid_rolconnlimit - 1] = Int32GetDatum(connlimit); - new_record_repl[Anum_pg_authid_rolconnlimit - 1] = true; - } + HeapTupleUpdateValue(pg_authid, rolconnlimit, Int32GetDatum(connlimit), values, nulls, updated); /* password */ if (password) @@ -922,40 +902,33 @@ AlterRole(ParseState *pstate, AlterRoleStmt *stmt) { ereport(NOTICE, (errmsg("empty string is not a valid password, clearing password"))); - new_record_nulls[Anum_pg_authid_rolpassword - 1] = true; + HeapTupleSetValueNull(pg_authid, rolpassword, values, nulls); } else { /* Encrypt the password to the requested format. */ shadow_pass = encrypt_password(Password_encryption, rolename, password); - new_record[Anum_pg_authid_rolpassword - 1] = - CStringGetTextDatum(shadow_pass); + HeapTupleUpdateValue(pg_authid, rolpassword, CStringGetTextDatum(shadow_pass), values, nulls, updated); } - new_record_repl[Anum_pg_authid_rolpassword - 1] = true; } /* unset password */ if (dpassword && dpassword->arg == NULL) - { - new_record_repl[Anum_pg_authid_rolpassword - 1] = true; - new_record_nulls[Anum_pg_authid_rolpassword - 1] = true; - } + HeapTupleUpdateValueNull(pg_authid, rolpassword, values, nulls, updated); /* valid until */ - new_record[Anum_pg_authid_rolvaliduntil - 1] = validUntil_datum; - new_record_nulls[Anum_pg_authid_rolvaliduntil - 1] = validUntil_null; - new_record_repl[Anum_pg_authid_rolvaliduntil - 1] = true; + HeapTupleUpdateValue(pg_authid, rolvaliduntil, validUntil_datum, values, nulls, updated); + if (validUntil_null) + HeapTupleUpdateValueNull(pg_authid, rolvaliduntil, values, nulls, updated); if (dbypassRLS) - { - new_record[Anum_pg_authid_rolbypassrls - 1] = BoolGetDatum(boolVal(dbypassRLS->arg)); - new_record_repl[Anum_pg_authid_rolbypassrls - 1] = true; - } + HeapTupleUpdateValue(pg_authid, rolbypassrls, BoolGetDatum(boolVal(dbypassRLS->arg)), values, nulls, updated); - new_tuple = heap_modify_tuple(tuple, pg_authid_dsc, new_record, - new_record_nulls, new_record_repl); - CatalogTupleUpdate(pg_authid_rel, &tuple->t_self, new_tuple); + new_tuple = heap_update_tuple(tuple, pg_authid_dsc, values, + nulls, updated); + CatalogTupleUpdate(pg_authid_rel, &tuple->t_self, new_tuple, updated, NULL); + bms_free(updated); InvokeObjectPostAlterHook(AuthIdRelationId, roleid, 0); @@ -1339,10 +1312,9 @@ RenameRole(const char *oldname, const char *newname) Relation rel; Datum datum; bool isnull; - Datum repl_val[Natts_pg_authid]; - bool repl_null[Natts_pg_authid]; - bool repl_repl[Natts_pg_authid]; - int i; + Datum values[Natts_pg_authid] = {0}; + bool nulls[Natts_pg_authid] = {false}; + Bitmapset *updated = NULL; Oid roleid; ObjectAddress address; Form_pg_authid authform; @@ -1433,29 +1405,22 @@ RenameRole(const char *oldname, const char *newname) "CREATEROLE", "ADMIN", NameStr(authform->rolname)))); } - /* OK, construct the modified tuple */ - for (i = 0; i < Natts_pg_authid; i++) - repl_repl[i] = false; - - repl_repl[Anum_pg_authid_rolname - 1] = true; - repl_val[Anum_pg_authid_rolname - 1] = DirectFunctionCall1(namein, - CStringGetDatum(newname)); - repl_null[Anum_pg_authid_rolname - 1] = false; + HeapTupleUpdateValue(pg_authid, rolname, DirectFunctionCall1(namein, CStringGetDatum(newname)), values, nulls, updated); datum = heap_getattr(oldtuple, Anum_pg_authid_rolpassword, dsc, &isnull); if (!isnull && get_password_type(TextDatumGetCString(datum)) == PASSWORD_TYPE_MD5) { /* MD5 uses the username as salt, so just clear it on a rename */ - repl_repl[Anum_pg_authid_rolpassword - 1] = true; - repl_null[Anum_pg_authid_rolpassword - 1] = true; + HeapTupleUpdateValueNull(pg_authid, rolpassword, values, nulls, updated); ereport(NOTICE, (errmsg("MD5 password cleared because of role rename"))); } - newtuple = heap_modify_tuple(oldtuple, dsc, repl_val, repl_null, repl_repl); - CatalogTupleUpdate(rel, &oldtuple->t_self, newtuple); + newtuple = heap_update_tuple(oldtuple, dsc, values, nulls, updated); + CatalogTupleUpdate(rel, &oldtuple->t_self, newtuple, updated, NULL); + bms_free(updated); InvokeObjectPostAlterHook(AuthIdRelationId, roleid, 0); @@ -1823,17 +1788,14 @@ AddRoleMems(Oid currentUserId, const char *rolename, Oid roleid, Oid memberid = lfirst_oid(iditem); HeapTuple authmem_tuple; HeapTuple tuple; - Datum new_record[Natts_pg_auth_members] = {0}; - bool new_record_nulls[Natts_pg_auth_members] = {0}; - bool new_record_repl[Natts_pg_auth_members] = {0}; + Datum values[Natts_pg_auth_members] = {0}; + bool nulls[Natts_pg_auth_members] = {false}; + Bitmapset *updated = NULL; /* Common initialization for possible insert or update */ - new_record[Anum_pg_auth_members_roleid - 1] = - ObjectIdGetDatum(roleid); - new_record[Anum_pg_auth_members_member - 1] = - ObjectIdGetDatum(memberid); - new_record[Anum_pg_auth_members_grantor - 1] = - ObjectIdGetDatum(grantorId); + HeapTupleUpdateValue(pg_auth_members, roleid, ObjectIdGetDatum(roleid), values, nulls, updated); + HeapTupleUpdateValue(pg_auth_members, member, ObjectIdGetDatum(memberid), values, nulls, updated); + HeapTupleUpdateValue(pg_auth_members, grantor, ObjectIdGetDatum(grantorId), values, nulls, updated); /* Find any existing tuple */ authmem_tuple = SearchSysCache3(AUTHMEMROLEMEM, @@ -1857,30 +1819,21 @@ AddRoleMems(Oid currentUserId, const char *rolename, Oid roleid, if ((popt->specified & GRANT_ROLE_SPECIFIED_ADMIN) != 0 && authmem_form->admin_option != popt->admin) { - new_record[Anum_pg_auth_members_admin_option - 1] = - BoolGetDatum(popt->admin); - new_record_repl[Anum_pg_auth_members_admin_option - 1] = - true; + HeapTupleUpdateValue(pg_auth_members, admin_option, BoolGetDatum(popt->admin), values, nulls, updated); at_least_one_change = true; } if ((popt->specified & GRANT_ROLE_SPECIFIED_INHERIT) != 0 && authmem_form->inherit_option != popt->inherit) { - new_record[Anum_pg_auth_members_inherit_option - 1] = - BoolGetDatum(popt->inherit); - new_record_repl[Anum_pg_auth_members_inherit_option - 1] = - true; + HeapTupleUpdateValue(pg_auth_members, inherit_option, BoolGetDatum(popt->inherit), values, nulls, updated); at_least_one_change = true; } if ((popt->specified & GRANT_ROLE_SPECIFIED_SET) != 0 && authmem_form->set_option != popt->set) { - new_record[Anum_pg_auth_members_set_option - 1] = - BoolGetDatum(popt->set); - new_record_repl[Anum_pg_auth_members_set_option - 1] = - true; + HeapTupleUpdateValue(pg_auth_members, set_option, BoolGetDatum(popt->set), values, nulls, updated); at_least_one_change = true; } @@ -1894,10 +1847,8 @@ AddRoleMems(Oid currentUserId, const char *rolename, Oid roleid, continue; } - tuple = heap_modify_tuple(authmem_tuple, pg_authmem_dsc, - new_record, - new_record_nulls, new_record_repl); - CatalogTupleUpdate(pg_authmem_rel, &tuple->t_self, tuple); + tuple = heap_update_tuple(authmem_tuple, pg_authmem_dsc, values, nulls, updated); + CatalogTupleUpdate(pg_authmem_rel, &tuple->t_self, tuple, updated, NULL); ReleaseSysCache(authmem_tuple); } @@ -1911,10 +1862,8 @@ AddRoleMems(Oid currentUserId, const char *rolename, Oid roleid, * Either they were specified, or the defaults as set by * InitGrantRoleOptions are correct. */ - new_record[Anum_pg_auth_members_admin_option - 1] = - BoolGetDatum(popt->admin); - new_record[Anum_pg_auth_members_set_option - 1] = - BoolGetDatum(popt->set); + HeapTupleSetValue(pg_auth_members, admin_option, BoolGetDatum(popt->admin), values); + HeapTupleSetValue(pg_auth_members, set_option, BoolGetDatum(popt->set), values); /* * If the user specified a value for the inherit option, use @@ -1922,8 +1871,7 @@ AddRoleMems(Oid currentUserId, const char *rolename, Oid roleid, * on the role-level property. */ if ((popt->specified & GRANT_ROLE_SPECIFIED_INHERIT) != 0) - new_record[Anum_pg_auth_members_inherit_option - 1] = - BoolGetDatum(popt->inherit); + HeapTupleSetValue(pg_auth_members, inherit_option, BoolGetDatum(popt->inherit), values); else { HeapTuple mrtup; @@ -1933,18 +1881,16 @@ AddRoleMems(Oid currentUserId, const char *rolename, Oid roleid, if (!HeapTupleIsValid(mrtup)) elog(ERROR, "cache lookup failed for role %u", memberid); mrform = (Form_pg_authid) GETSTRUCT(mrtup); - new_record[Anum_pg_auth_members_inherit_option - 1] = - BoolGetDatum(mrform->rolinherit); + HeapTupleSetValue(pg_auth_members, inherit_option, BoolGetDatum(mrform->rolinherit), values); ReleaseSysCache(mrtup); } /* get an OID for the new row and insert it */ objectId = GetNewOidWithIndex(pg_authmem_rel, AuthMemOidIndexId, Anum_pg_auth_members_oid); - new_record[Anum_pg_auth_members_oid - 1] = ObjectIdGetDatum(objectId); - tuple = heap_form_tuple(pg_authmem_dsc, - new_record, new_record_nulls); - CatalogTupleInsert(pg_authmem_rel, tuple); + HeapTupleSetValue(pg_auth_members, oid, ObjectIdGetDatum(objectId), values); + tuple = heap_form_tuple(pg_authmem_dsc, values, nulls); + CatalogTupleInsert(pg_authmem_rel, tuple, NULL); /* updateAclDependencies wants to pfree array inputs */ newmembers[0] = grantorId; @@ -1954,6 +1900,8 @@ AddRoleMems(Oid currentUserId, const char *rolename, Oid roleid, 1, newmembers); } + bms_free(updated); + /* CCI after each change, in case there are duplicates in list */ CommandCounterIncrement(); } @@ -1986,7 +1934,6 @@ DelRoleMems(Oid currentUserId, const char *rolename, Oid roleid, ListCell *iditem; CatCList *memlist; RevokeRoleGrantAction *actions; - int i; Assert(list_length(memberSpecs) == list_length(memberIds)); @@ -2034,7 +1981,7 @@ DelRoleMems(Oid currentUserId, const char *rolename, Oid roleid, * left alone, deleted, or just have the admin_option flag cleared. * Perform the appropriate action in each case. */ - for (i = 0; i < memlist->n_members; ++i) + for (int i = 0; i < memlist->n_members; ++i) { HeapTuple authmem_tuple; Form_pg_auth_members authmem_form; @@ -2059,39 +2006,24 @@ DelRoleMems(Oid currentUserId, const char *rolename, Oid roleid, { /* Just turn off the specified option */ HeapTuple tuple; - Datum new_record[Natts_pg_auth_members] = {0}; - bool new_record_nulls[Natts_pg_auth_members] = {0}; - bool new_record_repl[Natts_pg_auth_members] = {0}; + Datum values[Natts_pg_auth_members] = {0}; + bool nulls[Natts_pg_auth_members] = {false}; + Bitmapset *updated = NULL; /* Build a tuple to update with */ if (actions[i] == RRG_REMOVE_ADMIN_OPTION) - { - new_record[Anum_pg_auth_members_admin_option - 1] = - BoolGetDatum(false); - new_record_repl[Anum_pg_auth_members_admin_option - 1] = - true; - } + HeapTupleUpdateValue(pg_auth_members, admin_option, BoolGetDatum(false), values, nulls, updated); else if (actions[i] == RRG_REMOVE_INHERIT_OPTION) - { - new_record[Anum_pg_auth_members_inherit_option - 1] = - BoolGetDatum(false); - new_record_repl[Anum_pg_auth_members_inherit_option - 1] = - true; - } + HeapTupleUpdateValue(pg_auth_members, inherit_option, BoolGetDatum(false), values, nulls, updated); else if (actions[i] == RRG_REMOVE_SET_OPTION) - { - new_record[Anum_pg_auth_members_set_option - 1] = - BoolGetDatum(false); - new_record_repl[Anum_pg_auth_members_set_option - 1] = - true; - } + HeapTupleUpdateValue(pg_auth_members, set_option, BoolGetDatum(false), values, nulls, updated); else elog(ERROR, "unknown role revoke action"); - tuple = heap_modify_tuple(authmem_tuple, pg_authmem_dsc, - new_record, - new_record_nulls, new_record_repl); - CatalogTupleUpdate(pg_authmem_rel, &tuple->t_self, tuple); + tuple = heap_update_tuple(authmem_tuple, pg_authmem_dsc, + values, nulls, updated); + CatalogTupleUpdate(pg_authmem_rel, &tuple->t_self, tuple, updated, NULL); + bms_free(updated); } } diff --git a/src/backend/replication/logical/origin.c b/src/backend/replication/logical/origin.c index 4632aa8115d30..8b077b7b43f95 100644 --- a/src/backend/replication/logical/origin.c +++ b/src/backend/replication/logical/origin.c @@ -312,8 +312,8 @@ replorigin_create(const char *roname) for (roident = InvalidOid + 1; roident < PG_UINT16_MAX; roident++) { - bool nulls[Natts_pg_replication_origin]; - Datum values[Natts_pg_replication_origin]; + Datum values[Natts_pg_replication_origin] = {0}; + bool nulls[Natts_pg_replication_origin] = {false}; bool collides; CHECK_FOR_INTERRUPTS(); @@ -340,11 +340,11 @@ replorigin_create(const char *roname) */ memset(&nulls, 0, sizeof(nulls)); - values[Anum_pg_replication_origin_roident - 1] = ObjectIdGetDatum(roident); - values[Anum_pg_replication_origin_roname - 1] = roname_d; + HeapTupleSetValue(pg_replication_origin, roident, ObjectIdGetDatum(roident), values); + HeapTupleSetValue(pg_replication_origin, roname, roname_d, values); tuple = heap_form_tuple(RelationGetDescr(rel), values, nulls); - CatalogTupleInsert(rel, tuple); + CatalogTupleInsert(rel, tuple, NULL); CommandCounterIncrement(); break; } diff --git a/src/backend/replication/logical/tablesync.c b/src/backend/replication/logical/tablesync.c index dcc6124cc7308..6ca50840e473a 100644 --- a/src/backend/replication/logical/tablesync.c +++ b/src/backend/replication/logical/tablesync.c @@ -1651,9 +1651,9 @@ UpdateTwoPhaseState(Oid suboid, char new_state) { Relation rel; HeapTuple tup; - bool nulls[Natts_pg_subscription]; - bool replaces[Natts_pg_subscription]; - Datum values[Natts_pg_subscription]; + Datum values[Natts_pg_subscription] = {0}; + bool nulls[Natts_pg_subscription] = {false}; + Bitmapset *updated = NULL; Assert(new_state == LOGICALREP_TWOPHASE_STATE_DISABLED || new_state == LOGICALREP_TWOPHASE_STATE_PENDING || @@ -1666,19 +1666,13 @@ UpdateTwoPhaseState(Oid suboid, char new_state) "cache lookup failed for subscription oid %u", suboid); - /* Form a new tuple. */ - memset(values, 0, sizeof(values)); - memset(nulls, false, sizeof(nulls)); - memset(replaces, false, sizeof(replaces)); - /* And update/set two_phase state */ - values[Anum_pg_subscription_subtwophasestate - 1] = CharGetDatum(new_state); - replaces[Anum_pg_subscription_subtwophasestate - 1] = true; + HeapTupleUpdateValue(pg_subscription, subtwophasestate, CharGetDatum(new_state), values, nulls, updated); - tup = heap_modify_tuple(tup, RelationGetDescr(rel), - values, nulls, replaces); - CatalogTupleUpdate(rel, &tup->t_self, tup); + tup = heap_update_tuple(tup, RelationGetDescr(rel), values, nulls, updated); + CatalogTupleUpdate(rel, &tup->t_self, tup, updated, NULL); - heap_freetuple(tup); table_close(rel, RowExclusiveLock); + bms_free(updated); + heap_freetuple(tup); } diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c index 93970c6af2948..8551609c97718 100644 --- a/src/backend/replication/logical/worker.c +++ b/src/backend/replication/logical/worker.c @@ -6121,21 +6121,12 @@ clear_subscription_skip_lsn(XLogRecPtr finish_lsn) */ if (subform->subskiplsn == myskiplsn) { - bool nulls[Natts_pg_subscription]; - bool replaces[Natts_pg_subscription]; - Datum values[Natts_pg_subscription]; - - memset(values, 0, sizeof(values)); - memset(nulls, false, sizeof(nulls)); - memset(replaces, false, sizeof(replaces)); + Bitmapset *updated = NULL; /* reset subskiplsn */ - values[Anum_pg_subscription_subskiplsn - 1] = LSNGetDatum(InvalidXLogRecPtr); - replaces[Anum_pg_subscription_subskiplsn - 1] = true; - - tup = heap_modify_tuple(tup, RelationGetDescr(rel), values, nulls, - replaces); - CatalogTupleUpdate(rel, &tup->t_self, tup); + HeapTupleUpdateField(pg_subscription, subskiplsn, LSNGetDatum(InvalidXLogRecPtr), subform, updated); + CatalogTupleUpdate(rel, &tup->t_self, tup, updated, NULL); + bms_free(updated); if (myskiplsn != finish_lsn) ereport(WARNING, diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c index a96fbdc1ddd64..92f82081d257a 100644 --- a/src/backend/rewrite/rewriteDefine.c +++ b/src/backend/rewrite/rewriteDefine.c @@ -59,8 +59,8 @@ InsertRule(const char *rulname, { char *evqual = nodeToString(event_qual); char *actiontree = nodeToString((Node *) action); - Datum values[Natts_pg_rewrite]; - bool nulls[Natts_pg_rewrite] = {0}; + Datum values[Natts_pg_rewrite] = {0}; + bool nulls[Natts_pg_rewrite] = {false}; NameData rname; Relation pg_rewrite_desc; HeapTuple tup, @@ -69,18 +69,19 @@ InsertRule(const char *rulname, ObjectAddress myself, referenced; bool is_update = false; + Bitmapset *updated = NULL; /* * Set up *nulls and *values arrays */ namestrcpy(&rname, rulname); - values[Anum_pg_rewrite_rulename - 1] = NameGetDatum(&rname); - values[Anum_pg_rewrite_ev_class - 1] = ObjectIdGetDatum(eventrel_oid); - values[Anum_pg_rewrite_ev_type - 1] = CharGetDatum(evtype + '0'); - values[Anum_pg_rewrite_ev_enabled - 1] = CharGetDatum(RULE_FIRES_ON_ORIGIN); - values[Anum_pg_rewrite_is_instead - 1] = BoolGetDatum(evinstead); - values[Anum_pg_rewrite_ev_qual - 1] = CStringGetTextDatum(evqual); - values[Anum_pg_rewrite_ev_action - 1] = CStringGetTextDatum(actiontree); + HeapTupleUpdateValue(pg_rewrite, rulename, NameGetDatum(&rname), values, nulls, updated); + HeapTupleUpdateValue(pg_rewrite, ev_class, ObjectIdGetDatum(eventrel_oid), values, nulls, updated); + HeapTupleUpdateValue(pg_rewrite, ev_type, CharGetDatum(evtype + '0'), values, nulls, updated); + HeapTupleUpdateValue(pg_rewrite, ev_enabled, CharGetDatum(RULE_FIRES_ON_ORIGIN), values, nulls, updated); + HeapTupleUpdateValue(pg_rewrite, is_instead, BoolGetDatum(evinstead), values, nulls, updated); + HeapTupleUpdateValue(pg_rewrite, ev_qual, CStringGetTextDatum(evqual), values, nulls, updated); + HeapTupleUpdateValue(pg_rewrite, ev_action, CStringGetTextDatum(actiontree), values, nulls, updated); /* * Ready to store new pg_rewrite tuple @@ -96,8 +97,6 @@ InsertRule(const char *rulname, if (HeapTupleIsValid(oldtup)) { - bool replaces[Natts_pg_rewrite] = {0}; - if (!replace) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), @@ -107,16 +106,14 @@ InsertRule(const char *rulname, /* * When replacing, we don't need to replace every attribute */ - replaces[Anum_pg_rewrite_ev_type - 1] = true; - replaces[Anum_pg_rewrite_is_instead - 1] = true; - replaces[Anum_pg_rewrite_ev_qual - 1] = true; - replaces[Anum_pg_rewrite_ev_action - 1] = true; - - tup = heap_modify_tuple(oldtup, RelationGetDescr(pg_rewrite_desc), - values, nulls, replaces); - - CatalogTupleUpdate(pg_rewrite_desc, &tup->t_self, tup); - + HeapTupleUpdateValue(pg_rewrite, ev_type, CharGetDatum(evtype + '0'), values, nulls, updated); + HeapTupleUpdateValue(pg_rewrite, is_instead, BoolGetDatum(evinstead), values, nulls, updated); + HeapTupleUpdateValue(pg_rewrite, ev_qual, CStringGetTextDatum(evqual), values, nulls, updated); + HeapTupleUpdateValue(pg_rewrite, ev_action, CStringGetTextDatum(actiontree), values, nulls, updated); + + tup = heap_update_tuple(oldtup, RelationGetDescr(pg_rewrite_desc), + values, nulls, updated); + CatalogTupleUpdate(pg_rewrite_desc, &tup->t_self, tup, updated, NULL); ReleaseSysCache(oldtup); rewriteObjectId = ((Form_pg_rewrite) GETSTRUCT(tup))->oid; @@ -127,14 +124,12 @@ InsertRule(const char *rulname, rewriteObjectId = GetNewOidWithIndex(pg_rewrite_desc, RewriteOidIndexId, Anum_pg_rewrite_oid); - values[Anum_pg_rewrite_oid - 1] = ObjectIdGetDatum(rewriteObjectId); - + HeapTupleUpdateValue(pg_rewrite, oid, ObjectIdGetDatum(rewriteObjectId), values, nulls, updated); tup = heap_form_tuple(pg_rewrite_desc->rd_att, values, nulls); - - CatalogTupleInsert(pg_rewrite_desc, tup); + CatalogTupleInsert(pg_rewrite_desc, tup, NULL); } - + bms_free(updated); heap_freetuple(tup); /* If replacing, get rid of old dependencies and make new ones */ @@ -727,8 +722,11 @@ EnableDisableRule(Relation rel, const char *rulename, */ if (ruleform->ev_enabled != fires_when) { - ruleform->ev_enabled = fires_when; - CatalogTupleUpdate(pg_rewrite_desc, &ruletup->t_self, ruletup); + Bitmapset *updated = NULL; + + HeapTupleUpdateField(pg_rewrite, ev_enabled, fires_when, ruleform, updated); + CatalogTupleUpdate(pg_rewrite_desc, &ruletup->t_self, ruletup, updated, NULL); + bms_free(updated); changed = true; } @@ -799,6 +797,7 @@ RenameRewriteRule(RangeVar *relation, const char *oldName, Form_pg_rewrite ruleform; Oid ruleOid; ObjectAddress address; + Bitmapset *updated = NULL; /* * Look up name, check permissions, and acquire lock (which we will NOT @@ -845,8 +844,8 @@ RenameRewriteRule(RangeVar *relation, const char *oldName, /* OK, do the update */ namestrcpy(&(ruleform->rulename), newName); - - CatalogTupleUpdate(pg_rewrite_desc, &ruletup->t_self, ruletup); + CatalogTupleUpdate(pg_rewrite_desc, &ruletup->t_self, ruletup, updated, NULL); + bms_free(updated); InvokeObjectPostAlterHook(RewriteRelationId, ruleOid, 0); diff --git a/src/backend/rewrite/rewriteSupport.c b/src/backend/rewrite/rewriteSupport.c index e401c19594902..4d82c0c8e1626 100644 --- a/src/backend/rewrite/rewriteSupport.c +++ b/src/backend/rewrite/rewriteSupport.c @@ -18,6 +18,7 @@ #include "access/table.h" #include "catalog/indexing.h" #include "catalog/pg_class.h" +#include "nodes/bitmapset.h" #include "catalog/pg_rewrite.h" #include "rewrite/rewriteSupport.h" #include "utils/inval.h" @@ -68,9 +69,12 @@ SetRelationRuleStatus(Oid relationId, bool relHasRules) if (classForm->relhasrules != relHasRules) { /* Do the update */ + Bitmapset *updated = NULL; + classForm->relhasrules = relHasRules; + updated = bms_add_member(updated, Anum_pg_class_relhasrules - FirstLowInvalidHeapAttributeNumber); - CatalogTupleUpdate(relationRelation, &tuple->t_self, tuple); + CatalogTupleUpdate(relationRelation, &tuple->t_self, tuple, updated, NULL); } else { diff --git a/src/backend/statistics/extended_stats.c b/src/backend/statistics/extended_stats.c index 3c3d2d315c6f4..7a6e6a2787b81 100644 --- a/src/backend/statistics/extended_stats.c +++ b/src/backend/statistics/extended_stats.c @@ -762,20 +762,14 @@ statext_store(Oid statOid, bool inh, { Relation pg_stextdata; HeapTuple stup; - Datum values[Natts_pg_statistic_ext_data]; - bool nulls[Natts_pg_statistic_ext_data]; + Datum values[Natts_pg_statistic_ext_data] = {0}; + bool nulls[Natts_pg_statistic_ext_data] = {false}; pg_stextdata = table_open(StatisticExtDataRelationId, RowExclusiveLock); - memset(nulls, true, sizeof(nulls)); - memset(values, 0, sizeof(values)); - /* basic info */ - values[Anum_pg_statistic_ext_data_stxoid - 1] = ObjectIdGetDatum(statOid); - nulls[Anum_pg_statistic_ext_data_stxoid - 1] = false; - - values[Anum_pg_statistic_ext_data_stxdinherit - 1] = BoolGetDatum(inh); - nulls[Anum_pg_statistic_ext_data_stxdinherit - 1] = false; + HeapTupleSetValue(pg_statistic_ext_data, stxoid, ObjectIdGetDatum(statOid), values); + HeapTupleSetValue(pg_statistic_ext_data, stxdinherit, BoolGetDatum(inh), values); /* * Construct a new pg_statistic_ext_data tuple, replacing the calculated @@ -785,29 +779,42 @@ statext_store(Oid statOid, bool inh, { bytea *data = statext_ndistinct_serialize(ndistinct); - nulls[Anum_pg_statistic_ext_data_stxdndistinct - 1] = (data == NULL); - values[Anum_pg_statistic_ext_data_stxdndistinct - 1] = PointerGetDatum(data); + if (data == NULL) + HeapTupleSetValueNull(pg_statistic_ext_data, stxdndistinct, values, nulls); + else + HeapTupleSetValue(pg_statistic_ext_data, stxdndistinct, PointerGetDatum(data), values); } + else + HeapTupleSetValueNull(pg_statistic_ext_data, stxdndistinct, values, nulls); if (dependencies != NULL) { bytea *data = statext_dependencies_serialize(dependencies); - nulls[Anum_pg_statistic_ext_data_stxddependencies - 1] = (data == NULL); - values[Anum_pg_statistic_ext_data_stxddependencies - 1] = PointerGetDatum(data); + if (data == NULL) + HeapTupleSetValueNull(pg_statistic_ext_data, stxddependencies, values, nulls); + else + HeapTupleSetValue(pg_statistic_ext_data, stxddependencies, PointerGetDatum(data), values); } + else + HeapTupleSetValueNull(pg_statistic_ext_data, stxddependencies, values, nulls); + if (mcv != NULL) { bytea *data = statext_mcv_serialize(mcv, stats); - nulls[Anum_pg_statistic_ext_data_stxdmcv - 1] = (data == NULL); - values[Anum_pg_statistic_ext_data_stxdmcv - 1] = PointerGetDatum(data); + if (data == NULL) + HeapTupleSetValueNull(pg_statistic_ext_data, stxdmcv, values, nulls); + else + HeapTupleSetValue(pg_statistic_ext_data, stxdmcv, PointerGetDatum(data), values); } + else + HeapTupleSetValueNull(pg_statistic_ext_data, stxdmcv, values, nulls); + if (exprs != (Datum) 0) - { - nulls[Anum_pg_statistic_ext_data_stxdexpr - 1] = false; - values[Anum_pg_statistic_ext_data_stxdexpr - 1] = exprs; - } + HeapTupleSetValue(pg_statistic_ext_data, stxdexpr, exprs, values); + else + HeapTupleSetValueNull(pg_statistic_ext_data, stxdexpr, values, nulls); /* * Delete the old tuple if it exists, and insert a new one. It's easier @@ -817,7 +824,7 @@ statext_store(Oid statOid, bool inh, /* form and insert a new tuple */ stup = heap_form_tuple(RelationGetDescr(pg_stextdata), values, nulls); - CatalogTupleInsert(pg_stextdata, stup); + CatalogTupleInsert(pg_stextdata, stup, NULL); heap_freetuple(stup); @@ -2293,8 +2300,8 @@ serialize_expr_stats(AnlExprData *exprdata, int nexprs) k; VacAttrStats *stats = exprdata[exprno].vacattrstat; - Datum values[Natts_pg_statistic]; - bool nulls[Natts_pg_statistic]; + Datum values[Natts_pg_statistic] = {0}; + bool nulls[Natts_pg_statistic] = {false}; HeapTuple stup; if (!stats->stats_valid) @@ -2315,12 +2322,12 @@ serialize_expr_stats(AnlExprData *exprdata, int nexprs) nulls[i] = false; } - values[Anum_pg_statistic_starelid - 1] = ObjectIdGetDatum(InvalidOid); - values[Anum_pg_statistic_staattnum - 1] = Int16GetDatum(InvalidAttrNumber); - values[Anum_pg_statistic_stainherit - 1] = BoolGetDatum(false); - values[Anum_pg_statistic_stanullfrac - 1] = Float4GetDatum(stats->stanullfrac); - values[Anum_pg_statistic_stawidth - 1] = Int32GetDatum(stats->stawidth); - values[Anum_pg_statistic_stadistinct - 1] = Float4GetDatum(stats->stadistinct); + HeapTupleSetValue(pg_statistic, starelid, ObjectIdGetDatum(InvalidOid), values); + HeapTupleSetValue(pg_statistic, staattnum, Int16GetDatum(InvalidAttrNumber), values); + HeapTupleSetValue(pg_statistic, stainherit, BoolGetDatum(false), values); + HeapTupleSetValue(pg_statistic, stanullfrac, Float4GetDatum(stats->stanullfrac), values); + HeapTupleSetValue(pg_statistic, stawidth, Int32GetDatum(stats->stawidth), values); + HeapTupleSetValue(pg_statistic, stadistinct, Float4GetDatum(stats->stadistinct), values); i = Anum_pg_statistic_stakind1 - 1; for (k = 0; k < STATISTIC_NUM_SLOTS; k++) { diff --git a/src/backend/statistics/relation_stats.c b/src/backend/statistics/relation_stats.c index 174da7d93a505..790391b573dc1 100644 --- a/src/backend/statistics/relation_stats.c +++ b/src/backend/statistics/relation_stats.c @@ -18,6 +18,7 @@ #include "postgres.h" #include "access/heapam.h" +#include "access/htup.h" #include "catalog/indexing.h" #include "catalog/namespace.h" #include "nodes/makefuncs.h" @@ -79,10 +80,9 @@ relation_statistics_update(FunctionCallInfo fcinfo) bool update_relallfrozen = false; HeapTuple ctup; Form_pg_class pgcform; - int replaces[4] = {0}; - Datum values[4] = {0}; - bool nulls[4] = {0}; - int nreplaces = 0; + Datum values[Natts_pg_class] = {0}; + bool nulls[Natts_pg_class] = {false}; + Bitmapset *updated = NULL; Oid locked_table = InvalidOid; stats_check_required_arg(fcinfo, relarginfo, RELSCHEMA_ARG); @@ -146,42 +146,26 @@ relation_statistics_update(FunctionCallInfo fcinfo) pgcform = (Form_pg_class) GETSTRUCT(ctup); if (update_relpages && relpages != pgcform->relpages) - { - replaces[nreplaces] = Anum_pg_class_relpages; - values[nreplaces] = UInt32GetDatum(relpages); - nreplaces++; - } + HeapTupleUpdateValue(pg_class, relpages, UInt32GetDatum(relpages), values, nulls, updated); if (update_reltuples && reltuples != pgcform->reltuples) - { - replaces[nreplaces] = Anum_pg_class_reltuples; - values[nreplaces] = Float4GetDatum(reltuples); - nreplaces++; - } + HeapTupleUpdateValue(pg_class, reltuples, Float4GetDatum(reltuples), values, nulls, updated); if (update_relallvisible && relallvisible != pgcform->relallvisible) - { - replaces[nreplaces] = Anum_pg_class_relallvisible; - values[nreplaces] = UInt32GetDatum(relallvisible); - nreplaces++; - } + HeapTupleUpdateValue(pg_class, relallvisible, UInt32GetDatum(relallvisible), values, nulls, updated); if (update_relallfrozen && relallfrozen != pgcform->relallfrozen) - { - replaces[nreplaces] = Anum_pg_class_relallfrozen; - values[nreplaces] = UInt32GetDatum(relallfrozen); - nreplaces++; - } + HeapTupleUpdateValue(pg_class, relallfrozen, UInt32GetDatum(relallfrozen), values, nulls, updated); - if (nreplaces > 0) + if (!bms_is_empty(updated)) { TupleDesc tupdesc = RelationGetDescr(crel); HeapTuple newtup; - newtup = heap_modify_tuple_by_cols(ctup, tupdesc, nreplaces, - replaces, values, nulls); - CatalogTupleUpdate(crel, &newtup->t_self, newtup); + newtup = heap_update_tuple(ctup, tupdesc, values, nulls, updated); + CatalogTupleUpdate(crel, &newtup->t_self, newtup, updated, NULL); heap_freetuple(newtup); + bms_free(updated); } ReleaseSysCache(ctup); diff --git a/src/backend/storage/large_object/inv_api.c b/src/backend/storage/large_object/inv_api.c index f6d2f9dba13d0..163c77e49272e 100644 --- a/src/backend/storage/large_object/inv_api.c +++ b/src/backend/storage/large_object/inv_api.c @@ -564,9 +564,8 @@ inv_write(LargeObjectDesc *obj_desc, const char *buf, int nbytes) } workbuf = {0}; char *workb = VARDATA(&workbuf.hdr); HeapTuple newtup; - Datum values[Natts_pg_largeobject]; - bool nulls[Natts_pg_largeobject]; - bool replace[Natts_pg_largeobject]; + Datum values[Natts_pg_largeobject] = {0}; + bool nulls[Natts_pg_largeobject] = {false}; CatalogIndexState indstate; Assert(obj_desc); @@ -612,6 +611,8 @@ inv_write(LargeObjectDesc *obj_desc, const char *buf, int nbytes) while (nwritten < nbytes) { + Bitmapset *updated = NULL; + /* * If possible, get next pre-existing page of the LO. We expect the * indexscan will deliver these in order --- but there may be holes. @@ -667,16 +668,11 @@ inv_write(LargeObjectDesc *obj_desc, const char *buf, int nbytes) /* * Form and insert updated tuple */ - memset(values, 0, sizeof(values)); - memset(nulls, false, sizeof(nulls)); - memset(replace, false, sizeof(replace)); - values[Anum_pg_largeobject_data - 1] = PointerGetDatum(&workbuf); - replace[Anum_pg_largeobject_data - 1] = true; - newtup = heap_modify_tuple(oldtuple, RelationGetDescr(lo_heap_r), - values, nulls, replace); - CatalogTupleUpdateWithInfo(lo_heap_r, &newtup->t_self, newtup, - indstate); + HeapTupleUpdateValue(pg_largeobject, data, PointerGetDatum(&workbuf), values, nulls, updated); + newtup = heap_update_tuple(oldtuple, RelationGetDescr(lo_heap_r), values, nulls, updated); + CatalogTupleUpdate(lo_heap_r, &newtup->t_self, newtup, updated, indstate); heap_freetuple(newtup); + bms_free(updated); /* * We're done with this old page. @@ -713,11 +709,11 @@ inv_write(LargeObjectDesc *obj_desc, const char *buf, int nbytes) */ memset(values, 0, sizeof(values)); memset(nulls, false, sizeof(nulls)); - values[Anum_pg_largeobject_loid - 1] = ObjectIdGetDatum(obj_desc->id); - values[Anum_pg_largeobject_pageno - 1] = Int32GetDatum(pageno); - values[Anum_pg_largeobject_data - 1] = PointerGetDatum(&workbuf); + HeapTupleSetValue(pg_largeobject, loid, ObjectIdGetDatum(obj_desc->id), values); + HeapTupleSetValue(pg_largeobject, pageno, Int32GetDatum(pageno), values); + HeapTupleSetValue(pg_largeobject, data, PointerGetDatum(&workbuf), values); newtup = heap_form_tuple(lo_heap_r->rd_att, values, nulls); - CatalogTupleInsertWithInfo(lo_heap_r, newtup, indstate); + CatalogTupleInsert(lo_heap_r, newtup, indstate); heap_freetuple(newtup); } pageno++; @@ -755,9 +751,9 @@ inv_truncate(LargeObjectDesc *obj_desc, int64 len) } workbuf = {0}; char *workb = VARDATA(&workbuf.hdr); HeapTuple newtup; - Datum values[Natts_pg_largeobject]; - bool nulls[Natts_pg_largeobject]; - bool replace[Natts_pg_largeobject]; + Datum values[Natts_pg_largeobject] = {0}; + bool nulls[Natts_pg_largeobject] = {false}; + Bitmapset *updated = NULL; CatalogIndexState indstate; Assert(obj_desc); @@ -844,14 +840,11 @@ inv_truncate(LargeObjectDesc *obj_desc, int64 len) */ memset(values, 0, sizeof(values)); memset(nulls, false, sizeof(nulls)); - memset(replace, false, sizeof(replace)); - values[Anum_pg_largeobject_data - 1] = PointerGetDatum(&workbuf); - replace[Anum_pg_largeobject_data - 1] = true; - newtup = heap_modify_tuple(oldtuple, RelationGetDescr(lo_heap_r), - values, nulls, replace); - CatalogTupleUpdateWithInfo(lo_heap_r, &newtup->t_self, newtup, - indstate); + HeapTupleUpdateValue(pg_largeobject, data, PointerGetDatum(&workbuf), values, nulls, updated); + newtup = heap_update_tuple(oldtuple, RelationGetDescr(lo_heap_r), values, nulls, updated); + CatalogTupleUpdate(lo_heap_r, &newtup->t_self, newtup, updated, indstate); heap_freetuple(newtup); + bms_free(updated); } else { @@ -883,11 +876,11 @@ inv_truncate(LargeObjectDesc *obj_desc, int64 len) */ memset(values, 0, sizeof(values)); memset(nulls, false, sizeof(nulls)); - values[Anum_pg_largeobject_loid - 1] = ObjectIdGetDatum(obj_desc->id); - values[Anum_pg_largeobject_pageno - 1] = Int32GetDatum(pageno); - values[Anum_pg_largeobject_data - 1] = PointerGetDatum(&workbuf); + HeapTupleSetValue(pg_largeobject, loid, ObjectIdGetDatum(obj_desc->id), values); + HeapTupleSetValue(pg_largeobject, pageno, Int32GetDatum(pageno), values); + HeapTupleSetValue(pg_largeobject, data, PointerGetDatum(&workbuf), values); newtup = heap_form_tuple(lo_heap_r->rd_att, values, nulls); - CatalogTupleInsertWithInfo(lo_heap_r, newtup, indstate); + CatalogTupleInsert(lo_heap_r, newtup, indstate); heap_freetuple(newtup); } diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 915d0bc908423..61d3b760e15e7 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -3780,6 +3780,7 @@ RelationSetNewRelfilenumber(Relation relation, char persistence) MultiXactId minmulti = InvalidMultiXactId; TransactionId freezeXid = InvalidTransactionId; RelFileLocator newrlocator; + Bitmapset *updated = NULL; if (!IsBinaryUpgrade) { @@ -3929,21 +3930,21 @@ RelationSetNewRelfilenumber(Relation relation, char persistence) else { /* Normal case, update the pg_class entry */ - classform->relfilenode = newrelfilenumber; + HeapTupleUpdateField(pg_class, relfilenode, newrelfilenumber, classform, updated); /* relpages etc. never change for sequences */ if (relation->rd_rel->relkind != RELKIND_SEQUENCE) { - classform->relpages = 0; /* it's empty until further notice */ - classform->reltuples = -1; - classform->relallvisible = 0; - classform->relallfrozen = 0; + HeapTupleUpdateField(pg_class, relpages, 0, classform, updated); + HeapTupleUpdateField(pg_class, reltuples, -1, classform, updated); + HeapTupleUpdateField(pg_class, relallvisible, 0, classform, updated); + HeapTupleUpdateField(pg_class, relallfrozen, 0, classform, updated); } - classform->relfrozenxid = freezeXid; - classform->relminmxid = minmulti; - classform->relpersistence = persistence; + HeapTupleUpdateField(pg_class, relfrozenxid, freezeXid, classform, updated); + HeapTupleUpdateField(pg_class, relminmxid, minmulti, classform, updated); + HeapTupleUpdateField(pg_class, relpersistence, persistence, classform, updated); - CatalogTupleUpdate(pg_class, &otid, tuple); + CatalogTupleUpdate(pg_class, &otid, tuple, updated, NULL); } UnlockTuple(pg_class, &otid, InplaceUpdateTupleLock); @@ -3958,6 +3959,7 @@ RelationSetNewRelfilenumber(Relation relation, char persistence) CommandCounterIncrement(); RelationAssumeNewRelfilelocator(relation); + bms_free(updated); } /*