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