public inbox for [email protected]help / color / mirror / Atom feed
[PATCH 07/10] add wal_compression_method: zstd 2+ messages / 2 participants [nested] [flat]
* [PATCH 07/10] add wal_compression_method: zstd @ 2021-03-12 20:43 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 2+ messages in thread From: Justin Pryzby @ 2021-03-12 20:43 UTC (permalink / raw) --- configure | 163 ++++++++++++++++++ configure.ac | 26 +++ doc/src/sgml/config.sgml | 2 +- src/backend/access/transam/xlog.c | 3 + src/backend/access/transam/xloginsert.c | 19 ++ src/backend/access/transam/xlogreader.c | 16 ++ src/backend/utils/misc/postgresql.conf.sample | 2 +- src/include/access/xlog_internal.h | 1 + src/include/pg_config.h.in | 3 + src/tools/msvc/Solution.pm | 1 + 10 files changed, 234 insertions(+), 2 deletions(-) diff --git a/configure b/configure index 3afa1e87e3..20c6e08c02 100755 --- a/configure +++ b/configure @@ -699,6 +699,9 @@ with_gnu_ld LD LDFLAGS_SL LDFLAGS_EX +ZSTD_LIBS +ZSTD_CFLAGS +with_zstd LZ4_LIBS LZ4_CFLAGS with_lz4 @@ -868,6 +871,7 @@ with_libxslt with_system_tzdata with_zlib with_lz4 +with_zstd with_gnu_ld with_ssl with_openssl @@ -897,6 +901,8 @@ XML2_CFLAGS XML2_LIBS LZ4_CFLAGS LZ4_LIBS +ZSTD_CFLAGS +ZSTD_LIBS LDFLAGS_EX LDFLAGS_SL PERL @@ -1576,6 +1582,7 @@ Optional Packages: use system time zone data in DIR --without-zlib do not use Zlib --without-lz4 build without LZ4 support + --with-zstd build with Zstd compression library --with-gnu-ld assume the C compiler uses GNU ld [default=no] --with-ssl=LIB use LIB for SSL/TLS support (openssl) --with-openssl obsolete spelling of --with-ssl=openssl @@ -1605,6 +1612,8 @@ Some influential environment variables: XML2_LIBS linker flags for XML2, overriding pkg-config LZ4_CFLAGS C compiler flags for LZ4, overriding pkg-config LZ4_LIBS linker flags for LZ4, overriding pkg-config + ZSTD_CFLAGS C compiler flags for ZSTD, overriding pkg-config + ZSTD_LIBS linker flags for ZSTD, overriding pkg-config LDFLAGS_EX extra linker flags for linking executables only LDFLAGS_SL extra linker flags for linking shared libraries only PERL Perl program @@ -8705,6 +8714,137 @@ fi CFLAGS="$LZ4_CFLAGS $CFLAGS" fi +# +# ZSTD +# +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build with zstd support" >&5 +$as_echo_n "checking whether to build with zstd support... " >&6; } + + + +# Check whether --with-zstd was given. +if test "${with_zstd+set}" = set; then : + withval=$with_zstd; + case $withval in + yes) + +$as_echo "#define USE_ZSTD 1" >>confdefs.h + + ;; + no) + : + ;; + *) + as_fn_error $? "no argument expected for --with-zstd option" "$LINENO" 5 + ;; + esac + +else + with_zstd=no + +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_zstd" >&5 +$as_echo "$with_zstd" >&6; } + + +if test "$with_zstd" = yes; then + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libzstd" >&5 +$as_echo_n "checking for libzstd... " >&6; } + +if test -n "$ZSTD_CFLAGS"; then + pkg_cv_ZSTD_CFLAGS="$ZSTD_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libzstd\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libzstd") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_ZSTD_CFLAGS=`$PKG_CONFIG --cflags "libzstd" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$ZSTD_LIBS"; then + pkg_cv_ZSTD_LIBS="$ZSTD_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libzstd\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libzstd") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_ZSTD_LIBS=`$PKG_CONFIG --libs "libzstd" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + ZSTD_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libzstd" 2>&1` + else + ZSTD_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libzstd" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$ZSTD_PKG_ERRORS" >&5 + + as_fn_error $? "Package requirements (libzstd) were not met: + +$ZSTD_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +Alternatively, you may set the environment variables ZSTD_CFLAGS +and ZSTD_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details." "$LINENO" 5 +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +Alternatively, you may set the environment variables ZSTD_CFLAGS +and ZSTD_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details. + +To get pkg-config, see <http://pkg-config.freedesktop.org/;. +See \`config.log' for more details" "$LINENO" 5; } +else + ZSTD_CFLAGS=$pkg_cv_ZSTD_CFLAGS + ZSTD_LIBS=$pkg_cv_ZSTD_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +fi + LIBS="$ZSTD_LIBS $LIBS" + CFLAGS="$ZSTD_CFLAGS $CFLAGS" +fi + # # Assignments # @@ -13556,6 +13696,29 @@ done CPPFLAGS=$ac_save_CPPFLAGS fi +if test "$with_zstd" = yes; then + ac_save_CPPFLAGS=$CPPFLAGS + CPPFLAGS="$ZSTD_CFLAGS $CPPFLAGS" + + # Verify we have zstd's header files + for ac_header in zstd.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "zstd.h" "ac_cv_header_zstd_h" "$ac_includes_default" +if test "x$ac_cv_header_zstd_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ZSTD_H 1 +_ACEOF + +else + as_fn_error $? "zstd.h header file is required for zstd" "$LINENO" 5 +fi + +done + + + CPPFLAGS=$ac_save_CPPFLAGS +fi + if test "$with_gssapi" = yes ; then for ac_header in gssapi/gssapi.h do : diff --git a/configure.ac b/configure.ac index d62ea5f742..c4956745ce 100644 --- a/configure.ac +++ b/configure.ac @@ -1001,6 +1001,21 @@ if test "$with_lz4" = yes; then CFLAGS="$LZ4_CFLAGS $CFLAGS" fi +# +# ZSTD +# +AC_MSG_CHECKING([whether to build with zstd support]) +PGAC_ARG_BOOL(with, zstd, no, [build with Zstd compression library], + [AC_DEFINE([USE_ZSTD], 1, [Define to 1 to build with zstd support. (--with-zstd)])]) +AC_MSG_RESULT([$with_zstd]) +AC_SUBST(with_zstd) + +if test "$with_zstd" = yes; then + PKG_CHECK_MODULES(ZSTD, libzstd) + LIBS="$ZSTD_LIBS $LIBS" + CFLAGS="$ZSTD_CFLAGS $CFLAGS" +fi + # # Assignments # @@ -1433,6 +1448,17 @@ if test "$with_lz4" = yes; then CPPFLAGS=$ac_save_CPPFLAGS fi +if test "$with_zstd" = yes; then + ac_save_CPPFLAGS=$CPPFLAGS + CPPFLAGS="$ZSTD_CFLAGS $CPPFLAGS" + + # Verify we have zstd's header files + AC_CHECK_HEADERS(zstd.h, [], + [AC_MSG_ERROR([zstd.h header file is required for zstd])]) + + CPPFLAGS=$ac_save_CPPFLAGS +fi + if test "$with_gssapi" = yes ; then AC_CHECK_HEADERS(gssapi/gssapi.h, [], [AC_CHECK_HEADERS(gssapi.h, [], [AC_MSG_ERROR([gssapi.h header file is required for GSSAPI])])]) diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index 257775c83b..94dd6ef3e9 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -3083,7 +3083,7 @@ include_dir 'conf.d' This parameter selects the compression method used to compress WAL when <varname>wal_compression</varname> is enabled. The supported methods are pglz, zlib, and (if configured when - <productname>PostgreSQL</productname> was built) lz4. + <productname>PostgreSQL</productname> was built) lz4 and zstd. The default value is <literal>pglz</literal>. Only superusers can change this setting. </para> diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 609d954a3a..9bac79b579 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -189,6 +189,9 @@ const struct config_enum_entry wal_compression_options[] = { #endif #ifdef USE_LZ4 {"lz4", WAL_COMPRESSION_LZ4, false}, +#endif +#ifdef USE_ZSTD + {"zstd", WAL_COMPRESSION_ZSTD, false}, #endif {NULL, 0, false} }; diff --git a/src/backend/access/transam/xloginsert.c b/src/backend/access/transam/xloginsert.c index 9fe5c30236..5d1ae37dae 100644 --- a/src/backend/access/transam/xloginsert.c +++ b/src/backend/access/transam/xloginsert.c @@ -41,6 +41,10 @@ #include "lz4.h" #endif +#ifdef USE_ZSTD +#include "zstd.h" +#endif + /* Buffer size required to store a compressed version of backup block image */ #define PGLZ_MAX_BLCKSZ PGLZ_MAX_OUTPUT(BLCKSZ) @@ -896,6 +900,21 @@ XLogCompressBackupBlock(char *page, uint16 hole_offset, uint16 hole_length, break; #endif +#ifdef USE_ZSTD + case WAL_COMPRESSION_ZSTD: + len = ZSTD_compress(dest, PGLZ_MAX_BLCKSZ, source, orig_len, 1); + if (ZSTD_isError(len)) + { + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("failed compressing zstd: %s", + ZSTD_getErrorName(len)))); + len = -1; + } + + break; +#endif + default: /* * It should be impossible to get here for unsupported algorithms, diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c index fa1e38a810..caa1031d63 100644 --- a/src/backend/access/transam/xlogreader.c +++ b/src/backend/access/transam/xlogreader.c @@ -41,6 +41,10 @@ #include "lz4.h" #endif +#ifdef USE_ZSTD +#include "zstd.h" +#endif + static void report_invalid_record(XLogReaderState *state, const char *fmt,...) pg_attribute_printf(2, 3); static bool allocate_recordbuf(XLogReaderState *state, uint32 reclength); @@ -1564,6 +1568,8 @@ wal_compression_name(WalCompression compression) return "zlib"; case WAL_COMPRESSION_LZ4: return "lz4"; + case WAL_COMPRESSION_ZSTD: + return "zstd"; default: return "???"; } @@ -1621,6 +1627,16 @@ RestoreBlockImage(XLogReaderState *record, uint8 block_id, char *page) break; #endif +#ifdef USE_ZSTD + case WAL_COMPRESSION_ZSTD: + decomp_result = ZSTD_decompress(tmp.data, BLCKSZ-bkpb->hole_length, + ptr, bkpb->bimg_len); + // XXX: ZSTD_getErrorName + if (ZSTD_isError(decomp_result)) + decomp_result = -1; + break; +#endif + default: report_invalid_record(record, "image at %X/%X is compressed with unsupported codec, block %d (%d/%s)", (uint32) (record->ReadRecPtr >> 32), diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample index 76f494cb9b..d372e2a817 100644 --- a/src/backend/utils/misc/postgresql.conf.sample +++ b/src/backend/utils/misc/postgresql.conf.sample @@ -213,7 +213,7 @@ # open_sync #full_page_writes = on # recover from partial page writes #wal_compression = off # enable compression of full-page writes -#wal_compression_method = pglz # pglz, zlib, lz4 +#wal_compression_method = pglz # pglz, zlib, lz4, zstd #wal_log_hints = off # also do full page writes of non-critical updates # (change requires restart) #wal_init_zero = on # zero-fill new WAL files diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h index e70886b81c..48b16b6083 100644 --- a/src/include/access/xlog_internal.h +++ b/src/include/access/xlog_internal.h @@ -329,6 +329,7 @@ typedef enum WalCompression WAL_COMPRESSION_PGLZ, WAL_COMPRESSION_ZLIB, WAL_COMPRESSION_LZ4, + WAL_COMPRESSION_ZSTD, } WalCompression; extern const char *wal_compression_name(WalCompression compression); diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in index 0a6422da4f..ad26393352 100644 --- a/src/include/pg_config.h.in +++ b/src/include/pg_config.h.in @@ -902,6 +902,9 @@ /* Define to 1 to build with LZ4 support (--with-lz4) */ #undef USE_LZ4 +/* Define to 1 if you have the `zstd' library (-lzstd). */ +#undef USE_ZSTD + /* Define to select named POSIX semaphores. */ #undef USE_NAMED_POSIX_SEMAPHORES diff --git a/src/tools/msvc/Solution.pm b/src/tools/msvc/Solution.pm index 14605371bb..fff0212087 100644 --- a/src/tools/msvc/Solution.pm +++ b/src/tools/msvc/Solution.pm @@ -486,6 +486,7 @@ sub GenerateFiles USE_LIBXML => undef, USE_LIBXSLT => undef, USE_LZ4 => undef, + USE_ZSTD => $self->{options}->{zstd} ? 1 : undef, USE_LDAP => $self->{options}->{ldap} ? 1 : undef, USE_LLVM => undef, USE_NAMED_POSIX_SEMAPHORES => undef, -- 2.17.0 --0qVF/w3MHQqLSynd Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0008-Default-to-zstd.patch" ^ permalink raw reply [nested|flat] 2+ messages in thread
* [BUG#19384] Fix Server crash at textout @ 2026-01-26 05:16 vaibhave postgres <[email protected]> 0 siblings, 0 replies; 2+ messages in thread From: vaibhave postgres @ 2026-01-26 05:16 UTC (permalink / raw) To: pgsql-hackers Hey hackers, I replaced the `tupDesc_identifier` with a 64-bit signature from its structure which was a todo. Stored Datums can detect stale definitions. Thanks. [1] BUG #19384: Server crash at textout - Mailing list pgsql-bugs : Postgres Professional <https://postgrespro.com/list/id/[email protected]; Attachments: [application/octet-stream] 0002-Fix-tests.patch (2.9K, ../../CAM_eQjyEFTN_bmWWJLo+R_Q10DP2yQ1-QO96YHXGPzB9B2QMXA@mail.gmail.com/3-0002-Fix-tests.patch) download | inline diff: From 4a6521055859a5ddb60250be0d341ce30d9d2424 Mon Sep 17 00:00:00 2001 From: Vaibhave Sekar <[email protected]> Date: Sun, 25 Jan 2026 10:34:55 +0000 Subject: [PATCH 2/2] Fix tests. --- src/test/regress/expected/portals.out | 19 +++++++++++++++++++ src/test/regress/expected/rowtypes.out | 7 ++----- src/test/regress/sql/portals.sql | 14 ++++++++++++++ 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/src/test/regress/expected/portals.out b/src/test/regress/expected/portals.out index 06726ed4ab7..c4408c8d0bf 100644 --- a/src/test/regress/expected/portals.out +++ b/src/test/regress/expected/portals.out @@ -1561,3 +1561,22 @@ fetch all in held_portal; (1 row) reset default_toast_compression; +-- Changing a composite type after a cursor has emitted rows should error +DROP TYPE IF EXISTS portal_composite CASCADE; +NOTICE: type "portal_composite" does not exist, skipping +CREATE TYPE portal_composite AS (a int, b int); +BEGIN; +DECLARE stale_portal CURSOR FOR + SELECT (i, power(2, 10))::portal_composite FROM generate_series(1, 2) i; +FETCH FROM stale_portal; + row +---------- + (1,1024) +(1 row) + +ALTER TYPE portal_composite ALTER ATTRIBUTE b TYPE text; +FETCH FROM stale_portal; -- should fail instead of crashing +ERROR: type portal_composite has changed +DETAIL: The composite value was created using a previous definition of type portal_composite. +ROLLBACK; +DROP TYPE portal_composite; diff --git a/src/test/regress/expected/rowtypes.out b/src/test/regress/expected/rowtypes.out index 9168979a620..4b9104219b7 100644 --- a/src/test/regress/expected/rowtypes.out +++ b/src/test/regress/expected/rowtypes.out @@ -135,11 +135,8 @@ ERROR: cannot alter table "fullname" because column "people.fn" uses its row ty -- but this should work: alter table fullname add column suffix text default null; select * from people; - fn | bd --------------+------------ - (Joe,Blow,) | 01-10-1984 -(1 row) - +ERROR: type fullname has changed +DETAIL: The composite value was created using a previous definition of type fullname. -- test insertion/updating of subfields update people set fn.suffix = 'Jr'; select * from people; diff --git a/src/test/regress/sql/portals.sql b/src/test/regress/sql/portals.sql index fc4cccb96c0..17110ee7c2e 100644 --- a/src/test/regress/sql/portals.sql +++ b/src/test/regress/sql/portals.sql @@ -605,3 +605,17 @@ drop table toasted_data; fetch all in held_portal; reset default_toast_compression; + +-- Changing a composite type after a cursor has emitted rows should error +DROP TYPE IF EXISTS portal_composite CASCADE; +CREATE TYPE portal_composite AS (a int, b int); + +BEGIN; +DECLARE stale_portal CURSOR FOR + SELECT (i, power(2, 10))::portal_composite FROM generate_series(1, 2) i; +FETCH FROM stale_portal; +ALTER TYPE portal_composite ALTER ATTRIBUTE b TYPE text; +FETCH FROM stale_portal; -- should fail instead of crashing +ROLLBACK; + +DROP TYPE portal_composite; -- 2.43.0 [application/octet-stream] 0001-Stable-tupDesc_identifier.patch (6.5K, ../../CAM_eQjyEFTN_bmWWJLo+R_Q10DP2yQ1-QO96YHXGPzB9B2QMXA@mail.gmail.com/4-0001-Stable-tupDesc_identifier.patch) download | inline diff: From 8c4d491c2cb02cdb51805f52eaa8c0f5fc37ac4c Mon Sep 17 00:00:00 2001 From: Vaibhave Sekar <[email protected]> Date: Sun, 25 Jan 2026 10:34:46 +0000 Subject: [PATCH 1/2] Stable tupDesc_identifier. --- src/backend/utils/cache/typcache.c | 111 +++++++++++++++++++++++++++-- 1 file changed, 104 insertions(+), 7 deletions(-) diff --git a/src/backend/utils/cache/typcache.c b/src/backend/utils/cache/typcache.c index aa4720cb598..6795ac294c1 100644 --- a/src/backend/utils/cache/typcache.c +++ b/src/backend/utils/cache/typcache.c @@ -57,6 +57,7 @@ #include "catalog/pg_range.h" #include "catalog/pg_type.h" #include "commands/defrem.h" +#include "common/hashfn.h" #include "common/int.h" #include "executor/executor.h" #include "lib/dshash.h" @@ -287,12 +288,15 @@ static int32 RecordCacheArrayLen = 0; /* allocated length of above array */ static int32 NextRecordTypmod = 0; /* number of entries used */ /* - * Process-wide counter for generating unique tupledesc identifiers. + * Process-wide counter for generating unique tupledesc identifiers for + * record (RECORDOID) tupdescs. Named composite types now derive their + * identifiers from a deterministic signature of the tupledesc contents. * Zero and one (INVALID_TUPLEDESC_IDENTIFIER) aren't allowed to be chosen * as identifiers, so we start the counter at INVALID_TUPLEDESC_IDENTIFIER. */ static uint64 tupledesc_id_counter = INVALID_TUPLEDESC_IDENTIFIER; +static uint64 compute_tupdesc_identifier(TupleDesc tupdesc); static void load_typcache_tupdesc(TypeCacheEntry *typentry); static void load_rangetype_info(TypeCacheEntry *typentry); static void load_multirangetype_info(TypeCacheEntry *typentry); @@ -331,6 +335,75 @@ static dsa_pointer share_tupledesc(dsa_area *area, TupleDesc tupdesc, uint32 typmod); +/* + * compute_tupdesc_identifier + * + * Build a stable, deterministic 64-bit signature for a tuple descriptor so + * that unchanged composite type definitions keep the same identifier across + * cache reloads and backends. We hash only structural fields that affect the + * layout or logical contract of the rowtype, avoiding volatile fields such as + * attcacheoff. + */ +static uint64 +compute_tupdesc_identifier(TupleDesc tupdesc) +{ + uint64 hash; + int natts = tupdesc->natts; + + hash = hash_bytes_extended((const unsigned char *) &tupdesc->tdtypeid, + sizeof(Oid), 0); + hash = hash_bytes_extended((const unsigned char *) &tupdesc->tdtypmod, + sizeof(int32), hash); + hash = hash_bytes_extended((const unsigned char *) &natts, + sizeof(int), hash); + + for (int i = 0; i < natts; i++) + { + Form_pg_attribute att = TupleDescAttr(tupdesc, i); + + hash = hash_bytes_extended((const unsigned char *) att->attname.data, + NAMEDATALEN, hash); + hash = hash_bytes_extended((const unsigned char *) &att->attisdropped, + sizeof(bool), hash); + hash = hash_bytes_extended((const unsigned char *) &att->attnotnull, + sizeof(bool), hash); + hash = hash_bytes_extended((const unsigned char *) &att->attlen, + sizeof(int16), hash); + hash = hash_bytes_extended((const unsigned char *) &att->attbyval, + sizeof(bool), hash); + hash = hash_bytes_extended((const unsigned char *) &att->attalign, + sizeof(char), hash); + hash = hash_bytes_extended((const unsigned char *) &att->attstorage, + sizeof(char), hash); + hash = hash_bytes_extended((const unsigned char *) &att->attcompression, + sizeof(char), hash); + hash = hash_bytes_extended((const unsigned char *) &att->atttypid, + sizeof(Oid), hash); + hash = hash_bytes_extended((const unsigned char *) &att->atttypmod, + sizeof(int32), hash); + hash = hash_bytes_extended((const unsigned char *) &att->attcollation, + sizeof(Oid), hash); + hash = hash_bytes_extended((const unsigned char *) &att->attndims, + sizeof(int32), hash); + hash = hash_bytes_extended((const unsigned char *) &att->attidentity, + sizeof(char), hash); + hash = hash_bytes_extended((const unsigned char *) &att->attgenerated, + sizeof(char), hash); + hash = hash_bytes_extended((const unsigned char *) &att->atthasmissing, + sizeof(bool), hash); + } + + /* Avoid reserved identifiers (0 and 1). */ + if (hash <= INVALID_TUPLEDESC_IDENTIFIER) + hash = hash_bytes_extended((const unsigned char *) &natts, + sizeof(int), UINT64CONST(0xA5A5A5A5A5A5A5A5)); + if (hash <= INVALID_TUPLEDESC_IDENTIFIER) + hash = INVALID_TUPLEDESC_IDENTIFIER + 1; + + return hash; +} + + /* * lookup_type_cache * @@ -898,11 +971,14 @@ load_typcache_tupdesc(TypeCacheEntry *typentry) Assert(typentry->tupDesc->tdrefcount > 0); typentry->tupDesc->tdrefcount++; + typentry->tupDesc_identifier = compute_tupdesc_identifier(typentry->tupDesc); + /* - * In future, we could take some pains to not change tupDesc_identifier if - * the tupdesc didn't really change; but for now it's not worth it. + * Stash a version marker in tdtypmod so composite Datums can detect stale + * definitions later. Keep it non-negative so callers can reliably check + * for it. */ - typentry->tupDesc_identifier = ++tupledesc_id_counter; + typentry->tupDesc->tdtypmod = (int32) (typentry->tupDesc_identifier & 0x7FFFFFFF); relation_close(rel, AccessShareLock); } @@ -1748,9 +1824,30 @@ lookup_rowtype_tupdesc_internal(Oid type_id, int32 typmod, bool noError) typentry = lookup_type_cache(type_id, TYPECACHE_TUPDESC); if (typentry->tupDesc == NULL && !noError) ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("type %s is not composite", - format_type_be(type_id)))); + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("type %s is not composite", + format_type_be(type_id)))); + else if (typentry->tupDesc == NULL) + return NULL; + + /* + * If the caller supplied a non-negative typmod, treat it as the version + * of the composite type that was current when the Datum was formed. If + * it doesn't match the current definition, fail fast instead of + * interpreting the tuple using the wrong layout. + */ + if (typmod >= 0) + { + int32 expected_typmod = typentry->tupDesc->tdtypmod; + + if (expected_typmod >= 0 && typmod != expected_typmod) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("type %s has changed", + format_type_be(type_id)), + errdetail("The composite value was created using a previous definition of type %s.", + format_type_be(type_id)))); + } return typentry->tupDesc; } else -- 2.43.0 ^ permalink raw reply [nested|flat] 2+ messages in thread
end of thread, other threads:[~2026-01-26 05:16 UTC | newest] Thread overview: 2+ messages (download: mbox mbox.gz follow: Atom feed) -- links below jump to the message on this page -- 2021-03-12 20:43 [PATCH 07/10] add wal_compression_method: zstd Justin Pryzby <[email protected]> 2026-01-26 05:16 [BUG#19384] Fix Server crash at textout vaibhave postgres <[email protected]>
This inbox is served by agora; see mirroring instructions for how to clone and mirror all data and code used for this inbox