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..86bb55375da28 --- /dev/null +++ b/.gdbinit @@ -0,0 +1,15 @@ +set tui tab-width 4 +set tui mouse-events off + + +#b tts_heap_check_idx_attrs +#b ExecCheckTupleForChanges +#b ExecOpenIndicies +#b ExecInsertIndexTuples +#b simple_heap_update + +#b fork_process +#b ParallelWorkerMain +#set follow-fork-mode child +#b initdb.c:3105 + 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..d0b5ed16eb0e0 --- /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=0 \ + -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/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/access/heap/heapam.c b/src/backend/access/heap/heapam.c index 4d382a04338e6..e2ec62f528ded 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -39,18 +39,24 @@ #include "access/syncscan.h" #include "access/valid.h" #include "access/visibilitymap.h" +#include "access/xact.h" #include "access/xloginsert.h" +#include "catalog/catalog.h" #include "catalog/pg_database.h" #include "catalog/pg_database_d.h" #include "commands/vacuum.h" +#include "nodes/bitmapset.h" #include "pgstat.h" #include "port/pg_bitutils.h" +#include "storage/bufmgr.h" +#include "storage/itemptr.h" #include "storage/lmgr.h" #include "storage/predicate.h" #include "storage/procarray.h" #include "utils/datum.h" #include "utils/injection_point.h" #include "utils/inval.h" +#include "utils/relcache.h" #include "utils/spccache.h" #include "utils/syscache.h" @@ -62,16 +68,8 @@ static XLogRecPtr log_heap_update(Relation reln, Buffer oldbuf, HeapTuple newtup, HeapTuple old_key_tuple, bool all_visible_cleared, bool new_all_visible_cleared); #ifdef USE_ASSERT_CHECKING -static void check_lock_if_inplace_updateable_rel(Relation relation, - const ItemPointerData *otid, - HeapTuple newtup); static void check_inplace_rel_lock(HeapTuple oldtup); #endif -static Bitmapset *HeapDetermineColumnsInfo(Relation relation, - Bitmapset *interesting_cols, - Bitmapset *external_cols, - HeapTuple oldtup, HeapTuple newtup, - bool *has_external); static bool heap_acquire_tuplock(Relation relation, const ItemPointerData *tid, LockTupleMode mode, LockWaitPolicy wait_policy, bool *have_tuple_lock); @@ -103,10 +101,10 @@ static bool ConditionalMultiXactIdWait(MultiXactId multi, MultiXactStatus status static void index_delete_sort(TM_IndexDeleteOp *delstate); static int bottomup_sort_and_shrink(TM_IndexDeleteOp *delstate); static XLogRecPtr log_heap_new_cid(Relation relation, HeapTuple tup); -static HeapTuple ExtractReplicaIdentity(Relation relation, HeapTuple tp, bool key_required, +static HeapTuple ExtractReplicaIdentity(Relation relation, HeapTuple tp, + Bitmapset *rid_attrs, bool key_required, bool *copy); - /* * Each tuple lock mode has a corresponding heavyweight lock, and one or two * corresponding MultiXactStatuses (one to merely lock tuples, another one to @@ -2814,6 +2812,7 @@ heap_delete(Relation relation, const ItemPointerData *tid, Buffer buffer; Buffer vmbuffer = InvalidBuffer; TransactionId new_xmax; + Bitmapset *rid_attrs; uint16 new_infomask, new_infomask2; bool have_tuple_lock = false; @@ -2826,6 +2825,8 @@ heap_delete(Relation relation, const ItemPointerData *tid, AssertHasSnapshotForToast(relation); + rid_attrs = RelationGetIndexAttrBitmap(relation, INDEX_ATTR_BITMAP_IDENTITY_KEY); + /* * Forbid this during a parallel operation, lest it allocate a combo CID. * Other workers might need that combo CID for visibility checks, and we @@ -3029,6 +3030,7 @@ heap_delete(Relation relation, const ItemPointerData *tid, UnlockTupleTuplock(relation, &(tp.t_self), LockTupleExclusive); if (vmbuffer != InvalidBuffer) ReleaseBuffer(vmbuffer); + bms_free(rid_attrs); return result; } @@ -3050,7 +3052,10 @@ heap_delete(Relation relation, const ItemPointerData *tid, * Compute replica identity tuple before entering the critical section so * we don't PANIC upon a memory allocation failure. */ - old_key_tuple = ExtractReplicaIdentity(relation, &tp, true, &old_key_copied); + old_key_tuple = ExtractReplicaIdentity(relation, &tp, rid_attrs, + true, &old_key_copied); + bms_free(rid_attrs); + rid_attrs = NULL; /* * If this is the first possibly-multixact-able operation in the current @@ -3262,7 +3267,10 @@ simple_heap_delete(Relation relation, const ItemPointerData *tid) * heap_update - replace a tuple * * See table_tuple_update() for an explanation of the parameters, except that - * this routine directly takes a tuple rather than a slot. + * this routine directly takes a heap tuple rather than a slot. + * + * It's required that the caller has acquired the pin and lock on the buffer. + * That lock and pin will be managed here, not in the caller. * * In the failure cases, the routine fills *tmfd with the tuple's t_ctid, * t_xmax (resolving a possible MultiXact, if necessary), and t_cmax (the last @@ -3270,30 +3278,21 @@ simple_heap_delete(Relation relation, const ItemPointerData *tid) * generated by another transaction). */ TM_Result -heap_update(Relation relation, const ItemPointerData *otid, HeapTuple newtup, - CommandId cid, Snapshot crosscheck, bool wait, - TM_FailureData *tmfd, LockTupleMode *lockmode, - TU_UpdateIndexes *update_indexes) +heap_update(Relation relation, HeapTupleData *oldtup, + HeapTuple newtup, CommandId cid, Snapshot crosscheck, bool wait, + TM_FailureData *tmfd, LockTupleMode *lockmode, Buffer buffer, + Page page, BlockNumber block, ItemId lp, Bitmapset *hot_attrs, + Bitmapset *sum_attrs, Bitmapset *pk_attrs, Bitmapset *rid_attrs, + Bitmapset *mix_attrs, Buffer *vmbuffer, + bool rep_id_key_required, TU_UpdateIndexes *update_indexes) { TM_Result result; TransactionId xid = GetCurrentTransactionId(); - Bitmapset *hot_attrs; - Bitmapset *sum_attrs; - Bitmapset *key_attrs; - Bitmapset *id_attrs; - Bitmapset *interesting_attrs; - Bitmapset *modified_attrs; - ItemId lp; - HeapTupleData oldtup; HeapTuple heaptup; HeapTuple old_key_tuple = NULL; bool old_key_copied = false; - Page page; - BlockNumber block; MultiXactStatus mxact_status; - Buffer buffer, - newbuf, - vmbuffer = InvalidBuffer, + Buffer newbuf, vmbuffer_new = InvalidBuffer; bool need_toast; Size newtupsize, @@ -3307,7 +3306,6 @@ heap_update(Relation relation, const ItemPointerData *otid, HeapTuple newtup, bool all_visible_cleared_new = false; bool checked_lockers; bool locker_remains; - bool id_has_external = false; TransactionId xmax_new_tuple, xmax_old_tuple; uint16 infomask_old_tuple, @@ -3315,144 +3313,13 @@ heap_update(Relation relation, const ItemPointerData *otid, HeapTuple newtup, infomask_new_tuple, infomask2_new_tuple; - Assert(ItemPointerIsValid(otid)); - - /* Cheap, simplistic check that the tuple matches the rel's rowtype. */ - Assert(HeapTupleHeaderGetNatts(newtup->t_data) <= - RelationGetNumberOfAttributes(relation)); - + Assert(BufferIsLockedByMe(buffer)); + Assert(ItemIdIsNormal(lp)); AssertHasSnapshotForToast(relation); - /* - * Forbid this during a parallel operation, lest it allocate a combo CID. - * Other workers might need that combo CID for visibility checks, and we - * have no provision for broadcasting it to them. - */ - if (IsInParallelMode()) - ereport(ERROR, - (errcode(ERRCODE_INVALID_TRANSACTION_STATE), - errmsg("cannot update tuples during a parallel operation"))); - -#ifdef USE_ASSERT_CHECKING - check_lock_if_inplace_updateable_rel(relation, otid, newtup); -#endif - - /* - * Fetch the list of attributes to be checked for various operations. - * - * For HOT considerations, this is wasted effort if we fail to update or - * have to put the new tuple on a different page. But we must compute the - * list before obtaining buffer lock --- in the worst case, if we are - * doing an update on one of the relevant system catalogs, we could - * deadlock if we try to fetch the list later. In any case, the relcache - * caches the data so this is usually pretty cheap. - * - * We also need columns used by the replica identity and columns that are - * considered the "key" of rows in the table. - * - * Note that we get copies of each bitmap, so we need not worry about - * relcache flush happening midway through. - */ - hot_attrs = RelationGetIndexAttrBitmap(relation, - INDEX_ATTR_BITMAP_HOT_BLOCKING); - sum_attrs = RelationGetIndexAttrBitmap(relation, - INDEX_ATTR_BITMAP_SUMMARIZED); - key_attrs = RelationGetIndexAttrBitmap(relation, INDEX_ATTR_BITMAP_KEY); - id_attrs = RelationGetIndexAttrBitmap(relation, - INDEX_ATTR_BITMAP_IDENTITY_KEY); - interesting_attrs = NULL; - interesting_attrs = bms_add_members(interesting_attrs, hot_attrs); - interesting_attrs = bms_add_members(interesting_attrs, sum_attrs); - interesting_attrs = bms_add_members(interesting_attrs, key_attrs); - interesting_attrs = bms_add_members(interesting_attrs, id_attrs); - - block = ItemPointerGetBlockNumber(otid); - INJECTION_POINT("heap_update-before-pin", NULL); - buffer = ReadBuffer(relation, block); - page = BufferGetPage(buffer); - - /* - * Before locking the buffer, pin the visibility map page if it appears to - * be necessary. Since we haven't got the lock yet, someone else might be - * in the middle of changing this, so we'll need to recheck after we have - * the lock. - */ - if (PageIsAllVisible(page)) - visibilitymap_pin(relation, block, &vmbuffer); - - LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE); - - lp = PageGetItemId(page, ItemPointerGetOffsetNumber(otid)); - - /* - * Usually, a buffer pin and/or snapshot blocks pruning of otid, ensuring - * we see LP_NORMAL here. When the otid origin is a syscache, we may have - * neither a pin nor a snapshot. Hence, we may see other LP_ states, each - * of which indicates concurrent pruning. - * - * Failing with TM_Updated would be most accurate. However, unlike other - * TM_Updated scenarios, we don't know the successor ctid in LP_UNUSED and - * LP_DEAD cases. While the distinction between TM_Updated and TM_Deleted - * does matter to SQL statements UPDATE and MERGE, those SQL statements - * hold a snapshot that ensures LP_NORMAL. Hence, the choice between - * TM_Updated and TM_Deleted affects only the wording of error messages. - * Settle on TM_Deleted, for two reasons. First, it avoids complicating - * the specification of when tmfd->ctid is valid. Second, it creates - * error log evidence that we took this branch. - * - * Since it's possible to see LP_UNUSED at otid, it's also possible to see - * LP_NORMAL for a tuple that replaced LP_UNUSED. If it's a tuple for an - * unrelated row, we'll fail with "duplicate key value violates unique". - * XXX if otid is the live, newer version of the newtup row, we'll discard - * changes originating in versions of this catalog row after the version - * the caller got from syscache. See syscache-update-pruned.spec. - */ - if (!ItemIdIsNormal(lp)) - { - Assert(RelationSupportsSysCache(RelationGetRelid(relation))); - - UnlockReleaseBuffer(buffer); - Assert(!have_tuple_lock); - if (vmbuffer != InvalidBuffer) - ReleaseBuffer(vmbuffer); - tmfd->ctid = *otid; - tmfd->xmax = InvalidTransactionId; - tmfd->cmax = InvalidCommandId; - *update_indexes = TU_None; - - bms_free(hot_attrs); - bms_free(sum_attrs); - bms_free(key_attrs); - bms_free(id_attrs); - /* modified_attrs not yet initialized */ - bms_free(interesting_attrs); - return TM_Deleted; - } - - /* - * Fill in enough data in oldtup for HeapDetermineColumnsInfo to work - * properly. - */ - oldtup.t_tableOid = RelationGetRelid(relation); - oldtup.t_data = (HeapTupleHeader) PageGetItem(page, lp); - oldtup.t_len = ItemIdGetLength(lp); - oldtup.t_self = *otid; - - /* the new tuple is ready, except for this: */ + /* The new tuple is ready, except for this */ newtup->t_tableOid = RelationGetRelid(relation); - /* - * Determine columns modified by the update. Additionally, identify - * whether any of the unmodified replica identity key attributes in the - * old tuple is externally stored or not. This is required because for - * such attributes the flattened value won't be WAL logged as part of the - * new tuple so we must include it as part of the old_key_tuple. See - * ExtractReplicaIdentity. - */ - modified_attrs = HeapDetermineColumnsInfo(relation, interesting_attrs, - id_attrs, &oldtup, - newtup, &id_has_external); - /* * If we're not updating any "key" column, we can grab a weaker lock type. * This allows for more concurrency when we are running simultaneously @@ -3464,7 +3331,7 @@ heap_update(Relation relation, const ItemPointerData *otid, HeapTuple newtup, * is updates that don't manipulate key columns, not those that * serendipitously arrive at the same key values. */ - if (!bms_overlap(modified_attrs, key_attrs)) + if (!bms_overlap(mix_attrs, pk_attrs)) { *lockmode = LockTupleNoKeyExclusive; mxact_status = MultiXactStatusNoKeyUpdate; @@ -3488,17 +3355,10 @@ heap_update(Relation relation, const ItemPointerData *otid, HeapTuple newtup, key_intact = false; } - /* - * Note: beyond this point, use oldtup not otid to refer to old tuple. - * otid may very well point at newtup->t_self, which we will overwrite - * with the new tuple's location, so there's great risk of confusion if we - * use otid anymore. - */ - l2: checked_lockers = false; locker_remains = false; - result = HeapTupleSatisfiesUpdate(&oldtup, cid, buffer); + result = HeapTupleSatisfiesUpdate(oldtup, cid, buffer); /* see below about the "no wait" case */ Assert(result != TM_BeingModified || wait); @@ -3530,8 +3390,8 @@ heap_update(Relation relation, const ItemPointerData *otid, HeapTuple newtup, */ /* must copy state data before unlocking buffer */ - xwait = HeapTupleHeaderGetRawXmax(oldtup.t_data); - infomask = oldtup.t_data->t_infomask; + xwait = HeapTupleHeaderGetRawXmax(oldtup->t_data); + infomask = oldtup->t_data->t_infomask; /* * Now we have to do something about the existing locker. If it's a @@ -3571,13 +3431,12 @@ heap_update(Relation relation, const ItemPointerData *otid, HeapTuple newtup, * requesting a lock and already have one; avoids deadlock). */ if (!current_is_member) - heap_acquire_tuplock(relation, &(oldtup.t_self), *lockmode, + heap_acquire_tuplock(relation, &oldtup->t_self, *lockmode, LockWaitBlock, &have_tuple_lock); /* wait for multixact */ MultiXactIdWait((MultiXactId) xwait, mxact_status, infomask, - relation, &oldtup.t_self, XLTW_Update, - &remain); + relation, &oldtup->t_self, XLTW_Update, &remain); checked_lockers = true; locker_remains = remain != 0; LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE); @@ -3587,9 +3446,9 @@ heap_update(Relation relation, const ItemPointerData *otid, HeapTuple newtup, * could update this tuple before we get to this point. Check * for xmax change, and start over if so. */ - if (xmax_infomask_changed(oldtup.t_data->t_infomask, + if (xmax_infomask_changed(oldtup->t_data->t_infomask, infomask) || - !TransactionIdEquals(HeapTupleHeaderGetRawXmax(oldtup.t_data), + !TransactionIdEquals(HeapTupleHeaderGetRawXmax(oldtup->t_data), xwait)) goto l2; } @@ -3614,8 +3473,8 @@ heap_update(Relation relation, const ItemPointerData *otid, HeapTuple newtup, * before this one, which are important to keep in case this * subxact aborts. */ - if (!HEAP_XMAX_IS_LOCKED_ONLY(oldtup.t_data->t_infomask)) - update_xact = HeapTupleGetUpdateXid(oldtup.t_data); + if (!HEAP_XMAX_IS_LOCKED_ONLY(oldtup->t_data->t_infomask)) + update_xact = HeapTupleGetUpdateXid(oldtup->t_data); else update_xact = InvalidTransactionId; @@ -3656,9 +3515,9 @@ heap_update(Relation relation, const ItemPointerData *otid, HeapTuple newtup, * lock. */ LockBuffer(buffer, BUFFER_LOCK_UNLOCK); - heap_acquire_tuplock(relation, &(oldtup.t_self), *lockmode, + heap_acquire_tuplock(relation, &oldtup->t_self, *lockmode, LockWaitBlock, &have_tuple_lock); - XactLockTableWait(xwait, relation, &oldtup.t_self, + XactLockTableWait(xwait, relation, &oldtup->t_self, XLTW_Update); checked_lockers = true; LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE); @@ -3668,20 +3527,20 @@ heap_update(Relation relation, const ItemPointerData *otid, HeapTuple newtup, * other xact could update this tuple before we get to this point. * Check for xmax change, and start over if so. */ - if (xmax_infomask_changed(oldtup.t_data->t_infomask, infomask) || + if (xmax_infomask_changed(oldtup->t_data->t_infomask, infomask) || !TransactionIdEquals(xwait, - HeapTupleHeaderGetRawXmax(oldtup.t_data))) + HeapTupleHeaderGetRawXmax(oldtup->t_data))) goto l2; /* Otherwise check if it committed or aborted */ - UpdateXmaxHintBits(oldtup.t_data, buffer, xwait); - if (oldtup.t_data->t_infomask & HEAP_XMAX_INVALID) + UpdateXmaxHintBits(oldtup->t_data, buffer, xwait); + if (oldtup->t_data->t_infomask & HEAP_XMAX_INVALID) can_continue = true; } if (can_continue) result = TM_Ok; - else if (!ItemPointerEquals(&oldtup.t_self, &oldtup.t_data->t_ctid)) + else if (!ItemPointerEquals(&oldtup->t_self, &oldtup->t_data->t_ctid)) result = TM_Updated; else result = TM_Deleted; @@ -3694,39 +3553,33 @@ heap_update(Relation relation, const ItemPointerData *otid, HeapTuple newtup, result == TM_Updated || result == TM_Deleted || result == TM_BeingModified); - Assert(!(oldtup.t_data->t_infomask & HEAP_XMAX_INVALID)); + Assert(!(oldtup->t_data->t_infomask & HEAP_XMAX_INVALID)); Assert(result != TM_Updated || - !ItemPointerEquals(&oldtup.t_self, &oldtup.t_data->t_ctid)); + !ItemPointerEquals(&oldtup->t_self, &oldtup->t_data->t_ctid)); } if (crosscheck != InvalidSnapshot && result == TM_Ok) { /* Perform additional check for transaction-snapshot mode RI updates */ - if (!HeapTupleSatisfiesVisibility(&oldtup, crosscheck, buffer)) + if (!HeapTupleSatisfiesVisibility(oldtup, crosscheck, buffer)) result = TM_Updated; } if (result != TM_Ok) { - tmfd->ctid = oldtup.t_data->t_ctid; - tmfd->xmax = HeapTupleHeaderGetUpdateXid(oldtup.t_data); + tmfd->ctid = oldtup->t_data->t_ctid; + tmfd->xmax = HeapTupleHeaderGetUpdateXid(oldtup->t_data); if (result == TM_SelfModified) - tmfd->cmax = HeapTupleHeaderGetCmax(oldtup.t_data); + tmfd->cmax = HeapTupleHeaderGetCmax(oldtup->t_data); else tmfd->cmax = InvalidCommandId; UnlockReleaseBuffer(buffer); if (have_tuple_lock) - UnlockTupleTuplock(relation, &(oldtup.t_self), *lockmode); - if (vmbuffer != InvalidBuffer) - ReleaseBuffer(vmbuffer); + UnlockTupleTuplock(relation, &oldtup->t_self, *lockmode); + if (*vmbuffer != InvalidBuffer) + ReleaseBuffer(*vmbuffer); *update_indexes = TU_None; - bms_free(hot_attrs); - bms_free(sum_attrs); - bms_free(key_attrs); - bms_free(id_attrs); - bms_free(modified_attrs); - bms_free(interesting_attrs); return result; } @@ -3739,10 +3592,10 @@ heap_update(Relation relation, const ItemPointerData *otid, HeapTuple newtup, * tuple has been locked or updated under us, but hopefully it won't * happen very often. */ - if (vmbuffer == InvalidBuffer && PageIsAllVisible(page)) + if (*vmbuffer == InvalidBuffer && PageIsAllVisible(page)) { LockBuffer(buffer, BUFFER_LOCK_UNLOCK); - visibilitymap_pin(relation, block, &vmbuffer); + visibilitymap_pin(relation, block, vmbuffer); LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE); goto l2; } @@ -3753,9 +3606,9 @@ heap_update(Relation relation, const ItemPointerData *otid, HeapTuple newtup, * If the tuple we're updating is locked, we need to preserve the locking * info in the old tuple's Xmax. Prepare a new Xmax value for this. */ - compute_new_xmax_infomask(HeapTupleHeaderGetRawXmax(oldtup.t_data), - oldtup.t_data->t_infomask, - oldtup.t_data->t_infomask2, + compute_new_xmax_infomask(HeapTupleHeaderGetRawXmax(oldtup->t_data), + oldtup->t_data->t_infomask, + oldtup->t_data->t_infomask2, xid, *lockmode, true, &xmax_old_tuple, &infomask_old_tuple, &infomask2_old_tuple); @@ -3767,12 +3620,12 @@ heap_update(Relation relation, const ItemPointerData *otid, HeapTuple newtup, * tuple. (In rare cases that might also be InvalidTransactionId and yet * not have the HEAP_XMAX_INVALID bit set; that's fine.) */ - if ((oldtup.t_data->t_infomask & HEAP_XMAX_INVALID) || - HEAP_LOCKED_UPGRADED(oldtup.t_data->t_infomask) || + if ((oldtup->t_data->t_infomask & HEAP_XMAX_INVALID) || + HEAP_LOCKED_UPGRADED(oldtup->t_data->t_infomask) || (checked_lockers && !locker_remains)) xmax_new_tuple = InvalidTransactionId; else - xmax_new_tuple = HeapTupleHeaderGetRawXmax(oldtup.t_data); + xmax_new_tuple = HeapTupleHeaderGetRawXmax(oldtup->t_data); if (!TransactionIdIsValid(xmax_new_tuple)) { @@ -3787,7 +3640,7 @@ heap_update(Relation relation, const ItemPointerData *otid, HeapTuple newtup, * Note that since we're doing an update, the only possibility is that * the lockers had FOR KEY SHARE lock. */ - if (oldtup.t_data->t_infomask & HEAP_XMAX_IS_MULTI) + if (oldtup->t_data->t_infomask & HEAP_XMAX_IS_MULTI) { GetMultiXactIdHintBits(xmax_new_tuple, &infomask_new_tuple, &infomask2_new_tuple); @@ -3815,7 +3668,7 @@ heap_update(Relation relation, const ItemPointerData *otid, HeapTuple newtup, * Replace cid with a combo CID if necessary. Note that we already put * the plain cid into the new tuple. */ - HeapTupleHeaderAdjustCmax(oldtup.t_data, &cid, &iscombo); + HeapTupleHeaderAdjustCmax(oldtup->t_data, &cid, &iscombo); /* * If the toaster needs to be activated, OR if the new tuple will not fit @@ -3832,12 +3685,12 @@ heap_update(Relation relation, const ItemPointerData *otid, HeapTuple newtup, relation->rd_rel->relkind != RELKIND_MATVIEW) { /* toast table entries should never be recursively toasted */ - Assert(!HeapTupleHasExternal(&oldtup)); + Assert(!HeapTupleHasExternal(oldtup)); Assert(!HeapTupleHasExternal(newtup)); need_toast = false; } else - need_toast = (HeapTupleHasExternal(&oldtup) || + need_toast = (HeapTupleHasExternal(oldtup) || HeapTupleHasExternal(newtup) || newtup->t_len > TOAST_TUPLE_THRESHOLD); @@ -3870,9 +3723,9 @@ heap_update(Relation relation, const ItemPointerData *otid, HeapTuple newtup, * updating, because the potentially created multixact would otherwise * be wrong. */ - compute_new_xmax_infomask(HeapTupleHeaderGetRawXmax(oldtup.t_data), - oldtup.t_data->t_infomask, - oldtup.t_data->t_infomask2, + compute_new_xmax_infomask(HeapTupleHeaderGetRawXmax(oldtup->t_data), + oldtup->t_data->t_infomask, + oldtup->t_data->t_infomask2, xid, *lockmode, false, &xmax_lock_old_tuple, &infomask_lock_old_tuple, &infomask2_lock_old_tuple); @@ -3882,18 +3735,18 @@ heap_update(Relation relation, const ItemPointerData *otid, HeapTuple newtup, START_CRIT_SECTION(); /* Clear obsolete visibility flags ... */ - oldtup.t_data->t_infomask &= ~(HEAP_XMAX_BITS | HEAP_MOVED); - oldtup.t_data->t_infomask2 &= ~HEAP_KEYS_UPDATED; - HeapTupleClearHotUpdated(&oldtup); + oldtup->t_data->t_infomask &= ~(HEAP_XMAX_BITS | HEAP_MOVED); + oldtup->t_data->t_infomask2 &= ~HEAP_KEYS_UPDATED; + HeapTupleClearHotUpdated(oldtup); /* ... and store info about transaction updating this tuple */ Assert(TransactionIdIsValid(xmax_lock_old_tuple)); - HeapTupleHeaderSetXmax(oldtup.t_data, xmax_lock_old_tuple); - oldtup.t_data->t_infomask |= infomask_lock_old_tuple; - oldtup.t_data->t_infomask2 |= infomask2_lock_old_tuple; - HeapTupleHeaderSetCmax(oldtup.t_data, cid, iscombo); + HeapTupleHeaderSetXmax(oldtup->t_data, xmax_lock_old_tuple); + oldtup->t_data->t_infomask |= infomask_lock_old_tuple; + oldtup->t_data->t_infomask2 |= infomask2_lock_old_tuple; + HeapTupleHeaderSetCmax(oldtup->t_data, cid, iscombo); /* temporarily make it look not-updated, but locked */ - oldtup.t_data->t_ctid = oldtup.t_self; + oldtup->t_data->t_ctid = oldtup->t_self; /* * Clear all-frozen bit on visibility map if needed. We could @@ -3902,7 +3755,7 @@ heap_update(Relation relation, const ItemPointerData *otid, HeapTuple newtup, * worthwhile. */ if (PageIsAllVisible(page) && - visibilitymap_clear(relation, block, vmbuffer, + visibilitymap_clear(relation, block, *vmbuffer, VISIBILITYMAP_ALL_FROZEN)) cleared_all_frozen = true; @@ -3916,10 +3769,10 @@ heap_update(Relation relation, const ItemPointerData *otid, HeapTuple newtup, XLogBeginInsert(); XLogRegisterBuffer(0, buffer, REGBUF_STANDARD); - xlrec.offnum = ItemPointerGetOffsetNumber(&oldtup.t_self); + xlrec.offnum = ItemPointerGetOffsetNumber(&oldtup->t_self); xlrec.xmax = xmax_lock_old_tuple; - xlrec.infobits_set = compute_infobits(oldtup.t_data->t_infomask, - oldtup.t_data->t_infomask2); + xlrec.infobits_set = compute_infobits(oldtup->t_data->t_infomask, + oldtup->t_data->t_infomask2); xlrec.flags = cleared_all_frozen ? XLH_LOCK_ALL_FROZEN_CLEARED : 0; XLogRegisterData(&xlrec, SizeOfHeapLock); @@ -3941,7 +3794,7 @@ heap_update(Relation relation, const ItemPointerData *otid, HeapTuple newtup, if (need_toast) { /* Note we always use WAL and FSM during updates */ - heaptup = heap_toast_insert_or_update(relation, newtup, &oldtup, 0); + heaptup = heap_toast_insert_or_update(relation, newtup, oldtup, 0); newtupsize = MAXALIGN(heaptup->t_len); } else @@ -3977,20 +3830,20 @@ heap_update(Relation relation, const ItemPointerData *otid, HeapTuple newtup, /* It doesn't fit, must use RelationGetBufferForTuple. */ newbuf = RelationGetBufferForTuple(relation, heaptup->t_len, buffer, 0, NULL, - &vmbuffer_new, &vmbuffer, + &vmbuffer_new, vmbuffer, 0); /* We're all done. */ break; } /* Acquire VM page pin if needed and we don't have it. */ - if (vmbuffer == InvalidBuffer && PageIsAllVisible(page)) - visibilitymap_pin(relation, block, &vmbuffer); + if (*vmbuffer == InvalidBuffer && PageIsAllVisible(page)) + visibilitymap_pin(relation, block, vmbuffer); /* Re-acquire the lock on the old tuple's page. */ LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE); /* Re-check using the up-to-date free space */ pagefree = PageGetHeapFreeSpace(page); if (newtupsize > pagefree || - (vmbuffer == InvalidBuffer && PageIsAllVisible(page))) + (*vmbuffer == InvalidBuffer && PageIsAllVisible(page))) { /* * Rats, it doesn't fit anymore, or somebody just now set the @@ -4028,7 +3881,7 @@ heap_update(Relation relation, const ItemPointerData *otid, HeapTuple newtup, * will include checking the relation level, there is no benefit to a * separate check for the new tuple. */ - CheckForSerializableConflictIn(relation, &oldtup.t_self, + CheckForSerializableConflictIn(relation, &oldtup->t_self, BufferGetBlockNumber(buffer)); /* @@ -4036,7 +3889,6 @@ heap_update(Relation relation, const ItemPointerData *otid, HeapTuple newtup, * has enough space for the new tuple. If they are the same buffer, only * one pin is held. */ - if (newbuf == buffer) { /* @@ -4044,7 +3896,7 @@ heap_update(Relation relation, const ItemPointerData *otid, HeapTuple newtup, * to do a HOT update. Check if any of the index columns have been * changed. */ - if (!bms_overlap(modified_attrs, hot_attrs)) + if (!bms_overlap(mix_attrs, hot_attrs)) { use_hot_update = true; @@ -4055,7 +3907,7 @@ heap_update(Relation relation, const ItemPointerData *otid, HeapTuple newtup, * indexes if the columns were updated, or we may fail to detect * e.g. value bound changes in BRIN minmax indexes. */ - if (bms_overlap(modified_attrs, sum_attrs)) + if (bms_overlap(mix_attrs, sum_attrs)) summarized_update = true; } } @@ -4072,10 +3924,8 @@ heap_update(Relation relation, const ItemPointerData *otid, HeapTuple newtup, * logged. Pass old key required as true only if the replica identity key * columns are modified or it has external data. */ - old_key_tuple = ExtractReplicaIdentity(relation, &oldtup, - bms_overlap(modified_attrs, id_attrs) || - id_has_external, - &old_key_copied); + old_key_tuple = ExtractReplicaIdentity(relation, oldtup, rid_attrs, + rep_id_key_required, &old_key_copied); /* NO EREPORT(ERROR) from here till changes are logged */ START_CRIT_SECTION(); @@ -4097,7 +3947,7 @@ heap_update(Relation relation, const ItemPointerData *otid, HeapTuple newtup, if (use_hot_update) { /* Mark the old tuple as HOT-updated */ - HeapTupleSetHotUpdated(&oldtup); + HeapTupleSetHotUpdated(oldtup); /* And mark the new tuple as heap-only */ HeapTupleSetHeapOnly(heaptup); /* Mark the caller's copy too, in case different from heaptup */ @@ -4106,7 +3956,7 @@ heap_update(Relation relation, const ItemPointerData *otid, HeapTuple newtup, else { /* Make sure tuples are correctly marked as not-HOT */ - HeapTupleClearHotUpdated(&oldtup); + HeapTupleClearHotUpdated(oldtup); HeapTupleClearHeapOnly(heaptup); HeapTupleClearHeapOnly(newtup); } @@ -4115,17 +3965,17 @@ heap_update(Relation relation, const ItemPointerData *otid, HeapTuple newtup, /* Clear obsolete visibility flags, possibly set by ourselves above... */ - oldtup.t_data->t_infomask &= ~(HEAP_XMAX_BITS | HEAP_MOVED); - oldtup.t_data->t_infomask2 &= ~HEAP_KEYS_UPDATED; + oldtup->t_data->t_infomask &= ~(HEAP_XMAX_BITS | HEAP_MOVED); + oldtup->t_data->t_infomask2 &= ~HEAP_KEYS_UPDATED; /* ... and store info about transaction updating this tuple */ Assert(TransactionIdIsValid(xmax_old_tuple)); - HeapTupleHeaderSetXmax(oldtup.t_data, xmax_old_tuple); - oldtup.t_data->t_infomask |= infomask_old_tuple; - oldtup.t_data->t_infomask2 |= infomask2_old_tuple; - HeapTupleHeaderSetCmax(oldtup.t_data, cid, iscombo); + HeapTupleHeaderSetXmax(oldtup->t_data, xmax_old_tuple); + oldtup->t_data->t_infomask |= infomask_old_tuple; + oldtup->t_data->t_infomask2 |= infomask2_old_tuple; + HeapTupleHeaderSetCmax(oldtup->t_data, cid, iscombo); /* record address of new tuple in t_ctid of old one */ - oldtup.t_data->t_ctid = heaptup->t_self; + oldtup->t_data->t_ctid = heaptup->t_self; /* clear PD_ALL_VISIBLE flags, reset all visibilitymap bits */ if (PageIsAllVisible(BufferGetPage(buffer))) @@ -4133,7 +3983,7 @@ heap_update(Relation relation, const ItemPointerData *otid, HeapTuple newtup, all_visible_cleared = true; PageClearAllVisible(BufferGetPage(buffer)); visibilitymap_clear(relation, BufferGetBlockNumber(buffer), - vmbuffer, VISIBILITYMAP_VALID_BITS); + *vmbuffer, VISIBILITYMAP_VALID_BITS); } if (newbuf != buffer && PageIsAllVisible(BufferGetPage(newbuf))) { @@ -4158,12 +4008,12 @@ heap_update(Relation relation, const ItemPointerData *otid, HeapTuple newtup, */ if (RelationIsAccessibleInLogicalDecoding(relation)) { - log_heap_new_cid(relation, &oldtup); + log_heap_new_cid(relation, oldtup); log_heap_new_cid(relation, heaptup); } recptr = log_heap_update(relation, buffer, - newbuf, &oldtup, heaptup, + newbuf, oldtup, heaptup, old_key_tuple, all_visible_cleared, all_visible_cleared_new); @@ -4188,7 +4038,7 @@ heap_update(Relation relation, const ItemPointerData *otid, HeapTuple newtup, * both tuple versions in one call to inval.c so we can avoid redundant * sinval messages.) */ - CacheInvalidateHeapTuple(relation, &oldtup, heaptup); + CacheInvalidateHeapTuple(relation, oldtup, heaptup); /* Now we can release the buffer(s) */ if (newbuf != buffer) @@ -4196,14 +4046,14 @@ heap_update(Relation relation, const ItemPointerData *otid, HeapTuple newtup, ReleaseBuffer(buffer); if (BufferIsValid(vmbuffer_new)) ReleaseBuffer(vmbuffer_new); - if (BufferIsValid(vmbuffer)) - ReleaseBuffer(vmbuffer); + if (BufferIsValid(*vmbuffer)) + ReleaseBuffer(*vmbuffer); /* * Release the lmgr tuple lock, if we had it. */ if (have_tuple_lock) - UnlockTupleTuplock(relation, &(oldtup.t_self), *lockmode); + UnlockTupleTuplock(relation, &oldtup->t_self, *lockmode); pgstat_count_heap_update(relation, use_hot_update, newbuf != buffer); @@ -4236,13 +4086,6 @@ heap_update(Relation relation, const ItemPointerData *otid, HeapTuple newtup, if (old_key_tuple != NULL && old_key_copied) heap_freetuple(old_key_tuple); - bms_free(hot_attrs); - bms_free(sum_attrs); - bms_free(key_attrs); - bms_free(id_attrs); - bms_free(modified_attrs); - bms_free(interesting_attrs); - return TM_Ok; } @@ -4251,7 +4094,7 @@ heap_update(Relation relation, const ItemPointerData *otid, HeapTuple newtup, * Confirm adequate lock held during heap_update(), per rules from * README.tuplock section "Locking to write inplace-updated tables". */ -static void +void check_lock_if_inplace_updateable_rel(Relation relation, const ItemPointerData *otid, HeapTuple newtup) @@ -4423,7 +4266,7 @@ heap_attr_equals(TupleDesc tupdesc, int attrnum, Datum value1, Datum value2, * listed as interesting) of the old tuple is a member of external_cols and is * stored externally. */ -static Bitmapset * +Bitmapset * HeapDetermineColumnsInfo(Relation relation, Bitmapset *interesting_cols, Bitmapset *external_cols, @@ -4506,25 +4349,171 @@ HeapDetermineColumnsInfo(Relation relation, } /* - * simple_heap_update - replace a tuple - * - * This routine may be used to update a tuple when concurrent updates of - * the target tuple are not expected (for example, because we have a lock - * on the relation associated with the tuple). Any failure is reported - * via ereport(). + * This routine may be used to update a tuple when concurrent updates of the + * target tuple are not expected (for example, because we have a lock on the + * relation associated with the tuple). Any failure is reported via ereport(). */ void -simple_heap_update(Relation relation, const ItemPointerData *otid, HeapTuple tup, - TU_UpdateIndexes *update_indexes) +simple_heap_update(Relation relation, const ItemPointerData *otid, HeapTuple tuple, + const Bitmapset *updated, TU_UpdateIndexes *update_indexes) { TM_Result result; TM_FailureData tmfd; LockTupleMode lockmode; + Buffer buffer; + Buffer vmbuffer = InvalidBuffer; + Page page; + BlockNumber block; + Bitmapset *hot_attrs, + *sum_attrs, + *pk_attrs, + *rid_attrs, + *mix_attrs, + *idx_attrs; + ItemId lp; + HeapTupleData oldtup; + bool rep_id_key_required = false; + + Assert(ItemPointerIsValid(otid)); + + /* Cheap, simplistic check that the tuple matches the rel's rowtype. */ + Assert(HeapTupleHeaderGetNatts(tuple->t_data) <= + RelationGetNumberOfAttributes(relation)); + + /* + * Forbid this during a parallel operation, lest it allocate a combo CID. + * Other workers might need that combo CID for visibility checks, and we + * have no provision for broadcasting it to them. + */ + if (IsInParallelMode()) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TRANSACTION_STATE), + errmsg("cannot update tuples during a parallel operation"))); + +#ifdef USE_ASSERT_CHECKING + check_lock_if_inplace_updateable_rel(relation, otid, tuple); +#endif + + /* + * Fetch the list of attributes to be checked for various operations. + * + * For HOT considerations, this is wasted effort if we fail to update or + * have to put the new tuple on a different page. But we must compute the + * list before obtaining buffer lock --- in the worst case, if we are + * doing an update on one of the relevant system catalogs, we could + * deadlock if we try to fetch the list later. In any case, the relcache + * caches the data so this is usually pretty cheap. + * + * We also need columns used by the replica identity and columns that are + * considered the "key" of rows in the table. + * + * Note that we get copies of each bitmap, so we need not worry about + * relcache flush happening midway through. + */ + hot_attrs = RelationGetIndexAttrBitmap(relation, + INDEX_ATTR_BITMAP_HOT_BLOCKING); + sum_attrs = RelationGetIndexAttrBitmap(relation, + INDEX_ATTR_BITMAP_SUMMARIZED); + pk_attrs = RelationGetIndexAttrBitmap(relation, INDEX_ATTR_BITMAP_KEY); + rid_attrs = RelationGetIndexAttrBitmap(relation, + INDEX_ATTR_BITMAP_IDENTITY_KEY); + + idx_attrs = bms_copy(hot_attrs); + idx_attrs = bms_add_members(idx_attrs, sum_attrs); + idx_attrs = bms_add_members(idx_attrs, pk_attrs); + idx_attrs = bms_add_members(idx_attrs, rid_attrs); + + block = ItemPointerGetBlockNumber(otid); + INJECTION_POINT("heap_update-before-pin", NULL); + buffer = ReadBuffer(relation, block); + page = BufferGetPage(buffer); + + /* + * Before locking the buffer, pin the visibility map page if it appears to + * be necessary. Since we haven't got the lock yet, someone else might be + * in the middle of changing this, so we'll need to recheck after we have + * the lock. + */ + if (PageIsAllVisible(page)) + visibilitymap_pin(relation, block, &vmbuffer); + + LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE); + + lp = PageGetItemId(page, ItemPointerGetOffsetNumber(otid)); + + /* + * Usually, a buffer pin and/or snapshot blocks pruning of otid, ensuring + * we see LP_NORMAL here. When the otid origin is a syscache, we may have + * neither a pin nor a snapshot. Hence, we may see other LP_ states, each + * of which indicates concurrent pruning. + * + * Failing with TM_Updated would be most accurate. However, unlike other + * TM_Updated scenarios, we don't know the successor ctid in LP_UNUSED and + * LP_DEAD cases. While the distinction between TM_Updated and TM_Deleted + * does matter to SQL statements UPDATE and MERGE, those SQL statements + * hold a snapshot that ensures LP_NORMAL. Hence, the choice between + * TM_Updated and TM_Deleted affects only the wording of error messages. + * Settle on TM_Deleted, for two reasons. First, it avoids complicating + * the specification of when tmfd->ctid is valid. Second, it creates + * error log evidence that we took this branch. + * + * Since it's possible to see LP_UNUSED at otid, it's also possible to see + * LP_NORMAL for a tuple that replaced LP_UNUSED. If it's a tuple for an + * unrelated row, we'll fail with "duplicate key value violates unique". + * XXX if otid is the live, newer version of the newtup row, we'll discard + * changes originating in versions of this catalog row after the version + * the caller got from syscache. See syscache-update-pruned.spec. + */ + if (!ItemIdIsNormal(lp)) + { + Assert(RelationSupportsSysCache(RelationGetRelid(relation))); + + UnlockReleaseBuffer(buffer); + if (vmbuffer != InvalidBuffer) + ReleaseBuffer(vmbuffer); + *update_indexes = TU_None; + + bms_free(hot_attrs); + bms_free(sum_attrs); + bms_free(pk_attrs); + bms_free(rid_attrs); + bms_free(idx_attrs); + /* mix_attrs not yet initialized */ + + elog(ERROR, "tuple concurrently deleted"); + + return; + } + + /* Partially construct the oldtup to pass into heap_update() */ + oldtup.t_tableOid = RelationGetRelid(relation); + oldtup.t_data = (HeapTupleHeader) PageGetItem(page, lp); + oldtup.t_len = ItemIdGetLength(lp); + oldtup.t_self = *otid; + + /* We know what attributes were updated, which were indexed too? */ + Assert(!bms_is_empty(updated)); + mix_attrs = bms_intersect(updated, idx_attrs); + + /* + * We'll need to WAL log the replica identity attributes if either they + * overlap with the modified indexed attributes or, as we've checked for + * just now in HeapDetermineColumnsInfo, they were unmodified external + * indexed attributes. + */ + rep_id_key_required = rep_id_key_required || bms_overlap(mix_attrs, rid_attrs); + + result = heap_update(relation, &oldtup, tuple, GetCurrentCommandId(true), + InvalidSnapshot, true /* wait for commit */ , &tmfd, &lockmode, + buffer, page, block, lp, hot_attrs, sum_attrs, pk_attrs, + rid_attrs, mix_attrs, &vmbuffer, rep_id_key_required, + update_indexes); + + bms_free(hot_attrs); + bms_free(sum_attrs); + bms_free(pk_attrs); + bms_free(rid_attrs); - result = heap_update(relation, otid, tup, - GetCurrentCommandId(true), InvalidSnapshot, - true /* wait for commit */ , - &tmfd, &lockmode, update_indexes); switch (result) { case TM_SelfModified: @@ -9164,12 +9153,11 @@ log_heap_new_cid(Relation relation, HeapTuple tup) * the same tuple that was passed in. */ static HeapTuple -ExtractReplicaIdentity(Relation relation, HeapTuple tp, bool key_required, - bool *copy) +ExtractReplicaIdentity(Relation relation, HeapTuple tp, Bitmapset *rid_attrs, + bool key_required, bool *copy) { TupleDesc desc = RelationGetDescr(relation); char replident = relation->rd_rel->relreplident; - Bitmapset *idattrs; HeapTuple key_tuple; bool nulls[MaxHeapAttributeNumber]; Datum values[MaxHeapAttributeNumber]; @@ -9200,17 +9188,13 @@ ExtractReplicaIdentity(Relation relation, HeapTuple tp, bool key_required, if (!key_required) return NULL; - /* find out the replica identity columns */ - idattrs = RelationGetIndexAttrBitmap(relation, - INDEX_ATTR_BITMAP_IDENTITY_KEY); - /* * If there's no defined replica identity columns, treat as !key_required. * (This case should not be reachable from heap_update, since that should * calculate key_required accurately. But heap_delete just passes * constant true for key_required, so we can hit this case in deletes.) */ - if (bms_is_empty(idattrs)) + if (bms_is_empty(rid_attrs)) return NULL; /* @@ -9223,7 +9207,7 @@ ExtractReplicaIdentity(Relation relation, HeapTuple tp, bool key_required, for (int i = 0; i < desc->natts; i++) { if (bms_is_member(i + 1 - FirstLowInvalidHeapAttributeNumber, - idattrs)) + rid_attrs)) Assert(!nulls[i]); else nulls[i] = true; @@ -9232,8 +9216,6 @@ ExtractReplicaIdentity(Relation relation, HeapTuple tp, bool key_required, key_tuple = heap_form_tuple(desc, values, nulls); *copy = true; - bms_free(idattrs); - /* * If the tuple, which by here only contains indexed columns, still has * toasted columns, force them to be inlined. This is somewhat unlikely diff --git a/src/backend/access/heap/heapam_handler.c b/src/backend/access/heap/heapam_handler.c index bcbac844bb669..1cf9a18775d6d 100644 --- a/src/backend/access/heap/heapam_handler.c +++ b/src/backend/access/heap/heapam_handler.c @@ -44,6 +44,7 @@ #include "storage/procarray.h" #include "storage/smgr.h" #include "utils/builtins.h" +#include "utils/injection_point.h" #include "utils/rel.h" static void reform_and_rewrite_tuple(HeapTuple tuple, @@ -312,23 +313,133 @@ heapam_tuple_delete(Relation relation, ItemPointer tid, CommandId cid, return heap_delete(relation, tid, cid, crosscheck, wait, tmfd, changingPart); } - static TM_Result heapam_tuple_update(Relation relation, ItemPointer otid, TupleTableSlot *slot, CommandId cid, Snapshot snapshot, Snapshot crosscheck, bool wait, TM_FailureData *tmfd, LockTupleMode *lockmode, TU_UpdateIndexes *update_indexes) { + bool rep_id_key_required = false; bool shouldFree = true; HeapTuple tuple = ExecFetchSlotHeapTuple(slot, true, &shouldFree); + HeapTupleData oldtup; + Buffer buffer; + Buffer vmbuffer = InvalidBuffer; + Page page; + BlockNumber block; + ItemId lp; + Bitmapset *hot_attrs, + *sum_attrs, + *pk_attrs, + *rid_attrs, + *mix_attrs, + *idx_attrs; TM_Result result; + Assert(ItemPointerIsValid(otid)); + + /* Cheap, simplistic check that the tuple matches the rel's rowtype. */ + Assert(HeapTupleHeaderGetNatts(tuple->t_data) <= + RelationGetNumberOfAttributes(relation)); + + /* + * Forbid this during a parallel operation, lest it allocate a combo CID. + * Other workers might need that combo CID for visibility checks, and we + * have no provision for broadcasting it to them. + */ + if (IsInParallelMode()) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TRANSACTION_STATE), + errmsg("cannot update tuples during a parallel operation"))); + +#ifdef USE_ASSERT_CHECKING + check_lock_if_inplace_updateable_rel(relation, otid, tuple); +#endif + + /* + * Fetch the list of attributes to be checked for various operations. + * + * For HOT considerations, this is wasted effort if we fail to update or + * have to put the new tuple on a different page. But we must compute the + * list before obtaining buffer lock --- in the worst case, if we are + * doing an update on one of the relevant system catalogs, we could + * deadlock if we try to fetch the list later. In any case, the relcache + * caches the data so this is usually pretty cheap. + * + * We also need columns used by the replica identity and columns that are + * considered the "key" of rows in the table. + * + * Note that we get copies of each bitmap, so we need not worry about + * relcache flush happening midway through. + */ + hot_attrs = RelationGetIndexAttrBitmap(relation, + INDEX_ATTR_BITMAP_HOT_BLOCKING); + sum_attrs = RelationGetIndexAttrBitmap(relation, + INDEX_ATTR_BITMAP_SUMMARIZED); + pk_attrs = RelationGetIndexAttrBitmap(relation, INDEX_ATTR_BITMAP_KEY); + rid_attrs = RelationGetIndexAttrBitmap(relation, + INDEX_ATTR_BITMAP_IDENTITY_KEY); + + idx_attrs = bms_copy(hot_attrs); + idx_attrs = bms_add_members(idx_attrs, sum_attrs); + idx_attrs = bms_add_members(idx_attrs, pk_attrs); + idx_attrs = bms_add_members(idx_attrs, rid_attrs); + + block = ItemPointerGetBlockNumber(otid); + INJECTION_POINT("heap_update-before-pin", NULL); + buffer = ReadBuffer(relation, block); + page = BufferGetPage(buffer); + + /* + * Before locking the buffer, pin the visibility map page if it appears to + * be necessary. Since we haven't got the lock yet, someone else might be + * in the middle of changing this, so we'll need to recheck after we have + * the lock. + */ + if (PageIsAllVisible(page)) + visibilitymap_pin(relation, block, &vmbuffer); + + LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE); + + lp = PageGetItemId(page, ItemPointerGetOffsetNumber(otid)); + + Assert(ItemIdIsNormal(lp)); + + /* + * Partially construct the oldtup for HeapDetermineColumnsInfo to work and + * then pass that on to heap_update. + */ + oldtup.t_tableOid = RelationGetRelid(relation); + oldtup.t_data = (HeapTupleHeader) PageGetItem(page, lp); + oldtup.t_len = ItemIdGetLength(lp); + oldtup.t_self = *otid; + + mix_attrs = HeapDetermineColumnsInfo(relation, idx_attrs, rid_attrs, + &oldtup, tuple, &rep_id_key_required); + + /* + * We'll need to WAL log the replica identity attributes if either they + * overlap with the modified indexed attributes or, as we've checked for + * just now in HeapDetermineColumnsInfo, they were unmodified external + * indexed attributes. + */ + rep_id_key_required = rep_id_key_required || bms_overlap(mix_attrs, rid_attrs); + /* Update the tuple with table oid */ slot->tts_tableOid = RelationGetRelid(relation); tuple->t_tableOid = slot->tts_tableOid; - result = heap_update(relation, otid, tuple, cid, crosscheck, wait, - tmfd, lockmode, update_indexes); + result = heap_update(relation, &oldtup, tuple, cid, crosscheck, wait, tmfd, lockmode, + buffer, page, block, lp, hot_attrs, sum_attrs, pk_attrs, + rid_attrs, mix_attrs, &vmbuffer, rep_id_key_required, update_indexes); + + bms_free(hot_attrs); + bms_free(sum_attrs); + bms_free(pk_attrs); + bms_free(rid_attrs); + bms_free(mix_attrs); + bms_free(idx_attrs); + ItemPointerCopy(&tuple->t_self, &slot->tts_tid); /* diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c index cd139bd65a668..cb402c0c7a650 100644 --- a/src/backend/catalog/aclchk.c +++ b/src/backend/catalog/aclchk.c @@ -1154,7 +1154,6 @@ SetDefaultACL(InternalDefaultACL *iacls) Acl *def_acl; Acl *old_acl; Acl *new_acl; - HeapTuple newtuple; int noldmembers; int nnewmembers; Oid *oldmembers; @@ -1315,36 +1314,30 @@ 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}; Oid defAclOid; + CatalogUpdateValuesContext(pg_default_acl, ctx); + if (isNew) { /* 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); - - newtuple = heap_form_tuple(RelationGetDescr(rel), values, nulls); - CatalogTupleInsert(rel, newtuple); + CatalogTupleSetValue(ctx, pg_default_acl, oid, ObjectIdGetDatum(defAclOid)); + CatalogTupleSetValue(ctx, pg_default_acl, defaclrole, ObjectIdGetDatum(iacls->roleid)); + CatalogTupleSetValue(ctx, pg_default_acl, defaclnamespace, ObjectIdGetDatum(iacls->nspid)); + CatalogTupleSetValue(ctx, pg_default_acl, defaclobjtype, CharGetDatum(objtype)); + CatalogTupleSetValue(ctx, pg_default_acl, defaclacl, PointerGetDatum(new_acl)); + + InsertCatalogTupleValues(rel, ctx); } else { 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; - - newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel), - values, nulls, replaces); - CatalogTupleUpdate(rel, &newtuple->t_self, newtuple); + CatalogTupleUpdateValue(ctx, pg_default_acl, defaclacl, PointerGetDatum(new_acl)); + ModifyCatalogTupleValues(rel, tuple, ctx); } /* these dependencies don't change in an update */ @@ -1648,15 +1641,13 @@ ExecGrant_Attribute(InternalGrant *istmt, Oid relOid, const char *relname, Oid grantorId; AclMode avail_goptions; bool need_update; - HeapTuple newtuple; - Datum values[Natts_pg_attribute] = {0}; - bool nulls[Natts_pg_attribute] = {0}; - bool replaces[Natts_pg_attribute] = {0}; int noldmembers; int nnewmembers; Oid *oldmembers; Oid *newmembers; + CatalogUpdateValuesContext(pg_attribute, ctx); + attr_tuple = SearchSysCache2(ATTNUM, ObjectIdGetDatum(relOid), Int16GetDatum(attnum)); @@ -1742,22 +1733,18 @@ ExecGrant_Attribute(InternalGrant *istmt, Oid relOid, const char *relname, */ if (ACL_NUM(new_acl) > 0) { - values[Anum_pg_attribute_attacl - 1] = PointerGetDatum(new_acl); + CatalogTupleUpdateValue(ctx, pg_attribute, attacl, PointerGetDatum(new_acl)); need_update = true; } else { - nulls[Anum_pg_attribute_attacl - 1] = true; + CatalogTupleUpdateValueNull(ctx, pg_attribute, attacl); need_update = !isNull; } - replaces[Anum_pg_attribute_attacl - 1] = true; if (need_update) { - newtuple = heap_modify_tuple(attr_tuple, RelationGetDescr(attRelation), - values, nulls, replaces); - - CatalogTupleUpdate(attRelation, &newtuple->t_self, newtuple); + ModifyCatalogTupleValues(attRelation, attr_tuple, ctx); /* Update initial privileges for extensions */ recordExtensionInitPriv(relOid, RelationRelationId, attnum, @@ -1958,14 +1945,12 @@ ExecGrant_Relation(InternalGrant *istmt) AclMode avail_goptions; Acl *new_acl; Oid grantorId; - HeapTuple newtuple; - Datum values[Natts_pg_class] = {0}; - bool nulls[Natts_pg_class] = {0}; - bool replaces[Natts_pg_class] = {0}; int nnewmembers; Oid *newmembers; ObjectType objtype; + CatalogUpdateValuesContext(pg_class, ctx); + /* Determine ID to do the grant as, and available grant options */ select_best_grantor(GetUserId(), this_privileges, old_acl, ownerId, @@ -2011,13 +1996,8 @@ 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); - - newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), - values, nulls, replaces); - - CatalogTupleUpdate(relation, &newtuple->t_self, newtuple); + CatalogTupleUpdateValue(ctx, pg_class, relacl, PointerGetDatum(new_acl)); + ModifyCatalogTupleValues(relation, tuple, ctx); UnlockTuple(relation, &tuple->t_self, InplaceUpdateTupleLock); /* Update initial privileges for extensions */ @@ -2140,7 +2120,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 +2194,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 CatalogTuple*() macros 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 +2220,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(); @@ -2286,10 +2270,6 @@ ExecGrant_Largeobject(InternalGrant *istmt) Acl *new_acl; Oid grantorId; 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}; int noldmembers; int nnewmembers; Oid *oldmembers; @@ -2298,6 +2278,8 @@ ExecGrant_Largeobject(InternalGrant *istmt) SysScanDesc scan; HeapTuple tuple; + CatalogUpdateValuesContext(pg_largeobject_metadata, ctx); + /* There's no syscache for pg_largeobject_metadata */ ScanKeyInit(&entry[0], Anum_pg_largeobject_metadata_oid, @@ -2367,14 +2349,8 @@ 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); - - newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), - values, nulls, replaces); - - CatalogTupleUpdate(relation, &newtuple->t_self, newtuple); + CatalogTupleUpdateValue(ctx, pg_largeobject_metadata, lomacl, PointerGetDatum(new_acl)); + ModifyCatalogTupleValues(relation, tuple, ctx); /* Update initial privileges for extensions */ recordExtensionInitPriv(loid, LargeObjectRelationId, 0, new_acl); @@ -2524,19 +2500,11 @@ ExecGrant_Parameter(InternalGrant *istmt) } else { - /* 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}; - - replaces[Anum_pg_parameter_acl_paracl - 1] = true; - values[Anum_pg_parameter_acl_paracl - 1] = PointerGetDatum(new_acl); - - newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), - values, nulls, replaces); + /* finished building new ACL value, now update it */ + CatalogUpdateValuesContext(pg_parameter_acl, ctx); - CatalogTupleUpdate(relation, &newtuple->t_self, newtuple); + CatalogTupleUpdateValue(ctx, pg_parameter_acl, paracl, PointerGetDatum(new_acl)); + ModifyCatalogTupleValues(relation, tuple, ctx); } /* Update initial privileges for extensions */ @@ -4631,7 +4599,6 @@ recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid, Relation relation; ScanKeyData key[3]; SysScanDesc scan; - HeapTuple tuple; HeapTuple oldtuple; int noldmembers; int nnewmembers; @@ -4666,9 +4633,6 @@ recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid, /* If we find an entry, update it with the latest ACL. */ if (HeapTupleIsValid(oldtuple)) { - Datum values[Natts_pg_init_privs] = {0}; - bool nulls[Natts_pg_init_privs] = {0}; - bool replace[Natts_pg_init_privs] = {0}; Datum oldAclDatum; bool isNull; Acl *old_acl; @@ -4687,13 +4651,10 @@ 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; - - oldtuple = heap_modify_tuple(oldtuple, RelationGetDescr(relation), - values, nulls, replace); + CatalogUpdateValuesContext(pg_init_privs, ctx); - CatalogTupleUpdate(relation, &oldtuple->t_self, oldtuple); + CatalogTupleUpdateValue(ctx, pg_init_privs, initprivs, PointerGetDatum(new_acl)); + ModifyCatalogTupleValues(relation, oldtuple, ctx); } else { @@ -4703,8 +4664,7 @@ recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid, } else { - Datum values[Natts_pg_init_privs] = {0}; - bool nulls[Natts_pg_init_privs] = {0}; + CatalogInsertValuesContext(pg_init_privs, ctx); /* * Only add a new entry if the new ACL is non-NULL. @@ -4715,19 +4675,15 @@ 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); + CatalogTupleSetValue(ctx, pg_init_privs, objoid, ObjectIdGetDatum(objoid)); + CatalogTupleSetValue(ctx, pg_init_privs, classoid, ObjectIdGetDatum(classoid)); + CatalogTupleSetValue(ctx, pg_init_privs, objsubid, Int32GetDatum(objsubid)); /* This function only handles initial privileges of extensions */ - values[Anum_pg_init_privs_privtype - 1] = - CharGetDatum(INITPRIVS_EXTENSION); - - values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl); + CatalogTupleSetValue(ctx, pg_init_privs, privtype, CharGetDatum(INITPRIVS_EXTENSION)); + CatalogTupleSetValue(ctx, pg_init_privs, initprivs, PointerGetDatum(new_acl)); - tuple = heap_form_tuple(RelationGetDescr(relation), values, nulls); - - CatalogTupleInsert(relation, tuple); + InsertCatalogTupleValues(relation, ctx); /* Update pg_shdepend, too. */ noldmembers = 0; @@ -4764,7 +4720,6 @@ ReplaceRoleInInitPriv(Oid oldroleid, Oid newroleid, bool isNull; Acl *old_acl; Acl *new_acl; - HeapTuple newtuple; int noldmembers; int nnewmembers; Oid *oldmembers; @@ -4825,17 +4780,11 @@ 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}; - /* Update existing entry. */ - values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl); - replaces[Anum_pg_init_privs_initprivs - 1] = true; + CatalogUpdateValuesContext(pg_init_privs, ctx); - newtuple = heap_modify_tuple(oldtuple, RelationGetDescr(rel), - values, nulls, replaces); - CatalogTupleUpdate(rel, &newtuple->t_self, newtuple); + CatalogTupleUpdateValue(ctx, pg_init_privs, initprivs, PointerGetDatum(new_acl)); + ModifyCatalogTupleValues(rel, oldtuple, ctx); } /* @@ -4875,7 +4824,6 @@ RemoveRoleFromInitPriv(Oid roleid, Oid classid, Oid objid, int32 objsubid) bool isNull; Acl *old_acl; Acl *new_acl; - HeapTuple newtuple; int noldmembers; int nnewmembers; Oid *oldmembers; @@ -4961,17 +4909,11 @@ 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}; - /* Update existing entry. */ - values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl); - replaces[Anum_pg_init_privs_initprivs - 1] = true; + CatalogUpdateValuesContext(pg_init_privs, ctx); - newtuple = heap_modify_tuple(oldtuple, RelationGetDescr(rel), - values, nulls, replaces); - CatalogTupleUpdate(rel, &newtuple->t_self, newtuple); + CatalogTupleUpdateValue(ctx, pg_init_privs, initprivs, PointerGetDatum(new_acl)); + ModifyCatalogTupleValues(rel, oldtuple, ctx); } /* diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index fd6537567ea27..010b9dd13a346 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,63 +918,55 @@ 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]; - HeapTuple tup; + + CatalogInsertValuesContext(pg_class, ctx); /* 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); + CatalogTupleSetValue(ctx, pg_class, oid, ObjectIdGetDatum(new_rel_oid)); + CatalogTupleSetValue(ctx, pg_class, relname, NameGetDatum(&rd_rel->relname)); + CatalogTupleSetValue(ctx, pg_class, relnamespace, ObjectIdGetDatum(rd_rel->relnamespace)); + CatalogTupleSetValue(ctx, pg_class, reltype, ObjectIdGetDatum(rd_rel->reltype)); + CatalogTupleSetValue(ctx, pg_class, reloftype, ObjectIdGetDatum(rd_rel->reloftype)); + CatalogTupleSetValue(ctx, pg_class, relowner, ObjectIdGetDatum(rd_rel->relowner)); + CatalogTupleSetValue(ctx, pg_class, relam, ObjectIdGetDatum(rd_rel->relam)); + CatalogTupleSetValue(ctx, pg_class, relfilenode, ObjectIdGetDatum(rd_rel->relfilenode)); + CatalogTupleSetValue(ctx, pg_class, reltablespace, ObjectIdGetDatum(rd_rel->reltablespace)); + CatalogTupleSetValue(ctx, pg_class, relpages, Int32GetDatum(rd_rel->relpages)); + CatalogTupleSetValue(ctx, pg_class, reltuples, Float4GetDatum(rd_rel->reltuples)); + CatalogTupleSetValue(ctx, pg_class, relallvisible, Int32GetDatum(rd_rel->relallvisible)); + CatalogTupleSetValue(ctx, pg_class, relallfrozen, Int32GetDatum(rd_rel->relallfrozen)); + CatalogTupleSetValue(ctx, pg_class, reltoastrelid, ObjectIdGetDatum(rd_rel->reltoastrelid)); + CatalogTupleSetValue(ctx, pg_class, relhasindex, BoolGetDatum(rd_rel->relhasindex)); + CatalogTupleSetValue(ctx, pg_class, relisshared, BoolGetDatum(rd_rel->relisshared)); + CatalogTupleSetValue(ctx, pg_class, relpersistence, CharGetDatum(rd_rel->relpersistence)); + CatalogTupleSetValue(ctx, pg_class, relkind, CharGetDatum(rd_rel->relkind)); + CatalogTupleSetValue(ctx, pg_class, relnatts, Int16GetDatum(rd_rel->relnatts)); + CatalogTupleSetValue(ctx, pg_class, relchecks, Int16GetDatum(rd_rel->relchecks)); + CatalogTupleSetValue(ctx, pg_class, relhasrules, BoolGetDatum(rd_rel->relhasrules)); + CatalogTupleSetValue(ctx, pg_class, relhastriggers, BoolGetDatum(rd_rel->relhastriggers)); + CatalogTupleSetValue(ctx, pg_class, relrowsecurity, BoolGetDatum(rd_rel->relrowsecurity)); + CatalogTupleSetValue(ctx, pg_class, relforcerowsecurity, BoolGetDatum(rd_rel->relforcerowsecurity)); + CatalogTupleSetValue(ctx, pg_class, relhassubclass, BoolGetDatum(rd_rel->relhassubclass)); + CatalogTupleSetValue(ctx, pg_class, relispopulated, BoolGetDatum(rd_rel->relispopulated)); + CatalogTupleSetValue(ctx, pg_class, relreplident, CharGetDatum(rd_rel->relreplident)); + CatalogTupleSetValue(ctx, pg_class, relispartition, BoolGetDatum(rd_rel->relispartition)); + CatalogTupleSetValue(ctx, pg_class, relrewrite, ObjectIdGetDatum(rd_rel->relrewrite)); + CatalogTupleSetValue(ctx, pg_class, relfrozenxid, TransactionIdGetDatum(rd_rel->relfrozenxid)); + CatalogTupleSetValue(ctx, pg_class, relminmxid, MultiXactIdGetDatum(rd_rel->relminmxid)); if (relacl != (Datum) 0) - values[Anum_pg_class_relacl - 1] = relacl; + CatalogTupleSetValue(ctx, pg_class, relacl, relacl); else - nulls[Anum_pg_class_relacl - 1] = true; + CatalogTupleSetValueNull(ctx, pg_class, relacl); if (reloptions != (Datum) 0) - values[Anum_pg_class_reloptions - 1] = reloptions; + CatalogTupleSetValue(ctx, pg_class, reloptions, reloptions); else - nulls[Anum_pg_class_reloptions - 1] = true; + CatalogTupleSetValueNull(ctx, pg_class, reloptions); /* relpartbound is set by updating this tuple, if necessary */ - nulls[Anum_pg_class_relpartbound - 1] = true; - - tup = heap_form_tuple(RelationGetDescr(pg_class_desc), values, nulls); + CatalogTupleSetValueNull(ctx, pg_class, relpartbound); /* finally insert the new tuple, update the indexes, and clean up */ - CatalogTupleInsert(pg_class_desc, tup); - - heap_freetuple(tup); + InsertCatalogTupleValues(pg_class_desc, ctx); } /* -------------------------------- @@ -1685,11 +1681,9 @@ RemoveAttributeById(Oid relid, AttrNumber attnum) Relation rel; Relation attr_rel; 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}; + + CatalogUpdateFormContext(pg_attribute, ctx); /* * Grab an exclusive lock on the target table, which we will NOT release @@ -1707,10 +1701,11 @@ RemoveAttributeById(Oid relid, AttrNumber attnum) if (!HeapTupleIsValid(tuple)) /* shouldn't happen */ elog(ERROR, "cache lookup failed for attribute %d of relation %u", attnum, relid); - attStruct = (Form_pg_attribute) GETSTRUCT(tuple); + + CatalogSetForm(pg_attribute, ctx, tuple); /* Mark the attribute as dropped */ - attStruct->attisdropped = true; + CatalogTupleUpdateField(ctx, pg_attribute, attisdropped, true); /* * Set the type OID to invalid. A dropped attribute's type link cannot be @@ -1720,43 +1715,35 @@ 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; + CatalogTupleUpdateField(ctx, pg_attribute, atttypid, InvalidOid); /* Remove any not-null constraint the column may have */ - attStruct->attnotnull = false; + CatalogTupleUpdateField(ctx, pg_attribute, attnotnull, false); /* Unset this so no one tries to look up the generation expression */ - attStruct->attgenerated = '\0'; + CatalogTupleUpdateField(ctx, pg_attribute, attgenerated, '\0'); /* * Change the column name to something that isn't likely to conflict */ snprintf(newattname, sizeof(newattname), "........pg.dropped.%d........", attnum); - namestrcpy(&(attStruct->attname), newattname); + CatalogTupleUpdateStrField(ctx, pg_attribute, attname, newattname); /* Clear the missing value */ - attStruct->atthasmissing = false; - nullsAtt[Anum_pg_attribute_attmissingval - 1] = true; - replacesAtt[Anum_pg_attribute_attmissingval - 1] = true; + CatalogTupleUpdateField(ctx, pg_attribute, atthasmissing, false); + CatalogTupleUpdateFieldNull(ctx, pg_attribute, attmissingval); /* * 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; + CatalogTupleUpdateFieldNull(ctx, pg_attribute, attstattarget); + CatalogTupleUpdateFieldNull(ctx, pg_attribute, attacl); + CatalogTupleUpdateFieldNull(ctx, pg_attribute, attoptions); + CatalogTupleUpdateFieldNull(ctx, pg_attribute, attfdwoptions); - tuple = heap_modify_tuple(tuple, RelationGetDescr(attr_rel), - valuesAtt, nullsAtt, replacesAtt); - - CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple); + ModifyCatalogTupleField(attr_rel, tuple, ctx); /* * Because updating the pg_attribute row will trigger a relcache flush for @@ -1765,9 +1752,7 @@ RemoveAttributeById(Oid relid, AttrNumber attnum) */ table_close(attr_rel, RowExclusiveLock); - RemoveStatistics(relid, attnum); - relation_close(rel, NoLock); } @@ -1967,23 +1952,13 @@ 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]; 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; + HeapTuple tuple; - repl_repl[Anum_pg_attribute_atthasmissing - 1] = true; - repl_repl[Anum_pg_attribute_attmissingval - 1] = true; + CatalogUpdateValuesContext(pg_attribute, ctx); + CatalogTupleUpdateValue(ctx, pg_attribute, atthasmissing, BoolGetDatum(false)); + CatalogTupleUpdateValueNull(ctx, pg_attribute, attmissingval); /* Get a lock on pg_attribute */ attr_rel = table_open(AttributeRelationId, RowExclusiveLock); @@ -2002,14 +1977,7 @@ 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); - - CatalogTupleUpdate(attr_rel, &newtuple->t_self, newtuple); - - heap_freetuple(newtuple); - } + ModifyCatalogTupleValues(attr_rel, tuple, ctx); ReleaseSysCache(tuple); } @@ -2029,13 +1997,11 @@ 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}; Relation attrrel; Form_pg_attribute attStruct; - HeapTuple atttup, - newtup; + HeapTuple atttup; + + CatalogUpdateValuesContext(pg_attribute, ctx); /* This is only supported for plain tables */ Assert(rel->rd_rel->relkind == RELKIND_RELATION); @@ -2060,15 +2026,10 @@ 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; + CatalogTupleUpdateValue(ctx, pg_attribute, atthasmissing, BoolGetDatum(true)); + CatalogTupleUpdateValue(ctx, pg_attribute, attmissingval, missingval); - newtup = heap_modify_tuple(atttup, RelationGetDescr(attrrel), - valuesAtt, nullsAtt, replacesAtt); - CatalogTupleUpdate(attrrel, &newtup->t_self, newtup); + ModifyCatalogTupleValues(attrrel, atttup, ctx); /* clean up */ ReleaseSysCache(atttup); @@ -2085,15 +2046,13 @@ 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 missingval; Form_pg_attribute attStruct; Relation attrrel, tablerel; - HeapTuple atttup, - newtup; + HeapTuple atttup; + + CatalogUpdateValuesContext(pg_attribute, ctx); /* lock the table the attribute belongs to */ tablerel = table_open(relid, AccessExclusiveLock); @@ -2120,14 +2079,10 @@ 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; + CatalogTupleUpdateValue(ctx, pg_attribute, atthasmissing, BoolGetDatum(true)); + CatalogTupleUpdateValue(ctx, pg_attribute, attmissingval, missingval); - newtup = heap_modify_tuple(atttup, RelationGetDescr(attrrel), - valuesAtt, nullsAtt, replacesAtt); - CatalogTupleUpdate(attrrel, &newtup->t_self, newtup); + ModifyCatalogTupleValues(attrrel, atttup, ctx); /* clean up */ ReleaseSysCache(atttup); @@ -2720,6 +2675,8 @@ MergeWithExistingConstraint(Relation rel, const char *ccname, Node *expr, ScanKeyData skey[3]; HeapTuple tup; + CatalogUpdateFormContext(pg_constraint, ctx); + /* Search for a pg_constraint entry with same name and relation */ conDesc = table_open(ConstraintRelationId, RowExclusiveLock); @@ -2825,7 +2782,7 @@ MergeWithExistingConstraint(Relation rel, const char *ccname, Node *expr, ccname))); tup = heap_copytuple(tup); - con = (Form_pg_constraint) GETSTRUCT(tup); + CatalogSetForm(pg_constraint, ctx, tup); /* * In case of partitions, an inherited constraint must be inherited @@ -2834,24 +2791,26 @@ MergeWithExistingConstraint(Relation rel, const char *ccname, Node *expr, */ if (rel->rd_rel->relispartition) { - con->coninhcount = 1; - con->conislocal = false; + CatalogTupleUpdateField(ctx, pg_constraint, coninhcount, 1); + CatalogTupleUpdateField(ctx, pg_constraint, conislocal, false); } else { if (is_local) - con->conislocal = true; - else if (pg_add_s16_overflow(con->coninhcount, 1, - &con->coninhcount)) - ereport(ERROR, - errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), - errmsg("too many inheritance parents")); + CatalogTupleUpdateField(ctx, pg_constraint, conislocal, true); + else + CatalogTupleCondUpdateField(ctx, pg_constraint, coninhcount, + pg_add_s16_overflow(CatalogGetFormField(ctx, coninhcount), 1, + &CatalogGetFormField(ctx, coninhcount)), + ereport(ERROR, + errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), + errmsg("too many inheritance parents"))); } if (is_no_inherit) { Assert(is_local); - con->connoinherit = true; + CatalogTupleUpdateField(ctx, pg_constraint, connoinherit, true); } /* @@ -2863,11 +2822,11 @@ MergeWithExistingConstraint(Relation rel, const char *ccname, Node *expr, if (is_enforced && !con->conenforced) { Assert(is_local); - con->conenforced = true; - con->convalidated = true; + CatalogTupleUpdateField(ctx, pg_constraint, conenforced, true); + CatalogTupleUpdateField(ctx, pg_constraint, convalidated, true); } - CatalogTupleUpdate(conDesc, &tup->t_self, tup); + UpdateCatalogTupleField(conDesc, tup, ctx); } systable_endscan(conscan); @@ -3147,7 +3106,8 @@ SetRelationNumChecks(Relation rel, int numchecks) { Relation relrel; HeapTuple reltup; - Form_pg_class relStruct; + + CatalogUpdateFormContext(pg_class, ctx); relrel = table_open(RelationRelationId, RowExclusiveLock); reltup = SearchSysCacheCopy1(RELOID, @@ -3155,13 +3115,12 @@ SetRelationNumChecks(Relation rel, int numchecks) if (!HeapTupleIsValid(reltup)) elog(ERROR, "cache lookup failed for relation %u", RelationGetRelid(rel)); - relStruct = (Form_pg_class) GETSTRUCT(reltup); + CatalogSetForm(pg_class, ctx, reltup); - if (relStruct->relchecks != numchecks) + if (CatalogGetFormField(ctx, relchecks) != numchecks) { - relStruct->relchecks = numchecks; - - CatalogTupleUpdate(relrel, &reltup->t_self, reltup); + CatalogTupleUpdateField(ctx, pg_class, relchecks, numchecks); + UpdateCatalogTupleField(relrel, reltup, ctx); } else { @@ -3470,7 +3429,7 @@ CopyStatistics(Oid fromrelid, Oid torelid) if (indstate == NULL) indstate = CatalogOpenIndexes(statrel); - CatalogTupleInsertWithInfo(statrel, tup, indstate); + CatalogTupleInsert(statrel, tup, indstate); heap_freetuple(tup); } @@ -3905,13 +3864,12 @@ StorePartitionKey(Relation rel, oidvector *partcollation_vec; Datum partexprDatum; Relation pg_partitioned_table; - HeapTuple tuple; - Datum values[Natts_pg_partitioned_table]; - bool nulls[Natts_pg_partitioned_table] = {0}; ObjectAddress myself; ObjectAddress referenced; ObjectAddresses *addrs; + CatalogInsertValuesContext(pg_partitioned_table, ctx); + Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE); /* Copy the partition attribute numbers, opclass OIDs into arrays */ @@ -3935,20 +3893,19 @@ StorePartitionKey(Relation rel, /* Only this can ever be NULL */ if (!partexprDatum) - nulls[Anum_pg_partitioned_table_partexprs - 1] = true; - - 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; + CatalogTupleSetValueNull(ctx, pg_partitioned_table, partexprs); + else + CatalogTupleSetValue(ctx, pg_partitioned_table, partexprs, partexprDatum); - tuple = heap_form_tuple(RelationGetDescr(pg_partitioned_table), values, nulls); + CatalogTupleSetValue(ctx, pg_partitioned_table, partrelid, ObjectIdGetDatum(RelationGetRelid(rel))); + CatalogTupleSetValue(ctx, pg_partitioned_table, partstrat, CharGetDatum(strategy)); + CatalogTupleSetValue(ctx, pg_partitioned_table, partnatts, Int16GetDatum(partnatts)); + CatalogTupleSetValue(ctx, pg_partitioned_table, partdefid, ObjectIdGetDatum(InvalidOid)); + CatalogTupleSetValue(ctx, pg_partitioned_table, partattrs, PointerGetDatum(partattrs_vec)); + CatalogTupleSetValue(ctx, pg_partitioned_table, partclass, PointerGetDatum(partopclass_vec)); + CatalogTupleSetValue(ctx, pg_partitioned_table, partcollation, PointerGetDatum(partcollation_vec)); - CatalogTupleInsert(pg_partitioned_table, tuple); + InsertCatalogTupleValues(pg_partitioned_table, ctx); table_close(pg_partitioned_table, RowExclusiveLock); /* Mark this relation as dependent on a few things as follows */ @@ -4050,13 +4007,11 @@ void 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]; + HeapTuple tuple; Oid defaultPartOid; + CatalogUpdateValuesContext(pg_class, ctx); + /* Update pg_class tuple */ classRel = table_open(RelationRelationId, RowExclusiveLock); tuple = SearchSysCacheCopy1(RELOID, @@ -4065,12 +4020,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 +4036,19 @@ 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); + CatalogTupleUpdateValue(ctx, pg_class, relpartbound, CStringGetTextDatum(nodeToString(bound))); + /* Also set the flag */ - ((Form_pg_class) GETSTRUCT(newtuple))->relispartition = true; + CatalogTupleUpdateValue(ctx, pg_class, relispartition, true); /* * 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; + CatalogTupleUpdateValue(ctx, pg_class, relhassubclass, false); - CatalogTupleUpdate(classRel, &newtuple->t_self, newtuple); - heap_freetuple(newtuple); + ModifyCatalogTupleValues(classRel, tuple, ctx); table_close(classRel, RowExclusiveLock); /* diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index 5d9db167e5950..9ad357f4c0033 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -579,18 +579,16 @@ UpdateIndexRelation(Oid indexoid, int2vector *indoption; Datum exprsDatum; Datum predDatum; - Datum values[Natts_pg_index]; - bool nulls[Natts_pg_index] = {0}; Relation pg_index; - HeapTuple tuple; - int i; + + CatalogInsertValuesContext(pg_index, ctx); /* * Copy the index key, opclass, and indoption info into arrays (should we * make the caller pass them like this to start with?) */ indkey = buildint2vector(NULL, indexInfo->ii_NumIndexAttrs); - for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++) + for (int i = 0; i < indexInfo->ii_NumIndexAttrs; i++) indkey->values[i] = indexInfo->ii_IndexAttrNumbers[i]; indcollation = buildoidvector(collationOids, indexInfo->ii_NumIndexKeyAttrs); indclass = buildoidvector(opclassOids, indexInfo->ii_NumIndexKeyAttrs); @@ -625,53 +623,45 @@ UpdateIndexRelation(Oid indexoid, else predDatum = (Datum) 0; - - /* - * open the system catalog index relation - */ + /* Open the system catalog index relation */ pg_index = table_open(IndexRelationId, RowExclusiveLock); - /* - * 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; + /* Build a pg_index tuple */ + CatalogTupleSetValue(ctx, pg_index, indexrelid, ObjectIdGetDatum(indexoid)); + CatalogTupleSetValue(ctx, pg_index, indrelid, ObjectIdGetDatum(heapoid)); + CatalogTupleSetValue(ctx, pg_index, indnatts, Int16GetDatum(indexInfo->ii_NumIndexAttrs)); + CatalogTupleSetValue(ctx, pg_index, indnkeyatts, Int16GetDatum(indexInfo->ii_NumIndexKeyAttrs)); + CatalogTupleSetValue(ctx, pg_index, indisunique, BoolGetDatum(indexInfo->ii_Unique)); + CatalogTupleSetValue(ctx, pg_index, indnullsnotdistinct, BoolGetDatum(indexInfo->ii_NullsNotDistinct)); + CatalogTupleSetValue(ctx, pg_index, indisprimary, BoolGetDatum(primary)); + CatalogTupleSetValue(ctx, pg_index, indisexclusion, BoolGetDatum(isexclusion)); + CatalogTupleSetValue(ctx, pg_index, indimmediate, BoolGetDatum(immediate)); + CatalogTupleSetValue(ctx, pg_index, indisclustered, BoolGetDatum(false)); + CatalogTupleSetValue(ctx, pg_index, indisvalid, BoolGetDatum(isvalid)); + CatalogTupleSetValue(ctx, pg_index, indcheckxmin, BoolGetDatum(false)); + CatalogTupleSetValue(ctx, pg_index, indisready, BoolGetDatum(isready)); + CatalogTupleSetValue(ctx, pg_index, indislive, BoolGetDatum(true)); + CatalogTupleSetValue(ctx, pg_index, indisreplident, BoolGetDatum(false)); + CatalogTupleSetValue(ctx, pg_index, indkey, PointerGetDatum(indkey)); + CatalogTupleSetValue(ctx, pg_index, indcollation, PointerGetDatum(indcollation)); + CatalogTupleSetValue(ctx, pg_index, indclass, PointerGetDatum(indclass)); + CatalogTupleSetValue(ctx, pg_index, indoption, PointerGetDatum(indoption)); + if (exprsDatum == (Datum) 0) - nulls[Anum_pg_index_indexprs - 1] = true; - values[Anum_pg_index_indpred - 1] = predDatum; + CatalogTupleSetValueNull(ctx, pg_index, indexprs); + else + CatalogTupleSetValue(ctx, pg_index, indexprs, exprsDatum); + if (predDatum == (Datum) 0) - nulls[Anum_pg_index_indpred - 1] = true; + CatalogTupleSetValueNull(ctx, pg_index, indpred); + else + CatalogTupleSetValue(ctx, pg_index, indpred, predDatum); - tuple = heap_form_tuple(RelationGetDescr(pg_index), values, nulls); + /* Insert the tuple into the pg_index catalog */ + InsertCatalogTupleValues(pg_index, ctx); - /* - * insert the tuple into the pg_index catalog - */ - CatalogTupleInsert(pg_index, tuple); - - /* - * close the relation and free the tuple - */ + /* Close the relation and free the tuple */ table_close(pg_index, RowExclusiveLock); - heap_freetuple(tuple); } @@ -1559,17 +1549,19 @@ index_concurrently_swap(Oid newIndexId, Oid oldIndexId, const char *oldName) newClassRel; HeapTuple oldClassTuple, newClassTuple; - Form_pg_class oldClassForm, - newClassForm; HeapTuple oldIndexTuple, newIndexTuple; - Form_pg_index oldIndexForm, - newIndexForm; bool isPartition; Oid indexConstraintOid; List *constraintOids = NIL; ListCell *lc; + CatalogUpdateFormContext(pg_class, old_class); + CatalogUpdateFormContext(pg_class, new_class); + + CatalogUpdateFormContext(pg_index, old_idx); + CatalogUpdateFormContext(pg_index, new_idx); + /* * Take a necessary lock on the old and new index before swapping them. */ @@ -1588,20 +1580,20 @@ index_concurrently_swap(Oid newIndexId, Oid oldIndexId, const char *oldName) if (!HeapTupleIsValid(newClassTuple)) elog(ERROR, "could not find tuple for relation %u", newIndexId); - oldClassForm = (Form_pg_class) GETSTRUCT(oldClassTuple); - newClassForm = (Form_pg_class) GETSTRUCT(newClassTuple); + CatalogSetForm(pg_class, old_class, oldClassTuple); + CatalogSetForm(pg_class, new_class, newClassTuple); /* Swap the names */ - namestrcpy(&newClassForm->relname, NameStr(oldClassForm->relname)); - namestrcpy(&oldClassForm->relname, oldName); + CatalogTupleUpdateStrField(new_class, pg_class, relname, NameStr(CatalogGetFormField(old_class, relname))); + CatalogTupleUpdateStrField(old_class, pg_class, relname, oldName); /* Swap the partition flags to track inheritance properly */ - isPartition = newClassForm->relispartition; - newClassForm->relispartition = oldClassForm->relispartition; - oldClassForm->relispartition = isPartition; + isPartition = CatalogGetFormField(new_class, relispartition); + CatalogTupleUpdateField(new_class, pg_class, relispartition, CatalogGetFormField(old_class, relispartition)); + CatalogTupleUpdateField(old_class, pg_class, relispartition, isPartition); - CatalogTupleUpdate(pg_class, &oldClassTuple->t_self, oldClassTuple); - CatalogTupleUpdate(pg_class, &newClassTuple->t_self, newClassTuple); + ModifyCatalogTupleField(pg_class, oldClassTuple, old_class); + ModifyCatalogTupleField(pg_class, newClassTuple, new_class); heap_freetuple(oldClassTuple); heap_freetuple(newClassTuple); @@ -1618,37 +1610,37 @@ index_concurrently_swap(Oid newIndexId, Oid oldIndexId, const char *oldName) if (!HeapTupleIsValid(newIndexTuple)) elog(ERROR, "could not find tuple for relation %u", newIndexId); - oldIndexForm = (Form_pg_index) GETSTRUCT(oldIndexTuple); - newIndexForm = (Form_pg_index) GETSTRUCT(newIndexTuple); + CatalogSetForm(pg_index, old_idx, oldIndexTuple); + CatalogSetForm(pg_index, new_idx, newIndexTuple); /* * 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; + CatalogTupleUpdateField(new_idx, pg_index, indisprimary, CatalogGetFormField(old_idx, indisprimary)); + CatalogTupleUpdateField(old_idx, pg_index, indisprimary, false); + CatalogTupleUpdateField(new_idx, pg_index, indisexclusion, CatalogGetFormField(old_idx, indisexclusion)); + CatalogTupleUpdateField(old_idx, pg_index, indisexclusion, false); + CatalogTupleUpdateField(new_idx, pg_index, indimmediate, CatalogGetFormField(old_idx, indimmediate)); + CatalogTupleUpdateField(old_idx, pg_index, indimmediate, true); /* Preserve indisreplident in the new index */ - newIndexForm->indisreplident = oldIndexForm->indisreplident; + CatalogTupleUpdateField(new_idx, pg_index, indisreplident, CatalogGetFormField(old_idx, indisreplident)); /* Preserve indisclustered in the new index */ - newIndexForm->indisclustered = oldIndexForm->indisclustered; + CatalogTupleUpdateField(new_idx, pg_index, indisclustered, CatalogGetFormField(old_idx, indisclustered)); /* * 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; + CatalogTupleUpdateField(new_idx, pg_index, indisvalid, true); + CatalogTupleUpdateField(old_idx, pg_index, indisvalid, false); + CatalogTupleUpdateField(old_idx, pg_index, indisclustered, false); + CatalogTupleUpdateField(old_idx, pg_index, indisreplident, false); - CatalogTupleUpdate(pg_index, &oldIndexTuple->t_self, oldIndexTuple); - CatalogTupleUpdate(pg_index, &newIndexTuple->t_self, newIndexTuple); + ModifyCatalogTupleField(pg_index, oldIndexTuple, old_idx); + ModifyCatalogTupleField(pg_index, newIndexTuple, new_idx); heap_freetuple(oldIndexTuple); heap_freetuple(newIndexTuple); @@ -1671,24 +1663,24 @@ index_concurrently_swap(Oid newIndexId, Oid oldIndexId, const char *oldName) { HeapTuple constraintTuple, triggerTuple; - Form_pg_constraint conForm; ScanKeyData key[1]; SysScanDesc scan; Oid constraintOid = lfirst_oid(lc); + CatalogUpdateFormContext(pg_constraint, con); + /* Move the constraint from the old to the new index */ constraintTuple = SearchSysCacheCopy1(CONSTROID, ObjectIdGetDatum(constraintOid)); if (!HeapTupleIsValid(constraintTuple)) elog(ERROR, "could not find tuple for constraint %u", constraintOid); - conForm = ((Form_pg_constraint) GETSTRUCT(constraintTuple)); + CatalogSetForm(pg_constraint, con, constraintTuple); - if (conForm->conindid == oldIndexId) + if (CatalogGetFormField(con, conindid) == oldIndexId) { - conForm->conindid = newIndexId; - - CatalogTupleUpdate(pg_constraint, &constraintTuple->t_self, constraintTuple); + CatalogTupleUpdateField(con, pg_constraint, conindid, newIndexId); + ModifyCatalogTupleField(pg_constraint, constraintTuple, con); } heap_freetuple(constraintTuple); @@ -1704,20 +1696,18 @@ index_concurrently_swap(Oid newIndexId, Oid oldIndexId, const char *oldName) while (HeapTupleIsValid((triggerTuple = systable_getnext(scan)))) { - Form_pg_trigger tgForm = (Form_pg_trigger) GETSTRUCT(triggerTuple); + CatalogUpdateFormContext(pg_trigger, trg); + CatalogSetForm(pg_trigger, trg, triggerTuple); - if (tgForm->tgconstrindid != oldIndexId) + if (CatalogGetFormField(trg, tgconstrindid) != oldIndexId) continue; /* Make a modifiable copy */ triggerTuple = heap_copytuple(triggerTuple); - tgForm = (Form_pg_trigger) GETSTRUCT(triggerTuple); - - tgForm->tgconstrindid = newIndexId; + CatalogSetForm(pg_trigger, trg, triggerTuple); - CatalogTupleUpdate(pg_trigger, &triggerTuple->t_self, triggerTuple); - - heap_freetuple(triggerTuple); + CatalogTupleUpdateField(trg, pg_trigger, tgconstrindid, newIndexId); + ModifyCatalogTupleField(pg_trigger, triggerTuple, trg); } systable_endscan(scan); @@ -1729,14 +1719,12 @@ index_concurrently_swap(Oid newIndexId, Oid oldIndexId, const char *oldName) { Relation description; ScanKeyData skey[3]; - SysScanDesc sd; HeapTuple tuple; - Datum values[Natts_pg_description] = {0}; - bool nulls[Natts_pg_description] = {0}; - bool replaces[Natts_pg_description] = {0}; + SysScanDesc sd; + + CatalogUpdateValuesContext(pg_description, des); - values[Anum_pg_description_objoid - 1] = ObjectIdGetDatum(newIndexId); - replaces[Anum_pg_description_objoid - 1] = true; + CatalogTupleUpdateValue(des, pg_description, objoid, ObjectIdGetDatum(newIndexId)); ScanKeyInit(&skey[0], Anum_pg_description_objoid, @@ -1758,10 +1746,7 @@ 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); - + ModifyCatalogTupleValues(description, tuple, des); break; /* Assume there can be only one match */ } @@ -2061,6 +2046,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 +2058,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 +2088,7 @@ index_constraint_create(Relation heapRelation, heap_freetuple(indexTuple); table_close(pg_index, RowExclusiveLock); + bms_free(updated); } return myself; @@ -3130,6 +3117,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 +3130,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 +3494,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 +3513,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 +3537,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 +3553,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 +3841,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 +3858,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 +3877,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/indexing.c b/src/backend/catalog/indexing.c index 004c5121000fe..4553158a21ae0 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,44 @@ 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. + * + * 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, updated, &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 +365,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/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_aggregate.c b/src/backend/catalog/pg_aggregate.c index a1cb5719a0c6d..0519241cbf0e6 100644 --- a/src/backend/catalog/pg_aggregate.c +++ b/src/backend/catalog/pg_aggregate.c @@ -79,9 +79,6 @@ 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]; Form_pg_proc proc; Oid transfn; Oid finalfn = InvalidOid; /* can be omitted */ @@ -100,14 +97,14 @@ AggregateCreate(const char *aggName, int nargs_transfn; int nargs_finalfn; Oid procOid; - TupleDesc tupDesc; char *detailmsg; - int i; ObjectAddress myself, referenced; ObjectAddresses *addrs; AclResult aclresult; + CatalogUpdateValuesContext(pg_aggregate, ctx); + /* sanity checks (caller should have caught these) */ if (!aggName) elog(ERROR, "no aggregate name supplied"); @@ -584,7 +581,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) @@ -648,43 +645,36 @@ AggregateCreate(const char *aggName, * Okay to create the pg_aggregate entry. */ aggdesc = table_open(AggregateRelationId, RowExclusiveLock); - 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); + CatalogTupleUpdateValue(ctx, pg_aggregate, aggfnoid, ObjectIdGetDatum(procOid)); + CatalogTupleUpdateValue(ctx, pg_aggregate, aggkind, CharGetDatum(aggKind)); + CatalogTupleUpdateValue(ctx, pg_aggregate, aggnumdirectargs, Int16GetDatum(numDirectArgs)); + CatalogTupleUpdateValue(ctx, pg_aggregate, aggtransfn, ObjectIdGetDatum(transfn)); + CatalogTupleUpdateValue(ctx, pg_aggregate, aggfinalfn, ObjectIdGetDatum(finalfn)); + CatalogTupleUpdateValue(ctx, pg_aggregate, aggcombinefn, ObjectIdGetDatum(combinefn)); + CatalogTupleUpdateValue(ctx, pg_aggregate, aggserialfn, ObjectIdGetDatum(serialfn)); + CatalogTupleUpdateValue(ctx, pg_aggregate, aggdeserialfn, ObjectIdGetDatum(deserialfn)); + CatalogTupleUpdateValue(ctx, pg_aggregate, aggmtransfn, ObjectIdGetDatum(mtransfn)); + CatalogTupleUpdateValue(ctx, pg_aggregate, aggminvtransfn, ObjectIdGetDatum(minvtransfn)); + CatalogTupleUpdateValue(ctx, pg_aggregate, aggmfinalfn, ObjectIdGetDatum(mfinalfn)); + CatalogTupleUpdateValue(ctx, pg_aggregate, aggfinalextra, BoolGetDatum(finalfnExtraArgs)); + CatalogTupleUpdateValue(ctx, pg_aggregate, aggmfinalextra, BoolGetDatum(mfinalfnExtraArgs)); + CatalogTupleUpdateValue(ctx, pg_aggregate, aggfinalmodify, CharGetDatum(finalfnModify)); + CatalogTupleUpdateValue(ctx, pg_aggregate, aggmfinalmodify, CharGetDatum(mfinalfnModify)); + CatalogTupleUpdateValue(ctx, pg_aggregate, aggsortop, ObjectIdGetDatum(sortop)); + CatalogTupleUpdateValue(ctx, pg_aggregate, aggtranstype, ObjectIdGetDatum(aggTransType)); + CatalogTupleUpdateValue(ctx, pg_aggregate, aggtransspace, Int32GetDatum(aggTransSpace)); + CatalogTupleUpdateValue(ctx, pg_aggregate, aggmtranstype, ObjectIdGetDatum(aggmTransType)); + CatalogTupleUpdateValue(ctx, pg_aggregate, aggmtransspace, Int32GetDatum(aggmTransSpace)); if (agginitval) - values[Anum_pg_aggregate_agginitval - 1] = CStringGetTextDatum(agginitval); + CatalogTupleUpdateValue(ctx, pg_aggregate, agginitval, CStringGetTextDatum(agginitval)); else - nulls[Anum_pg_aggregate_agginitval - 1] = true; + CatalogTupleUpdateValueNull(ctx, pg_aggregate, agginitval); if (aggminitval) - values[Anum_pg_aggregate_aggminitval - 1] = CStringGetTextDatum(aggminitval); + CatalogTupleUpdateValue(ctx, pg_aggregate, aggminitval, CStringGetTextDatum(aggminitval)); else - nulls[Anum_pg_aggregate_aggminitval - 1] = true; + CatalogTupleUpdateValueNull(ctx, pg_aggregate, aggminitval); if (replace) oldtup = SearchSysCache1(AGGFNOID, ObjectIdGetDatum(procOid)); @@ -717,18 +707,12 @@ 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); + ModifyCatalogTupleValues(aggdesc, oldtup, ctx); ReleaseSysCache(oldtup); } else { - tup = heap_form_tuple(tupDesc, values, nulls); - CatalogTupleInsert(aggdesc, tup); + InsertCatalogTupleValues(aggdesc, ctx); } table_close(aggdesc, RowExclusiveLock); diff --git a/src/backend/catalog/pg_attrdef.c b/src/backend/catalog/pg_attrdef.c index 29f5691bee9e0..865980213dae2 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 @@ -215,6 +212,7 @@ RemoveAttrDefaultById(Oid attrdefId) HeapTuple tuple; Oid myrelid; AttrNumber myattnum; + Bitmapset *updated = NULL; /* Grab an appropriate lock on the pg_attrdef relation */ attrdef_rel = table_open(AttrDefaultRelationId, RowExclusiveLock); @@ -255,8 +253,8 @@ RemoveAttrDefaultById(Oid attrdefId) myattnum, myrelid); ((Form_pg_attribute) GETSTRUCT(tuple))->atthasdef = false; - - CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple); + HeapTupleMarkColumnUpdated(pg_attribute, atthasdef, updated); + CatalogTupleUpdate(attr_rel, &tuple->t_self, tuple, updated, 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..d70c762e435c5 100644 --- a/src/backend/catalog/pg_cast.c +++ b/src/backend/catalog/pg_cast.c @@ -14,6 +14,7 @@ */ #include "postgres.h" +#include "access/htup.h" #include "access/htup_details.h" #include "access/table.h" #include "catalog/catalog.h" @@ -53,12 +54,12 @@ CastCreate(Oid sourcetypeid, Oid targettypeid, Relation relation; HeapTuple tuple; Oid castid; - Datum values[Natts_pg_cast]; - bool nulls[Natts_pg_cast] = {0}; ObjectAddress myself, referenced; ObjectAddresses *addrs; + CatalogInsertValuesContext(pg_cast, ctx); + relation = table_open(CastRelationId, RowExclusiveLock); /* @@ -78,16 +79,14 @@ 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); - - tuple = heap_form_tuple(RelationGetDescr(relation), values, nulls); + CatalogTupleSetValue(ctx, pg_cast, oid, ObjectIdGetDatum(castid)); + CatalogTupleSetValue(ctx, pg_cast, castsource, ObjectIdGetDatum(sourcetypeid)); + CatalogTupleSetValue(ctx, pg_cast, casttarget, ObjectIdGetDatum(targettypeid)); + CatalogTupleSetValue(ctx, pg_cast, castfunc, ObjectIdGetDatum(funcid)); + CatalogTupleSetValue(ctx, pg_cast, castcontext, CharGetDatum(castcontext)); + CatalogTupleSetValue(ctx, pg_cast, castmethod, CharGetDatum(castmethod)); - CatalogTupleInsert(relation, tuple); + InsertCatalogTupleValues(relation, ctx); addrs = new_object_addresses(); @@ -130,8 +129,6 @@ CastCreate(Oid sourcetypeid, Oid targettypeid, /* Post creation hook for new cast */ InvokeObjectPostCreateHook(CastRelationId, castid, 0); - heap_freetuple(tuple); - table_close(relation, RowExclusiveLock); return myself; 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_constraint.c b/src/backend/catalog/pg_constraint.c index 9944e4bd2d10e..b0f9d03538939 100644 --- a/src/backend/catalog/pg_constraint.c +++ b/src/backend/catalog/pg_constraint.c @@ -84,9 +84,6 @@ CreateConstraintEntry(const char *constraintName, { Relation conDesc; Oid conOid; - HeapTuple tup; - bool nulls[Natts_pg_constraint]; - Datum values[Natts_pg_constraint]; ArrayType *conkeyArray; ArrayType *confkeyArray; ArrayType *conpfeqopArray; @@ -100,6 +97,8 @@ CreateConstraintEntry(const char *constraintName, ObjectAddresses *addrs_auto; ObjectAddresses *addrs_normal; + CatalogInsertValuesContext(pg_constraint, ctx); + /* Only CHECK or FOREIGN KEY constraint can be not enforced */ Assert(isEnforced || constraintType == CONSTRAINT_CHECK || constraintType == CONSTRAINT_FOREIGN); @@ -175,79 +174,70 @@ CreateConstraintEntry(const char *constraintName, else conexclopArray = NULL; - /* initialize nulls and values */ - for (i = 0; i < Natts_pg_constraint; i++) - { - nulls[i] = false; - values[i] = (Datum) 0; - } - 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); + CatalogTupleSetValue(ctx, pg_constraint, oid, ObjectIdGetDatum(conOid)); + CatalogTupleSetValue(ctx, pg_constraint, conname, NameGetDatum(&cname)); + CatalogTupleSetValue(ctx, pg_constraint, connamespace, ObjectIdGetDatum(constraintNamespace)); + CatalogTupleSetValue(ctx, pg_constraint, contype, CharGetDatum(constraintType)); + CatalogTupleSetValue(ctx, pg_constraint, condeferrable, BoolGetDatum(isDeferrable)); + CatalogTupleSetValue(ctx, pg_constraint, condeferred, BoolGetDatum(isDeferred)); + CatalogTupleSetValue(ctx, pg_constraint, conenforced, BoolGetDatum(isEnforced)); + CatalogTupleSetValue(ctx, pg_constraint, convalidated, BoolGetDatum(isValidated)); + CatalogTupleSetValue(ctx, pg_constraint, conrelid, ObjectIdGetDatum(relId)); + CatalogTupleSetValue(ctx, pg_constraint, contypid, ObjectIdGetDatum(domainId)); + CatalogTupleSetValue(ctx, pg_constraint, conindid, ObjectIdGetDatum(indexRelId)); + CatalogTupleSetValue(ctx, pg_constraint, conparentid, ObjectIdGetDatum(parentConstrId)); + CatalogTupleSetValue(ctx, pg_constraint, confrelid, ObjectIdGetDatum(foreignRelId)); + CatalogTupleSetValue(ctx, pg_constraint, confupdtype, CharGetDatum(foreignUpdateType)); + CatalogTupleSetValue(ctx, pg_constraint, confdeltype, CharGetDatum(foreignDeleteType)); + CatalogTupleSetValue(ctx, pg_constraint, confmatchtype, CharGetDatum(foreignMatchType)); + CatalogTupleSetValue(ctx, pg_constraint, conislocal, BoolGetDatum(conIsLocal)); + CatalogTupleSetValue(ctx, pg_constraint, coninhcount, Int16GetDatum(conInhCount)); + CatalogTupleSetValue(ctx, pg_constraint, connoinherit, BoolGetDatum(conNoInherit)); + CatalogTupleSetValue(ctx, pg_constraint, conperiod, BoolGetDatum(conPeriod)); if (conkeyArray) - values[Anum_pg_constraint_conkey - 1] = PointerGetDatum(conkeyArray); + CatalogTupleSetValue(ctx, pg_constraint, conkey, PointerGetDatum(conkeyArray)); else - nulls[Anum_pg_constraint_conkey - 1] = true; + CatalogTupleSetValueNull(ctx, pg_constraint, conkey); if (confkeyArray) - values[Anum_pg_constraint_confkey - 1] = PointerGetDatum(confkeyArray); + CatalogTupleSetValue(ctx, pg_constraint, confkey, PointerGetDatum(confkeyArray)); else - nulls[Anum_pg_constraint_confkey - 1] = true; + CatalogTupleSetValueNull(ctx, pg_constraint, confkey); if (conpfeqopArray) - values[Anum_pg_constraint_conpfeqop - 1] = PointerGetDatum(conpfeqopArray); + CatalogTupleSetValue(ctx, pg_constraint, conpfeqop, PointerGetDatum(conpfeqopArray)); else - nulls[Anum_pg_constraint_conpfeqop - 1] = true; + CatalogTupleSetValueNull(ctx, pg_constraint, conpfeqop); if (conppeqopArray) - values[Anum_pg_constraint_conppeqop - 1] = PointerGetDatum(conppeqopArray); + CatalogTupleSetValue(ctx, pg_constraint, conppeqop, PointerGetDatum(conppeqopArray)); else - nulls[Anum_pg_constraint_conppeqop - 1] = true; + CatalogTupleSetValueNull(ctx, pg_constraint, conppeqop); if (conffeqopArray) - values[Anum_pg_constraint_conffeqop - 1] = PointerGetDatum(conffeqopArray); + CatalogTupleSetValue(ctx, pg_constraint, conffeqop, PointerGetDatum(conffeqopArray)); else - nulls[Anum_pg_constraint_conffeqop - 1] = true; + CatalogTupleSetValueNull(ctx, pg_constraint, conffeqop); if (confdelsetcolsArray) - values[Anum_pg_constraint_confdelsetcols - 1] = PointerGetDatum(confdelsetcolsArray); + CatalogTupleSetValue(ctx, pg_constraint, confdelsetcols, PointerGetDatum(confdelsetcolsArray)); else - nulls[Anum_pg_constraint_confdelsetcols - 1] = true; + CatalogTupleSetValueNull(ctx, pg_constraint, confdelsetcols); if (conexclopArray) - values[Anum_pg_constraint_conexclop - 1] = PointerGetDatum(conexclopArray); + CatalogTupleSetValue(ctx, pg_constraint, conexclop, PointerGetDatum(conexclopArray)); else - nulls[Anum_pg_constraint_conexclop - 1] = true; + CatalogTupleSetValueNull(ctx, pg_constraint, conexclop); if (conBin) - values[Anum_pg_constraint_conbin - 1] = CStringGetTextDatum(conBin); + CatalogTupleSetValue(ctx, pg_constraint, conbin, CStringGetTextDatum(conBin)); else - nulls[Anum_pg_constraint_conbin - 1] = true; + CatalogTupleSetValueNull(ctx, pg_constraint, conbin); - tup = heap_form_tuple(RelationGetDescr(conDesc), values, nulls); - - CatalogTupleInsert(conDesc, tup); + InsertCatalogTupleValues(conDesc, ctx); ObjectAddressSet(conobject, ConstraintRelationId, conOid); @@ -747,21 +737,21 @@ AdjustNotNullInheritance(Oid relid, AttrNumber attnum, if (HeapTupleIsValid(tup)) { Relation pg_constraint; - Form_pg_constraint conform; - bool changed = false; + + CatalogUpdateFormContext(pg_constraint, ctx); + CatalogSetForm(pg_constraint, ctx, tup); pg_constraint = table_open(ConstraintRelationId, RowExclusiveLock); - conform = (Form_pg_constraint) GETSTRUCT(tup); /* * If the NO INHERIT flag we're asked for doesn't match what the * existing constraint has, throw an error. */ - if (is_no_inherit != conform->connoinherit) + if (is_no_inherit != CatalogGetFormField(ctx, connoinherit)) ereport(ERROR, errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("cannot change NO INHERIT status of NOT NULL constraint \"%s\" on relation \"%s\"", - NameStr(conform->conname), get_rel_name(relid)), + NameStr(CatalogGetFormField(ctx, conname)), get_rel_name(relid)), errhint("You might need to make the existing constraint inheritable using %s.", "ALTER TABLE ... ALTER CONSTRAINT ... INHERIT")); @@ -769,31 +759,29 @@ AdjustNotNullInheritance(Oid relid, AttrNumber attnum, * Throw an error if the existing constraint is NOT VALID and caller * wants a valid one. */ - if (!is_notvalid && !conform->convalidated) + if (!is_notvalid && !CatalogGetFormField(ctx, convalidated)) ereport(ERROR, errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("incompatible NOT VALID constraint \"%s\" on relation \"%s\"", - NameStr(conform->conname), get_rel_name(relid)), + NameStr(CatalogGetFormField(ctx, conname)), get_rel_name(relid)), errhint("You might need to validate it using %s.", "ALTER TABLE ... VALIDATE CONSTRAINT")); if (!is_local) { - if (pg_add_s16_overflow(conform->coninhcount, 1, - &conform->coninhcount)) - ereport(ERROR, - errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), - errmsg("too many inheritance parents")); - changed = true; + CatalogTupleCondUpdateField(ctx, pg_constraint, coninhcount, + pg_add_s16_overflow(CatalogGetFormField(ctx, coninhcount), 1, + &CatalogGetFormField(ctx, coninhcount)), + ereport(ERROR, errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), + errmsg("too many inheritance parents"))); } - else if (!conform->conislocal) + else if (!CatalogGetFormField(ctx, conislocal)) { - conform->conislocal = true; - changed = true; + CatalogTupleUpdateField(ctx, pg_constraint, conislocal, true); } - if (changed) - CatalogTupleUpdate(pg_constraint, &tup->t_self, tup); + if (CatalogTupleHasChanged(ctx)) + UpdateCatalogTupleField(pg_constraint, tup, ctx); table_close(pg_constraint, RowExclusiveLock); @@ -928,6 +916,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 +927,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 +979,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 +1010,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 +1064,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 +1110,7 @@ ConstraintSetParentConstraint(Oid childConstrId, newtup; ObjectAddress depender; ObjectAddress referenced; + Bitmapset *updated = NULL; constrRel = table_open(ConstraintRelationId, RowExclusiveLock); tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(childConstrId)); @@ -1131,16 +1126,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 +1148,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 +1165,7 @@ ConstraintSetParentConstraint(Oid childConstrId, DEPENDENCY_PARTITION_SEC); } + bms_free(updated); ReleaseSysCache(tuple); table_close(constrRel, RowExclusiveLock); } 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 d608f37d36188..c582ee83adc19 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" @@ -135,9 +136,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; @@ -318,67 +319,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); @@ -579,13 +574,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; @@ -599,18 +594,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 0994220c53d5b..0172191651494 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..732d1e5409822 100644 --- a/src/backend/catalog/pg_shdepend.c +++ b/src/backend/catalog/pg_shdepend.c @@ -266,38 +266,41 @@ shdepChangeDep(Relation sdepRel, } else if (oldtup) { + Bitmapset *updated = NULL; + /* Need to update existing entry */ Form_pg_shdepend shForm = (Form_pg_shdepend) GETSTRUCT(oldtup); /* Since oldtup is a copy, we can just modify it in-memory */ shForm->refclassid = refclassid; + HeapTupleMarkColumnUpdated(pg_shdepend, refclassid, updated); shForm->refobjid = refobjid; + HeapTupleMarkColumnUpdated(pg_shdepend, refobjid, updated); - CatalogTupleUpdate(sdepRel, &oldtup->t_self, oldtup); + CatalogTupleUpdate(sdepRel, &oldtup->t_self, oldtup, updated, NULL); + bms_free(updated); } else { /* Need to insert new entry */ - Datum values[Natts_pg_shdepend]; - bool nulls[Natts_pg_shdepend]; - - memset(nulls, false, sizeof(nulls)); + Datum values[Natts_pg_shdepend] = {0}; + bool nulls[Natts_pg_shdepend] = {false}; - 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 +958,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 +972,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 +1075,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 +1090,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/alter.c b/src/backend/commands/alter.c index cb75e11fced62..b132301e68360 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 CatalogTuple*() macros here because 'Anum_name' + * isn't a table/field 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 CatalogTuple*() macros 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,10 @@ 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 CatalogTuple() macros 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 +1041,18 @@ AlterObjectOwner_internal(Oid classId, Oid objectId, Oid new_ownerId) newAcl = aclnewowner(DatumGetAclP(datum), old_ownerId, new_ownerId); + + /* NOTE: Don't use the CatalogTuple*() macros 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 +1062,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/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/analyze.c b/src/backend/commands/analyze.c index 25089fae3e006..6fb774133d922 100644 --- a/src/backend/commands/analyze.c +++ b/src/backend/commands/analyze.c @@ -29,6 +29,7 @@ #include "catalog/index.h" #include "catalog/indexing.h" #include "catalog/pg_inherits.h" +#include "catalog/pg_statistic.h" #include "commands/progress.h" #include "commands/tablecmds.h" #include "commands/vacuum.h" @@ -1666,50 +1667,34 @@ update_attstats(Oid relid, bool inh, int natts, VacAttrStats **vacattrstats) for (attno = 0; attno < natts; attno++) { VacAttrStats *stats = vacattrstats[attno]; - HeapTuple stup, - oldtup; - int i, - k, + HeapTuple oldtup; + int k, n; - Datum values[Natts_pg_statistic]; - bool nulls[Natts_pg_statistic]; - bool replaces[Natts_pg_statistic]; + + CatalogUpdateValuesContext(pg_statistic, ctx); /* 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 */ + CatalogTupleUpdateMarkAllColumnsUpdated(ctx, pg_statistic); + CatalogTupleSetValue(ctx, pg_statistic, starelid, ObjectIdGetDatum(relid)); + CatalogTupleSetValue(ctx, pg_statistic, staattnum, Int16GetDatum(stats->tupattnum)); + CatalogTupleSetValue(ctx, pg_statistic, stainherit, BoolGetDatum(inh)); + CatalogTupleSetValue(ctx, pg_statistic, stanullfrac, Float4GetDatum(stats->stanullfrac)); + CatalogTupleSetValue(ctx, pg_statistic, stawidth, Int32GetDatum(stats->stawidth)); + CatalogTupleSetValue(ctx, pg_statistic, stadistinct, Float4GetDatum(stats->stadistinct)); - 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; + CatalogTupleSetValue(ctx, pg_statistic, stakind1 + k, Int16GetDatum(stats->stakind[k])); + for (k = 0; k < STATISTIC_NUM_SLOTS; k++) - { - values[i++] = ObjectIdGetDatum(stats->staop[k]); /* staopN */ - } - i = Anum_pg_statistic_stacoll1 - 1; + CatalogTupleSetValue(ctx, pg_statistic, staop1 + k, ObjectIdGetDatum(stats->staop[k])); + for (k = 0; k < STATISTIC_NUM_SLOTS; k++) - { - values[i++] = ObjectIdGetDatum(stats->stacoll[k]); /* stacollN */ - } - i = Anum_pg_statistic_stanumbers1 - 1; + CatalogTupleSetValue(ctx, pg_statistic, stacoll1 + k, ObjectIdGetDatum(stats->stacoll[k])); + for (k = 0; k < STATISTIC_NUM_SLOTS; k++) { if (stats->stanumbers[k] != NULL) @@ -1721,15 +1706,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 */ + CatalogTupleSetValue(ctx, pg_statistic, stanumbers1 + k, PointerGetDatum(arry)); } else - { - nulls[i] = true; - values[i++] = (Datum) 0; - } + CatalogTupleSetValueNull(ctx, pg_statistic, stanumbers1 + k); } - i = Anum_pg_statistic_stavalues1 - 1; + for (k = 0; k < STATISTIC_NUM_SLOTS; k++) { if (stats->stavalues[k] != NULL) @@ -1742,12 +1724,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 */ + CatalogTupleSetValue(ctx, pg_statistic, stavalues1 + k, PointerGetDatum(arry)); } else { - nulls[i] = true; - values[i++] = (Datum) 0; + CatalogTupleSetValueNull(ctx, pg_statistic, stavalues1 + k); } } @@ -1761,29 +1742,26 @@ update_attstats(Oid relid, bool inh, int natts, VacAttrStats **vacattrstats) if (indstate == NULL) indstate = CatalogOpenIndexes(sd); + ctx->idx = indstate; + if (HeapTupleIsValid(oldtup)) { - /* Yes, replace it */ - stup = heap_modify_tuple(oldtup, - RelationGetDescr(sd), - values, - nulls, - replaces); + /* Yes, replace existing tuple */ + ModifyCatalogTupleValues(sd, oldtup, ctx); ReleaseSysCache(oldtup); - CatalogTupleUpdateWithInfo(sd, &stup->t_self, stup, indstate); } else { /* No, insert new tuple */ - stup = heap_form_tuple(RelationGetDescr(sd), values, nulls); - CatalogTupleInsertWithInfo(sd, stup, indstate); + InsertCatalogTupleValues(sd, ctx); } - heap_freetuple(stup); + CatalogTupleReuseUpdateContext(ctx); } if (indstate != NULL) CatalogCloseIndexes(indstate); + table_close(sd, RowExclusiveLock); } 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..c3d8c86c05c84 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; @@ -459,6 +460,7 @@ AlterCollation(AlterCollationStmt *stmt) datum = SysCacheGetAttrNotNull(COLLOID, tup, Anum_pg_collation_collcollate); else datum = SysCacheGetAttrNotNull(COLLOID, tup, Anum_pg_collation_colllocale); + HeapTupleMarkColumnUpdated(pg_collation, collcollate, updated); newversion = get_collation_actual_version(collForm->collprovider, TextDatumGetCString(datum)); @@ -468,29 +470,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 +493,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 ebc204c446213..597207f0e2719 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 59d00638ee614..818babacbbe65 100644 --- a/src/backend/commands/functioncmds.c +++ b/src/backend/commands/functioncmds.c @@ -1377,6 +1377,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); @@ -1425,14 +1426,25 @@ AlterFunction(ParseState *pstate, AlterFunctionStmt *stmt) } if (volatility_item) + { procForm->provolatile = interpret_func_volatility(volatility_item); + HeapTupleMarkColumnUpdated(pg_proc, provolatile, updated); + } + if (strict_item) + { procForm->proisstrict = boolVal(strict_item->arg); + HeapTupleMarkColumnUpdated(pg_proc, proisstrict, updated); + } if (security_def_item) + { procForm->prosecdef = boolVal(security_def_item->arg); + HeapTupleMarkColumnUpdated(pg_proc, prosecdef, updated); + } if (leakproof_item) { procForm->proleakproof = boolVal(leakproof_item->arg); + HeapTupleMarkColumnUpdated(pg_proc, proleakproof, updated); if (procForm->proleakproof && !superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), @@ -1441,6 +1453,7 @@ AlterFunction(ParseState *pstate, AlterFunctionStmt *stmt) if (cost_item) { procForm->procost = defGetNumeric(cost_item); + HeapTupleMarkColumnUpdated(pg_proc, procost, updated); if (procForm->procost <= 0) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1449,6 +1462,7 @@ AlterFunction(ParseState *pstate, AlterFunctionStmt *stmt) if (rows_item) { procForm->prorows = defGetNumeric(rows_item); + HeapTupleMarkColumnUpdated(pg_proc, prorows, updated); if (procForm->prorows <= 0) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1483,17 +1497,20 @@ AlterFunction(ParseState *pstate, AlterFunctionStmt *stmt) } procForm->prosupport = newsupport; + HeapTupleMarkColumnUpdated(pg_proc, prosupport, updated); } if (parallel_item) + { procForm->proparallel = interpret_func_parallel(parallel_item); + HeapTupleMarkColumnUpdated(pg_proc, proparallel, updated); + } if (set_items) { 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); @@ -1503,27 +1520,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); @@ -1840,9 +1849,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; @@ -1943,10 +1952,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); @@ -1964,11 +1973,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); @@ -1978,9 +1984,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; } @@ -2022,6 +2028,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 a8033be4bffb1..186d5f2dbf527 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); @@ -4579,6 +4583,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)); @@ -4586,8 +4592,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 51567994126f4..3f3eca341799d 100644 --- a/src/backend/commands/sequence.c +++ b/src/backend/commands/sequence.c @@ -125,8 +125,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; /* @@ -221,17 +221,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); @@ -444,6 +444,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, @@ -525,8 +526,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 77b1a6e2dc51f..a041056b38f60 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; @@ -531,22 +531,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); @@ -642,9 +642,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; @@ -719,23 +719,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); @@ -746,6 +739,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 24b70234b3559..21709ea5c0176 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..f8ade7482bec7 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,10 @@ 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); + HeapTupleMarkColumnUpdated(pg_attribute, attname, updated); + CatalogTupleUpdate(attrelation, &atttup->t_self, atttup, updated, NULL); + bms_free(updated); InvokeObjectPostAlterHook(RelationRelationId, myrelid, attnum); @@ -4267,6 +4279,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 +4325,12 @@ 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); + HeapTupleMarkColumnUpdated(pg_class, relname, updated); + CatalogTupleUpdate(relrelation, &otid, reltup, updated, NULL); + bms_free(updated); + UnlockTuple(relrelation, &otid, InplaceUpdateTupleLock); InvokeObjectPostAlterHookArg(RelationRelationId, myrelid, 0, @@ -4357,6 +4373,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 +4385,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 +7242,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 +7302,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 +7406,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 +7873,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 +7887,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 +7968,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 +7992,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 +8016,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 +8265,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 +8346,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 +8461,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 +8520,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 +8569,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 +8833,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 +8887,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 +8941,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 +9046,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 +9086,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 +9118,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 +9189,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 +9224,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 +9244,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 +9261,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 +9455,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 +9472,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 +12689,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 +12749,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 +12776,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 +12898,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 +12908,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 +12917,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 +13049,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 +13146,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 +13179,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 +13253,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 +13283,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 +13360,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 +14242,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 +14379,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 +14399,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 +14817,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 +14994,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 +15013,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 +15102,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel, RelationGetRelid(rel), attnum); /* Cleanup */ + bms_free(updated); heap_freetuple(heapTup); return address; @@ -15956,9 +16038,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 +16082,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 +16097,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 +16117,7 @@ ATExecAlterColumnGenericOptions(Relation rel, table_close(attrel, RowExclusiveLock); + bms_free(updated); heap_freetuple(newtuple); return address; @@ -16169,13 +16244,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 +16278,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 +16291,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 +16390,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 +16410,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 +16589,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 +16607,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 +16666,7 @@ ATExecSetAccessMethodNoStorage(Relation rel, Oid newAccessMethodId) InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), 0); + bms_free(updated); heap_freetuple(tuple); table_close(pg_class, RowExclusiveLock); } @@ -16643,9 +16714,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 +16818,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 +16876,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 +17566,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 +17651,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 +17661,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 +17729,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 +17838,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 +17848,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 +17957,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 +17972,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 +18068,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 +18083,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 +18152,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 +18198,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 +18311,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 +18417,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 +18445,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 +18466,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 +18511,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 +18528,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 +18542,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 +18551,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 +18570,7 @@ relation_mark_replica_identity(Relation rel, char ri_type, Oid indexOid, */ CacheInvalidateRelcache(rel); } + bms_free(updated); heap_freetuple(pg_index_tuple); } @@ -18596,6 +18700,7 @@ ATExecSetRowSecurity(Relation rel, bool rls) Relation pg_class; Oid relid; HeapTuple tuple; + Bitmapset *updated = NULL; relid = RelationGetRelid(rel); @@ -18607,13 +18712,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 +18732,7 @@ ATExecForceNoForceRowSecurity(Relation rel, bool force_rls) Relation pg_class; Oid relid; HeapTuple tuple; + Bitmapset *updated = NULL; relid = RelationGetRelid(rel); @@ -18636,13 +18743,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 +18765,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 +18787,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 +18802,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 +18824,7 @@ ATExecGenericOptions(Relation rel, List *options) table_close(ftrel, RowExclusiveLock); + bms_free(updated); heap_freetuple(tuple); } @@ -18743,6 +18846,7 @@ ATExecSetCompression(Relation rel, char *compression; char cmethod; ObjectAddress address; + Bitmapset *updated = NULL; compression = strVal(newValue); @@ -18771,8 +18875,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 +18891,7 @@ ATExecSetCompression(Relation rel, true, cmethod, lockmode); + bms_free(updated); heap_freetuple(tuple); table_close(attrel, RowExclusiveLock); @@ -19050,6 +19155,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 +19189,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 +21184,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 +21436,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 +21862,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 +21915,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..2678dfe3f702f 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); @@ -1632,8 +1631,8 @@ renametrig_internal(Relation tgrel, Relation targetrel, HeapTuple trigtup, RelationGetRelationName(targetrel))); namestrcpy(&tgform->tgname, newname); - - CatalogTupleUpdate(tgrel, &tuple->t_self, tuple); + HeapTupleMarkColumnUpdated(pg_trigger, tgname, updated); + 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 47d5047fe8b1d..eb20b251f55ef 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -2623,9 +2623,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; @@ -2673,10 +2673,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 { @@ -2691,27 +2689,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, @@ -2731,6 +2723,7 @@ AlterDomainDefault(List *names, Node *defaultRaw) /* Clean up */ table_close(rel, RowExclusiveLock); heap_freetuple(newtuple); + bms_free(updated); return address; } @@ -2751,6 +2744,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); @@ -2806,9 +2800,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); @@ -2817,6 +2811,7 @@ AlterDomainNotNull(List *names, bool notNull) /* Clean up */ heap_freetuple(tup); table_close(typrel, RowExclusiveLock); + bms_free(updated); return address; } @@ -2842,6 +2837,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); @@ -2885,8 +2881,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; @@ -2925,6 +2921,7 @@ AlterDomainDropConstraint(List *names, const char *constrName, /* Clean up */ table_close(rel, RowExclusiveLock); + bms_free(updated); return address; } @@ -2946,6 +2943,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); @@ -3014,14 +3012,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; } @@ -3048,6 +3047,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); @@ -3113,8 +3113,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); @@ -3128,6 +3128,7 @@ AlterDomainValidateConstraint(List *names, const char *constrName) table_close(conrel, RowExclusiveLock); ReleaseSysCache(tup); + bms_free(updated); return address; } @@ -4002,9 +4003,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; @@ -4016,11 +4017,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, @@ -4031,14 +4028,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)) @@ -4059,6 +4054,7 @@ AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId) /* Clean up */ table_close(rel, RowExclusiveLock); + bms_free(updated); } /* @@ -4179,6 +4175,7 @@ AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, Oid arrayOid; bool isCompositeType; ObjectAddress thisobj; + Bitmapset *updated = NULL; /* * Make sure we haven't moved this object previously. @@ -4244,9 +4241,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); } /* @@ -4310,6 +4307,7 @@ AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, true, /* errorOnTableType */ objsMoved); + bms_free(updated); return oldNspOid; } @@ -4577,9 +4575,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]; @@ -4589,50 +4587,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, @@ -4717,4 +4690,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 fa8e3bf969a92..495345feed968 100644 --- a/src/backend/replication/logical/tablesync.c +++ b/src/backend/replication/logical/tablesync.c @@ -1652,9 +1652,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 || @@ -1667,19 +1667,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..9cd3e35d9486a 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,9 @@ RenameRewriteRule(RangeVar *relation, const char *oldName, /* OK, do the update */ namestrcpy(&(ruleform->rulename), newName); - - CatalogTupleUpdate(pg_rewrite_desc, &ruletup->t_self, ruletup); + HeapTupleMarkColumnUpdated(pg_rewrite, rulename, updated); + 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/attribute_stats.c b/src/backend/statistics/attribute_stats.c index ef4d768feab7e..fd4a25326b388 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,13 @@ 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, +static void set_stats_slot(void *_ctx, 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); +static void upsert_pg_statistic(Relation starel, HeapTuple oldtup, void *_ctx); 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 void init_empty_stats_tuple(Oid reloid, int16 attnum, bool inherited, void *_ctx); /* * Insert or Update Attribute Statistics @@ -182,13 +181,10 @@ attribute_statistics_update(FunctionCallInfo fcinfo) bool do_bounds_histogram = !PG_ARGISNULL(RANGE_BOUNDS_HISTOGRAM_ARG); bool do_range_length_histogram = !PG_ARGISNULL(RANGE_LENGTH_HISTOGRAM_ARG) && !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 result = true; + CatalogUpdateValuesContext(pg_statistic, ctx); + stats_check_required_arg(fcinfo, attarginfo, ATTRELSCHEMA_ARG); stats_check_required_arg(fcinfo, attarginfo, ATTRELNAME_ARG); @@ -359,27 +355,19 @@ attribute_statistics_update(FunctionCallInfo fcinfo) /* initialize from existing tuple if exists */ if (HeapTupleIsValid(statup)) - heap_deform_tuple(statup, RelationGetDescr(starel), values, nulls); + DeformCatalogTuple(starel, statup, ctx); else - init_empty_stats_tuple(reloid, attnum, inherited, values, nulls, - replaces); + init_empty_stats_tuple(reloid, attnum, inherited, (void *) ctx); /* 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; - } + CatalogTupleUpdateValue(ctx, pg_statistic, stanullfrac, PG_GETARG_DATUM(NULL_FRAC_ARG)); + 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; - } + CatalogTupleUpdateValue(ctx, pg_statistic, stawidth, PG_GETARG_DATUM(AVG_WIDTH_ARG)); + 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; - } + CatalogTupleUpdateValue(ctx, pg_statistic, stadistinct, PG_GETARG_DATUM(N_DISTINCT_ARG)); /* STATISTIC_KIND_MCV */ if (do_mcv) @@ -394,7 +382,7 @@ attribute_statistics_update(FunctionCallInfo fcinfo) if (converted) { - set_stats_slot(values, nulls, replaces, + set_stats_slot(ctx, STATISTIC_KIND_MCV, eq_opr, atttypcoll, stanumbers, false, stavalues, false); @@ -417,7 +405,7 @@ attribute_statistics_update(FunctionCallInfo fcinfo) if (converted) { - set_stats_slot(values, nulls, replaces, + set_stats_slot(ctx, STATISTIC_KIND_HISTOGRAM, lt_opr, atttypcoll, 0, true, stavalues, false); @@ -433,7 +421,7 @@ attribute_statistics_update(FunctionCallInfo fcinfo) ArrayType *arry = construct_array_builtin(elems, 1, FLOAT4OID); Datum stanumbers = PointerGetDatum(arry); - set_stats_slot(values, nulls, replaces, + set_stats_slot(ctx, STATISTIC_KIND_CORRELATION, lt_opr, atttypcoll, stanumbers, false, 0, true); @@ -454,7 +442,7 @@ attribute_statistics_update(FunctionCallInfo fcinfo) if (converted) { - set_stats_slot(values, nulls, replaces, + set_stats_slot(ctx, STATISTIC_KIND_MCELEM, elem_eq_opr, atttypcoll, stanumbers, false, stavalues, false); @@ -468,7 +456,7 @@ attribute_statistics_update(FunctionCallInfo fcinfo) { Datum stanumbers = PG_GETARG_DATUM(ELEM_COUNT_HISTOGRAM_ARG); - set_stats_slot(values, nulls, replaces, + set_stats_slot(ctx, STATISTIC_KIND_DECHIST, elem_eq_opr, atttypcoll, stanumbers, false, 0, true); @@ -494,7 +482,7 @@ attribute_statistics_update(FunctionCallInfo fcinfo) if (converted) { - set_stats_slot(values, nulls, replaces, + set_stats_slot(ctx, STATISTIC_KIND_BOUNDS_HISTOGRAM, InvalidOid, InvalidOid, 0, true, stavalues, false); @@ -521,7 +509,7 @@ attribute_statistics_update(FunctionCallInfo fcinfo) if (converted) { - set_stats_slot(values, nulls, replaces, + set_stats_slot(ctx, STATISTIC_KIND_RANGE_LENGTH_HISTOGRAM, Float8LessOperator, InvalidOid, stanumbers, false, stavalues, false); @@ -530,7 +518,7 @@ attribute_statistics_update(FunctionCallInfo fcinfo) result = false; } - upsert_pg_statistic(starel, statup, values, nulls, replaces); + upsert_pg_statistic(starel, statup, ctx); if (HeapTupleIsValid(statup)) ReleaseSysCache(statup); @@ -760,92 +748,75 @@ text_to_stavalues(const char *staname, FmgrInfo *array_in, Datum d, Oid typid, * slot. */ static void -set_stats_slot(Datum *values, bool *nulls, bool *replaces, +set_stats_slot(void *_ctx, int16 stakind, Oid staop, Oid stacoll, Datum stanumbers, bool stanumbers_isnull, Datum stavalues, bool stavalues_isnull) { - int slotidx; + CatalogUpdateValuesDecl(pg_statistic, ctx) * ctx = _ctx; + 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++) + /* + * 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: CatalogTupleValue(ctx, pg_statistic, stakind1 + i); + * + * Becomes: ctx.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 = CatalogTupleValue(ctx, pg_statistic, stakind1 + i); + 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(CatalogTupleValue(ctx, pg_statistic, stakind1 + i)) != stakind) + CatalogTupleUpdateValue(ctx, pg_statistic, stakind1 + i, Int16GetDatum(stakind)); + + if (DatumGetInt16(CatalogTupleValue(ctx, pg_statistic, staop1 + i)) != staop) + CatalogTupleUpdateValue(ctx, pg_statistic, staop1 + i, ObjectIdGetDatum(staop)); + + if (DatumGetInt16(CatalogTupleValue(ctx, pg_statistic, stacoll1 + i)) != stacoll) + CatalogTupleUpdateValue(ctx, pg_statistic, stacoll1 + i, ObjectIdGetDatum(stacoll)); - 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; - } + CatalogTupleUpdateValue(ctx, pg_statistic, stanumbers1 + i, stanumbers); + 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; - } + CatalogTupleUpdateValue(ctx, pg_statistic, stavalues1 + i, stavalues); } /* * Upsert the pg_statistic record. */ static void -upsert_pg_statistic(Relation starel, HeapTuple oldtup, - const Datum *values, const bool *nulls, const bool *replaces) +upsert_pg_statistic(Relation starel, HeapTuple oldtup, void *_ctx) { - HeapTuple newtup; + CatalogUpdateValuesDecl(pg_statistic, ctx) * ctx = _ctx; if (HeapTupleIsValid(oldtup)) - { - newtup = heap_modify_tuple(oldtup, RelationGetDescr(starel), - values, nulls, replaces); - CatalogTupleUpdate(starel, &newtup->t_self, newtup); - } + ModifyCatalogTupleValues(starel, oldtup, ctx); else - { - newtup = heap_form_tuple(RelationGetDescr(starel), values, nulls); - CatalogTupleInsert(starel, newtup); - } - - heap_freetuple(newtup); + InsertCatalogTupleValues(starel, ctx); CommandCounterIncrement(); } @@ -884,37 +855,28 @@ delete_pg_statistic(Oid reloid, AttrNumber attnum, bool stainherit) * Initialize values and nulls for a new stats tuple. */ static void -init_empty_stats_tuple(Oid reloid, int16 attnum, bool inherited, - Datum *values, bool *nulls, bool *replaces) +init_empty_stats_tuple(Oid reloid, int16 attnum, bool inherited, void *_ctx) { - memset(nulls, true, sizeof(bool) * Natts_pg_statistic); - memset(replaces, true, sizeof(bool) * Natts_pg_statistic); + CatalogUpdateValuesDecl(pg_statistic, ctx) * ctx = (struct _cat_pg_statistic_ctx_upd_vals *) _ctx; - /* must initialize non-NULL attributes */ + CatalogTupleUpdateMarkAllColumnsUpdated(ctx, pg_statistic); + memset(ctx->nulls, true, sizeof(bool) * Natts_pg_statistic); - 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; + /* Now we must initialize non-NULL attributes */ + CatalogTupleUpdateValue(ctx, pg_statistic, starelid, ObjectIdGetDatum(reloid)); + CatalogTupleUpdateValue(ctx, pg_statistic, staattnum, Int16GetDatum(attnum)); + CatalogTupleUpdateValue(ctx, pg_statistic, stainherit, BoolGetDatum(inherited)); - 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; + CatalogTupleUpdateValue(ctx, pg_statistic, stanullfrac, DEFAULT_NULL_FRAC); + CatalogTupleUpdateValue(ctx, pg_statistic, stawidth, DEFAULT_AVG_WIDTH); + CatalogTupleUpdateValue(ctx, pg_statistic, stadistinct, DEFAULT_N_DISTINCT); /* 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; + CatalogTupleUpdateValue(ctx, pg_statistic, stakind1 + i, (Datum) 0); + CatalogTupleUpdateValue(ctx, pg_statistic, staop1 + i, ObjectIdGetDatum(InvalidOid)); + CatalogTupleUpdateValue(ctx, pg_statistic, stacoll1 + i, ObjectIdGetDatum(InvalidOid)); } } 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 2bd872d6581f8..34c48532a3097 100644 --- a/src/backend/storage/large_object/inv_api.c +++ b/src/backend/storage/large_object/inv_api.c @@ -562,9 +562,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); @@ -610,6 +609,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. @@ -665,16 +666,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. @@ -711,11 +707,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++; @@ -751,9 +747,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); @@ -840,14 +836,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 { @@ -879,11 +872,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); } /* diff --git a/src/include/access/heapam.h b/src/include/access/heapam.h index 632c4332a8c34..3220821df6915 100644 --- a/src/include/access/heapam.h +++ b/src/include/access/heapam.h @@ -364,11 +364,13 @@ extern TM_Result heap_delete(Relation relation, const ItemPointerData *tid, TM_FailureData *tmfd, bool changingPart); extern void heap_finish_speculative(Relation relation, const ItemPointerData *tid); extern void heap_abort_speculative(Relation relation, const ItemPointerData *tid); -extern TM_Result heap_update(Relation relation, const ItemPointerData *otid, - HeapTuple newtup, - CommandId cid, Snapshot crosscheck, bool wait, - TM_FailureData *tmfd, LockTupleMode *lockmode, - TU_UpdateIndexes *update_indexes); +extern TM_Result heap_update(Relation relation, HeapTupleData *oldtup, + HeapTuple newtup, CommandId cid, Snapshot crosscheck, bool wait, + TM_FailureData *tmfd, LockTupleMode *lockmode, Buffer buffer, + Page page, BlockNumber block, ItemId lp, Bitmapset *hot_attrs, + Bitmapset *sum_attrs, Bitmapset *pk_attrs, Bitmapset *rid_attrs, + Bitmapset *mix_attrs, Buffer *vmbuffer, + bool rep_id_key_required, TU_UpdateIndexes *update_indexes); extern TM_Result heap_lock_tuple(Relation relation, HeapTuple tuple, CommandId cid, LockTupleMode mode, LockWaitPolicy wait_policy, bool follow_updates, @@ -403,7 +405,8 @@ extern bool heap_tuple_needs_eventual_freeze(HeapTupleHeader tuple); extern void simple_heap_insert(Relation relation, HeapTuple tup); extern void simple_heap_delete(Relation relation, const ItemPointerData *tid); extern void simple_heap_update(Relation relation, const ItemPointerData *otid, - HeapTuple tup, TU_UpdateIndexes *update_indexes); + HeapTuple tup, const Bitmapset *updated, + TU_UpdateIndexes *update_indexes); extern TransactionId heap_index_delete_tuples(Relation rel, TM_IndexDeleteOp *delstate); @@ -430,6 +433,18 @@ extern void log_heap_prune_and_freeze(Relation relation, Buffer buffer, OffsetNumber *dead, int ndead, OffsetNumber *unused, int nunused); +/* in heap/heapam.c */ +extern Bitmapset *HeapDetermineColumnsInfo(Relation relation, + Bitmapset *interesting_cols, + Bitmapset *external_cols, + HeapTuple oldtup, HeapTuple newtup, + bool *has_external); +#ifdef USE_ASSERT_CHECKING +extern void check_lock_if_inplace_updateable_rel(Relation relation, + const ItemPointerData *otid, + HeapTuple newtup); +#endif + /* in heap/vacuumlazy.c */ extern void heap_vacuum_rel(Relation rel, const VacuumParams params, BufferAccessStrategy bstrategy); diff --git a/src/include/access/htup.h b/src/include/access/htup.h index f6b766697e297..bdc6bd187d8ef 100644 --- a/src/include/access/htup.h +++ b/src/include/access/htup.h @@ -14,6 +14,8 @@ #ifndef HTUP_H #define HTUP_H +#include "catalog/pg_aggregate_d.h" +#include "nodes/bitmapset.h" #include "storage/itemptr.h" /* typedefs and forward declarations for structs defined in htup_details.h */ @@ -77,6 +79,254 @@ typedef HeapTupleData *HeapTuple; */ #define HeapTupleIsValid(tuple) ((tuple) != NULL) +#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) + +/* + * The following should be used when manipulating CatalogTuples for + * insert or update. + */ + +#define CatalogInsertValuesDecl(table_name, var) \ + struct _cat_##table_name##_##var##_ins_vals { \ + CatalogIndexState idx; \ + bool nulls[Natts_##table_name]; \ + Datum values[Natts_##table_name]; \ + } +#define CatalogInsertValuesContext(table_name, var) \ + CatalogInsertValuesDecl(table_name, var) _##table_name##_##var = { \ + .idx = NULL, \ + .nulls = {false}, \ + .values = {0} \ + }, *var = &_##table_name##_##var + +#define CatalogUpdateValuesDecl(table_name, var) \ + struct _cat_##table_name##_##var##_upd_vals { \ + CatalogIndexState idx; \ + bool nulls[Natts_##table_name]; \ + Datum values[Natts_##table_name]; \ + Bitmapset *updated; \ + } +#define CatalogUpdateValuesContext(table_name, var) \ + CatalogUpdateValuesDecl(table_name, var) _##table_name##_##var = { \ + .idx = NULL, \ + .nulls = {false}, \ + .values = {0}, \ + .updated = NULL \ + }, *var = &_##table_name##_##var + +#define CatalogFormContext(table_name, var, tuple) \ + Form_##table_name var = (Form_##table_name) GETSTRUCT(tuple) + +#define CatalogInsertFormDecl(table_name, var) \ + struct _cat_##table_name##_##var##_ins_form { \ + CatalogIndexState idx; \ + Form_##table_name form; \ + bool nulls[Natts_##table_name]; \ + } +#define CatalogInsertFormContext(table_name, var) \ + CatalogInsertFormDecl(table_name, var) _##table_name##_##var = { \ + .idx = NULL, \ + .form = NULL, \ + .nulls = {false} \ + }, *var = &_##table_name##_##var + +#define CatalogUpdateFormDecl(table_name, var) \ + struct _cat_##table_name##_##var##_upd_form { \ + CatalogIndexState idx; \ + Form_##table_name form; \ + bool nulls[Natts_##table_name]; \ + Bitmapset *updated; \ + } +#define CatalogUpdateFormContext(table_name, var) \ + CatalogUpdateFormDecl(table_name, var) _##table_name##_##var = { \ + .idx = NULL, \ + .form = NULL, \ + .nulls = {false}, \ + .updated = NULL \ + }, *var = &_##table_name##_##var + +#define CatalogSetForm(table_name, var, tuple) \ + var->form = (Form_##table_name) GETSTRUCT(tuple) + +#define CatalogGetFormField(var, field) var->form->field + +#define CatalogTupleValue(var, table_name, field) \ + var->values[Anum_##table_name##_##field - 1] + +#define FormCatalogTuple(relation, var) \ + heap_form_tuple(RelationGetDescr(relation), var->values, var->nulls) + +#define DeformCatalogTuple(relation, tuple, var) \ + heap_deform_tuple(tuple, RelationGetDescr(relation), var->values, var->nulls) + +#define ModifyCatalogTupleValues(relation, tuple, var) \ + do { \ + HeapTuple new; \ + \ + new = heap_update_tuple(tuple, RelationGetDescr(relation), \ + var->values, var->nulls, var->updated); \ + CatalogTupleUpdate(relation, &new->t_self, new, var->updated, var->idx); \ + heap_freetuple(new); \ + } while(0) + +#define UpdateCatalogTupleField(relation, tuple, var) \ + CatalogTupleUpdate(relation, &tuple->t_self, tuple, var->updated, var->idx) + +#define ModifyCatalogTupleField(relation, tuple, var) \ + do { \ + HeapTuple new; \ + \ + new = heap_update_tuple(tuple, RelationGetDescr(relation), \ + NULL, var->nulls, var->updated); \ + CatalogTupleUpdate(relation, &new->t_self, new, var->updated, var->idx); \ + heap_freetuple(new); \ + } while(0) + +#define InsertCatalogTupleValues(relation, var) \ + do { \ + HeapTuple new = heap_form_tuple(RelationGetDescr(relation), \ + var->values, var->nulls); \ + CatalogTupleInsert(relation, new, var->idx); \ + heap_freetuple(new); \ + } while(0) + +#define CatalogTupleSetField(var, table_name, field, value) \ + var->field = (value) + +#define CatalogTupleSetFieldNull(var, table_name, field) \ + var->nulls[Anum_##table_name##_##field - 1] = true + +#define CatalogTupleSetValue(var, table_name, field, value) \ + do { \ + var->values[Anum_##table_name##_##field - 1] = (value); \ + var->nulls[Anum_##table_name##_##field - 1] = false; \ + } while(0) + +#define CatalogTupleSetValueNull(var, table_name, field) \ + var->nulls[Anum_##table_name##_##field - 1] = true + +#define CatalogTupleUpdateValue(var, table_name, field, value) \ + do { \ + var->values[Anum_##table_name##_##field - 1] = (value); \ + var->nulls[Anum_##table_name##_##field - 1] = false; \ + var->updated = bms_add_member(var->updated, \ + Anum_##table_name##_##field - \ + FirstLowInvalidHeapAttributeNumber); \ + } while(0) + +#define CatalogTupleUpdateValueNull(var, table_name, field) \ + do { \ + var->nulls[Anum_##table_name##_##field - 1] = true; \ + var->updated = bms_add_member(var->updated, \ + Anum_##table_name##_##field - \ + FirstLowInvalidHeapAttributeNumber); \ + } while(0) + +#define CatalogTupleUpdateField(var, table_name, field, value) \ + do { \ + var->form->field = (value); \ + var->nulls[Anum_##table_name##_##field - 1] = false; \ + var->updated = bms_add_member(var->updated, \ + Anum_##table_name##_##field - \ + FirstLowInvalidHeapAttributeNumber); \ + } while(0) + +#define CatalogTupleCondUpdateField(var, table_name, field, cond_set_value, stmt) \ + if (!(cond_set_value)) \ + { \ + var->nulls[Anum_##table_name##_##field - 1] = false; \ + var->updated = bms_add_member(var->updated, \ + Anum_##table_name##_##field - \ + FirstLowInvalidHeapAttributeNumber); \ + } else stmt + +#define CatalogTupleUpdateStrField(var, table_name, field, value) \ + do { \ + namestrcpy(&(var->form->field), value); \ + var->nulls[Anum_##table_name##_##field - 1] = false; \ + var->updated = bms_add_member(var->updated, \ + Anum_##table_name##_##field - \ + FirstLowInvalidHeapAttributeNumber); \ + } while(0) + +#define CatalogTupleUpdateFieldNull(var, table_name, field) \ + do { \ + var->nulls[Anum_##table_name##_##field - 1] = true; \ + var->updated = bms_add_member(var->updated, \ + Anum_##table_name##_##field - \ + FirstLowInvalidHeapAttributeNumber); \ + } while(0) + +#define CatalogTupleUpdateMarkAllColumnsUpdated(var, table_name) \ + var->updated = bms_add_range(var->updated, 1 - FirstLowInvalidHeapAttributeNumber, \ + Natts_##table_name - FirstLowInvalidHeapAttributeNumber) + +#define CatalogTupleReuseUpdateContext(var) \ + do { \ + bms_free(var->updated); \ + var->updated = NULL; \ + } while(0) + +#define CatalogTupleHasChanged(var) (!bms_is_empty(var->updated)) + + + +/* TODO BELOW */ + +#define HeapTupleValue(table_name, field, values) \ + (values)[Anum_##table_name##_##field - 1] + +#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 + +/* + * 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 */ 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