diff --git a/config/c-compiler.m4 b/config/c-compiler.m4 index da40bd6a647..8de232ec050 100644 --- a/config/c-compiler.m4 +++ b/config/c-compiler.m4 @@ -7,10 +7,10 @@ # Select the format archetype to be used by gcc to check printf-type functions. # We prefer "gnu_printf", as that most closely matches the features supported # by src/port/snprintf.c (particularly the %m conversion spec). However, -# on some NetBSD versions, that doesn't work while "__syslog__" does. -# If all else fails, use "printf". +# on clang and on some NetBSD versions, that doesn't work while "__syslog__" +# does. If all else fails, use "printf". AC_DEFUN([PGAC_PRINTF_ARCHETYPE], -[AC_CACHE_CHECK([for printf format archetype], pgac_cv_printf_archetype, +[AC_CACHE_CHECK([for C printf format archetype], pgac_cv_printf_archetype, [pgac_cv_printf_archetype=gnu_printf PGAC_TEST_PRINTF_ARCHETYPE if [[ "$ac_archetype_ok" = no ]]; then @@ -20,8 +20,8 @@ if [[ "$ac_archetype_ok" = no ]]; then pgac_cv_printf_archetype=printf fi fi]) -AC_DEFINE_UNQUOTED([PG_PRINTF_ATTRIBUTE], [$pgac_cv_printf_archetype], -[Define to best printf format archetype, usually gnu_printf if available.]) +AC_DEFINE_UNQUOTED([PG_C_PRINTF_ATTRIBUTE], [$pgac_cv_printf_archetype], +[Define to best C printf format archetype, usually gnu_printf if available.]) ])# PGAC_PRINTF_ARCHETYPE # Subroutine: test $pgac_cv_printf_archetype, set $ac_archetype_ok to yes or no @@ -38,6 +38,42 @@ ac_c_werror_flag=$ac_save_c_werror_flag ])# PGAC_TEST_PRINTF_ARCHETYPE +# PGAC_CXX_PRINTF_ARCHETYPE +# ------------------------- +# Because we support using gcc as C compiler with clang as C++ compiler, +# we have to be prepared to use different printf archetypes in C++ code. +# So, do the above test all over in C++. +AC_DEFUN([PGAC_CXX_PRINTF_ARCHETYPE], +[AC_CACHE_CHECK([for C++ printf format archetype], pgac_cv_cxx_printf_archetype, +[pgac_cv_cxx_printf_archetype=gnu_printf +PGAC_TEST_CXX_PRINTF_ARCHETYPE +if [[ "$ac_archetype_ok" = no ]]; then + pgac_cv_cxx_printf_archetype=__syslog__ + PGAC_TEST_CXX_PRINTF_ARCHETYPE + if [[ "$ac_archetype_ok" = no ]]; then + pgac_cv_cxx_printf_archetype=printf + fi +fi]) +AC_DEFINE_UNQUOTED([PG_CXX_PRINTF_ATTRIBUTE], [$pgac_cv_cxx_printf_archetype], +[Define to best C++ printf format archetype, usually gnu_printf if available.]) +])# PGAC_CXX_PRINTF_ARCHETYPE + +# Subroutine: test $pgac_cv_cxx_printf_archetype, set $ac_archetype_ok to yes or no +AC_DEFUN([PGAC_TEST_CXX_PRINTF_ARCHETYPE], +[ac_save_cxx_werror_flag=$ac_cxx_werror_flag +ac_cxx_werror_flag=yes +AC_LANG_PUSH(C++) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM( +[extern void pgac_write(int ignore, const char *fmt,...) +__attribute__((format($pgac_cv_cxx_printf_archetype, 2, 3)));], +[pgac_write(0, "error %s: %m", "foo");])], + [ac_archetype_ok=yes], + [ac_archetype_ok=no]) +AC_LANG_POP([]) +ac_cxx_werror_flag=$ac_save_cxx_werror_flag +])# PGAC_TEST_CXX_PRINTF_ARCHETYPE + + # PGAC_TYPE_128BIT_INT # -------------------- # Check if __int128 is a working 128 bit integer type, and if so diff --git a/configure b/configure index bae1c6915db..d2343c8d800 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for PostgreSQL 18.3. +# Generated by GNU Autoconf 2.69 for PostgreSQL 18.4. # # Report bugs to . # @@ -583,8 +583,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='PostgreSQL' PACKAGE_TARNAME='postgresql' -PACKAGE_VERSION='18.3' -PACKAGE_STRING='PostgreSQL 18.3' +PACKAGE_VERSION='18.4' +PACKAGE_STRING='PostgreSQL 18.4' PACKAGE_BUGREPORT='pgsql-bugs@lists.postgresql.org' PACKAGE_URL='https://www.postgresql.org/' @@ -1473,7 +1473,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures PostgreSQL 18.3 to adapt to many kinds of systems. +\`configure' configures PostgreSQL 18.4 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1538,7 +1538,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of PostgreSQL 18.3:";; + short | recursive ) echo "Configuration of PostgreSQL 18.4:";; esac cat <<\_ACEOF @@ -1733,7 +1733,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -PostgreSQL configure 18.3 +PostgreSQL configure 18.4 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2486,7 +2486,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by PostgreSQL $as_me 18.3, which was +It was created by PostgreSQL $as_me 18.4, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -14985,8 +14985,8 @@ _ACEOF ;; esac -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for printf format archetype" >&5 -$as_echo_n "checking for printf format archetype... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C printf format archetype" >&5 +$as_echo_n "checking for C printf format archetype... " >&6; } if ${pgac_cv_printf_archetype+:} false; then : $as_echo_n "(cached) " >&6 else @@ -15046,7 +15046,97 @@ fi $as_echo "$pgac_cv_printf_archetype" >&6; } cat >>confdefs.h <<_ACEOF -#define PG_PRINTF_ATTRIBUTE $pgac_cv_printf_archetype +#define PG_C_PRINTF_ATTRIBUTE $pgac_cv_printf_archetype +_ACEOF + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ printf format archetype" >&5 +$as_echo_n "checking for C++ printf format archetype... " >&6; } +if ${pgac_cv_cxx_printf_archetype+:} false; then : + $as_echo_n "(cached) " >&6 +else + pgac_cv_cxx_printf_archetype=gnu_printf +ac_save_cxx_werror_flag=$ac_cxx_werror_flag +ac_cxx_werror_flag=yes +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +extern void pgac_write(int ignore, const char *fmt,...) +__attribute__((format($pgac_cv_cxx_printf_archetype, 2, 3))); +int +main () +{ +pgac_write(0, "error %s: %m", "foo"); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_archetype_ok=yes +else + ac_archetype_ok=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +ac_cxx_werror_flag=$ac_save_cxx_werror_flag + +if [ "$ac_archetype_ok" = no ]; then + pgac_cv_cxx_printf_archetype=__syslog__ + ac_save_cxx_werror_flag=$ac_cxx_werror_flag +ac_cxx_werror_flag=yes +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +extern void pgac_write(int ignore, const char *fmt,...) +__attribute__((format($pgac_cv_cxx_printf_archetype, 2, 3))); +int +main () +{ +pgac_write(0, "error %s: %m", "foo"); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_archetype_ok=yes +else + ac_archetype_ok=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +ac_cxx_werror_flag=$ac_save_cxx_werror_flag + + if [ "$ac_archetype_ok" = no ]; then + pgac_cv_cxx_printf_archetype=printf + fi +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_cxx_printf_archetype" >&5 +$as_echo "$pgac_cv_cxx_printf_archetype" >&6; } + +cat >>confdefs.h <<_ACEOF +#define PG_CXX_PRINTF_ATTRIBUTE $pgac_cv_cxx_printf_archetype _ACEOF @@ -19645,7 +19735,7 @@ else fi # IvorySQL version -PACKAGE_IVORYSQL_VERSION='5.3' +PACKAGE_IVORYSQL_VERSION='5.4' cat >>confdefs.h <<_ACEOF #define PACKAGE_IVORYSQL_VERSION "$PACKAGE_IVORYSQL_VERSION" @@ -20246,7 +20336,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by PostgreSQL $as_me 18.3, which was +This file was extended by PostgreSQL $as_me 18.4, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -20317,7 +20407,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -PostgreSQL config.status 18.3 +PostgreSQL config.status 18.4 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index 89846c8f3f3..66f9e2254b5 100644 --- a/configure.ac +++ b/configure.ac @@ -17,7 +17,7 @@ dnl Read the Autoconf manual for details. dnl m4_pattern_forbid(^PGAC_)dnl to catch undefined macros -AC_INIT([PostgreSQL], [18.3], [pgsql-bugs@lists.postgresql.org], [], [https://www.postgresql.org/]) +AC_INIT([PostgreSQL], [18.4], [pgsql-bugs@lists.postgresql.org], [], [https://www.postgresql.org/]) m4_if(m4_defn([m4_PACKAGE_VERSION]), [2.69], [], [m4_fatal([Autoconf version 2.69 is required. Untested combinations of 'autoconf' and PostgreSQL versions are not @@ -31,7 +31,7 @@ AC_PREFIX_DEFAULT(/usr/local/pgsql) AC_DEFINE_UNQUOTED(CONFIGURE_ARGS, ["$ac_configure_args"], [Saved arguments from configure]) # IvorySQL version -PACKAGE_IVORYSQL_VERSION='5.3' +PACKAGE_IVORYSQL_VERSION='5.4' [PG_MAJORVERSION=`expr "$PACKAGE_VERSION" : '\([0-9][0-9]*\)'`] [PG_MINORVERSION=`expr "$PACKAGE_VERSION" : '.*\.\([0-9][0-9]*\)'`] @@ -1769,6 +1769,7 @@ m4_defun([AC_PROG_CC_STDC], []) dnl We don't want that. AC_C_BIGENDIAN AC_C_INLINE PGAC_PRINTF_ARCHETYPE +PGAC_CXX_PRINTF_ARCHETYPE PGAC_C_STATIC_ASSERT PGAC_C_TYPEOF PGAC_C_TYPES_COMPATIBLE diff --git a/contrib/basic_archive/basic_archive.c b/contrib/basic_archive/basic_archive.c index 4a8b8c7ac29..0eec948e002 100644 --- a/contrib/basic_archive/basic_archive.c +++ b/contrib/basic_archive/basic_archive.c @@ -90,13 +90,11 @@ _PG_archive_module_init(void) /* * check_archive_directory * - * Checks that the provided archive directory exists. + * Checks that the provided archive directory path isn't too long. */ static bool check_archive_directory(char **newval, void **extra, GucSource source) { - struct stat st; - /* * The default value is an empty string, so we have to accept that value. * Our check_configured callback also checks for this and prevents @@ -115,17 +113,6 @@ check_archive_directory(char **newval, void **extra, GucSource source) return false; } - /* - * Do a basic sanity check that the specified archive directory exists. It - * could be removed at some point in the future, so we still need to be - * prepared for it not to exist in the actual archiving logic. - */ - if (stat(*newval, &st) != 0 || !S_ISDIR(st.st_mode)) - { - GUC_check_errdetail("Specified archive directory does not exist."); - return false; - } - return true; } diff --git a/contrib/hstore_plperl/hstore_plperl.c b/contrib/hstore_plperl/hstore_plperl.c index 31393b4fa50..2727a5f2ceb 100644 --- a/contrib/hstore_plperl/hstore_plperl.c +++ b/contrib/hstore_plperl/hstore_plperl.c @@ -121,7 +121,7 @@ plperl_to_hstore(PG_FUNCTION_ARGS) pcount = hv_iterinit(hv); - pairs = palloc(pcount * sizeof(Pairs)); + pairs = palloc_array(Pairs, pcount); i = 0; while ((he = hv_iternext(hv))) diff --git a/contrib/hstore_plpython/hstore_plpython.c b/contrib/hstore_plpython/hstore_plpython.c index e2bfc6da38e..b0af13945bb 100644 --- a/contrib/hstore_plpython/hstore_plpython.c +++ b/contrib/hstore_plpython/hstore_plpython.c @@ -150,7 +150,7 @@ plpython_to_hstore(PG_FUNCTION_ARGS) Py_ssize_t i; Pairs *pairs; - pairs = palloc(pcount * sizeof(*pairs)); + pairs = palloc_array(Pairs, pcount); for (i = 0; i < pcount; i++) { diff --git a/contrib/intarray/_int_bool.c b/contrib/intarray/_int_bool.c index 2b2c3f4029e..26ba0b8a3b6 100644 --- a/contrib/intarray/_int_bool.c +++ b/contrib/intarray/_int_bool.c @@ -434,37 +434,77 @@ boolop(PG_FUNCTION_ARGS) PG_RETURN_BOOL(result); } -static void -findoprnd(ITEM *ptr, int32 *pos) +/* + * Recursively fill the "left" fields of an ITEM array that represents + * a valid postfix tree. + * + * state: only needed for error reporting + * ptr: starting element of array + * pos: in/out argument, the array index this call is responsible to fill + * + * At exit, *pos has been decremented to point before the sub-tree whose + * top is the entry-time value of *pos. + * + * Returns true if okay, false if error (the only possible error is + * overflow of a "left" field). + */ +static bool +findoprnd(WORKSTATE *state, ITEM *ptr, int32 *pos) { + int32 mypos; + /* since this function recurses, it could be driven to stack overflow. */ check_stack_depth(); + /* get the position this call is supposed to update */ + mypos = *pos; + Assert(mypos >= 0); + + /* in all cases, we should decrement *pos to advance over this item */ + (*pos)--; + #ifdef BS_DEBUG - elog(DEBUG3, (ptr[*pos].type == OPR) ? - "%d %c" : "%d %d", *pos, ptr[*pos].val); + elog(DEBUG3, (ptr[mypos].type == OPR) ? + "%d %c" : "%d %d", mypos, ptr[mypos].val); #endif - if (ptr[*pos].type == VAL) + + if (ptr[mypos].type == VAL) { - ptr[*pos].left = 0; - (*pos)--; + /* base case: a VAL has no operand, so just set its left to zero */ + ptr[mypos].left = 0; } - else if (ptr[*pos].val == (int32) '!') + else if (ptr[mypos].val == (int32) '!') { - ptr[*pos].left = -1; - (*pos)--; - findoprnd(ptr, pos); + /* unary operator, likewise easy: operand is just before it */ + ptr[mypos].left = -1; + /* recurse to scan operand */ + if (!findoprnd(state, ptr, pos)) + return false; } else { - ITEM *curitem = &ptr[*pos]; - int32 tmp = *pos; + /* binary operator */ + int32 delta; - (*pos)--; - findoprnd(ptr, pos); - curitem->left = *pos - tmp; - findoprnd(ptr, pos); + /* recurse to scan right operand */ + if (!findoprnd(state, ptr, pos)) + return false; + /* we must fill left with offset to left operand's top */ + /* abs(delta) < QUERYTYPEMAXITEMS, so it can't overflow ... */ + delta = *pos - mypos; + /* ... but it might be too large to fit in the 16-bit left field */ + Assert(delta < 0); + if (unlikely(delta < PG_INT16_MIN)) + ereturn(state->escontext, false, + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), + errmsg("query_int expression is too complex"))); + ptr[mypos].left = (int16) delta; + /* recurse to scan left operand */ + if (!findoprnd(state, ptr, pos)) + return false; } + + return true; } @@ -515,6 +555,7 @@ bqarr_in(PG_FUNCTION_ARGS) query->size = state.num; ptr = GETQUERY(query); + /* fill the query array from the data makepol constructed */ for (i = state.num - 1; i >= 0; i--) { ptr[i].type = state.str->type; @@ -524,8 +565,13 @@ bqarr_in(PG_FUNCTION_ARGS) state.str = tmp; } + /* now fill the "left" fields */ pos = query->size - 1; - findoprnd(ptr, &pos); + if (!findoprnd(&state, ptr, &pos)) + PG_RETURN_NULL(); + /* if successful, findoprnd should have scanned the whole array */ + Assert(pos == -1); + #ifdef BS_DEBUG initStringInfo(&pbuf); for (i = 0; i < query->size; i++) diff --git a/contrib/ivorysql_ora/expected/ora_xml_functions.out b/contrib/ivorysql_ora/expected/ora_xml_functions.out index 1800b467513..5944990c047 100644 --- a/contrib/ivorysql_ora/expected/ora_xml_functions.out +++ b/contrib/ivorysql_ora/expected/ora_xml_functions.out @@ -27,45 +27,69 @@ INSERT INTO xmlnstest VALUES(1, xmltype('1'), '/AA/ID') fro... - ^ + extract +------------ + 1 +(1 row) + SELECT extract(XMLType('1'), '/AA') from dual; -ERROR: syntax error at or near "(" -LINE 1: SELECT extract(XMLType('1'), '/AA') from d... - ^ + extract +-------------- + + + 1+ + +(1 row) + SELECT extract(XMLType('1'), '/Co') from dual; -ERROR: syntax error at or near "(" -LINE 1: SELECT extract(XMLType('1+ + 1 + + +(1 row) + SELECT extract(XMLType('1'), '/Co/@ Attr') from dual; -ERROR: syntax error at or near "(" -LINE 1: SELECT extract(XMLType('1b1b2'),'/a/b[2]') from dual; -ERROR: syntax error at or near "(" -LINE 1: SELECT extract(XMLType('b1b2'),'/a/b[2]... - ^ + extract +----------- + b2 +(1 row) + SELECT extract(XMLType('b1b2'),'/a/b[3]') from dual; -ERROR: syntax error at or near "(" -LINE 1: SELECT extract(XMLType('b1b2'),'/a/b[3]... - ^ + extract +--------- + +(1 row) + SELECT extract(b, '/a/b') from inaf where a = 2; -ERROR: syntax error at or near "," -LINE 1: SELECT extract(b, '/a/b') from inaf where a = 2; - ^ + extract +--------- + +(1 row) + SELECT extract(XMLType('b1b2'),'') from dual; -ERROR: syntax error at or near "(" -LINE 1: SELECT extract(XMLType('b1b2'),'') from... - ^ + extract +--------- + +(1 row) + SELECT extract(XMLType('b1b2'),null) from dual; -ERROR: syntax error at or near "(" -LINE 1: SELECT extract(XMLType('b1b2'),null) fr... - ^ + extract +--------- + +(1 row) + SELECT extract(data, 'soapenv:Envelope/soapenv:Body/web:BBB/typ:EEE', 'xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:typ="http://www.def.com" xmlns:web="http://www.abc.com"') from xmlnstest where id = 1; -ERROR: syntax error at or near "data" -LINE 1: SELECT extract(data, 'soapenv:Envelope/soapenv:Body/web:BBB/... - ^ + extract +------------------------------------------------------ + 41 +(1 row) + -- -- extractvalue -- diff --git a/contrib/ltree/lquery_op.c b/contrib/ltree/lquery_op.c index 14d84e81c0b..e15e726ad09 100644 --- a/contrib/ltree/lquery_op.c +++ b/contrib/ltree/lquery_op.c @@ -41,8 +41,7 @@ getlexeme(char *start, char *end, int *len) } bool -compare_subnode(ltree_level *t, char *qn, int len, - ltree_prefix_eq_func prefix_eq, bool anyend) +compare_subnode(ltree_level *t, char *qn, int len, bool prefix, bool ci) { char *endt = t->name + t->len; char *endq = qn + len; @@ -57,10 +56,8 @@ compare_subnode(ltree_level *t, char *qn, int len, isok = false; while ((tn = getlexeme(tn, endt, &lent)) != NULL) { - if ((lent == lenq || (lent > lenq && anyend)) && - (*prefix_eq) (qn, lenq, tn, lent)) + if (ltree_label_match(qn, lenq, tn, lent, prefix, ci)) { - isok = true; break; } @@ -76,81 +73,84 @@ compare_subnode(ltree_level *t, char *qn, int len, } /* - * Check if 'a' is a prefix of 'b'. - */ -bool -ltree_prefix_eq(const char *a, size_t a_sz, const char *b, size_t b_sz) -{ - if (a_sz > b_sz) - return false; - else - return (strncmp(a, b, a_sz) == 0); -} - -/* - * Case-insensitive check if 'a' is a prefix of 'b'. + * Check if the label matches the predicate string. If 'prefix' is true, then + * the predicate string is treated as a prefix. If 'ci' is true, then the + * predicate string is case-insensitive (and locale-aware). */ bool -ltree_prefix_eq_ci(const char *a, size_t a_sz, const char *b, size_t b_sz) +ltree_label_match(const char *pred, size_t pred_len, const char *label, + size_t label_len, bool prefix, bool ci) { static pg_locale_t locale = NULL; - size_t al_sz = a_sz + 1; - size_t al_len; - char *al; - size_t bl_sz = b_sz + 1; - size_t bl_len; - char *bl; + char *fpred; /* casefolded predicate */ + size_t fpred_len = pred_len; + char *flabel; /* casefolded label */ + size_t flabel_len = label_len; + size_t len; bool res; + /* fast path for binary match or binary prefix match */ + if ((pred_len == label_len || (prefix && pred_len < label_len)) && + strncmp(pred, label, pred_len) == 0) + return true; + else if (!ci) + return false; + if (!locale) locale = pg_newlocale_from_collation(DEFAULT_COLLATION_OID); if (locale->ctype_is_c) { - if (a_sz > b_sz) + if (pred_len > label_len || (!prefix && pred_len != label_len)) return false; - for (int i = 0; i < a_sz; i++) + for (int i = 0; i < pred_len; i++) { - if (pg_ascii_tolower(a[i]) != pg_ascii_tolower(b[i])) + if (pg_ascii_tolower(pred[i]) != pg_ascii_tolower(label[i])) return false; } return true; } - al = palloc(al_sz); - bl = palloc(bl_sz); - - /* casefold both a and b */ + /* + * Slow path for case-insensitive comparison: case fold and then compare. + * This path is necessary even if pred_len > label_len, because the byte + * lengths may change after casefolding. + */ - al_len = pg_strfold(al, al_sz, a, a_sz, locale); - if (al_len + 1 > al_sz) + fpred = palloc(fpred_len + 1); + len = pg_strfold(fpred, fpred_len + 1, pred, pred_len, locale); + if (len > fpred_len) { /* grow buffer if needed and retry */ - al_sz = al_len + 1; - al = repalloc(al, al_sz); - al_len = pg_strfold(al, al_sz, a, a_sz, locale); - Assert(al_len + 1 <= al_sz); + fpred_len = len; + fpred = repalloc(fpred, fpred_len + 1); + len = pg_strfold(fpred, fpred_len + 1, pred, pred_len, locale); } + Assert(len <= fpred_len); + fpred_len = len; - bl_len = pg_strfold(bl, bl_sz, b, b_sz, locale); - if (bl_len + 1 > bl_sz) + flabel = palloc(flabel_len + 1); + len = pg_strfold(flabel, flabel_len + 1, label, label_len, locale); + if (len > flabel_len) { /* grow buffer if needed and retry */ - bl_sz = bl_len + 1; - bl = repalloc(bl, bl_sz); - bl_len = pg_strfold(bl, bl_sz, b, b_sz, locale); - Assert(bl_len + 1 <= bl_sz); + flabel_len = len; + flabel = repalloc(flabel, flabel_len + 1); + len = pg_strfold(flabel, flabel_len + 1, label, label_len, locale); } + Assert(len <= flabel_len); + flabel_len = len; - if (al_len > bl_len) - res = false; + if ((fpred_len == flabel_len || (prefix && fpred_len < flabel_len)) && + strncmp(fpred, flabel, fpred_len) == 0) + res = true; else - res = (strncmp(al, bl, al_len) == 0); + res = false; - pfree(al); - pfree(bl); + pfree(fpred); + pfree(flabel); return res; } @@ -175,19 +175,16 @@ checkLevel(lquery_level *curq, ltree_level *curt) for (int i = 0; i < curq->numvar; i++) { - ltree_prefix_eq_func prefix_eq; - - prefix_eq = (curvar->flag & LVAR_INCASE) ? ltree_prefix_eq_ci : ltree_prefix_eq; + bool prefix = (curvar->flag & LVAR_ANYEND); + bool ci = (curvar->flag & LVAR_INCASE); if (curvar->flag & LVAR_SUBLEXEME) { - if (compare_subnode(curt, curvar->name, curvar->len, prefix_eq, - (curvar->flag & LVAR_ANYEND))) + if (compare_subnode(curt, curvar->name, curvar->len, prefix, ci)) return success; } - else if ((curvar->len == curt->len || - (curt->len > curvar->len && (curvar->flag & LVAR_ANYEND))) && - (*prefix_eq) (curvar->name, curvar->len, curt->name, curt->len)) + else if (ltree_label_match(curvar->name, curvar->len, curt->name, + curt->len, prefix, ci)) return success; curvar = LVAR_NEXT(curvar); diff --git a/contrib/ltree/ltree.h b/contrib/ltree/ltree.h index b0ded40eba9..226c1cb2115 100644 --- a/contrib/ltree/ltree.h +++ b/contrib/ltree/ltree.h @@ -157,8 +157,6 @@ typedef struct char data[FLEXIBLE_ARRAY_MEMBER]; } ltxtquery; -typedef bool (*ltree_prefix_eq_func) (const char *, size_t, const char *, size_t); - #define HDRSIZEQT MAXALIGN(VARHDRSZ + sizeof(int32)) #define COMPUTESIZE(size,lenofoperand) ( HDRSIZEQT + (size) * sizeof(ITEM) + (lenofoperand) ) #define LTXTQUERY_TOO_BIG(size,lenofoperand) \ @@ -209,11 +207,11 @@ bool ltree_execute(ITEM *curitem, void *checkval, int ltree_compare(const ltree *a, const ltree *b); bool inner_isparent(const ltree *c, const ltree *p); -bool compare_subnode(ltree_level *t, char *qn, int len, - ltree_prefix_eq_func prefix_eq, bool anyend); +bool compare_subnode(ltree_level *t, char *qn, int len, bool prefix, bool ci); ltree *lca_inner(ltree **a, int len); -bool ltree_prefix_eq(const char *a, size_t a_sz, const char *b, size_t b_sz); -bool ltree_prefix_eq_ci(const char *a, size_t a_sz, const char *b, size_t b_sz); +bool ltree_label_match(const char *pred, size_t pred_len, + const char *label, size_t label_len, + bool prefix, bool ci); /* fmgr macros for ltree objects */ #define DatumGetLtreeP(X) ((ltree *) PG_DETOAST_DATUM(X)) diff --git a/contrib/ltree/ltree_io.c b/contrib/ltree/ltree_io.c index 827a7822fbc..5192a184d02 100644 --- a/contrib/ltree/ltree_io.c +++ b/contrib/ltree/ltree_io.c @@ -7,6 +7,7 @@ #include +#include "common/int.h" #include "crc32.h" #include "libpq/pqformat.h" #include "ltree.h" @@ -344,7 +345,12 @@ parse_lquery(const char *buf, struct Node *escontext) lptr++; lptr->start = ptr; state = LQPRS_WAITDELIM; - curqlevel->numvar++; + if (pg_add_u16_overflow(curqlevel->numvar, 1, &curqlevel->numvar)) + ereturn(escontext, NULL, + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), + errmsg("lquery level has too many variants"), + errdetail("Number of variants exceeds the maximum allowed (%d).", + PG_UINT16_MAX))); } else UNCHAR; @@ -542,7 +548,16 @@ parse_lquery(const char *buf, struct Node *escontext) lptr = GETVAR(curqlevel); while (lptr - GETVAR(curqlevel) < curqlevel->numvar) { - cur->totallen += MAXALIGN(LVAR_HDRSIZE + lptr->len); + int newlen = cur->totallen + MAXALIGN(LVAR_HDRSIZE + lptr->len); + + if (newlen > PG_UINT16_MAX) + ereturn(escontext, NULL, + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), + errmsg("lquery level is too large"), + errdetail("Total size of level exceeds the maximum allowed (%d bytes).", + PG_UINT16_MAX))); + cur->totallen = (uint16) newlen; + lrptr->len = lptr->len; lrptr->flag = lptr->flag; lrptr->val = ltree_crc32_sz(lptr->start, lptr->len); diff --git a/contrib/ltree/ltxtquery_io.c b/contrib/ltree/ltxtquery_io.c index 113f97afc24..5eca740cb35 100644 --- a/contrib/ltree/ltxtquery_io.c +++ b/contrib/ltree/ltxtquery_io.c @@ -294,33 +294,71 @@ makepol(QPRS_STATE *state) return END; } -static void -findoprnd(ITEM *ptr, int32 *pos) +/* + * Recursively fill the "left" fields of an ITEM array that represents + * a valid postfix tree. + * + * state: only needed for error reporting + * ptr: starting element of array + * pos: in/out argument, the array index this call is responsible to fill + * + * At exit, *pos has been incremented to point after the sub-tree whose + * top is the entry-time value of *pos. + * + * Returns true if okay, false if error (the only possible error is + * overflow of a "left" field). + */ +static bool +findoprnd(QPRS_STATE *state, ITEM *ptr, int32 *pos) { + int32 mypos; + /* since this function recurses, it could be driven to stack overflow. */ check_stack_depth(); - if (ptr[*pos].type == VAL || ptr[*pos].type == VALTRUE) + /* get the position this call is supposed to update */ + mypos = *pos; + + /* in all cases, we should increment *pos to advance over this item */ + (*pos)++; + + if (ptr[mypos].type == VAL || ptr[mypos].type == VALTRUE) { - ptr[*pos].left = 0; - (*pos)++; + /* base case: a VAL has no operand, so just set its left to zero */ + ptr[mypos].left = 0; } - else if (ptr[*pos].val == (int32) '!') + else if (ptr[mypos].val == (int32) '!') { - ptr[*pos].left = 1; - (*pos)++; - findoprnd(ptr, pos); + /* unary operator, likewise easy: operand is just after it */ + ptr[mypos].left = 1; + /* recurse to scan operand */ + if (!findoprnd(state, ptr, pos)) + return false; } else { - ITEM *curitem = &ptr[*pos]; - int32 tmp = *pos; - - (*pos)++; - findoprnd(ptr, pos); - curitem->left = *pos - tmp; - findoprnd(ptr, pos); + /* binary operator */ + int32 delta; + + /* recurse to scan right operand */ + if (!findoprnd(state, ptr, pos)) + return false; + /* we must fill left with offset to left operand's top */ + /* delta can't overflow, see LTXTQUERY_TOO_BIG ... */ + delta = *pos - mypos; + /* ... but it might be too large to fit in the 16-bit left field */ + Assert(delta > 0); + if (unlikely(delta > PG_INT16_MAX)) + ereturn(state->escontext, false, + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), + errmsg("ltxtquery is too large"))); + ptr[mypos].left = (int16) delta; + /* recurse to scan left operand */ + if (!findoprnd(state, ptr, pos)) + return false; } + + return true; } @@ -396,7 +434,10 @@ queryin(char *buf, struct Node *escontext) /* set left operand's position for every operator */ pos = 0; - findoprnd(ptr, &pos); + if (!findoprnd(&state, ptr, &pos)) + return NULL; + /* if successful, findoprnd should have scanned the whole array */ + Assert(pos == state.num); return query; } diff --git a/contrib/ltree/ltxtquery_op.c b/contrib/ltree/ltxtquery_op.c index 3dcbab2c484..0e6612ff77a 100644 --- a/contrib/ltree/ltxtquery_op.c +++ b/contrib/ltree/ltxtquery_op.c @@ -58,19 +58,18 @@ checkcondition_str(void *checkval, ITEM *val) ltree_level *level = LTREE_FIRST(((CHKVAL *) checkval)->node); int tlen = ((CHKVAL *) checkval)->node->numlevel; char *op = ((CHKVAL *) checkval)->operand + val->distance; - ltree_prefix_eq_func prefix_eq; + bool prefix = (val->flag & LVAR_ANYEND); + bool ci = (val->flag & LVAR_INCASE); - prefix_eq = (val->flag & LVAR_INCASE) ? ltree_prefix_eq_ci : ltree_prefix_eq; while (tlen > 0) { if (val->flag & LVAR_SUBLEXEME) { - if (compare_subnode(level, op, val->length, prefix_eq, (val->flag & LVAR_ANYEND))) + if (compare_subnode(level, op, val->length, prefix, ci)) return true; } - else if ((val->length == level->len || - (level->len > val->length && (val->flag & LVAR_ANYEND))) && - (*prefix_eq) (op, val->length, level->name, level->len)) + else if (ltree_label_match(op, val->length, level->name, level->len, + prefix, ci)) return true; tlen--; diff --git a/contrib/pg_overexplain/expected/ivy_pg_overexplain.out b/contrib/pg_overexplain/expected/ivy_pg_overexplain.out index c190fe1df65..f2fb042b79f 100644 --- a/contrib/pg_overexplain/expected/ivy_pg_overexplain.out +++ b/contrib/pg_overexplain/expected/ivy_pg_overexplain.out @@ -292,9 +292,9 @@ $$); false + false + + - 1 3 4 + - none + + + 1 3 4 + + none + + (1 row) diff --git a/contrib/pg_overexplain/expected/pg_overexplain.out b/contrib/pg_overexplain/expected/pg_overexplain.out index 6de02323d7c..0c1d32d386e 100644 --- a/contrib/pg_overexplain/expected/pg_overexplain.out +++ b/contrib/pg_overexplain/expected/pg_overexplain.out @@ -291,13 +291,130 @@ $$); false + false + + - 1 3 4 + - none + + + 1 3 4 + + none + + (1 row) +-- Test JSON format with RANGE_TABLE to verify valid JSON structure. +SELECT explain_filter($$ +EXPLAIN (RANGE_TABLE, FORMAT JSON, COSTS OFF) +SELECT genus, array_agg(name ORDER BY name) FROM vegetables GROUP BY genus +$$); + explain_filter +---------------------------------------------------------------- + [ + + { + + "Plan": { + + "Node Type": "Aggregate", + + "Strategy": "Sorted", + + "Partial Mode": "Simple", + + "Parallel Aware": false, + + "Async Capable": false, + + "Disabled": false, + + "Group Key": ["vegetables.genus"], + + "Plans": [ + + { + + "Node Type": "Sort", + + "Parent Relationship": "Outer", + + "Parallel Aware": false, + + "Async Capable": false, + + "Disabled": false, + + "Sort Key": ["vegetables.genus", "vegetables.name"],+ + "Plans": [ + + { + + "Node Type": "Append", + + "Parent Relationship": "Outer", + + "Parallel Aware": false, + + "Async Capable": false, + + "Disabled": false, + + "Append RTIs": "1", + + "Subplans Removed": 0, + + "Plans": [ + + { + + "Node Type": "Seq Scan", + + "Parent Relationship": "Member", + + "Parallel Aware": false, + + "Async Capable": false, + + "Relation Name": "brassica", + + "Alias": "vegetables_1", + + "Disabled": false, + + "Scan RTI": 3 + + }, + + { + + "Node Type": "Seq Scan", + + "Parent Relationship": "Member", + + "Parallel Aware": false, + + "Async Capable": false, + + "Relation Name": "daucus", + + "Alias": "vegetables_2", + + "Disabled": false, + + "Scan RTI": 4 + + } + + ] + + } + + ] + + } + + ] + + }, + + "Range Table": [ + + { + + "RTI": 1, + + "Kind": "relation", + + "Inherited": true, + + "In From Clause": true, + + "Eref": "vegetables (id, name, genus)", + + "Relation": "vegetables", + + "Relation Kind": "partitioned_table", + + "Relation Lock Mode": "AccessShareLock", + + "Permission Info Index": 1, + + "Security Barrier": false, + + "Lateral": false + + }, + + { + + "RTI": 2, + + "Kind": "group", + + "Inherited": false, + + "In From Clause": false, + + "Eref": "\"*GROUP*\" (genus)", + + "Security Barrier": false, + + "Lateral": false + + }, + + { + + "RTI": 3, + + "Kind": "relation", + + "Inherited": false, + + "In From Clause": true, + + "Alias": "vegetables (id, name, genus)", + + "Eref": "vegetables (id, name, genus)", + + "Relation": "brassica", + + "Relation Kind": "relation", + + "Relation Lock Mode": "AccessShareLock", + + "Security Barrier": false, + + "Lateral": false + + }, + + { + + "RTI": 4, + + "Kind": "relation", + + "Inherited": false, + + "In From Clause": true, + + "Alias": "vegetables (id, name, genus)", + + "Eref": "vegetables (id, name, genus)", + + "Relation": "daucus", + + "Relation Kind": "relation", + + "Relation Lock Mode": "AccessShareLock", + + "Security Barrier": false, + + "Lateral": false + + } + + ], + + "Unprunable RTIs": "1 3 4", + + "Result RTIs": "none" + + } + + ] +(1 row) + -- Test just the DEBUG option. Verify that it shows information about -- disabled nodes, parallel safety, and the parallelModeNeeded flag. SET enable_seqscan = false; diff --git a/contrib/pg_overexplain/pg_overexplain.c b/contrib/pg_overexplain/pg_overexplain.c index de824566f8c..78f128562e6 100644 --- a/contrib/pg_overexplain/pg_overexplain.c +++ b/contrib/pg_overexplain/pg_overexplain.c @@ -658,7 +658,14 @@ overexplain_range_table(PlannedStmt *plannedstmt, ExplainState *es) ExplainCloseGroup("Range Table Entry", NULL, true, es); } - /* Print PlannedStmt fields that contain RTIs. */ + /* Close the Range Table array before emitting PlannedStmt-level fields. */ + ExplainCloseGroup("Range Table", "Range Table", false, es); + + /* + * Print PlannedStmt fields that contain RTIs. These are properties of + * the PlannedStmt, not of individual RTEs, so they belong outside the + * Range Table array. + */ if (es->format != EXPLAIN_FORMAT_TEXT || !bms_is_empty(plannedstmt->unprunableRelids)) overexplain_bitmapset("Unprunable RTIs", plannedstmt->unprunableRelids, @@ -666,9 +673,6 @@ overexplain_range_table(PlannedStmt *plannedstmt, ExplainState *es) if (es->format != EXPLAIN_FORMAT_TEXT || plannedstmt->resultRelations != NIL) overexplain_intlist("Result RTIs", plannedstmt->resultRelations, es); - - /* Close group, we're all done */ - ExplainCloseGroup("Range Table", "Range Table", false, es); } /* diff --git a/contrib/pg_overexplain/sql/pg_overexplain.sql b/contrib/pg_overexplain/sql/pg_overexplain.sql index 42e275ac2f9..4703ac3e3d7 100644 --- a/contrib/pg_overexplain/sql/pg_overexplain.sql +++ b/contrib/pg_overexplain/sql/pg_overexplain.sql @@ -66,6 +66,12 @@ EXPLAIN (DEBUG, RANGE_TABLE, FORMAT XML, COSTS OFF) SELECT genus, array_agg(name ORDER BY name) FROM vegetables GROUP BY genus $$); +-- Test JSON format with RANGE_TABLE to verify valid JSON structure. +SELECT explain_filter($$ +EXPLAIN (RANGE_TABLE, FORMAT JSON, COSTS OFF) +SELECT genus, array_agg(name ORDER BY name) FROM vegetables GROUP BY genus +$$); + -- Test just the DEBUG option. Verify that it shows information about -- disabled nodes, parallel safety, and the parallelModeNeeded flag. SET enable_seqscan = false; diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c index 375da9a198a..e3dce9613ad 100644 --- a/contrib/pg_stat_statements/pg_stat_statements.c +++ b/contrib/pg_stat_statements/pg_stat_statements.c @@ -805,7 +805,7 @@ pgss_shmem_shutdown(int code, Datum arg) if (fwrite(&pgss->stats, sizeof(pgssGlobalStats), 1, file) != 1) goto error; - free(qbuffer); + pfree(qbuffer); qbuffer = NULL; if (FreeFile(file)) @@ -829,7 +829,8 @@ pgss_shmem_shutdown(int code, Datum arg) (errcode_for_file_access(), errmsg("could not write file \"%s\": %m", PGSS_DUMP_FILE ".tmp"))); - free(qbuffer); + if (qbuffer) + pfree(qbuffer); if (file) FreeFile(file); unlink(PGSS_DUMP_FILE ".tmp"); @@ -1798,7 +1799,8 @@ pg_stat_statements_internal(FunctionCallInfo fcinfo, pgss->extent != extent || pgss->gc_count != gc_count) { - free(qbuffer); + if (qbuffer) + pfree(qbuffer); qbuffer = qtext_load_file(&qbuffer_size); } } @@ -2013,7 +2015,8 @@ pg_stat_statements_internal(FunctionCallInfo fcinfo, LWLockRelease(pgss->lock); - free(qbuffer); + if (qbuffer) + pfree(qbuffer); } /* Number of output arguments (columns) for pg_stat_statements_info */ @@ -2300,7 +2303,7 @@ qtext_store(const char *query, int query_len, } /* - * Read the external query text file into a malloc'd buffer. + * Read the external query text file into a palloc'd buffer. * * Returns NULL (without throwing an error) if unable to read, eg * file not there or insufficient memory. @@ -2342,7 +2345,7 @@ qtext_load_file(Size *buffer_size) /* Allocate buffer; beware that off_t might be wider than size_t */ if (stat.st_size <= MaxAllocHugeSize) - buf = (char *) malloc(stat.st_size); + buf = (char *) palloc_extended(stat.st_size, MCXT_ALLOC_HUGE | MCXT_ALLOC_NO_OOM); else buf = NULL; if (buf == NULL) @@ -2381,7 +2384,7 @@ qtext_load_file(Size *buffer_size) (errcode_for_file_access(), errmsg("could not read file \"%s\": %m", PGSS_TEXT_FILE))); - free(buf); + pfree(buf); CloseTransientFile(fd); return NULL; } @@ -2592,7 +2595,7 @@ gc_qtexts(void) else pgss->mean_query_len = ASSUMED_LENGTH_INIT; - free(qbuffer); + pfree(qbuffer); /* * OK, count a garbage collection cycle. (Note: even though we have @@ -2609,7 +2612,8 @@ gc_qtexts(void) /* clean up resources */ if (qfile) FreeFile(qfile); - free(qbuffer); + if (qbuffer) + pfree(qbuffer); /* * Since the contents of the external file are now uncertain, mark all diff --git a/contrib/postgres_fdw/connection.c b/contrib/postgres_fdw/connection.c index f80528efb8d..738edc2c8ee 100644 --- a/contrib/postgres_fdw/connection.c +++ b/contrib/postgres_fdw/connection.c @@ -660,8 +660,9 @@ disconnect_pg_server(ConnCacheEntry *entry) } /* - * Return true if the password_required is defined and false for this user - * mapping, otherwise false. The mapping has been pre-validated. + * Check and return the value of password_required, if defined; otherwise, + * return true, which is the default value of it. The mapping has been + * pre-validated. */ static bool UserMappingPasswordRequired(UserMapping *user) @@ -1341,6 +1342,11 @@ pgfdw_inval_callback(Datum arg, int cacheid, uint32 hashvalue) * Such connections can't safely be further used. Re-establishing the * connection would change the snapshot and roll back any writes already * performed, so that's not an option, either. Thus, we must abort. + * + * Note: there might be open cursors that use the connection, so even if the + * connection cache entry is marked as such, we will retain it until abort + * cleanup of the main transaction, to ensure such open cursors can safely + * refer to the PGconn for the connection. */ static void pgfdw_reject_incomplete_xact_state_change(ConnCacheEntry *entry) @@ -1351,15 +1357,12 @@ pgfdw_reject_incomplete_xact_state_change(ConnCacheEntry *entry) if (entry->conn == NULL || !entry->changing_xact_state) return; - /* make sure this entry is inactive */ - disconnect_pg_server(entry); - /* find server name to be shown in the message below */ server = GetForeignServer(entry->serverid); ereport(ERROR, (errcode(ERRCODE_CONNECTION_EXCEPTION), - errmsg("connection to server \"%s\" was lost", + errmsg("connection to server \"%s\" cannot be used due to abort cleanup failure", server->servername))); } diff --git a/contrib/postgres_fdw/expected/ivy_postgres_fdw.out b/contrib/postgres_fdw/expected/ivy_postgres_fdw.out index e79c9aa27c3..a11e4c3499c 100644 --- a/contrib/postgres_fdw/expected/ivy_postgres_fdw.out +++ b/contrib/postgres_fdw/expected/ivy_postgres_fdw.out @@ -14071,4 +14071,81 @@ SELECT server_name, -- Clean up \set VERBOSITY default RESET debug_discard_caches; +-- =================================================================== +-- test cleanup of failed connections on abort +-- =================================================================== +CREATE VIEW my_backend_pid (pid) AS SELECT pg_backend_pid(); +CREATE FOREIGN TABLE remote_backend_pid (pid int) + SERVER loopback OPTIONS (table_name 'my_backend_pid'); +CREATE FUNCTION wait_for_backend_termination(int) RETURNS void AS $$ + BEGIN + WHILE (SELECT count(*) FROM pg_stat_activity WHERE pid = $1) > 0 + LOOP + PERFORM pg_stat_clear_snapshot(); + END LOOP; + END +$$ LANGUAGE plpgsql; +/ +SET client_min_messages = 'ERROR'; +BEGIN; +DECLARE c CURSOR FOR SELECT * FROM ft1 ORDER BY c1; +SAVEPOINT s; +SELECT pid AS remote_pid FROM remote_backend_pid \gset +SELECT pg_terminate_backend(:remote_pid); + pg_terminate_backend +---------------------- + t +(1 row) + +SELECT wait_for_backend_termination(:remote_pid); + wait_for_backend_termination +------------------------------ + +(1 row) + +ROLLBACK TO SAVEPOINT s; +SELECT pid FROM remote_backend_pid; +ERROR: connection to server "loopback" cannot be used due to abort cleanup failure +ROLLBACK TO SAVEPOINT s; +RELEASE SAVEPOINT s; +FETCH c; +ERROR: no connection to the server +CONTEXT: remote SQL command: DECLARE c1 CURSOR FOR +SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" +ABORT; +BEGIN; +DECLARE c CURSOR FOR SELECT * FROM ft1 ORDER BY c1; +FETCH c; + c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 +----+----+-------------------+-----------------------------------+----------------------------+----+------------+----- + 1 | 2 | 00001_trig_update | 1970-01-02 00:00:00.000000 -08:00 | 1970-01-02 00:00:00.000000 | 1 | 1 | foo +(1 row) + +SAVEPOINT s; +SELECT pid AS remote_pid FROM remote_backend_pid \gset +SELECT pg_terminate_backend(:remote_pid); + pg_terminate_backend +---------------------- + t +(1 row) + +SELECT wait_for_backend_termination(:remote_pid); + wait_for_backend_termination +------------------------------ + +(1 row) + +ROLLBACK TO SAVEPOINT s; +SELECT pid FROM remote_backend_pid; +ERROR: connection to server "loopback" cannot be used due to abort cleanup failure +ROLLBACK TO SAVEPOINT s; +RELEASE SAVEPOINT s; +CLOSE c; +ERROR: no connection to the server +CONTEXT: remote SQL command: CLOSE c1 +ABORT; +RESET client_min_messages; +DROP FUNCTION wait_for_backend_termination(int); +DROP FOREIGN TABLE remote_backend_pid; +DROP VIEW my_backend_pid; RESET ivorysql.enable_emptystring_to_NULL; diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out index abfc84f8860..f975ceff200 100644 --- a/contrib/postgres_fdw/expected/postgres_fdw.out +++ b/contrib/postgres_fdw/expected/postgres_fdw.out @@ -12714,3 +12714,79 @@ SELECT server_name, -- Clean up \set VERBOSITY default RESET debug_discard_caches; +-- =================================================================== +-- test cleanup of failed connections on abort +-- =================================================================== +CREATE VIEW my_backend_pid (pid) AS SELECT pg_backend_pid(); +CREATE FOREIGN TABLE remote_backend_pid (pid int) + SERVER loopback OPTIONS (table_name 'my_backend_pid'); +CREATE FUNCTION wait_for_backend_termination(int) RETURNS void AS $$ + BEGIN + WHILE (SELECT count(*) FROM pg_stat_activity WHERE pid = $1) > 0 + LOOP + PERFORM pg_stat_clear_snapshot(); + END LOOP; + END +$$ LANGUAGE plpgsql; +SET client_min_messages = 'ERROR'; +BEGIN; +DECLARE c CURSOR FOR SELECT * FROM ft1 ORDER BY c1; +SAVEPOINT s; +SELECT pid AS remote_pid FROM remote_backend_pid \gset +SELECT pg_terminate_backend(:remote_pid); + pg_terminate_backend +---------------------- + t +(1 row) + +SELECT wait_for_backend_termination(:remote_pid); + wait_for_backend_termination +------------------------------ + +(1 row) + +ROLLBACK TO SAVEPOINT s; +SELECT pid FROM remote_backend_pid; +ERROR: connection to server "loopback" cannot be used due to abort cleanup failure +ROLLBACK TO SAVEPOINT s; +RELEASE SAVEPOINT s; +FETCH c; +ERROR: no connection to the server +CONTEXT: remote SQL command: DECLARE c1 CURSOR FOR +SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" ORDER BY "C 1" ASC NULLS LAST +ABORT; +BEGIN; +DECLARE c CURSOR FOR SELECT * FROM ft1 ORDER BY c1; +FETCH c; + c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 +----+----+-------------------+------------------------------+--------------------------+----+------------+----- + 1 | 2 | 00001_trig_update | Fri Jan 02 00:00:00 1970 PST | Fri Jan 02 00:00:00 1970 | 1 | 1 | foo +(1 row) + +SAVEPOINT s; +SELECT pid AS remote_pid FROM remote_backend_pid \gset +SELECT pg_terminate_backend(:remote_pid); + pg_terminate_backend +---------------------- + t +(1 row) + +SELECT wait_for_backend_termination(:remote_pid); + wait_for_backend_termination +------------------------------ + +(1 row) + +ROLLBACK TO SAVEPOINT s; +SELECT pid FROM remote_backend_pid; +ERROR: connection to server "loopback" cannot be used due to abort cleanup failure +ROLLBACK TO SAVEPOINT s; +RELEASE SAVEPOINT s; +CLOSE c; +ERROR: no connection to the server +CONTEXT: remote SQL command: CLOSE c1 +ABORT; +RESET client_min_messages; +DROP FUNCTION wait_for_backend_termination(int); +DROP FOREIGN TABLE remote_backend_pid; +DROP VIEW my_backend_pid; diff --git a/contrib/postgres_fdw/sql/ivy_postgres_fdw.sql b/contrib/postgres_fdw/sql/ivy_postgres_fdw.sql index bf6013f4f12..afcd5d9ed56 100644 --- a/contrib/postgres_fdw/sql/ivy_postgres_fdw.sql +++ b/contrib/postgres_fdw/sql/ivy_postgres_fdw.sql @@ -4543,5 +4543,56 @@ SELECT server_name, \set VERBOSITY default RESET debug_discard_caches; +-- =================================================================== +-- test cleanup of failed connections on abort +-- =================================================================== + +CREATE VIEW my_backend_pid (pid) AS SELECT pg_backend_pid(); +CREATE FOREIGN TABLE remote_backend_pid (pid int) + SERVER loopback OPTIONS (table_name 'my_backend_pid'); +CREATE FUNCTION wait_for_backend_termination(int) RETURNS void AS $$ + BEGIN + WHILE (SELECT count(*) FROM pg_stat_activity WHERE pid = $1) > 0 + LOOP + PERFORM pg_stat_clear_snapshot(); + END LOOP; + END +$$ LANGUAGE plpgsql; +/ + +SET client_min_messages = 'ERROR'; + +BEGIN; +DECLARE c CURSOR FOR SELECT * FROM ft1 ORDER BY c1; +SAVEPOINT s; +SELECT pid AS remote_pid FROM remote_backend_pid \gset +SELECT pg_terminate_backend(:remote_pid); +SELECT wait_for_backend_termination(:remote_pid); +ROLLBACK TO SAVEPOINT s; +SELECT pid FROM remote_backend_pid; +ROLLBACK TO SAVEPOINT s; +RELEASE SAVEPOINT s; +FETCH c; +ABORT; + +BEGIN; +DECLARE c CURSOR FOR SELECT * FROM ft1 ORDER BY c1; +FETCH c; +SAVEPOINT s; +SELECT pid AS remote_pid FROM remote_backend_pid \gset +SELECT pg_terminate_backend(:remote_pid); +SELECT wait_for_backend_termination(:remote_pid); +ROLLBACK TO SAVEPOINT s; +SELECT pid FROM remote_backend_pid; +ROLLBACK TO SAVEPOINT s; +RELEASE SAVEPOINT s; +CLOSE c; +ABORT; + +RESET client_min_messages; + +DROP FUNCTION wait_for_backend_termination(int); +DROP FOREIGN TABLE remote_backend_pid; +DROP VIEW my_backend_pid; RESET ivorysql.enable_emptystring_to_NULL; diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql index f03c5aab4d9..04a5a1244e8 100644 --- a/contrib/postgres_fdw/sql/postgres_fdw.sql +++ b/contrib/postgres_fdw/sql/postgres_fdw.sql @@ -4433,3 +4433,54 @@ SELECT server_name, -- Clean up \set VERBOSITY default RESET debug_discard_caches; + +-- =================================================================== +-- test cleanup of failed connections on abort +-- =================================================================== + +CREATE VIEW my_backend_pid (pid) AS SELECT pg_backend_pid(); +CREATE FOREIGN TABLE remote_backend_pid (pid int) + SERVER loopback OPTIONS (table_name 'my_backend_pid'); +CREATE FUNCTION wait_for_backend_termination(int) RETURNS void AS $$ + BEGIN + WHILE (SELECT count(*) FROM pg_stat_activity WHERE pid = $1) > 0 + LOOP + PERFORM pg_stat_clear_snapshot(); + END LOOP; + END +$$ LANGUAGE plpgsql; + +SET client_min_messages = 'ERROR'; + +BEGIN; +DECLARE c CURSOR FOR SELECT * FROM ft1 ORDER BY c1; +SAVEPOINT s; +SELECT pid AS remote_pid FROM remote_backend_pid \gset +SELECT pg_terminate_backend(:remote_pid); +SELECT wait_for_backend_termination(:remote_pid); +ROLLBACK TO SAVEPOINT s; +SELECT pid FROM remote_backend_pid; +ROLLBACK TO SAVEPOINT s; +RELEASE SAVEPOINT s; +FETCH c; +ABORT; + +BEGIN; +DECLARE c CURSOR FOR SELECT * FROM ft1 ORDER BY c1; +FETCH c; +SAVEPOINT s; +SELECT pid AS remote_pid FROM remote_backend_pid \gset +SELECT pg_terminate_backend(:remote_pid); +SELECT wait_for_backend_termination(:remote_pid); +ROLLBACK TO SAVEPOINT s; +SELECT pid FROM remote_backend_pid; +ROLLBACK TO SAVEPOINT s; +RELEASE SAVEPOINT s; +CLOSE c; +ABORT; + +RESET client_min_messages; + +DROP FUNCTION wait_for_backend_termination(int); +DROP FOREIGN TABLE remote_backend_pid; +DROP VIEW my_backend_pid; diff --git a/contrib/spi/refint.c b/contrib/spi/refint.c index d5e25e07ae9..ab0b2b291f9 100644 --- a/contrib/spi/refint.c +++ b/contrib/spi/refint.c @@ -171,21 +171,24 @@ check_primary_key(PG_FUNCTION_ARGS) if (plan->nplans <= 0) { SPIPlanPtr pplan; - char sql[8192]; + StringInfoData sql; + + initStringInfo(&sql); /* * Construct query: SELECT 1 FROM _referenced_relation_ WHERE Pkey1 = * $1 [AND Pkey2 = $2 [...]] */ - snprintf(sql, sizeof(sql), "select 1 from %s where ", relname); - for (i = 0; i < nkeys; i++) + appendStringInfo(&sql, "select 1 from %s where ", relname); + for (i = 1; i <= nkeys; i++) { - snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s = $%d %s", - args[i + nkeys + 1], i + 1, (i < nkeys - 1) ? "and " : ""); + appendStringInfo(&sql, "%s = $%d ", args[i + nkeys], i); + if (i < nkeys) + appendStringInfoString(&sql, "and "); } /* Prepare plan for query */ - pplan = SPI_prepare(sql, nkeys, argtypes); + pplan = SPI_prepare(sql.data, nkeys, argtypes); if (pplan == NULL) /* internal error */ elog(ERROR, "check_primary_key: SPI_prepare returned %s", SPI_result_code_string(SPI_result)); @@ -201,6 +204,8 @@ check_primary_key(PG_FUNCTION_ARGS) sizeof(SPIPlanPtr)); *(plan->splan) = pplan; plan->nplans = 1; + + pfree(sql.data); } /* @@ -423,7 +428,6 @@ check_foreign_key(PG_FUNCTION_ARGS) if (plan->nplans <= 0) { SPIPlanPtr pplan; - char sql[8192]; char **args2 = args; plan->splan = (SPIPlanPtr *) MemoryContextAlloc(TopMemoryContext, @@ -431,6 +435,10 @@ check_foreign_key(PG_FUNCTION_ARGS) for (r = 0; r < nrefs; r++) { + StringInfoData sql; + + initStringInfo(&sql); + relname = args2[0]; /*--------- @@ -444,8 +452,7 @@ check_foreign_key(PG_FUNCTION_ARGS) *--------- */ if (action == 'r') - - snprintf(sql, sizeof(sql), "select 1 from %s where ", relname); + appendStringInfo(&sql, "select 1 from %s where ", relname); /*--------- * For 'C'ascade action we construct DELETE query @@ -472,42 +479,23 @@ check_foreign_key(PG_FUNCTION_ARGS) char *nv; int k; - snprintf(sql, sizeof(sql), "update %s set ", relname); + appendStringInfo(&sql, "update %s set ", relname); for (k = 1; k <= nkeys; k++) { - int is_char_type = 0; - char *type; - fn = SPI_fnumber(tupdesc, args_temp[k - 1]); Assert(fn > 0); /* already checked above */ nv = SPI_getvalue(newtuple, tupdesc, fn); - type = SPI_gettype(tupdesc, fn); - - if (strcmp(type, "text") == 0 || - strcmp(type, "varchar") == 0 || - strcmp(type, "char") == 0 || - strcmp(type, "bpchar") == 0 || - strcmp(type, "date") == 0 || - strcmp(type, "timestamp") == 0) - is_char_type = 1; -#ifdef DEBUG_QUERY - elog(DEBUG4, "check_foreign_key Debug value %s type %s %d", - nv, type, is_char_type); -#endif - /* - * is_char_type =1 i set ' ' for define a new value - */ - snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), - " %s = %s%s%s %s ", - args2[k], (is_char_type > 0) ? "'" : "", - nv, (is_char_type > 0) ? "'" : "", (k < nkeys) ? ", " : ""); + appendStringInfo(&sql, " %s = %s ", + args2[k], quote_literal_cstr(nv)); + if (k < nkeys) + appendStringInfoString(&sql, ", "); } - strcat(sql, " where "); + appendStringInfoString(&sql, " where "); } else /* DELETE */ - snprintf(sql, sizeof(sql), "delete from %s where ", relname); + appendStringInfo(&sql, "delete from %s where ", relname); } /* @@ -518,25 +506,26 @@ check_foreign_key(PG_FUNCTION_ARGS) */ else if (action == 's') { - snprintf(sql, sizeof(sql), "update %s set ", relname); + appendStringInfo(&sql, "update %s set ", relname); for (i = 1; i <= nkeys; i++) { - snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), - "%s = null%s", - args2[i], (i < nkeys) ? ", " : ""); + appendStringInfo(&sql, "%s = null", args2[i]); + if (i < nkeys) + appendStringInfoString(&sql, ", "); } - strcat(sql, " where "); + appendStringInfoString(&sql, " where "); } /* Construct WHERE qual */ for (i = 1; i <= nkeys; i++) { - snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s = $%d %s", - args2[i], i, (i < nkeys) ? "and " : ""); + appendStringInfo(&sql, "%s = $%d ", args2[i], i); + if (i < nkeys) + appendStringInfoString(&sql, "and "); } /* Prepare plan for query */ - pplan = SPI_prepare(sql, nkeys, argtypes); + pplan = SPI_prepare(sql.data, nkeys, argtypes); if (pplan == NULL) /* internal error */ elog(ERROR, "check_foreign_key: SPI_prepare returned %s", SPI_result_code_string(SPI_result)); @@ -552,11 +541,14 @@ check_foreign_key(PG_FUNCTION_ARGS) plan->splan[r] = pplan; args2 += nkeys + 1; /* to the next relation */ + +#ifdef DEBUG_QUERY + elog(DEBUG4, "check_foreign_key Debug Query is : %s ", sql.data); +#endif + + pfree(sql.data); } plan->nplans = nrefs; -#ifdef DEBUG_QUERY - elog(DEBUG4, "check_foreign_key Debug Query is : %s ", sql); -#endif } /* diff --git a/contrib/xml2/expected/ivy_xml2.out b/contrib/xml2/expected/ivy_xml2.out index d8a1d2804fc..e343537fe8b 100644 --- a/contrib/xml2/expected/ivy_xml2.out +++ b/contrib/xml2/expected/ivy_xml2.out @@ -262,4 +262,14 @@ $$ $$); ERROR: failed to apply stylesheet +-- empty output +select xslt_process('', +$$ +$$); + xslt_process +-------------- + +(1 row) + reset ivorysql.enable_emptystring_to_null; diff --git a/contrib/xml2/expected/ivy_xml2_1.out b/contrib/xml2/expected/ivy_xml2_1.out index 40ce13c6e7a..2e21decc2ba 100644 --- a/contrib/xml2/expected/ivy_xml2_1.out +++ b/contrib/xml2/expected/ivy_xml2_1.out @@ -167,4 +167,10 @@ $$ $$); ERROR: xslt_process() is not available without libxslt +-- empty output +select xslt_process('', +$$ +$$); +ERROR: xslt_process() is not available without libxslt reset ivorysql.enable_emptystring_to_null; diff --git a/contrib/xml2/expected/xml2.out b/contrib/xml2/expected/xml2.out index 3d97b14c3a1..1906fcf33e2 100644 --- a/contrib/xml2/expected/xml2.out +++ b/contrib/xml2/expected/xml2.out @@ -261,3 +261,13 @@ $$ $$); ERROR: failed to apply stylesheet +-- empty output +select xslt_process('', +$$ +$$); + xslt_process +-------------- + +(1 row) + diff --git a/contrib/xml2/expected/xml2_1.out b/contrib/xml2/expected/xml2_1.out index 31e6d33c2df..6e53263a1a4 100644 --- a/contrib/xml2/expected/xml2_1.out +++ b/contrib/xml2/expected/xml2_1.out @@ -206,4 +206,10 @@ $$ $$); ERROR: xslt_process() is not available without libxslt +-- empty output +select xslt_process('', +$$ +$$); +ERROR: xslt_process() is not available without libxslt reset ivorysql.enable_emptystring_to_null; diff --git a/contrib/xml2/sql/ivy_xml2.sql b/contrib/xml2/sql/ivy_xml2.sql index fa1885f7a67..75af3ece5a6 100644 --- a/contrib/xml2/sql/ivy_xml2.sql +++ b/contrib/xml2/sql/ivy_xml2.sql @@ -153,4 +153,10 @@ $$ $$); + +-- empty output +select xslt_process('', +$$ +$$); reset ivorysql.enable_emptystring_to_null; diff --git a/contrib/xml2/sql/xml2.sql b/contrib/xml2/sql/xml2.sql index ef99d164f27..510d18a3679 100644 --- a/contrib/xml2/sql/xml2.sql +++ b/contrib/xml2/sql/xml2.sql @@ -153,3 +153,9 @@ $$ $$); + +-- empty output +select xslt_process('', +$$ +$$); diff --git a/contrib/xml2/xslt_proc.c b/contrib/xml2/xslt_proc.c index b720d89f754..8ff7c7f1bbf 100644 --- a/contrib/xml2/xslt_proc.c +++ b/contrib/xml2/xslt_proc.c @@ -176,7 +176,14 @@ xslt_process(PG_FUNCTION_ARGS) if (resstat < 0) PG_RETURN_NULL(); - result = cstring_to_text_with_len((char *) resstr, reslen); + /* + * If an empty string has been returned, resstr would be NULL. In + * this case, assume that the result is an empty string. + */ + if (reslen == 0) + result = cstring_to_text(""); + else + result = cstring_to_text_with_len((char *) resstr, reslen); if (resstr) xmlFree(resstr); diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index 2b4ba036f9c..2f3d95b832b 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -12740,7 +12740,9 @@ LOG: CleanUpLock: deleting: lock(0xb7acd844) id(24688,24696,0,0,0,1) If LLVM has the required functionality, register generated functions with GDB. This makes debugging easier. The default setting is off. - This parameter can only be set at server start. + Only superusers and users with the appropriate SET + privilege can change this parameter at session start, + and it cannot be changed at all within a session. @@ -12791,7 +12793,9 @@ LOG: CleanUpLock: deleting: lock(0xb7acd844) id(24688,24696,0,0,0,1) This writes out files to ~/.debug/jit/; the user is responsible for performing cleanup when desired. The default setting is off. - This parameter can only be set at server start. + Only superusers and users with the appropriate SET + privilege can change this parameter at session start, + and it cannot be changed at all within a session. diff --git a/doc/src/sgml/ddl.sgml b/doc/src/sgml/ddl.sgml index 49c98967d50..8813a09561b 100644 --- a/doc/src/sgml/ddl.sgml +++ b/doc/src/sgml/ddl.sgml @@ -5085,13 +5085,9 @@ EXPLAIN SELECT count(*) FROM measurement WHERE logdate >= DATE '2008-01-01'; It is possible to determine the number of partitions which were removed during this phase by observing the Subplans Removed property in the - EXPLAIN output. The query planner obtains locks for - all partitions which are part of the plan. However, when the executor - uses a cached plan, locks are only obtained on the partitions which - remain after partition pruning done during the initialization phase of - execution, i.e., the ones shown in the EXPLAIN - output and not the ones referred to by the - Subplans Removed property. + EXPLAIN output. It's important to note that any + partitions removed by the partition pruning done at this stage are + still locked at the beginning of execution. diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml index 7aa114291a6..62a278e61fb 100644 --- a/doc/src/sgml/libpq.sgml +++ b/doc/src/sgml/libpq.sgml @@ -7016,15 +7016,20 @@ int PQrequestCancel(PGconn *conn); to send simple function calls to the server. - + - This interface is somewhat obsolete, as one can achieve similar + This interface is unsafe and should not be used. When + result_is_int is set to 0, + PQfn may write data beyond the end of + result_buf, regardless of whether the buffer has + enough space for the requested number of bytes. Furthermore, it is + obsolete, as one can achieve similar performance and greater functionality by setting up a prepared statement to define the function call. Then, executing the statement with binary transmission of parameters and results substitutes for a fast-path function call. - + The function PQfnPQfn diff --git a/doc/src/sgml/logical-replication.sgml b/doc/src/sgml/logical-replication.sgml index fd2edc1addb..03e3ed9c170 100644 --- a/doc/src/sgml/logical-replication.sgml +++ b/doc/src/sgml/logical-replication.sgml @@ -68,7 +68,7 @@ Replicating between PostgreSQL instances on different platforms (for - example Linux to Windows) + example Linux to Windows). @@ -89,7 +89,7 @@ The subscriber database behaves in the same way as any other PostgreSQL instance and can be used as a publisher for other databases by defining its - own publications. When the subscriber is treated as read-only by + own publications. When the subscriber is treated as read-only by an application, there will be no conflicts from a single subscription. On the other hand, if there are other writes done either by an application or by other subscribers to the same set of tables, conflicts can arise. @@ -202,8 +202,8 @@ A subscription is the downstream side of logical replication. The node where a subscription is defined is referred to as the subscriber. A subscription defines the connection - to another database and set of publications (one or more) to which it wants - to subscribe. + to another database and the set of publications (one or more) to which it + wants to subscribe. @@ -977,7 +977,7 @@ HINT: To initiate replication, you must manually create the replication slot, e - If the subscriber is in a release prior to 15, copy pre-existing data + If the subscriber is in a release prior to 15, copying pre-existing data doesn't use row filters even if they are defined in the publication. This is because old releases can only copy the entire table data. @@ -2188,7 +2188,7 @@ CONTEXT: processing remote data for replication origin "pg_16395" during "INSER Initial Snapshot - The initial data in existing subscribed tables are snapshotted and + The initial data in existing subscribed tables is snapshotted and copied in parallel instances of a special kind of apply process. These special apply processes are dedicated table synchronization workers, spawned for each table to be synchronized. Each table diff --git a/doc/src/sgml/ref/alter_foreign_table.sgml b/doc/src/sgml/ref/alter_foreign_table.sgml index e2da3cc719f..9d923c00fff 100644 --- a/doc/src/sgml/ref/alter_foreign_table.sgml +++ b/doc/src/sgml/ref/alter_foreign_table.sgml @@ -32,7 +32,7 @@ ALTER FOREIGN TABLE [ IF EXISTS ] namewhere action is one of: - ADD [ COLUMN ] column_name data_type [ COLLATE collation ] [ column_constraint [ ... ] ] + ADD [ COLUMN ] [ IF NOT EXISTS ] column_name data_type [ COLLATE collation ] [ column_constraint [ ... ] ] DROP [ COLUMN ] [ IF EXISTS ] column_name [ RESTRICT | CASCADE ] ALTER [ COLUMN ] column_name [ SET DATA ] TYPE data_type [ COLLATE collation ] ALTER [ COLUMN ] column_name SET DEFAULT expression @@ -67,11 +67,13 @@ ALTER FOREIGN TABLE [ IF EXISTS ] name - ADD COLUMN + ADD [ COLUMN ] [ IF NOT EXISTS ] This form adds a new column to the foreign table, using the same syntax as CREATE FOREIGN TABLE. + If IF NOT EXISTS is specified and a column already + exists with this name, no error is thrown. Unlike the case when adding a column to a regular table, nothing happens to the underlying storage: this action simply declares that some new column is now accessible through the foreign table. @@ -80,7 +82,7 @@ ALTER FOREIGN TABLE [ IF EXISTS ] name - DROP COLUMN [ IF EXISTS ] + DROP [ COLUMN ] [ IF EXISTS ] This form drops a column from a foreign table. diff --git a/doc/src/sgml/ref/alter_index.sgml b/doc/src/sgml/ref/alter_index.sgml index 1d42d05d858..fb7096c16ea 100644 --- a/doc/src/sgml/ref/alter_index.sgml +++ b/doc/src/sgml/ref/alter_index.sgml @@ -97,6 +97,11 @@ ALTER INDEX ALL IN TABLESPACE name index cannot be dropped by itself, and will automatically be dropped if its parent index is dropped. + + If the named index is already attached to the altered index, the + command will attempt to validate the parent index if the parent is + currently invalid. + diff --git a/doc/src/sgml/ref/alter_subscription.sgml b/doc/src/sgml/ref/alter_subscription.sgml index fdc648d007f..1333a0b559f 100644 --- a/doc/src/sgml/ref/alter_subscription.sgml +++ b/doc/src/sgml/ref/alter_subscription.sgml @@ -272,7 +272,7 @@ ALTER SUBSCRIPTION name RENAME TO < process reports an error if any prepared transactions done by the logical replication worker (from when two_phase parameter was still true) are found. You can resolve - prepared transactions on the publisher node, or manually roll back them + prepared transactions on the publisher node, or manually roll them back on the subscriber, and then try again. The transactions prepared by logical replication worker corresponding to a particular subscription have the following pattern: pg_gid_%u_%u diff --git a/doc/src/sgml/ref/alter_table.sgml b/doc/src/sgml/ref/alter_table.sgml index 2a7d4b84f83..409164bf180 100644 --- a/doc/src/sgml/ref/alter_table.sgml +++ b/doc/src/sgml/ref/alter_table.sgml @@ -157,7 +157,7 @@ WITH ( MODULUS numeric_literal, REM - ADD COLUMN [ IF NOT EXISTS ] + ADD [ COLUMN ] [ IF NOT EXISTS ] This form adds a new column to the table, using the same syntax as @@ -169,7 +169,7 @@ WITH ( MODULUS numeric_literal, REM - DROP COLUMN [ IF EXISTS ] + DROP [ COLUMN ] [ IF EXISTS ] This form drops a column from a table. Indexes and diff --git a/doc/src/sgml/ref/comment.sgml b/doc/src/sgml/ref/comment.sgml index 5b43c56b133..a824b99f826 100644 --- a/doc/src/sgml/ref/comment.sgml +++ b/doc/src/sgml/ref/comment.sgml @@ -80,14 +80,16 @@ COMMENT ON Description - COMMENT stores a comment about a database object. + COMMENT stores, replaces, or removes the comment on a + database object. - Only one comment string is stored for each object, so to modify a comment, - issue a new COMMENT command for the same object. To remove a - comment, write NULL in place of the text string. - Comments are automatically dropped when their object is dropped. + Only one comment string is stored for each object. Issuing a new + COMMENT command for the same object replaces the + existing comment. Specifying NULL or an empty + string ('') removes the comment. Comments are + automatically dropped when their object is dropped. @@ -266,7 +268,8 @@ COMMENT ON string_literal - The new comment contents, written as a string literal. + The new comment contents, written as a string literal. An empty string + ('') removes the comment. @@ -275,7 +278,7 @@ COMMENT ON NULL - Write NULL to drop the comment. + Write NULL to remove the comment. @@ -362,6 +365,7 @@ COMMENT ON TRANSFORM FOR hstore LANGUAGE plpython3u IS 'Transform between hstore COMMENT ON TRIGGER my_trigger ON my_table IS 'Used for RI'; COMMENT ON TYPE complex IS 'Complex number data type'; COMMENT ON VIEW my_view IS 'View of departmental costs'; +COMMENT ON VIEW my_view IS NULL; diff --git a/doc/src/sgml/ref/create_foreign_table.sgml b/doc/src/sgml/ref/create_foreign_table.sgml index 009fa46532b..adc775b90c5 100644 --- a/doc/src/sgml/ref/create_foreign_table.sgml +++ b/doc/src/sgml/ref/create_foreign_table.sgml @@ -232,9 +232,9 @@ WITH ( MODULUS numeric_literal, REM INCLUDING COMMENTS - Comments for the copied columns and constraints will be - copied. The default behavior is to exclude comments, resulting in - the copied columns and constraints in the new table having no + Comments for the copied columns, constraints, and extended statistics + will be copied. The default behavior is to exclude comments, + resulting in the corresponding objects in the new table having no comments. diff --git a/doc/src/sgml/ref/create_publication.sgml b/doc/src/sgml/ref/create_publication.sgml index e83da50e4fe..b9e12a33c62 100644 --- a/doc/src/sgml/ref/create_publication.sgml +++ b/doc/src/sgml/ref/create_publication.sgml @@ -155,7 +155,7 @@ CREATE PUBLICATION name - When a partitioned table is published via schema level publication, all + When a partitioned table is published via a schema-level publication, all of its existing and future partitions are implicitly considered to be part of the publication, regardless of whether they are from the publication schema or not. So, even operations that are performed directly on a @@ -178,7 +178,7 @@ CREATE PUBLICATION name This parameter determines which DML operations will be published by - the new publication to the subscribers. The value is + the new publication to the subscribers. The value is a comma-separated list of operations. The allowed operations are insert, update, delete, and truncate. @@ -218,7 +218,7 @@ CREATE PUBLICATION name If the subscriber is from a release prior to 18, then initial table - synchronization won't copy generated columns even if parameter + synchronization won't copy generated columns even if the parameter publish_generated_columns is stored in the publisher. diff --git a/doc/src/sgml/ref/create_table.sgml b/doc/src/sgml/ref/create_table.sgml index 927d5417814..a033efce4de 100644 --- a/doc/src/sgml/ref/create_table.sgml +++ b/doc/src/sgml/ref/create_table.sgml @@ -672,9 +672,10 @@ WITH ( MODULUS numeric_literal, REM INCLUDING COMMENTS - Comments for the copied columns, constraints, and indexes will be + Comments for the copied columns, check constraints, + not-null constraints, indexes, and extended statistics will be copied. The default behavior is to exclude comments, resulting in - the copied columns and constraints in the new table having no + the corresponding objects in the new table having no comments. diff --git a/doc/src/sgml/ref/drop_subscription.sgml b/doc/src/sgml/ref/drop_subscription.sgml index d4f54c7170e..6e84bb0a256 100644 --- a/doc/src/sgml/ref/drop_subscription.sgml +++ b/doc/src/sgml/ref/drop_subscription.sgml @@ -49,6 +49,16 @@ DROP SUBSCRIPTION [ IF EXISTS ] nameParameters + + IF EXISTS + + + Do not throw an error if the subscription does not exist. A notice is + issued in this case. + + + + name diff --git a/doc/src/sgml/ref/pg_ctl-ref.sgml b/doc/src/sgml/ref/pg_ctl-ref.sgml index a0287bb81d6..b762b002c02 100644 --- a/doc/src/sgml/ref/pg_ctl-ref.sgml +++ b/doc/src/sgml/ref/pg_ctl-ref.sgml @@ -299,8 +299,9 @@ PostgreSQL documentation Append the server log output to filename. If the file does not - exist, it is created. The umask is set to 077, - so access to the log file is disallowed to other users by default. + exist, it is created. By default, only the cluster owner can + access the log file. If group access is enabled in the cluster, + users in the same group as the cluster owner can also read it. diff --git a/doc/src/sgml/ref/pg_walsummary.sgml b/doc/src/sgml/ref/pg_walsummary.sgml index 57b2d24650c..399b6879754 100644 --- a/doc/src/sgml/ref/pg_walsummary.sgml +++ b/doc/src/sgml/ref/pg_walsummary.sgml @@ -31,7 +31,7 @@ PostgreSQL documentation Description pg_walsummary is used to print the contents of - WAL summary files. These binary files are found with the + WAL summary files. These binary files are found in the pg_wal/summaries subdirectory of the data directory, and can be converted to text using this tool. This is not ordinarily necessary, since WAL summary files primarily exist to support diff --git a/doc/src/sgml/release-18.sgml b/doc/src/sgml/release-18.sgml index ebb84c43f23..9537f1932ec 100644 --- a/doc/src/sgml/release-18.sgml +++ b/doc/src/sgml/release-18.sgml @@ -1,6 +1,1877 @@ + + Release 18.4 + + + Release date: + 2026-05-14 + + + + This release contains a variety of fixes from 18.3. + For information about new features in major release 18, see + . + + + + Migration to Version 18.4 + + + A dump/restore is not required for those running 18.X. + + + + However, if you are upgrading from a version earlier than 18.2, + see . + + + + + Changes + + + + + + + Prevent unbounded recursion while processing startup packets + (Michael Paquier) + § + + + + A malicious client could crash the connected backend by alternating + rejected SSL and GSS encryption requests indefinitely. + + + + The PostgreSQL Project thanks Calif.io + (in collaboration with Claude and Anthropic Research) for reporting + this problem. + (CVE-2026-6479) + + + + + + + Fix assorted integer overflows in memory-allocation calculations + (Tom Lane, Nathan Bossart, Heikki Linnakangas) + § + § + § + § + § + § + § + § + § + + + + Various places were incautious about the possibility of integer + overflow in calculations of how much memory to allocate. Overflow + would lead to allocating a too-small buffer which the caller would + then write past the end of. This would at least trigger server + crashes, and probably could be exploited for arbitrary code + execution. In many but by no means all cases, the hazard exists + only in 32-bit builds. + + + + The PostgreSQL Project thanks Xint Code, + Bruce Dang, Sven Klemm, and Pavel Kohout for reporting these problems. + (CVE-2026-6473) + + + + + + + Properly quote subscription names + in pg_createsubscriber (Nathan Bossart) + § + + + + The given subscription name was inserted into SQL commands without + quoting, so that SQL injection could be achieved in the (perhaps + unlikely) case that the subscription name comes from an untrusted + source. + + + + The PostgreSQL Project thanks + Yu Kunpeng for reporting this problem. + (CVE-2026-6476) + + + + + + + Properly quote object names in logical replication origin checks + (Pavel Kohout) + § + + + + ALTER SUBSCRIPTION ... REFRESH PUBLICATION + interpolated schema and relation names into SQL commands without + quoting them, allowing execution of arbitrary SQL on the publisher. + + + + The PostgreSQL Project thanks + Pavel Kohout for reporting this problem. + (CVE-2026-6638) + + + + + + + Reject over-length options in ts_headline() + (Michael Paquier) + § + + + + The StartSel, StopSel + and FragmentDelimiter strings must not exceed + 32Kb in length, but this was not checked for. An over-length value + would typically crash the server. + + + + The PostgreSQL Project thanks + Xint Code for reporting this problem. + (CVE-2026-6473) + + + + + + + Detect faulty input when restoring attribute MCV statistics + (Michael Paquier) + § + + + + The statistics restore functions were insufficiently careful about + validating most-common-value statistics, and would accept values + that could crash the planner later on. + + + + The PostgreSQL Project thanks + Jeroen Gui for reporting this problem. + (CVE-2026-6575) + + + + + + + Guard against malicious time zone names + in timeofday() + and pg_strftime() (Tom Lane) + § + § + + + + A crafted time zone setting could pass % + sequences to snprintf(), potentially causing + crashes or disclosure of server memory. Another path to similar + results was to overflow the limited-size output buffer used + by pg_strftime(). + + + + The PostgreSQL Project thanks + Xint Code for reporting this problem. + (CVE-2026-6474) + + + + + + + When creating a multirange type, ensure the user + has CREATE privilege on the schema specified for + the multirange type (Jelte Fennema-Nio) + § + + + + The multirange type can be put into a different schema than its + parent range type, but we neglected to apply the required privilege + check when doing so. + + + + The PostgreSQL Project thanks + Jelte Fennema-Nio for reporting this problem. + (CVE-2026-6472) + + + + + + + Use timing-safe string comparisons in authentication code + (Michael Paquier) + § + + + + Use timingsafe_bcmp() instead + of memcpy() or strcmp() + when checking passwords, hashes, etc. It is not known whether the + data dependency of those functions is usefully exploitable in any of + these places, but in the interests of safety, replace them. + + + + The PostgreSQL Project thanks + Joe Conway for reporting this problem. + (CVE-2026-6478) + + + + + + + Mark PQfn() as unsafe, and avoid using it + within libpq (Nathan Bossart) + § + + + + For a non-integral result type, PQfn() is not + passed the size of the output buffer, so it cannot check that the + data returned by the server will fit. A malicious server could + therefore overwrite client memory. This is unfixable without an + API change, so mark the function as deprecated. Internally + to libpq, use a variant version that can + apply the missing check. + + + + The PostgreSQL Project thanks + Yu Kunpeng and Martin Heistermann for reporting this problem. + (CVE-2026-6477) + + + + + + + Prevent path traversal in pg_basebackup + and pg_rewind (Michael Paquier) + § + + + + These applications failed to validate output file paths read from + their input, so that a malicious source could overwrite any file + writable by these applications. Constrain where data can be written + by rejecting paths that are absolute or contain parent-directory + references. + + + + The PostgreSQL Project thanks XlabAI Team + of Tencent Xuanwu Lab and Valery Gubanov for reporting this problem. + (CVE-2026-6475) + + + + + + + Guard against field overflow + within contrib/intarray's query_int + type and contrib/ltree's ltxtquery + type (Tom Lane) + § + § + + + + Parsing of these query structures did not check for overflow of + 16-bit fields, so that construction of an invalid query tree was + possible. This can crash the server when executing the query. + + + + The PostgreSQL Project thanks + Xint Code for reporting this problem. + (CVE-2026-6473) + + + + + + + Guard against overly long values + of contrib/ltree's lquery type + (Michael Paquier) + § + + + + Values with more than 64K items caused internal overflows, + potentially resulting in stack smashes or wrong answers. + + + + The PostgreSQL Project thanks + Vergissmeinnicht, A1ex, and Jihe Wang + for reporting this problem. + (CVE-2026-6473) + + + + + + + Prevent SQL injection and buffer overruns + in contrib/spi (Nathan Bossart) + § + + + + check_foreign_key() was insufficiently careful + about quoting key values, and also used fixed-length buffers for + constructing queries. While this module is only meant as example + code, it still shouldn't contain such dangerous errors. + + + + The PostgreSQL Project thanks + Nikolay Samokhvalov for reporting this problem. + (CVE-2026-6637) + + + + + + + Check for nondeterministic collations before assuming that an + equality condition on a collatable type implies uniqueness + (Richard Guo) + § + § + § + § + § + + + + Numerous planner optimizations assume that, for example, at most one + table row can satisfy WHERE x = 'abc' if there is + a unique index on x. However this conclusion is + unsafe in general if the index and the WHERE + clause have different collations attached. It is safe when both + collations are deterministic, because that property essentially + requires that equality of two strings means bitwise equality. But + nondeterministic collations don't act that way, so that optimizing + on the assumption of unique matches can give wrong query answers if + either the WHERE clause or the index has a + nondeterministic collation. + + + + + + + Fix incomplete removal of relation references + in RestrictInfo structs during join removal + (Tom Lane) + § + + + + This oversight has been shown to result in planner failures such as + unexpected FULL JOIN is only supported with merge-joinable or + hash-joinable join conditions errors. It may also have + caused failure to consider valid plans in other cases. + + + + + + + Improve planner's matching of partition key columns to sub-query + outputs (Richard Guo) + § + + + + Strip no-op PlaceHolderVars from operands before comparing them to + partition keys. This change enables partition pruning to succeed in + some cases where it previously failed to recognize that a partition + need not be scanned. + + + + + + + Fix self-join removal to handle join clauses that are bare boolean + columns, e.g. ON t1.boolcol (Andrei Lepikhov, + Tender Wang, Alexander Korotkov) + § + + + + Previously such a case led to a no relation entry + for relid N error. + + + + + + + Fix UPDATE/DELETE ... WHERE CURRENT OF to work on + tables with virtual generated columns (Satyanarayana Narlapuram, + Dean Rasheed) + § + + + + + + + Fix expansion of virtual generated columns + in EXCLUDED column references in INSERT + ... ON CONFLICT (Satyanarayana Narlapuram, Dean Rasheed) + § + + + + + + + Fix incorrect handling of NEW generated columns + in rule actions and rule qualifications (Richard Guo, Dean Rasheed) + § + + + + Previously, such column references would produce NULL + in INSERT cases, or be equivalent to + the OLD value in UPDATE cases. + + + + + + + Fix spurious indexes on virtual generated columns are not + supported errors (Robert Haas) + § + + + + Creation of an expression index could sometimes incorrectly report + this error. + + + + + + + Fix spurious generated columns are not supported in COPY FROM + WHERE conditions errors (Tom Lane) + § + + + + Use of a system column in a COPY FROM WHERE + condition could sometimes incorrectly report this error. + + + + + + + Correctly report a serialization failure + when MERGE encounters a concurrently-updated + tuple in repeatable-read or serializable mode (Tender Wang) + § + + + + Previously, such cases behaved the same as in lower isolation + levels. + + + + + + + Fix CREATE TABLE ... LIKE ... INCLUDING + STATISTICS for cases where the source table has dropped + column(s) (Julien Tachoires) + § + + + + In such cases, extended statistics objects could be copied + incorrectly, or the command could give an incorrect error. + + + + + + + Allow ALTER INDEX ... ATTACH PARTITION to mark + the parent index valid if appropriate (Sami Imseih) + § + + + + There are edge cases in which a partitioned index might remain + marked as invalid even when all its leaf indexes are valid. This + change provides a mechanism whereby a user can correct such a + situation without resorting to manual catalog updates. + + + + + + + Fix ALTER TABLE ... SET NOT NULL to invoke + object-access hook functions only after completing the catalog + change (Artur Zakirov) + § + + + + + + + Fix ALTER FOREIGN DATA WRAPPER to not drop the + wrapper object's dependency on its handler function (Jeff Davis) + § + + + + + + + Fix loss of deferrability of foreign-key triggers (Yasuo Honda) + § + + + + Previously, a foreign key defined as DEFERRABLE INITIALLY + DEFERRED would behave as NOT DEFERRABLE + after being set to NOT ENFORCED status and then + back to ENFORCED. + + + + If you have a foreign key with this problem, it can be repaired + (after installing this update) by again setting it to NOT + ENFORCED and then back to ENFORCED. + + + + + + + Fix WITHOUT OVERLAPS to allow domains (Jian He) + § + + + + UNIQUE/PRIMARY KEY ... WITHOUT OVERLAPS requires + the no-overlap column to be a range or multirange, but it should + allow a domain over such a type too. + + + + + + + Disallow making a composite type be a member of itself via a + multirange (Heikki Linnakangas) + § + + + + We already forbade such cases when the intermediate type is a + domain, array, composite type, or range; but multiranges were + overlooked. + + + + + + + Fix datum-image comparisons to be insensitive to sign-extension + variations (David Rowley) + § + + + + This fixes some situations that previously led to could not + find memoization table entry errors or wrong query results. + + + + + + + Fix incorrect logic for hashed IN/NOT + IN with non-strict equality operator (Chengpeng Yan) + § + + + + The previous coding could crash or give wrong answers. All built-in + data types have strict equality operators, so that this issue could + only arise with an extension data type. + + + + + + + Truncate overly-long locale-specific numeric symbols + in to_char() (Tom Lane) + § + + + + If a locale specified a currency symbol, thousands separator, or + decimal or sign symbol more than 8 bytes long, a buffer overrun was + possible. No such locales exist in the real world, and it's + impractical for an unprivileged attacker to install a malicious + locale definition underneath a Postgres server; but for safety's + sake check for overlength symbols and truncate if needed. + + + + + + + Prevent buffer overruns when parsing an affix file for + an Ispell dictionary (Tom Lane) + § + § + + + + A corrupt or malicious affix file could crash the server. + This is not considered a security issue because text search + configuration files are presumed trustworthy, but it still seems + worth fixing. + + + + + + + Guard against integer overflow in calculations of frame start and + end positions for window aggregates (Richard Guo) + § + + + + Very large user-specified offsets (close to INT64_MAX) could result + in errors or incorrect query results. + + + + + + + Fix array_agg_array_combine() to combine the + arrays' null bitmaps correctly (Dmytro Astapov) + § + + + + This mistake resulted in sometimes-incorrect output from + parallelized array_agg(anyarray) calculations. + + + + + + + Retry sync_file_range() if it returns error + code EINTR (DaeMyung Kang) + § + + + + + + + Fix incorrect behavior + of pg_stat_reset_single_table_counters() on a + shared catalog (Chao Li) + § + + + + Such cases had a side-effect of resetting the + current database's stat_reset_timestamp, which + was unintended. + + + + + + + Update activity statistics when a parallel apply worker is idle + (Zhijie Hou) + § + + + + Previously, statistics from a recently-completed transaction might + go unreported for long intervals, particularly if the workload is + light. + + + + + + + Fix no relation entry for relid 0 failure while + estimating array lengths in set operations (Tender Wang) + § + + + + + + + Fix buffer overread when pglz_decompress() + receives corrupt input (Andrew Dunstan) + § + + + + It was possible to read a few bytes past the end of the input, which + in very unlucky cases might cause a crash. + + + + + + + Fix incremental JSON parser's handling of numeric tokens that cross + input buffer boundaries (Andrew Dunstan) + § + + + + It was possible to accept an incorrectly-formatted number, leading + to failures later. + + + + + + + Prevent bloating relation visibility maps during restore of an + incremental backup (Robert Haas) + § + + + + Restore could append many blocks of zeroes to a visibility map, due + to incorrect computation of the expected file length. This does not + result in data corruption, but it could waste a substantial amount + of disk space. + + + + + + + Use C collation, not the database's default collation, in catalog + cache lookups on text columns (Jeff Davis) + § + + + + This avoids failures in edge cases such as physical replication + startup, where there is no identified database so that a default + collation cannot be determined. + + + + + + + Prevent stuck slotsync worker processes from blocking promotion of a + standby server (Nisha Moond, Ajin Cherian) + § + § + § + + + + A worker process that was vainly waiting for a response from the + primary would delay promotion for an unreasonable amount of time. + + + + + + + Fix excessive log output from idle slotsync worker processes + (Zhijie Hou) + § + + + + + + + Ensure that tuplestore data structures are internally consistent + even after an error (Tom Lane) + § + + + + The code was previously careless about this, which is fine most of + the time but is problematic for the tuplestore backing + a WITH HOLD cursor. In v15 and before this + leads to easily-reproducible crashes; later branches are not known + to be vulnerable, but it seems best to preserve consistency in all. + + + + + + + Make the pg_aios system + view's pid column show NULL not + 0 when an entry has no owning process (ChangAo Chen) + § + + + + + + + Fix premature NULL lag reporting + in pg_stat_replication (Shinya Kato) + § + + + + The lag columns frequently read as NULL even while replication + activity was happening. + + + + + + + Fix under-allocation of shared memory used for parallel btree index + scans (Siddharth Kothari) + § + + + + In edge cases this could result in a server crash. + + + + + + + Avoid rare flush failure when working with non-WAL-logged GiST + indexes (Tomas Vondra) + § + + + + A non-logged GiST index could nonetheless sometimes + produce xlog flush request n/nnnn + is not satisfied errors, due to incorrect selection of + a fake LSN to represent an insertion point. + + + + + + + Fix underestimate of required size of DSA page maps for odd-size + segments (Paul Bunn) + § + + + + This miscalculation led to out-of-bounds accesses and hence server + crashes. + + + + + + + Fix indexing of oldest-multixact arrays in shared memory + (Yura Sokolov) + § + § + + + + This mistake could cause a prepared-but-not-yet-committed + transaction's row locks to appear invisible to other sessions, or + other visibility issues for the results of such a transaction. + With a very small max_connections setting, memory stomps were also + possible. + + + + + + + Fix array overrun when too many EXPLAIN extension + options are installed (Joel Jacobson) + § + + + + + + + Fix possible server crash when processing extended statistics on + expressions of extension data types (Michael Paquier) + § + + + + NULL pointer dereferences were possible if the data type's + typanalyze function does not compute any useful statistics. + No in-core typanalyze function behaves that way, but extensions + could. + + + + + + + Correctly display join alias Vars that are used in GROUP + BY (Tom Lane) + § + + + + In views containing queries like SELECT ... t1 LEFT JOIN t2 + USING (x) GROUP BY x, the GROUP BY + clause could be displayed incorrectly by deparsing, leading to + dump/restore failures. Failures occurred only + if t1.x and t2.x were not of + identical data types and t1.x was the side that + required an implicit coercion. + + + + + + + Fix minor memory leaks in ICU-based string processing (Jeff Davis) + § + + + + + + + If the startup process fails, properly shut down other child + processes before exiting the postmaster (Ayush Tiwari) + § + + + + The handling of this situation relied on a long-obsolete assumption + that no other postmaster children exist while the startup process is + running, so that immediate postmaster exit is acceptable. + Orphaned children would eventually notice the postmaster's death and + exit on their own, but a cleaner shutdown procedure is desirable. + + + + + + + Fix race condition between WAL replay of checkpoints and multixact + ID creations (Heikki Linnakangas) + § + + + + A standby server following WAL from a primary of an older minor + version could get into a crash-and-restart loop complaining + about could not access status of transaction. + + + + + + + Prevent indefinite wait in shutdown of a walsender process + (Anthonin Bonnefoy) + § + § + + + + At shutdown of a cluster that is publishing logical replication + data, the walsender waits for all pending WAL to be written out. + But it did not correctly request that to happen, so that in some + cases this could become an indefinite wait. + + + + + + + Ensure that changes to tables' free space maps are persisted during + recovery (Alexey Makhmutov) + § + + + + Previously, while WAL replay did update the free space map while + replaying operations that should change it, the map page buffer did + not get marked dirty if checksums are enabled, so that the changes + might never get written out. On a standby server, over time this + would result in a map wildly at variance with the table's actual + contents. While the map is only used as a hint, this condition + could cause significant performance degradation for some period of + time after the standby server is promoted to be active, until most + of the map has been repaired by updates. + + + + + + + Fix crashes in some ecpg functions when + called without any established connection (Shruthi Gowda) + § + + + + + + + Harden tar-file parsing logic against archives it can't handle + (Tom Lane) + § + + + + The tar-file reading code used + in pg_basebackup + and pg_verifybackup failed to verify that + the input is a tar file at all, let alone that it fits into the + subset of valid tar files that we can handle. This isn't a problem + for the normal scenario where the input file was generated + by PostgreSQL code, but it can be an + issue if the input has been generated by some + other tar program. + + + + + + + Fix assorted bugs in backup decompression and tar-parsing code + (Andrew Dunstan, Tom Lane, Chao Li) + § + § + § + + + + The decompression and tar-file reading code used + in pg_basebackup + and pg_verifybackup mishandled tar-file + padding data, could corrupt LZ4-compressed data in edge cases, + failed to check for some unusual error conditions, failed to exit + after compression/decompression errors (leading to cascading error + reports), and leaked memory. + + + + + + + In pg_dump, preserve NO + INHERIT property of NOT NULL + constraints (Jian He) + § + + + + Some cases missed printing the NO INHERIT clause. + + + + + + + In pg_dumpall, don't skip + role GRANTs with dangling grantor OIDs + (Tom Lane) + § + + + + Instead, handle such cases by emitting GRANT + without any GRANTED BY clause, as we did before + v16. This avoids losing the grant in foreseeable cases, since + pre-v16 servers didn't prevent dropping the grantor role. Continue + to emit a warning about the missing grantor, but only if the source + server is v16 or later. + + + + + + + In pg_upgrade, take care to use the + correct protocol version when connecting to older source servers + (Jacob Champion) + § + + + + This could be problematic when attempting to upgrade from a pre-2018 + server. + + + + + + + In contrib/basic_archive, allow the archive + directory to be missing at startup (Nathan Bossart) + § + + + + Previously, the setting + of basic_archive.archive_directory was rejected + if it didn't point to an existing directory. This is undesirable + because archiving will be stuck indefinitely, even if the directory + appears later. + + + + + + + Fix contrib/ltree to cope when case-folding + changes a string's byte length (Jeff Davis) + § + § + + + + Previously, lquery patterns specifying case-insensitive + matching might fail to match labels they should match. + + + + + + + Fix mis-structured output + from contrib/pg_overexplain's + RANGE_TABLE option (Satyanarayana Narlapuram) + § + + + + Some fields were misplaced in JSON, YAML, and XML formats, resulting + in structurally invalid output. + + + + + + + In contrib/pg_stat_statements, don't leak + memory if an error occurs while parsing the + pgss_query_texts.stat file (Heikki Linnakangas) + § + + + + + + + In contrib/postgres_fdw, avoid crash due to + premature cleanup of a failed connection (Etsuro Fujita) + § + + + + If a remote connection fails abort cleanup, we can't use it any + longer. But delay closing the connection object until end of + transaction, because there might still be references to it within + data structures such as open cursors. + + + + + + + Update time zone data files to tzdata + release 2026b (Tom Lane) + § + + + + British Columbia (America/Vancouver) will be on year-round UTC-07 + (effectively, permanent DST) beginning in November 2026. This + release assumes that their TZ abbreviation will + be MST from that time forward. That seems likely + to change, but it's unclear what new abbreviation will be used. + Also a historical correction for Moldova: they have followed EU DST + transition times since 2022. + + + + + + + + Release 18.3 diff --git a/meson.build b/meson.build index fca1dc86b2d..abdf156deb6 100644 --- a/meson.build +++ b/meson.build @@ -9,7 +9,7 @@ project('postgresql', ['c'], - version: '18.3', + version: '18.4', license: 'PostgreSQL', # We want < 0.56 for python 3.5 compatibility on old platforms. EPEL for @@ -28,7 +28,7 @@ project('postgresql', ) # IvorySQL version -ivorysql_version = '5.3' +ivorysql_version = '5.4' ############################################################### @@ -1917,6 +1917,8 @@ if cc.compiles(''' endif +# Select the format archetype to be used to check printf-type functions. +# # Need to check a call with %m because netbsd supports gnu_printf but emits a # warning for each use of %m. printf_attributes = ['gnu_printf', '__syslog__', 'printf'] @@ -1931,11 +1933,24 @@ attrib_error_args = cc.get_supported_arguments('-Werror=format', '-Werror=ignore foreach a : printf_attributes if cc.compiles(testsrc.format(a), args: test_c_args + attrib_error_args, name: 'format ' + a) - cdata.set('PG_PRINTF_ATTRIBUTE', a) + cdata.set('PG_C_PRINTF_ATTRIBUTE', a) break endif endforeach +# We need to repeat the test for C++ because gcc and clang prefer different +# format archetypes. +if llvm.found() + attrib_error_args = cpp.get_supported_arguments('-Werror=format', '-Werror=ignored-attributes') + foreach a : printf_attributes + if cpp.compiles(testsrc.format(a), + args: attrib_error_args, name: 'cppformat ' + a) + cdata.set('PG_CXX_PRINTF_ATTRIBUTE', a) + break + endif + endforeach +endif + if cc.has_function_attribute('visibility:default') and \ cc.has_function_attribute('visibility:hidden') diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c index cdc4ab3151b..7d4d7f733e4 100644 --- a/src/backend/access/gist/gistutil.c +++ b/src/backend/access/gist/gistutil.c @@ -1034,7 +1034,7 @@ gistGetFakeLSN(Relation rel) * last call. */ static XLogRecPtr lastlsn = InvalidXLogRecPtr; - XLogRecPtr currlsn = GetXLogInsertRecPtr(); + XLogRecPtr currlsn = GetXLogInsertEndRecPtr(); /* Shouldn't be called for WAL-logging relations */ Assert(!RelationNeedsWAL(rel)); diff --git a/src/backend/access/heap/visibilitymap.c b/src/backend/access/heap/visibilitymap.c index 226ac4899ec..21b4863c148 100644 --- a/src/backend/access/heap/visibilitymap.c +++ b/src/backend/access/heap/visibilitymap.c @@ -115,6 +115,8 @@ /* Mapping from heap block number to the right bit in the visibility map */ #define HEAPBLK_TO_MAPBLOCK(x) ((x) / HEAPBLOCKS_PER_PAGE) +#define HEAPBLK_TO_MAPBLOCK_LIMIT(x) \ + (((x) + HEAPBLOCKS_PER_PAGE - 1) / HEAPBLOCKS_PER_PAGE) #define HEAPBLK_TO_MAPBYTE(x) (((x) % HEAPBLOCKS_PER_PAGE) / HEAPBLOCKS_PER_BYTE) #define HEAPBLK_TO_OFFSET(x) (((x) % HEAPBLOCKS_PER_BYTE) * BITS_PER_HEAPBLOCK) @@ -533,6 +535,21 @@ visibilitymap_prepare_truncate(Relation rel, BlockNumber nheapblocks) return newnblocks; } +/* + * visibilitymap_truncation_length - + * compute truncation length for visibility map + * + * Given a proposed truncation length for the main fork, compute the + * correct truncation length for the visibility map. Should return the + * same answer as visibilitymap_prepare_truncate(), but without modifying + * anything. + */ +BlockNumber +visibilitymap_truncation_length(BlockNumber nheapblocks) +{ + return HEAPBLK_TO_MAPBLOCK_LIMIT(nheapblocks); +} + /* * Read a visibility map page. * diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c index fdff960c130..74677cc04ff 100644 --- a/src/backend/access/nbtree/nbtree.c +++ b/src/backend/access/nbtree/nbtree.c @@ -619,8 +619,11 @@ btestimateparallelscan(Relation rel, int nkeys, int norderbys) * also require a skip array. * * Every skip array must have space to store its scan key's sk_flags. + * We also need space for each skip array's unused btps_arrElems slot + * (we need to be able to subscript btps_arrElems using a simple + * so->arrayKeys[]-wise offset for any subsequent SAOP arrays). */ - estnbtreeshared = add_size(estnbtreeshared, sizeof(int)); + estnbtreeshared = add_size(estnbtreeshared, sizeof(int) * 2); /* Consider space required to store a datum of opclass input type */ attr = TupleDescCompactAttr(rel->rd_att, attnum - 1); diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c index 822f5eb5535..037f59fafd8 100644 --- a/src/backend/access/transam/multixact.c +++ b/src/backend/access/transam/multixact.c @@ -277,12 +277,7 @@ typedef struct MultiXactStateData /* * Per-backend data starts here. We have two arrays stored in the area - * immediately following the MultiXactStateData struct. Each is indexed by - * ProcNumber. - * - * In both arrays, there's a slot for all normal backends - * (0..MaxBackends-1) followed by a slot for max_prepared_xacts prepared - * transactions. + * immediately following the MultiXactStateData struct: * * OldestMemberMXactId[k] is the oldest MultiXactId each backend's current * transaction(s) could possibly be a member of, or InvalidMultiXactId @@ -294,6 +289,10 @@ typedef struct MultiXactStateData * member of a MultiXact, and that MultiXact would have to be created * during or after the lock acquisition.) * + * In the OldestMemberMXactId array, there's a slot for all normal + * backends (0..MaxBackends-1) followed by a slot for max_prepared_xacts + * prepared transactions. + * * OldestVisibleMXactId[k] is the oldest MultiXactId each backend's * current transaction(s) think is potentially live, or InvalidMultiXactId * when not in a transaction or not in a transaction that's paid any @@ -305,6 +304,9 @@ typedef struct MultiXactStateData * than its own OldestVisibleMXactId[] setting; this is necessary because * the relevant SLRU data can be concurrently truncated away. * + * In the OldestVisibleMXactId array, there's a slot for all normal + * backends (0..MaxBackends-1) only. No slots for prepared transactions. + * * The oldest valid value among all of the OldestMemberMXactId[] and * OldestVisibleMXactId[] entries is considered by vacuum as the earliest * possible value still having any live member transaction -- OldestMxact. @@ -326,9 +328,10 @@ typedef struct MultiXactStateData } MultiXactStateData; /* - * Size of OldestMemberMXactId and OldestVisibleMXactId arrays. + * Sizes of OldestMemberMXactId and OldestVisibleMXactId arrays. */ -#define MaxOldestSlot (MaxBackends + max_prepared_xacts) +#define NumMemberSlots (MaxBackends + max_prepared_xacts) +#define NumVisibleSlots MaxBackends /* Pointers to the state data in shared memory */ static MultiXactStateData *MultiXactState; @@ -336,6 +339,41 @@ static MultiXactId *OldestMemberMXactId; static MultiXactId *OldestVisibleMXactId; +static inline MultiXactId * +MyOldestMemberMXactIdSlot(void) +{ + /* + * The first MaxBackends entries in the OldestMemberMXactId array are + * reserved for regular backends. MyProcNumber should index into one of + * them. + */ + Assert(MyProcNumber >= 0 && MyProcNumber < MaxBackends); + return &OldestMemberMXactId[MyProcNumber]; +} + +static inline MultiXactId * +PreparedXactOldestMemberMXactIdSlot(ProcNumber procno) +{ + int prepared_xact_idx; + + Assert(procno >= FIRST_PREPARED_XACT_PROC_NUMBER); + prepared_xact_idx = procno - FIRST_PREPARED_XACT_PROC_NUMBER; + + /* + * The first MaxBackends entries in the OldestMemberMXactId array are + * reserved for regular backends. Prepared xacts come after them. + */ + Assert(MaxBackends + prepared_xact_idx < NumMemberSlots); + return &OldestMemberMXactId[MaxBackends + prepared_xact_idx]; +} + +static inline MultiXactId * +MyOldestVisibleMXactIdSlot(void) +{ + Assert(MyProcNumber >= 0 && MyProcNumber < NumVisibleSlots); + return &OldestVisibleMXactId[MyProcNumber]; +} + /* * Definitions for the backend-local MultiXactId cache. * @@ -379,7 +417,17 @@ static MemoryContext MXactContext = NULL; #define debug_elog6(a,b,c,d,e,f) #endif -/* hack to deal with WAL generated with older minor versions */ +/* + * Hack to deal with WAL generated with older minor versions. + * + * last_initialized_offsets_page is the XLOG_MULTIXACT_ZERO_OFF_PAGE record + * that we saw during WAL replay, or -1 if we haven't seen any yet. + * + * pre_initialized_offsets_page is the last page that was implicitly + * initialized by replaying a XLOG_MULTIXACT_CREATE_ID record, when we had not + * seen a XLOG_MULTIXACT_ZERO_OFF_PAGE record for the page yet. + */ +static int64 last_initialized_offsets_page = -1; static int64 pre_initialized_offsets_page = -1; /* internal MultiXactId management */ @@ -440,7 +488,7 @@ MultiXactIdCreate(TransactionId xid1, MultiXactStatus status1, Assert(!TransactionIdEquals(xid1, xid2) || (status1 != status2)); /* MultiXactIdSetOldestMember() must have been called already. */ - Assert(MultiXactIdIsValid(OldestMemberMXactId[MyProcNumber])); + Assert(MultiXactIdIsValid(*MyOldestMemberMXactIdSlot())); /* * Note: unlike MultiXactIdExpand, we don't bother to check that both XIDs @@ -494,7 +542,7 @@ MultiXactIdExpand(MultiXactId multi, TransactionId xid, MultiXactStatus status) Assert(TransactionIdIsValid(xid)); /* MultiXactIdSetOldestMember() must have been called already. */ - Assert(MultiXactIdIsValid(OldestMemberMXactId[MyProcNumber])); + Assert(MultiXactIdIsValid(*MyOldestMemberMXactIdSlot())); debug_elog5(DEBUG2, "Expand: received multi %u, xid %u status %s", multi, xid, mxstatus_to_string(status)); @@ -669,7 +717,7 @@ MultiXactIdIsRunning(MultiXactId multi, bool isLockOnly) void MultiXactIdSetOldestMember(void) { - if (!MultiXactIdIsValid(OldestMemberMXactId[MyProcNumber])) + if (!MultiXactIdIsValid(*MyOldestMemberMXactIdSlot())) { MultiXactId nextMXact; @@ -698,7 +746,7 @@ MultiXactIdSetOldestMember(void) if (nextMXact < FirstMultiXactId) nextMXact = FirstMultiXactId; - OldestMemberMXactId[MyProcNumber] = nextMXact; + *MyOldestMemberMXactIdSlot() = nextMXact; LWLockRelease(MultiXactGenLock); @@ -726,7 +774,7 @@ MultiXactIdSetOldestMember(void) static void MultiXactIdSetOldestVisible(void) { - if (!MultiXactIdIsValid(OldestVisibleMXactId[MyProcNumber])) + if (!MultiXactIdIsValid(*MyOldestVisibleMXactIdSlot())) { MultiXactId oldestMXact; int i; @@ -742,7 +790,7 @@ MultiXactIdSetOldestVisible(void) if (oldestMXact < FirstMultiXactId) oldestMXact = FirstMultiXactId; - for (i = 0; i < MaxOldestSlot; i++) + for (i = 0; i < NumMemberSlots; i++) { MultiXactId thisoldest = OldestMemberMXactId[i]; @@ -751,7 +799,7 @@ MultiXactIdSetOldestVisible(void) oldestMXact = thisoldest; } - OldestVisibleMXactId[MyProcNumber] = oldestMXact; + *MyOldestVisibleMXactIdSlot() = oldestMXact; LWLockRelease(MultiXactGenLock); @@ -944,29 +992,68 @@ RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset, * such a version, the next page might not be initialized yet. Initialize * it now. */ - if (InRecovery && - next_pageno != pageno && - pg_atomic_read_u64(&MultiXactOffsetCtl->shared->latest_page_number) == pageno) + if (InRecovery && next_pageno != pageno) { - elog(DEBUG1, "next offsets page is not initialized, initializing it now"); + bool init_needed; - lock = SimpleLruGetBankLock(MultiXactOffsetCtl, next_pageno); - LWLockAcquire(lock, LW_EXCLUSIVE); + /*---------- + * Check if the page exists, and if not, initialize it now. + * + * The straightforward way to check if the page exists is to call + * SimpleLruDoesPhysicalPageExist(). However, there two problems with + * that: + * + * 1. It's somewhat expensive to call on every page switch. + * + * 2. It does not take into account pages that have been initialized + * in the SLRU buffer cache but not yet flushed to disk. For such + * pages, it will incorrectly return false. + * + * To fix both of those problems, if we have replayed any + * XLOG_MULTIXACT_ZERO_OFF_PAGE records, we assume that the last page + * that was zeroed by XLOG_MULTIXACT_ZERO_OFF_PAGE is the last page + * that exists. This works because the XLOG_MULTIXACT_ZERO_OFF_PAGE + * records must appear in the WAL in order, unlike CREATE_ID records. + * We only resort to SimpleLruDoesPhysicalPageExist() if we haven't + * seen any XLOG_MULTIXACT_ZERO_OFF_PAGE records yet, which should + * happen at most once after starting WAL recovery. + * + * As an extra safety measure, if we do resort to + * SimpleLruDoesPhysicalPageExist(), flush the SLRU buffers first so + * that it will return an accurate result. + *---------- + */ + if (last_initialized_offsets_page == -1) + { + SimpleLruWriteAll(MultiXactOffsetCtl, false); + init_needed = !SimpleLruDoesPhysicalPageExist(MultiXactOffsetCtl, next_pageno); + } + else + init_needed = (last_initialized_offsets_page == pageno); - /* Create and zero the page */ - slotno = SimpleLruZeroPage(MultiXactOffsetCtl, next_pageno); + if (init_needed) + { + elog(DEBUG1, "next offsets page is not initialized, initializing it now"); - /* Make sure it's written out */ - SimpleLruWritePage(MultiXactOffsetCtl, slotno); - Assert(!MultiXactOffsetCtl->shared->page_dirty[slotno]); + lock = SimpleLruGetBankLock(MultiXactOffsetCtl, next_pageno); + LWLockAcquire(lock, LW_EXCLUSIVE); - LWLockRelease(lock); + /* Create and zero the page */ + slotno = SimpleLruZeroPage(MultiXactOffsetCtl, next_pageno); - /* - * Remember that we initialized the page, so that we don't zero it - * again at the XLOG_MULTIXACT_ZERO_OFF_PAGE record. - */ - pre_initialized_offsets_page = next_pageno; + /* Make sure it's written out */ + SimpleLruWritePage(MultiXactOffsetCtl, slotno); + Assert(!MultiXactOffsetCtl->shared->page_dirty[slotno]); + + LWLockRelease(lock); + + /* + * Remember that we initialized the page, so that we don't zero it + * again at the XLOG_MULTIXACT_ZERO_OFF_PAGE record. + */ + pre_initialized_offsets_page = next_pageno; + last_initialized_offsets_page = next_pageno; + } } /* @@ -1425,7 +1512,7 @@ GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members, * multi. It cannot possibly still be running. */ if (isLockOnly && - MultiXactIdPrecedes(multi, OldestVisibleMXactId[MyProcNumber])) + MultiXactIdPrecedes(multi, *MyOldestVisibleMXactIdSlot())) { debug_elog2(DEBUG2, "GetMembers: a locker-only multi is too old"); *members = NULL; @@ -1877,8 +1964,8 @@ AtEOXact_MultiXact(void) * We assume that storing a MultiXactId is atomic and so we need not take * MultiXactGenLock to do this. */ - OldestMemberMXactId[MyProcNumber] = InvalidMultiXactId; - OldestVisibleMXactId[MyProcNumber] = InvalidMultiXactId; + *MyOldestMemberMXactIdSlot() = InvalidMultiXactId; + *MyOldestVisibleMXactIdSlot() = InvalidMultiXactId; /* * Discard the local MultiXactId cache. Since MXactContext was created as @@ -1898,7 +1985,7 @@ AtEOXact_MultiXact(void) void AtPrepare_MultiXact(void) { - MultiXactId myOldestMember = OldestMemberMXactId[MyProcNumber]; + MultiXactId myOldestMember = *MyOldestMemberMXactIdSlot(); if (MultiXactIdIsValid(myOldestMember)) RegisterTwoPhaseRecord(TWOPHASE_RM_MULTIXACT_ID, 0, @@ -1918,7 +2005,7 @@ PostPrepare_MultiXact(TransactionId xid) * Transfer our OldestMemberMXactId value to the slot reserved for the * prepared transaction. */ - myOldestMember = OldestMemberMXactId[MyProcNumber]; + myOldestMember = *MyOldestMemberMXactIdSlot(); if (MultiXactIdIsValid(myOldestMember)) { ProcNumber dummyProcNumber = TwoPhaseGetDummyProcNumber(xid, false); @@ -1931,8 +2018,8 @@ PostPrepare_MultiXact(TransactionId xid) */ LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE); - OldestMemberMXactId[dummyProcNumber] = myOldestMember; - OldestMemberMXactId[MyProcNumber] = InvalidMultiXactId; + *PreparedXactOldestMemberMXactIdSlot(dummyProcNumber) = myOldestMember; + *MyOldestMemberMXactIdSlot() = InvalidMultiXactId; LWLockRelease(MultiXactGenLock); } @@ -1945,7 +2032,7 @@ PostPrepare_MultiXact(TransactionId xid) * We assume that storing a MultiXactId is atomic and so we need not take * MultiXactGenLock to do this. */ - OldestVisibleMXactId[MyProcNumber] = InvalidMultiXactId; + *MyOldestVisibleMXactIdSlot() = InvalidMultiXactId; /* * Discard the local MultiXactId cache like in AtEOXact_MultiXact. @@ -1972,7 +2059,7 @@ multixact_twophase_recover(TransactionId xid, uint16 info, Assert(len == sizeof(MultiXactId)); oldestMember = *((MultiXactId *) recdata); - OldestMemberMXactId[dummyProcNumber] = oldestMember; + *PreparedXactOldestMemberMXactIdSlot(dummyProcNumber) = oldestMember; } /* @@ -1987,7 +2074,7 @@ multixact_twophase_postcommit(TransactionId xid, uint16 info, Assert(len == sizeof(MultiXactId)); - OldestMemberMXactId[dummyProcNumber] = InvalidMultiXactId; + *PreparedXactOldestMemberMXactIdSlot(dummyProcNumber) = InvalidMultiXactId; } /* @@ -2002,21 +2089,32 @@ multixact_twophase_postabort(TransactionId xid, uint16 info, } /* - * Initialization of shared memory for MultiXact. We use two SLRU areas, - * thus double memory. Also, reserve space for the shared MultiXactState - * struct and the per-backend MultiXactId arrays (two of those, too). + * Initialization of shared memory for MultiXact. + * + * MultiXactSharedStateShmemSize() calculates the size of the MultiXactState + * struct, and the two per-backend MultiXactId arrays. They are carved out of + * the same allocation. MultiXactShmemSize() additionally includes the memory + * needed for the two SLRU areas. */ +static Size +MultiXactSharedStateShmemSize(void) +{ + Size size; + + size = offsetof(MultiXactStateData, perBackendXactIds); + size = add_size(size, + mul_size(sizeof(MultiXactId), NumMemberSlots)); + size = add_size(size, + mul_size(sizeof(MultiXactId), NumVisibleSlots)); + return size; +} + Size MultiXactShmemSize(void) { Size size; - /* We need 2*MaxOldestSlot perBackendXactIds[] entries */ -#define SHARED_MULTIXACT_STATE_SIZE \ - add_size(offsetof(MultiXactStateData, perBackendXactIds), \ - mul_size(sizeof(MultiXactId) * 2, MaxOldestSlot)) - - size = SHARED_MULTIXACT_STATE_SIZE; + size = MultiXactSharedStateShmemSize(); size = add_size(size, SimpleLruShmemSize(multixact_offset_buffers, 0)); size = add_size(size, SimpleLruShmemSize(multixact_member_buffers, 0)); @@ -2050,14 +2148,14 @@ MultiXactShmemInit(void) /* Initialize our shared state struct */ MultiXactState = ShmemInitStruct("Shared MultiXact State", - SHARED_MULTIXACT_STATE_SIZE, + MultiXactSharedStateShmemSize(), &found); if (!IsUnderPostmaster) { Assert(!found); /* Make sure we zero out the per-backend state */ - MemSet(MultiXactState, 0, SHARED_MULTIXACT_STATE_SIZE); + MemSet(MultiXactState, 0, MultiXactSharedStateShmemSize()); } else Assert(found); @@ -2066,7 +2164,7 @@ MultiXactShmemInit(void) * Set up array pointers. */ OldestMemberMXactId = MultiXactState->perBackendXactIds; - OldestVisibleMXactId = OldestMemberMXactId + MaxOldestSlot; + OldestVisibleMXactId = OldestMemberMXactId + NumMemberSlots; } /* @@ -2731,7 +2829,6 @@ GetOldestMultiXactId(void) { MultiXactId oldestMXact; MultiXactId nextMXact; - int i; /* * This is the oldest valid value among all the OldestMemberMXactId[] and @@ -2749,7 +2846,7 @@ GetOldestMultiXactId(void) nextMXact = FirstMultiXactId; oldestMXact = nextMXact; - for (i = 0; i < MaxOldestSlot; i++) + for (int i = 0; i < NumMemberSlots; i++) { MultiXactId thisoldest; @@ -2757,6 +2854,11 @@ GetOldestMultiXactId(void) if (MultiXactIdIsValid(thisoldest) && MultiXactIdPrecedes(thisoldest, oldestMXact)) oldestMXact = thisoldest; + } + for (int i = 0; i < NumVisibleSlots; i++) + { + MultiXactId thisoldest; + thisoldest = OldestVisibleMXactId[i]; if (MultiXactIdIsValid(thisoldest) && MultiXactIdPrecedes(thisoldest, oldestMXact)) @@ -3507,6 +3609,8 @@ multixact_redo(XLogReaderState *record) Assert(!MultiXactOffsetCtl->shared->page_dirty[slotno]); LWLockRelease(lock); + + last_initialized_offsets_page = pageno; } else elog(DEBUG1, "skipping initialization of offsets page " INT64_FORMAT " because it was already initialized on multixid creation", pageno); diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c index 73a80559194..77be057bdbb 100644 --- a/src/backend/access/transam/twophase.c +++ b/src/backend/access/transam/twophase.c @@ -895,9 +895,10 @@ TwoPhaseGetXidByVirtualXID(VirtualTransactionId vxid, * Get the dummy proc number for prepared transaction specified by XID * * Dummy proc numbers are similar to proc numbers of real backends. They - * start at MaxBackends, and are unique across all currently active real - * backends and prepared transactions. If lock_held is set to true, - * TwoPhaseStateLock will not be taken, so the caller had better hold it. + * start at FIRST_PREPARED_XACT_PROC_NUMBER, and are unique across all + * currently active real backends and prepared transactions. If lock_held is + * set to true, TwoPhaseStateLock will not be taken, so the caller had better + * hold it. */ ProcNumber TwoPhaseGetDummyProcNumber(TransactionId xid, bool lock_held) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 00c808207b3..a31e8322ad6 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -9627,6 +9627,22 @@ GetXLogInsertRecPtr(void) return XLogBytePosToRecPtr(current_bytepos); } +/* + * Get latest WAL record end pointer + */ +XLogRecPtr +GetXLogInsertEndRecPtr(void) +{ + XLogCtlInsert *Insert = &XLogCtl->Insert; + uint64 current_bytepos; + + SpinLockAcquire(&Insert->insertpos_lck); + current_bytepos = Insert->CurrBytePos; + SpinLockRelease(&Insert->insertpos_lck); + + return XLogBytePosToEndRecPtr(current_bytepos); +} + /* * Get latest WAL write pointer */ diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 7e7926d6670..b6b5a2d6f47 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -527,11 +527,15 @@ CheckAttributeNamesTypes(TupleDesc tupdesc, char relkind, */ for (i = 0; i < natts; i++) { - CheckAttributeType(NameStr(TupleDescAttr(tupdesc, i)->attname), - TupleDescAttr(tupdesc, i)->atttypid, - TupleDescAttr(tupdesc, i)->attcollation, + Form_pg_attribute attr = TupleDescAttr(tupdesc, i); + + if (attr->attisdropped) + continue; + CheckAttributeType(NameStr(attr->attname), + attr->atttypid, + attr->attcollation, NIL, /* assume we're creating a new rowtype */ - flags | (TupleDescAttr(tupdesc, i)->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL ? CHKATYPE_IS_VIRTUAL : 0)); + flags | (attr->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL ? CHKATYPE_IS_VIRTUAL : 0)); } } @@ -677,6 +681,16 @@ CheckAttributeType(const char *attname, containing_rowtypes, flags); } + else if (att_typtype == TYPTYPE_MULTIRANGE) + { + /* + * If it's a multirange, recurse to check its plain range type. + */ + CheckAttributeType(attname, get_multirange_range(atttypid), + InvalidOid, /* range types are not collatable */ + containing_rowtypes, + flags); + } else if (OidIsValid((att_typelem = get_element_type(atttypid)))) { /* diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c index b36f81afb9d..bf15c603a82 100644 --- a/src/backend/catalog/pg_type.c +++ b/src/backend/catalog/pg_type.c @@ -950,7 +950,7 @@ char * makeMultirangeTypeName(const char *rangeTypeName, Oid typeNamespace) { char *buf; - char *rangestr; + const char *rangestr; /* * If the range type name contains "range" then change that to diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index 87bbdddea94..bf0b867c0ac 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -176,7 +176,8 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt, * would need to expand them somewhere around here), but for * now we keep them consistent with the stored variant. */ - if (TupleDescAttr(RelationGetDescr(rel), attno - 1)->attgenerated) + if (attno > 0 && + TupleDescAttr(RelationGetDescr(rel), attno - 1)->attgenerated) ereport(ERROR, errcode(ERRCODE_INVALID_COLUMN_REFERENCE), errmsg("generated columns are not supported in COPY FROM WHERE conditions"), diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c index d08f28667e7..d4a69d6056c 100644 --- a/src/backend/commands/event_trigger.c +++ b/src/backend/commands/event_trigger.c @@ -2005,8 +2005,11 @@ EventTriggerCollectAlterTSConfig(AlterTSConfigurationStmt *stmt, Oid cfgId, command->in_extension = creating_extension; ObjectAddressSet(command->d.atscfg.address, TSConfigRelationId, cfgId); - command->d.atscfg.dictIds = palloc(sizeof(Oid) * ndicts); - memcpy(command->d.atscfg.dictIds, dictIds, sizeof(Oid) * ndicts); + if (ndicts > 0) + { + command->d.atscfg.dictIds = palloc_array(Oid, ndicts); + memcpy(command->d.atscfg.dictIds, dictIds, sizeof(Oid) * ndicts); + } command->d.atscfg.ndicts = ndicts; command->parsetree = (Node *) copyObject(stmt); diff --git a/src/backend/commands/explain_state.c b/src/backend/commands/explain_state.c index dae256809d2..1fcfa7883cc 100644 --- a/src/backend/commands/explain_state.c +++ b/src/backend/commands/explain_state.c @@ -338,7 +338,7 @@ RegisterExtensionExplainOption(const char *option_name, ExplainExtensionOptionArray = (ExplainExtensionOption *) MemoryContextAlloc(TopMemoryContext, ExplainExtensionOptionsAllocated - * sizeof(char *)); + * sizeof(ExplainExtensionOption)); } /* If there's an array but it's currently full, expand it. */ @@ -347,7 +347,7 @@ RegisterExtensionExplainOption(const char *option_name, int i = pg_nextpower2_32(ExplainExtensionOptionsAssigned + 1); ExplainExtensionOptionArray = (ExplainExtensionOption *) - repalloc(ExplainExtensionOptionArray, i * sizeof(char *)); + repalloc(ExplainExtensionOptionArray, i * sizeof(ExplainExtensionOption)); ExplainExtensionOptionsAllocated = i; } diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c index 8d2d7431544..d7ac1489a17 100644 --- a/src/backend/commands/foreigncmds.c +++ b/src/backend/commands/foreigncmds.c @@ -740,6 +740,11 @@ AlterForeignDataWrapper(ParseState *pstate, AlterFdwStmt *stmt) ereport(WARNING, (errmsg("changing the foreign-data wrapper handler can change behavior of existing foreign tables"))); } + else + { + /* handler unchanged */ + fdwhandler = fdwForm->fdwhandler; + } if (validator_given) { diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index c5c31a62129..2d59be3cbee 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -1116,7 +1116,8 @@ DefineIndex(Oid tableId, errmsg("index creation on system columns is not supported"))); - if (TupleDescAttr(RelationGetDescr(rel), attno - 1)->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL) + if (attno > 0 && + TupleDescAttr(RelationGetDescr(rel), attno - 1)->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL) ereport(ERROR, errcode(ERRCODE_FEATURE_NOT_SUPPORTED), stmt->primary ? @@ -1158,7 +1159,8 @@ DefineIndex(Oid tableId, { AttrNumber attno = j + FirstLowInvalidHeapAttributeNumber; - if (TupleDescAttr(RelationGetDescr(rel), attno - 1)->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL) + if (attno > 0 && + TupleDescAttr(RelationGetDescr(rel), attno - 1)->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), stmt->isconstraint ? diff --git a/src/backend/commands/subscriptioncmds.c b/src/backend/commands/subscriptioncmds.c index 081e293d672..3b544f93f49 100644 --- a/src/backend/commands/subscriptioncmds.c +++ b/src/backend/commands/subscriptioncmds.c @@ -2138,9 +2138,14 @@ check_publications_origin(WalReceiverConn *wrconn, List *publications, Oid relid = subrel_local_oids[i]; char *schemaname = get_namespace_name(get_rel_namespace(relid)); char *tablename = get_rel_name(relid); + char *schemaname_lit = quote_literal_cstr(schemaname); + char *tablename_lit = quote_literal_cstr(tablename); - appendStringInfo(&cmd, "AND NOT (N.nspname = '%s' AND C.relname = '%s')\n", - schemaname, tablename); + appendStringInfo(&cmd, "AND NOT (N.nspname = %s AND C.relname = %s)\n", + schemaname_lit, tablename_lit); + + pfree(schemaname_lit); + pfree(tablename_lit); } res = walrcv_exec(wrconn, cmd.data, 1, tableRow); diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 3bf1d677b69..2a75cfe13b4 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -8507,12 +8507,12 @@ ATExecSetNotNull(List **wqueue, Relation rel, char *conName, char *colName, ccon = linitial(cooked); ObjectAddressSet(address, ConstraintRelationId, ccon->conoid); - InvokeObjectPostAlterHook(RelationRelationId, - RelationGetRelid(rel), attnum); - /* Mark pg_attribute.attnotnull for the column and queue validation */ set_attnotnull(wqueue, rel, attnum, true, true); + InvokeObjectPostAlterHook(RelationRelationId, + RelationGetRelid(rel), attnum); + /* * Recurse to propagate the constraint to children that don't have one. */ @@ -13006,6 +13006,8 @@ ATExecAlterConstrEnforceability(List **wqueue, ATAlterConstraint *cmdcon, fkconstraint->fk_matchtype = currcon->confmatchtype; fkconstraint->fk_upd_action = currcon->confupdtype; fkconstraint->fk_del_action = currcon->confdeltype; + fkconstraint->deferrable = currcon->condeferrable; + fkconstraint->initdeferred = currcon->condeferred; /* Create referenced triggers */ if (currcon->conrelid == fkrelid) @@ -22447,7 +22449,10 @@ ATExecAttachPartitionIdx(List **wqueue, Relation parentIdx, RangeVar *name) ObjectAddressSet(address, RelationRelationId, RelationGetRelid(partIdx)); - /* Silently do nothing if already in the right state */ + /* + * Check if the index is already attached to the correct parent, + * ultimately attempting one round of validation if already the case. + */ currParent = partIdx->rd_rel->relispartition ? get_partition_parent(partIdxId, false) : InvalidOid; if (currParent != RelationGetRelid(parentIdx)) @@ -22556,6 +22561,14 @@ ATExecAttachPartitionIdx(List **wqueue, Relation parentIdx, RangeVar *name) validatePartitionedIndex(parentIdx, parentTbl); } + else if (!parentIdx->rd_index->indisvalid) + { + /* + * The index is attached, but the parent is still invalid; see if it + * can be validated now. + */ + validatePartitionedIndex(parentIdx, parentTbl); + } relation_close(parentTbl, AccessShareLock); /* keep these locks till commit */ diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index 4552379fb94..da213c37f07 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -1488,6 +1488,13 @@ DefineRange(ParseState *pstate, CreateRangeStmt *stmt) /* we can look up the subtype name immediately */ multirangeNamespace = QualifiedNameGetCreationNamespace(defGetQualifiedName(defel), &multirangeTypeName); + + /* Check we have creation rights in target namespace */ + aclresult = object_aclcheck(NamespaceRelationId, multirangeNamespace, + GetUserId(), ACL_CREATE); + if (aclresult != ACLCHECK_OK) + aclcheck_error(aclresult, OBJECT_SCHEMA, + get_namespace_name(multirangeNamespace)); } else ereport(ERROR, diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c index 9de9369045f..22d766f59c5 100644 --- a/src/backend/executor/execExprInterp.c +++ b/src/backend/executor/execExprInterp.c @@ -185,6 +185,14 @@ static Datum ExecJustHashInnerVarVirt(ExprState *state, ExprContext *econtext, b static Datum ExecJustHashOuterVarStrict(ExprState *state, ExprContext *econtext, bool *isnull); /* execution helper functions */ +static pg_attribute_always_inline void ExecEvalArrayCompareInternal(FunctionCallInfo fcinfo, + ArrayType *arr, + int16 typlen, + bool typbyval, + char typalign, + bool useOr, + Datum *result, + bool *resultnull); static pg_attribute_always_inline void ExecAggPlainTransByVal(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroup, @@ -4059,12 +4067,6 @@ ExecEvalScalarArrayOp(ExprState *state, ExprEvalStep *op) int nitems; Datum result; bool resultnull; - int16 typlen; - bool typbyval; - char typalign; - char *s; - bits8 *bitmap; - int bitmask; /* * If the array is NULL then we return NULL --- it's not very meaningful @@ -4113,13 +4115,42 @@ ExecEvalScalarArrayOp(ExprState *state, ExprEvalStep *op) op->d.scalararrayop.element_type = ARR_ELEMTYPE(arr); } - typlen = op->d.scalararrayop.typlen; - typbyval = op->d.scalararrayop.typbyval; - typalign = op->d.scalararrayop.typalign; + ExecEvalArrayCompareInternal(fcinfo, + arr, + op->d.scalararrayop.typlen, + op->d.scalararrayop.typbyval, + op->d.scalararrayop.typalign, + useOr, + &result, + &resultnull); + + *op->resvalue = result; + *op->resnull = resultnull; +} + +/* + * Shared helper for ExecEvalScalarArrayOp() and the NULL-LHS fallback for + * non-strict ExecEvalHashedScalarArrayOp(). + * + * Callers must handle the strict LHS-is-NULL; return NULL fast path prior to + * calling this. + */ +static pg_attribute_always_inline void +ExecEvalArrayCompareInternal(FunctionCallInfo fcinfo, ArrayType *arr, + int16 typlen, bool typbyval, char typalign, + bool useOr, Datum *result, bool *resultnull) +{ + int nitems; + char *s; + bits8 *bitmap; + int bitmask; + bool strictfunc = fcinfo->flinfo->fn_strict; + + nitems = ArrayGetNItems(ARR_NDIM(arr), ARR_DIMS(arr)); /* Initialize result appropriately depending on useOr */ - result = BoolGetDatum(!useOr); - resultnull = false; + *result = BoolGetDatum(!useOr); + *resultnull = false; /* Loop over the array elements */ s = (char *) ARR_DATA_PTR(arr); @@ -4155,18 +4186,18 @@ ExecEvalScalarArrayOp(ExprState *state, ExprEvalStep *op) else { fcinfo->isnull = false; - thisresult = op->d.scalararrayop.fn_addr(fcinfo); + thisresult = fcinfo->flinfo->fn_addr(fcinfo); } /* Combine results per OR or AND semantics */ if (fcinfo->isnull) - resultnull = true; + *resultnull = true; else if (useOr) { if (DatumGetBool(thisresult)) { - result = BoolGetDatum(true); - resultnull = false; + *result = BoolGetDatum(true); + *resultnull = false; break; /* needn't look at any more elements */ } } @@ -4174,8 +4205,8 @@ ExecEvalScalarArrayOp(ExprState *state, ExprEvalStep *op) { if (!DatumGetBool(thisresult)) { - result = BoolGetDatum(false); - resultnull = false; + *result = BoolGetDatum(false); + *resultnull = false; break; /* needn't look at any more elements */ } } @@ -4191,9 +4222,6 @@ ExecEvalScalarArrayOp(ExprState *state, ExprEvalStep *op) } } } - - *op->resvalue = result; - *op->resnull = resultnull; } /* @@ -4272,7 +4300,7 @@ ExecEvalHashedScalarArrayOp(ExprState *state, ExprEvalStep *op, ExprContext *eco * If the scalar is NULL, and the function is strict, return NULL; no * point in executing the search. */ - if (fcinfo->args[0].isnull && strictfunc) + if (scalar_isnull && strictfunc) { *op->resnull = true; return; @@ -4370,8 +4398,51 @@ ExecEvalHashedScalarArrayOp(ExprState *state, ExprEvalStep *op, ExprContext *eco * non-strict functions with a null lhs value if no match is found. */ op->d.hashedscalararrayop.has_nulls = has_nulls; + + /* + * When we have a non-strict equality function, check and cache the + * result from looking up a NULL. Non-strict functions are free to + * treat a NULL as equal to any other value, e.g. a 0 or an empty + * string. Here we perform a linear search over the array and cache + * the outcome so that we can use that result any time we receive a + * NULL. + */ + if (!strictfunc) + { + bool null_lhs_result; + + fcinfo->args[0].value = (Datum) 0; + fcinfo->args[0].isnull = true; + + ExecEvalArrayCompareInternal(fcinfo, arr, typlen, typbyval, + typalign, true, &result, + &resultnull); + + null_lhs_result = DatumGetBool(result); + + /* invert non-NULL results for NOT IN */ + if (!resultnull && !inclause) + null_lhs_result = !null_lhs_result; + + op->d.hashedscalararrayop.null_lhs_isnull = resultnull; + op->d.hashedscalararrayop.null_lhs_result = null_lhs_result; + } + } + + /* + * When looking up an SQL NULL value with non-strict functions, we defer + * to the value we cached when building the hash table. + */ + if (scalar_isnull) + { + Assert(!strictfunc); + + *op->resnull = op->d.hashedscalararrayop.null_lhs_isnull; + *op->resvalue = BoolGetDatum(op->d.hashedscalararrayop.null_lhs_result); + return; } + /* Check the hash to see if we have a match. */ hashfound = NULL != saophash_lookup(elements_tab->hashtab, scalar); diff --git a/src/backend/executor/execIndexing.c b/src/backend/executor/execIndexing.c index 73ac06cfd1f..8815638b484 100644 --- a/src/backend/executor/execIndexing.c +++ b/src/backend/executor/execIndexing.c @@ -114,6 +114,7 @@ #include "executor/executor.h" #include "nodes/nodeFuncs.h" #include "storage/lmgr.h" +#include "utils/lsyscache.h" #include "utils/multirangetypes.h" #include "utils/rangetypes.h" #include "utils/snapmgr.h" @@ -753,11 +754,18 @@ check_exclusion_or_unique_constraint(Relation heap, Relation index, { TupleDesc tupdesc = RelationGetDescr(heap); Form_pg_attribute att = TupleDescAttr(tupdesc, attno - 1); - TypeCacheEntry *typcache = lookup_type_cache(att->atttypid, 0); + TypeCacheEntry *typcache = lookup_type_cache(att->atttypid, + TYPECACHE_DOMAIN_BASE_INFO); + char typtype; + + if (OidIsValid(typcache->domainBaseType)) + typtype = get_typtype(typcache->domainBaseType); + else + typtype = typcache->typtype; ExecWithoutOverlapsNotEmpty(heap, att->attname, values[indnkeyatts - 1], - typcache->typtype, att->atttypid); + typtype, att->atttypid); } } diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c index 73c5c6d5263..d85341b96ed 100644 --- a/src/backend/executor/nodeAgg.c +++ b/src/backend/executor/nodeAgg.c @@ -4413,7 +4413,7 @@ ExecEndAgg(AggState *node) { AggregateInstrumentation *si; - Assert(ParallelWorkerNumber <= node->shared_info->num_workers); + Assert(ParallelWorkerNumber < node->shared_info->num_workers); si = &node->shared_info->sinstrument[ParallelWorkerNumber]; si->hash_batches_used = node->hash_batches_used; si->hash_disk_used = node->hash_disk_used; diff --git a/src/backend/executor/nodeBitmapHeapscan.c b/src/backend/executor/nodeBitmapHeapscan.c index bf24f3d7fe0..fd842ad8e22 100644 --- a/src/backend/executor/nodeBitmapHeapscan.c +++ b/src/backend/executor/nodeBitmapHeapscan.c @@ -277,7 +277,7 @@ ExecEndBitmapHeapScan(BitmapHeapScanState *node) { BitmapHeapScanInstrumentation *si; - Assert(ParallelWorkerNumber <= node->sinstrument->num_workers); + Assert(ParallelWorkerNumber < node->sinstrument->num_workers); si = &node->sinstrument->sinstrument[ParallelWorkerNumber]; /* diff --git a/src/backend/executor/nodeBitmapIndexscan.c b/src/backend/executor/nodeBitmapIndexscan.c index abbb033881a..59a6a16b053 100644 --- a/src/backend/executor/nodeBitmapIndexscan.c +++ b/src/backend/executor/nodeBitmapIndexscan.c @@ -192,7 +192,7 @@ ExecEndBitmapIndexScan(BitmapIndexScanState *node) { IndexScanInstrumentation *winstrument; - Assert(ParallelWorkerNumber <= node->biss_SharedInfo->num_workers); + Assert(ParallelWorkerNumber < node->biss_SharedInfo->num_workers); winstrument = &node->biss_SharedInfo->winstrument[ParallelWorkerNumber]; /* diff --git a/src/backend/executor/nodeIncrementalSort.c b/src/backend/executor/nodeIncrementalSort.c index bcebaf41c78..80b4bf96106 100644 --- a/src/backend/executor/nodeIncrementalSort.c +++ b/src/backend/executor/nodeIncrementalSort.c @@ -102,7 +102,7 @@ if ((node)->shared_info && (node)->am_worker) \ { \ Assert(IsParallelWorker()); \ - Assert(ParallelWorkerNumber <= (node)->shared_info->num_workers); \ + Assert(ParallelWorkerNumber < (node)->shared_info->num_workers); \ instrumentSortedGroup(&(node)->shared_info->sinfo[ParallelWorkerNumber].groupName##GroupInfo, \ (node)->groupName##_state); \ } \ diff --git a/src/backend/executor/nodeIndexonlyscan.c b/src/backend/executor/nodeIndexonlyscan.c index 6498ae4c8b9..63a0be4f347 100644 --- a/src/backend/executor/nodeIndexonlyscan.c +++ b/src/backend/executor/nodeIndexonlyscan.c @@ -423,7 +423,7 @@ ExecEndIndexOnlyScan(IndexOnlyScanState *node) { IndexScanInstrumentation *winstrument; - Assert(ParallelWorkerNumber <= node->ioss_SharedInfo->num_workers); + Assert(ParallelWorkerNumber < node->ioss_SharedInfo->num_workers); winstrument = &node->ioss_SharedInfo->winstrument[ParallelWorkerNumber]; /* diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c index 7fcaa37fe62..aff3100f6e2 100644 --- a/src/backend/executor/nodeIndexscan.c +++ b/src/backend/executor/nodeIndexscan.c @@ -804,7 +804,7 @@ ExecEndIndexScan(IndexScanState *node) { IndexScanInstrumentation *winstrument; - Assert(ParallelWorkerNumber <= node->iss_SharedInfo->num_workers); + Assert(ParallelWorkerNumber < node->iss_SharedInfo->num_workers); winstrument = &node->iss_SharedInfo->winstrument[ParallelWorkerNumber]; /* diff --git a/src/backend/executor/nodeMemoize.c b/src/backend/executor/nodeMemoize.c index 609deb12afb..c0f42a5c19d 100644 --- a/src/backend/executor/nodeMemoize.c +++ b/src/backend/executor/nodeMemoize.c @@ -1122,7 +1122,7 @@ ExecEndMemoize(MemoizeState *node) if (node->stats.mem_peak == 0) node->stats.mem_peak = node->mem_used; - Assert(ParallelWorkerNumber <= node->shared_info->num_workers); + Assert(ParallelWorkerNumber < node->shared_info->num_workers); si = &node->shared_info->sinstrument[ParallelWorkerNumber]; memcpy(si, &node->stats, sizeof(MemoizeInstrumentation)); } diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c index cf6cb07451d..9e14cefeba9 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -3298,6 +3298,11 @@ ExecMergeMatched(IvyModifyTableContext *context, ResultRelInfo *resultRelInfo, *inputslot; LockTupleMode lockmode; + if (IsolationUsesXactSnapshot()) + ereport(ERROR, + (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE), + errmsg("could not serialize access due to concurrent update"))); + /* * The target tuple was concurrently updated by some other * transaction. If we are currently processing a MATCHED diff --git a/src/backend/executor/nodeSort.c b/src/backend/executor/nodeSort.c index f603337ecd3..c5219fe880b 100644 --- a/src/backend/executor/nodeSort.c +++ b/src/backend/executor/nodeSort.c @@ -175,7 +175,7 @@ ExecSort(PlanState *pstate) TuplesortInstrumentation *si; Assert(IsParallelWorker()); - Assert(ParallelWorkerNumber <= node->shared_info->num_workers); + Assert(ParallelWorkerNumber < node->shared_info->num_workers); si = &node->shared_info->sinstrument[ParallelWorkerNumber]; tuplesort_get_stats(tuplesortstate, si); } diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c index c9e5ce62159..d6480490577 100644 --- a/src/backend/executor/nodeWindowAgg.c +++ b/src/backend/executor/nodeWindowAgg.c @@ -37,6 +37,7 @@ #include "catalog/objectaccess.h" #include "catalog/pg_aggregate.h" #include "catalog/pg_proc.h" +#include "common/int.h" #include "executor/executor.h" #include "executor/nodeWindowAgg.h" #include "miscadmin.h" @@ -1465,12 +1466,21 @@ row_is_in_frame(WindowAggState *winstate, int64 pos, TupleTableSlot *slot) if (frameOptions & FRAMEOPTION_ROWS) { int64 offset = DatumGetInt64(winstate->endOffsetValue); + int64 frameendpos = 0; /* rows after current row + offset are out of frame */ if (frameOptions & FRAMEOPTION_END_OFFSET_PRECEDING) offset = -offset; - if (pos > winstate->currentpos + offset) + /* + * If we have an overflow, it means the frame end is beyond the + * range of int64. Since currentpos >= 0, this can only be a + * positive overflow. We treat this as meaning that the frame + * extends to end of partition. + */ + if (!pg_add_s64_overflow(winstate->currentpos, offset, + &frameendpos) && + pos > frameendpos) return -1; } else if (frameOptions & (FRAMEOPTION_RANGE | FRAMEOPTION_GROUPS)) @@ -1605,7 +1615,16 @@ update_frameheadpos(WindowAggState *winstate) if (frameOptions & FRAMEOPTION_START_OFFSET_PRECEDING) offset = -offset; - winstate->frameheadpos = winstate->currentpos + offset; + /* + * If we have an overflow, it means the frame head is beyond the + * range of int64. Since currentpos >= 0, this can only be a + * positive overflow. We treat this as being beyond end of + * partition. + */ + if (pg_add_s64_overflow(winstate->currentpos, offset, + &winstate->frameheadpos)) + winstate->frameheadpos = PG_INT64_MAX; + /* frame head can't go before first row */ if (winstate->frameheadpos < 0) winstate->frameheadpos = 0; @@ -1717,12 +1736,21 @@ update_frameheadpos(WindowAggState *winstate) * framehead_slot empty. */ int64 offset = DatumGetInt64(winstate->startOffsetValue); - int64 minheadgroup; + int64 minheadgroup = 0; if (frameOptions & FRAMEOPTION_START_OFFSET_PRECEDING) minheadgroup = winstate->currentgroup - offset; else - minheadgroup = winstate->currentgroup + offset; + { + /* + * If we have an overflow, it means the target group is beyond + * the range of int64. We treat this as "infinity", which + * ensures the loop below advances to end of partition. + */ + if (pg_add_s64_overflow(winstate->currentgroup, offset, + &minheadgroup)) + minheadgroup = PG_INT64_MAX; + } tuplestore_select_read_pointer(winstate->buffer, winstate->framehead_ptr); @@ -1859,7 +1887,18 @@ update_frametailpos(WindowAggState *winstate) if (frameOptions & FRAMEOPTION_END_OFFSET_PRECEDING) offset = -offset; - winstate->frametailpos = winstate->currentpos + offset + 1; + /* + * If we have an overflow, it means the frame tail is beyond the + * range of int64. Since currentpos >= 0, this can only be a + * positive overflow. We treat this as being beyond end of + * partition. + */ + if (pg_add_s64_overflow(winstate->currentpos, offset, + &winstate->frametailpos) || + pg_add_s64_overflow(winstate->frametailpos, 1, + &winstate->frametailpos)) + winstate->frametailpos = PG_INT64_MAX; + /* smallest allowable value of frametailpos is 0 */ if (winstate->frametailpos < 0) winstate->frametailpos = 0; @@ -1971,12 +2010,21 @@ update_frametailpos(WindowAggState *winstate) * leave frametailpos = end+1 and frametail_slot empty. */ int64 offset = DatumGetInt64(winstate->endOffsetValue); - int64 maxtailgroup; + int64 maxtailgroup = 0; if (frameOptions & FRAMEOPTION_END_OFFSET_PRECEDING) maxtailgroup = winstate->currentgroup - offset; else - maxtailgroup = winstate->currentgroup + offset; + { + /* + * If we have an overflow, it means the target group is beyond + * the range of int64. We treat this as "infinity", which + * ensures the loop below advances to end of partition. + */ + if (pg_add_s64_overflow(winstate->currentgroup, offset, + &maxtailgroup)) + maxtailgroup = PG_INT64_MAX; + } tuplestore_select_read_pointer(winstate->buffer, winstate->frametail_ptr); diff --git a/src/backend/jit/llvm/SectionMemoryManager.cpp b/src/backend/jit/llvm/SectionMemoryManager.cpp index 2171db5f382..ba00fd4cf3f 100644 --- a/src/backend/jit/llvm/SectionMemoryManager.cpp +++ b/src/backend/jit/llvm/SectionMemoryManager.cpp @@ -1,18 +1,11 @@ /* - * This file is from https://github.com/llvm/llvm-project/pull/71968 - * with minor modifications to avoid name clash and work with older - * LLVM versions. The llvm::backport::SectionMemoryManager class is a - * drop-in replacement for llvm::SectionMemoryManager, for use with - * llvm::RuntimeDyld. It fixes a memory layout bug on large memory - * ARM systems (see pull request for details). If the LLVM project - * eventually commits the change, we may need to resynchronize our - * copy with any further modifications, but they would be unlikely to - * backport it into the LLVM versions that we target so we would still - * need this copy. + * This file is from LLVM 22 (originally pull request #71968), with minor + * modifications to avoid name clash and work with older LLVM versions. It + * replaces llvm::SectionMemoryManager, and is injected into llvm::RuntimeDyld + * to fix a memory layout bug on large memory ARM systems on LLVM < 22. * - * In the future we will switch to using JITLink instead of - * RuntimeDyld where possible, and later remove this code (.cpp, .h, - * .LICENSE) after all LLVM versions that we target allow it. + * We can remove this code (.cpp, .h, .LICENSE) once LLVM 22 is our minimum + * supported version or we've switched to JITLink for at least Aarch64. * * This file is a modified copy of a part of the LLVM source code that * we would normally access from the LLVM library. It is therefore diff --git a/src/backend/jit/llvm/llvmjit.c b/src/backend/jit/llvm/llvmjit.c index 09e49b43811..5e765e0aa78 100644 --- a/src/backend/jit/llvm/llvmjit.c +++ b/src/backend/jit/llvm/llvmjit.c @@ -1174,7 +1174,10 @@ llvm_log_jit_error(void *ctx, LLVMErrorRef error) static LLVMOrcObjectLayerRef llvm_create_object_layer(void *Ctx, LLVMOrcExecutionSessionRef ES, const char *Triple) { -#ifdef USE_LLVM_BACKPORT_SECTION_MEMORY_MANAGER +#if LLVM_VERSION_MAJOR >= 22 + LLVMOrcObjectLayerRef objlayer = + LLVMOrcCreateRTDyldObjectLinkingLayerWithSectionMemoryManagerReserveAlloc(ES, true); +#elif defined(USE_LLVM_BACKPORT_SECTION_MEMORY_MANAGER) LLVMOrcObjectLayerRef objlayer = LLVMOrcCreateRTDyldObjectLinkingLayerWithSafeSectionMemoryManager(ES); #else diff --git a/src/backend/jit/llvm/llvmjit_expr.c b/src/backend/jit/llvm/llvmjit_expr.c index 458bcd3bcf6..8a459cc0366 100644 --- a/src/backend/jit/llvm/llvmjit_expr.c +++ b/src/backend/jit/llvm/llvmjit_expr.c @@ -62,7 +62,9 @@ static LLVMValueRef build_EvalXFuncInt(LLVMBuilderRef b, LLVMModuleRef mod, LLVMValueRef v_state, ExprEvalStep *op, int natts, LLVMValueRef *v_args); +#if LLVM_VERSION_MAJOR < 22 static LLVMValueRef create_LifetimeEnd(LLVMModuleRef mod); +#endif /* macro making it easier to call ExecEval* functions */ #define build_EvalXFunc(b, mod, funcname, v_state, op, ...) \ @@ -3008,14 +3010,11 @@ BuildV1Call(LLVMJitContext *context, LLVMBuilderRef b, LLVMModuleRef mod, FunctionCallInfo fcinfo, LLVMValueRef *v_fcinfo_isnull) { - LLVMContextRef lc; LLVMValueRef v_fn; LLVMValueRef v_fcinfo_isnullp; LLVMValueRef v_retval; LLVMValueRef v_fcinfo; - lc = LLVMGetModuleContext(mod); - v_fn = llvm_function_reference(context, b, mod, fcinfo); v_fcinfo = l_ptr_const(fcinfo, l_ptr(StructFunctionCallInfoData)); @@ -3031,11 +3030,14 @@ BuildV1Call(LLVMJitContext *context, LLVMBuilderRef b, if (v_fcinfo_isnull) *v_fcinfo_isnull = l_load(b, TypeStorageBool, v_fcinfo_isnullp, ""); +#if LLVM_VERSION_MAJOR < 22 + /* * Add lifetime-end annotation, signaling that writes to memory don't have * to be retained (important for inlining potential). */ { + LLVMContextRef lc = LLVMGetModuleContext(mod); LLVMValueRef v_lifetime = create_LifetimeEnd(mod); LLVMValueRef params[2]; @@ -3047,6 +3049,7 @@ BuildV1Call(LLVMJitContext *context, LLVMBuilderRef b, params[1] = l_ptr_const(&fcinfo->isnull, l_ptr(LLVMInt8TypeInContext(lc))); l_call(b, LLVMGetFunctionType(v_lifetime), v_lifetime, params, lengthof(params), ""); } +#endif return v_retval; } @@ -3084,6 +3087,7 @@ build_EvalXFuncInt(LLVMBuilderRef b, LLVMModuleRef mod, const char *funcname, return v_ret; } +#if LLVM_VERSION_MAJOR < 22 static LLVMValueRef create_LifetimeEnd(LLVMModuleRef mod) { @@ -3113,3 +3117,4 @@ create_LifetimeEnd(LLVMModuleRef mod) return fn; } +#endif diff --git a/src/backend/libpq/auth-scram.c b/src/backend/libpq/auth-scram.c index db778405724..8fe5b989c2f 100644 --- a/src/backend/libpq/auth-scram.c +++ b/src/backend/libpq/auth-scram.c @@ -581,7 +581,7 @@ scram_verify_plain_password(const char *username, const char *password, * Compare the secret's Server Key with the one computed from the * user-supplied password. */ - return memcmp(computed_key, server_key, key_length) == 0; + return timingsafe_bcmp(computed_key, server_key, key_length) == 0; } @@ -1132,9 +1132,9 @@ verify_final_nonce(scram_state *state) if (final_nonce_len != client_nonce_len + server_nonce_len) return false; - if (memcmp(state->client_final_nonce, state->client_nonce, client_nonce_len) != 0) + if (timingsafe_bcmp(state->client_final_nonce, state->client_nonce, client_nonce_len) != 0) return false; - if (memcmp(state->client_final_nonce + client_nonce_len, state->server_nonce, server_nonce_len) != 0) + if (timingsafe_bcmp(state->client_final_nonce + client_nonce_len, state->server_nonce, server_nonce_len) != 0) return false; return true; @@ -1188,7 +1188,7 @@ verify_client_proof(scram_state *state) client_StoredKey, &errstr) < 0) elog(ERROR, "could not hash stored key: %s", errstr); - if (memcmp(client_StoredKey, state->StoredKey, state->key_length) != 0) + if (timingsafe_bcmp(client_StoredKey, state->StoredKey, state->key_length) != 0) return false; return true; diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c index 4da46666439..40b6f93bffc 100644 --- a/src/backend/libpq/auth.c +++ b/src/backend/libpq/auth.c @@ -3232,7 +3232,7 @@ PerformRadiusTransaction(const char *server, const char *secret, const char *por } pfree(cryptvector); - if (memcmp(receivepacket->vector, encryptedpassword, RADIUS_VECTOR_LENGTH) != 0) + if (timingsafe_bcmp(receivepacket->vector, encryptedpassword, RADIUS_VECTOR_LENGTH) != 0) { ereport(LOG, (errmsg("RADIUS response from %s has incorrect MD5 signature", diff --git a/src/backend/libpq/crypt.c b/src/backend/libpq/crypt.c index f6b641e726e..063ac95778d 100644 --- a/src/backend/libpq/crypt.c +++ b/src/backend/libpq/crypt.c @@ -230,7 +230,8 @@ md5_crypt_verify(const char *role, const char *shadow_pass, return STATUS_ERROR; } - if (strcmp(client_pass, crypt_pwd) == 0) + if (strlen(client_pass) == strlen(crypt_pwd) && + timingsafe_bcmp(client_pass, crypt_pwd, strlen(crypt_pwd)) == 0) retval = STATUS_OK; else { @@ -292,7 +293,8 @@ plain_crypt_verify(const char *role, const char *shadow_pass, *logdetail = errstr; return STATUS_ERROR; } - if (strcmp(crypt_client_pass, shadow_pass) == 0) + if (strlen(crypt_client_pass) == strlen(shadow_pass) && + timingsafe_bcmp(crypt_client_pass, shadow_pass, strlen(shadow_pass)) == 0) return STATUS_OK; else { diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c index 28dce6296b6..8a60e255a19 100644 --- a/src/backend/optimizer/path/indxpath.c +++ b/src/backend/optimizer/path/indxpath.c @@ -31,6 +31,7 @@ #include "optimizer/optimizer.h" #include "optimizer/pathnode.h" #include "optimizer/paths.h" +#include "optimizer/placeholder.h" #include "optimizer/prep.h" #include "optimizer/restrictinfo.h" #include "utils/lsyscache.h" @@ -196,8 +197,6 @@ static Expr *match_clause_to_ordering_op(IndexOptInfo *index, static bool ec_member_matches_indexcol(PlannerInfo *root, RelOptInfo *rel, EquivalenceClass *ec, EquivalenceMember *em, void *arg); -static bool contain_strippable_phv_walker(Node *node, void *context); -static Node *strip_phvs_in_index_operand_mutator(Node *node, void *context); /* @@ -4260,16 +4259,19 @@ relation_has_unique_index_ext(PlannerInfo *root, RelOptInfo *rel, * The condition's equality operator must be a member of the * index opfamily, else it is not asserting the right kind of * equality behavior for this index. We check this first - * since it's probably cheaper than match_index_to_operand(). + * since it's probably the cheapest test. */ if (!list_member_oid(rinfo->mergeopfamilies, ind->opfamily[c])) continue; /* - * XXX at some point we may need to check collations here too. - * For the moment we assume all collations reduce to the same - * notion of equality. + * The index's collation must agree with the clause's input + * collation on equality, else the index's uniqueness does not + * imply uniqueness under the clause's equality semantics. */ + if (!collations_agree_on_equality(ind->indexcollations[c], + exprInputCollation((Node *) rinfo->clause))) + continue; /* OK, see if the condition operand matches the index key */ if (rinfo->outer_is_left) @@ -4325,10 +4327,13 @@ relation_has_unique_index_ext(PlannerInfo *root, RelOptInfo *rel, continue; /* - * XXX at some point we may need to check collations here too. - * For the moment we assume all collations reduce to the same - * notion of equality. + * The index's collation must agree with the operand's + * collation on equality, else the index's uniqueness does not + * imply uniqueness under the operator's equality semantics. */ + if (!collations_agree_on_equality(ind->indexcollations[c], + exprCollation(expr))) + continue; matched = true; /* column is unique */ break; @@ -4430,7 +4435,7 @@ match_index_to_operand(Node *operand, * a subtree) has been wrapped in PlaceHolderVars to enforce separate * identity or as a result of outer joins. */ - operand = strip_phvs_in_index_operand(operand); + operand = strip_noop_phvs(operand); /* * Ignore any RelabelType node above the operand. This is needed to be @@ -4496,88 +4501,15 @@ match_index_to_operand(Node *operand, /* * strip_phvs_in_index_operand - * Strip PlaceHolderVar nodes from the given operand expression to - * facilitate matching against an index's key. - * - * A PlaceHolderVar appearing in a relation-scan-level expression is - * effectively a no-op. Nevertheless, to play it safe, we strip only - * PlaceHolderVars that are not marked nullable. * - * The removal is performed recursively because PlaceHolderVars can be nested - * or interleaved with other node types. We must peel back all layers to - * expose the base operand. - * - * As a performance optimization, we first use a lightweight walker to check - * for the presence of strippable PlaceHolderVars. The expensive mutator is - * invoked only if a candidate is found, avoiding unnecessary memory allocation - * and tree copying in the common case where no PlaceHolderVars are present. + * Retained as a backward-compatibility wrapper around strip_noop_phvs() to + * avoid breaking third-party extensions that may reference this function. New + * code should call strip_noop_phvs() directly. */ Node * strip_phvs_in_index_operand(Node *operand) { - /* Don't mutate/copy if no target PHVs exist */ - if (!contain_strippable_phv_walker(operand, NULL)) - return operand; - - return strip_phvs_in_index_operand_mutator(operand, NULL); -} - -/* - * contain_strippable_phv_walker - * Detect if there are any PlaceHolderVars in the tree that are candidates - * for stripping. - * - * We identify a PlaceHolderVar as strippable only if its phnullingrels is - * empty. - */ -static bool -contain_strippable_phv_walker(Node *node, void *context) -{ - if (node == NULL) - return false; - - if (IsA(node, PlaceHolderVar)) - { - PlaceHolderVar *phv = (PlaceHolderVar *) node; - - if (bms_is_empty(phv->phnullingrels)) - return true; - } - - return expression_tree_walker(node, contain_strippable_phv_walker, - context); -} - -/* - * strip_phvs_in_index_operand_mutator - * Recursively remove PlaceHolderVars in the tree that match the criteria. - * - * We strip a PlaceHolderVar only if its phnullingrels is empty, replacing it - * with its contained expression. - */ -static Node * -strip_phvs_in_index_operand_mutator(Node *node, void *context) -{ - if (node == NULL) - return NULL; - - if (IsA(node, PlaceHolderVar)) - { - PlaceHolderVar *phv = (PlaceHolderVar *) node; - - /* If matches the criteria, strip it */ - if (bms_is_empty(phv->phnullingrels)) - { - /* Recurse on its contained expression */ - return strip_phvs_in_index_operand_mutator((Node *) phv->phexpr, - context); - } - - /* Otherwise, keep this PHV but check its contained expression */ - } - - return expression_tree_mutator(node, strip_phvs_in_index_operand_mutator, - context); + return strip_noop_phvs(operand); } /* diff --git a/src/backend/optimizer/plan/analyzejoins.c b/src/backend/optimizer/plan/analyzejoins.c index 79598f62ca4..9f546b4d3a6 100644 --- a/src/backend/optimizer/plan/analyzejoins.c +++ b/src/backend/optimizer/plan/analyzejoins.c @@ -34,6 +34,20 @@ #include "rewrite/rewriteManip.h" #include "utils/lsyscache.h" +/* + * One element of the list passed to query_is_distinct_for_with_collations(). + * Each entry names a subquery output column that the caller needs to be + * distinct over, plus the upper-level equality operator and its input + * collation, so that the subquery's own DISTINCT/GROUP BY/set-op clauses can + * be compared for compatibility. + */ +typedef struct DistinctColInfo +{ + int colno; /* subquery output column resno */ + Oid opid; /* upper-level equality operator */ + Oid collid; /* input collation of opid */ +} DistinctColInfo; + /* * Utility structure. A sorting procedure is needed to simplify the search * of SJE-candidate baserels referencing the same database relation. Having @@ -65,7 +79,9 @@ static List *remove_rel_from_joinlist(List *joinlist, int relid, int *nremoved); static bool rel_supports_distinctness(PlannerInfo *root, RelOptInfo *rel); static bool rel_is_distinct_for(PlannerInfo *root, RelOptInfo *rel, List *clause_list, List **extra_clauses); -static Oid distinct_col_search(int colno, List *colnos, List *opids); +static bool query_is_distinct_for_with_collations(Query *query, + List *distinct_cols); +static DistinctColInfo *distinct_col_search(int colno, List *distinct_cols); static bool is_innerrel_unique_for(PlannerInfo *root, Relids joinrelids, Relids outerrelids, @@ -649,7 +665,7 @@ remove_leftjoinrel_from_query(PlannerInfo *root, int relid, /* * Remove any references to relid or ojrelid from the RestrictInfo. * - * We only bother to clean out bits in clause_relids and required_relids, + * We only bother to clean out bits in the RestrictInfo's various relid sets, * not nullingrel bits in contained Vars and PHVs. (This might have to be * improved sometime.) However, if the RestrictInfo contains an OR clause * we have to also clean up the sub-clauses. @@ -671,6 +687,22 @@ remove_rel_from_restrictinfo(RestrictInfo *rinfo, int relid, int ojrelid) rinfo->required_relids = bms_copy(rinfo->required_relids); rinfo->required_relids = bms_del_member(rinfo->required_relids, relid); rinfo->required_relids = bms_del_member(rinfo->required_relids, ojrelid); + /* Likewise for incompatible_relids */ + rinfo->incompatible_relids = bms_copy(rinfo->incompatible_relids); + rinfo->incompatible_relids = bms_del_member(rinfo->incompatible_relids, relid); + rinfo->incompatible_relids = bms_del_member(rinfo->incompatible_relids, ojrelid); + /* Likewise for outer_relids */ + rinfo->outer_relids = bms_copy(rinfo->outer_relids); + rinfo->outer_relids = bms_del_member(rinfo->outer_relids, relid); + rinfo->outer_relids = bms_del_member(rinfo->outer_relids, ojrelid); + /* Likewise for left_relids */ + rinfo->left_relids = bms_copy(rinfo->left_relids); + rinfo->left_relids = bms_del_member(rinfo->left_relids, relid); + rinfo->left_relids = bms_del_member(rinfo->left_relids, ojrelid); + /* Likewise for right_relids */ + rinfo->right_relids = bms_copy(rinfo->right_relids); + rinfo->right_relids = bms_del_member(rinfo->right_relids, relid); + rinfo->right_relids = bms_del_member(rinfo->right_relids, ojrelid); /* If it's an OR, recurse to clean up sub-clauses */ if (restriction_is_or_clause(rinfo)) @@ -1002,15 +1034,17 @@ rel_is_distinct_for(PlannerInfo *root, RelOptInfo *rel, List *clause_list, { Index relid = rel->relid; Query *subquery = root->simple_rte_array[relid]->subquery; - List *colnos = NIL; - List *opids = NIL; + List *distinct_cols = NIL; ListCell *l; /* - * Build the argument lists for query_is_distinct_for: a list of - * output column numbers that the query needs to be distinct over, and - * a list of equality operators that the output columns need to be - * distinct according to. + * Build the argument list for query_is_distinct_for_with_collations: + * a list of DistinctColInfo entries, each holding an output column + * number that the query needs to be distinct over, the equality + * operator that the column needs to be distinct according to, and + * that operator's input collation. The collation matters because the + * subquery's own DISTINCT / GROUP BY / set-op proves uniqueness under + * its own collation, which need not agree with the operator's. * * (XXX we are not considering restriction clauses attached to the * subquery; is that worth doing?) @@ -1018,18 +1052,18 @@ rel_is_distinct_for(PlannerInfo *root, RelOptInfo *rel, List *clause_list, foreach(l, clause_list) { RestrictInfo *rinfo = lfirst_node(RestrictInfo, l); - Oid op; + OpExpr *opexpr; Var *var; + DistinctColInfo *dcinfo; /* - * Get the equality operator we need uniqueness according to. - * (This might be a cross-type operator and thus not exactly the - * same operator the subquery would consider; that's all right - * since query_is_distinct_for can resolve such cases.) The - * caller's mergejoinability test should have selected only - * OpExprs. + * The caller's mergejoinability test should have selected only + * OpExprs. The operator might be a cross-type operator and thus + * not exactly the same operator the subquery would consider; + * that's all right since query_is_distinct_for_with_collations + * can resolve such cases. */ - op = castNode(OpExpr, rinfo->clause)->opno; + opexpr = castNode(OpExpr, rinfo->clause); /* caller identified the inner side for us */ if (rinfo->outer_is_left) @@ -1053,11 +1087,14 @@ rel_is_distinct_for(PlannerInfo *root, RelOptInfo *rel, List *clause_list, var->varno != relid || var->varlevelsup != 0) continue; - colnos = lappend_int(colnos, var->varattno); - opids = lappend_oid(opids, op); + dcinfo = palloc(sizeof(DistinctColInfo)); + dcinfo->colno = var->varattno; + dcinfo->opid = opexpr->opno; + dcinfo->collid = opexpr->inputcollid; + distinct_cols = lappend(distinct_cols, dcinfo); } - if (query_is_distinct_for(subquery, colnos, opids)) + if (query_is_distinct_for_with_collations(subquery, distinct_cols)) return true; } return false; @@ -1095,31 +1132,70 @@ query_supports_distinctness(Query *query) } /* - * query_is_distinct_for - does query never return duplicates of the - * specified columns? + * query_is_distinct_for - ABI-preserving wrapper around + * query_is_distinct_for_with_collations(). + * + * The original signature took parallel colnos/opids lists and did not + * consider collations. External callers built against earlier minor + * releases continue to call it with the historical (collation-blind) + * semantics; we forward with InvalidOid collations, which makes the + * collation check a no-op (see collations_agree_on_equality()). + */ +bool +query_is_distinct_for(Query *query, List *colnos, List *opids) +{ + List *distinct_cols = NIL; + ListCell *lc1; + ListCell *lc2; + + Assert(list_length(colnos) == list_length(opids)); + + forboth(lc1, colnos, lc2, opids) + { + DistinctColInfo *dcinfo = palloc(sizeof(DistinctColInfo)); + + dcinfo->colno = lfirst_int(lc1); + dcinfo->opid = lfirst_oid(lc2); + dcinfo->collid = InvalidOid; + distinct_cols = lappend(distinct_cols, dcinfo); + } + + return query_is_distinct_for_with_collations(query, distinct_cols); +} + +/* + * query_is_distinct_for_with_collations - does query never return duplicates + * of the specified columns? * * query is a not-yet-planned subquery (in current usage, it's always from * a subquery RTE, which the planner avoids scribbling on). * - * colnos is an integer list of output column numbers (resno's). We are - * interested in whether rows consisting of just these columns are certain - * to be distinct. "Distinctness" is defined according to whether the - * corresponding upper-level equality operators listed in opids would think - * the values are distinct. (Note: the opids entries could be cross-type - * operators, and thus not exactly the equality operators that the subquery - * would use itself. We use equality_ops_are_compatible() to check - * compatibility. That looks at opfamily membership for index AMs that have - * declared that they support consistent equality semantics within an + * distinct_cols is a list of DistinctColInfo, one per requested output column. + * Each entry names the subquery output column number we want distinct, the + * upper-level equality operator we'll compare values with, and that operator's + * input collation. We are interested in whether rows consisting of just these + * columns are certain to be distinct. + * + * "Distinctness" is defined according to whether the corresponding upper-level + * equality operators would think the values are distinct. (Note: each opid + * could be a cross-type operator, and thus not exactly the equality operator + * that the subquery would use itself. We use equality_ops_are_compatible() to + * check compatibility. That looks at opfamily membership for index AMs that + * have declared that they support consistent equality semantics within an * opfamily, and so should give trustworthy answers for all operators that we * might need to deal with here.) + * + * The collid must also agree on equality with the collation the subquery's own + * DISTINCT/GROUP BY/set-op uses to deduplicate the column, else the subquery's + * distinctness does not carry over to the caller's equality semantics. Two + * collations agree on equality if they match or if both are deterministic (in + * which case both reduce equality to byte-equality; see CREATE COLLATION). */ -bool -query_is_distinct_for(Query *query, List *colnos, List *opids) +static bool +query_is_distinct_for_with_collations(Query *query, List *distinct_cols) { ListCell *l; - Oid opid; - - Assert(list_length(colnos) == list_length(opids)); + DistinctColInfo *dcinfo; /* * DISTINCT (including DISTINCT ON) guarantees uniqueness if all the @@ -1135,9 +1211,11 @@ query_is_distinct_for(Query *query, List *colnos, List *opids) TargetEntry *tle = get_sortgroupclause_tle(sgc, query->targetList); - opid = distinct_col_search(tle->resno, colnos, opids); - if (!OidIsValid(opid) || - !equality_ops_are_compatible(opid, sgc->eqop)) + dcinfo = distinct_col_search(tle->resno, distinct_cols); + if (dcinfo == NULL || + !equality_ops_are_compatible(dcinfo->opid, sgc->eqop) || + !collations_agree_on_equality(dcinfo->collid, + exprCollation((Node *) tle->expr))) break; /* exit early if no match */ } if (l == NULL) /* had matches for all? */ @@ -1166,9 +1244,11 @@ query_is_distinct_for(Query *query, List *colnos, List *opids) TargetEntry *tle = get_sortgroupclause_tle(sgc, query->targetList); - opid = distinct_col_search(tle->resno, colnos, opids); - if (!OidIsValid(opid) || - !equality_ops_are_compatible(opid, sgc->eqop)) + dcinfo = distinct_col_search(tle->resno, distinct_cols); + if (dcinfo == NULL || + !equality_ops_are_compatible(dcinfo->opid, sgc->eqop) || + !collations_agree_on_equality(dcinfo->collid, + exprCollation((Node *) tle->expr))) break; /* exit early if no match */ } if (l == NULL) /* had matches for all? */ @@ -1234,9 +1314,11 @@ query_is_distinct_for(Query *query, List *colnos, List *opids) sgc = (SortGroupClause *) lfirst(lg); lg = lnext(topop->groupClauses, lg); - opid = distinct_col_search(tle->resno, colnos, opids); - if (!OidIsValid(opid) || - !equality_ops_are_compatible(opid, sgc->eqop)) + dcinfo = distinct_col_search(tle->resno, distinct_cols); + if (dcinfo == NULL || + !equality_ops_are_compatible(dcinfo->opid, sgc->eqop) || + !collations_agree_on_equality(dcinfo->collid, + exprCollation((Node *) tle->expr))) break; /* exit early if no match */ } if (l == NULL) /* had matches for all? */ @@ -1256,24 +1338,23 @@ query_is_distinct_for(Query *query, List *colnos, List *opids) } /* - * distinct_col_search - subroutine for query_is_distinct_for + * distinct_col_search - subroutine for query_is_distinct_for_with_collations * - * If colno is in colnos, return the corresponding element of opids, - * else return InvalidOid. (Ordinarily colnos would not contain duplicates, - * but if it does, we arbitrarily select the first match.) + * If colno matches the colno field of an entry in distinct_cols, return a + * pointer to that entry; else return NULL. (Ordinarily distinct_cols would + * not contain duplicate colnos, but if it does, we arbitrarily select the + * first match.) */ -static Oid -distinct_col_search(int colno, List *colnos, List *opids) +static DistinctColInfo * +distinct_col_search(int colno, List *distinct_cols) { - ListCell *lc1, - *lc2; - - forboth(lc1, colnos, lc2, opids) + foreach_ptr(DistinctColInfo, dcinfo, distinct_cols) { - if (colno == lfirst_int(lc1)) - return lfirst_oid(lc2); + if (dcinfo->colno == colno) + return dcinfo; } - return InvalidOid; + + return NULL; } diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index 06128a9f243..10b7358c28b 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -5271,7 +5271,7 @@ fix_indexqual_operand(Node *node, IndexOptInfo *index, int indexcol) /* * Remove any PlaceHolderVar wrapping of the indexkey */ - node = strip_phvs_in_index_operand(node); + node = strip_noop_phvs(node); /* * Remove any binary-compatible relabeling of the indexkey diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c index 01804b085b3..8112509e872 100644 --- a/src/backend/optimizer/plan/initsplan.c +++ b/src/backend/optimizer/plan/initsplan.c @@ -80,6 +80,18 @@ typedef struct JoinTreeItem * lateral references */ } JoinTreeItem; +/* + * Compatibility info for one GROUP BY item, precomputed for use by + * remove_useless_groupby_columns() when matching unique-index columns against + * GROUP BY items. + */ +typedef struct GroupByColInfo +{ + AttrNumber attno; /* var->varattno */ + List *eq_opfamilies; /* mergejoin opfamilies of sgc->eqop */ + Oid coll; /* var->varcollid */ +} GroupByColInfo; + static void extract_lateral_references(PlannerInfo *root, RelOptInfo *brel, Index rtindex); @@ -413,6 +425,7 @@ remove_useless_groupby_columns(PlannerInfo *root) { Query *parse = root->parse; Bitmapset **groupbyattnos; + List **groupbycols; Bitmapset **surplusvars; bool tryremove = false; ListCell *lc; @@ -429,15 +442,21 @@ remove_useless_groupby_columns(PlannerInfo *root) /* * Scan the GROUP BY clause to find GROUP BY items that are simple Vars. * Fill groupbyattnos[k] with a bitmapset of the column attnos of RTE k - * that are GROUP BY items. + * that are GROUP BY items, and groupbycols[k] with a parallel list of + * GroupByColInfo records. We need the latter so that, when checking a + * unique index against this rel's GROUP BY items, we can verify that the + * index's notion of equality agrees with at least one GROUP BY item per + * index column. */ groupbyattnos = (Bitmapset **) palloc0(sizeof(Bitmapset *) * (list_length(parse->rtable) + 1)); + groupbycols = palloc0_array(List *, list_length(parse->rtable) + 1); foreach(lc, root->processed_groupClause) { SortGroupClause *sgc = lfirst_node(SortGroupClause, lc); TargetEntry *tle = get_sortgroupclause_tle(sgc, parse->targetList); Var *var = (Var *) tle->expr; + GroupByColInfo *info; /* * Ignore non-Vars and Vars from other query levels. @@ -463,6 +482,12 @@ remove_useless_groupby_columns(PlannerInfo *root) tryremove |= !bms_is_empty(groupbyattnos[relid]); groupbyattnos[relid] = bms_add_member(groupbyattnos[relid], var->varattno - FirstLowInvalidHeapAttributeNumber); + + info = palloc(sizeof(GroupByColInfo)); + info->attno = var->varattno; + info->eq_opfamilies = get_mergejoin_opfamilies(sgc->eqop); + info->coll = var->varcollid; + groupbycols[relid] = lappend(groupbycols[relid], info); } /* @@ -517,7 +542,7 @@ remove_useless_groupby_columns(PlannerInfo *root) foreach_node(IndexOptInfo, index, rel->indexlist) { Bitmapset *ind_attnos; - bool nulls_check_ok; + bool index_check_ok; /* * Skip any non-unique and deferrable indexes. Predicate indexes @@ -532,9 +557,14 @@ remove_useless_groupby_columns(PlannerInfo *root) continue; ind_attnos = NULL; - nulls_check_ok = true; + index_check_ok = true; for (int i = 0; i < index->nkeycolumns; i++) { + AttrNumber indkey_attno = index->indexkeys[i]; + Oid indkey_opfamily = index->opfamily[i]; + Oid indkey_coll = index->indexcollations[i]; + ListCell *lc2; + /* * We must insist that the index columns are all defined NOT * NULL otherwise duplicate NULLs could exist. However, we @@ -544,20 +574,41 @@ remove_useless_groupby_columns(PlannerInfo *root) * despite the NULL. */ if (!index->nullsnotdistinct && - !bms_is_member(index->indexkeys[i], - rel->notnullattnums)) + !bms_is_member(indkey_attno, rel->notnullattnums)) + { + index_check_ok = false; + break; + } + + /* + * The index proves uniqueness only under its own opfamily and + * collation. Require some GROUP BY item on this column to + * use a compatible eqop and collation, the same check + * relation_has_unique_index_for() applies to join clauses. + */ + foreach(lc2, groupbycols[relid]) + { + GroupByColInfo *info = (GroupByColInfo *) lfirst(lc2); + + if (info->attno != indkey_attno) + continue; + if (list_member_oid(info->eq_opfamilies, indkey_opfamily) && + collations_agree_on_equality(indkey_coll, info->coll)) + break; + } + if (lc2 == NULL) { - nulls_check_ok = false; + index_check_ok = false; break; } ind_attnos = bms_add_member(ind_attnos, - index->indexkeys[i] - + indkey_attno - FirstLowInvalidHeapAttributeNumber); } - if (!nulls_check_ok) + if (!index_check_ok) continue; /* diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 53eea5a5d35..55fddf804c4 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -128,9 +128,27 @@ typedef struct * subquery belonging to a set operation */ } standard_qp_extra; +/* + * Context for the find_having_collation_conflicts walker. + * + * ancestor_collids is a stack of inputcollids contributed by collation-aware + * ancestors of the current node. Entries are pushed before recursing into a + * node's children and popped afterwards, so the stack reflects exactly the + * inputcollids on the current root-to-node path. + */ +typedef struct +{ + Index group_rtindex; + List *ancestor_collids; +} having_collation_ctx; + /* Local functions */ static Node *preprocess_expression(PlannerInfo *root, Node *expr, int kind); static void preprocess_qual_conditions(PlannerInfo *root, Node *jtnode); +static Bitmapset *find_having_collation_conflicts(Query *parse, + Index group_rtindex); +static bool having_collation_conflict_walker(Node *node, + having_collation_ctx *ctx); static void grouping_planner(PlannerInfo *root, double tuple_fraction, SetOperationStmt *setops); static grouping_sets_data *preprocess_grouping_sets(PlannerInfo *root); @@ -655,6 +673,8 @@ subquery_planner(PlannerGlobal *glob, Query *parse, PlannerInfo *parent_root, PlannerInfo *root; List *newWithCheckOptions; List *newHaving; + Bitmapset *havingCollationConflicts; + int havingIdx; bool hasOuterJoins; bool hasResultRTEs; RelOptInfo *final_rel; @@ -1076,6 +1096,27 @@ subquery_planner(PlannerGlobal *glob, Query *parse, PlannerInfo *parent_root, } } + /* + * Before we flatten GROUP Vars, check which HAVING clauses have collation + * conflicts. When GROUP BY uses a nondeterministic collation, values + * that are "equal" for grouping may be distinguishable under a different + * collation. If such a HAVING clause were moved to WHERE, it would + * filter individual rows before grouping, potentially eliminating some + * members of a group and thereby changing aggregate results. + * + * We do this check before flatten_group_exprs because we can easily + * identify grouping expressions by checking whether a Var references + * RTE_GROUP, and such Vars directly carry the GROUP BY collation as their + * varcollid. After flattening, these Vars are replaced by the underlying + * expressions, and we would have to match expressions in the HAVING + * clause back to grouping expressions, which is much more complex. + */ + if (parse->hasGroupRTE) + havingCollationConflicts = + find_having_collation_conflicts(parse, root->group_rtindex); + else + havingCollationConflicts = NULL; + /* * Replace any Vars in the subquery's targetlist and havingQual that * reference GROUP outputs with the underlying grouping expressions. @@ -1120,6 +1161,14 @@ subquery_planner(PlannerGlobal *glob, Query *parse, PlannerInfo *parent_root, * but it's okay: it's just an optimization to avoid running pull_varnos * when there cannot be any Vars in the HAVING clause.) * + * We also cannot do this if the HAVING clause uses a different collation + * than the GROUP BY for any grouping expression whose GROUP BY collation + * is nondeterministic. This is detected before flatten_group_exprs (see + * find_having_collation_conflicts above) and recorded in the + * havingCollationConflicts bitmapset. The bitmapset indexes remain valid + * here because flatten_group_exprs uses expression_tree_mutator, which + * preserves the list length and ordering of havingQual. + * * Also, it may be that the clause is so expensive to execute that we're * better off doing it only once per group, despite the loss of * selectivity. This is hard to estimate short of doing the entire @@ -1152,6 +1201,7 @@ subquery_planner(PlannerGlobal *glob, Query *parse, PlannerInfo *parent_root, * as Node *. */ newHaving = NIL; + havingIdx = 0; foreach(l, (List *) parse->havingQual) { Node *havingclause = (Node *) lfirst(l); @@ -1159,6 +1209,7 @@ subquery_planner(PlannerGlobal *glob, Query *parse, PlannerInfo *parent_root, if (contain_agg_clause(havingclause) || contain_volatile_functions(havingclause) || contain_subplans(havingclause) || + bms_is_member(havingIdx, havingCollationConflicts) || (parse->groupClause && parse->groupingSets && bms_is_member(root->group_rtindex, pull_varnos(root, havingclause)))) { @@ -1195,6 +1246,8 @@ subquery_planner(PlannerGlobal *glob, Query *parse, PlannerInfo *parent_root, /* ... and also keep it in HAVING */ newHaving = lappend(newHaving, havingclause); } + + havingIdx++; } parse->havingQual = (Node *) newHaving; @@ -1386,6 +1439,195 @@ preprocess_qual_conditions(PlannerInfo *root, Node *jtnode) (int) nodeTag(jtnode)); } +/* + * find_having_collation_conflicts + * Identify HAVING clauses that must not be moved to WHERE due to collation + * mismatches with GROUP BY. + * + * This must be called before flatten_group_exprs, while the HAVING clause + * still contains GROUP Vars (Vars referencing RTE_GROUP). These GROUP Vars + * carry the GROUP BY collation as their varcollid. A GROUP Var with a + * nondeterministic varcollid conflicts whenever some collation-aware ancestor + * on its path applies a different inputcollid: that operator would distinguish + * values which the GROUP BY considers equal, so the clause is unsafe to push + * to WHERE. + * + * Returns a Bitmapset of zero-based indexes into the havingQual list for + * clauses that have collation conflicts and must stay in HAVING. + */ +static Bitmapset * +find_having_collation_conflicts(Query *parse, Index group_rtindex) +{ + Bitmapset *result = NULL; + having_collation_ctx ctx; + int idx; + + if (parse->havingQual == NULL) + return NULL; + + ctx.group_rtindex = group_rtindex; + ctx.ancestor_collids = NIL; + + idx = 0; + foreach_ptr(Node, clause, (List *) parse->havingQual) + { + if (having_collation_conflict_walker(clause, &ctx)) + result = bms_add_member(result, idx); + idx++; + Assert(ctx.ancestor_collids == NIL); + } + + return result; +} + +/* + * Walker function for find_having_collation_conflicts. + * + * Walk the clause top-down, maintaining a stack of inputcollids contributed + * by collation-aware ancestors. At each GROUP Var with a nondeterministic + * varcollid, the clause has a conflict if any ancestor's inputcollid differs + * from the GROUP Var's varcollid. Most collation-aware nodes expose their + * inputcollid through exprInputCollation(). Two structural exceptions need + * special handling: + * + * - RowCompareExpr carries one inputcollid per column in inputcollids[], so we + * descend into its (largs[i], rargs[i]) pairs explicitly with the matching + * collation pushed onto the stack. + * + * - A simple CASE (CaseExpr with a non-NULL arg) holds the arg outside the + * WHEN's OpExpr, even though the WHEN's OpExpr is the place where the + * comparison's inputcollid lives. Parse analysis builds each WHEN as + * "OpExpr(CaseTestExpr op val)" -- the CaseTestExpr is a placeholder for + * the arg. Before walking cexpr->arg we therefore push every WHEN's + * inputcollid onto the ancestor stack, so a GROUP Var at the arg is + * checked against the same collations the WHEN comparisons would apply. + * The WHEN bodies and defresult are then walked under the unchanged stack + * so their own collation contexts are picked up by the default path. + */ +static bool +having_collation_conflict_walker(Node *node, having_collation_ctx *ctx) +{ + Oid this_collid; + bool result; + + if (node == NULL) + return false; + + if (IsA(node, Var)) + { + Var *var = (Var *) node; + + /* We should not see any upper-level Vars here */ + Assert(var->varlevelsup == 0); + + if (var->varno == ctx->group_rtindex && + OidIsValid(var->varcollid) && + !get_collation_isdeterministic(var->varcollid)) + { + foreach_oid(collid, ctx->ancestor_collids) + { + if (collid != var->varcollid) + return true; + } + } + return false; + } + + if (IsA(node, RowCompareExpr)) + { + RowCompareExpr *rcexpr = (RowCompareExpr *) node; + ListCell *lc_l; + ListCell *lc_r; + ListCell *lc_c; + + /* + * Each column of a row comparison is compared under its own + * inputcollids[i]. Walk each (largs[i], rargs[i]) pair with that + * collation pushed, so a Var in column i is checked against the + * collation that actually applies to it. + */ + forthree(lc_l, rcexpr->largs, + lc_r, rcexpr->rargs, + lc_c, rcexpr->inputcollids) + { + Oid collid = lfirst_oid(lc_c); + bool found; + + if (OidIsValid(collid)) + ctx->ancestor_collids = lappend_oid(ctx->ancestor_collids, + collid); + + found = having_collation_conflict_walker((Node *) lfirst(lc_l), + ctx) || + having_collation_conflict_walker((Node *) lfirst(lc_r), + ctx); + + if (OidIsValid(collid)) + ctx->ancestor_collids = + list_delete_last(ctx->ancestor_collids); + + if (found) + return true; + } + return false; + } + + if (IsA(node, CaseExpr) && ((CaseExpr *) node)->arg != NULL) + { + CaseExpr *cexpr = (CaseExpr *) node; + int saved_len = list_length(ctx->ancestor_collids); + bool found; + + /* + * Push every WHEN's inputcollid before walking cexpr->arg, since each + * WHEN implicitly compares the arg under that inputcollid. + */ + foreach_node(CaseWhen, cw, cexpr->args) + { + Oid collid = exprInputCollation((Node *) cw->expr); + + if (OidIsValid(collid)) + ctx->ancestor_collids = lappend_oid(ctx->ancestor_collids, + collid); + } + + found = having_collation_conflict_walker((Node *) cexpr->arg, ctx); + + ctx->ancestor_collids = list_truncate(ctx->ancestor_collids, + saved_len); + + if (found) + return true; + + /* + * Walk the WHEN bodies and defresult under the unchanged ancestor + * stack; any inputcollids inside them are picked up by the default + * path. + */ + foreach_node(CaseWhen, cw, cexpr->args) + { + if (having_collation_conflict_walker((Node *) cw->expr, ctx) || + having_collation_conflict_walker((Node *) cw->result, ctx)) + return true; + } + return having_collation_conflict_walker((Node *) cexpr->defresult, + ctx); + } + + this_collid = exprInputCollation(node); + if (OidIsValid(this_collid)) + ctx->ancestor_collids = lappend_oid(ctx->ancestor_collids, + this_collid); + + result = expression_tree_walker(node, having_collation_conflict_walker, + ctx); + + if (OidIsValid(this_collid)) + ctx->ancestor_collids = list_delete_last(ctx->ancestor_collids); + + return result; +} + /* * preprocess_phv_expression * Do preprocessing on a PlaceHolderVar expression that's been pulled up. diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index e7cb3fede66..0e567890c72 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -1618,8 +1618,6 @@ convert_EXISTS_sublink_to_join(PlannerInfo *root, SubLink *sublink, static bool simplify_EXISTS_query(PlannerInfo *root, Query *query) { - ListCell *lc; - /* * We don't try to simplify at all if the query uses set operations, * aggregates, grouping sets, SRFs, modifying CTEs, HAVING, OFFSET, or FOR @@ -1689,25 +1687,27 @@ simplify_EXISTS_query(PlannerInfo *root, Query *query) query->hasDistinctOn = false; /* - * Since we have thrown away the GROUP BY clauses, we'd better remove the - * RTE_GROUP RTE and clear the hasGroupRTE flag. + * Since we have thrown away the GROUP BY clauses, we'd better get rid of + * the RTE_GROUP RTE and clear the hasGroupRTE flag. To safely get rid of + * the RTE_GROUP RTE without shifting the index of any subsequent RTE in + * the rtable, we convert the RTE to be RTE_RESULT type in-place, and zero + * out RTE_GROUP-specific fields. */ - foreach(lc, query->rtable) + if (query->hasGroupRTE) { - RangeTblEntry *rte = lfirst_node(RangeTblEntry, lc); - - /* - * Remove the RTE_GROUP RTE and clear the hasGroupRTE flag. (Since - * we'll exit the foreach loop immediately, we don't bother with - * foreach_delete_current.) - */ - if (rte->rtekind == RTE_GROUP) + foreach_node(RangeTblEntry, rte, query->rtable) { - Assert(query->hasGroupRTE); - query->rtable = list_delete_cell(query->rtable, lc); - query->hasGroupRTE = false; - break; + if (rte->rtekind == RTE_GROUP) + { + rte->rtekind = RTE_RESULT; + rte->groupexprs = NIL; + + /* A query should only have one RTE_GROUP, so we can stop. */ + break; + } } + + query->hasGroupRTE = false; } return true; diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c index 87dc6f56b57..7bf4e55c7a1 100644 --- a/src/backend/optimizer/prep/prepjointree.c +++ b/src/backend/optimizer/prep/prepjointree.c @@ -994,6 +994,7 @@ expand_virtual_generated_columns(PlannerInfo *root) { List *tlist = NIL; pullup_replace_vars_context rvcontext; + List *save_exclRelTlist = NIL; for (int i = 0; i < tupdesc->natts; i++) { @@ -1061,8 +1062,26 @@ expand_virtual_generated_columns(PlannerInfo *root) /* * Apply pullup variable replacement throughout the query tree. + * + * We intentionally do not touch the EXCLUDED pseudo-relation's + * targetlist here. Various places in the planner assume that it + * contains only Vars, and we want that to remain the case. More + * importantly, we don't want setrefs.c to turn any expanded + * EXCLUDED.virtual_column expressions in other parts of the query + * back into Vars referencing the original virtual column, which + * set_plan_refs() would do if exclRelTlist contained matching + * expressions. */ + if (parse->onConflict) + { + save_exclRelTlist = parse->onConflict->exclRelTlist; + parse->onConflict->exclRelTlist = NIL; + } + parse = (Query *) pullup_replace_vars((Node *) parse, &rvcontext); + + if (parse->onConflict) + parse->onConflict->exclRelTlist = save_exclRelTlist; } table_close(rel, NoLock); diff --git a/src/backend/optimizer/util/placeholder.c b/src/backend/optimizer/util/placeholder.c index e1cd00a72fb..86e3c1e751f 100644 --- a/src/backend/optimizer/util/placeholder.c +++ b/src/backend/optimizer/util/placeholder.c @@ -35,6 +35,8 @@ static void find_placeholders_recurse(PlannerInfo *root, Node *jtnode); static void find_placeholders_in_expr(PlannerInfo *root, Node *expr); static bool contain_placeholder_references_walker(Node *node, contain_placeholder_references_context *context); +static bool contain_noop_phv_walker(Node *node, void *context); +static Node *strip_noop_phvs_mutator(Node *node, void *context); /* @@ -585,3 +587,92 @@ get_placeholder_nulling_relids(PlannerInfo *root, PlaceHolderInfo *phinfo) result = bms_del_members(result, phinfo->ph_eval_at); return result; } + +/* + * strip_noop_phvs + * Strip no-op PlaceHolderVar nodes from the given expression tree. + * + * A PlaceHolderVar that is not marked as nullable (i.e., its phnullingrels + * is empty) is effectively a no-op when it appears in a relation-scan-level + * expression. This function strips such PlaceHolderVars, which is useful + * for matching expressions to index keys or partition keys in cases where + * the expression has been wrapped in PlaceHolderVars during subquery pullup. + * + * IMPORTANT: the caller must ensure that the expression is a scan-level + * expression, so that non-nullable PlaceHolderVars in it are indeed no-ops. + * + * The removal is performed recursively because PlaceHolderVars can be nested + * or interleaved with other node types. We must peel back all layers to + * expose the base expression. + * + * As a performance optimization, we first use a lightweight walker to check + * for the presence of strippable PlaceHolderVars. The expensive mutator is + * invoked only if a candidate is found, avoiding unnecessary memory allocation + * and tree copying in the common case where no PlaceHolderVars are present. + */ +Node * +strip_noop_phvs(Node *node) +{ + /* Don't mutate/copy if no target PHVs exist */ + if (!contain_noop_phv_walker(node, NULL)) + return node; + + return strip_noop_phvs_mutator(node, NULL); +} + +/* + * contain_noop_phv_walker + * Detect if there are any PlaceHolderVars in the tree that are candidates + * for stripping. + * + * We identify a PlaceHolderVar as strippable only if its phnullingrels is + * empty. + */ +static bool +contain_noop_phv_walker(Node *node, void *context) +{ + if (node == NULL) + return false; + + if (IsA(node, PlaceHolderVar)) + { + PlaceHolderVar *phv = (PlaceHolderVar *) node; + + if (bms_is_empty(phv->phnullingrels)) + return true; + } + + return expression_tree_walker(node, contain_noop_phv_walker, + context); +} + +/* + * strip_noop_phvs_mutator + * Recursively remove PlaceHolderVars that are not marked nullable. + * + * We strip a PlaceHolderVar only if its phnullingrels is empty, replacing it + * with its contained expression. + */ +static Node * +strip_noop_phvs_mutator(Node *node, void *context) +{ + if (node == NULL) + return NULL; + + if (IsA(node, PlaceHolderVar)) + { + PlaceHolderVar *phv = (PlaceHolderVar *) node; + + if (bms_is_empty(phv->phnullingrels)) + { + /* Recurse on its contained expression */ + return strip_noop_phvs_mutator((Node *) phv->phexpr, + context); + } + + /* Otherwise, keep this PHV but check its contained expression */ + } + + return expression_tree_mutator(node, strip_noop_phvs_mutator, + context); +} diff --git a/src/backend/oracle_parser/ora_gram.y b/src/backend/oracle_parser/ora_gram.y index e972113ecb6..09adcb86e0a 100644 --- a/src/backend/oracle_parser/ora_gram.y +++ b/src/backend/oracle_parser/ora_gram.y @@ -18025,6 +18025,20 @@ func_expr_common_subexpr: COERCE_SQL_SYNTAX, @1); } + | EXTRACT '(' a_expr ',' a_expr ')' + { + $$ = (Node *) makeFuncCall(list_make1(makeString("extract")), + list_make2($3, $5), + COERCE_EXPLICIT_CALL, + @1); + } + | EXTRACT '(' a_expr ',' a_expr ',' a_expr ')' + { + $$ = (Node *) makeFuncCall(list_make1(makeString("extract")), + list_make3($3, $5, $7), + COERCE_EXPLICIT_CALL, + @1); + } /* End - ReqID:SRS-SQL-XML */ | NORMALIZE '(' a_expr ')' { diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index c93e546b1b7..7f4eb90b28b 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -579,6 +579,14 @@ transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt) ACL_DELETE); nsitem = pstate->p_target_nsitem; + /* disallow DELETE ... WHERE CURRENT OF on a view */ + if (stmt->whereClause && + IsA(stmt->whereClause, CurrentOfExpr) && + pstate->p_target_relation->rd_rel->relkind == RELKIND_VIEW) + ereport(ERROR, + errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("WHERE CURRENT OF on a view is not implemented")); + /* there's no DISTINCT in DELETE */ qry->distinctClause = NIL; @@ -2520,6 +2528,14 @@ transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt) ACL_UPDATE); nsitem = pstate->p_target_nsitem; + /* disallow UPDATE ... WHERE CURRENT OF on a view */ + if (stmt->whereClause && + IsA(stmt->whereClause, CurrentOfExpr) && + pstate->p_target_relation->rd_rel->relkind == RELKIND_VIEW) + ereport(ERROR, + errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("WHERE CURRENT OF on a view is not implemented")); + /* subqueries in FROM cannot access the result relation */ nsitem->p_lateral_only = true; nsitem->p_lateral_ok = false; diff --git a/src/backend/parser/parse_agg.c b/src/backend/parser/parse_agg.c index b8340557b34..4163d9a5930 100644 --- a/src/backend/parser/parse_agg.c +++ b/src/backend/parser/parse_agg.c @@ -1213,8 +1213,8 @@ parseCheckAggregates(ParseState *pstate, Query *qry) } /* - * Build a list of the acceptable GROUP BY expressions for use by - * substitute_grouped_columns(). + * Build a list of the acceptable GROUP BY expressions to save in the + * RTE_GROUP RTE, and for use by substitute_grouped_columns(). * * We get the TLE, not just the expr, because GROUPING wants to know the * sortgroupref. @@ -1231,6 +1231,23 @@ parseCheckAggregates(ParseState *pstate, Query *qry) groupClauses = lappend(groupClauses, expr); } + /* + * If there are any acceptable GROUP BY expressions, build an RTE and + * nsitem for the result of the grouping step. (It's important to do this + * before flattening join alias vars in groupClauses, because the RTE + * should preserve any alias vars that were in the input.) + */ + if (groupClauses) + { + pstate->p_grouping_nsitem = + addRangeTableEntryForGroup(pstate, groupClauses); + + /* Set qry->rtable again in case it was previously NIL */ + qry->rtable = pstate->p_rtable; + /* Mark the Query as having RTE_GROUP RTE */ + qry->hasGroupRTE = true; + } + /* * If there are join alias vars involved, we have to flatten them to the * underlying vars, so that aliased and unaliased vars will be correctly @@ -1266,21 +1283,6 @@ parseCheckAggregates(ParseState *pstate, Query *qry) } } - /* - * If there are any acceptable GROUP BY expressions, build an RTE and - * nsitem for the result of the grouping step. - */ - if (groupClauses) - { - pstate->p_grouping_nsitem = - addRangeTableEntryForGroup(pstate, groupClauses); - - /* Set qry->rtable again in case it was previously NIL */ - qry->rtable = pstate->p_rtable; - /* Mark the Query as having RTE_GROUP RTE */ - qry->hasGroupRTE = true; - } - /* * Replace grouped variables in the targetlist and HAVING clause with Vars * that reference the RTE_GROUP RTE. Emit an error message if we find any diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c index 5992e0296b7..433e0ba1112 100644 --- a/src/backend/parser/parse_utilcmd.c +++ b/src/backend/parser/parse_utilcmd.c @@ -2195,7 +2195,10 @@ generateClonedIndexStmt(RangeVar *heapRel, Relation source_idx, * extended statistic "source_statsid", for the rel identified by heapRel and * heapRelid. * - * Attribute numbers in expression Vars are adjusted according to attmap. + * stxkeys in the source statistic holds attribute numbers from the parent + * relation. Those attnums, along with the attribute numbers referenced by + * Vars inside the expression tree, are remapped to the new relation's + * numbering according to attmap. */ static CreateStatsStmt * generateClonedExtStatsStmt(RangeVar *heapRel, Oid heapRelid, @@ -2253,7 +2256,8 @@ generateClonedExtStatsStmt(RangeVar *heapRel, Oid heapRelid, StatsElem *selem = makeNode(StatsElem); AttrNumber attnum = statsrec->stxkeys.values[i]; - selem->name = get_attname(heapRelid, attnum, false); + selem->name = + get_attname(heapRelid, attmap->attnums[attnum - 1], false); selem->expr = NULL; def_names = lappend(def_names, selem); @@ -2913,7 +2917,7 @@ transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt) /* * The WITHOUT OVERLAPS part (if any) must be a range or - * multirange type. + * multirange type, or a domain over such a type. */ if (constraint->without_overlaps && lc == list_last_cell(constraint->keys)) { @@ -2931,8 +2935,7 @@ transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt) const char *attname; if (attr->attisdropped) - break; - + continue; attname = NameStr(attr->attname); if (strcmp(attname, key) == 0) { @@ -2944,10 +2947,16 @@ transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt) } if (found) { + /* Look up column type if we didn't already */ if (!OidIsValid(typid) && column) - typid = typenameTypeId(NULL, column->typeName); - - if (!OidIsValid(typid) || !(type_is_range(typid) || type_is_multirange(typid))) + typid = typenameTypeId(cxt->pstate, + column->typeName); + /* Look through any domain */ + if (OidIsValid(typid)) + typid = getBaseType(typid); + /* Complain if not range/multirange */ + if (!OidIsValid(typid) || + !(type_is_range(typid) || type_is_multirange(typid))) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("column \"%s\" in WITHOUT OVERLAPS is not a range or multirange type", key), diff --git a/src/backend/partitioning/partprune.c b/src/backend/partitioning/partprune.c index 48a35f763e9..2ef98d6ad6e 100644 --- a/src/backend/partitioning/partprune.c +++ b/src/backend/partitioning/partprune.c @@ -49,6 +49,7 @@ #include "optimizer/cost.h" #include "optimizer/optimizer.h" #include "optimizer/pathnode.h" +#include "optimizer/placeholder.h" #include "parser/parsetree.h" #include "partitioning/partbounds.h" #include "partitioning/partprune.h" @@ -1814,6 +1815,15 @@ gen_prune_steps_from_opexps(GeneratePruningStepsContext *context, * and couldn't possibly match any other one either, due to its form or * properties (such as containing a volatile function). * Output arguments: none set. + * + * Note that when pulling up a subquery, the clause operands may get wrapped + * in PlaceHolderVars to enforce separate identity or as a result of outer + * joins. We must strip such no-op PlaceHolderVars before comparing operands + * to the partition key, otherwise the equal() checks will fail to recognize + * valid matches. This is safe because the clauses here are always + * relation-scan-level expressions, where a PlaceHolderVar with empty + * phnullingrels is effectively a no-op. Stripping may also bring separate + * RelabelType nodes into adjacency, so we must loop when peeling those. */ static PartClauseMatchStatus match_clause_to_partition_key(GeneratePruningStepsContext *context, @@ -1929,10 +1939,12 @@ match_clause_to_partition_key(GeneratePruningStepsContext *context, PartClauseInfo *partclause; leftop = (Expr *) get_leftop(clause); - if (IsA(leftop, RelabelType)) + leftop = (Expr *) strip_noop_phvs((Node *) leftop); + while (IsA(leftop, RelabelType)) leftop = ((RelabelType *) leftop)->arg; rightop = (Expr *) get_rightop(clause); - if (IsA(rightop, RelabelType)) + rightop = (Expr *) strip_noop_phvs((Node *) rightop); + while (IsA(rightop, RelabelType)) rightop = ((RelabelType *) rightop)->arg; opno = opclause->opno; @@ -2180,7 +2192,8 @@ match_clause_to_partition_key(GeneratePruningStepsContext *context, *elem_clauses; ListCell *lc1; - if (IsA(leftop, RelabelType)) + leftop = (Expr *) strip_noop_phvs((Node *) leftop); + while (IsA(leftop, RelabelType)) leftop = ((RelabelType *) leftop)->arg; /* check if the LHS matches this partition key */ @@ -2406,7 +2419,8 @@ match_clause_to_partition_key(GeneratePruningStepsContext *context, NullTest *nulltest = (NullTest *) clause; Expr *arg = nulltest->arg; - if (IsA(arg, RelabelType)) + arg = (Expr *) strip_noop_phvs((Node *) arg); + while (IsA(arg, RelabelType)) arg = ((RelabelType *) arg)->arg; /* Does arg match with this partition key column? */ @@ -3718,7 +3732,8 @@ match_boolean_partition_clause(Oid partopfamily, Expr *clause, Expr *partkey, BooleanTest *btest = (BooleanTest *) clause; leftop = btest->arg; - if (IsA(leftop, RelabelType)) + leftop = (Expr *) strip_noop_phvs((Node *) leftop); + while (IsA(leftop, RelabelType)) leftop = ((RelabelType *) leftop)->arg; if (equal(leftop, partkey)) @@ -3755,7 +3770,8 @@ match_boolean_partition_clause(Oid partopfamily, Expr *clause, Expr *partkey, leftop = is_not_clause ? get_notclausearg(clause) : clause; - if (IsA(leftop, RelabelType)) + leftop = (Expr *) strip_noop_phvs((Node *) leftop); + while (IsA(leftop, RelabelType)) leftop = ((RelabelType *) leftop)->arg; /* Compare to the partition key, and make up a clause ... */ diff --git a/src/backend/po/de.po b/src/backend/po/de.po index 97c72dc96f3..05941cd212a 100644 --- a/src/backend/po/de.po +++ b/src/backend/po/de.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: PostgreSQL 18\n" "Report-Msgid-Bugs-To: pgsql-bugs@lists.postgresql.org\n" -"POT-Creation-Date: 2026-02-19 16:41+0000\n" -"PO-Revision-Date: 2026-02-20 09:18+0100\n" +"POT-Creation-Date: 2026-05-05 12:03+0000\n" +"PO-Revision-Date: 2026-05-06 16:05+0200\n" "Last-Translator: Peter Eisentraut \n" "Language-Team: German \n" "Language: de\n" @@ -88,7 +88,7 @@ msgstr "konnte Datei »%s« nicht zum Lesen öffnen: %m" #: ../common/controldata_utils.c:108 ../common/controldata_utils.c:110 #: access/transam/timeline.c:143 access/transam/timeline.c:362 -#: access/transam/twophase.c:1353 access/transam/xlog.c:3478 +#: access/transam/twophase.c:1354 access/transam/xlog.c:3478 #: access/transam/xlog.c:4369 access/transam/xlogrecovery.c:1257 #: access/transam/xlogrecovery.c:1355 access/transam/xlogrecovery.c:1392 #: access/transam/xlogrecovery.c:1459 backup/basebackup.c:2128 @@ -117,8 +117,8 @@ msgstr "konnte Datei »%s« nicht lesen: %d von %zu gelesen" #: ../common/controldata_utils.c:277 ../common/controldata_utils.c:280 #: access/heap/rewriteheap.c:1141 access/heap/rewriteheap.c:1246 #: access/transam/timeline.c:392 access/transam/timeline.c:438 -#: access/transam/timeline.c:512 access/transam/twophase.c:1365 -#: access/transam/twophase.c:1783 access/transam/xlog.c:3324 +#: access/transam/timeline.c:512 access/transam/twophase.c:1366 +#: access/transam/twophase.c:1784 access/transam/xlog.c:3324 #: access/transam/xlog.c:3518 access/transam/xlog.c:3523 #: access/transam/xlog.c:3659 access/transam/xlog.c:4339 #: access/transam/xlog.c:5311 commands/copyfrom.c:1929 commands/copyto.c:598 @@ -158,7 +158,7 @@ msgstr "" #: ../common/file_utils.c:428 ../common/file_utils.c:502 #: access/heap/rewriteheap.c:1229 access/transam/timeline.c:111 #: access/transam/timeline.c:251 access/transam/timeline.c:348 -#: access/transam/twophase.c:1309 access/transam/xlog.c:3214 +#: access/transam/twophase.c:1310 access/transam/xlog.c:3214 #: access/transam/xlog.c:3394 access/transam/xlog.c:3433 #: access/transam/xlog.c:3626 access/transam/xlog.c:4359 #: access/transam/xlogrecovery.c:4307 access/transam/xlogrecovery.c:4408 @@ -170,7 +170,7 @@ msgstr "" #: replication/logical/reorderbuffer.c:5346 #: replication/logical/snapbuild.c:1651 replication/logical/snapbuild.c:1763 #: replication/slot.c:2518 replication/walsender.c:616 -#: replication/walsender.c:3094 storage/file/copydir.c:167 +#: replication/walsender.c:3103 storage/file/copydir.c:167 #: storage/file/copydir.c:255 storage/file/fd.c:803 storage/file/fd.c:3575 #: storage/file/fd.c:3805 storage/file/fd.c:3895 storage/smgr/md.c:686 #: utils/cache/relmapper.c:818 utils/cache/relmapper.c:935 @@ -182,10 +182,10 @@ msgid "could not open file \"%s\": %m" msgstr "konnte Datei »%s« nicht öffnen: %m" #: ../common/controldata_utils.c:246 ../common/controldata_utils.c:249 -#: access/transam/twophase.c:1756 access/transam/twophase.c:1765 +#: access/transam/twophase.c:1757 access/transam/twophase.c:1766 #: access/transam/xlog.c:9340 access/transam/xlogfuncs.c:699 #: backup/basebackup_server.c:173 backup/basebackup_server.c:266 -#: backup/walsummary.c:304 postmaster/postmaster.c:4105 +#: backup/walsummary.c:304 postmaster/postmaster.c:4087 #: postmaster/syslogger.c:1523 postmaster/syslogger.c:1536 #: postmaster/syslogger.c:1549 utils/cache/relmapper.c:947 #, c-format @@ -196,7 +196,7 @@ msgstr "konnte Datei »%s« nicht schreiben: %m" #: ../common/file_utils.c:440 ../common/file_utils.c:510 #: access/heap/rewriteheap.c:925 access/heap/rewriteheap.c:1135 #: access/heap/rewriteheap.c:1240 access/transam/timeline.c:432 -#: access/transam/timeline.c:506 access/transam/twophase.c:1777 +#: access/transam/timeline.c:506 access/transam/twophase.c:1778 #: access/transam/xlog.c:3314 access/transam/xlog.c:3512 #: access/transam/xlog.c:4332 access/transam/xlog.c:8726 #: access/transam/xlog.c:8770 backup/basebackup_server.c:207 @@ -212,15 +212,15 @@ msgstr "konnte Datei »%s« nicht fsyncen: %m" #: ../common/cryptohash_openssl.c:356 ../common/exec.c:543 ../common/exec.c:588 #: ../common/exec.c:680 ../common/hmac.c:309 ../common/hmac.c:325 #: ../common/hmac_openssl.c:151 ../common/hmac_openssl.c:339 -#: ../common/jsonapi.c:2410 ../common/md5_common.c:156 +#: ../common/jsonapi.c:2459 ../common/md5_common.c:156 #: ../common/parse_manifest.c:157 ../common/parse_manifest.c:852 #: ../common/psprintf.c:140 ../common/scram-common.c:268 ../port/path.c:829 -#: ../port/path.c:866 ../port/path.c:883 access/transam/twophase.c:1418 +#: ../port/path.c:866 ../port/path.c:883 access/transam/twophase.c:1419 #: access/transam/xlogrecovery.c:571 lib/dshash.c:253 libpq/auth.c:1353 #: libpq/auth.c:1397 libpq/auth.c:1959 libpq/be-secure-gssapi.c:537 #: libpq/be-secure-gssapi.c:717 postmaster/bgworker.c:355 -#: postmaster/bgworker.c:1023 postmaster/postmaster.c:3575 -#: postmaster/walsummarizer.c:938 +#: postmaster/bgworker.c:1023 postmaster/postmaster.c:3557 +#: postmaster/walsummarizer.c:939 #: replication/libpqwalreceiver/libpqwalreceiver.c:364 #: replication/logical/logical.c:212 replication/walsender.c:825 #: storage/buffer/localbuf.c:745 storage/file/fd.c:912 storage/file/fd.c:1447 @@ -321,7 +321,7 @@ msgid "could not synchronize file system for file \"%s\": %m" msgstr "konnte Dateisystem für Datei »%s« nicht synchronisieren: %m" #: ../common/file_utils.c:123 ../common/file_utils.c:588 -#: ../common/file_utils.c:592 access/transam/twophase.c:1321 +#: ../common/file_utils.c:592 access/transam/twophase.c:1322 #: access/transam/xlogarchive.c:111 access/transam/xlogarchive.c:235 #: backup/basebackup.c:357 backup/basebackup.c:555 backup/basebackup.c:626 #: backup/walsummary.c:247 commands/copyfrom.c:1889 commands/copyto.c:979 @@ -342,7 +342,7 @@ msgstr "diese Installation unterstützt Sync-Methode »%s« nicht" #: ../common/file_utils.c:156 ../common/file_utils.c:304 #: ../common/pgfnames.c:48 ../common/rmtree.c:63 commands/tablespace.c:728 -#: commands/tablespace.c:738 postmaster/postmaster.c:1496 +#: commands/tablespace.c:738 postmaster/postmaster.c:1497 #: storage/file/fd.c:2997 storage/file/reinit.c:126 utils/adt/misc.c:256 #: utils/misc/tzparser.c:340 #, c-format @@ -368,107 +368,107 @@ msgstr "konnte Datei »%s« nicht in »%s« umbenennen: %m" msgid "internal error" msgstr "interner Fehler" -#: ../common/jsonapi.c:2435 +#: ../common/jsonapi.c:2484 msgid "Recursive descent parser cannot use incremental lexer." msgstr "Parser mit rekursivem Abstieg kann inkrementellen Lexer nicht benutzen." -#: ../common/jsonapi.c:2437 +#: ../common/jsonapi.c:2486 msgid "Incremental parser requires incremental lexer." msgstr "Inkrementeller Parser benötigt inkrementellen Lexer." -#: ../common/jsonapi.c:2439 +#: ../common/jsonapi.c:2488 msgid "JSON nested too deep, maximum permitted depth is 6400." msgstr "JSON zu tief geschachtelt, maximale erlaubte Tiefe ist 6400." -#: ../common/jsonapi.c:2441 +#: ../common/jsonapi.c:2490 #, c-format msgid "Escape sequence \"\\%.*s\" is invalid." msgstr "Escape-Sequenz »\\%.*s« ist nicht gültig." -#: ../common/jsonapi.c:2445 +#: ../common/jsonapi.c:2494 #, c-format msgid "Character with value 0x%02x must be escaped." msgstr "Zeichen mit Wert 0x%02x muss escapt werden." -#: ../common/jsonapi.c:2449 +#: ../common/jsonapi.c:2498 #, c-format msgid "Expected end of input, but found \"%.*s\"." msgstr "Ende der Eingabe erwartet, aber »%.*s« gefunden." -#: ../common/jsonapi.c:2452 +#: ../common/jsonapi.c:2501 #, c-format msgid "Expected array element or \"]\", but found \"%.*s\"." msgstr "Array-Element oder »]« erwartet, aber »%.*s« gefunden." -#: ../common/jsonapi.c:2455 +#: ../common/jsonapi.c:2504 #, c-format msgid "Expected \",\" or \"]\", but found \"%.*s\"." msgstr "»,« oder »]« erwartet, aber »%.*s« gefunden." -#: ../common/jsonapi.c:2458 +#: ../common/jsonapi.c:2507 #, c-format msgid "Expected \":\", but found \"%.*s\"." msgstr "»:« erwartet, aber »%.*s« gefunden." -#: ../common/jsonapi.c:2461 +#: ../common/jsonapi.c:2510 #, c-format msgid "Expected JSON value, but found \"%.*s\"." msgstr "JSON-Wert erwartet, aber »%.*s« gefunden." -#: ../common/jsonapi.c:2464 +#: ../common/jsonapi.c:2513 msgid "The input string ended unexpectedly." msgstr "Die Eingabezeichenkette endete unerwartet." -#: ../common/jsonapi.c:2466 +#: ../common/jsonapi.c:2515 #, c-format msgid "Expected string or \"}\", but found \"%.*s\"." msgstr "Zeichenkette oder »}« erwartet, aber »%.*s« gefunden." -#: ../common/jsonapi.c:2469 +#: ../common/jsonapi.c:2518 #, c-format msgid "Expected \",\" or \"}\", but found \"%.*s\"." msgstr "»,« oder »}« erwartet, aber »%.*s« gefunden." -#: ../common/jsonapi.c:2472 +#: ../common/jsonapi.c:2521 #, c-format msgid "Expected string, but found \"%.*s\"." msgstr "Zeichenkette erwartet, aber »%.*s« gefunden." -#: ../common/jsonapi.c:2475 +#: ../common/jsonapi.c:2524 #, c-format msgid "Token \"%.*s\" is invalid." msgstr "Token »%.*s« ist ungültig." -#: ../common/jsonapi.c:2481 jsonpath_scan.l:585 +#: ../common/jsonapi.c:2530 jsonpath_scan.l:585 #, c-format msgid "\\u0000 cannot be converted to text." msgstr "\\u0000 kann nicht in »text« umgewandelt werden." -#: ../common/jsonapi.c:2483 +#: ../common/jsonapi.c:2532 msgid "\"\\u\" must be followed by four hexadecimal digits." msgstr "Nach »\\u« müssen vier Hexadezimalziffern folgen." -#: ../common/jsonapi.c:2486 +#: ../common/jsonapi.c:2535 msgid "Unicode escape values cannot be used for code point values above 007F when the encoding is not UTF8." msgstr "Unicode-Escape-Werte können nicht für Code-Punkt-Werte über 007F verwendet werden, wenn die Kodierung nicht UTF8 ist." -#: ../common/jsonapi.c:2495 +#: ../common/jsonapi.c:2544 #, c-format msgid "Unicode escape value could not be translated to the server's encoding %s." msgstr "Unicode-Escape-Wert konnte nicht in die Serverkodierung %s umgewandelt werden." -#: ../common/jsonapi.c:2502 jsonpath_scan.l:618 +#: ../common/jsonapi.c:2551 jsonpath_scan.l:618 #, c-format msgid "Unicode high surrogate must not follow a high surrogate." msgstr "Unicode-High-Surrogate darf nicht auf ein High-Surrogate folgen." -#: ../common/jsonapi.c:2504 jsonpath_scan.l:629 jsonpath_scan.l:639 +#: ../common/jsonapi.c:2553 jsonpath_scan.l:629 jsonpath_scan.l:639 #: jsonpath_scan.l:691 #, c-format msgid "Unicode low surrogate must follow a high surrogate." msgstr "Unicode-Low-Surrogate muss auf ein High-Surrogate folgen." -#: ../common/jsonapi.c:2526 +#: ../common/jsonapi.c:2575 msgid "out of memory while constructing error description" msgstr "Speicher aufgebraucht beim Konstruieren der Fehlerbeschreibung" @@ -714,9 +714,9 @@ msgid "could not get exit code from subprocess: error code %lu" msgstr "konnte Statuscode des Subprozesses nicht ermitteln: Fehlercode %lu" #: ../common/rmtree.c:97 access/heap/rewriteheap.c:1214 -#: access/transam/twophase.c:1716 access/transam/xlogarchive.c:119 +#: access/transam/twophase.c:1717 access/transam/xlogarchive.c:119 #: access/transam/xlogarchive.c:399 backup/walsummary.c:254 -#: postmaster/postmaster.c:1069 postmaster/syslogger.c:1489 +#: postmaster/postmaster.c:1070 postmaster/syslogger.c:1489 #: replication/logical/origin.c:614 replication/logical/reorderbuffer.c:4841 #: replication/logical/snapbuild.c:1589 replication/logical/snapbuild.c:2045 #: replication/slot.c:2502 storage/file/fd.c:878 storage/file/fd.c:3443 @@ -926,7 +926,7 @@ msgid "could not open parent table of index \"%s\"" msgstr "konnte Basistabelle von Index »%s« nicht öffnen" #: access/brin/brin.c:1472 access/brin/brin.c:1568 access/gin/ginfast.c:1085 -#: parser/parse_utilcmd.c:2454 +#: parser/parse_utilcmd.c:2458 #, c-format msgid "index \"%s\" is not valid" msgstr "Index »%s« ist nicht gültig" @@ -1058,7 +1058,7 @@ msgid "index row requires %zu bytes, maximum size is %zu" msgstr "Indexzeile benötigt %zu Bytes, Maximalgröße ist %zu" #: access/common/printtup.c:292 commands/explain_dr.c:94 tcop/fastpath.c:106 -#: tcop/fastpath.c:453 tcop/postgres.c:1950 +#: tcop/fastpath.c:453 tcop/postgres.c:1951 #, c-format msgid "unsupported format code: %d" msgstr "nicht unterstützter Formatcode: %d" @@ -1192,7 +1192,7 @@ msgid "failed to re-find tuple within index \"%s\"" msgstr "konnte Tupel mit Index »%s« nicht erneut finden" #: access/gin/gininsert.c:1310 access/gin/ginutil.c:152 -#: executor/execExpr.c:2244 utils/adt/array_userfuncs.c:1963 +#: executor/execExpr.c:2244 utils/adt/array_userfuncs.c:1972 #: utils/adt/arrayfuncs.c:4034 utils/adt/arrayfuncs.c:6732 #: utils/adt/rowtypes.c:974 utils/sort/tuplesortvariants.c:646 #, c-format @@ -1288,12 +1288,12 @@ msgstr "Operatorfamilie »%s« für Zugriffsmethode %s enthält ungültige ORDER msgid "could not determine which collation to use for string hashing" msgstr "konnte die für das Zeichenketten-Hashing zu verwendende Sortierfolge nicht bestimmen" -#: access/hash/hashfunc.c:281 access/hash/hashfunc.c:336 catalog/heap.c:688 -#: catalog/heap.c:694 commands/createas.c:203 commands/createas.c:515 -#: commands/indexcmds.c:2090 commands/tablecmds.c:19987 commands/view.c:80 -#: regex/regc_pg_locale.c:242 utils/adt/formatting.c:1655 -#: utils/adt/formatting.c:1719 utils/adt/formatting.c:1783 -#: utils/adt/formatting.c:1847 utils/adt/like.c:163 utils/adt/like.c:194 +#: access/hash/hashfunc.c:281 access/hash/hashfunc.c:336 catalog/heap.c:702 +#: catalog/heap.c:708 commands/createas.c:203 commands/createas.c:515 +#: commands/indexcmds.c:2092 commands/tablecmds.c:19999 commands/view.c:80 +#: regex/regc_pg_locale.c:242 utils/adt/formatting.c:1657 +#: utils/adt/formatting.c:1721 utils/adt/formatting.c:1785 +#: utils/adt/formatting.c:1849 utils/adt/like.c:163 utils/adt/like.c:194 #: utils/adt/like_support.c:1020 utils/adt/varchar.c:738 #: utils/adt/varchar.c:1001 utils/adt/varchar.c:1057 utils/adt/varlena.c:1648 #, c-format @@ -1404,8 +1404,8 @@ msgstr "konnte nicht in Datei »%s« schreiben, %d von %d geschrieben: %m" #: access/transam/xlog.c:4311 access/transam/xlog.c:9329 #: access/transam/xlogfuncs.c:693 backup/basebackup_server.c:149 #: backup/basebackup_server.c:242 commands/dbcommands.c:495 -#: postmaster/launch_backend.c:354 postmaster/postmaster.c:4092 -#: postmaster/walsummarizer.c:1215 replication/logical/origin.c:626 +#: postmaster/launch_backend.c:354 postmaster/postmaster.c:4074 +#: postmaster/walsummarizer.c:1216 replication/logical/origin.c:626 #: replication/slot.c:2360 storage/file/copydir.c:173 #: storage/file/copydir.c:261 storage/smgr/md.c:252 utils/time/snapmgr.c:1252 #, c-format @@ -1684,8 +1684,8 @@ msgid "cannot access index \"%s\" while it is being reindexed" msgstr "auf Index »%s« kann nicht zugegriffen werden, während er reindiziert wird" #: access/index/indexam.c:203 catalog/objectaddress.c:1361 -#: commands/indexcmds.c:3016 commands/tablecmds.c:284 commands/tablecmds.c:308 -#: commands/tablecmds.c:19666 commands/tablecmds.c:21608 +#: commands/indexcmds.c:3018 commands/tablecmds.c:284 commands/tablecmds.c:308 +#: commands/tablecmds.c:19678 commands/tablecmds.c:21620 #, c-format msgid "\"%s\" is not an index" msgstr "»%s« ist kein Index" @@ -1711,7 +1711,7 @@ msgid "This may be because of a non-immutable index expression." msgstr "Das kann daran liegen, dass der Indexausdruck nicht »immutable« ist." #: access/nbtree/nbtpage.c:157 access/nbtree/nbtpage.c:611 -#: parser/parse_utilcmd.c:2504 +#: parser/parse_utilcmd.c:2508 #, c-format msgid "index \"%s\" is not a btree" msgstr "Index »%s« ist kein B-Tree" @@ -1831,13 +1831,13 @@ msgstr "Stellen Sie sicher, dass der Konfigurationsparameter »%s« auf dem Prim msgid "Make sure the configuration parameter \"%s\" is set." msgstr "Stellen Sie sicher, dass der Konfigurationsparameter »%s« gesetzt ist." -#: access/transam/multixact.c:1179 +#: access/transam/multixact.c:1266 #, c-format msgid "database is not accepting commands that assign new MultiXactIds to avoid wraparound data loss in database \"%s\"" msgstr "Datenbank nimmt keine Befehle an, die neue MultiXactIds zuweisen, um Datenverlust wegen Transaktionsnummernüberlauf in Datenbank »%s« zu vermeiden" -#: access/transam/multixact.c:1181 access/transam/multixact.c:1188 -#: access/transam/multixact.c:1212 access/transam/multixact.c:1221 +#: access/transam/multixact.c:1268 access/transam/multixact.c:1275 +#: access/transam/multixact.c:1299 access/transam/multixact.c:1308 #: access/transam/varsup.c:158 access/transam/varsup.c:165 #, c-format msgid "" @@ -1847,70 +1847,70 @@ msgstr "" "Führen Sie ein datenbankweites VACUUM in dieser Datenbank aus.\n" "Eventuell müssen Sie auch alte vorbereitete Transaktionen committen oder zurückrollen oder unbenutzte Replikations-Slots löschen." -#: access/transam/multixact.c:1186 +#: access/transam/multixact.c:1273 #, c-format msgid "database is not accepting commands that assign new MultiXactIds to avoid wraparound data loss in database with OID %u" msgstr "Datenbank nimmt keine Befehle an, die neue MultiXactIds zuweisen, um Datenverlust wegen Transaktionsnummernüberlauf in Datenbank mit OID %u zu vermeiden" -#: access/transam/multixact.c:1207 access/transam/multixact.c:2552 +#: access/transam/multixact.c:1294 access/transam/multixact.c:2650 #, c-format msgid "database \"%s\" must be vacuumed before %u more MultiXactId is used" msgid_plural "database \"%s\" must be vacuumed before %u more MultiXactIds are used" msgstr[0] "Datenbank »%s« muss gevacuumt werden, bevor %u weitere MultiXactId aufgebraucht ist" msgstr[1] "Datenbank »%s« muss gevacuumt werden, bevor %u weitere MultiXactIds aufgebraucht sind" -#: access/transam/multixact.c:1216 access/transam/multixact.c:2561 +#: access/transam/multixact.c:1303 access/transam/multixact.c:2659 #, c-format msgid "database with OID %u must be vacuumed before %u more MultiXactId is used" msgid_plural "database with OID %u must be vacuumed before %u more MultiXactIds are used" msgstr[0] "Datenbank mit OID %u muss gevacuumt werden, bevor %u weitere MultiXactId aufgebraucht ist" msgstr[1] "Datenbank mit OID %u muss gevacuumt werden, bevor %u weitere MultiXactIds aufgebraucht sind" -#: access/transam/multixact.c:1280 +#: access/transam/multixact.c:1367 #, c-format msgid "multixact \"members\" limit exceeded" msgstr "Grenzwert für Multixact-»Members« überschritten" -#: access/transam/multixact.c:1281 +#: access/transam/multixact.c:1368 #, c-format msgid "This command would create a multixact with %u members, but the remaining space is only enough for %u member." msgid_plural "This command would create a multixact with %u members, but the remaining space is only enough for %u members." msgstr[0] "Dieser Befehl würde eine Multixact mit %u Mitgliedern erzeugen, aber es ist nur genug Platz für %u Mitglied." msgstr[1] "Dieser Befehl würde eine Multixact mit %u Mitgliedern erzeugen, aber es ist nur genug Platz für %u Mitglieder." -#: access/transam/multixact.c:1286 +#: access/transam/multixact.c:1373 #, c-format msgid "Execute a database-wide VACUUM in database with OID %u with reduced \"vacuum_multixact_freeze_min_age\" and \"vacuum_multixact_freeze_table_age\" settings." msgstr "Führen Sie ein datenbankweites VACUUM in der Datenbank mit OID %u aus, mit reduzierten Einstellungen für »vacuum_multixact_freeze_min_age« und »vacuum_multixact_freeze_table_age«." -#: access/transam/multixact.c:1317 +#: access/transam/multixact.c:1404 #, c-format msgid "database with OID %u must be vacuumed before %d more multixact member is used" msgid_plural "database with OID %u must be vacuumed before %d more multixact members are used" msgstr[0] "Datenbank mit OID %u muss gevacuumt werden, bevor %d weiteres Multixact-Mitglied aufgebraucht ist" msgstr[1] "Datenbank mit OID %u muss gevacuumt werden, bevor %d weitere Multixact-Mitglieder aufgebraucht sind" -#: access/transam/multixact.c:1322 +#: access/transam/multixact.c:1409 #, c-format msgid "Execute a database-wide VACUUM in that database with reduced \"vacuum_multixact_freeze_min_age\" and \"vacuum_multixact_freeze_table_age\" settings." msgstr "Führen Sie ein datenbankweites VACUUM in dieser Datenbank aus, mit reduzierten Einstellungen für »vacuum_multixact_freeze_min_age« und »vacuum_multixact_freeze_table_age«." -#: access/transam/multixact.c:1461 +#: access/transam/multixact.c:1548 #, c-format msgid "MultiXactId %u does no longer exist -- apparent wraparound" msgstr "MultiXactId %u existiert nicht mehr -- anscheinender Überlauf" -#: access/transam/multixact.c:1467 +#: access/transam/multixact.c:1554 #, c-format msgid "MultiXactId %u has not been created yet -- apparent wraparound" msgstr "MultiXactId %u wurde noch nicht erzeugt -- anscheinender Überlauf" -#: access/transam/multixact.c:1560 +#: access/transam/multixact.c:1647 #, c-format msgid "MultiXact %u has invalid next offset" msgstr "MultiXact %u hat ungültiges nächstes Offset" -#: access/transam/multixact.c:2557 access/transam/multixact.c:2566 +#: access/transam/multixact.c:2655 access/transam/multixact.c:2664 #, c-format msgid "" "To avoid MultiXactId assignment failures, execute a database-wide VACUUM in that database.\n" @@ -1919,32 +1919,32 @@ msgstr "" "Um Scheitern von MultiXactId-Zuweisungen zu vermeiden, führen Sie ein komplettes VACUUM über diese Datenbank aus.\n" "Eventuell müssen Sie auch alte vorbereitete Transaktionen committen oder zurückrollen oder unbenutzte Replikations-Slots löschen." -#: access/transam/multixact.c:2845 +#: access/transam/multixact.c:2947 #, c-format msgid "MultiXact member wraparound protections are disabled because oldest checkpointed MultiXact %u does not exist on disk" msgstr "MultiXact-Member-Wraparound-Schutz ist deaktiviert, weil die älteste gecheckpointete MultiXact %u nicht auf der Festplatte existiert" -#: access/transam/multixact.c:2867 +#: access/transam/multixact.c:2969 #, c-format msgid "MultiXact member wraparound protections are now enabled" msgstr "MultiXact-Member-Wraparound-Schutz ist jetzt aktiviert" -#: access/transam/multixact.c:3258 +#: access/transam/multixact.c:3360 #, c-format msgid "oldest MultiXact %u not found, earliest MultiXact %u, skipping truncation" msgstr "älteste MultiXact %u nicht gefunden, älteste ist MultiXact %u, Truncate wird ausgelassen" -#: access/transam/multixact.c:3276 +#: access/transam/multixact.c:3378 #, c-format msgid "cannot truncate up to MultiXact %u because it does not exist on disk, skipping truncation" msgstr "kann nicht bis MultiXact %u trunkieren, weil sie nicht auf der Festplatte existiert, Trunkierung wird ausgelassen" -#: access/transam/multixact.c:3293 +#: access/transam/multixact.c:3395 #, c-format msgid "cannot truncate up to MultiXact %u because it has invalid offset, skipping truncation" msgstr "kann nicht bis MultiXact %u trunkieren, weil es ein ungültiges Offset hat, Trunkierung wird ausgelassen" -#: access/transam/multixact.c:3628 +#: access/transam/multixact.c:3732 #, c-format msgid "invalid MultiXactId: %u" msgstr "ungültige MultiXactId: %u" @@ -1973,12 +1973,12 @@ msgstr "Verbindung mit parallelem Arbeitsprozess verloren" msgid "parallel worker" msgstr "paralleler Arbeitsprozess" -#: access/transam/parallel.c:1355 replication/logical/applyparallelworker.c:897 +#: access/transam/parallel.c:1355 replication/logical/applyparallelworker.c:906 #, c-format msgid "could not map dynamic shared memory segment" msgstr "konnte dynamisches Shared-Memory-Segment nicht mappen" -#: access/transam/parallel.c:1360 replication/logical/applyparallelworker.c:903 +#: access/transam/parallel.c:1360 replication/logical/applyparallelworker.c:912 #, c-format msgid "invalid magic number in dynamic shared memory segment" msgstr "ungültige magische Zahl in dynamischem Shared-Memory-Segment" @@ -2162,12 +2162,12 @@ msgstr "Setzen Sie »max_prepared_transactions« auf einen Wert höher als null. msgid "transaction identifier \"%s\" is already in use" msgstr "Transaktionsbezeichner »%s« wird bereits verwendet" -#: access/transam/twophase.c:404 access/transam/twophase.c:2530 +#: access/transam/twophase.c:404 access/transam/twophase.c:2531 #, c-format msgid "maximum number of prepared transactions reached" msgstr "maximale Anzahl vorbereiteter Transaktionen erreicht" -#: access/transam/twophase.c:405 access/transam/twophase.c:2531 +#: access/transam/twophase.c:405 access/transam/twophase.c:2532 #, c-format msgid "Increase \"max_prepared_transactions\" (currently %d)." msgstr "Erhöhen Sie »max_prepared_transactions« (aktuell %d)." @@ -2202,123 +2202,123 @@ msgstr "Verbinden Sie sich mit der Datenbank, wo die Transaktion vorbereitet wur msgid "prepared transaction with identifier \"%s\" does not exist" msgstr "vorbereitete Transaktion mit Bezeichner »%s« existiert nicht" -#: access/transam/twophase.c:1174 +#: access/transam/twophase.c:1175 #, c-format msgid "two-phase state file maximum length exceeded" msgstr "maximale Länge der Zweiphasen-Statusdatei überschritten" -#: access/transam/twophase.c:1329 +#: access/transam/twophase.c:1330 #, c-format msgid "incorrect size of file \"%s\": %lld byte" msgid_plural "incorrect size of file \"%s\": %lld bytes" msgstr[0] "falsche Größe von Datei »%s«: %lld Byte" msgstr[1] "falsche Größe von Datei »%s«: %lld Bytes" -#: access/transam/twophase.c:1338 +#: access/transam/twophase.c:1339 #, c-format msgid "incorrect alignment of CRC offset for file \"%s\"" msgstr "falsche Ausrichtung des CRC-Offsets für Datei »%s«" -#: access/transam/twophase.c:1356 +#: access/transam/twophase.c:1357 #, c-format msgid "could not read file \"%s\": read %d of %lld" msgstr "konnte Datei »%s« nicht lesen: %d von %lld gelesen" -#: access/transam/twophase.c:1371 +#: access/transam/twophase.c:1372 #, c-format msgid "invalid magic number stored in file \"%s\"" msgstr "ungültige magische Zahl in Datei »%s gespeichert«" -#: access/transam/twophase.c:1377 +#: access/transam/twophase.c:1378 #, c-format msgid "invalid size stored in file \"%s\"" msgstr "ungültige Größe in Datei »%s« gespeichert" -#: access/transam/twophase.c:1389 +#: access/transam/twophase.c:1390 #, c-format msgid "calculated CRC checksum does not match value stored in file \"%s\"" msgstr "berechnete CRC-Prüfsumme stimmt nicht mit dem Wert in Datei »%s« überein" -#: access/transam/twophase.c:1419 access/transam/xlogrecovery.c:572 -#: postmaster/walsummarizer.c:939 replication/logical/logical.c:213 +#: access/transam/twophase.c:1420 access/transam/xlogrecovery.c:572 +#: postmaster/walsummarizer.c:940 replication/logical/logical.c:213 #: replication/walsender.c:826 #, c-format msgid "Failed while allocating a WAL reading processor." msgstr "Fehlgeschlagen beim Anlegen eines WAL-Leseprozessors." -#: access/transam/twophase.c:1429 +#: access/transam/twophase.c:1430 #, c-format msgid "could not read two-phase state from WAL at %X/%X: %s" msgstr "konnte Zweiphasen-Status nicht aus dem WAL bei %X/%X lesen: %s" -#: access/transam/twophase.c:1434 +#: access/transam/twophase.c:1435 #, c-format msgid "could not read two-phase state from WAL at %X/%X" msgstr "konnte Zweiphasen-Status nicht aus dem WAL bei %X/%X lesen" -#: access/transam/twophase.c:1442 +#: access/transam/twophase.c:1443 #, c-format msgid "expected two-phase state data is not present in WAL at %X/%X" msgstr "erwartete Zweiphasen-Status-Daten sind nicht im WAL bei %X/%X vorhanden" -#: access/transam/twophase.c:1744 +#: access/transam/twophase.c:1745 #, c-format msgid "could not recreate file \"%s\": %m" msgstr "konnte Datei »%s« nicht neu erzeugen: %m" -#: access/transam/twophase.c:1871 +#: access/transam/twophase.c:1872 #, c-format msgid "%u two-phase state file was written for a long-running prepared transaction" msgid_plural "%u two-phase state files were written for long-running prepared transactions" msgstr[0] "%u Zweiphasen-Statusdatei wurde für eine lange laufende vorbereitete Transaktion geschrieben" msgstr[1] "%u Zweiphasen-Statusdateien wurden für lange laufende vorbereitete Transaktionen geschrieben" -#: access/transam/twophase.c:2106 +#: access/transam/twophase.c:2107 #, c-format msgid "recovering prepared transaction %u from shared memory" msgstr "Wiederherstellung der vorbereiteten Transaktion %u aus dem Shared Memory" -#: access/transam/twophase.c:2199 +#: access/transam/twophase.c:2200 #, c-format msgid "removing stale two-phase state file for transaction %u" msgstr "entferne abgelaufene Zweiphasen-Statusdatei für Transaktion %u" -#: access/transam/twophase.c:2206 +#: access/transam/twophase.c:2207 #, c-format msgid "removing stale two-phase state from memory for transaction %u" msgstr "entferne abgelaufenen Zweiphasen-Status aus dem Speicher für Transaktion %u" -#: access/transam/twophase.c:2219 +#: access/transam/twophase.c:2220 #, c-format msgid "removing future two-phase state file for transaction %u" msgstr "entferne zukünftige Zweiphasen-Statusdatei für Transaktion %u" -#: access/transam/twophase.c:2226 +#: access/transam/twophase.c:2227 #, c-format msgid "removing future two-phase state from memory for transaction %u" msgstr "entferne zukünftigen Zweiphasen-Status aus dem Speicher für Transaktion %u" -#: access/transam/twophase.c:2251 +#: access/transam/twophase.c:2252 #, c-format msgid "corrupted two-phase state file for transaction %u" msgstr "verfälschte Zweiphasen-Statusdatei für Transaktion %u" -#: access/transam/twophase.c:2256 +#: access/transam/twophase.c:2257 #, c-format msgid "corrupted two-phase state in memory for transaction %u" msgstr "verfälschter Zweiphasen-Status im Speicher für Transaktion %u" -#: access/transam/twophase.c:2513 +#: access/transam/twophase.c:2514 #, c-format msgid "could not recover two-phase state file for transaction %u" msgstr "konnte Zweiphasen-Statusdatei für Transaktion %u nicht wiederherstellen" -#: access/transam/twophase.c:2515 +#: access/transam/twophase.c:2516 #, c-format msgid "Two-phase state file has been found in WAL record %X/%X, but this transaction has already been restored from disk." msgstr "Zweiphasen-Statusdatei wurde in WAL-Eintrag %X/%X gefunden, aber diese Transaktion wurde schon von der Festplatte wiederhergestellt." -#: access/transam/twophase.c:2523 storage/file/fd.c:514 utils/fmgr/dfmgr.c:214 +#: access/transam/twophase.c:2524 storage/file/fd.c:514 utils/fmgr/dfmgr.c:214 #, c-format msgid "could not access file \"%s\": %m" msgstr "konnte nicht auf Datei »%s« zugreifen: %m" @@ -2497,7 +2497,7 @@ msgid "could not write to log file \"%s\" at offset %u, length %zu: %m" msgstr "konnte nicht in Logdatei »%s« bei Position %u, Länge %zu schreiben: %m" #: access/transam/xlog.c:3740 access/transam/xlogutils.c:820 -#: replication/walsender.c:3088 +#: replication/walsender.c:3097 #, c-format msgid "requested WAL segment %s has already been removed" msgstr "das angeforderte WAL-Segment %s wurde schon entfernt" @@ -2616,13 +2616,13 @@ msgstr "»%s« muss mindestens zweimal so groß wie »%s« sein" #: access/transam/xlog.c:4725 catalog/namespace.c:4699 #: commands/tablespace.c:1210 commands/user.c:2531 commands/variable.c:72 -#: replication/slot.c:2768 tcop/postgres.c:3626 utils/error/elog.c:2257 +#: replication/slot.c:2768 tcop/postgres.c:3630 utils/error/elog.c:2257 #, c-format msgid "List syntax is invalid." msgstr "Die Listensyntax ist ungültig." #: access/transam/xlog.c:4771 commands/user.c:2547 commands/variable.c:173 -#: tcop/postgres.c:3642 utils/error/elog.c:2283 +#: tcop/postgres.c:3646 utils/error/elog.c:2283 #, c-format msgid "Unrecognized key word: \"%s\"." msgstr "Unbekanntes Schlüsselwort: »%s«." @@ -3645,11 +3645,11 @@ msgstr "Sie können den Server neu starten, nachdem die nötigen Konfigurations #: access/transam/xlogrecovery.c:4793 access/transam/xlogrecovery.c:4795 #: catalog/dependency.c:1153 catalog/dependency.c:1160 -#: catalog/dependency.c:1171 commands/tablecmds.c:1519 -#: commands/tablecmds.c:16740 commands/tablespace.c:460 commands/user.c:1302 -#: commands/vacuum.c:226 commands/view.c:441 executor/execExprInterp.c:5211 -#: executor/execExprInterp.c:5219 libpq/auth.c:320 -#: replication/logical/applyparallelworker.c:1048 replication/slot.c:1705 +#: catalog/dependency.c:1171 commands/tablecmds.c:1529 +#: commands/tablecmds.c:16752 commands/tablespace.c:460 commands/user.c:1302 +#: commands/vacuum.c:226 commands/view.c:441 executor/execExprInterp.c:5282 +#: executor/execExprInterp.c:5290 libpq/auth.c:320 +#: replication/logical/applyparallelworker.c:1057 replication/slot.c:1705 #: replication/slot.c:2783 replication/slot.c:2785 replication/syncrep.c:1079 #: storage/aio/method_io_uring.c:389 storage/lmgr/deadlock.c:1137 #: storage/lmgr/proc.c:1525 utils/misc/guc.c:3166 utils/misc/guc.c:3207 @@ -3710,7 +3710,7 @@ msgstr "Der fehlgeschlagene Archivbefehl war: %s" msgid "archive command was terminated by exception 0x%X" msgstr "Archivbefehl wurde durch Ausnahme 0x%X beendet" -#: archive/shell_archive.c:109 postmaster/postmaster.c:2850 +#: archive/shell_archive.c:109 postmaster/postmaster.c:2832 #, c-format msgid "See C include file \"ntstatus.h\" for a description of the hexadecimal value." msgstr "Sehen Sie die Beschreibung des Hexadezimalwerts in der C-Include-Datei »ntstatus.h« nach." @@ -4040,23 +4040,23 @@ msgstr "konnte Long-Distance-Modus nicht einschalten: %s" msgid "invalid timeline %" msgstr "ungültige Zeitleiste %" -#: bootstrap/bootstrap.c:239 postmaster/postmaster.c:626 tcop/postgres.c:3858 +#: bootstrap/bootstrap.c:239 postmaster/postmaster.c:627 tcop/postgres.c:3862 #, c-format msgid "--%s must be first argument" msgstr "--%s muss erstes Argument sein" -#: bootstrap/bootstrap.c:253 postmaster/postmaster.c:640 tcop/postgres.c:3872 +#: bootstrap/bootstrap.c:253 postmaster/postmaster.c:641 tcop/postgres.c:3876 #, c-format msgid "--%s requires a value" msgstr "--%s benötigt einen Wert" -#: bootstrap/bootstrap.c:258 postmaster/postmaster.c:645 tcop/postgres.c:3877 +#: bootstrap/bootstrap.c:258 postmaster/postmaster.c:646 tcop/postgres.c:3881 #, c-format msgid "-c %s requires a value" msgstr "-c %s benötigt einen Wert" -#: bootstrap/bootstrap.c:296 postmaster/postmaster.c:763 -#: postmaster/postmaster.c:776 +#: bootstrap/bootstrap.c:296 postmaster/postmaster.c:764 +#: postmaster/postmaster.c:777 #, c-format msgid "Try \"%s --help\" for more information.\n" msgstr "Versuchen Sie »%s --help« für weitere Informationen.\n" @@ -4211,21 +4211,21 @@ msgstr "keine Berechtigung, um Vorgabeprivilegien zu ändern" msgid "cannot use IN SCHEMA clause when using %s" msgstr "Klausel IN SCHEMA kann nicht verwendet werden, wenn %s verwendet wird" -#: catalog/aclchk.c:1577 catalog/catalog.c:684 catalog/heap.c:2621 -#: catalog/heap.c:2941 catalog/objectaddress.c:1528 -#: catalog/pg_publication.c:570 commands/analyze.c:388 commands/copy.c:1039 -#: commands/sequence.c:1655 commands/tablecmds.c:7751 commands/tablecmds.c:7929 -#: commands/tablecmds.c:8130 commands/tablecmds.c:8259 -#: commands/tablecmds.c:8413 commands/tablecmds.c:8507 -#: commands/tablecmds.c:8610 commands/tablecmds.c:8776 -#: commands/tablecmds.c:8806 commands/tablecmds.c:8961 -#: commands/tablecmds.c:9064 commands/tablecmds.c:9198 -#: commands/tablecmds.c:9311 commands/tablecmds.c:14397 -#: commands/tablecmds.c:14600 commands/tablecmds.c:14761 -#: commands/tablecmds.c:15989 commands/tablecmds.c:18756 commands/trigger.c:948 -#: parser/analyze.c:2575 parser/parse_relation.c:749 parser/parse_target.c:1070 -#: parser/parse_type.c:144 parser/parse_utilcmd.c:3662 -#: parser/parse_utilcmd.c:3702 parser/parse_utilcmd.c:3744 +#: catalog/aclchk.c:1577 catalog/catalog.c:684 catalog/heap.c:2635 +#: catalog/heap.c:2957 catalog/objectaddress.c:1528 +#: catalog/pg_publication.c:570 commands/analyze.c:388 commands/copy.c:1040 +#: commands/sequence.c:1655 commands/tablecmds.c:7761 commands/tablecmds.c:7939 +#: commands/tablecmds.c:8140 commands/tablecmds.c:8269 +#: commands/tablecmds.c:8423 commands/tablecmds.c:8517 +#: commands/tablecmds.c:8620 commands/tablecmds.c:8786 +#: commands/tablecmds.c:8816 commands/tablecmds.c:8971 +#: commands/tablecmds.c:9074 commands/tablecmds.c:9208 +#: commands/tablecmds.c:9321 commands/tablecmds.c:14409 +#: commands/tablecmds.c:14612 commands/tablecmds.c:14773 +#: commands/tablecmds.c:16001 commands/tablecmds.c:18768 commands/trigger.c:948 +#: parser/analyze.c:2591 parser/parse_relation.c:749 parser/parse_target.c:1070 +#: parser/parse_type.c:144 parser/parse_utilcmd.c:3671 +#: parser/parse_utilcmd.c:3711 parser/parse_utilcmd.c:3753 #: statistics/attribute_stats.c:212 statistics/attribute_stats.c:955 #: utils/adt/acl.c:2938 utils/adt/ruleutils.c:2858 #, c-format @@ -4237,13 +4237,13 @@ msgstr "Spalte »%s« von Relation »%s« existiert nicht" msgid "\"%s\" is an index" msgstr "»%s« ist ein Index" -#: catalog/aclchk.c:1829 commands/tablecmds.c:16146 commands/tablecmds.c:19675 +#: catalog/aclchk.c:1829 commands/tablecmds.c:16158 commands/tablecmds.c:19687 #, c-format msgid "\"%s\" is a composite type" msgstr "»%s« ist ein zusammengesetzter Typ" #: catalog/aclchk.c:1837 catalog/objectaddress.c:1368 commands/tablecmds.c:266 -#: commands/tablecmds.c:19639 utils/adt/acl.c:2122 utils/adt/acl.c:2152 +#: commands/tablecmds.c:19651 utils/adt/acl.c:2122 utils/adt/acl.c:2152 #: utils/adt/acl.c:2185 utils/adt/acl.c:2221 utils/adt/acl.c:2252 #: utils/adt/acl.c:2283 #, c-format @@ -4704,7 +4704,7 @@ msgstr "nur Superuser können %s() aufrufen" msgid "pg_nextoid() can only be used on system catalogs" msgstr "pg_nextoid() kann nur mit Systemkatalogen verwendet werden" -#: catalog/catalog.c:676 parser/parse_utilcmd.c:2447 +#: catalog/catalog.c:676 parser/parse_utilcmd.c:2451 #, c-format msgid "index \"%s\" does not belong to table \"%s\"" msgstr "Index »%s« gehört nicht zu Tabelle »%s«" @@ -4808,13 +4808,13 @@ msgstr "keine Berechtigung, um »%s.%s« zu erzeugen" msgid "System catalog modifications are currently disallowed." msgstr "Änderungen an Systemkatalogen sind gegenwärtig nicht erlaubt." -#: catalog/heap.c:463 commands/tablecmds.c:2562 commands/tablecmds.c:3014 -#: commands/tablecmds.c:7361 +#: catalog/heap.c:463 commands/tablecmds.c:2572 commands/tablecmds.c:3024 +#: commands/tablecmds.c:7371 #, c-format msgid "tables can have at most %d columns" msgstr "Tabellen können höchstens %d Spalten haben" -#: catalog/heap.c:481 commands/tablecmds.c:7663 +#: catalog/heap.c:481 commands/tablecmds.c:7673 #, c-format msgid "column name \"%s\" conflicts with a system column name" msgstr "Spaltenname »%s« steht im Konflikt mit dem Namen einer Systemspalte" @@ -4825,54 +4825,54 @@ msgid "column name \"%s\" specified more than once" msgstr "Spaltenname »%s« mehrmals angegeben" #. translator: first %s is an integer not a name -#: catalog/heap.c:575 +#: catalog/heap.c:579 #, c-format msgid "partition key column %s has pseudo-type %s" msgstr "Partitionierungsschlüsselspalte %s hat Pseudotyp %s" -#: catalog/heap.c:580 +#: catalog/heap.c:584 #, c-format msgid "column \"%s\" has pseudo-type %s" msgstr "Spalte »%s« hat Pseudotyp %s" -#: catalog/heap.c:595 +#: catalog/heap.c:599 #, c-format msgid "virtual generated column \"%s\" cannot have a domain type" msgstr "virtuelle generierte Spalte »%s« kann keinen Domänentyp haben" -#: catalog/heap.c:622 +#: catalog/heap.c:626 #, c-format msgid "composite type %s cannot be made a member of itself" msgstr "zusammengesetzter Typ %s kann nicht Teil von sich selbst werden" -#: catalog/heap.c:673 +#: catalog/heap.c:687 #, c-format msgid "virtual generated column \"%s\" cannot have a user-defined type" msgstr "virtuelle generierte Spalte »%s« kann keinen benutzerdefinierten Typ haben" -#: catalog/heap.c:674 catalog/heap.c:3295 +#: catalog/heap.c:688 catalog/heap.c:3311 #, c-format msgid "Virtual generated columns that make use of user-defined types are not yet supported." msgstr "Virtuelle generierte Spalten, die benutzerdefinierte Typen verwenden, werden noch nicht unterstützt." #. translator: first %s is an integer not a name -#: catalog/heap.c:686 +#: catalog/heap.c:700 #, c-format msgid "no collation was derived for partition key column %s with collatable type %s" msgstr "für Partitionierungsschlüsselspalte %s mit sortierbarem Typ %s wurde keine Sortierfolge abgeleitet" -#: catalog/heap.c:692 commands/createas.c:200 commands/createas.c:512 +#: catalog/heap.c:706 commands/createas.c:200 commands/createas.c:512 #, c-format msgid "no collation was derived for column \"%s\" with collatable type %s" msgstr "für Spalte »%s« mit sortierbarem Typ %s wurde keine Sortierfolge abgeleitet" -#: catalog/heap.c:1179 catalog/index.c:901 commands/createas.c:408 -#: commands/tablecmds.c:4296 +#: catalog/heap.c:1193 catalog/index.c:901 commands/createas.c:408 +#: commands/tablecmds.c:4306 #, c-format msgid "relation \"%s\" already exists" msgstr "Relation »%s« existiert bereits" -#: catalog/heap.c:1195 catalog/pg_type.c:434 catalog/pg_type.c:805 +#: catalog/heap.c:1209 catalog/pg_type.c:434 catalog/pg_type.c:805 #: catalog/pg_type.c:977 commands/typecmds.c:253 commands/typecmds.c:265 #: commands/typecmds.c:758 commands/typecmds.c:1213 commands/typecmds.c:1439 #: commands/typecmds.c:1619 commands/typecmds.c:2594 @@ -4880,183 +4880,183 @@ msgstr "Relation »%s« existiert bereits" msgid "type \"%s\" already exists" msgstr "Typ »%s« existiert bereits" -#: catalog/heap.c:1196 +#: catalog/heap.c:1210 #, c-format msgid "A relation has an associated type of the same name, so you must use a name that doesn't conflict with any existing type." msgstr "Eine Relation hat einen zugehörigen Typ mit dem selben Namen, daher müssen Sie einen Namen wählen, der nicht mit einem bestehenden Typ kollidiert." -#: catalog/heap.c:1236 +#: catalog/heap.c:1250 #, c-format msgid "toast relfilenumber value not set when in binary upgrade mode" msgstr "TOAST-Relfile-Nummer-Wert ist im Binary-Upgrade-Modus nicht gesetzt" -#: catalog/heap.c:1247 +#: catalog/heap.c:1261 #, c-format msgid "pg_class heap OID value not set when in binary upgrade mode" msgstr "Heap-OID-Wert für pg_class ist im Binary-Upgrade-Modus nicht gesetzt" -#: catalog/heap.c:1257 +#: catalog/heap.c:1271 #, c-format msgid "relfilenumber value not set when in binary upgrade mode" msgstr "Relfile-Nummer-Wert ist im Binary-Upgrade-Modus nicht gesetzt" -#: catalog/heap.c:2202 +#: catalog/heap.c:2216 #, c-format msgid "cannot add NO INHERIT constraint to partitioned table \"%s\"" msgstr "zur partitionierten Tabelle »%s« kann kein NO-INHERIT-Constraint hinzugefügt werden" -#: catalog/heap.c:2525 +#: catalog/heap.c:2539 #, c-format msgid "check constraint \"%s\" already exists" msgstr "Check-Constraint »%s« existiert bereits" -#: catalog/heap.c:2626 catalog/heap.c:2947 +#: catalog/heap.c:2640 catalog/heap.c:2963 #, c-format msgid "cannot add not-null constraint on system column \"%s\"" msgstr "zur Systemspalte »%s« kann kein Not-Null-Constraint hinzugefügt werden" -#: catalog/heap.c:2654 catalog/heap.c:2780 catalog/heap.c:3031 -#: catalog/index.c:915 catalog/pg_constraint.c:1025 commands/tablecmds.c:9821 +#: catalog/heap.c:2668 catalog/heap.c:2794 catalog/heap.c:3047 +#: catalog/index.c:915 catalog/pg_constraint.c:1025 commands/tablecmds.c:9831 #, c-format msgid "constraint \"%s\" for relation \"%s\" already exists" msgstr "Constraint »%s« existiert bereits für Relation »%s«" -#: catalog/heap.c:2787 +#: catalog/heap.c:2801 #, c-format msgid "constraint \"%s\" conflicts with non-inherited constraint on relation \"%s\"" msgstr "Constraint »%s« kollidiert mit nicht vererbtem Constraint für Relation »%s«" -#: catalog/heap.c:2798 +#: catalog/heap.c:2812 #, c-format msgid "constraint \"%s\" conflicts with inherited constraint on relation \"%s\"" msgstr "Constraint »%s« kollidiert mit vererbtem Constraint für Relation »%s«" -#: catalog/heap.c:2808 +#: catalog/heap.c:2822 #, c-format msgid "constraint \"%s\" conflicts with NOT VALID constraint on relation \"%s\"" msgstr "Constraint »%s« kollidiert mit NOT-VALID-Constraint für Relation »%s«" -#: catalog/heap.c:2820 +#: catalog/heap.c:2834 #, c-format msgid "constraint \"%s\" conflicts with NOT ENFORCED constraint on relation \"%s\"" msgstr "Constraint »%s« kollidiert mit NOT-ENFORCED-Constraint für Relation »%s«" -#: catalog/heap.c:2825 +#: catalog/heap.c:2839 #, c-format msgid "merging constraint \"%s\" with inherited definition" msgstr "Constraint »%s« wird mit geerbter Definition zusammengeführt" -#: catalog/heap.c:2849 catalog/pg_constraint.c:803 catalog/pg_constraint.c:1154 -#: commands/tablecmds.c:3179 commands/tablecmds.c:3499 -#: commands/tablecmds.c:7286 commands/tablecmds.c:7967 -#: commands/tablecmds.c:17583 commands/tablecmds.c:17765 +#: catalog/heap.c:2863 catalog/pg_constraint.c:803 catalog/pg_constraint.c:1154 +#: commands/tablecmds.c:3189 commands/tablecmds.c:3509 +#: commands/tablecmds.c:7296 commands/tablecmds.c:7977 +#: commands/tablecmds.c:17595 commands/tablecmds.c:17777 #, c-format msgid "too many inheritance parents" msgstr "zu viele Elterntabellen" -#: catalog/heap.c:2966 parser/parse_utilcmd.c:2655 +#: catalog/heap.c:2982 parser/parse_utilcmd.c:2659 #, c-format msgid "conflicting NO INHERIT declaration for not-null constraint on column \"%s\"" msgstr "widersprüchliche NO INHERIT-Deklaration für Not-Null-Constraint für Spalte »%s«" -#: catalog/heap.c:2980 +#: catalog/heap.c:2996 #, c-format msgid "conflicting not-null constraint names \"%s\" and \"%s\"" msgstr "widersprüchliche Not-Null-Constraint-Namen »%s« und »%s«" -#: catalog/heap.c:3010 +#: catalog/heap.c:3026 #, c-format msgid "cannot define not-null constraint with NO INHERIT on column \"%s\"" msgstr "kann keinen Not-Null-Constraint mit NO INHERIT für Spalte »%s« definieren" -#: catalog/heap.c:3012 +#: catalog/heap.c:3028 #, c-format msgid "The column has an inherited not-null constraint." msgstr "Die Spalte hat einen geerbten Not-Null-Constraint." -#: catalog/heap.c:3202 +#: catalog/heap.c:3218 #, c-format msgid "cannot use generated column \"%s\" in column generation expression" msgstr "generierte Spalte »%s« kann nicht im Spaltengenerierungsausdruck verwendet werden" -#: catalog/heap.c:3204 +#: catalog/heap.c:3220 #, c-format msgid "A generated column cannot reference another generated column." msgstr "Eine generierte Spalte kann nicht auf eine andere generierte Spalte verweisen." -#: catalog/heap.c:3210 +#: catalog/heap.c:3226 #, c-format msgid "cannot use whole-row variable in column generation expression" msgstr "Variable mit Verweis auf die ganze Zeile kann nicht im Spaltengenerierungsausdruck verwendet werden" -#: catalog/heap.c:3211 +#: catalog/heap.c:3227 #, c-format msgid "This would cause the generated column to depend on its own value." msgstr "Dadurch würde die generierte Spalte von ihrem eigenen Wert abhängen." -#: catalog/heap.c:3278 +#: catalog/heap.c:3294 #, c-format msgid "generation expression uses user-defined function" msgstr "Generierungsausdruck verwendet benutzerdefinierte Funktion" -#: catalog/heap.c:3279 +#: catalog/heap.c:3295 #, c-format msgid "Virtual generated columns that make use of user-defined functions are not yet supported." msgstr "Virtuelle generierte Spalten, die benutzerdefinierte Funktionen verwenden, werden noch nicht unterstützt." -#: catalog/heap.c:3294 +#: catalog/heap.c:3310 #, c-format msgid "generation expression uses user-defined type" msgstr "Generierungsausdruck verwendet benutzerdefinierten Typ" -#: catalog/heap.c:3346 +#: catalog/heap.c:3362 #, c-format msgid "generation expression is not immutable" msgstr "Generierungsausdruck ist nicht »immutable«" -#: catalog/heap.c:3378 rewrite/rewriteHandler.c:1288 +#: catalog/heap.c:3394 rewrite/rewriteHandler.c:1321 #, c-format msgid "column \"%s\" is of type %s but default expression is of type %s" msgstr "Spalte »%s« hat Typ %s, aber der Vorgabeausdruck hat Typ %s" -#: catalog/heap.c:3383 commands/prepare.c:334 parser/analyze.c:2906 +#: catalog/heap.c:3399 commands/prepare.c:334 parser/analyze.c:2922 #: parser/parse_target.c:595 parser/parse_target.c:885 -#: parser/parse_target.c:895 rewrite/rewriteHandler.c:1293 +#: parser/parse_target.c:895 rewrite/rewriteHandler.c:1326 #, c-format msgid "You will need to rewrite or cast the expression." msgstr "Sie müssen den Ausdruck umschreiben oder eine Typumwandlung vornehmen." -#: catalog/heap.c:3430 +#: catalog/heap.c:3446 #, c-format msgid "only table \"%s\" can be referenced in check constraint" msgstr "nur Verweise auf Tabelle »%s« sind im Check-Constraint zugelassen" -#: catalog/heap.c:3736 +#: catalog/heap.c:3752 #, c-format msgid "unsupported ON COMMIT and foreign key combination" msgstr "nicht unterstützte Kombination aus ON COMMIT und Fremdschlüssel" -#: catalog/heap.c:3737 +#: catalog/heap.c:3753 #, c-format msgid "Table \"%s\" references \"%s\", but they do not have the same ON COMMIT setting." msgstr "Tabelle »%s« verweist auf »%s«, aber sie haben nicht die gleiche ON-COMMIT-Einstellung." -#: catalog/heap.c:3742 +#: catalog/heap.c:3758 #, c-format msgid "cannot truncate a table referenced in a foreign key constraint" msgstr "kann eine Tabelle, die in einen Fremdschlüssel-Constraint eingebunden ist, nicht leeren" -#: catalog/heap.c:3743 +#: catalog/heap.c:3759 #, c-format msgid "Table \"%s\" references \"%s\"." msgstr "Tabelle »%s« verweist auf »%s«." -#: catalog/heap.c:3745 +#: catalog/heap.c:3761 #, c-format msgid "Truncate table \"%s\" at the same time, or use TRUNCATE ... CASCADE." msgstr "Leeren Sie die Tabelle »%s« gleichzeitig oder verwenden Sie TRUNCATE ... CASCADE." -#: catalog/index.c:220 parser/parse_utilcmd.c:2352 +#: catalog/index.c:220 parser/parse_utilcmd.c:2356 #, c-format msgid "multiple primary keys for table \"%s\" are not allowed" msgstr "mehrere Primärschlüssel für Tabelle »%s« nicht erlaubt" @@ -5127,13 +5127,13 @@ msgstr "DROP INDEX CONCURRENTLY muss die erste Aktion in einer Transaktion sein" msgid "cannot reindex temporary tables of other sessions" msgstr "kann temporäre Tabellen anderer Sitzungen nicht reindizieren" -#: catalog/index.c:3740 commands/indexcmds.c:3791 +#: catalog/index.c:3740 commands/indexcmds.c:3793 #, c-format msgid "cannot reindex invalid index on TOAST table" msgstr "ungültiger Index einer TOAST-Tabelle kann nicht reindiziert werden" -#: catalog/index.c:3756 commands/indexcmds.c:3669 commands/indexcmds.c:3815 -#: commands/tablecmds.c:3703 +#: catalog/index.c:3756 commands/indexcmds.c:3671 commands/indexcmds.c:3817 +#: commands/tablecmds.c:3713 #, c-format msgid "cannot move system relation \"%s\"" msgstr "Systemrelation »%s« kann nicht verschoben werden" @@ -5249,7 +5249,7 @@ msgid "cannot move objects into or out of TOAST schema" msgstr "Objekte können nicht in oder aus TOAST-Schemas verschoben werden" #: catalog/namespace.c:3547 commands/schemacmds.c:264 commands/schemacmds.c:344 -#: commands/tablecmds.c:1464 utils/adt/regproc.c:1688 +#: commands/tablecmds.c:1474 utils/adt/regproc.c:1688 #, c-format msgid "schema \"%s\" does not exist" msgstr "Schema »%s« existiert nicht" @@ -5285,26 +5285,26 @@ msgid "cannot create temporary tables during a parallel operation" msgstr "während einer parallelen Operation können keine temporären Tabellen erzeugt werden" #: catalog/objectaddress.c:1376 commands/policy.c:93 commands/policy.c:373 -#: commands/tablecmds.c:260 commands/tablecmds.c:302 commands/tablecmds.c:2387 -#: commands/tablecmds.c:14535 +#: commands/tablecmds.c:260 commands/tablecmds.c:302 commands/tablecmds.c:2397 +#: commands/tablecmds.c:14547 #, c-format msgid "\"%s\" is not a table" msgstr "»%s« ist keine Tabelle" #: catalog/objectaddress.c:1383 commands/tablecmds.c:272 -#: commands/tablecmds.c:19644 commands/view.c:113 +#: commands/tablecmds.c:19656 commands/view.c:113 #, c-format msgid "\"%s\" is not a view" msgstr "»%s« ist keine Sicht" #: catalog/objectaddress.c:1390 commands/matview.c:201 commands/tablecmds.c:278 -#: commands/tablecmds.c:19649 +#: commands/tablecmds.c:19661 #, c-format msgid "\"%s\" is not a materialized view" msgstr "»%s« ist keine materialisierte Sicht" #: catalog/objectaddress.c:1397 commands/tablecmds.c:296 -#: commands/tablecmds.c:19654 +#: commands/tablecmds.c:19666 #, c-format msgid "\"%s\" is not a foreign table" msgstr "»%s« ist keine Fremdtabelle" @@ -5353,7 +5353,7 @@ msgid "user mapping for user \"%s\" on server \"%s\" does not exist" msgstr "Benutzerabbildung für Benutzer »%s« auf Server »%s« existiert nicht" #: catalog/objectaddress.c:1839 commands/foreigncmds.c:441 -#: commands/foreigncmds.c:1004 commands/foreigncmds.c:1367 +#: commands/foreigncmds.c:1009 commands/foreigncmds.c:1372 #: foreign/foreign.c:714 #, c-format msgid "server \"%s\" does not exist" @@ -5820,7 +5820,7 @@ msgstr "Anfangswert darf nicht ausgelassen werden, wenn Übergangsfunktion strik msgid "return type of inverse transition function %s is not %s" msgstr "Rückgabetyp der inversen Übergangsfunktion %s ist nicht %s" -#: catalog/pg_aggregate.c:352 executor/nodeWindowAgg.c:3057 +#: catalog/pg_aggregate.c:352 executor/nodeWindowAgg.c:3105 #, c-format msgid "strictness of aggregate's forward and inverse transition functions must match" msgstr "Striktheit der vorwärtigen und inversen Übergangsfunktionen einer Aggregatfunktion müssen übereinstimmen" @@ -5996,23 +5996,23 @@ msgstr "Sortierfolge »%s« existiert bereits" msgid "collation \"%s\" for encoding \"%s\" already exists" msgstr "Sortierfolge »%s« für Kodierung »%s« existiert bereits" -#: catalog/pg_constraint.c:764 commands/tablecmds.c:7952 +#: catalog/pg_constraint.c:764 commands/tablecmds.c:7962 #, c-format msgid "cannot change NO INHERIT status of NOT NULL constraint \"%s\" on relation \"%s\"" msgstr "NO INHERIT-Status von NOT-NULL-Constraint »%s« von Relation »%s« kann nicht geändert werden" -#: catalog/pg_constraint.c:766 commands/tablecmds.c:9584 +#: catalog/pg_constraint.c:766 commands/tablecmds.c:9594 #, c-format msgid "You might need to make the existing constraint inheritable using %s." msgstr "Sie müssen möglicherweise den bestehenden Constraint mit %s vererbbar machen." -#: catalog/pg_constraint.c:776 commands/tablecmds.c:8301 +#: catalog/pg_constraint.c:776 commands/tablecmds.c:8311 #, c-format msgid "incompatible NOT VALID constraint \"%s\" on relation \"%s\"" msgstr "inkompatibler NOT-VALID-Constraint »%s« für Relation »%s«" -#: catalog/pg_constraint.c:778 commands/tablecmds.c:8303 -#: commands/tablecmds.c:9596 +#: catalog/pg_constraint.c:778 commands/tablecmds.c:8313 +#: commands/tablecmds.c:9606 #, c-format msgid "You might need to validate it using %s." msgstr "Sie müssen ihn möglicherweise mit %s validieren." @@ -6132,8 +6132,8 @@ msgstr "Partition »%s« kann nicht abgetrennt werden" msgid "The partition is being detached concurrently or has an unfinished detach." msgstr "Die Partition wird nebenläufig abgetrennt oder hat eine unfertige Abtrennoperation." -#: catalog/pg_inherits.c:595 commands/tablecmds.c:4916 -#: commands/tablecmds.c:17891 +#: catalog/pg_inherits.c:595 commands/tablecmds.c:4926 +#: commands/tablecmds.c:17903 #, c-format msgid "Use ALTER TABLE ... DETACH PARTITION ... FINALIZE to complete the pending detach operation." msgstr "Verwendet Sie ALTER TABLE ... DETACH PARTITION ... FINALIZE, um die unerledigte Abtrennoperation abzuschließen." @@ -6628,7 +6628,7 @@ msgstr "Ereignistrigger »%s« existiert bereits" msgid "foreign-data wrapper \"%s\" already exists" msgstr "Fremddaten-Wrapper »%s« existiert bereits" -#: commands/alter.c:89 commands/foreigncmds.c:895 +#: commands/alter.c:89 commands/foreigncmds.c:900 #, c-format msgid "server \"%s\" already exists" msgstr "Server »%s« existiert bereits" @@ -6826,7 +6826,7 @@ msgid "The NOTIFY queue cannot be emptied until that process ends its current tr msgstr "Die NOTIFY-Schlange kann erst geleert werden, wenn dieser Prozess seine aktuelle Transaktion beendet." #: commands/cluster.c:127 commands/dbcommands.c:2356 -#: commands/explain_state.c:165 commands/indexcmds.c:2846 commands/vacuum.c:234 +#: commands/explain_state.c:165 commands/indexcmds.c:2848 commands/vacuum.c:234 #: commands/vacuum.c:308 #, c-format msgid "unrecognized %s option \"%s\"" @@ -6842,7 +6842,7 @@ msgstr "kann temporäre Tabellen anderer Sitzungen nicht clustern" msgid "there is no previously clustered index for table \"%s\"" msgstr "es gibt keinen bereits geclusterten Index für Tabelle »%s«" -#: commands/cluster.c:190 commands/tablecmds.c:16447 commands/tablecmds.c:18513 +#: commands/cluster.c:190 commands/tablecmds.c:16459 commands/tablecmds.c:18525 #, c-format msgid "index \"%s\" for table \"%s\" does not exist" msgstr "Index »%s« für Tabelle »%s« existiert nicht" @@ -6857,7 +6857,7 @@ msgstr "globaler Katalog kann nicht geclustert werden" msgid "cannot vacuum temporary tables of other sessions" msgstr "temporäre Tabellen anderer Sitzungen können nicht gevacuumt werden" -#: commands/cluster.c:507 commands/tablecmds.c:18523 +#: commands/cluster.c:507 commands/tablecmds.c:18535 #, c-format msgid "\"%s\" is not an index for table \"%s\"" msgstr "»%s« ist kein Index für Tabelle »%s«" @@ -6922,7 +6922,7 @@ msgid "collation attribute \"%s\" not recognized" msgstr "Attribut »%s« für Sortierfolge unbekannt" #: commands/collationcmds.c:123 commands/collationcmds.c:129 -#: commands/define.c:375 commands/tablecmds.c:8394 +#: commands/define.c:375 commands/tablecmds.c:8404 #: replication/pgoutput/pgoutput.c:321 replication/pgoutput/pgoutput.c:344 #: replication/pgoutput/pgoutput.c:362 replication/pgoutput/pgoutput.c:372 #: replication/pgoutput/pgoutput.c:382 replication/pgoutput/pgoutput.c:392 @@ -6998,9 +6998,9 @@ msgstr "Version der Standardsortierfolge kann nicht aufgefrischt werden" #. translator: %s is an SQL command #. translator: %s is an SQL ALTER command #: commands/collationcmds.c:443 commands/subscriptioncmds.c:1445 -#: commands/tablecmds.c:8146 commands/tablecmds.c:8156 -#: commands/tablecmds.c:8158 commands/tablecmds.c:16149 -#: commands/tablecmds.c:19677 commands/tablecmds.c:19698 +#: commands/tablecmds.c:8156 commands/tablecmds.c:8166 +#: commands/tablecmds.c:8168 commands/tablecmds.c:16161 +#: commands/tablecmds.c:19689 commands/tablecmds.c:19710 #: commands/typecmds.c:3786 commands/typecmds.c:3871 commands/typecmds.c:4225 #, c-format msgid "Use %s instead." @@ -7127,181 +7127,181 @@ msgstr "keine Berechtigung für COPY in eine Datei" msgid "Only roles with privileges of the \"%s\" role may COPY to a file." msgstr "Nur Rollen mit den Privilegien der Rolle »%s« können mit COPY in eine Datei schreiben." -#: commands/copy.c:182 +#: commands/copy.c:183 #, c-format msgid "generated columns are not supported in COPY FROM WHERE conditions" msgstr "generierte Spalten werden in COPY-FROM-WHERE-Bedingungen nicht unterstützt" -#: commands/copy.c:183 commands/tablecmds.c:14418 commands/tablecmds.c:19824 -#: commands/tablecmds.c:19906 commands/trigger.c:660 -#: rewrite/rewriteHandler.c:952 rewrite/rewriteHandler.c:987 +#: commands/copy.c:184 commands/tablecmds.c:14430 commands/tablecmds.c:19836 +#: commands/tablecmds.c:19918 commands/trigger.c:660 +#: rewrite/rewriteHandler.c:985 rewrite/rewriteHandler.c:1020 #, c-format msgid "Column \"%s\" is a generated column." msgstr "Spalte »%s« ist eine generierte Spalte." -#: commands/copy.c:232 +#: commands/copy.c:233 #, c-format msgid "COPY FROM not supported with row-level security" msgstr "COPY FROM wird nicht unterstützt mit Sicherheit auf Zeilenebene" -#: commands/copy.c:233 +#: commands/copy.c:234 #, c-format msgid "Use INSERT statements instead." msgstr "Verwenden Sie stattdessen INSERT-Anweisungen." -#: commands/copy.c:414 +#: commands/copy.c:415 #, c-format msgid "cannot use \"%s\" with HEADER in COPY TO" msgstr "»%s« kann nicht mit HEADER in COPY TO verwendet werden" -#: commands/copy.c:423 +#: commands/copy.c:424 #, c-format msgid "%s requires a Boolean value or \"match\"" msgstr "%s erfordert einen Boole’schen Wert oder »match«" #. translator: first %s is the name of a COPY option, e.g. ON_ERROR, #. second %s is a COPY with direction, e.g. COPY TO -#: commands/copy.c:441 commands/copy.c:857 commands/copy.c:873 -#: commands/copy.c:890 commands/copy.c:916 commands/copy.c:926 +#: commands/copy.c:442 commands/copy.c:858 commands/copy.c:874 +#: commands/copy.c:891 commands/copy.c:917 commands/copy.c:927 #, c-format msgid "COPY %s cannot be used with %s" msgstr "COPY %s kann nicht mit %s verwendet werden" #. translator: first %s is the name of a COPY option, e.g. ON_ERROR -#: commands/copy.c:455 commands/copy.c:513 +#: commands/copy.c:456 commands/copy.c:514 #, c-format msgid "COPY %s \"%s\" not recognized" msgstr "COPY %s »%s« nicht erkannt" -#: commands/copy.c:475 commands/define.c:73 commands/define.c:84 +#: commands/copy.c:476 commands/define.c:73 commands/define.c:84 #: commands/define.c:178 commands/define.c:196 commands/define.c:211 #: commands/define.c:229 #, c-format msgid "%s requires a numeric value" msgstr "%s erfordert einen numerischen Wert" -#: commands/copy.c:485 +#: commands/copy.c:486 #, c-format msgid "REJECT_LIMIT (%) must be greater than zero" msgstr "REJECT_LIMIT (%) muss größer als null sein" -#: commands/copy.c:575 +#: commands/copy.c:576 #, c-format msgid "COPY format \"%s\" not recognized" msgstr "COPY-Format »%s« nicht erkannt" -#: commands/copy.c:633 commands/copy.c:648 commands/copy.c:663 -#: commands/copy.c:682 +#: commands/copy.c:634 commands/copy.c:649 commands/copy.c:664 +#: commands/copy.c:683 #, c-format msgid "argument to option \"%s\" must be a list of column names" msgstr "Argument von Option »%s« muss eine Liste aus Spaltennamen sein" -#: commands/copy.c:694 +#: commands/copy.c:695 #, c-format msgid "argument to option \"%s\" must be a valid encoding name" msgstr "Argument von Option »%s« muss ein gültiger Kodierungsname sein" -#: commands/copy.c:722 commands/dbcommands.c:880 commands/dbcommands.c:2421 +#: commands/copy.c:723 commands/dbcommands.c:880 commands/dbcommands.c:2421 #, c-format msgid "option \"%s\" not recognized" msgstr "Option »%s« nicht erkannt" #. translator: %s is the name of a COPY option, e.g. ON_ERROR -#: commands/copy.c:735 commands/copy.c:740 commands/copy.c:745 -#: commands/copy.c:815 +#: commands/copy.c:736 commands/copy.c:741 commands/copy.c:746 +#: commands/copy.c:816 #, c-format msgid "cannot specify %s in BINARY mode" msgstr "%s kann nicht im BINARY-Modus angegeben werden" -#: commands/copy.c:767 +#: commands/copy.c:768 #, c-format msgid "COPY delimiter must be a single one-byte character" msgstr "DELIMITER für COPY muss ein einzelnes Ein-Byte-Zeichen sein" -#: commands/copy.c:774 +#: commands/copy.c:775 #, c-format msgid "COPY delimiter cannot be newline or carriage return" msgstr "COPY-Trennzeichen kann nicht Newline oder Carriage Return sein" -#: commands/copy.c:780 +#: commands/copy.c:781 #, c-format msgid "COPY null representation cannot use newline or carriage return" msgstr "COPY NULL-Darstellung kann nicht Newline oder Carriage Return enthalten" -#: commands/copy.c:790 +#: commands/copy.c:791 #, c-format msgid "COPY default representation cannot use newline or carriage return" msgstr "COPY DEFAULT-Darstellung kann nicht Newline oder Carriage Return enthalten" -#: commands/copy.c:808 +#: commands/copy.c:809 #, c-format msgid "COPY delimiter cannot be \"%s\"" msgstr "DELIMITER für COPY darf nicht »%s« sein" #. translator: %s is the name of a COPY option, e.g. ON_ERROR -#: commands/copy.c:822 commands/copy.c:839 commands/copy.c:851 -#: commands/copy.c:866 commands/copy.c:882 +#: commands/copy.c:823 commands/copy.c:840 commands/copy.c:852 +#: commands/copy.c:867 commands/copy.c:883 #, c-format msgid "COPY %s requires CSV mode" msgstr "COPY %s benötigt CSV-Modus" -#: commands/copy.c:827 +#: commands/copy.c:828 #, c-format msgid "COPY quote must be a single one-byte character" msgstr "Quote-Zeichen für COPY muss ein einzelnes Ein-Byte-Zeichen sein" -#: commands/copy.c:832 +#: commands/copy.c:833 #, c-format msgid "COPY delimiter and quote must be different" msgstr "DELIMITER und QUOTE für COPY müssen verschieden sein" -#: commands/copy.c:844 +#: commands/copy.c:845 #, c-format msgid "COPY escape must be a single one-byte character" msgstr "Escape-Zeichen für COPY muss ein einzelnes Ein-Byte-Zeichen sein" #. translator: %s is the name of a COPY option, e.g. NULL -#: commands/copy.c:898 commands/copy.c:934 +#: commands/copy.c:899 commands/copy.c:935 #, c-format msgid "COPY delimiter character must not appear in the %s specification" msgstr "Trennzeichen für COPY darf nicht in der %s-Darstellung erscheinen" #. translator: %s is the name of a COPY option, e.g. NULL -#: commands/copy.c:907 commands/copy.c:943 +#: commands/copy.c:908 commands/copy.c:944 #, c-format msgid "CSV quote character must not appear in the %s specification" msgstr "CSV-Quote-Zeichen darf nicht in der %s-Darstellung erscheinen" -#: commands/copy.c:952 +#: commands/copy.c:953 #, c-format msgid "NULL specification and DEFAULT specification cannot be the same" msgstr "NULL-Darstellung und DEFAULT-Darstellung können nicht gleich sein" -#: commands/copy.c:958 +#: commands/copy.c:959 #, c-format msgid "only ON_ERROR STOP is allowed in BINARY mode" msgstr "nur ON_ERROR STOP ist im BINARY-Modus erlaubt" #. translator: first and second %s are the names of COPY option, e.g. #. * ON_ERROR, third is the value of the COPY option, e.g. IGNORE -#: commands/copy.c:965 +#: commands/copy.c:966 #, c-format msgid "COPY %s requires %s to be set to %s" msgstr "COPY %s erfordert, dass %s auf %s gesetzt ist" -#: commands/copy.c:1027 +#: commands/copy.c:1028 #, c-format msgid "column \"%s\" is a generated column" msgstr "Spalte »%s« ist eine generierte Spalte" -#: commands/copy.c:1029 +#: commands/copy.c:1030 #, c-format msgid "Generated columns cannot be used in COPY." msgstr "Generierte Spalten können nicht in COPY verwendet werden." -#: commands/copy.c:1044 commands/indexcmds.c:1959 commands/statscmds.c:260 -#: commands/tablecmds.c:2593 commands/tablecmds.c:3101 -#: commands/tablecmds.c:3930 parser/parse_relation.c:3798 +#: commands/copy.c:1045 commands/indexcmds.c:1961 commands/statscmds.c:260 +#: commands/tablecmds.c:2603 commands/tablecmds.c:3111 +#: commands/tablecmds.c:3940 parser/parse_relation.c:3798 #: parser/parse_relation.c:3808 parser/parse_relation.c:3826 #: parser/parse_relation.c:3833 parser/parse_relation.c:3847 #: utils/adt/tsvector_op.c:2857 @@ -7309,7 +7309,7 @@ msgstr "Generierte Spalten können nicht in COPY verwendet werden." msgid "column \"%s\" does not exist" msgstr "Spalte »%s« existiert nicht" -#: commands/copy.c:1051 commands/tablecmds.c:2619 commands/trigger.c:957 +#: commands/copy.c:1052 commands/tablecmds.c:2629 commands/trigger.c:957 #: parser/parse_target.c:1086 parser/parse_target.c:1097 #, c-format msgid "column \"%s\" specified more than once" @@ -7470,7 +7470,7 @@ msgid "could not read from COPY file: %m" msgstr "konnte nicht aus COPY-Datei lesen: %m" #: commands/copyfromparse.c:278 commands/copyfromparse.c:303 -#: replication/walsender.c:746 replication/walsender.c:772 tcop/postgres.c:369 +#: replication/walsender.c:746 replication/walsender.c:772 tcop/postgres.c:370 #, c-format msgid "unexpected EOF on client connection with an open transaction" msgstr "unerwartetes EOF auf Client-Verbindung mit einer offenen Transaktion" @@ -8150,14 +8150,14 @@ msgstr "»%s« ist eine Aggregatfunktion" msgid "Use DROP AGGREGATE to drop aggregate functions." msgstr "Verwenden Sie DROP AGGREGATE, um Aggregatfunktionen zu löschen." -#: commands/dropcmds.c:153 commands/sequence.c:462 commands/tablecmds.c:4014 -#: commands/tablecmds.c:4175 commands/tablecmds.c:4227 -#: commands/tablecmds.c:18954 tcop/utility.c:1328 +#: commands/dropcmds.c:153 commands/sequence.c:462 commands/tablecmds.c:4024 +#: commands/tablecmds.c:4185 commands/tablecmds.c:4237 +#: commands/tablecmds.c:18966 tcop/utility.c:1328 #, c-format msgid "relation \"%s\" does not exist, skipping" msgstr "Relation »%s« existiert nicht, wird übersprungen" -#: commands/dropcmds.c:183 commands/dropcmds.c:282 commands/tablecmds.c:1469 +#: commands/dropcmds.c:183 commands/dropcmds.c:282 commands/tablecmds.c:1479 #, c-format msgid "schema \"%s\" does not exist, skipping" msgstr "Schema »%s« existiert nicht, wird übersprungen" @@ -8277,7 +8277,7 @@ msgstr "Regel »%s« für Relation »%s« existiert nicht, wird übersprungen" msgid "foreign-data wrapper \"%s\" does not exist, skipping" msgstr "Fremddaten-Wrapper »%s« existiert nicht, wird übersprungen" -#: commands/dropcmds.c:448 commands/foreigncmds.c:1371 +#: commands/dropcmds.c:448 commands/foreigncmds.c:1376 #, c-format msgid "server \"%s\" does not exist, skipping" msgstr "Server »%s« existiert nicht, wird übersprungen" @@ -8369,7 +8369,7 @@ msgstr "%s kann nur in einer sql_drop-Ereignistriggerfunktion aufgerufen werden" msgid "%s can only be called in a table_rewrite event trigger function" msgstr "%s kann nur in einer table_rewrite-Ereignistriggerfunktion aufgerufen werden" -#: commands/event_trigger.c:2063 +#: commands/event_trigger.c:2066 #, c-format msgid "%s can only be called in an event trigger function" msgstr "%s kann nur in einer Ereignistriggerfunktion aufgerufen werden" @@ -8754,47 +8754,47 @@ msgstr "Nur Superuser können Fremddaten-Wrapper ändern." msgid "changing the foreign-data wrapper handler can change behavior of existing foreign tables" msgstr "das Ändern des Handlers des Fremddaten-Wrappers kann das Verhalten von bestehenden Fremdtabellen verändern" -#: commands/foreigncmds.c:756 +#: commands/foreigncmds.c:761 #, c-format msgid "changing the foreign-data wrapper validator can cause the options for dependent objects to become invalid" msgstr "durch Ändern des Validators des Fremddaten-Wrappers können die Optionen von abhängigen Objekten ungültig werden" -#: commands/foreigncmds.c:887 +#: commands/foreigncmds.c:892 #, c-format msgid "server \"%s\" already exists, skipping" msgstr "Server »%s« existiert bereits, wird übersprungen" -#: commands/foreigncmds.c:1155 +#: commands/foreigncmds.c:1160 #, c-format msgid "user mapping for \"%s\" already exists for server \"%s\", skipping" msgstr "Benutzerabbildung für »%s« existiert bereits für Server »%s«, wird übersprungen" -#: commands/foreigncmds.c:1165 +#: commands/foreigncmds.c:1170 #, c-format msgid "user mapping for \"%s\" already exists for server \"%s\"" msgstr "Benutzerabbildung für »%s« existiert bereits für Server »%s«" -#: commands/foreigncmds.c:1265 commands/foreigncmds.c:1385 +#: commands/foreigncmds.c:1270 commands/foreigncmds.c:1390 #, c-format msgid "user mapping for \"%s\" does not exist for server \"%s\"" msgstr "Benutzerabbildung für »%s« existiert nicht für Server »%s«" -#: commands/foreigncmds.c:1390 +#: commands/foreigncmds.c:1395 #, c-format msgid "user mapping for \"%s\" does not exist for server \"%s\", skipping" msgstr "Benutzerabbildung für »%s« existiert nicht für Server »%s«, wird übersprungen" -#: commands/foreigncmds.c:1518 foreign/foreign.c:405 +#: commands/foreigncmds.c:1523 foreign/foreign.c:405 #, c-format msgid "foreign-data wrapper \"%s\" has no handler" msgstr "Fremddaten-Wrapper »%s« hat keinen Handler" -#: commands/foreigncmds.c:1524 +#: commands/foreigncmds.c:1529 #, c-format msgid "foreign-data wrapper \"%s\" does not support IMPORT FOREIGN SCHEMA" msgstr "Fremddaten-Wrapper »%s« unterstützt IMPORT FOREIGN SCHEMA nicht" -#: commands/foreigncmds.c:1626 +#: commands/foreigncmds.c:1631 #, c-format msgid "importing foreign table \"%s\"" msgstr "importiere Fremdtabelle »%s«" @@ -9192,12 +9192,12 @@ msgstr "kann Index für partitionierte Tabelle »%s« nicht nebenläufig erzeuge msgid "cannot create indexes on temporary tables of other sessions" msgstr "kann keine Indexe für temporäre Tabellen anderer Sitzungen erzeugen" -#: commands/indexcmds.c:786 commands/tablecmds.c:892 commands/tablespace.c:1178 +#: commands/indexcmds.c:786 commands/tablecmds.c:893 commands/tablespace.c:1178 #, c-format msgid "cannot specify default tablespace for partitioned relations" msgstr "für partitionierte Relationen kann kein Standard-Tablespace angegeben werden" -#: commands/indexcmds.c:818 commands/tablecmds.c:923 commands/tablecmds.c:3710 +#: commands/indexcmds.c:818 commands/tablecmds.c:924 commands/tablecmds.c:3720 #, c-format msgid "only shared relations can be placed in pg_global tablespace" msgstr "nur geteilte Relationen können in den Tablespace »pg_global« gelegt werden" @@ -9242,17 +9242,17 @@ msgstr "nicht unterstützter %s-Constraint mit Partitionierungsschlüsseldefinit msgid "%s constraints cannot be used when partition keys include expressions." msgstr "%s-Constraints können nicht verwendet werden, wenn Partitionierungsschlüssel Ausdrücke enthalten." -#: commands/indexcmds.c:1056 commands/indexcmds.c:2469 -#: commands/indexcmds.c:2488 executor/execReplication.c:329 +#: commands/indexcmds.c:1056 commands/indexcmds.c:2471 +#: commands/indexcmds.c:2490 executor/execReplication.c:329 #: parser/parse_cte.c:303 parser/parse_oper.c:221 -#: utils/adt/array_userfuncs.c:1410 utils/adt/array_userfuncs.c:1553 +#: utils/adt/array_userfuncs.c:1419 utils/adt/array_userfuncs.c:1562 #: utils/adt/arrayfuncs.c:3870 utils/adt/arrayfuncs.c:4425 #: utils/adt/arrayfuncs.c:6446 utils/adt/rowtypes.c:1220 #, c-format msgid "could not identify an equality operator for type %s" msgstr "konnte keinen Ist-Gleich-Operator für Typ %s ermitteln" -#: commands/indexcmds.c:1057 commands/indexcmds.c:2491 +#: commands/indexcmds.c:1057 commands/indexcmds.c:2493 #, c-format msgid "There is no suitable operator in operator family \"%s\" for access method \"%s\"." msgstr "Es gibt keinen passenden Operator in Operatorfamilie »%s« für Zugriffsmethode »%s«." @@ -9272,238 +9272,238 @@ msgstr "Unique-Constraint für partitionierte Tabelle muss alle Partitionierungs msgid "%s constraint on table \"%s\" lacks column \"%s\" which is part of the partition key." msgstr "Im %s-Constraint in Tabelle »%s« fehlt Spalte »%s«, welche Teil des Partitionierungsschlüssels ist." -#: commands/indexcmds.c:1116 commands/indexcmds.c:1147 +#: commands/indexcmds.c:1116 commands/indexcmds.c:1148 #, c-format msgid "index creation on system columns is not supported" msgstr "Indexerzeugung für Systemspalten wird nicht unterstützt" -#: commands/indexcmds.c:1123 +#: commands/indexcmds.c:1124 #, c-format msgid "primary keys on virtual generated columns are not supported" msgstr "Primärschlüssel über virtuelle generierte Spalten werden nicht unterstützt" -#: commands/indexcmds.c:1125 commands/indexcmds.c:1164 +#: commands/indexcmds.c:1126 commands/indexcmds.c:1166 #, c-format msgid "unique constraints on virtual generated columns are not supported" msgstr "Unique Constraints über virtuelle generierte Spalten werden nicht unterstützt" -#: commands/indexcmds.c:1126 commands/indexcmds.c:1165 +#: commands/indexcmds.c:1127 commands/indexcmds.c:1167 #, c-format msgid "indexes on virtual generated columns are not supported" msgstr "Indexe über virtuelle generierte Spalten werden nicht unterstützt" -#: commands/indexcmds.c:1397 tcop/utility.c:1518 +#: commands/indexcmds.c:1399 tcop/utility.c:1518 #, c-format msgid "cannot create unique index on partitioned table \"%s\"" msgstr "kann keinen Unique Index für partitionierte Tabelle »%s« erzeugen" -#: commands/indexcmds.c:1399 tcop/utility.c:1520 +#: commands/indexcmds.c:1401 tcop/utility.c:1520 #, c-format msgid "Table \"%s\" contains partitions that are foreign tables." msgstr "Tabelle »%s« enthält Partitionen, die Fremdtabellen sind." -#: commands/indexcmds.c:1857 +#: commands/indexcmds.c:1859 #, c-format msgid "functions in index predicate must be marked IMMUTABLE" msgstr "Funktionen im Indexprädikat müssen als IMMUTABLE markiert sein" -#: commands/indexcmds.c:1954 parser/parse_utilcmd.c:2735 -#: parser/parse_utilcmd.c:2918 +#: commands/indexcmds.c:1956 parser/parse_utilcmd.c:2739 +#: parser/parse_utilcmd.c:2927 #, c-format msgid "column \"%s\" named in key does not exist" msgstr "Spalte »%s«, die im Schlüssel verwendet wird, existiert nicht" -#: commands/indexcmds.c:1978 parser/parse_utilcmd.c:1988 +#: commands/indexcmds.c:1980 parser/parse_utilcmd.c:1988 #, c-format msgid "expressions are not supported in included columns" msgstr "in eingeschlossenen Spalten werden keine Ausdrücke unterstützt" -#: commands/indexcmds.c:2019 +#: commands/indexcmds.c:2021 #, c-format msgid "functions in index expression must be marked IMMUTABLE" msgstr "Funktionen im Indexausdruck müssen als IMMUTABLE markiert sein" -#: commands/indexcmds.c:2034 +#: commands/indexcmds.c:2036 #, c-format msgid "including column does not support a collation" msgstr "inkludierte Spalte unterstützt keine Sortierfolge" -#: commands/indexcmds.c:2038 +#: commands/indexcmds.c:2040 #, c-format msgid "including column does not support an operator class" msgstr "inkludierte Spalte unterstützt keine Operatorklasse" -#: commands/indexcmds.c:2042 +#: commands/indexcmds.c:2044 #, c-format msgid "including column does not support ASC/DESC options" msgstr "inkludierte Spalte unterstützt die Optionen ASC/DESC nicht" -#: commands/indexcmds.c:2046 +#: commands/indexcmds.c:2048 #, c-format msgid "including column does not support NULLS FIRST/LAST options" msgstr "inkludierte Spalte unterstützt die Optionen NULLS FIRST/LAST nicht" -#: commands/indexcmds.c:2089 +#: commands/indexcmds.c:2091 #, c-format msgid "could not determine which collation to use for index expression" msgstr "konnte die für den Indexausdruck zu verwendende Sortierfolge nicht bestimmen" -#: commands/indexcmds.c:2097 commands/tablecmds.c:19994 commands/typecmds.c:812 -#: parser/parse_expr.c:2815 parser/parse_type.c:568 parser/parse_utilcmd.c:4064 +#: commands/indexcmds.c:2099 commands/tablecmds.c:20006 commands/typecmds.c:812 +#: parser/parse_expr.c:2815 parser/parse_type.c:568 parser/parse_utilcmd.c:4073 #: utils/adt/misc.c:630 #, c-format msgid "collations are not supported by type %s" msgstr "Sortierfolgen werden von Typ %s nicht unterstützt" -#: commands/indexcmds.c:2164 +#: commands/indexcmds.c:2166 #, c-format msgid "operator %s is not commutative" msgstr "Operator %s ist nicht kommutativ" -#: commands/indexcmds.c:2166 +#: commands/indexcmds.c:2168 #, c-format msgid "Only commutative operators can be used in exclusion constraints." msgstr "In Exclusion-Constraints können nur kommutative Operatoren verwendet werden." -#: commands/indexcmds.c:2176 +#: commands/indexcmds.c:2178 #, c-format msgid "operator %s is not a member of operator family \"%s\"" msgstr "Operator %s ist kein Mitglied der Operatorfamilie »%s«" -#: commands/indexcmds.c:2179 +#: commands/indexcmds.c:2181 #, c-format msgid "The exclusion operator must be related to the index operator class for the constraint." msgstr "Der Exklusionsoperator muss in Beziehung zur Indexoperatorklasse des Constraints stehen." -#: commands/indexcmds.c:2228 +#: commands/indexcmds.c:2230 #, c-format msgid "access method \"%s\" does not support ASC/DESC options" msgstr "Zugriffsmethode »%s« unterstützt die Optionen ASC/DESC nicht" -#: commands/indexcmds.c:2233 +#: commands/indexcmds.c:2235 #, c-format msgid "access method \"%s\" does not support NULLS FIRST/LAST options" msgstr "Zugriffsmethode »%s« unterstützt die Optionen NULLS FIRST/LAST nicht" -#: commands/indexcmds.c:2277 commands/tablecmds.c:20019 -#: commands/tablecmds.c:20025 commands/typecmds.c:2349 +#: commands/indexcmds.c:2279 commands/tablecmds.c:20031 +#: commands/tablecmds.c:20037 commands/typecmds.c:2349 #, c-format msgid "data type %s has no default operator class for access method \"%s\"" msgstr "Datentyp %s hat keine Standardoperatorklasse für Zugriffsmethode »%s«" -#: commands/indexcmds.c:2279 +#: commands/indexcmds.c:2281 #, c-format msgid "You must specify an operator class for the index or define a default operator class for the data type." msgstr "Sie müssen für den Index eine Operatorklasse angeben oder eine Standardoperatorklasse für den Datentyp definieren." -#: commands/indexcmds.c:2308 commands/indexcmds.c:2316 +#: commands/indexcmds.c:2310 commands/indexcmds.c:2318 #: commands/opclasscmds.c:205 #, c-format msgid "operator class \"%s\" does not exist for access method \"%s\"" msgstr "Operatorklasse »%s« existiert nicht für Zugriffsmethode »%s«" -#: commands/indexcmds.c:2330 commands/typecmds.c:2337 +#: commands/indexcmds.c:2332 commands/typecmds.c:2337 #, c-format msgid "operator class \"%s\" does not accept data type %s" msgstr "Operatorklasse »%s« akzeptiert Datentyp %s nicht" -#: commands/indexcmds.c:2420 +#: commands/indexcmds.c:2422 #, c-format msgid "there are multiple default operator classes for data type %s" msgstr "es gibt mehrere Standardoperatorklassen für Datentyp %s" -#: commands/indexcmds.c:2470 commands/indexcmds.c:2489 +#: commands/indexcmds.c:2472 commands/indexcmds.c:2491 #, c-format msgid "could not identify an overlaps operator for type %s" msgstr "konnte keinen Überlappungsoperator für Typ %s ermitteln" -#: commands/indexcmds.c:2471 commands/indexcmds.c:2490 +#: commands/indexcmds.c:2473 commands/indexcmds.c:2492 #, c-format msgid "could not identify a contained-by operator for type %s" msgstr "konnte keinen Contained-By-Operator für Typ %s ermitteln" -#: commands/indexcmds.c:2472 commands/tablecmds.c:10358 +#: commands/indexcmds.c:2474 commands/tablecmds.c:10368 #, c-format msgid "Could not translate compare type %d for operator family \"%s\" of access method \"%s\"." msgstr "Konnte Vergleichstyp %d für Operatorfamilie »%s« von Zugriffsmethode »%s« nicht übersetzen." -#: commands/indexcmds.c:3078 +#: commands/indexcmds.c:3080 #, c-format msgid "table \"%s\" has no indexes that can be reindexed concurrently" msgstr "Tabelle »%s« hat keine Indexe, die nebenläufig reindiziert werden können" -#: commands/indexcmds.c:3092 +#: commands/indexcmds.c:3094 #, c-format msgid "table \"%s\" has no indexes to reindex" msgstr "Tabelle »%s« hat keine zu reindizierenden Indexe" -#: commands/indexcmds.c:3139 commands/indexcmds.c:3650 -#: commands/indexcmds.c:3780 +#: commands/indexcmds.c:3141 commands/indexcmds.c:3652 +#: commands/indexcmds.c:3782 #, c-format msgid "cannot reindex system catalogs concurrently" msgstr "Systemkataloge können nicht nebenläufig reindiziert werden" -#: commands/indexcmds.c:3163 +#: commands/indexcmds.c:3165 #, c-format msgid "can only reindex the currently open database" msgstr "nur die aktuell geöffnete Datenbank kann reindiziert werden" -#: commands/indexcmds.c:3255 +#: commands/indexcmds.c:3257 #, c-format msgid "cannot reindex system catalogs concurrently, skipping all" msgstr "Systemkataloge können nicht nebenläufig reindiziert werden, werden alle übersprungen" -#: commands/indexcmds.c:3288 +#: commands/indexcmds.c:3290 #, c-format msgid "cannot move system relations, skipping all" msgstr "Systemrelationen können nicht verschoben werden, werden alle übersprungen" -#: commands/indexcmds.c:3334 +#: commands/indexcmds.c:3336 #, c-format msgid "while reindexing partitioned table \"%s.%s\"" msgstr "beim Reindizieren der partitionierten Tabelle »%s.%s«" -#: commands/indexcmds.c:3337 +#: commands/indexcmds.c:3339 #, c-format msgid "while reindexing partitioned index \"%s.%s\"" msgstr "beim Reindizieren des partitionierten Index »%s.%s«" -#: commands/indexcmds.c:3530 commands/indexcmds.c:4422 +#: commands/indexcmds.c:3532 commands/indexcmds.c:4424 #, c-format msgid "table \"%s.%s\" was reindexed" msgstr "Tabelle »%s.%s« wurde neu indiziert" -#: commands/indexcmds.c:3682 commands/indexcmds.c:3735 +#: commands/indexcmds.c:3684 commands/indexcmds.c:3737 #, c-format msgid "skipping reindex of invalid index \"%s.%s\"" msgstr "Reindizieren des ungültigen Index »%s.%s« wird übersprungen" -#: commands/indexcmds.c:3685 commands/indexcmds.c:3738 +#: commands/indexcmds.c:3687 commands/indexcmds.c:3740 #, c-format msgid "Use DROP INDEX or REINDEX INDEX." msgstr "Verwenden Sie DROP INDEX oder REINDEX INDEX." -#: commands/indexcmds.c:3689 +#: commands/indexcmds.c:3691 #, c-format msgid "cannot reindex exclusion constraint index \"%s.%s\" concurrently, skipping" msgstr "Exclusion-Constraint-Index »%s.%s« kann nicht nebenläufig reindizert werden, wird übersprungen" -#: commands/indexcmds.c:3845 +#: commands/indexcmds.c:3847 #, c-format msgid "cannot reindex this type of relation concurrently" msgstr "diese Art Relation kann nicht nebenläufig reindiziert werden" -#: commands/indexcmds.c:3863 +#: commands/indexcmds.c:3865 #, c-format msgid "cannot move non-shared relation to tablespace \"%s\"" msgstr "nicht geteilte Relation kann nicht nach Tablespace »%s« verschoben werden" -#: commands/indexcmds.c:4403 commands/indexcmds.c:4415 +#: commands/indexcmds.c:4405 commands/indexcmds.c:4417 #, c-format msgid "index \"%s.%s\" was reindexed" msgstr "Index »%s.%s« wurde neu indiziert" -#: commands/indexcmds.c:4405 commands/indexcmds.c:4424 +#: commands/indexcmds.c:4407 commands/indexcmds.c:4426 #, c-format msgid "%s." msgstr "%s." @@ -9863,10 +9863,10 @@ msgid "operator attribute \"%s\" cannot be changed if it has already been set" msgstr "Operator-Attribut »%s« kann nicht geändert werden, wenn es schon gesetzt wurde" #: commands/policy.c:86 commands/policy.c:379 commands/statscmds.c:152 -#: commands/tablecmds.c:1800 commands/tablecmds.c:2400 -#: commands/tablecmds.c:3824 commands/tablecmds.c:6793 -#: commands/tablecmds.c:10114 commands/tablecmds.c:19565 -#: commands/tablecmds.c:19600 commands/trigger.c:319 commands/trigger.c:1338 +#: commands/tablecmds.c:1810 commands/tablecmds.c:2410 +#: commands/tablecmds.c:3834 commands/tablecmds.c:6803 +#: commands/tablecmds.c:10124 commands/tablecmds.c:19577 +#: commands/tablecmds.c:19612 commands/trigger.c:319 commands/trigger.c:1338 #: commands/trigger.c:1448 rewrite/rewriteDefine.c:268 #: rewrite/rewriteDefine.c:779 rewrite/rewriteRemove.c:74 #, c-format @@ -9965,7 +9965,7 @@ msgid "must be superuser to create custom procedural language" msgstr "nur Superuser können maßgeschneiderte prozedurale Sprachen erzeugen" #: commands/publicationcmds.c:135 libpq/auth-oauth.c:850 -#: postmaster/postmaster.c:1130 postmaster/postmaster.c:1232 +#: postmaster/postmaster.c:1131 postmaster/postmaster.c:1233 #: utils/init/miscinit.c:1871 #, c-format msgid "invalid list syntax in parameter \"%s\"" @@ -10107,7 +10107,7 @@ msgid "Tables cannot be added to or dropped from FOR ALL TABLES publications." msgstr "In einer FOR-ALL-TABLES-Publikation können keine Tabellen hinzugefügt oder entfernt werden." #: commands/publicationcmds.c:1497 commands/publicationcmds.c:1536 -#: commands/publicationcmds.c:2073 utils/cache/lsyscache.c:3774 +#: commands/publicationcmds.c:2073 utils/cache/lsyscache.c:3812 #, c-format msgid "publication \"%s\" does not exist" msgstr "Publikation »%s« existiert nicht" @@ -10327,8 +10327,8 @@ msgstr "Sequenz muss im selben Schema wie die verknüpfte Tabelle sein" msgid "cannot change ownership of identity sequence" msgstr "kann Eigentümer einer Identitätssequenz nicht ändern" -#: commands/sequence.c:1671 commands/tablecmds.c:16136 -#: commands/tablecmds.c:18974 +#: commands/sequence.c:1671 commands/tablecmds.c:16148 +#: commands/tablecmds.c:18986 #, c-format msgid "Sequence \"%s\" is linked to table \"%s\"." msgstr "Sequenz »%s« ist mit Tabelle »%s« verknüpft." @@ -10403,12 +10403,12 @@ msgstr "doppelter Spaltenname in Statistikdefinition" msgid "duplicate expression in statistics definition" msgstr "doppelter Ausdruck in Statistikdefinition" -#: commands/statscmds.c:667 commands/tablecmds.c:8939 +#: commands/statscmds.c:667 commands/tablecmds.c:8949 #, c-format msgid "statistics target %d is too low" msgstr "Statistikziel %d ist zu niedrig" -#: commands/statscmds.c:675 commands/tablecmds.c:8947 +#: commands/statscmds.c:675 commands/tablecmds.c:8957 #, c-format msgid "lowering statistics target to %d" msgstr "setze Statistikziel auf %d herab" @@ -10501,7 +10501,7 @@ msgid "cannot set option \"%s\" for a subscription that does not have a slot nam msgstr "Option »%s« kann nicht für eine Subskription ohne Slot-Name gesetzt werden" #: commands/subscriptioncmds.c:1127 commands/subscriptioncmds.c:1665 -#: commands/subscriptioncmds.c:2046 utils/cache/lsyscache.c:3824 +#: commands/subscriptioncmds.c:2046 utils/cache/lsyscache.c:3862 #, c-format msgid "subscription \"%s\" does not exist" msgstr "Subskription »%s« existiert nicht" @@ -10727,8 +10727,8 @@ msgstr "materialisierte Sicht »%s« existiert nicht, wird übersprungen" msgid "Use DROP MATERIALIZED VIEW to remove a materialized view." msgstr "Verwenden Sie DROP MATERIALIZED VIEW, um eine materialisierte Sicht zu löschen." -#: commands/tablecmds.c:282 commands/tablecmds.c:306 commands/tablecmds.c:21651 -#: parser/parse_utilcmd.c:2428 +#: commands/tablecmds.c:282 commands/tablecmds.c:306 commands/tablecmds.c:21663 +#: parser/parse_utilcmd.c:2432 #, c-format msgid "index \"%s\" does not exist" msgstr "Index »%s« existiert nicht" @@ -10751,8 +10751,8 @@ msgstr "»%s« ist kein Typ" msgid "Use DROP TYPE to remove a type." msgstr "Verwenden Sie DROP TYPE, um einen Typen zu löschen." -#: commands/tablecmds.c:294 commands/tablecmds.c:15975 -#: commands/tablecmds.c:18676 +#: commands/tablecmds.c:294 commands/tablecmds.c:15987 +#: commands/tablecmds.c:18688 #, c-format msgid "foreign table \"%s\" does not exist" msgstr "Fremdtabelle »%s« existiert nicht" @@ -10766,226 +10766,226 @@ msgstr "Fremdtabelle »%s« existiert nicht, wird übersprungen" msgid "Use DROP FOREIGN TABLE to remove a foreign table." msgstr "Verwenden Sie DROP FOREIGN TABLE, um eine Fremdtabelle zu löschen." -#: commands/tablecmds.c:802 +#: commands/tablecmds.c:803 #, c-format msgid "ON COMMIT can only be used on temporary tables" msgstr "ON COMMIT kann nur mit temporären Tabellen verwendet werden" -#: commands/tablecmds.c:819 +#: commands/tablecmds.c:820 #, c-format msgid "partitioned tables cannot be unlogged" msgstr "partitionierte Tabellen können nicht ungeloggt sein" -#: commands/tablecmds.c:839 +#: commands/tablecmds.c:840 #, c-format msgid "cannot create temporary table within security-restricted operation" msgstr "kann temporäre Tabelle nicht in einer sicherheitsbeschränkten Operation erzeugen" -#: commands/tablecmds.c:875 commands/tablecmds.c:17400 +#: commands/tablecmds.c:876 commands/tablecmds.c:17412 #, c-format msgid "relation \"%s\" would be inherited from more than once" msgstr "von der Relation »%s« würde mehrmals geerbt werden" -#: commands/tablecmds.c:1133 +#: commands/tablecmds.c:1134 #, c-format msgid "\"%s\" is not partitioned" msgstr "»%s« ist nicht partitioniert" -#: commands/tablecmds.c:1227 +#: commands/tablecmds.c:1228 #, c-format msgid "cannot partition using more than %d columns" msgstr "Partitionierung kann nicht mehr als %d Spalten verwenden" -#: commands/tablecmds.c:1283 +#: commands/tablecmds.c:1284 #, c-format msgid "cannot create foreign partition of partitioned table \"%s\"" msgstr "kann keine Fremdpartition der partitionierten Tabelle »%s« erzeugen" -#: commands/tablecmds.c:1285 +#: commands/tablecmds.c:1286 #, c-format msgid "Table \"%s\" contains indexes that are unique." msgstr "Tabelle »%s« enthält Unique Indexe." -#: commands/tablecmds.c:1415 commands/tablecmds.c:14952 +#: commands/tablecmds.c:1425 commands/tablecmds.c:14964 #, c-format msgid "too many array dimensions" msgstr "zu viele Array-Dimensionen" -#: commands/tablecmds.c:1420 parser/parse_clause.c:772 +#: commands/tablecmds.c:1430 parser/parse_clause.c:772 #: parser/parse_relation.c:1929 #, c-format msgid "column \"%s\" cannot be declared SETOF" msgstr "Spalte »%s« kann nicht als SETOF deklariert werden" -#: commands/tablecmds.c:1549 +#: commands/tablecmds.c:1559 #, c-format msgid "DROP INDEX CONCURRENTLY does not support dropping multiple objects" msgstr "DROP INDEX CONCURRENTLY unterstützt das Löschen von mehreren Objekten nicht" -#: commands/tablecmds.c:1553 +#: commands/tablecmds.c:1563 #, c-format msgid "DROP INDEX CONCURRENTLY does not support CASCADE" msgstr "DROP INDEX CONCURRENTLY unterstützt kein CASCADE" -#: commands/tablecmds.c:1657 +#: commands/tablecmds.c:1667 #, c-format msgid "cannot drop partitioned index \"%s\" concurrently" msgstr "kann partitionierten Index »%s« nicht nebenläufig löschen" -#: commands/tablecmds.c:1945 +#: commands/tablecmds.c:1955 #, c-format msgid "cannot truncate only a partitioned table" msgstr "kann nicht nur eine partitionierte Tabelle leeren" -#: commands/tablecmds.c:1946 +#: commands/tablecmds.c:1956 #, c-format msgid "Do not specify the ONLY keyword, or use TRUNCATE ONLY on the partitions directly." msgstr "Lassen Sie das Schlüsselwort ONLY weg oder wenden Sie TRUNCATE ONLY direkt auf die Partitionen an." -#: commands/tablecmds.c:2019 +#: commands/tablecmds.c:2029 #, c-format msgid "truncate cascades to table \"%s\"" msgstr "Truncate-Vorgang leert ebenfalls Tabelle »%s«" -#: commands/tablecmds.c:2380 +#: commands/tablecmds.c:2390 #, c-format msgid "cannot truncate foreign table \"%s\"" msgstr "kann Fremdtabelle »%s« nicht leeren" -#: commands/tablecmds.c:2437 +#: commands/tablecmds.c:2447 #, c-format msgid "cannot truncate temporary tables of other sessions" msgstr "kann temporäre Tabellen anderer Sitzungen nicht leeren" -#: commands/tablecmds.c:2675 commands/tablecmds.c:17297 +#: commands/tablecmds.c:2685 commands/tablecmds.c:17309 #, c-format msgid "cannot inherit from partitioned table \"%s\"" msgstr "von partitionierter Tabelle »%s« kann nicht geerbt werden" -#: commands/tablecmds.c:2680 +#: commands/tablecmds.c:2690 #, c-format msgid "cannot inherit from partition \"%s\"" msgstr "von Partition »%s« kann nicht geerbt werden" -#: commands/tablecmds.c:2688 parser/parse_utilcmd.c:2699 -#: parser/parse_utilcmd.c:2887 +#: commands/tablecmds.c:2698 parser/parse_utilcmd.c:2703 +#: parser/parse_utilcmd.c:2896 #, c-format msgid "inherited relation \"%s\" is not a table or foreign table" msgstr "geerbte Relation »%s« ist keine Tabelle oder Fremdtabelle" -#: commands/tablecmds.c:2700 +#: commands/tablecmds.c:2710 #, c-format msgid "cannot create a temporary relation as partition of permanent relation \"%s\"" msgstr "eine temporäre Relation kann nicht als Partition der permanenten Relation »%s« erzeugt werden" -#: commands/tablecmds.c:2709 commands/tablecmds.c:17276 +#: commands/tablecmds.c:2719 commands/tablecmds.c:17288 #, c-format msgid "cannot inherit from temporary relation \"%s\"" msgstr "von temporärer Relation »%s« kann nicht geerbt werden" -#: commands/tablecmds.c:2719 commands/tablecmds.c:17284 +#: commands/tablecmds.c:2729 commands/tablecmds.c:17296 #, c-format msgid "cannot inherit from temporary relation of another session" msgstr "von temporärer Relation einer anderen Sitzung kann nicht geerbt werden" -#: commands/tablecmds.c:2874 commands/tablecmds.c:2928 -#: commands/tablecmds.c:14635 parser/parse_utilcmd.c:1440 +#: commands/tablecmds.c:2884 commands/tablecmds.c:2938 +#: commands/tablecmds.c:14647 parser/parse_utilcmd.c:1440 #: parser/parse_utilcmd.c:1484 parser/parse_utilcmd.c:1916 #: parser/parse_utilcmd.c:2024 #, c-format msgid "cannot convert whole-row table reference" msgstr "kann Verweis auf ganze Zeile der Tabelle nicht umwandeln" -#: commands/tablecmds.c:2875 parser/parse_utilcmd.c:1441 +#: commands/tablecmds.c:2885 parser/parse_utilcmd.c:1441 #, c-format msgid "Generation expression for column \"%s\" contains a whole-row reference to table \"%s\"." msgstr "Generierungsausdruck für Spalte »%s« enthält einen Verweis auf die ganze Zeile der Tabelle »%s«." -#: commands/tablecmds.c:2929 parser/parse_utilcmd.c:1485 +#: commands/tablecmds.c:2939 parser/parse_utilcmd.c:1485 #, c-format msgid "Constraint \"%s\" contains a whole-row reference to table \"%s\"." msgstr "Constraint »%s« enthält einen Verweis auf die ganze Zeile der Tabelle »%s«." -#: commands/tablecmds.c:3051 commands/tablecmds.c:3345 +#: commands/tablecmds.c:3061 commands/tablecmds.c:3355 #, c-format msgid "column \"%s\" inherits from generated column but specifies default" msgstr "Spalte »%s« erbt von einer generierten Spalte aber hat einen Vorgabewert angegeben" -#: commands/tablecmds.c:3056 commands/tablecmds.c:3350 +#: commands/tablecmds.c:3066 commands/tablecmds.c:3360 #, c-format msgid "column \"%s\" inherits from generated column but specifies identity" msgstr "Spalte »%s« erbt von einer generierten Spalte aber ist als Identitätsspalte definiert" -#: commands/tablecmds.c:3064 commands/tablecmds.c:3358 +#: commands/tablecmds.c:3074 commands/tablecmds.c:3368 #, c-format msgid "child column \"%s\" specifies generation expression" msgstr "abgeleitete Spalte »%s« gibt einen Generierungsausdruck an" -#: commands/tablecmds.c:3066 commands/tablecmds.c:3360 +#: commands/tablecmds.c:3076 commands/tablecmds.c:3370 #, c-format msgid "A child table column cannot be generated unless its parent column is." msgstr "Eine Spalte einer abgeleiteten Tabelle kann nur generiert sein, wenn die Spalte in der Elterntabelle es auch ist." -#: commands/tablecmds.c:3072 commands/tablecmds.c:3366 -#: commands/tablecmds.c:17562 +#: commands/tablecmds.c:3082 commands/tablecmds.c:3376 +#: commands/tablecmds.c:17574 #, c-format msgid "column \"%s\" inherits from generated column of different kind" msgstr "Spalte »%s« erbt von einer generierten Spalte einer anderen Art" -#: commands/tablecmds.c:3074 commands/tablecmds.c:3368 -#: commands/tablecmds.c:17563 +#: commands/tablecmds.c:3084 commands/tablecmds.c:3378 +#: commands/tablecmds.c:17575 #, c-format msgid "Parent column is %s, child column is %s." msgstr "Spalte in Elterntabelle ist %s, Spalte in abgeleiteter Tabelle ist %s." -#: commands/tablecmds.c:3121 +#: commands/tablecmds.c:3131 #, c-format msgid "column \"%s\" inherits conflicting generation expressions" msgstr "Spalte »%s« erbt widersprüchliche Generierungsausdrücke" -#: commands/tablecmds.c:3123 +#: commands/tablecmds.c:3133 #, c-format msgid "To resolve the conflict, specify a generation expression explicitly." msgstr "Um den Konflikt zu lösen, geben Sie einen Generierungsausdruck ausdrücklich an." -#: commands/tablecmds.c:3127 +#: commands/tablecmds.c:3137 #, c-format msgid "column \"%s\" inherits conflicting default values" msgstr "Spalte »%s« erbt widersprüchliche Vorgabewerte" -#: commands/tablecmds.c:3129 +#: commands/tablecmds.c:3139 #, c-format msgid "To resolve the conflict, specify a default explicitly." msgstr "Um den Konflikt zu lösen, geben Sie einen Vorgabewert ausdrücklich an." -#: commands/tablecmds.c:3196 +#: commands/tablecmds.c:3206 #, c-format msgid "check constraint name \"%s\" appears multiple times but with different expressions" msgstr "Check-Constraint-Name »%s« erscheint mehrmals, aber mit unterschiedlichen Ausdrücken" -#: commands/tablecmds.c:3249 +#: commands/tablecmds.c:3259 #, c-format msgid "merging column \"%s\" with inherited definition" msgstr "Spalte »%s« wird mit geerbter Definition zusammengeführt" -#: commands/tablecmds.c:3253 +#: commands/tablecmds.c:3263 #, c-format msgid "moving and merging column \"%s\" with inherited definition" msgstr "Spalte »%s« wird verschoben und mit geerbter Definition zusammengeführt" -#: commands/tablecmds.c:3254 +#: commands/tablecmds.c:3264 #, c-format msgid "User-specified column moved to the position of the inherited column." msgstr "Benutzerdefinierte Spalte wurde auf die Position der geerbten Spalte verschoben." -#: commands/tablecmds.c:3266 +#: commands/tablecmds.c:3276 #, c-format msgid "column \"%s\" has a type conflict" msgstr "für Spalte »%s« besteht ein Typkonflikt" -#: commands/tablecmds.c:3268 commands/tablecmds.c:3302 -#: commands/tablecmds.c:3318 commands/tablecmds.c:3434 -#: commands/tablecmds.c:3462 commands/tablecmds.c:3478 +#: commands/tablecmds.c:3278 commands/tablecmds.c:3312 +#: commands/tablecmds.c:3328 commands/tablecmds.c:3444 +#: commands/tablecmds.c:3472 commands/tablecmds.c:3488 #: parser/parse_coerce.c:2190 parser/parse_coerce.c:2210 #: parser/parse_coerce.c:2230 parser/parse_coerce.c:2251 #: parser/parse_coerce.c:2306 parser/parse_coerce.c:2340 @@ -10996,1309 +10996,1309 @@ msgstr "für Spalte »%s« besteht ein Typkonflikt" msgid "%s versus %s" msgstr "%s gegen %s" -#: commands/tablecmds.c:3280 +#: commands/tablecmds.c:3290 #, c-format msgid "column \"%s\" has a collation conflict" msgstr "für Spalte »%s« besteht ein Sortierfolgenkonflikt" -#: commands/tablecmds.c:3282 commands/tablecmds.c:3448 -#: commands/tablecmds.c:7277 parser/parse_expr.c:4792 +#: commands/tablecmds.c:3292 commands/tablecmds.c:3458 +#: commands/tablecmds.c:7287 parser/parse_expr.c:4792 #, c-format msgid "\"%s\" versus \"%s\"" msgstr "»%s« gegen »%s«" -#: commands/tablecmds.c:3300 +#: commands/tablecmds.c:3310 #, c-format msgid "column \"%s\" has a storage parameter conflict" msgstr "für Spalte »%s« besteht ein Konflikt bei einem Storage-Parameter" -#: commands/tablecmds.c:3316 commands/tablecmds.c:3476 +#: commands/tablecmds.c:3326 commands/tablecmds.c:3486 #, c-format msgid "column \"%s\" has a compression method conflict" msgstr "für Spalte »%s« besteht ein Komprimierungsmethodenkonflikt" -#: commands/tablecmds.c:3420 +#: commands/tablecmds.c:3430 #, c-format msgid "merging multiple inherited definitions of column \"%s\"" msgstr "geerbte Definitionen von Spalte »%s« werden zusammengeführt" -#: commands/tablecmds.c:3432 +#: commands/tablecmds.c:3442 #, c-format msgid "inherited column \"%s\" has a type conflict" msgstr "geerbte Spalte »%s« hat Typkonflikt" -#: commands/tablecmds.c:3446 +#: commands/tablecmds.c:3456 #, c-format msgid "inherited column \"%s\" has a collation conflict" msgstr "geerbte Spalte »%s« hat Sortierfolgenkonflikt" -#: commands/tablecmds.c:3460 +#: commands/tablecmds.c:3470 #, c-format msgid "inherited column \"%s\" has a storage parameter conflict" msgstr "geerbte Spalte »%s« hat einen Konflikt bei einem Storage-Parameter" -#: commands/tablecmds.c:3488 +#: commands/tablecmds.c:3498 #, c-format msgid "inherited column \"%s\" has a generation conflict" msgstr "geerbte Spalte »%s« hat einen Generierungskonflikt" -#: commands/tablecmds.c:3719 +#: commands/tablecmds.c:3729 #, c-format msgid "cannot move temporary tables of other sessions" msgstr "temporäre Tabellen anderer Sitzungen können nicht verschoben werden" -#: commands/tablecmds.c:3792 +#: commands/tablecmds.c:3802 #, c-format msgid "cannot rename column of typed table" msgstr "Spalte einer getypten Tabelle kann nicht umbenannt werden" -#: commands/tablecmds.c:3811 +#: commands/tablecmds.c:3821 #, c-format msgid "cannot rename columns of relation \"%s\"" msgstr "Spalten von Relation »%s« können nicht umbenannt werden" -#: commands/tablecmds.c:3906 +#: commands/tablecmds.c:3916 #, c-format msgid "inherited column \"%s\" must be renamed in child tables too" msgstr "vererbte Spalte »%s« muss ebenso in den abgeleiteten Tabellen umbenannt werden" -#: commands/tablecmds.c:3938 +#: commands/tablecmds.c:3948 #, c-format msgid "cannot rename system column \"%s\"" msgstr "Systemspalte »%s« kann nicht umbenannt werden" -#: commands/tablecmds.c:3953 +#: commands/tablecmds.c:3963 #, c-format msgid "cannot rename inherited column \"%s\"" msgstr "kann vererbte Spalte »%s« nicht umbenennen" -#: commands/tablecmds.c:4108 +#: commands/tablecmds.c:4118 #, c-format msgid "inherited constraint \"%s\" must be renamed in child tables too" msgstr "vererbter Constraint »%s« muss ebenso in den abgeleiteten Tabellen umbenannt werden" -#: commands/tablecmds.c:4115 +#: commands/tablecmds.c:4125 #, c-format msgid "cannot rename inherited constraint \"%s\"" msgstr "kann vererbten Constraint »%s« nicht umbenennen" #. translator: first %s is a SQL command, eg ALTER TABLE -#: commands/tablecmds.c:4415 +#: commands/tablecmds.c:4425 #, c-format msgid "cannot %s \"%s\" because it is being used by active queries in this session" msgstr "%s mit Relation »%s« nicht möglich, weil sie von aktiven Anfragen in dieser Sitzung verwendet wird" #. translator: first %s is a SQL command, eg ALTER TABLE -#: commands/tablecmds.c:4424 +#: commands/tablecmds.c:4434 #, c-format msgid "cannot %s \"%s\" because it has pending trigger events" msgstr "%s mit Relation »%s« nicht möglich, weil es anstehende Trigger-Ereignisse dafür gibt" -#: commands/tablecmds.c:4450 +#: commands/tablecmds.c:4460 #, c-format msgid "cannot alter temporary tables of other sessions" msgstr "kann temporäre Tabellen anderer Sitzungen nicht ändern" -#: commands/tablecmds.c:4914 +#: commands/tablecmds.c:4924 #, c-format msgid "cannot alter partition \"%s\" with an incomplete detach" msgstr "kann Partition »%s« mit einer unvollständigen Abtrennoperation nicht ändern" -#: commands/tablecmds.c:5143 +#: commands/tablecmds.c:5153 #, c-format msgid "cannot change persistence setting twice" msgstr "Persistenzeinstellung kann nicht zweimal geändert werden" -#: commands/tablecmds.c:5160 +#: commands/tablecmds.c:5170 #, c-format msgid "cannot have multiple SET ACCESS METHOD subcommands" msgstr "mehrere SET ACCESS METHOD Unterbefehle sind ungültig" -#: commands/tablecmds.c:5894 +#: commands/tablecmds.c:5904 #, c-format msgid "cannot rewrite system relation \"%s\"" msgstr "Systemrelation »%s« kann nicht neu geschrieben werden" -#: commands/tablecmds.c:5900 +#: commands/tablecmds.c:5910 #, c-format msgid "cannot rewrite table \"%s\" used as a catalog table" msgstr "Tabelle »%s«, die als Katalogtabelle verwendet wird, kann nicht neu geschrieben werden" -#: commands/tablecmds.c:5912 +#: commands/tablecmds.c:5922 #, c-format msgid "cannot rewrite temporary tables of other sessions" msgstr "kann temporäre Tabellen anderer Sitzungen nicht neu schreiben" -#: commands/tablecmds.c:6448 commands/tablecmds.c:6468 +#: commands/tablecmds.c:6458 commands/tablecmds.c:6478 #, c-format msgid "column \"%s\" of relation \"%s\" contains null values" msgstr "Spalte »%s« von Relation »%s« enthält NULL-Werte" -#: commands/tablecmds.c:6485 +#: commands/tablecmds.c:6495 #, c-format msgid "check constraint \"%s\" of relation \"%s\" is violated by some row" msgstr "Check-Constraint »%s« von Relation »%s« wird von irgendeiner Zeile verletzt" -#: commands/tablecmds.c:6505 partitioning/partbounds.c:3387 +#: commands/tablecmds.c:6515 partitioning/partbounds.c:3387 #, c-format msgid "updated partition constraint for default partition \"%s\" would be violated by some row" msgstr "aktualisierter Partitions-Constraint der Standardpartition »%s« würde von irgendeiner Zeile verletzt werden" -#: commands/tablecmds.c:6511 +#: commands/tablecmds.c:6521 #, c-format msgid "partition constraint of relation \"%s\" is violated by some row" msgstr "Partitions-Constraint von Relation »%s« wird von irgendeiner Zeile verletzt" #. translator: %s is a group of some SQL keywords -#: commands/tablecmds.c:6776 +#: commands/tablecmds.c:6786 #, c-format msgid "ALTER action %s cannot be performed on relation \"%s\"" msgstr "ALTER-Aktion %s kann nicht mit Relation »%s« ausgeführt werden" -#: commands/tablecmds.c:7031 commands/tablecmds.c:7038 +#: commands/tablecmds.c:7041 commands/tablecmds.c:7048 #, c-format msgid "cannot alter type \"%s\" because column \"%s.%s\" uses it" msgstr "kann Typ »%s« nicht ändern, weil Spalte »%s.%s« ihn verwendet" -#: commands/tablecmds.c:7045 +#: commands/tablecmds.c:7055 #, c-format msgid "cannot alter foreign table \"%s\" because column \"%s.%s\" uses its row type" msgstr "kann Fremdtabelle »%s« nicht ändern, weil Spalte »%s.%s« ihren Zeilentyp verwendet" -#: commands/tablecmds.c:7052 +#: commands/tablecmds.c:7062 #, c-format msgid "cannot alter table \"%s\" because column \"%s.%s\" uses its row type" msgstr "kann Tabelle »%s« nicht ändern, weil Spalte »%s.%s« ihren Zeilentyp verwendet" -#: commands/tablecmds.c:7108 +#: commands/tablecmds.c:7118 #, c-format msgid "cannot alter type \"%s\" because it is the type of a typed table" msgstr "kann Typ »%s« nicht ändern, weil er der Typ einer getypten Tabelle ist" -#: commands/tablecmds.c:7110 +#: commands/tablecmds.c:7120 #, c-format msgid "Use ALTER ... CASCADE to alter the typed tables too." msgstr "Verwenden Sie ALTER ... CASCADE, um die getypten Tabellen ebenfalls zu ändern." -#: commands/tablecmds.c:7156 +#: commands/tablecmds.c:7166 #, c-format msgid "type %s is the row type of another table" msgstr "Typ %s ist der Zeilentyp einer anderen Tabelle" -#: commands/tablecmds.c:7158 +#: commands/tablecmds.c:7168 #, c-format msgid "A typed table must use a stand-alone composite type created with CREATE TYPE." msgstr "Eine getypte Tabelle muss einen alleinstehenden mit CREATE TYPE erzeugten Typ verwenden." -#: commands/tablecmds.c:7163 +#: commands/tablecmds.c:7173 #, c-format msgid "type %s is not a composite type" msgstr "Typ %s ist kein zusammengesetzter Typ" -#: commands/tablecmds.c:7190 +#: commands/tablecmds.c:7200 #, c-format msgid "cannot add column to typed table" msgstr "zu einer getypten Tabelle kann keine Spalte hinzugefügt werden" -#: commands/tablecmds.c:7240 +#: commands/tablecmds.c:7250 #, c-format msgid "cannot add column to a partition" msgstr "zu einer Partition kann keine Spalte hinzugefügt werden" -#: commands/tablecmds.c:7269 commands/tablecmds.c:17518 +#: commands/tablecmds.c:7279 commands/tablecmds.c:17530 #, c-format msgid "child table \"%s\" has different type for column \"%s\"" msgstr "abgeleitete Tabelle »%s« hat unterschiedlichen Typ für Spalte »%s«" -#: commands/tablecmds.c:7275 commands/tablecmds.c:17524 +#: commands/tablecmds.c:7285 commands/tablecmds.c:17536 #, c-format msgid "child table \"%s\" has different collation for column \"%s\"" msgstr "abgeleitete Tabelle »%s« hat unterschiedliche Sortierfolge für Spalte »%s«" -#: commands/tablecmds.c:7293 +#: commands/tablecmds.c:7303 #, c-format msgid "merging definition of column \"%s\" for child \"%s\"" msgstr "Definition von Spalte »%s« für abgeleitete Tabelle »%s« wird zusammengeführt" -#: commands/tablecmds.c:7346 +#: commands/tablecmds.c:7356 #, c-format msgid "cannot recursively add identity column to table that has child tables" msgstr "eine Identitätsspalte kann nicht rekursiv zu einer Tabelle hinzugefügt werden, die abgeleitete Tabellen hat" -#: commands/tablecmds.c:7593 +#: commands/tablecmds.c:7603 #, c-format msgid "column must be added to child tables too" msgstr "Spalte muss ebenso in den abgeleiteten Tabellen hinzugefügt werden" -#: commands/tablecmds.c:7671 +#: commands/tablecmds.c:7681 #, c-format msgid "column \"%s\" of relation \"%s\" already exists, skipping" msgstr "Spalte »%s« von Relation »%s« existiert bereits, wird übersprungen" -#: commands/tablecmds.c:7678 +#: commands/tablecmds.c:7688 #, c-format msgid "column \"%s\" of relation \"%s\" already exists" msgstr "Spalte »%s« von Relation »%s« existiert bereits" -#: commands/tablecmds.c:7769 commands/tablecmds.c:7936 -#: commands/tablecmds.c:8137 commands/tablecmds.c:8268 -#: commands/tablecmds.c:8422 commands/tablecmds.c:8516 -#: commands/tablecmds.c:8619 commands/tablecmds.c:8815 -#: commands/tablecmds.c:8981 commands/tablecmds.c:9072 -#: commands/tablecmds.c:9206 commands/tablecmds.c:14407 -#: commands/tablecmds.c:15998 commands/tablecmds.c:18765 +#: commands/tablecmds.c:7779 commands/tablecmds.c:7946 +#: commands/tablecmds.c:8147 commands/tablecmds.c:8278 +#: commands/tablecmds.c:8432 commands/tablecmds.c:8526 +#: commands/tablecmds.c:8629 commands/tablecmds.c:8825 +#: commands/tablecmds.c:8991 commands/tablecmds.c:9082 +#: commands/tablecmds.c:9216 commands/tablecmds.c:14419 +#: commands/tablecmds.c:16010 commands/tablecmds.c:18777 #, c-format msgid "cannot alter system column \"%s\"" msgstr "Systemspalte »%s« kann nicht geändert werden" -#: commands/tablecmds.c:7775 commands/tablecmds.c:8143 -#: commands/tablecmds.c:14168 +#: commands/tablecmds.c:7785 commands/tablecmds.c:8153 +#: commands/tablecmds.c:14180 #, c-format msgid "column \"%s\" of relation \"%s\" is an identity column" msgstr "Spalte »%s« von Relation »%s« ist eine Identitätsspalte" -#: commands/tablecmds.c:7792 +#: commands/tablecmds.c:7802 #, c-format msgid "column \"%s\" is marked NOT NULL in parent table" msgstr "Spalte »%s« ist in Elterntabelle als NOT NULL markiert" -#: commands/tablecmds.c:8014 commands/tablecmds.c:10013 +#: commands/tablecmds.c:8024 commands/tablecmds.c:10023 #, c-format msgid "constraint must be added to child tables too" msgstr "Constraint muss ebenso in den abgeleiteten Tabellen hinzugefügt werden" -#: commands/tablecmds.c:8015 commands/tablecmds.c:8246 -#: commands/tablecmds.c:8378 commands/tablecmds.c:8495 -#: commands/tablecmds.c:9379 commands/tablecmds.c:12207 +#: commands/tablecmds.c:8025 commands/tablecmds.c:8256 +#: commands/tablecmds.c:8388 commands/tablecmds.c:8505 +#: commands/tablecmds.c:9389 commands/tablecmds.c:12217 #, c-format msgid "Do not specify the ONLY keyword." msgstr "Lassen Sie das Schlüsselwort ONLY weg." -#: commands/tablecmds.c:8152 +#: commands/tablecmds.c:8162 #, c-format msgid "column \"%s\" of relation \"%s\" is a generated column" msgstr "Spalte »%s« von Relation »%s« ist eine generierte Spalte" -#: commands/tablecmds.c:8245 +#: commands/tablecmds.c:8255 #, c-format msgid "cannot add identity to a column of only the partitioned table" msgstr "Identität kann nicht einer Spalte nur in der partitionierten Tabelle hinzugefügt werden" -#: commands/tablecmds.c:8251 +#: commands/tablecmds.c:8261 #, c-format msgid "cannot add identity to a column of a partition" msgstr "zu einer Spalte einer Partition kann keine Identität hinzugefügt werden" -#: commands/tablecmds.c:8279 +#: commands/tablecmds.c:8289 #, c-format msgid "column \"%s\" of relation \"%s\" must be declared NOT NULL before identity can be added" msgstr "Spalte »%s« von Relation »%s« muss als NOT NULL deklariert werden, bevor Sie Identitätsspalte werden kann" -#: commands/tablecmds.c:8310 +#: commands/tablecmds.c:8320 #, c-format msgid "column \"%s\" of relation \"%s\" is already an identity column" msgstr "Spalte »%s« von Relation »%s« ist bereits eine Identitätsspalte" -#: commands/tablecmds.c:8316 +#: commands/tablecmds.c:8326 #, c-format msgid "column \"%s\" of relation \"%s\" already has a default value" msgstr "Spalte »%s« von Relation »%s« hat bereits einen Vorgabewert" -#: commands/tablecmds.c:8377 +#: commands/tablecmds.c:8387 #, c-format msgid "cannot change identity column of only the partitioned table" msgstr "Identitätsspalte kann nicht nur in der partitionierten Tabelle geändert werden" -#: commands/tablecmds.c:8383 +#: commands/tablecmds.c:8393 #, c-format msgid "cannot change identity column of a partition" msgstr "Identitätsspalte einer Partition kann nicht geändert werden" -#: commands/tablecmds.c:8428 commands/tablecmds.c:8524 +#: commands/tablecmds.c:8438 commands/tablecmds.c:8534 #, c-format msgid "column \"%s\" of relation \"%s\" is not an identity column" msgstr "Spalte »%s« von Relation »%s« ist keine Identitätsspalte" -#: commands/tablecmds.c:8494 +#: commands/tablecmds.c:8504 #, c-format msgid "cannot drop identity from a column of only the partitioned table" msgstr "Identität kann nicht von einer Spalte nur in der partitionierten Tabelle gelöscht werden" -#: commands/tablecmds.c:8500 +#: commands/tablecmds.c:8510 #, c-format msgid "cannot drop identity from a column of a partition" msgstr "Identität kann nicht von einer Spalte einer Partition gelöscht werden" -#: commands/tablecmds.c:8529 +#: commands/tablecmds.c:8539 #, c-format msgid "column \"%s\" of relation \"%s\" is not an identity column, skipping" msgstr "Spalte »%s« von Relation »%s« ist keine Identitätsspalte, wird übersprungen" -#: commands/tablecmds.c:8626 commands/tablecmds.c:8836 +#: commands/tablecmds.c:8636 commands/tablecmds.c:8846 #, c-format msgid "column \"%s\" of relation \"%s\" is not a generated column" msgstr "Spalte »%s« von Relation »%s« ist keine generierte Spalte" -#: commands/tablecmds.c:8637 +#: commands/tablecmds.c:8647 #, c-format msgid "ALTER TABLE / SET EXPRESSION is not supported for virtual generated columns in tables with check constraints" msgstr "ALTER TABLE / SET EXPRESSION wird nicht unterstützt für virtuelle generierte Spalten in Tabellen mit Check-Constraints" -#: commands/tablecmds.c:8638 commands/tablecmds.c:8656 -#: commands/tablecmds.c:8828 +#: commands/tablecmds.c:8648 commands/tablecmds.c:8666 +#: commands/tablecmds.c:8838 #, c-format msgid "Column \"%s\" of relation \"%s\" is a virtual generated column." msgstr "Spalte »%s« von Relation »%s« ist eine virtuelle generierte Spalte." -#: commands/tablecmds.c:8655 +#: commands/tablecmds.c:8665 #, c-format msgid "ALTER TABLE / SET EXPRESSION is not supported for virtual generated columns in tables that are part of a publication" msgstr "ALTER TABLE / SET EXPRESSION wird nicht unterstützt für virtuelle generierte Spalten in Tabellen, die Teil einer Publikation sind" -#: commands/tablecmds.c:8762 +#: commands/tablecmds.c:8772 #, c-format msgid "ALTER TABLE / DROP EXPRESSION must be applied to child tables too" msgstr "ALTER TABLE / DROP EXPRESSION muss auch auf abgeleitete Tabellen angewendet werden" -#: commands/tablecmds.c:8784 +#: commands/tablecmds.c:8794 #, c-format msgid "cannot drop generation expression from inherited column" msgstr "Generierungsausdruck von vererbter Spalte kann nicht gelöscht werden" -#: commands/tablecmds.c:8827 +#: commands/tablecmds.c:8837 #, c-format msgid "ALTER TABLE / DROP EXPRESSION is not supported for virtual generated columns" msgstr "ALTER TABLE / DROP EXPRESSION wird für virtuelle generierte Spalten nicht unterstützt" -#: commands/tablecmds.c:8841 +#: commands/tablecmds.c:8851 #, c-format msgid "column \"%s\" of relation \"%s\" is not a generated column, skipping" msgstr "Spalte »%s« von Relation »%s« ist keine generierte Spalte, wird übersprungen" -#: commands/tablecmds.c:8919 +#: commands/tablecmds.c:8929 #, c-format msgid "cannot refer to non-index column by number" msgstr "auf eine Nicht-Index-Spalte kann nicht per Nummer verwiesen werden" -#: commands/tablecmds.c:8971 +#: commands/tablecmds.c:8981 #, c-format msgid "column number %d of relation \"%s\" does not exist" msgstr "Spalte Nummer %d von Relation »%s« existiert nicht" -#: commands/tablecmds.c:8991 +#: commands/tablecmds.c:9001 #, c-format msgid "cannot alter statistics on virtual generated column \"%s\"" msgstr "Statistiken von virtueller generierter Spalte »%s« können nicht geändert werden" -#: commands/tablecmds.c:9000 +#: commands/tablecmds.c:9010 #, c-format msgid "cannot alter statistics on included column \"%s\" of index \"%s\"" msgstr "Statistiken von eingeschlossener Spalte »%s« von Index »%s« können nicht geändert werden" -#: commands/tablecmds.c:9005 +#: commands/tablecmds.c:9015 #, c-format msgid "cannot alter statistics on non-expression column \"%s\" of index \"%s\"" msgstr "kann Statistiken von Spalte »%s« von Index »%s«, welche kein Ausdruck ist, nicht ändern" -#: commands/tablecmds.c:9007 +#: commands/tablecmds.c:9017 #, c-format msgid "Alter statistics on table column instead." msgstr "Ändern Sie stattdessen die Statistiken für die Tabellenspalte." -#: commands/tablecmds.c:9253 +#: commands/tablecmds.c:9263 #, c-format msgid "cannot drop column from typed table" msgstr "aus einer getypten Tabelle können keine Spalten gelöscht werden" -#: commands/tablecmds.c:9317 +#: commands/tablecmds.c:9327 #, c-format msgid "column \"%s\" of relation \"%s\" does not exist, skipping" msgstr "Spalte »%s« von Relation »%s« existiert nicht, wird übersprungen" -#: commands/tablecmds.c:9330 +#: commands/tablecmds.c:9340 #, c-format msgid "cannot drop system column \"%s\"" msgstr "Systemspalte »%s« kann nicht gelöscht werden" -#: commands/tablecmds.c:9340 +#: commands/tablecmds.c:9350 #, c-format msgid "cannot drop inherited column \"%s\"" msgstr "geerbte Spalte »%s« kann nicht gelöscht werden" -#: commands/tablecmds.c:9353 +#: commands/tablecmds.c:9363 #, c-format msgid "cannot drop column \"%s\" because it is part of the partition key of relation \"%s\"" msgstr "Spalte »%s« kann nicht gelöscht werden, weil sie Teil des Partitionierungsschlüssels von Relation »%s« ist" -#: commands/tablecmds.c:9378 +#: commands/tablecmds.c:9388 #, c-format msgid "cannot drop column from only the partitioned table when partitions exist" msgstr "Spalte kann nicht nur aus der partitionierten Tabelle gelöscht werden, wenn Partitionen existieren" -#: commands/tablecmds.c:9543 +#: commands/tablecmds.c:9553 #, c-format msgid "column \"%s\" of table \"%s\" is not marked NOT NULL" msgstr "Spalte »%s« von Tabelle »%s« ist nicht als NOT NULL markiert" -#: commands/tablecmds.c:9579 commands/tablecmds.c:9591 +#: commands/tablecmds.c:9589 commands/tablecmds.c:9601 #, c-format msgid "cannot create primary key on column \"%s\"" msgstr "kann keinen Primärschlüssel über Spalte »%s« erzeugen" #. translator: fourth %s is a constraint characteristic such as NOT VALID -#: commands/tablecmds.c:9581 commands/tablecmds.c:9593 +#: commands/tablecmds.c:9591 commands/tablecmds.c:9603 #, c-format msgid "The constraint \"%s\" on column \"%s\" of table \"%s\", marked %s, is incompatible with a primary key." msgstr "Der Constraint »%s« für Spalte »%s« von Tabelle »%s«, markiert als %s, ist inkompatibel mit einem Primärschlüssel." -#: commands/tablecmds.c:9717 +#: commands/tablecmds.c:9727 #, c-format msgid "ALTER TABLE / ADD CONSTRAINT USING INDEX is not supported on partitioned tables" msgstr "ALTER TABLE / ADD CONSTRAINT USING INDEX wird für partitionierte Tabellen nicht unterstützt" -#: commands/tablecmds.c:9742 +#: commands/tablecmds.c:9752 #, c-format msgid "ALTER TABLE / ADD CONSTRAINT USING INDEX will rename index \"%s\" to \"%s\"" msgstr "ALTER TABLE / ADD CONSTRAINT USING INDEX benennt Index »%s« um in »%s«" -#: commands/tablecmds.c:10100 +#: commands/tablecmds.c:10110 #, c-format msgid "cannot use ONLY for foreign key on partitioned table \"%s\" referencing relation \"%s\"" msgstr "ONLY nicht möglich für Fremdschlüssel für partitionierte Tabelle »%s« verweisend auf Relation »%s«" -#: commands/tablecmds.c:10108 commands/tablecmds.c:10735 +#: commands/tablecmds.c:10118 commands/tablecmds.c:10745 #, c-format msgid "referenced relation \"%s\" is not a table" msgstr "Relation »%s«, auf die verwiesen wird, ist keine Tabelle" -#: commands/tablecmds.c:10131 +#: commands/tablecmds.c:10141 #, c-format msgid "constraints on permanent tables may reference only permanent tables" msgstr "Constraints für permanente Tabellen dürfen nur auf permanente Tabellen verweisen" -#: commands/tablecmds.c:10138 +#: commands/tablecmds.c:10148 #, c-format msgid "constraints on unlogged tables may reference only permanent or unlogged tables" msgstr "Constraints für ungeloggte Tabellen dürfen nur auf permanente oder ungeloggte Tabellen verweisen" -#: commands/tablecmds.c:10144 +#: commands/tablecmds.c:10154 #, c-format msgid "constraints on temporary tables may reference only temporary tables" msgstr "Constraints für temporäre Tabellen dürfen nur auf temporäre Tabellen verweisen" -#: commands/tablecmds.c:10148 +#: commands/tablecmds.c:10158 #, c-format msgid "constraints on temporary tables must involve temporary tables of this session" msgstr "Constraints für temporäre Tabellen müssen temporäre Tabellen dieser Sitzung beinhalten" -#: commands/tablecmds.c:10163 commands/tablecmds.c:10191 +#: commands/tablecmds.c:10173 commands/tablecmds.c:10201 #, c-format msgid "foreign key uses PERIOD on the referenced table but not the referencing table" msgstr "Fremdschlüssel verwendet PERIOD für die Tabelle, auf die verwiesen wird, aber nicht für die verweisende Tabelle" -#: commands/tablecmds.c:10203 +#: commands/tablecmds.c:10213 #, c-format msgid "foreign key uses PERIOD on the referencing table but not the referenced table" msgstr "Fremdschlüssel verwendet PERIOD für die verweisende Tabelle, aber nicht für die Tabelle, auf die verwiesen wird" -#: commands/tablecmds.c:10217 +#: commands/tablecmds.c:10227 #, c-format msgid "foreign key must use PERIOD when referencing a primary key using WITHOUT OVERLAPS" msgstr "Fremdschlüssel muss PERIOD verwenden, wenn auf einen Primärschlüssel verwiesen wird, der WITHOUT OVERLAPS verwendet" -#: commands/tablecmds.c:10241 commands/tablecmds.c:10247 +#: commands/tablecmds.c:10251 commands/tablecmds.c:10257 #, c-format msgid "invalid %s action for foreign key constraint containing generated column" msgstr "ungültige %s-Aktion für Fremdschlüssel-Constraint, der eine generierte Spalte enthält" -#: commands/tablecmds.c:10262 +#: commands/tablecmds.c:10272 #, c-format msgid "foreign key constraints on virtual generated columns are not supported" msgstr "Fremdschlüssel-Constraints für virtuelle generierte Spalten werden nicht unterstützt" -#: commands/tablecmds.c:10276 commands/tablecmds.c:10285 +#: commands/tablecmds.c:10286 commands/tablecmds.c:10295 #, c-format msgid "unsupported %s action for foreign key constraint using PERIOD" msgstr "nicht unterstützte %s-Aktion für Fremdschlüssel-Constraint, der PERIOD verwendet" -#: commands/tablecmds.c:10300 +#: commands/tablecmds.c:10310 #, c-format msgid "number of referencing and referenced columns for foreign key disagree" msgstr "Anzahl der Quell- und Zielspalten im Fremdschlüssel stimmt nicht überein" -#: commands/tablecmds.c:10356 +#: commands/tablecmds.c:10366 #, c-format msgid "could not identify an overlaps operator for foreign key" msgstr "konnte keinen Überlappungsoperator für den Fremdschlüssel ermitteln" -#: commands/tablecmds.c:10357 +#: commands/tablecmds.c:10367 #, c-format msgid "could not identify an equality operator for foreign key" msgstr "konnte keinen Ist-Gleich-Operator für den Fremdschlüssel ermitteln" -#: commands/tablecmds.c:10422 commands/tablecmds.c:10456 +#: commands/tablecmds.c:10432 commands/tablecmds.c:10466 #, c-format msgid "foreign key constraint \"%s\" cannot be implemented" msgstr "Fremdschlüssel-Constraint »%s« kann nicht implementiert werden" -#: commands/tablecmds.c:10424 +#: commands/tablecmds.c:10434 #, c-format msgid "Key columns \"%s\" of the referencing table and \"%s\" of the referenced table are of incompatible types: %s and %s." msgstr "Schlüsselspalten »%s« der referenzierenden Tabelle und »%s« der referenzierten Tabelle haben inkompatible Typen: %s und %s." -#: commands/tablecmds.c:10457 +#: commands/tablecmds.c:10467 #, c-format msgid "Key columns \"%s\" of the referencing table and \"%s\" of the referenced table have incompatible collations: \"%s\" and \"%s\". If either collation is nondeterministic, then both collations have to be the same." msgstr "Schlüsselspalten »%s« der referenzierenden Tabelle und »%s« der referenzierten Tabelle haben inkompatible Sortierfolgen: »%s« und »%s«. Wenn eine der Sortierfolgen nichtdeterministisch ist, dann müssen beide Sortierfolgen die selbe sein." -#: commands/tablecmds.c:10663 +#: commands/tablecmds.c:10673 #, c-format msgid "column \"%s\" referenced in ON DELETE SET action must be part of foreign key" msgstr "Spalte »%s«, auf die in der ON-DELETE-SET-Aktion verwiesen wird, muss Teil des Fremdschlüssels sein" -#: commands/tablecmds.c:11047 commands/tablecmds.c:11480 +#: commands/tablecmds.c:11057 commands/tablecmds.c:11490 #: parser/parse_utilcmd.c:941 parser/parse_utilcmd.c:1086 #, c-format msgid "foreign key constraints are not supported on foreign tables" msgstr "Fremdschlüssel-Constraints auf Fremdtabellen werden nicht unterstützt" -#: commands/tablecmds.c:11463 +#: commands/tablecmds.c:11473 #, c-format msgid "cannot attach table \"%s\" as a partition because it is referenced by foreign key \"%s\"" msgstr "kann Tabelle »%s« nicht als Partition anfügen, weil auf sie von Fremdschlüssel »%s« verwiesen wird" -#: commands/tablecmds.c:11744 +#: commands/tablecmds.c:11754 #, c-format msgid "constraint \"%s\" enforceability conflicts with constraint \"%s\" on relation \"%s\"" msgstr "ENFORCED-Einstellung von Constraint »%s« kollidiert mit Constraint »%s« für Relation »%s«" -#: commands/tablecmds.c:12206 +#: commands/tablecmds.c:12216 #, c-format msgid "constraint must be altered in child tables too" msgstr "Constraint muss ebenso in den abgeleiteten Tabellen geändert werden" -#: commands/tablecmds.c:12235 commands/tablecmds.c:12932 -#: commands/tablecmds.c:14047 commands/tablecmds.c:14276 +#: commands/tablecmds.c:12245 commands/tablecmds.c:12944 +#: commands/tablecmds.c:14059 commands/tablecmds.c:14288 #, c-format msgid "constraint \"%s\" of relation \"%s\" does not exist" msgstr "Constraint »%s« von Relation »%s« existiert nicht" -#: commands/tablecmds.c:12242 +#: commands/tablecmds.c:12252 #, c-format msgid "constraint \"%s\" of relation \"%s\" is not a foreign key constraint" msgstr "Constraint »%s« von Relation »%s« ist kein Fremdschlüssel-Constraint" -#: commands/tablecmds.c:12247 +#: commands/tablecmds.c:12257 #, c-format msgid "cannot alter enforceability of constraint \"%s\" of relation \"%s\"" msgstr "ENFORCED-Einstellung des Constraints »%s« von Relation »%s« kann nicht geändert werden" -#: commands/tablecmds.c:12253 +#: commands/tablecmds.c:12263 #, c-format msgid "constraint \"%s\" of relation \"%s\" is not a not-null constraint" msgstr "Constraint »%s« von Relation »%s« ist kein Not-Null-Constraint" -#: commands/tablecmds.c:12261 +#: commands/tablecmds.c:12271 #, c-format msgid "cannot alter inherited constraint \"%s\" on relation \"%s\"" msgstr "geerbter Constraint »%s« von Relation »%s« kann nicht geändert werden" -#: commands/tablecmds.c:12301 +#: commands/tablecmds.c:12311 #, c-format msgid "cannot alter constraint \"%s\" on relation \"%s\"" msgstr "Constraint »%s« von Relation »%s« kann nicht geändert werden" -#: commands/tablecmds.c:12304 +#: commands/tablecmds.c:12314 #, c-format msgid "Constraint \"%s\" is derived from constraint \"%s\" of relation \"%s\"." msgstr "Constraint »%s« ist von Constraint »%s« von Relation »%s« abgeleitet." -#: commands/tablecmds.c:12306 +#: commands/tablecmds.c:12316 #, c-format msgid "You may alter the constraint it derives from instead." msgstr "Sie können stattdessen den Constraint, von dem er abgeleitet ist, ändern." -#: commands/tablecmds.c:12941 +#: commands/tablecmds.c:12953 #, c-format msgid "cannot validate constraint \"%s\" of relation \"%s\"" msgstr "Constraint »%s« von Relation »%s« kann nicht validiert werden" -#: commands/tablecmds.c:12943 +#: commands/tablecmds.c:12955 #, c-format msgid "This operation is not supported for this type of constraint." msgstr "Diese Operation wird für diese Art von Constraint nicht unterstützt." -#: commands/tablecmds.c:12948 +#: commands/tablecmds.c:12960 #, c-format msgid "cannot validate NOT ENFORCED constraint" msgstr "auf NOT ENFORCED gesetzter Constraint kann nicht validiert werden" -#: commands/tablecmds.c:13157 commands/tablecmds.c:13257 +#: commands/tablecmds.c:13169 commands/tablecmds.c:13269 #, c-format msgid "constraint must be validated on child tables too" msgstr "Constraint muss ebenso in den abgeleiteten Tabellen validiert werden" -#: commands/tablecmds.c:13334 +#: commands/tablecmds.c:13346 #, c-format msgid "column \"%s\" referenced in foreign key constraint does not exist" msgstr "Spalte »%s«, die im Fremdschlüssel verwendet wird, existiert nicht" -#: commands/tablecmds.c:13340 +#: commands/tablecmds.c:13352 #, c-format msgid "system columns cannot be used in foreign keys" msgstr "Systemspalten können nicht in Fremdschlüsseln verwendet werden" -#: commands/tablecmds.c:13344 +#: commands/tablecmds.c:13356 #, c-format msgid "cannot have more than %d keys in a foreign key" msgstr "Fremdschlüssel kann nicht mehr als %d Schlüssel haben" -#: commands/tablecmds.c:13412 +#: commands/tablecmds.c:13424 #, c-format msgid "cannot use a deferrable primary key for referenced table \"%s\"" msgstr "aufschiebbarer Primärschlüssel kann nicht für Tabelle »%s«, auf die verwiesen wird, verwendet werden" -#: commands/tablecmds.c:13429 +#: commands/tablecmds.c:13441 #, c-format msgid "there is no primary key for referenced table \"%s\"" msgstr "in Tabelle »%s«, auf die verwiesen wird, gibt es keinen Primärschlüssel" -#: commands/tablecmds.c:13502 +#: commands/tablecmds.c:13514 #, c-format msgid "foreign key referenced-columns list must not contain duplicates" msgstr "die Liste der Spalten, auf die ein Fremdschlüssel verweist, darf keine doppelten Einträge enthalten" -#: commands/tablecmds.c:13605 +#: commands/tablecmds.c:13617 #, c-format msgid "cannot use a deferrable unique constraint for referenced table \"%s\"" msgstr "aufschiebbarer Unique-Constraint kann nicht für Tabelle »%s«, auf die verwiesen wird, verwendet werden" -#: commands/tablecmds.c:13610 +#: commands/tablecmds.c:13622 #, c-format msgid "there is no unique constraint matching given keys for referenced table \"%s\"" msgstr "in Tabelle »%s«, auf die verwiesen wird, gibt es keinen Unique-Constraint, der auf die angegebenen Schlüssel passt" -#: commands/tablecmds.c:14051 +#: commands/tablecmds.c:14063 #, c-format msgid "constraint \"%s\" of relation \"%s\" does not exist, skipping" msgstr "Constraint »%s« von Relation »%s« existiert nicht, wird übersprungen" -#: commands/tablecmds.c:14096 +#: commands/tablecmds.c:14108 #, c-format msgid "cannot drop inherited constraint \"%s\" of relation \"%s\"" msgstr "geerbter Constraint »%s« von Relation »%s« kann nicht gelöscht werden" -#: commands/tablecmds.c:14148 +#: commands/tablecmds.c:14160 #, c-format msgid "column \"%s\" is in a primary key" msgstr "Spalte »%s« ist in einem Primärschlüssel" -#: commands/tablecmds.c:14156 +#: commands/tablecmds.c:14168 #, c-format msgid "column \"%s\" is in index used as replica identity" msgstr "Spalte »%s« ist in einem Index, der als Replik-Identität verwendet wird" -#: commands/tablecmds.c:14389 +#: commands/tablecmds.c:14401 #, c-format msgid "cannot alter column type of typed table" msgstr "Spaltentyp einer getypten Tabelle kann nicht geändert werden" -#: commands/tablecmds.c:14417 +#: commands/tablecmds.c:14429 #, c-format msgid "cannot specify USING when altering type of generated column" msgstr "USING kann nicht angegeben werden, wenn der Typ einer generierten Spalte geändert wird" -#: commands/tablecmds.c:14429 +#: commands/tablecmds.c:14441 #, c-format msgid "cannot alter inherited column \"%s\"" msgstr "kann vererbte Spalte »%s« nicht ändern" -#: commands/tablecmds.c:14438 +#: commands/tablecmds.c:14450 #, c-format msgid "cannot alter column \"%s\" because it is part of the partition key of relation \"%s\"" msgstr "Spalte »%s« kann nicht geändert werden, weil sie Teil des Partitionierungsschlüssels von Relation »%s« ist" -#: commands/tablecmds.c:14493 +#: commands/tablecmds.c:14505 #, c-format msgid "result of USING clause for column \"%s\" cannot be cast automatically to type %s" msgstr "Ergebnis der USING-Klausel für Spalte »%s« kann nicht automatisch in Typ %s umgewandelt werden" -#: commands/tablecmds.c:14496 +#: commands/tablecmds.c:14508 #, c-format msgid "You might need to add an explicit cast." msgstr "Sie müssen möglicherweise eine ausdrückliche Typumwandlung hinzufügen." -#: commands/tablecmds.c:14500 +#: commands/tablecmds.c:14512 #, c-format msgid "column \"%s\" cannot be cast automatically to type %s" msgstr "Spalte »%s« kann nicht automatisch in Typ %s umgewandelt werden" #. translator: USING is SQL, don't translate it -#: commands/tablecmds.c:14504 +#: commands/tablecmds.c:14516 #, c-format msgid "You might need to specify \"USING %s::%s\"." msgstr "Sie müssen möglicherweise »USING %s::%s« angeben." -#: commands/tablecmds.c:14607 +#: commands/tablecmds.c:14619 #, c-format msgid "cannot alter inherited column \"%s\" of relation \"%s\"" msgstr "geerbte Spalte »%s« von Relation »%s« kann nicht geändert werden" -#: commands/tablecmds.c:14636 +#: commands/tablecmds.c:14648 #, c-format msgid "USING expression contains a whole-row table reference." msgstr "USING-Ausdruck enthält einen Verweis auf die ganze Zeile der Tabelle." -#: commands/tablecmds.c:14647 +#: commands/tablecmds.c:14659 #, c-format msgid "type of inherited column \"%s\" must be changed in child tables too" msgstr "Typ der vererbten Spalte »%s« muss ebenso in den abgeleiteten Tabellen geändert werden" -#: commands/tablecmds.c:14772 +#: commands/tablecmds.c:14784 #, c-format msgid "cannot alter type of column \"%s\" twice" msgstr "Typ der Spalte »%s« kann nicht zweimal geändert werden" -#: commands/tablecmds.c:14810 +#: commands/tablecmds.c:14822 #, c-format msgid "generation expression for column \"%s\" cannot be cast automatically to type %s" msgstr "Generierungsausdruck der Spalte »%s« kann nicht automatisch in Typ %s umgewandelt werden" -#: commands/tablecmds.c:14815 +#: commands/tablecmds.c:14827 #, c-format msgid "default for column \"%s\" cannot be cast automatically to type %s" msgstr "Vorgabewert der Spalte »%s« kann nicht automatisch in Typ %s umgewandelt werden" -#: commands/tablecmds.c:15119 +#: commands/tablecmds.c:15131 #, c-format msgid "cannot alter type of a column used by a function or procedure" msgstr "Typ einer Spalte, die von einer Funktion oder Prozedur verwendet wird, kann nicht geändert werden" -#: commands/tablecmds.c:15120 commands/tablecmds.c:15135 -#: commands/tablecmds.c:15155 commands/tablecmds.c:15174 -#: commands/tablecmds.c:15233 +#: commands/tablecmds.c:15132 commands/tablecmds.c:15147 +#: commands/tablecmds.c:15167 commands/tablecmds.c:15186 +#: commands/tablecmds.c:15245 #, c-format msgid "%s depends on column \"%s\"" msgstr "%s hängt von Spalte »%s« ab" -#: commands/tablecmds.c:15134 +#: commands/tablecmds.c:15146 #, c-format msgid "cannot alter type of a column used by a view or rule" msgstr "Typ einer Spalte, die von einer Sicht oder Regel verwendet wird, kann nicht geändert werden" -#: commands/tablecmds.c:15154 +#: commands/tablecmds.c:15166 #, c-format msgid "cannot alter type of a column used in a trigger definition" msgstr "Typ einer Spalte, die in einer Trigger-Definition verwendet wird, kann nicht geändert werden" -#: commands/tablecmds.c:15173 +#: commands/tablecmds.c:15185 #, c-format msgid "cannot alter type of a column used in a policy definition" msgstr "Typ einer Spalte, die in einer Policy-Definition verwendet wird, kann nicht geändert werden" -#: commands/tablecmds.c:15204 +#: commands/tablecmds.c:15216 #, c-format msgid "cannot alter type of a column used by a generated column" msgstr "Typ einer Spalte, die von einer generierten Spalte verwendet wird, kann nicht geändert werden" -#: commands/tablecmds.c:15205 +#: commands/tablecmds.c:15217 #, c-format msgid "Column \"%s\" is used by generated column \"%s\"." msgstr "Spalte »%s« wird von generierter Spalte »%s« verwendet." -#: commands/tablecmds.c:15232 +#: commands/tablecmds.c:15244 #, c-format msgid "cannot alter type of a column used by a publication WHERE clause" msgstr "Typ einer Spalte, die in der WHERE-Klausel einer Publikation verwendet wird, kann nicht geändert werden" -#: commands/tablecmds.c:16106 commands/tablecmds.c:16118 +#: commands/tablecmds.c:16118 commands/tablecmds.c:16130 #, c-format msgid "cannot change owner of index \"%s\"" msgstr "kann Eigentümer des Index »%s« nicht ändern" -#: commands/tablecmds.c:16108 commands/tablecmds.c:16120 +#: commands/tablecmds.c:16120 commands/tablecmds.c:16132 #, c-format msgid "Change the ownership of the index's table instead." msgstr "Ändern Sie stattdessen den Eigentümer der Tabelle des Index." -#: commands/tablecmds.c:16134 +#: commands/tablecmds.c:16146 #, c-format msgid "cannot change owner of sequence \"%s\"" msgstr "kann Eigentümer der Sequenz »%s« nicht ändern" -#: commands/tablecmds.c:16159 +#: commands/tablecmds.c:16171 #, c-format msgid "cannot change owner of relation \"%s\"" msgstr "kann Eigentümer der Relation »%s« nicht ändern" -#: commands/tablecmds.c:16626 +#: commands/tablecmds.c:16638 #, c-format msgid "cannot have multiple SET TABLESPACE subcommands" msgstr "mehrere SET TABLESPACE Unterbefehle sind ungültig" -#: commands/tablecmds.c:16705 +#: commands/tablecmds.c:16717 #, c-format msgid "cannot set options for relation \"%s\"" msgstr "für Relation »%s« können keine Optionen gesetzt werden" -#: commands/tablecmds.c:16739 commands/view.c:440 +#: commands/tablecmds.c:16751 commands/view.c:440 #, c-format msgid "WITH CHECK OPTION is supported only on automatically updatable views" msgstr "WITH CHECK OPTION wird nur für automatisch aktualisierbare Sichten unterstützt" -#: commands/tablecmds.c:16992 +#: commands/tablecmds.c:17004 #, c-format msgid "only tables, indexes, and materialized views exist in tablespaces" msgstr "nur Tabellen, Indexe und materialisierte Sichten existieren in Tablespaces" -#: commands/tablecmds.c:17004 +#: commands/tablecmds.c:17016 #, c-format msgid "cannot move relations in to or out of pg_global tablespace" msgstr "Relationen können nicht in den oder aus dem Tablespace »pg_global« verschoben werden" -#: commands/tablecmds.c:17096 +#: commands/tablecmds.c:17108 #, c-format msgid "aborting because lock on relation \"%s.%s\" is not available" msgstr "Abbruch weil Sperre für Relation »%s.%s« nicht verfügbar ist" -#: commands/tablecmds.c:17112 +#: commands/tablecmds.c:17124 #, c-format msgid "no matching relations in tablespace \"%s\" found" msgstr "keine passenden Relationen in Tablespace »%s« gefunden" -#: commands/tablecmds.c:17234 +#: commands/tablecmds.c:17246 #, c-format msgid "cannot change inheritance of typed table" msgstr "Vererbung einer getypten Tabelle kann nicht geändert werden" -#: commands/tablecmds.c:17239 commands/tablecmds.c:17823 +#: commands/tablecmds.c:17251 commands/tablecmds.c:17835 #, c-format msgid "cannot change inheritance of a partition" msgstr "Vererbung einer Partition kann nicht geändert werden" -#: commands/tablecmds.c:17244 +#: commands/tablecmds.c:17256 #, c-format msgid "cannot change inheritance of partitioned table" msgstr "Vererbung einer partitionierten Tabelle kann nicht geändert werden" -#: commands/tablecmds.c:17291 +#: commands/tablecmds.c:17303 #, c-format msgid "cannot inherit to temporary relation of another session" msgstr "an temporäre Relation einer anderen Sitzung kann nicht vererbt werden" -#: commands/tablecmds.c:17304 +#: commands/tablecmds.c:17316 #, c-format msgid "cannot inherit from a partition" msgstr "von einer Partition kann nicht geerbt werden" -#: commands/tablecmds.c:17326 commands/tablecmds.c:20347 +#: commands/tablecmds.c:17338 commands/tablecmds.c:20359 #, c-format msgid "circular inheritance not allowed" msgstr "zirkuläre Vererbung ist nicht erlaubt" -#: commands/tablecmds.c:17327 commands/tablecmds.c:20348 +#: commands/tablecmds.c:17339 commands/tablecmds.c:20360 #, c-format msgid "\"%s\" is already a child of \"%s\"." msgstr "»%s« ist schon von »%s« abgeleitet." -#: commands/tablecmds.c:17340 +#: commands/tablecmds.c:17352 #, c-format msgid "trigger \"%s\" prevents table \"%s\" from becoming an inheritance child" msgstr "Trigger »%s« verhindert, dass Tabelle »%s« ein Vererbungskind werden kann" -#: commands/tablecmds.c:17342 +#: commands/tablecmds.c:17354 #, c-format msgid "ROW triggers with transition tables are not supported in inheritance hierarchies." msgstr "ROW-Trigger mit Übergangstabellen werden in Vererbungshierarchien nicht unterstützt." -#: commands/tablecmds.c:17543 commands/tablecmds.c:17792 +#: commands/tablecmds.c:17555 commands/tablecmds.c:17804 #, c-format msgid "column \"%s\" in child table \"%s\" must be marked NOT NULL" msgstr "Spalte »%s« in abgeleiteter Tabelle »%s« muss als NOT NULL markiert sein" -#: commands/tablecmds.c:17553 +#: commands/tablecmds.c:17565 #, c-format msgid "column \"%s\" in child table must be a generated column" msgstr "Spalte »%s« in abgeleiteter Tabelle muss eine generierte Spalte sein" -#: commands/tablecmds.c:17557 +#: commands/tablecmds.c:17569 #, c-format msgid "column \"%s\" in child table must not be a generated column" msgstr "Spalte »%s« in abgeleiteter Tabelle darf keine generierte Spalte sein" -#: commands/tablecmds.c:17603 +#: commands/tablecmds.c:17615 #, c-format msgid "child table is missing column \"%s\"" msgstr "Spalte »%s« fehlt in abgeleiteter Tabelle" -#: commands/tablecmds.c:17720 +#: commands/tablecmds.c:17732 #, c-format msgid "child table \"%s\" has different definition for check constraint \"%s\"" msgstr "abgeleitete Tabelle »%s« hat unterschiedliche Definition für Check-Constraint »%s«" -#: commands/tablecmds.c:17729 +#: commands/tablecmds.c:17741 #, c-format msgid "constraint \"%s\" conflicts with non-inherited constraint on child table \"%s\"" msgstr "Constraint »%s« kollidiert mit nicht vererbtem Constraint für abgeleitete Tabelle »%s«" -#: commands/tablecmds.c:17740 +#: commands/tablecmds.c:17752 #, c-format msgid "constraint \"%s\" conflicts with NOT VALID constraint on child table \"%s\"" msgstr "Constraint »%s« kollidiert mit NOT-VALID-Constraint für abgeleitete Tabelle »%s«" -#: commands/tablecmds.c:17751 +#: commands/tablecmds.c:17763 #, c-format msgid "constraint \"%s\" conflicts with NOT ENFORCED constraint on child table \"%s\"" msgstr "Constraint »%s« kollidiert mit NOT-ENFORCED-Constraint für abgeleitete Tabelle »%s«" -#: commands/tablecmds.c:17800 +#: commands/tablecmds.c:17812 #, c-format msgid "child table is missing constraint \"%s\"" msgstr "Constraint »%s« fehlt in abgeleiteter Tabelle" -#: commands/tablecmds.c:17887 +#: commands/tablecmds.c:17899 #, c-format msgid "partition \"%s\" already pending detach in partitioned table \"%s.%s\"" msgstr "Partition »%s« hat schon eine unerledigte Abtrennoperation in der partitionierten Tabelle »%s.%s«" -#: commands/tablecmds.c:17916 commands/tablecmds.c:17964 +#: commands/tablecmds.c:17928 commands/tablecmds.c:17976 #, c-format msgid "relation \"%s\" is not a partition of relation \"%s\"" msgstr "Relation »%s« ist keine Partition von Relation »%s«" -#: commands/tablecmds.c:17970 +#: commands/tablecmds.c:17982 #, c-format msgid "relation \"%s\" is not a parent of relation \"%s\"" msgstr "Relation »%s« ist keine Basisrelation von Relation »%s«" -#: commands/tablecmds.c:18241 +#: commands/tablecmds.c:18253 #, c-format msgid "typed tables cannot inherit" msgstr "getypte Tabellen können nicht erben" -#: commands/tablecmds.c:18271 +#: commands/tablecmds.c:18283 #, c-format msgid "table is missing column \"%s\"" msgstr "Spalte »%s« fehlt in Tabelle" -#: commands/tablecmds.c:18282 +#: commands/tablecmds.c:18294 #, c-format msgid "table has column \"%s\" where type requires \"%s\"" msgstr "Tabelle hat Spalte »%s«, aber Typ benötigt »%s«" -#: commands/tablecmds.c:18291 +#: commands/tablecmds.c:18303 #, c-format msgid "table \"%s\" has different type for column \"%s\"" msgstr "Tabelle »%s« hat unterschiedlichen Typ für Spalte »%s«" -#: commands/tablecmds.c:18305 +#: commands/tablecmds.c:18317 #, c-format msgid "table has extra column \"%s\"" msgstr "Tabelle hat zusätzliche Spalte »%s«" -#: commands/tablecmds.c:18357 +#: commands/tablecmds.c:18369 #, c-format msgid "\"%s\" is not a typed table" msgstr "»%s« ist keine getypte Tabelle" -#: commands/tablecmds.c:18537 +#: commands/tablecmds.c:18549 #, c-format msgid "cannot use non-unique index \"%s\" as replica identity" msgstr "nicht eindeutiger Index »%s« kann nicht als Replik-Identität verwendet werden" -#: commands/tablecmds.c:18543 +#: commands/tablecmds.c:18555 #, c-format msgid "cannot use non-immediate index \"%s\" as replica identity" msgstr "Index »%s« kann nicht als Replik-Identität verwendet werden, weil er nicht IMMEDIATE ist" -#: commands/tablecmds.c:18549 +#: commands/tablecmds.c:18561 #, c-format msgid "cannot use expression index \"%s\" as replica identity" msgstr "Ausdrucksindex »%s« kann nicht als Replik-Identität verwendet werden" -#: commands/tablecmds.c:18555 +#: commands/tablecmds.c:18567 #, c-format msgid "cannot use partial index \"%s\" as replica identity" msgstr "partieller Index »%s« kann nicht als Replik-Identität verwendet werden" -#: commands/tablecmds.c:18572 +#: commands/tablecmds.c:18584 #, c-format msgid "index \"%s\" cannot be used as replica identity because column %d is a system column" msgstr "Index »%s« kann nicht als Replik-Identität verwendet werden, weil Spalte %d eine Systemspalte ist" -#: commands/tablecmds.c:18579 +#: commands/tablecmds.c:18591 #, c-format msgid "index \"%s\" cannot be used as replica identity because column \"%s\" is nullable" msgstr "Index »%s« kann nicht als Replik-Identität verwendet werden, weil Spalte »%s« NULL-Werte akzeptiert" -#: commands/tablecmds.c:18828 +#: commands/tablecmds.c:18840 #, c-format msgid "cannot change logged status of table \"%s\" because it is temporary" msgstr "kann den geloggten Status der Tabelle »%s« nicht ändern, weil sie temporär ist" -#: commands/tablecmds.c:18852 +#: commands/tablecmds.c:18864 #, c-format msgid "cannot change table \"%s\" to unlogged because it is part of a publication" msgstr "kann Tabelle »%s« nicht in ungeloggt ändern, weil sie Teil einer Publikation ist" -#: commands/tablecmds.c:18854 +#: commands/tablecmds.c:18866 #, c-format msgid "Unlogged relations cannot be replicated." msgstr "Ungeloggte Relationen können nicht repliziert werden." -#: commands/tablecmds.c:18899 +#: commands/tablecmds.c:18911 #, c-format msgid "could not change table \"%s\" to logged because it references unlogged table \"%s\"" msgstr "konnte Tabelle »%s« nicht in geloggt ändern, weil sie auf die ungeloggte Tabelle »%s« verweist" -#: commands/tablecmds.c:18909 +#: commands/tablecmds.c:18921 #, c-format msgid "could not change table \"%s\" to unlogged because it references logged table \"%s\"" msgstr "konnte Tabelle »%s« nicht in ungeloggt ändern, weil sie auf die geloggte Tabelle »%s« verweist" -#: commands/tablecmds.c:18973 +#: commands/tablecmds.c:18985 #, c-format msgid "cannot move an owned sequence into another schema" msgstr "einer Tabelle zugeordnete Sequenz kann nicht in ein anderes Schema verschoben werden" -#: commands/tablecmds.c:19081 +#: commands/tablecmds.c:19093 #, c-format msgid "relation \"%s\" already exists in schema \"%s\"" msgstr "Relation »%s« existiert bereits in Schema »%s«" -#: commands/tablecmds.c:19506 +#: commands/tablecmds.c:19518 #, c-format msgid "\"%s\" is not a table or materialized view" msgstr "»%s« ist keine Tabelle oder materialisierte Sicht" -#: commands/tablecmds.c:19659 +#: commands/tablecmds.c:19671 #, c-format msgid "\"%s\" is not a composite type" msgstr "»%s« ist kein zusammengesetzter Typ" -#: commands/tablecmds.c:19689 +#: commands/tablecmds.c:19701 #, c-format msgid "cannot change schema of index \"%s\"" msgstr "kann Schema des Index »%s« nicht ändern" -#: commands/tablecmds.c:19691 commands/tablecmds.c:19705 +#: commands/tablecmds.c:19703 commands/tablecmds.c:19717 #, c-format msgid "Change the schema of the table instead." msgstr "Ändern Sie stattdessen das Schema der Tabelle." -#: commands/tablecmds.c:19695 +#: commands/tablecmds.c:19707 #, c-format msgid "cannot change schema of composite type \"%s\"" msgstr "kann Schema des zusammengesetzten Typs »%s« nicht ändern" -#: commands/tablecmds.c:19703 +#: commands/tablecmds.c:19715 #, c-format msgid "cannot change schema of TOAST table \"%s\"" msgstr "kann Schema der TOAST-Tabelle »%s« nicht ändern" -#: commands/tablecmds.c:19735 +#: commands/tablecmds.c:19747 #, c-format msgid "cannot use \"list\" partition strategy with more than one column" msgstr "Partitionierungsstrategie »list« kann nicht mit mehr als einer Spalte verwendet werden" -#: commands/tablecmds.c:19801 +#: commands/tablecmds.c:19813 #, c-format msgid "column \"%s\" named in partition key does not exist" msgstr "Spalte »%s«, die im Partitionierungsschlüssel verwendet wird, existiert nicht" -#: commands/tablecmds.c:19809 +#: commands/tablecmds.c:19821 #, c-format msgid "cannot use system column \"%s\" in partition key" msgstr "Systemspalte »%s« kann nicht im Partitionierungsschlüssel verwendet werden" -#: commands/tablecmds.c:19823 commands/tablecmds.c:19905 +#: commands/tablecmds.c:19835 commands/tablecmds.c:19917 #, c-format msgid "cannot use generated column in partition key" msgstr "generierte Spalte kann nicht im Partitionierungsschlüssel verwendet werden" -#: commands/tablecmds.c:19892 +#: commands/tablecmds.c:19904 #, c-format msgid "partition key expressions cannot contain system column references" msgstr "Partitionierungsschlüsselausdruck kann nicht auf Systemspalten verweisen" -#: commands/tablecmds.c:19956 +#: commands/tablecmds.c:19968 #, c-format msgid "functions in partition key expression must be marked IMMUTABLE" msgstr "Funktionen im Partitionierungsschlüsselausdruck müssen als IMMUTABLE markiert sein" -#: commands/tablecmds.c:19965 +#: commands/tablecmds.c:19977 #, c-format msgid "cannot use constant expression as partition key" msgstr "Partitionierungsschlüssel kann kein konstanter Ausdruck sein" -#: commands/tablecmds.c:19986 +#: commands/tablecmds.c:19998 #, c-format msgid "could not determine which collation to use for partition expression" msgstr "konnte die für den Partitionierungsausdruck zu verwendende Sortierfolge nicht bestimmen" -#: commands/tablecmds.c:20021 +#: commands/tablecmds.c:20033 #, c-format msgid "You must specify a hash operator class or define a default hash operator class for the data type." msgstr "Sie müssen eine hash-Operatorklasse angeben oder eine hash-Standardoperatorklasse für den Datentyp definieren." -#: commands/tablecmds.c:20027 +#: commands/tablecmds.c:20039 #, c-format msgid "You must specify a btree operator class or define a default btree operator class for the data type." msgstr "Sie müssen eine btree-Operatorklasse angeben oder eine btree-Standardoperatorklasse für den Datentyp definieren." -#: commands/tablecmds.c:20287 +#: commands/tablecmds.c:20299 #, c-format msgid "\"%s\" is already a partition" msgstr "»%s« ist bereits eine Partition" -#: commands/tablecmds.c:20293 +#: commands/tablecmds.c:20305 #, c-format msgid "cannot attach a typed table as partition" msgstr "eine getypte Tabelle kann nicht als Partition angefügt werden" -#: commands/tablecmds.c:20309 +#: commands/tablecmds.c:20321 #, c-format msgid "cannot attach inheritance child as partition" msgstr "ein Vererbungskind kann nicht als Partition angefügt werden" -#: commands/tablecmds.c:20323 +#: commands/tablecmds.c:20335 #, c-format msgid "cannot attach inheritance parent as partition" msgstr "eine Tabelle mit abgeleiteten Tabellen kann nicht als Partition angefügt werden" -#: commands/tablecmds.c:20357 +#: commands/tablecmds.c:20369 #, c-format msgid "cannot attach a temporary relation as partition of permanent relation \"%s\"" msgstr "eine temporäre Relation kann nicht als Partition an permanente Relation »%s« angefügt werden" -#: commands/tablecmds.c:20365 +#: commands/tablecmds.c:20377 #, c-format msgid "cannot attach a permanent relation as partition of temporary relation \"%s\"" msgstr "eine permanente Relation kann nicht als Partition an temporäre Relation »%s« angefügt werden" -#: commands/tablecmds.c:20373 +#: commands/tablecmds.c:20385 #, c-format msgid "cannot attach as partition of temporary relation of another session" msgstr "kann nicht als Partition an temporäre Relation einer anderen Sitzung anfügen" -#: commands/tablecmds.c:20380 +#: commands/tablecmds.c:20392 #, c-format msgid "cannot attach temporary relation of another session as partition" msgstr "temporäre Relation einer anderen Sitzung kann nicht als Partition angefügt werden" -#: commands/tablecmds.c:20400 +#: commands/tablecmds.c:20412 #, c-format msgid "table \"%s\" being attached contains an identity column \"%s\"" msgstr "anzufügende Tabelle »%s« enthält eine Identitätsspalte »%s«" -#: commands/tablecmds.c:20402 +#: commands/tablecmds.c:20414 #, c-format msgid "The new partition may not contain an identity column." msgstr "Die neue Partition darf keine Identitätsspalte enthalten." -#: commands/tablecmds.c:20410 +#: commands/tablecmds.c:20422 #, c-format msgid "table \"%s\" contains column \"%s\" not found in parent \"%s\"" msgstr "Tabelle »%s« enthält Spalte »%s«, die nicht in der Elterntabelle »%s« gefunden wurde" -#: commands/tablecmds.c:20413 +#: commands/tablecmds.c:20425 #, c-format msgid "The new partition may contain only the columns present in parent." msgstr "Die neue Partition darf nur Spalten enthalten, die auch die Elterntabelle hat." -#: commands/tablecmds.c:20425 +#: commands/tablecmds.c:20437 #, c-format msgid "trigger \"%s\" prevents table \"%s\" from becoming a partition" msgstr "Trigger »%s« verhindert, dass Tabelle »%s« eine Partition werden kann" -#: commands/tablecmds.c:20427 +#: commands/tablecmds.c:20439 #, c-format msgid "ROW triggers with transition tables are not supported on partitions." msgstr "ROW-Trigger mit Übergangstabellen werden für Partitionen nicht unterstützt." -#: commands/tablecmds.c:20609 +#: commands/tablecmds.c:20621 #, c-format msgid "cannot attach foreign table \"%s\" as partition of partitioned table \"%s\"" msgstr "kann Fremdtabelle »%s« nicht als Partition an partitionierte Tabelle »%s« anfügen" -#: commands/tablecmds.c:20612 +#: commands/tablecmds.c:20624 #, c-format msgid "Partitioned table \"%s\" contains unique indexes." msgstr "Partitionierte Tabelle »%s« enthält Unique-Indexe." -#: commands/tablecmds.c:20936 +#: commands/tablecmds.c:20948 #, c-format msgid "cannot detach partitions concurrently when a default partition exists" msgstr "nebenläufiges Abtrennen einer Partition ist nicht möglich, wenn eine Standardpartition existiert" -#: commands/tablecmds.c:21048 +#: commands/tablecmds.c:21060 #, c-format msgid "partitioned table \"%s\" was removed concurrently" msgstr "partitionierte Tabelle »%s« wurde nebenläufig entfernt" -#: commands/tablecmds.c:21054 +#: commands/tablecmds.c:21066 #, c-format msgid "partition \"%s\" was removed concurrently" msgstr "Partition »%s« wurde nebenläufig entfernt" -#: commands/tablecmds.c:21685 commands/tablecmds.c:21705 -#: commands/tablecmds.c:21726 commands/tablecmds.c:21745 -#: commands/tablecmds.c:21794 +#: commands/tablecmds.c:21700 commands/tablecmds.c:21720 +#: commands/tablecmds.c:21741 commands/tablecmds.c:21760 +#: commands/tablecmds.c:21817 #, c-format msgid "cannot attach index \"%s\" as a partition of index \"%s\"" msgstr "kann Index »%s« nicht als Partition an Index »%s« anfügen" -#: commands/tablecmds.c:21688 +#: commands/tablecmds.c:21703 #, c-format msgid "Index \"%s\" is already attached to another index." msgstr "Index »%s« ist bereits an einen anderen Index angefügt." -#: commands/tablecmds.c:21708 +#: commands/tablecmds.c:21723 #, c-format msgid "Index \"%s\" is not an index on any partition of table \"%s\"." msgstr "Index »%s« ist kein Index irgendeiner Partition von Tabelle »%s«." -#: commands/tablecmds.c:21729 +#: commands/tablecmds.c:21744 #, c-format msgid "The index definitions do not match." msgstr "Die Indexdefinitionen stimmen nicht überein." -#: commands/tablecmds.c:21748 +#: commands/tablecmds.c:21763 #, c-format msgid "The index \"%s\" belongs to a constraint in table \"%s\" but no constraint exists for index \"%s\"." msgstr "Der Index »%s« gehört zu einem Constraint in Tabelle »%s«, aber kein Constraint existiert für Index »%s«." -#: commands/tablecmds.c:21797 +#: commands/tablecmds.c:21820 #, c-format msgid "Another index is already attached for partition \"%s\"." msgstr "Ein anderer Index ist bereits für Partition »%s« angefügt." -#: commands/tablecmds.c:21920 +#: commands/tablecmds.c:21943 #, c-format msgid "invalid primary key definition" msgstr "ungültige Primärschlüsseldefinition" -#: commands/tablecmds.c:21921 +#: commands/tablecmds.c:21944 #, c-format msgid "Column \"%s\" of relation \"%s\" is not marked NOT NULL." msgstr "Spalte »%s« von Relation »%s« ist nicht als NOT NULL markiert." -#: commands/tablecmds.c:22056 +#: commands/tablecmds.c:22079 #, c-format msgid "column data type %s does not support compression" msgstr "Spaltendatentyp %s unterstützt keine Komprimierung" -#: commands/tablecmds.c:22063 +#: commands/tablecmds.c:22086 #, c-format msgid "invalid compression method \"%s\"" msgstr "ungültige Komprimierungsmethode »%s«" -#: commands/tablecmds.c:22089 +#: commands/tablecmds.c:22112 #, c-format msgid "invalid storage type \"%s\"" msgstr "ungültiger Storage-Typ »%s«" -#: commands/tablecmds.c:22099 +#: commands/tablecmds.c:22122 #, c-format msgid "column data type %s can only have storage PLAIN" msgstr "Spaltendatentyp %s kann nur Storage-Typ PLAIN" @@ -12674,7 +12674,7 @@ msgstr "aus abgeleiteten Fremdtabellen können keine Übergangstupel gesammelt w #: commands/trigger.c:3402 executor/nodeModifyTable.c:1687 #: executor/nodeModifyTable.c:1761 executor/nodeModifyTable.c:2569 #: executor/nodeModifyTable.c:2659 executor/nodeModifyTable.c:3322 -#: executor/nodeModifyTable.c:3514 +#: executor/nodeModifyTable.c:3519 #, c-format msgid "Consider using an AFTER trigger instead of a BEFORE trigger to propagate changes to other rows." msgstr "Verwenden Sie einen AFTER-Trigger anstelle eines BEFORE-Triggers, um Änderungen an andere Zeilen zu propagieren." @@ -12682,7 +12682,7 @@ msgstr "Verwenden Sie einen AFTER-Trigger anstelle eines BEFORE-Triggers, um Än #: commands/trigger.c:3444 executor/nodeLockRows.c:228 #: executor/nodeLockRows.c:237 executor/nodeModifyTable.c:389 #: executor/nodeModifyTable.c:1703 executor/nodeModifyTable.c:2585 -#: executor/nodeModifyTable.c:2810 +#: executor/nodeModifyTable.c:2810 executor/nodeModifyTable.c:3360 #, c-format msgid "could not serialize access due to concurrent update" msgstr "konnte Zugriff nicht serialisieren wegen gleichzeitiger Aktualisierung" @@ -13860,19 +13860,19 @@ msgstr "Cursor »%s« ist nicht auf eine Zeile positioniert" msgid "cursor \"%s\" is not a simply updatable scan of table \"%s\"" msgstr "Cursor »%s« ist kein einfach aktualisierbarer Scan der Tabelle »%s«" -#: executor/execCurrent.c:280 executor/execExprInterp.c:3093 +#: executor/execCurrent.c:280 executor/execExprInterp.c:3101 #, c-format msgid "type of parameter %d (%s) does not match that when preparing the plan (%s)" msgstr "Typ von Parameter %d (%s) stimmt nicht mit dem überein, als der Plan vorbereitet worden ist (%s)" -#: executor/execCurrent.c:292 executor/execExprInterp.c:3105 +#: executor/execCurrent.c:292 executor/execExprInterp.c:3113 #, c-format msgid "no value found for parameter %d" msgstr "kein Wert für Parameter %d gefunden" #: executor/execExpr.c:667 executor/execExpr.c:674 executor/execExpr.c:680 -#: executor/execExprInterp.c:5439 executor/execExprInterp.c:5456 -#: executor/execExprInterp.c:5555 executor/nodeModifyTable.c:211 +#: executor/execExprInterp.c:5510 executor/execExprInterp.c:5527 +#: executor/execExprInterp.c:5626 executor/nodeModifyTable.c:211 #: executor/nodeModifyTable.c:230 executor/nodeModifyTable.c:247 #: executor/nodeModifyTable.c:257 executor/nodeModifyTable.c:267 #, c-format @@ -13889,7 +13889,7 @@ msgstr "Anfrage hat zu viele Spalten." msgid "Query provides a value for a dropped column at ordinal position %d." msgstr "Anfrage liefert einen Wert für eine gelöschte Spalte auf Position %d." -#: executor/execExpr.c:681 executor/execExprInterp.c:5457 +#: executor/execExpr.c:681 executor/execExprInterp.c:5528 #: executor/nodeModifyTable.c:258 #, c-format msgid "Table has type %s at ordinal position %d, but query expects %s." @@ -13934,23 +13934,23 @@ msgstr "kann aus Typ %s kein Element auswählen, weil er Subscripting nicht unte msgid "type %s does not support subscripted assignment" msgstr "Typ %s unterstützt Wertzuweisungen in Elemente nicht" -#: executor/execExprInterp.c:2415 +#: executor/execExprInterp.c:2423 #, c-format msgid "attribute %d of type %s has been dropped" msgstr "Attribut %d von Typ %s wurde gelöscht" -#: executor/execExprInterp.c:2421 +#: executor/execExprInterp.c:2429 #, c-format msgid "attribute %d of type %s has wrong type" msgstr "Attribut %d von Typ %s hat falschen Typ" -#: executor/execExprInterp.c:2423 executor/execExprInterp.c:3782 -#: executor/execExprInterp.c:3828 +#: executor/execExprInterp.c:2431 executor/execExprInterp.c:3790 +#: executor/execExprInterp.c:3836 #, c-format msgid "Table has type %s, but query expects %s." msgstr "Tabelle hat Typ %s, aber Anfrage erwartet %s." -#: executor/execExprInterp.c:2503 utils/adt/expandedrecord.c:99 +#: executor/execExprInterp.c:2511 utils/adt/expandedrecord.c:99 #: utils/adt/expandedrecord.c:231 utils/cache/typcache.c:1841 #: utils/cache/typcache.c:2000 utils/cache/typcache.c:2147 #: utils/fmgr/funcapi.c:569 @@ -13958,22 +13958,22 @@ msgstr "Tabelle hat Typ %s, aber Anfrage erwartet %s." msgid "type %s is not composite" msgstr "Typ %s ist kein zusammengesetzter Typ" -#: executor/execExprInterp.c:3266 +#: executor/execExprInterp.c:3274 #, c-format msgid "WHERE CURRENT OF is not supported for this table type" msgstr "WHERE CURRENT OF wird für diesen Tabellentyp nicht unterstützt" -#: executor/execExprInterp.c:3479 +#: executor/execExprInterp.c:3487 #, c-format msgid "cannot merge incompatible arrays" msgstr "kann inkompatible Arrays nicht verschmelzen" -#: executor/execExprInterp.c:3480 +#: executor/execExprInterp.c:3488 #, c-format msgid "Array with element type %s cannot be included in ARRAY construct with element type %s." msgstr "Arrayelement mit Typ %s kann nicht in ARRAY-Konstrukt mit Elementtyp %s verwendet werden." -#: executor/execExprInterp.c:3501 utils/adt/arrayfuncs.c:1305 +#: executor/execExprInterp.c:3509 utils/adt/arrayfuncs.c:1305 #: utils/adt/arrayfuncs.c:3515 utils/adt/arrayfuncs.c:5611 #: utils/adt/arrayfuncs.c:6130 utils/adt/arraysubs.c:151 #: utils/adt/arraysubs.c:489 @@ -13981,12 +13981,12 @@ msgstr "Arrayelement mit Typ %s kann nicht in ARRAY-Konstrukt mit Elementtyp %s msgid "number of array dimensions (%d) exceeds the maximum allowed (%d)" msgstr "Anzahl der Arraydimensionen (%d) überschreitet erlaubtes Maximum (%d)" -#: executor/execExprInterp.c:3521 executor/execExprInterp.c:3556 +#: executor/execExprInterp.c:3529 executor/execExprInterp.c:3564 #, c-format msgid "multidimensional arrays must have array expressions with matching dimensions" msgstr "mehrdimensionale Arrays müssen Arraysausdrücke mit gleicher Anzahl Dimensionen haben" -#: executor/execExprInterp.c:3533 utils/adt/array_expanded.c:274 +#: executor/execExprInterp.c:3541 utils/adt/array_expanded.c:274 #: utils/adt/arrayfuncs.c:335 utils/adt/arrayfuncs.c:494 #: utils/adt/arrayfuncs.c:727 utils/adt/arrayfuncs.c:1533 #: utils/adt/arrayfuncs.c:2341 utils/adt/arrayfuncs.c:2356 @@ -14001,85 +14001,85 @@ msgstr "mehrdimensionale Arrays müssen Arraysausdrücke mit gleicher Anzahl Dim msgid "array size exceeds the maximum allowed (%d)" msgstr "Arraygröße überschreitet erlaubtes Maximum (%d)" -#: executor/execExprInterp.c:3781 executor/execExprInterp.c:3827 +#: executor/execExprInterp.c:3789 executor/execExprInterp.c:3835 #, c-format msgid "attribute %d has wrong type" msgstr "Attribut %d hat falschen Typ" -#: executor/execExprInterp.c:4413 utils/adt/domains.c:158 +#: executor/execExprInterp.c:4484 utils/adt/domains.c:158 #, c-format msgid "domain %s does not allow null values" msgstr "Domäne %s erlaubt keine NULL-Werte" -#: executor/execExprInterp.c:4428 utils/adt/domains.c:196 +#: executor/execExprInterp.c:4499 utils/adt/domains.c:196 #, c-format msgid "value for domain %s violates check constraint \"%s\"" msgstr "Wert für Domäne %s verletzt Check-Constraint »%s«" -#: executor/execExprInterp.c:5003 +#: executor/execExprInterp.c:5074 #, c-format msgid "no SQL/JSON item found for specified path of column \"%s\"" msgstr "kein SQL/JSON-Item für angegebenen Pfad von Spalte »%s« gefunden" -#: executor/execExprInterp.c:5008 +#: executor/execExprInterp.c:5079 #, c-format msgid "no SQL/JSON item found for specified path" msgstr "kein SQL/JSON-Item für angegebenen Pfad gefunden" #. translator: first %s is a SQL/JSON clause (e.g. ON ERROR) -#: executor/execExprInterp.c:5208 executor/execExprInterp.c:5216 +#: executor/execExprInterp.c:5279 executor/execExprInterp.c:5287 #, c-format msgid "could not coerce %s expression (%s) to the RETURNING type" msgstr "konnte %s-Ausdruck (%s) nicht in RETURNING-Typ umwandeln" -#: executor/execExprInterp.c:5440 +#: executor/execExprInterp.c:5511 #, c-format msgid "Table row contains %d attribute, but query expects %d." msgid_plural "Table row contains %d attributes, but query expects %d." msgstr[0] "Tabellenzeile enthält %d Attribut, aber Anfrage erwartet %d." msgstr[1] "Tabellenzeile enthält %d Attribute, aber Anfrage erwartet %d." -#: executor/execExprInterp.c:5556 executor/execSRF.c:977 +#: executor/execExprInterp.c:5627 executor/execSRF.c:977 #, c-format msgid "Physical storage mismatch on dropped attribute at ordinal position %d." msgstr "Physischer Speicher stimmt nicht überein mit gelöschtem Attribut auf Position %d." -#: executor/execIndexing.c:608 +#: executor/execIndexing.c:609 #, c-format msgid "ON CONFLICT does not support deferrable unique constraints/exclusion constraints as arbiters" msgstr "ON CONFLICT unterstützt keine aufschiebbaren Unique-Constraints/Exclusion-Constraints als Arbiter" -#: executor/execIndexing.c:911 +#: executor/execIndexing.c:919 #, c-format msgid "could not create exclusion constraint \"%s\"" msgstr "konnte Exclusion-Constraint »%s« nicht erzeugen" -#: executor/execIndexing.c:914 +#: executor/execIndexing.c:922 #, c-format msgid "Key %s conflicts with key %s." msgstr "Schlüssel %s kollidiert mit Schlüssel %s." -#: executor/execIndexing.c:916 +#: executor/execIndexing.c:924 #, c-format msgid "Key conflicts exist." msgstr "Es bestehen Schlüsselkonflikte." -#: executor/execIndexing.c:922 +#: executor/execIndexing.c:930 #, c-format msgid "conflicting key value violates exclusion constraint \"%s\"" msgstr "kollidierender Schlüsselwert verletzt Exclusion-Constraint »%s«" -#: executor/execIndexing.c:925 +#: executor/execIndexing.c:933 #, c-format msgid "Key %s conflicts with existing key %s." msgstr "Schlüssel %s kollidiert mit vorhandenem Schlüssel %s." -#: executor/execIndexing.c:927 +#: executor/execIndexing.c:935 #, c-format msgid "Key conflicts with existing key." msgstr "Der Schlüssel kollidiert mit einem vorhandenen Schlüssel." -#: executor/execIndexing.c:1172 +#: executor/execIndexing.c:1180 #, c-format msgid "empty WITHOUT OVERLAPS value found in column \"%s\" in relation \"%s\"" msgstr "leerer WITHOUT-OVERLAPS-Wert gefunden in Spalte »%s« in Relation »%s«" @@ -14446,7 +14446,7 @@ msgstr "Die letzte Anweisung gibt zu wenige Spalten zurück." msgid "return type %s is not supported for SQL functions" msgstr "Rückgabetyp %s wird von SQL-Funktionen nicht unterstützt" -#: executor/nodeAgg.c:4039 executor/nodeWindowAgg.c:3041 +#: executor/nodeAgg.c:4039 executor/nodeWindowAgg.c:3089 #, c-format msgid "aggregate %u needs to have compatible input type and transition type" msgstr "Aggregatfunktion %u muss kompatiblen Eingabe- und Übergangstyp haben" @@ -14533,7 +14533,7 @@ msgstr "Definieren Sie den Fremdschlüssel eventuell für Tabelle »%s«." #. translator: %s is a SQL command name #: executor/nodeModifyTable.c:2788 executor/nodeModifyTable.c:3328 -#: executor/nodeModifyTable.c:3520 +#: executor/nodeModifyTable.c:3525 #, c-format msgid "%s command cannot affect row a second time" msgstr "Befehl in %s kann eine Zeile nicht ein zweites Mal ändern" @@ -14543,17 +14543,17 @@ msgstr "Befehl in %s kann eine Zeile nicht ein zweites Mal ändern" msgid "Ensure that no rows proposed for insertion within the same command have duplicate constrained values." msgstr "Stellen Sie sicher, dass keine im selben Befehl fürs Einfügen vorgesehene Zeilen doppelte Werte haben, die einen Constraint verletzen würden." -#: executor/nodeModifyTable.c:3321 executor/nodeModifyTable.c:3513 +#: executor/nodeModifyTable.c:3321 executor/nodeModifyTable.c:3518 #, c-format msgid "tuple to be updated or deleted was already modified by an operation triggered by the current command" msgstr "das zu aktualisierende oder zu löschende Tupel wurde schon durch eine vom aktuellen Befehl ausgelöste Operation verändert" -#: executor/nodeModifyTable.c:3330 executor/nodeModifyTable.c:3522 +#: executor/nodeModifyTable.c:3330 executor/nodeModifyTable.c:3527 #, c-format msgid "Ensure that not more than one source row matches any one target row." msgstr "Stellen Sie sicher, dass nicht mehr als eine Quellzeile auf jede Zielzeile passt." -#: executor/nodeModifyTable.c:3399 +#: executor/nodeModifyTable.c:3404 #, c-format msgid "tuple to be merged was already moved to another partition due to concurrent update" msgstr "das zu mergende Tupel wurde schon durch ein gleichzeitiges Update in eine andere Partition verschoben" @@ -14599,32 +14599,32 @@ msgstr "Filter für Spalte »%s« ist NULL." msgid "null is not allowed in column \"%s\"" msgstr "NULL ist in Spalte »%s« nicht erlaubt" -#: executor/nodeWindowAgg.c:356 +#: executor/nodeWindowAgg.c:357 #, c-format msgid "moving-aggregate transition function must not return null" msgstr "Moving-Aggregat-Übergangsfunktion darf nicht NULL zurückgeben" -#: executor/nodeWindowAgg.c:2106 +#: executor/nodeWindowAgg.c:2154 #, c-format msgid "frame starting offset must not be null" msgstr "Frame-Start-Offset darf nicht NULL sein" -#: executor/nodeWindowAgg.c:2120 +#: executor/nodeWindowAgg.c:2168 #, c-format msgid "frame starting offset must not be negative" msgstr "Frame-Start-Offset darf nicht negativ sein" -#: executor/nodeWindowAgg.c:2133 +#: executor/nodeWindowAgg.c:2181 #, c-format msgid "frame ending offset must not be null" msgstr "Frame-Ende-Offset darf nicht NULL sein" -#: executor/nodeWindowAgg.c:2147 +#: executor/nodeWindowAgg.c:2195 #, c-format msgid "frame ending offset must not be negative" msgstr "Frame-Ende-Offset darf nicht negativ sein" -#: executor/nodeWindowAgg.c:2957 +#: executor/nodeWindowAgg.c:3005 #, c-format msgid "aggregate function %s does not support use as a window function" msgstr "Aggregatfunktion %s unterstützt die Verwendung als Fensterfunktion nicht" @@ -14675,7 +14675,7 @@ msgstr "%s kann nicht als Cursor geöffnet werden" msgid "DECLARE SCROLL CURSOR ... FOR UPDATE/SHARE is not supported" msgstr "DECLARE SCROLL CURSOR ... FOR UPDATE/SHARE wird nicht unterstützt" -#: executor/spi.c:1719 parser/analyze.c:3077 +#: executor/spi.c:1719 parser/analyze.c:3093 #, c-format msgid "Scrollable cursors must be READ ONLY." msgstr "Scrollbare Cursor müssen READ ONLY sein." @@ -14856,7 +14856,7 @@ msgstr "CREATE OR REPLACE CONSTRAINT TRIGGER wird nicht unterstützt" msgid "duplicate trigger events specified" msgstr "mehrere Trigger-Ereignisse angegeben" -#: gram.y:6229 parser/parse_utilcmd.c:3946 parser/parse_utilcmd.c:3972 +#: gram.y:6229 parser/parse_utilcmd.c:3955 parser/parse_utilcmd.c:3981 #, c-format msgid "constraint declared INITIALLY DEFERRED must be DEFERRABLE" msgstr "Constraint, der als INITIALLY DEFERRED deklariert wurde, muss DEFERRABLE sein" @@ -15030,8 +15030,8 @@ msgstr "WITH TIES kann nicht ohne ORDER-BY-Klausel angegeben werden" msgid "improper use of \"*\"" msgstr "unzulässige Verwendung von »*«" -#: gram.y:18905 gram.y:18922 tsearch/spell.c:963 tsearch/spell.c:979 -#: tsearch/spell.c:995 tsearch/spell.c:1011 tsearch/spell.c:1076 +#: gram.y:18905 gram.y:18922 tsearch/spell.c:972 tsearch/spell.c:989 +#: tsearch/spell.c:1006 tsearch/spell.c:1023 tsearch/spell.c:1088 #, c-format msgid "syntax error" msgstr "Syntaxfehler" @@ -17038,7 +17038,7 @@ msgstr "es besteht keine Client-Verbindung" msgid "could not receive data from client: %m" msgstr "konnte Daten vom Client nicht empfangen: %m" -#: libpq/pqcomm.c:1151 tcop/postgres.c:4500 +#: libpq/pqcomm.c:1151 tcop/postgres.c:4504 #, c-format msgid "terminating connection because protocol synchronization was lost" msgstr "Verbindung wird abgebrochen, weil Protokollsynchronisierung verloren wurde" @@ -17084,7 +17084,7 @@ msgid "no data left in message" msgstr "keine Daten in Message übrig" #: libpq/pqformat.c:515 libpq/pqformat.c:533 libpq/pqformat.c:554 -#: utils/adt/array_userfuncs.c:873 utils/adt/arrayfuncs.c:1481 +#: utils/adt/array_userfuncs.c:874 utils/adt/arrayfuncs.c:1481 #: utils/adt/rowtypes.c:613 #, c-format msgid "insufficient data left in message" @@ -17395,7 +17395,7 @@ msgstr "erweiterbarer Knotentyp »%s« existiert bereits" msgid "ExtensibleNodeMethods \"%s\" was not registered" msgstr "ExtensibleNodeMethods »%s« wurde nicht registriert" -#: nodes/makefuncs.c:154 nodes/makefuncs.c:180 statistics/extended_stats.c:2286 +#: nodes/makefuncs.c:154 nodes/makefuncs.c:180 statistics/extended_stats.c:2296 #, c-format msgid "relation \"%s\" does not have a composite type" msgstr "Relation »%s« hat keinen zusammengesetzten Typ" @@ -17403,7 +17403,7 @@ msgstr "Relation »%s« hat keinen zusammengesetzten Typ" #: nodes/nodeFuncs.c:118 nodes/nodeFuncs.c:149 parser/parse_coerce.c:2602 #: parser/parse_coerce.c:2740 parser/parse_coerce.c:2787 #: parser/parse_expr.c:2130 parser/parse_func.c:710 parser/parse_oper.c:869 -#: utils/adt/array_userfuncs.c:1950 utils/fmgr/funcapi.c:669 +#: utils/adt/array_userfuncs.c:1959 utils/fmgr/funcapi.c:669 #, c-format msgid "could not find array type for data type %s" msgstr "konnte Arraytyp für Datentyp %s nicht finden" @@ -17424,7 +17424,7 @@ msgid "FULL JOIN is only supported with merge-joinable or hash-joinable join con msgstr "FULL JOIN wird nur für Merge- oder Hash-Verbund-fähige Verbundbedingungen unterstützt" #: optimizer/plan/createplan.c:7321 parser/parse_merge.c:203 -#: rewrite/rewriteHandler.c:1692 +#: rewrite/rewriteHandler.c:1725 #, c-format msgid "cannot execute MERGE on relation \"%s\"" msgstr "MERGE kann für Relation »%s« nicht ausgeführt werden" @@ -17436,44 +17436,44 @@ msgid "%s cannot be applied to the nullable side of an outer join" msgstr "%s kann nicht auf die nullbare Seite eines äußeren Verbundes angewendet werden" #. translator: %s is a SQL row locking clause such as FOR UPDATE -#: optimizer/plan/planner.c:1512 parser/analyze.c:1815 parser/analyze.c:2074 -#: parser/analyze.c:3396 +#: optimizer/plan/planner.c:1700 parser/analyze.c:1823 parser/analyze.c:2082 +#: parser/analyze.c:3412 #, c-format msgid "%s is not allowed with UNION/INTERSECT/EXCEPT" msgstr "%s ist nicht in UNION/INTERSECT/EXCEPT erlaubt" -#: optimizer/plan/planner.c:2258 optimizer/plan/planner.c:4144 +#: optimizer/plan/planner.c:2446 optimizer/plan/planner.c:4332 #, c-format msgid "could not implement GROUP BY" msgstr "konnte GROUP BY nicht implementieren" -#: optimizer/plan/planner.c:2259 optimizer/plan/planner.c:4145 -#: optimizer/plan/planner.c:4826 optimizer/prep/prepunion.c:1073 +#: optimizer/plan/planner.c:2447 optimizer/plan/planner.c:4333 +#: optimizer/plan/planner.c:5014 optimizer/prep/prepunion.c:1073 #, c-format msgid "Some of the datatypes only support hashing, while others only support sorting." msgstr "Einige Datentypen unterstützen nur Hashing, während andere nur Sortieren unterstützen." -#: optimizer/plan/planner.c:4825 +#: optimizer/plan/planner.c:5013 #, c-format msgid "could not implement DISTINCT" msgstr "konnte DISTINCT nicht implementieren" -#: optimizer/plan/planner.c:6322 +#: optimizer/plan/planner.c:6510 #, c-format msgid "could not implement window PARTITION BY" msgstr "konnte PARTITION BY für Fenster nicht implementieren" -#: optimizer/plan/planner.c:6323 +#: optimizer/plan/planner.c:6511 #, c-format msgid "Window partitioning columns must be of sortable datatypes." msgstr "Fensterpartitionierungsspalten müssen sortierbare Datentypen haben." -#: optimizer/plan/planner.c:6327 +#: optimizer/plan/planner.c:6515 #, c-format msgid "could not implement window ORDER BY" msgstr "konnte ORDER BY für Fenster nicht implementieren" -#: optimizer/plan/planner.c:6328 +#: optimizer/plan/planner.c:6516 #, c-format msgid "Window ordering columns must be of sortable datatypes." msgstr "Fenstersortierspalten müssen sortierbare Datentypen haben." @@ -17534,233 +17534,238 @@ msgstr "ON CONFLICT DO UPDATE nicht unterstützt mit Exclusion-Constraints" msgid "there is no unique or exclusion constraint matching the ON CONFLICT specification" msgstr "es gibt keinen Unique-Constraint oder Exclusion-Constraint, der auf die ON-CONFLICT-Angabe passt" -#: parser/analyze.c:869 parser/analyze.c:1594 +#: parser/analyze.c:582 parser/analyze.c:2501 +#, c-format +msgid "WHERE CURRENT OF on a view is not implemented" +msgstr "WHERE CURRENT OF mit einer Sicht ist nicht implementiert" + +#: parser/analyze.c:877 parser/analyze.c:1602 #, c-format msgid "VALUES lists must all be the same length" msgstr "VALUES-Listen müssen alle die gleiche Länge haben" -#: parser/analyze.c:1071 +#: parser/analyze.c:1079 #, c-format msgid "INSERT has more expressions than target columns" msgstr "INSERT hat mehr Ausdrücke als Zielspalten" -#: parser/analyze.c:1089 +#: parser/analyze.c:1097 #, c-format msgid "INSERT has more target columns than expressions" msgstr "INSERT hat mehr Zielspalten als Ausdrücke" -#: parser/analyze.c:1093 +#: parser/analyze.c:1101 #, c-format msgid "The insertion source is a row expression containing the same number of columns expected by the INSERT. Did you accidentally use extra parentheses?" msgstr "Der einzufügende Wert ist ein Zeilenausdruck mit der gleichen Anzahl Spalten wie von INSERT erwartet. Haben Sie versehentlich zu viele Klammern gesetzt?" -#: parser/analyze.c:1401 parser/analyze.c:1788 +#: parser/analyze.c:1409 parser/analyze.c:1796 #, c-format msgid "SELECT ... INTO is not allowed here" msgstr "SELECT ... INTO ist hier nicht erlaubt" #. translator: %s is a SQL row locking clause such as FOR UPDATE -#: parser/analyze.c:1717 parser/analyze.c:3628 +#: parser/analyze.c:1725 parser/analyze.c:3644 #, c-format msgid "%s cannot be applied to VALUES" msgstr "%s kann nicht auf VALUES angewendet werden" -#: parser/analyze.c:1955 +#: parser/analyze.c:1963 #, c-format msgid "invalid UNION/INTERSECT/EXCEPT ORDER BY clause" msgstr "ungültige ORDER-BY-Klausel mit UNION/INTERSECT/EXCEPT" -#: parser/analyze.c:1956 +#: parser/analyze.c:1964 #, c-format msgid "Only result column names can be used, not expressions or functions." msgstr "Es können nur Ergebnisspaltennamen verwendet werden, keine Ausdrücke oder Funktionen." -#: parser/analyze.c:1957 +#: parser/analyze.c:1965 #, c-format msgid "Add the expression/function to every SELECT, or move the UNION into a FROM clause." msgstr "Fügen Sie den Ausdrück/die Funktion jedem SELECT hinzu oder verlegen Sie die UNION in eine FROM-Klausel." -#: parser/analyze.c:2064 +#: parser/analyze.c:2072 #, c-format msgid "INTO is only allowed on first SELECT of UNION/INTERSECT/EXCEPT" msgstr "INTO ist nur im ersten SELECT von UNION/INTERSECT/EXCEPT erlaubt" -#: parser/analyze.c:2136 +#: parser/analyze.c:2144 #, c-format msgid "UNION/INTERSECT/EXCEPT member statement cannot refer to other relations of same query level" msgstr "Teilanweisung von UNION/INTERSECT/EXCEPT kann nicht auf andere Relationen auf der selben Anfrageebene verweisen" -#: parser/analyze.c:2223 +#: parser/analyze.c:2231 #, c-format msgid "each %s query must have the same number of columns" msgstr "jede %s-Anfrage muss die gleiche Anzahl Spalten haben" -#: parser/analyze.c:2580 +#: parser/analyze.c:2596 #, c-format msgid "SET target columns cannot be qualified with the relation name." msgstr "SET-Zielspalten können nicht mit dem Relationsnamen qualifiziert werden." #. translator: %s is OLD or NEW -#: parser/analyze.c:2668 parser/analyze.c:2678 +#: parser/analyze.c:2684 parser/analyze.c:2694 #, c-format msgid "%s cannot be specified multiple times" msgstr "%s kann nicht mehrmals angegeben werden" -#: parser/analyze.c:2690 parser/parse_relation.c:473 +#: parser/analyze.c:2706 parser/parse_relation.c:473 #, c-format msgid "table name \"%s\" specified more than once" msgstr "Tabellenname »%s« mehrmals angegeben" -#: parser/analyze.c:2738 +#: parser/analyze.c:2754 #, c-format msgid "RETURNING must have at least one column" msgstr "RETURNING muss mindestens eine Spalte haben" -#: parser/analyze.c:2840 +#: parser/analyze.c:2856 #, c-format msgid "assignment source returned %d column" msgid_plural "assignment source returned %d columns" msgstr[0] "Quelle der Wertzuweisung hat %d Spalte zurückgegeben" msgstr[1] "Quelle der Wertzuweisung hat %d Spalten zurückgegeben" -#: parser/analyze.c:2901 +#: parser/analyze.c:2917 #, c-format msgid "variable \"%s\" is of type %s but expression is of type %s" msgstr "Variable »%s« hat Typ %s, aber der Ausdruck hat Typ %s" #. translator: %s is a SQL keyword -#: parser/analyze.c:3027 parser/analyze.c:3035 +#: parser/analyze.c:3043 parser/analyze.c:3051 #, c-format msgid "cannot specify both %s and %s" msgstr "%s und %s können nicht beide angegeben werden" -#: parser/analyze.c:3055 +#: parser/analyze.c:3071 #, c-format msgid "DECLARE CURSOR must not contain data-modifying statements in WITH" msgstr "DECLARE CURSOR darf keine datenmodifizierenden Anweisungen in WITH enthalten" #. translator: %s is a SQL row locking clause such as FOR UPDATE -#: parser/analyze.c:3063 +#: parser/analyze.c:3079 #, c-format msgid "DECLARE CURSOR WITH HOLD ... %s is not supported" msgstr "DECLARE CURSOR WITH HOLD ... %s wird nicht unterstützt" -#: parser/analyze.c:3066 +#: parser/analyze.c:3082 #, c-format msgid "Holdable cursors must be READ ONLY." msgstr "Haltbare Cursor müssen READ ONLY sein." #. translator: %s is a SQL row locking clause such as FOR UPDATE -#: parser/analyze.c:3074 +#: parser/analyze.c:3090 #, c-format msgid "DECLARE SCROLL CURSOR ... %s is not supported" msgstr "DECLARE SCROLL CURSOR ... %s wird nicht unterstützt" #. translator: %s is a SQL row locking clause such as FOR UPDATE -#: parser/analyze.c:3085 +#: parser/analyze.c:3101 #, c-format msgid "DECLARE INSENSITIVE CURSOR ... %s is not valid" msgstr "DECLARE INSENSITIVE CURSOR ... %s ist nicht gültig" -#: parser/analyze.c:3088 +#: parser/analyze.c:3104 #, c-format msgid "Insensitive cursors must be READ ONLY." msgstr "Insensitive Cursor müssen READ ONLY sein." -#: parser/analyze.c:3182 +#: parser/analyze.c:3198 #, c-format msgid "materialized views must not use data-modifying statements in WITH" msgstr "materialisierte Sichten dürfen keine datenmodifizierenden Anweisungen in WITH verwenden" -#: parser/analyze.c:3192 +#: parser/analyze.c:3208 #, c-format msgid "materialized views must not use temporary tables or views" msgstr "materialisierte Sichten dürfen keine temporären Tabellen oder Sichten verwenden" -#: parser/analyze.c:3202 +#: parser/analyze.c:3218 #, c-format msgid "materialized views may not be defined using bound parameters" msgstr "materialisierte Sichten können nicht unter Verwendung von gebundenen Parametern definiert werden" -#: parser/analyze.c:3214 +#: parser/analyze.c:3230 #, c-format msgid "materialized views cannot be unlogged" msgstr "materialisierte Sichten können nicht ungeloggt sein" #. translator: %s is a SQL row locking clause such as FOR UPDATE -#: parser/analyze.c:3403 +#: parser/analyze.c:3419 #, c-format msgid "%s is not allowed with DISTINCT clause" msgstr "%s ist nicht mit DISTINCT-Klausel erlaubt" #. translator: %s is a SQL row locking clause such as FOR UPDATE -#: parser/analyze.c:3410 +#: parser/analyze.c:3426 #, c-format msgid "%s is not allowed with GROUP BY clause" msgstr "%s ist nicht mit GROUP-BY-Klausel erlaubt" #. translator: %s is a SQL row locking clause such as FOR UPDATE -#: parser/analyze.c:3417 +#: parser/analyze.c:3433 #, c-format msgid "%s is not allowed with HAVING clause" msgstr "%s ist nicht mit HAVING-Klausel erlaubt" #. translator: %s is a SQL row locking clause such as FOR UPDATE -#: parser/analyze.c:3424 +#: parser/analyze.c:3440 #, c-format msgid "%s is not allowed with aggregate functions" msgstr "%s ist nicht mit Aggregatfunktionen erlaubt" #. translator: %s is a SQL row locking clause such as FOR UPDATE -#: parser/analyze.c:3431 +#: parser/analyze.c:3447 #, c-format msgid "%s is not allowed with window functions" msgstr "%s ist nicht mit Fensterfunktionen erlaubt" #. translator: %s is a SQL row locking clause such as FOR UPDATE -#: parser/analyze.c:3438 +#: parser/analyze.c:3454 #, c-format msgid "%s is not allowed with set-returning functions in the target list" msgstr "%s ist nicht mit Funktionen mit Ergebnismenge in der Targetliste erlaubt" #. translator: %s is a SQL row locking clause such as FOR UPDATE -#: parser/analyze.c:3537 +#: parser/analyze.c:3553 #, c-format msgid "%s must specify unqualified relation names" msgstr "%s muss unqualifizierte Relationsnamen angeben" #. translator: %s is a SQL row locking clause such as FOR UPDATE -#: parser/analyze.c:3601 +#: parser/analyze.c:3617 #, c-format msgid "%s cannot be applied to a join" msgstr "%s kann nicht auf einen Verbund angewendet werden" #. translator: %s is a SQL row locking clause such as FOR UPDATE -#: parser/analyze.c:3610 +#: parser/analyze.c:3626 #, c-format msgid "%s cannot be applied to a function" msgstr "%s kann nicht auf eine Funktion angewendet werden" #. translator: %s is a SQL row locking clause such as FOR UPDATE -#: parser/analyze.c:3619 +#: parser/analyze.c:3635 #, c-format msgid "%s cannot be applied to a table function" msgstr "%s kann nicht auf eine Tabellenfunktion angewendet werden" #. translator: %s is a SQL row locking clause such as FOR UPDATE -#: parser/analyze.c:3637 +#: parser/analyze.c:3653 #, c-format msgid "%s cannot be applied to a WITH query" msgstr "%s kann nicht auf eine WITH-Anfrage angewendet werden" #. translator: %s is a SQL row locking clause such as FOR UPDATE -#: parser/analyze.c:3646 +#: parser/analyze.c:3662 #, c-format msgid "%s cannot be applied to a named tuplestore" msgstr "%s kann nicht auf einen benannten Tupelstore angewendet werden" #. translator: %s is a SQL row locking clause such as FOR UPDATE -#: parser/analyze.c:3666 +#: parser/analyze.c:3682 #, c-format msgid "relation \"%s\" in %s clause not found in FROM clause" msgstr "Relation »%s« in %s nicht in der FROM-Klausel gefunden" @@ -18079,27 +18084,27 @@ msgstr "Fenster »%s« existiert nicht" msgid "too many grouping sets present (maximum 4096)" msgstr "zu viele Grouping-Sets vorhanden (maximal 4096)" -#: parser/parse_agg.c:1329 +#: parser/parse_agg.c:1331 #, c-format msgid "aggregate functions are not allowed in a recursive query's recursive term" msgstr "Aggregatfunktionen sind nicht im rekursiven Ausdruck einer rekursiven Anfrage erlaubt" -#: parser/parse_agg.c:1552 +#: parser/parse_agg.c:1554 #, c-format msgid "column \"%s.%s\" must appear in the GROUP BY clause or be used in an aggregate function" msgstr "Spalte »%s.%s« muss in der GROUP-BY-Klausel erscheinen oder in einer Aggregatfunktion verwendet werden" -#: parser/parse_agg.c:1555 +#: parser/parse_agg.c:1557 #, c-format msgid "Direct arguments of an ordered-set aggregate must use only grouped columns." msgstr "Direkte Argumente einer Ordered-Set-Aggregatfunktion dürfen nur gruppierte Spalten verwenden." -#: parser/parse_agg.c:1560 +#: parser/parse_agg.c:1562 #, c-format msgid "subquery uses ungrouped column \"%s.%s\" from outer query" msgstr "Unteranfrage verwendet nicht gruppierte Spalte »%s.%s« aus äußerer Anfrage" -#: parser/parse_agg.c:1725 +#: parser/parse_agg.c:1727 #, c-format msgid "arguments to GROUPING must be grouping expressions of the associated query level" msgstr "Argumente von GROUPING müssen Gruppierausdrücke der zugehörigen Anfrageebene sein" @@ -19548,7 +19553,7 @@ msgstr "op ANY/ALL (array) erfordert, dass Operator keine Ergebnismenge zurückg msgid "inconsistent types deduced for parameter $%d" msgstr "inkonsistente Typen für Parameter $%d ermittelt" -#: parser/parse_param.c:310 tcop/postgres.c:734 +#: parser/parse_param.c:310 tcop/postgres.c:735 #, c-format msgid "could not determine data type of parameter $%d" msgstr "konnte Datentyp von Parameter $%d nicht ermitteln" @@ -19902,254 +19907,254 @@ msgstr "Relation »%s« ist ungültig in der LIKE-Klausel" msgid "Index \"%s\" contains a whole-row table reference." msgstr "Index »%s« enthält einen Verweis auf die ganze Zeile der Tabelle." -#: parser/parse_utilcmd.c:2419 +#: parser/parse_utilcmd.c:2423 #, c-format msgid "cannot use an existing index in CREATE TABLE" msgstr "bestehender Index kann nicht in CREATE TABLE verwendet werden" -#: parser/parse_utilcmd.c:2439 +#: parser/parse_utilcmd.c:2443 #, c-format msgid "index \"%s\" is already associated with a constraint" msgstr "Index »%s« gehört bereits zu einem Constraint" -#: parser/parse_utilcmd.c:2465 +#: parser/parse_utilcmd.c:2469 #, c-format msgid "\"%s\" is not a unique index" msgstr "»%s« ist kein Unique Index" -#: parser/parse_utilcmd.c:2466 parser/parse_utilcmd.c:2473 -#: parser/parse_utilcmd.c:2480 parser/parse_utilcmd.c:2556 +#: parser/parse_utilcmd.c:2470 parser/parse_utilcmd.c:2477 +#: parser/parse_utilcmd.c:2484 parser/parse_utilcmd.c:2560 #, c-format msgid "Cannot create a primary key or unique constraint using such an index." msgstr "Ein Primärschlüssel oder Unique-Constraint kann nicht mit einem solchen Index erzeugt werden." -#: parser/parse_utilcmd.c:2472 +#: parser/parse_utilcmd.c:2476 #, c-format msgid "index \"%s\" contains expressions" msgstr "Index »%s« enthält Ausdrücke" -#: parser/parse_utilcmd.c:2479 +#: parser/parse_utilcmd.c:2483 #, c-format msgid "\"%s\" is a partial index" msgstr "»%s« ist ein partieller Index" -#: parser/parse_utilcmd.c:2491 +#: parser/parse_utilcmd.c:2495 #, c-format msgid "\"%s\" is a deferrable index" msgstr "»%s« ist ein aufschiebbarer Index" -#: parser/parse_utilcmd.c:2492 +#: parser/parse_utilcmd.c:2496 #, c-format msgid "Cannot create a non-deferrable constraint using a deferrable index." msgstr "Ein nicht aufschiebbarer Constraint kann nicht mit einem aufschiebbaren Index erzeugt werden." -#: parser/parse_utilcmd.c:2555 +#: parser/parse_utilcmd.c:2559 #, c-format msgid "index \"%s\" column number %d does not have default sorting behavior" msgstr "Index »%s« Spalte Nummer %d hat nicht das Standardsortierverhalten" -#: parser/parse_utilcmd.c:2747 +#: parser/parse_utilcmd.c:2751 #, c-format msgid "column \"%s\" appears twice in primary key constraint" msgstr "Spalte »%s« erscheint zweimal im Primärschlüssel-Constraint" -#: parser/parse_utilcmd.c:2753 +#: parser/parse_utilcmd.c:2757 #, c-format msgid "column \"%s\" appears twice in unique constraint" msgstr "Spalte »%s« erscheint zweimal im Unique-Constraint" -#: parser/parse_utilcmd.c:2798 +#: parser/parse_utilcmd.c:2807 #, c-format msgid "column \"%s\" in WITHOUT OVERLAPS is not a range or multirange type" msgstr "Spalte »%s« in WITHOUT OVERLAPS ist kein Range- oder Multirange-Typ" -#: parser/parse_utilcmd.c:2826 +#: parser/parse_utilcmd.c:2835 #, c-format msgid "constraint using WITHOUT OVERLAPS needs at least two columns" msgstr "Constraints, die WITHOUT OVERLAPS verwenden, benötigen mindestens zwei Spalten" -#: parser/parse_utilcmd.c:3123 +#: parser/parse_utilcmd.c:3132 #, c-format msgid "index expressions and predicates can refer only to the table being indexed" msgstr "Indexausdrücke und -prädikate können nur auf die zu indizierende Tabelle verweisen" -#: parser/parse_utilcmd.c:3195 +#: parser/parse_utilcmd.c:3204 #, c-format msgid "statistics expressions can refer only to the table being referenced" msgstr "Statistikausdrücke können nur auf die referenzierte Tabelle verweisen" -#: parser/parse_utilcmd.c:3238 +#: parser/parse_utilcmd.c:3247 #, c-format msgid "rules on materialized views are not supported" msgstr "Regeln für materialisierte Sichten werden nicht unterstützt" -#: parser/parse_utilcmd.c:3298 +#: parser/parse_utilcmd.c:3307 #, c-format msgid "rule WHERE condition cannot contain references to other relations" msgstr "WHERE-Bedingung einer Regel kann keine Verweise auf andere Relationen enthalten" -#: parser/parse_utilcmd.c:3370 +#: parser/parse_utilcmd.c:3379 #, c-format msgid "rules with WHERE conditions can only have SELECT, INSERT, UPDATE, or DELETE actions" msgstr "Regeln mit WHERE-Bedingungen können als Aktion nur SELECT, INSERT, UPDATE oder DELETE haben" -#: parser/parse_utilcmd.c:3388 parser/parse_utilcmd.c:3489 -#: rewrite/rewriteHandler.c:546 rewrite/rewriteManip.c:1187 +#: parser/parse_utilcmd.c:3397 parser/parse_utilcmd.c:3498 +#: rewrite/rewriteHandler.c:545 rewrite/rewriteManip.c:1198 #, c-format msgid "conditional UNION/INTERSECT/EXCEPT statements are not implemented" msgstr "UNION/INTERSECTION/EXCEPT mit Bedingung sind nicht implementiert" -#: parser/parse_utilcmd.c:3406 +#: parser/parse_utilcmd.c:3415 #, c-format msgid "ON SELECT rule cannot use OLD" msgstr "ON-SELECT-Regel kann nicht OLD verwenden" -#: parser/parse_utilcmd.c:3410 +#: parser/parse_utilcmd.c:3419 #, c-format msgid "ON SELECT rule cannot use NEW" msgstr "ON-SELECT-Regel kann nicht NEW verwenden" -#: parser/parse_utilcmd.c:3419 +#: parser/parse_utilcmd.c:3428 #, c-format msgid "ON INSERT rule cannot use OLD" msgstr "ON-INSERT-Regel kann nicht OLD verwenden" -#: parser/parse_utilcmd.c:3425 +#: parser/parse_utilcmd.c:3434 #, c-format msgid "ON DELETE rule cannot use NEW" msgstr "ON-DELETE-Regel kann nicht NEW verwenden" -#: parser/parse_utilcmd.c:3453 +#: parser/parse_utilcmd.c:3462 #, c-format msgid "cannot refer to OLD within WITH query" msgstr "in WITH-Anfrage kann nicht auf OLD verweisen werden" -#: parser/parse_utilcmd.c:3460 +#: parser/parse_utilcmd.c:3469 #, c-format msgid "cannot refer to NEW within WITH query" msgstr "in WITH-Anfrage kann nicht auf NEW verwiesen werden" -#: parser/parse_utilcmd.c:3918 +#: parser/parse_utilcmd.c:3927 #, c-format msgid "misplaced DEFERRABLE clause" msgstr "falsch platzierte DEFERRABLE-Klausel" -#: parser/parse_utilcmd.c:3923 parser/parse_utilcmd.c:3938 +#: parser/parse_utilcmd.c:3932 parser/parse_utilcmd.c:3947 #, c-format msgid "multiple DEFERRABLE/NOT DEFERRABLE clauses not allowed" msgstr "mehrere DEFERRABLE/NOT DEFERRABLE-Klauseln sind nicht erlaubt" -#: parser/parse_utilcmd.c:3933 +#: parser/parse_utilcmd.c:3942 #, c-format msgid "misplaced NOT DEFERRABLE clause" msgstr "falsch platzierte NOT DEFERRABLE-Klausel" -#: parser/parse_utilcmd.c:3954 +#: parser/parse_utilcmd.c:3963 #, c-format msgid "misplaced INITIALLY DEFERRED clause" msgstr "falsch platzierte INITIALLY DEFERRED-Klausel" -#: parser/parse_utilcmd.c:3959 parser/parse_utilcmd.c:3985 +#: parser/parse_utilcmd.c:3968 parser/parse_utilcmd.c:3994 #, c-format msgid "multiple INITIALLY IMMEDIATE/DEFERRED clauses not allowed" msgstr "mehrere INITIALLY IMMEDIATE/DEFERRED-Klauseln sind nicht erlaubt" -#: parser/parse_utilcmd.c:3980 +#: parser/parse_utilcmd.c:3989 #, c-format msgid "misplaced INITIALLY IMMEDIATE clause" msgstr "falsch platzierte INITIALLY IMMEDIATE-Klausel" -#: parser/parse_utilcmd.c:3997 +#: parser/parse_utilcmd.c:4006 #, c-format msgid "misplaced ENFORCED clause" msgstr "falsch platzierte ENFORCED-Klausel" -#: parser/parse_utilcmd.c:4002 parser/parse_utilcmd.c:4019 +#: parser/parse_utilcmd.c:4011 parser/parse_utilcmd.c:4028 #, c-format msgid "multiple ENFORCED/NOT ENFORCED clauses not allowed" msgstr "mehrere ENFORCED/NOT ENFORCED-Klauseln sind nicht erlaubt" -#: parser/parse_utilcmd.c:4014 +#: parser/parse_utilcmd.c:4023 #, c-format msgid "misplaced NOT ENFORCED clause" msgstr "falsch platzierte NOT ENFORCED-Klausel" -#: parser/parse_utilcmd.c:4212 +#: parser/parse_utilcmd.c:4221 #, c-format msgid "CREATE specifies a schema (%s) different from the one being created (%s)" msgstr "CREATE gibt ein Schema an (%s) welches nicht gleich dem zu erzeugenden Schema ist (%s)" -#: parser/parse_utilcmd.c:4247 +#: parser/parse_utilcmd.c:4256 #, c-format msgid "\"%s\" is not a partitioned table" msgstr "»%s« ist keine partitionierte Tabelle" -#: parser/parse_utilcmd.c:4254 +#: parser/parse_utilcmd.c:4263 #, c-format msgid "table \"%s\" is not partitioned" msgstr "Tabelle »%s« ist nicht partitioniert" -#: parser/parse_utilcmd.c:4261 +#: parser/parse_utilcmd.c:4270 #, c-format msgid "index \"%s\" is not partitioned" msgstr "Index »%s« ist nicht partitioniert" -#: parser/parse_utilcmd.c:4301 +#: parser/parse_utilcmd.c:4310 #, c-format msgid "a hash-partitioned table may not have a default partition" msgstr "eine hashpartitionierte Tabelle kann keine Standardpartition haben" -#: parser/parse_utilcmd.c:4318 +#: parser/parse_utilcmd.c:4327 #, c-format msgid "invalid bound specification for a hash partition" msgstr "ungültige Begrenzungsangabe für eine Hash-Partition" -#: parser/parse_utilcmd.c:4324 partitioning/partbounds.c:4802 +#: parser/parse_utilcmd.c:4333 partitioning/partbounds.c:4802 #, c-format msgid "modulus for hash partition must be an integer value greater than zero" msgstr "Modulus für Hashpartition muss eine ganze Zahl größer als null sein" -#: parser/parse_utilcmd.c:4331 partitioning/partbounds.c:4810 +#: parser/parse_utilcmd.c:4340 partitioning/partbounds.c:4810 #, c-format msgid "remainder for hash partition must be less than modulus" msgstr "Rest für Hashpartition muss kleiner als Modulus sein" -#: parser/parse_utilcmd.c:4344 +#: parser/parse_utilcmd.c:4353 #, c-format msgid "invalid bound specification for a list partition" msgstr "ungültige Begrenzungsangabe für eine Listenpartition" -#: parser/parse_utilcmd.c:4397 +#: parser/parse_utilcmd.c:4406 #, c-format msgid "invalid bound specification for a range partition" msgstr "ungültige Begrenzungsangabe für eine Bereichspartition" -#: parser/parse_utilcmd.c:4403 +#: parser/parse_utilcmd.c:4412 #, c-format msgid "FROM must specify exactly one value per partitioning column" msgstr "FROM muss genau einen Wert pro Partitionierungsspalte angeben" -#: parser/parse_utilcmd.c:4407 +#: parser/parse_utilcmd.c:4416 #, c-format msgid "TO must specify exactly one value per partitioning column" msgstr "TO muss genau einen Wert pro Partitionierungsspalte angeben" -#: parser/parse_utilcmd.c:4523 +#: parser/parse_utilcmd.c:4532 #, c-format msgid "cannot specify NULL in range bound" msgstr "NULL kann nicht in der Bereichsgrenze angegeben werden" -#: parser/parse_utilcmd.c:4571 +#: parser/parse_utilcmd.c:4580 #, c-format msgid "every bound following MAXVALUE must also be MAXVALUE" msgstr "jede Begrenzung, die auf MAXVALUE folgt, muss auch MAXVALUE sein" -#: parser/parse_utilcmd.c:4578 +#: parser/parse_utilcmd.c:4587 #, c-format msgid "every bound following MINVALUE must also be MINVALUE" msgstr "jede Begrenzung, die auf MINVALUE folgt, muss auch MINVALUE sein" -#: parser/parse_utilcmd.c:4621 +#: parser/parse_utilcmd.c:4630 #, c-format msgid "specified value cannot be cast to type %s for column \"%s\"" msgstr "angegebener Wert kann nicht in Typ %s für Spalte »%s« umgewandelt werden" @@ -20546,7 +20551,7 @@ msgstr "Background-Worker »%s«: ungültiges Neustart-Intervall" msgid "background worker \"%s\": parallel workers may not be configured for restart" msgstr "Background-Worker »%s«: parallele Arbeitsprozesse dürfen nicht für Neustart konfiguriert sein" -#: postmaster/bgworker.c:710 tcop/postgres.c:3343 +#: postmaster/bgworker.c:710 tcop/postgres.c:3344 #, c-format msgid "terminating background worker \"%s\" due to administrator command" msgstr "Background-Worker »%s« wird abgebrochen aufgrund von Anweisung des Administrators" @@ -20740,138 +20745,138 @@ msgstr "Archivmodule müssen das Symbol %s definieren" msgid "archive modules must register an archive callback" msgstr "Archivmodule müssen einen Archiv-Callback registrieren" -#: postmaster/postmaster.c:678 +#: postmaster/postmaster.c:679 #, c-format msgid "%s: invalid argument for option -f: \"%s\"\n" msgstr "%s: ungültiges Argument für Option -f: »%s«\n" -#: postmaster/postmaster.c:751 +#: postmaster/postmaster.c:752 #, c-format msgid "%s: invalid argument for option -t: \"%s\"\n" msgstr "%s: ungültiges Argument für Option -t: »%s«\n" -#: postmaster/postmaster.c:774 +#: postmaster/postmaster.c:775 #, c-format msgid "%s: invalid argument: \"%s\"\n" msgstr "%s: ungültiges Argument: »%s«\n" -#: postmaster/postmaster.c:842 +#: postmaster/postmaster.c:843 #, c-format msgid "%s: \"superuser_reserved_connections\" (%d) plus \"reserved_connections\" (%d) must be less than \"max_connections\" (%d)\n" msgstr "%s: »superuser_reserved_connections« (%d) plus »reserved_connections« (%d) muss kleiner als »max_connections« (%d) sein\n" -#: postmaster/postmaster.c:850 +#: postmaster/postmaster.c:851 #, c-format msgid "WAL archival cannot be enabled when \"wal_level\" is \"minimal\"" msgstr "WAL-Archivierung kann nicht eingeschaltet werden, wenn »wal_level« »minimal« ist" -#: postmaster/postmaster.c:853 +#: postmaster/postmaster.c:854 #, c-format msgid "WAL streaming (\"max_wal_senders\" > 0) requires \"wal_level\" to be \"replica\" or \"logical\"" msgstr "WAL-Streaming (»max_wal_senders« > 0) benötigt »wal_level« »replica« oder »logical«" -#: postmaster/postmaster.c:856 +#: postmaster/postmaster.c:857 #, c-format msgid "WAL cannot be summarized when \"wal_level\" is \"minimal\"" msgstr "WAL kann nicht zusammengefasst werden, wenn »wal_level« »minimal« ist" -#: postmaster/postmaster.c:864 +#: postmaster/postmaster.c:865 #, c-format msgid "%s: invalid datetoken tables, please fix\n" msgstr "%s: ungültige datetoken-Tabellen, bitte reparieren\n" -#: postmaster/postmaster.c:1025 +#: postmaster/postmaster.c:1026 #, c-format msgid "could not create I/O completion port for child queue" msgstr "konnte Ein-/Ausgabe-Completion-Port für Child-Queue nicht erzeugen" -#: postmaster/postmaster.c:1091 +#: postmaster/postmaster.c:1092 #, c-format msgid "ending log output to stderr" msgstr "Logausgabe nach stderr endet" -#: postmaster/postmaster.c:1092 +#: postmaster/postmaster.c:1093 #, c-format msgid "Future log output will go to log destination \"%s\"." msgstr "Die weitere Logausgabe geht an Logziel »%s«." -#: postmaster/postmaster.c:1103 +#: postmaster/postmaster.c:1104 #, c-format msgid "starting %s" msgstr "%s startet" -#: postmaster/postmaster.c:1165 +#: postmaster/postmaster.c:1166 #, c-format msgid "could not create listen socket for \"%s\"" msgstr "konnte Listen-Socket für »%s« nicht erzeugen" -#: postmaster/postmaster.c:1171 +#: postmaster/postmaster.c:1172 #, c-format msgid "could not create any TCP/IP sockets" msgstr "konnte keine TCP/IP-Sockets erstellen" -#: postmaster/postmaster.c:1203 +#: postmaster/postmaster.c:1204 #, c-format msgid "DNSServiceRegister() failed: error code %ld" msgstr "DNSServiceRegister() fehlgeschlagen: Fehlercode %ld" -#: postmaster/postmaster.c:1256 +#: postmaster/postmaster.c:1257 #, c-format msgid "could not create Unix-domain socket in directory \"%s\"" msgstr "konnte Unix-Domain-Socket in Verzeichnis »%s« nicht erzeugen" -#: postmaster/postmaster.c:1262 +#: postmaster/postmaster.c:1263 #, c-format msgid "could not create any Unix-domain sockets" msgstr "konnte keine Unix-Domain-Sockets erzeugen" -#: postmaster/postmaster.c:1273 +#: postmaster/postmaster.c:1274 #, c-format msgid "no socket created for listening" msgstr "keine Listen-Socket erzeugt" -#: postmaster/postmaster.c:1304 +#: postmaster/postmaster.c:1305 #, c-format msgid "%s: could not change permissions of external PID file \"%s\": %m\n" msgstr "%s: konnte Rechte der externen PID-Datei »%s« nicht ändern: %m\n" -#: postmaster/postmaster.c:1308 +#: postmaster/postmaster.c:1309 #, c-format msgid "%s: could not write external PID file \"%s\": %m\n" msgstr "%s: konnte externe PID-Datei »%s« nicht schreiben: %m\n" #. translator: %s is a configuration file -#: postmaster/postmaster.c:1336 utils/init/postinit.c:225 +#: postmaster/postmaster.c:1337 utils/init/postinit.c:225 #, c-format msgid "could not load %s" msgstr "konnte %s nicht laden" -#: postmaster/postmaster.c:1364 +#: postmaster/postmaster.c:1365 #, c-format msgid "postmaster became multithreaded during startup" msgstr "Postmaster ist während des Starts multithreaded geworden" -#: postmaster/postmaster.c:1365 postmaster/postmaster.c:3668 +#: postmaster/postmaster.c:1366 postmaster/postmaster.c:3650 #, c-format msgid "Set the LC_ALL environment variable to a valid locale." msgstr "Setzen Sie die Umgebungsvariable LC_ALL auf eine gültige Locale." -#: postmaster/postmaster.c:1468 +#: postmaster/postmaster.c:1469 #, c-format msgid "%s: could not locate my own executable path" msgstr "%s: konnte Pfad des eigenen Programs nicht finden" -#: postmaster/postmaster.c:1475 +#: postmaster/postmaster.c:1476 #, c-format msgid "%s: could not locate matching postgres executable" msgstr "%s: konnte kein passendes Programm »postgres« finden" -#: postmaster/postmaster.c:1498 utils/misc/tzparser.c:342 +#: postmaster/postmaster.c:1499 utils/misc/tzparser.c:342 #, c-format msgid "This may indicate an incomplete PostgreSQL installation, or that the file \"%s\" has been moved away from its proper location." msgstr "Dies kann auf eine unvollständige PostgreSQL-Installation hindeuten, oder darauf, dass die Datei »%s« von ihrer richtigen Stelle verschoben worden ist." -#: postmaster/postmaster.c:1525 +#: postmaster/postmaster.c:1526 #, c-format msgid "" "%s: could not find the database system\n" @@ -20883,229 +20888,224 @@ msgstr "" "aber die Datei »%s« konnte nicht geöffnet werden: %m\n" #. translator: %s is SIGKILL or SIGABRT -#: postmaster/postmaster.c:1762 +#: postmaster/postmaster.c:1763 #, c-format msgid "issuing %s to recalcitrant children" msgstr "%s wird an ungehorsame Kinder gesendet" -#: postmaster/postmaster.c:1784 +#: postmaster/postmaster.c:1785 #, c-format msgid "performing immediate shutdown because data directory lock file is invalid" msgstr "führe sofortiges Herunterfahren durch, weil Sperrdatei im Datenverzeichnis ungültig ist" -#: postmaster/postmaster.c:2004 +#: postmaster/postmaster.c:2005 #, c-format msgid "received SIGHUP, reloading configuration files" msgstr "SIGHUP empfangen, Konfigurationsdateien werden neu geladen" #. translator: %s is a configuration file -#: postmaster/postmaster.c:2012 postmaster/postmaster.c:2016 +#: postmaster/postmaster.c:2013 postmaster/postmaster.c:2017 #, c-format msgid "%s was not reloaded" msgstr "%s wurde nicht neu geladen" -#: postmaster/postmaster.c:2026 +#: postmaster/postmaster.c:2027 #, c-format msgid "SSL configuration was not reloaded" msgstr "SSL-Konfiguration wurde nicht neu geladen" -#: postmaster/postmaster.c:2112 +#: postmaster/postmaster.c:2113 #, c-format msgid "received smart shutdown request" msgstr "intelligentes Herunterfahren verlangt" -#: postmaster/postmaster.c:2153 +#: postmaster/postmaster.c:2154 #, c-format msgid "received fast shutdown request" msgstr "schnelles Herunterfahren verlangt" -#: postmaster/postmaster.c:2171 +#: postmaster/postmaster.c:2172 #, c-format msgid "aborting any active transactions" msgstr "etwaige aktive Transaktionen werden abgebrochen" -#: postmaster/postmaster.c:2195 +#: postmaster/postmaster.c:2196 #, c-format msgid "received immediate shutdown request" msgstr "sofortiges Herunterfahren verlangt" -#: postmaster/postmaster.c:2270 +#: postmaster/postmaster.c:2271 #, c-format msgid "shutdown at recovery target" msgstr "Herunterfahren beim Wiederherstellungsziel" -#: postmaster/postmaster.c:2288 postmaster/postmaster.c:2324 +#: postmaster/postmaster.c:2309 msgid "startup process" msgstr "Startprozess" -#: postmaster/postmaster.c:2291 -#, c-format -msgid "aborting startup due to startup process failure" -msgstr "Serverstart abgebrochen wegen Startprozessfehler" - -#: postmaster/postmaster.c:2347 +#: postmaster/postmaster.c:2332 #, c-format msgid "database system is ready to accept connections" msgstr "Datenbanksystem ist bereit, um Verbindungen anzunehmen" -#: postmaster/postmaster.c:2369 +#: postmaster/postmaster.c:2354 msgid "background writer process" msgstr "Background-Writer-Prozess" -#: postmaster/postmaster.c:2402 +#: postmaster/postmaster.c:2387 msgid "checkpointer process" msgstr "Checkpointer-Prozess" -#: postmaster/postmaster.c:2419 +#: postmaster/postmaster.c:2404 msgid "WAL writer process" msgstr "WAL-Schreibprozess" -#: postmaster/postmaster.c:2435 +#: postmaster/postmaster.c:2420 msgid "WAL receiver process" msgstr "WAL-Receiver-Prozess" -#: postmaster/postmaster.c:2450 +#: postmaster/postmaster.c:2435 msgid "WAL summarizer process" msgstr "WAL-Summarizer-Prozess" -#: postmaster/postmaster.c:2466 +#: postmaster/postmaster.c:2451 msgid "autovacuum launcher process" msgstr "Autovacuum-Launcher-Prozess" -#: postmaster/postmaster.c:2482 +#: postmaster/postmaster.c:2467 msgid "archiver process" msgstr "Archivierprozess" -#: postmaster/postmaster.c:2497 +#: postmaster/postmaster.c:2482 msgid "system logger process" msgstr "Systemlogger-Prozess" -#: postmaster/postmaster.c:2515 +#: postmaster/postmaster.c:2500 msgid "slot sync worker process" msgstr "Slot-Sync-Arbeitsprozess" -#: postmaster/postmaster.c:2523 utils/init/miscinit.c:297 +#: postmaster/postmaster.c:2508 utils/init/miscinit.c:297 msgid "io worker" msgstr "I/O-Arbeitsprozess" -#: postmaster/postmaster.c:2545 postmaster/postmaster.c:2547 +#: postmaster/postmaster.c:2530 postmaster/postmaster.c:2532 msgid "untracked child process" msgstr "nicht verfolgter Kindprozess" -#: postmaster/postmaster.c:2580 +#: postmaster/postmaster.c:2565 #, c-format msgid "background worker \"%s\"" msgstr "Background-Worker »%s«" -#: postmaster/postmaster.c:2804 +#: postmaster/postmaster.c:2786 #, c-format msgid "terminating any other active server processes" msgstr "aktive Serverprozesse werden abgebrochen" #. translator: %s is a noun phrase describing a child process, such as #. "server process" -#: postmaster/postmaster.c:2837 +#: postmaster/postmaster.c:2819 #, c-format msgid "%s (PID %d) exited with exit code %d" msgstr "%s (PID %d) beendete mit Status %d" -#: postmaster/postmaster.c:2839 postmaster/postmaster.c:2851 -#: postmaster/postmaster.c:2861 postmaster/postmaster.c:2872 +#: postmaster/postmaster.c:2821 postmaster/postmaster.c:2833 +#: postmaster/postmaster.c:2843 postmaster/postmaster.c:2854 #, c-format msgid "Failed process was running: %s" msgstr "Der fehlgeschlagene Prozess führte aus: %s" #. translator: %s is a noun phrase describing a child process, such as #. "server process" -#: postmaster/postmaster.c:2848 +#: postmaster/postmaster.c:2830 #, c-format msgid "%s (PID %d) was terminated by exception 0x%X" msgstr "%s (PID %d) wurde durch Ausnahme 0x%X beendet" #. translator: %s is a noun phrase describing a child process, such as #. "server process" -#: postmaster/postmaster.c:2858 +#: postmaster/postmaster.c:2840 #, c-format msgid "%s (PID %d) was terminated by signal %d: %s" msgstr "%s (PID %d) wurde von Signal %d beendet: %s" #. translator: %s is a noun phrase describing a child process, such as #. "server process" -#: postmaster/postmaster.c:2870 +#: postmaster/postmaster.c:2852 #, c-format msgid "%s (PID %d) exited with unrecognized status %d" msgstr "%s (PID %d) beendete mit unbekanntem Status %d" -#: postmaster/postmaster.c:3161 +#: postmaster/postmaster.c:3143 #, c-format msgid "abnormal database system shutdown" msgstr "abnormales Herunterfahren des Datenbanksystems" -#: postmaster/postmaster.c:3187 +#: postmaster/postmaster.c:3169 #, c-format msgid "shutting down due to startup process failure" msgstr "fahre herunter wegen Startprozessfehler" -#: postmaster/postmaster.c:3193 +#: postmaster/postmaster.c:3175 #, c-format msgid "shutting down because \"restart_after_crash\" is off" msgstr "fahre herunter, weil »restart_after_crash« aus ist" -#: postmaster/postmaster.c:3205 +#: postmaster/postmaster.c:3187 #, c-format msgid "all server processes terminated; reinitializing" msgstr "alle Serverprozesse beendet; initialisiere neu" -#: postmaster/postmaster.c:3598 +#: postmaster/postmaster.c:3580 #, c-format msgid "could not fork new process for connection: %m" msgstr "konnte neuen Prozess für Verbindung nicht starten (fork-Fehler): %m" -#: postmaster/postmaster.c:3633 +#: postmaster/postmaster.c:3615 msgid "could not fork new process for connection: " msgstr "konnte neuen Prozess für Verbindung nicht starten (fork-Fehler): " -#: postmaster/postmaster.c:3667 +#: postmaster/postmaster.c:3649 #, c-format msgid "postmaster became multithreaded" msgstr "Postmaster ist multithreaded geworden" -#: postmaster/postmaster.c:3745 +#: postmaster/postmaster.c:3727 #, c-format msgid "database system is ready to accept read-only connections" msgstr "Datenbanksystem ist bereit, um lesende Verbindungen anzunehmen" -#: postmaster/postmaster.c:3846 +#: postmaster/postmaster.c:3828 #, c-format msgid "WAL was shut down unexpectedly" msgstr "WAL wurde unerwartet heruntergefahren" -#: postmaster/postmaster.c:3971 +#: postmaster/postmaster.c:3953 #, c-format msgid "no slot available for new autovacuum worker process" msgstr "kein Slot für neuen Autovacuum-Worker-Prozess verfügbar" -#: postmaster/postmaster.c:3986 +#: postmaster/postmaster.c:3968 #, c-format msgid "could not fork \"%s\" process: %m" msgstr "konnte »%s«-Prozess nicht starten (fork-Fehler): %m" -#: postmaster/postmaster.c:4145 +#: postmaster/postmaster.c:4127 #, c-format msgid "no slot available for new background worker process" msgstr "kein Slot für neuen Background-Worker-Prozess verfügbar" -#: postmaster/postmaster.c:4163 +#: postmaster/postmaster.c:4145 #, c-format msgid "could not fork background worker process: %m" msgstr "konnte Background-Worker-Prozess nicht starten (fork-Fehler): %m" -#: postmaster/postmaster.c:4496 +#: postmaster/postmaster.c:4478 #, c-format msgid "could not read exit code for process\n" msgstr "konnte Exitcode des Prozesses nicht lesen\n" -#: postmaster/postmaster.c:4538 +#: postmaster/postmaster.c:4520 #, c-format msgid "could not post child completion status\n" msgstr "konnte Child-Completion-Status nicht versenden\n" @@ -21160,39 +21160,39 @@ msgstr "konnte Logdatei »%s« nicht öffnen: %m" msgid "disabling automatic rotation (use SIGHUP to re-enable)" msgstr "automatische Rotation abgeschaltet (SIGHUP zum Wiederanschalten verwenden)" -#: postmaster/walsummarizer.c:743 +#: postmaster/walsummarizer.c:744 #, c-format msgid "WAL summarization is not progressing" msgstr "WAL-Zusammenfassung kommt nicht voran" -#: postmaster/walsummarizer.c:744 +#: postmaster/walsummarizer.c:745 #, c-format msgid "Summarization is needed through %X/%X, but is stuck at %X/%X on disk and %X/%X in memory." msgstr "Zusammenfassung bis %X/%X wird benötigt, aber sie hängt fest bei %X/%X auf Festplatte und %X/%X im Speicher." -#: postmaster/walsummarizer.c:758 +#: postmaster/walsummarizer.c:759 #, c-format msgid "still waiting for WAL summarization through %X/%X after %ld second" msgid_plural "still waiting for WAL summarization through %X/%X after %ld seconds" msgstr[0] "warte immer noch auf WAL-Zusammenfassung bis %X/%X nach %ld Sekunde" msgstr[1] "warte immer noch auf WAL-Zusammenfassung bis %X/%X nach %ld Sekunden" -#: postmaster/walsummarizer.c:763 +#: postmaster/walsummarizer.c:764 #, c-format msgid "Summarization has reached %X/%X on disk and %X/%X in memory." msgstr "Zusammenfassung hat %X/%X auf Festplatte und %X/%X im Speicher erreicht." -#: postmaster/walsummarizer.c:1003 +#: postmaster/walsummarizer.c:1004 #, c-format msgid "could not find a valid record after %X/%X" msgstr "konnte keinen gültigen Datensatz nach %X/%X finden" -#: postmaster/walsummarizer.c:1048 +#: postmaster/walsummarizer.c:1049 #, c-format msgid "could not read WAL from timeline %u at %X/%X: %s" msgstr "konnte WAL aus Zeitleiste %u bei %X/%X nicht lesen: %s" -#: postmaster/walsummarizer.c:1054 +#: postmaster/walsummarizer.c:1055 #, c-format msgid "could not read WAL from timeline %u at %X/%X" msgstr "konnte WAL aus Zeitleiste %u bei %X/%X nicht lesen" @@ -21362,33 +21362,33 @@ msgstr "unerwarteter Pipeline-Modus" msgid "logical replication parallel apply worker for subscription \"%s\" has finished" msgstr "Parallel-Apply-Worker für logische Replikation für Subskription »%s« hat abschlossen" -#: replication/logical/applyparallelworker.c:822 +#: replication/logical/applyparallelworker.c:831 #, c-format msgid "lost connection to the logical replication apply worker" msgstr "Verbindung mit dem Apply-Worker für logische Replikation verloren" -#: replication/logical/applyparallelworker.c:1031 -#: replication/logical/applyparallelworker.c:1033 +#: replication/logical/applyparallelworker.c:1040 +#: replication/logical/applyparallelworker.c:1042 msgid "logical replication parallel apply worker" msgstr "Parallel-Apply-Worker für logische Replikation" -#: replication/logical/applyparallelworker.c:1047 +#: replication/logical/applyparallelworker.c:1056 #, c-format msgid "logical replication parallel apply worker exited due to error" msgstr "Parallel-Apply-Worker für logische Replikation beendete wegen eines Fehlers" -#: replication/logical/applyparallelworker.c:1134 -#: replication/logical/applyparallelworker.c:1307 +#: replication/logical/applyparallelworker.c:1143 +#: replication/logical/applyparallelworker.c:1316 #, c-format msgid "lost connection to the logical replication parallel apply worker" msgstr "Verbindung mit dem Parallel-Apply-Worker für logische Replikation verloren" -#: replication/logical/applyparallelworker.c:1187 +#: replication/logical/applyparallelworker.c:1196 #, c-format msgid "could not send data to shared-memory queue" msgstr "konnte Daten nicht an Shared-Memory-Queue senden" -#: replication/logical/applyparallelworker.c:1222 +#: replication/logical/applyparallelworker.c:1231 #, c-format msgid "logical replication apply worker will serialize the remaining changes of remote transaction %u to a file" msgstr "Apply-Worker für logische Replikation wird die restlichen Änderungen der Remote-Transaktion %u in eine Datei serialisieren" @@ -21808,63 +21808,63 @@ msgstr "konnte Datei »%s« nicht löschen, beim Löschen von %s/%s/xid*: %m" msgid "could not read from file \"%s\": read %d instead of %d bytes" msgstr "konnte nicht aus Datei »%s« lesen: %d statt %d Bytes gelesen" -#: replication/logical/slotsync.c:214 replication/logical/slotsync.c:596 +#: replication/logical/slotsync.c:225 replication/logical/slotsync.c:620 #, c-format msgid "could not synchronize replication slot \"%s\"" msgstr "konnte Replikations-Slot »%s« nicht synchronisieren" -#: replication/logical/slotsync.c:216 +#: replication/logical/slotsync.c:227 #, c-format msgid "Synchronization could lead to data loss, because the remote slot needs WAL at LSN %X/%X and catalog xmin %u, but the standby has LSN %X/%X and catalog xmin %u." msgstr "Synchronisation könnte zu Datenverlust führen, weil der Remote-Slot WAL bei LSN %X/%X und Katalog-xmin %u benötigt, aber der Standby LSN %X/%X und Katalog-xmin %u hat." -#: replication/logical/slotsync.c:475 +#: replication/logical/slotsync.c:499 #, c-format msgid "dropped replication slot \"%s\" of database with OID %u" msgstr "Replikations-Slot »%s« von Datenbank mit OID %u wurde gelöscht" -#: replication/logical/slotsync.c:597 +#: replication/logical/slotsync.c:621 #, c-format msgid "Synchronization could lead to data loss, because the standby could not build a consistent snapshot to decode WALs at LSN %X/%X." msgstr "Synchronisation könnte zu Datenverlust führen, weil der Standby keinen konsistenten Snapshot zum Dekodieren von WAL bei LSN %X/%X bauen konnte." -#: replication/logical/slotsync.c:606 +#: replication/logical/slotsync.c:630 #, c-format msgid "newly created replication slot \"%s\" is sync-ready now" msgstr "neu erzeugter Replikations-Slot »%s« ist jetzt bereit für die Synchronisierung" -#: replication/logical/slotsync.c:645 +#: replication/logical/slotsync.c:669 #, c-format msgid "skipping slot synchronization because the received slot sync LSN %X/%X for slot \"%s\" is ahead of the standby position %X/%X" msgstr "Slot-Synchronisierung wird übersprungen, weil die empfangene Slot-Sync-LSN %X/%X für Slot »%s« der Position %X/%X des Standbys voraus ist" -#: replication/logical/slotsync.c:667 +#: replication/logical/slotsync.c:691 #, c-format msgid "exiting from slot synchronization because same name slot \"%s\" already exists on the standby" msgstr "verlasse Slot-Synchronisierung, weil der gleiche Slot »%s« schon auf dem Standby existiert" -#: replication/logical/slotsync.c:838 +#: replication/logical/slotsync.c:862 #, c-format msgid "could not fetch failover logical slots info from the primary server: %s" msgstr "konnte Informationen über logische Failover-Slots nicht vom Primärserver holen: %s" -#: replication/logical/slotsync.c:987 +#: replication/logical/slotsync.c:1011 #, c-format msgid "could not fetch primary slot name \"%s\" info from the primary server: %s" msgstr "konnte Informationen über primary_slot_name »%s« nicht vom Primärserver holen: %s" -#: replication/logical/slotsync.c:989 +#: replication/logical/slotsync.c:1013 #, c-format msgid "Check if \"primary_slot_name\" is configured correctly." msgstr "Prüfen Sie, ob »primary_slot_name« korrekt konfiguriert ist." -#: replication/logical/slotsync.c:1009 +#: replication/logical/slotsync.c:1033 #, c-format msgid "cannot synchronize replication slots from a standby server" msgstr "Replikations-Slots können nicht von einem Standby-Server synchronisiert werden" #. translator: second %s is a GUC variable name -#: replication/logical/slotsync.c:1018 +#: replication/logical/slotsync.c:1042 #, c-format msgid "replication slot \"%s\" specified by \"%s\" does not exist on primary server" msgstr "Replikations-Slot »%s«, der in »%s« angegeben ist, existiert auf dem Publikationsserver nicht" @@ -21872,60 +21872,75 @@ msgstr "Replikations-Slot »%s«, der in »%s« angegeben ist, existiert auf dem #. translator: first %s is a connection option; second %s is a GUC #. variable name #. -#: replication/logical/slotsync.c:1051 +#: replication/logical/slotsync.c:1075 #, c-format msgid "replication slot synchronization requires \"%s\" to be specified in \"%s\"" msgstr "Replikations-Slot-Synchronisierung erfordert, dass »%s« in »%s« angegeben wird" -#: replication/logical/slotsync.c:1070 +#: replication/logical/slotsync.c:1094 #, c-format msgid "replication slot synchronization requires \"wal_level\" >= \"logical\"" msgstr "Replikations-Slot-Synchronisierung erfordert »wal_level« >= »logical«" #. translator: %s is a GUC variable name -#: replication/logical/slotsync.c:1085 replication/logical/slotsync.c:1113 +#: replication/logical/slotsync.c:1109 replication/logical/slotsync.c:1137 #, c-format msgid "replication slot synchronization requires \"%s\" to be set" msgstr "Replikations-Slot-Synchronisierung erfordert, dass »%s« definiert ist" #. translator: %s is a GUC variable name -#: replication/logical/slotsync.c:1099 +#: replication/logical/slotsync.c:1123 #, c-format msgid "replication slot synchronization requires \"%s\" to be enabled" msgstr "Replikations-Slot-Synchronisierung erfordert, dass »%s« eingeschaltet ist" #. translator: %s is a GUC variable name -#: replication/logical/slotsync.c:1151 +#: replication/logical/slotsync.c:1180 #, c-format -msgid "replication slot synchronization worker will shut down because \"%s\" is disabled" -msgstr "Arbeitsprozess für Replikations-Slot-Synchronisierung wird herunterfahren, weil »%s« deaktiviert ist" +msgid "replication slot synchronization worker will stop because \"%s\" is disabled" +msgstr "Arbeitsprozess für Replikations-Slot-Synchronisierung wird anhalten, weil »%s« deaktiviert ist" -#: replication/logical/slotsync.c:1160 +#: replication/logical/slotsync.c:1198 #, c-format msgid "replication slot synchronization worker will restart because of a parameter change" msgstr "Arbeitsprozess für Replikations-Slot-Synchronisierung wird neu starten wegen einer Parameteränderung" -#: replication/logical/slotsync.c:1184 +#: replication/logical/slotsync.c:1223 #, c-format -msgid "replication slot synchronization worker is shutting down because promotion is triggered" -msgstr "Arbeitsprozess für Replikations-Slot-Synchronisierung fährt herunter, weil Beförderung ausgelöst wurde" +msgid "replication slot synchronization will stop because of a parameter change" +msgstr "Arbeitsprozess für Replikations-Slot-Synchronisierung wird anhalten wegen einer Parameteränderung" -#: replication/logical/slotsync.c:1309 +#: replication/logical/slotsync.c:1259 #, c-format -msgid "cannot synchronize replication slots when standby promotion is ongoing" -msgstr "Replikations-Slots können nicht synchronisiert werden, während die Standby-Beförderung läuft" +msgid "replication slot synchronization worker will stop because promotion is triggered" +msgstr "Arbeitsprozess für Replikations-Slot-Synchronisierung wird anhalten, weil Beförderung ausgelöst wurde" -#: replication/logical/slotsync.c:1317 +#: replication/logical/slotsync.c:1273 +#, c-format +msgid "replication slot synchronization will stop because promotion is triggered" +msgstr "Replikations-Slot-Synchronisierung wird anhalten, weil Beförderung ausgelöst wurde" + +#: replication/logical/slotsync.c:1393 +#, c-format +msgid "replication slot synchronization worker will not start because promotion was triggered" +msgstr "Arbeitsprozess für Replikations-Slot-Synchronisierung wird nicht starten, weil Beförderung ausgelöst wurde" + +#: replication/logical/slotsync.c:1405 +#, c-format +msgid "replication slot synchronization will not start because promotion was triggered" +msgstr "Replikations-Slot-Synchronisierung wird nicht starten, weil Beförderung ausgelöst wurde" + +#: replication/logical/slotsync.c:1414 #, c-format msgid "cannot synchronize replication slots concurrently" msgstr "Replikations-Slots können nicht nebenläufig synchronisiert werden" -#: replication/logical/slotsync.c:1425 +#: replication/logical/slotsync.c:1526 #, c-format msgid "slot sync worker started" msgstr "Slot-Sync-Arbeitsprozess gestartet" -#: replication/logical/slotsync.c:1487 replication/slotfuncs.c:928 +#: replication/logical/slotsync.c:1588 replication/slotfuncs.c:928 #, c-format msgid "synchronization worker \"%s\" could not connect to the primary server: %s" msgstr "Synchronisierungs-Arbeitsprozess »%s« konnte nicht mit dem Primärserver verbinden: %s" @@ -22817,44 +22832,44 @@ msgstr "%s darf nicht in einer Subtransaktion aufgerufen werden" msgid "terminating walsender process after promotion" msgstr "WAL-Sender-Prozess wird nach Beförderung abgebrochen" -#: replication/walsender.c:2010 +#: replication/walsender.c:2016 #, c-format msgid "cannot execute new commands while WAL sender is in stopping mode" msgstr "während der WAL-Sender im Stoppmodus ist können keine neuen Befehle ausgeführt werden" -#: replication/walsender.c:2064 +#: replication/walsender.c:2070 #, c-format msgid "cannot execute SQL commands in WAL sender for physical replication" msgstr "im WAL-Sender für physische Replikation können keine SQL-Befehle ausgeführt werden" -#: replication/walsender.c:2095 +#: replication/walsender.c:2101 #, c-format msgid "received replication command: %s" msgstr "Replikationsbefehl empfangen: %s" -#: replication/walsender.c:2103 tcop/fastpath.c:208 tcop/postgres.c:1137 -#: tcop/postgres.c:1494 tcop/postgres.c:1746 tcop/postgres.c:2251 -#: tcop/postgres.c:2688 tcop/postgres.c:2765 +#: replication/walsender.c:2109 tcop/fastpath.c:208 tcop/postgres.c:1138 +#: tcop/postgres.c:1495 tcop/postgres.c:1747 tcop/postgres.c:2252 +#: tcop/postgres.c:2689 tcop/postgres.c:2766 #, c-format msgid "current transaction is aborted, commands ignored until end of transaction block" msgstr "aktuelle Transaktion wurde abgebrochen, Befehle werden bis zum Ende der Transaktion ignoriert" -#: replication/walsender.c:2263 replication/walsender.c:2298 +#: replication/walsender.c:2269 replication/walsender.c:2304 #, c-format msgid "unexpected EOF on standby connection" msgstr "unerwartetes EOF auf Standby-Verbindung" -#: replication/walsender.c:2286 +#: replication/walsender.c:2292 #, c-format msgid "invalid standby message type \"%c\"" msgstr "ungültiger Standby-Message-Typ »%c«" -#: replication/walsender.c:2375 +#: replication/walsender.c:2381 #, c-format msgid "unexpected message type \"%c\"" msgstr "unerwarteter Message-Typ »%c«" -#: replication/walsender.c:2789 +#: replication/walsender.c:2798 #, c-format msgid "terminating walsender process due to replication timeout" msgstr "WAL-Sender-Prozess wird abgebrochen wegen Zeitüberschreitung bei der Replikation" @@ -23035,286 +23050,281 @@ msgstr "Regel »%s« für Relation »%s« existiert nicht" msgid "renaming an ON SELECT rule is not allowed" msgstr "Umbenennen einer ON-SELECT-Regel ist nicht erlaubt" -#: rewrite/rewriteHandler.c:590 +#: rewrite/rewriteHandler.c:589 #, c-format msgid "WITH query name \"%s\" appears in both a rule action and the query being rewritten" msgstr "WITH-Anfragename »%s« erscheint sowohl in der Regelaktion als auch in der umzuschreibenden Anfrage" -#: rewrite/rewriteHandler.c:620 +#: rewrite/rewriteHandler.c:619 #, c-format msgid "INSERT ... SELECT rule actions are not supported for queries having data-modifying statements in WITH" msgstr "INSERT ... SELECT-Regelaktionen werden für Anfrangen mit datenmodifizierenden Anweisungen in WITH nicht unterstützt" -#: rewrite/rewriteHandler.c:674 +#: rewrite/rewriteHandler.c:707 #, c-format msgid "cannot have RETURNING lists in multiple rules" msgstr "RETURNING-Listen können nicht in mehreren Regeln auftreten" -#: rewrite/rewriteHandler.c:911 rewrite/rewriteHandler.c:950 +#: rewrite/rewriteHandler.c:944 rewrite/rewriteHandler.c:983 #, c-format msgid "cannot insert a non-DEFAULT value into column \"%s\"" msgstr "kann keinen Wert außer DEFAULT in Spalte »%s« einfügen" -#: rewrite/rewriteHandler.c:913 rewrite/rewriteHandler.c:979 +#: rewrite/rewriteHandler.c:946 rewrite/rewriteHandler.c:1012 #, c-format msgid "Column \"%s\" is an identity column defined as GENERATED ALWAYS." msgstr "Spalte »%s« ist eine Identitätsspalte, die als GENERATED ALWAYS definiert ist." -#: rewrite/rewriteHandler.c:915 +#: rewrite/rewriteHandler.c:948 #, c-format msgid "Use OVERRIDING SYSTEM VALUE to override." msgstr "Verwenden Sie OVERRIDING SYSTEM VALUE, um diese Einschränkung außer Kraft zu setzen." -#: rewrite/rewriteHandler.c:977 rewrite/rewriteHandler.c:985 +#: rewrite/rewriteHandler.c:1010 rewrite/rewriteHandler.c:1018 #, c-format msgid "column \"%s\" can only be updated to DEFAULT" msgstr "Spalte »%s« kann nur auf DEFAULT aktualisiert werden" -#: rewrite/rewriteHandler.c:1121 rewrite/rewriteHandler.c:1139 +#: rewrite/rewriteHandler.c:1154 rewrite/rewriteHandler.c:1172 #, c-format msgid "multiple assignments to same column \"%s\"" msgstr "mehrere Zuweisungen zur selben Spalte »%s«" -#: rewrite/rewriteHandler.c:1694 +#: rewrite/rewriteHandler.c:1727 #, c-format msgid "MERGE is not supported for relations with rules." msgstr "MERGE wird für Relationen mit Regeln nicht unterstützt." -#: rewrite/rewriteHandler.c:1734 rewrite/rewriteHandler.c:3274 +#: rewrite/rewriteHandler.c:1767 rewrite/rewriteHandler.c:3339 #, c-format msgid "access to non-system view \"%s\" is restricted" msgstr "Zugriff auf Nicht-System-Sicht »%s« ist beschränkt" -#: rewrite/rewriteHandler.c:2133 rewrite/rewriteHandler.c:4285 +#: rewrite/rewriteHandler.c:2166 rewrite/rewriteHandler.c:4350 #, c-format msgid "infinite recursion detected in rules for relation \"%s\"" msgstr "unendliche Rekursion entdeckt in Regeln für Relation »%s«" -#: rewrite/rewriteHandler.c:2238 +#: rewrite/rewriteHandler.c:2271 #, c-format msgid "infinite recursion detected in policy for relation \"%s\"" msgstr "unendliche Rekursion entdeckt in Policys für Relation »%s«" -#: rewrite/rewriteHandler.c:2601 +#: rewrite/rewriteHandler.c:2666 msgid "Junk view columns are not updatable." msgstr "Junk-Sichtspalten sind nicht aktualisierbar." -#: rewrite/rewriteHandler.c:2606 +#: rewrite/rewriteHandler.c:2671 msgid "View columns that are not columns of their base relation are not updatable." msgstr "Sichtspalten, die nicht Spalten ihrer Basisrelation sind, sind nicht aktualisierbar." -#: rewrite/rewriteHandler.c:2609 +#: rewrite/rewriteHandler.c:2674 msgid "View columns that refer to system columns are not updatable." msgstr "Sichtspalten, die auf Systemspalten verweisen, sind nicht aktualisierbar." -#: rewrite/rewriteHandler.c:2612 +#: rewrite/rewriteHandler.c:2677 msgid "View columns that return whole-row references are not updatable." msgstr "Sichtspalten, die Verweise auf ganze Zeilen zurückgeben, sind nicht aktualisierbar." -#: rewrite/rewriteHandler.c:2673 +#: rewrite/rewriteHandler.c:2738 msgid "Views containing DISTINCT are not automatically updatable." msgstr "Sichten, die DISTINCT enthalten, sind nicht automatisch aktualisierbar." -#: rewrite/rewriteHandler.c:2676 +#: rewrite/rewriteHandler.c:2741 msgid "Views containing GROUP BY are not automatically updatable." msgstr "Sichten, die GROUP BY enthalten, sind nicht automatisch aktualisierbar." -#: rewrite/rewriteHandler.c:2679 +#: rewrite/rewriteHandler.c:2744 msgid "Views containing HAVING are not automatically updatable." msgstr "Sichten, die HAVING enthalten, sind nicht automatisch aktualisierbar." -#: rewrite/rewriteHandler.c:2682 +#: rewrite/rewriteHandler.c:2747 msgid "Views containing UNION, INTERSECT, or EXCEPT are not automatically updatable." msgstr "Sichten, die UNION, INTERSECT oder EXCEPT enthalten, sind nicht automatisch aktualisierbar." -#: rewrite/rewriteHandler.c:2685 +#: rewrite/rewriteHandler.c:2750 msgid "Views containing WITH are not automatically updatable." msgstr "Sichten, die WITH enthalten, sind nicht automatisch aktualisierbar." -#: rewrite/rewriteHandler.c:2688 +#: rewrite/rewriteHandler.c:2753 msgid "Views containing LIMIT or OFFSET are not automatically updatable." msgstr "Sichten, die LIMIT oder OFFSET enthalten, sind nicht automatisch aktualisierbar." -#: rewrite/rewriteHandler.c:2700 +#: rewrite/rewriteHandler.c:2765 msgid "Views that return aggregate functions are not automatically updatable." msgstr "Sichten, die Aggregatfunktionen zurückgeben, sind nicht automatisch aktualisierbar." -#: rewrite/rewriteHandler.c:2703 +#: rewrite/rewriteHandler.c:2768 msgid "Views that return window functions are not automatically updatable." msgstr "Sichten, die Fensterfunktionen zurückgeben, sind nicht automatisch aktualisierbar." -#: rewrite/rewriteHandler.c:2706 +#: rewrite/rewriteHandler.c:2771 msgid "Views that return set-returning functions are not automatically updatable." msgstr "Sichten, die Funktionen mit Ergebnismenge zurückgeben, sind nicht automatisch aktualisierbar." -#: rewrite/rewriteHandler.c:2713 rewrite/rewriteHandler.c:2717 -#: rewrite/rewriteHandler.c:2725 +#: rewrite/rewriteHandler.c:2778 rewrite/rewriteHandler.c:2782 +#: rewrite/rewriteHandler.c:2790 msgid "Views that do not select from a single table or view are not automatically updatable." msgstr "Sichten, die nicht aus einer einzigen Tabelle oder Sicht lesen, sind nicht automatisch aktualisierbar." -#: rewrite/rewriteHandler.c:2728 +#: rewrite/rewriteHandler.c:2793 msgid "Views containing TABLESAMPLE are not automatically updatable." msgstr "Sichten, die TABLESAMPLE enthalten, sind nicht automatisch aktualisierbar." -#: rewrite/rewriteHandler.c:2752 +#: rewrite/rewriteHandler.c:2817 msgid "Views that have no updatable columns are not automatically updatable." msgstr "Sichten, die keine aktualisierbaren Spalten haben, sind nicht automatisch aktualisierbar." -#: rewrite/rewriteHandler.c:3133 rewrite/rewriteHandler.c:3168 +#: rewrite/rewriteHandler.c:3198 rewrite/rewriteHandler.c:3233 #, c-format msgid "cannot insert into view \"%s\"" msgstr "kann nicht in Sicht »%s« einfügen" -#: rewrite/rewriteHandler.c:3136 +#: rewrite/rewriteHandler.c:3201 #, c-format msgid "To enable inserting into the view, provide an INSTEAD OF INSERT trigger or an unconditional ON INSERT DO INSTEAD rule." msgstr "Um Einfügen in die Sicht zu ermöglichen, richten Sie einen INSTEAD OF INSERT Trigger oder eine ON INSERT DO INSTEAD Regel ohne Bedingung ein." -#: rewrite/rewriteHandler.c:3141 rewrite/rewriteHandler.c:3177 +#: rewrite/rewriteHandler.c:3206 rewrite/rewriteHandler.c:3242 #, c-format msgid "cannot update view \"%s\"" msgstr "kann Sicht »%s« nicht aktualisieren" -#: rewrite/rewriteHandler.c:3144 +#: rewrite/rewriteHandler.c:3209 #, c-format msgid "To enable updating the view, provide an INSTEAD OF UPDATE trigger or an unconditional ON UPDATE DO INSTEAD rule." msgstr "Um Aktualisieren der Sicht zu ermöglichen, richten Sie einen INSTEAD OF UPDATE Trigger oder eine ON UPDATE DO INSTEAD Regel ohne Bedingung ein." -#: rewrite/rewriteHandler.c:3149 rewrite/rewriteHandler.c:3186 +#: rewrite/rewriteHandler.c:3214 rewrite/rewriteHandler.c:3251 #, c-format msgid "cannot delete from view \"%s\"" msgstr "kann nicht aus Sicht »%s« löschen" -#: rewrite/rewriteHandler.c:3152 +#: rewrite/rewriteHandler.c:3217 #, c-format msgid "To enable deleting from the view, provide an INSTEAD OF DELETE trigger or an unconditional ON DELETE DO INSTEAD rule." msgstr "Um Löschen aus der Sicht zu ermöglichen, richten Sie einen INSTEAD OF DELETE Trigger oder eine ON DELETE DO INSTEAD Regel ohne Bedingung ein." -#: rewrite/rewriteHandler.c:3171 +#: rewrite/rewriteHandler.c:3236 #, c-format msgid "To enable inserting into the view using MERGE, provide an INSTEAD OF INSERT trigger." msgstr "Um Einfügen in die Sicht mit MERGE zu ermöglichen, richten Sie einen INSTEAD OF INSERT Trigger ein." -#: rewrite/rewriteHandler.c:3180 +#: rewrite/rewriteHandler.c:3245 #, c-format msgid "To enable updating the view using MERGE, provide an INSTEAD OF UPDATE trigger." msgstr "Um Aktualisieren der Sicht mit MERGE zu ermöglichen, richten Sie einen INSTEAD OF UPDATE Trigger ein." -#: rewrite/rewriteHandler.c:3189 +#: rewrite/rewriteHandler.c:3254 #, c-format msgid "To enable deleting from the view using MERGE, provide an INSTEAD OF DELETE trigger." msgstr "Um Löschen aus der Sicht zu ermöglichen, richten Sie einen INSTEAD OF DELETE Trigger ein." -#: rewrite/rewriteHandler.c:3364 +#: rewrite/rewriteHandler.c:3429 #, c-format msgid "cannot insert into column \"%s\" of view \"%s\"" msgstr "kann nicht in Spalte »%s« von Sicht »%s« einfügen" -#: rewrite/rewriteHandler.c:3372 +#: rewrite/rewriteHandler.c:3437 #, c-format msgid "cannot update column \"%s\" of view \"%s\"" msgstr "kann Spalte »%s« von Sicht »%s« nicht aktualisieren" -#: rewrite/rewriteHandler.c:3380 +#: rewrite/rewriteHandler.c:3445 #, c-format msgid "cannot merge into column \"%s\" of view \"%s\"" msgstr "kann nicht in Spalte »%s« von Sicht »%s« mergen" -#: rewrite/rewriteHandler.c:3408 +#: rewrite/rewriteHandler.c:3473 #, c-format msgid "cannot merge into view \"%s\"" msgstr "kann nicht in Sicht »%s« mergen" -#: rewrite/rewriteHandler.c:3410 +#: rewrite/rewriteHandler.c:3475 #, c-format msgid "MERGE is not supported for views with INSTEAD OF triggers for some actions but not all." msgstr "MERGE wird nicht unterstützt für Sichten mit INSTEAD-OF-Trigger für einige Aktionen aber nicht für alle." -#: rewrite/rewriteHandler.c:3411 +#: rewrite/rewriteHandler.c:3476 #, c-format msgid "To enable merging into the view, either provide a full set of INSTEAD OF triggers or drop the existing INSTEAD OF triggers." msgstr "Um Mergen in die Sicht zu ermöglichen, richten Sie entweder einen vollen Satz an INSTEAD-OF-Triggern ein oder löschen Sie die bestehenden INSTEAD-OF-Trigger." -#: rewrite/rewriteHandler.c:3942 +#: rewrite/rewriteHandler.c:4007 #, c-format msgid "DO INSTEAD NOTIFY rules are not supported for data-modifying statements in WITH" msgstr "DO-INSTEAD-NOTIFY-Regeln werden für datenmodifizierende Anweisungen in WITH nicht unterstützt" -#: rewrite/rewriteHandler.c:3953 +#: rewrite/rewriteHandler.c:4018 #, c-format msgid "DO INSTEAD NOTHING rules are not supported for data-modifying statements in WITH" msgstr "DO-INSTEAD-NOTHING-Regeln werden für datenmodifizierende Anweisungen in WITH nicht unterstützt" -#: rewrite/rewriteHandler.c:3967 +#: rewrite/rewriteHandler.c:4032 #, c-format msgid "conditional DO INSTEAD rules are not supported for data-modifying statements in WITH" msgstr "DO-INSTEAD-Regeln mit Bedingung werden für datenmodifizierende Anweisungen in WITH nicht unterstützt" -#: rewrite/rewriteHandler.c:3971 +#: rewrite/rewriteHandler.c:4036 #, c-format msgid "DO ALSO rules are not supported for data-modifying statements in WITH" msgstr "DO-ALSO-Regeln werden für datenmodifizierende Anweisungen in WITH nicht unterstützt" -#: rewrite/rewriteHandler.c:3976 +#: rewrite/rewriteHandler.c:4041 #, c-format msgid "multi-statement DO INSTEAD rules are not supported for data-modifying statements in WITH" msgstr "DO-INSTEAD-Regeln mit mehreren Anweisungen werden für datenmodifizierende Anweisungen in WITH nicht unterstützt" -#: rewrite/rewriteHandler.c:4237 +#: rewrite/rewriteHandler.c:4302 msgid "Views with conditional DO INSTEAD rules are not automatically updatable." msgstr "Sichten mit DO-INSTEAD-Regeln mit Bedingung sind nicht automatisch aktualisierbar." -#: rewrite/rewriteHandler.c:4335 +#: rewrite/rewriteHandler.c:4400 #, c-format msgid "cannot perform INSERT RETURNING on relation \"%s\"" msgstr "INSERT RETURNING kann in Relation »%s« nicht ausgeführt werden" -#: rewrite/rewriteHandler.c:4337 +#: rewrite/rewriteHandler.c:4402 #, c-format msgid "You need an unconditional ON INSERT DO INSTEAD rule with a RETURNING clause." msgstr "Sie benötigen eine ON INSERT DO INSTEAD Regel ohne Bedingung, mit RETURNING-Klausel." -#: rewrite/rewriteHandler.c:4342 +#: rewrite/rewriteHandler.c:4407 #, c-format msgid "cannot perform UPDATE RETURNING on relation \"%s\"" msgstr "UPDATE RETURNING kann in Relation »%s« nicht ausgeführt werden" -#: rewrite/rewriteHandler.c:4344 +#: rewrite/rewriteHandler.c:4409 #, c-format msgid "You need an unconditional ON UPDATE DO INSTEAD rule with a RETURNING clause." msgstr "Sie benötigen eine ON UPDATE DO INSTEAD Regel ohne Bedingung, mit RETURNING-Klausel." -#: rewrite/rewriteHandler.c:4349 +#: rewrite/rewriteHandler.c:4414 #, c-format msgid "cannot perform DELETE RETURNING on relation \"%s\"" msgstr "DELETE RETURNING kann in Relation »%s« nicht ausgeführt werden" -#: rewrite/rewriteHandler.c:4351 +#: rewrite/rewriteHandler.c:4416 #, c-format msgid "You need an unconditional ON DELETE DO INSTEAD rule with a RETURNING clause." msgstr "Sie benötigen eine ON DELETE DO INSTEAD Regel ohne Bedingung, mit RETURNING-Klausel." -#: rewrite/rewriteHandler.c:4369 +#: rewrite/rewriteHandler.c:4434 #, c-format msgid "INSERT with ON CONFLICT clause cannot be used with table that has INSERT or UPDATE rules" msgstr "INSERT mit ON-CONFLICT-Klausel kann nicht mit Tabelle verwendet werden, die INSERT- oder UPDATE-Regeln hat" -#: rewrite/rewriteHandler.c:4426 +#: rewrite/rewriteHandler.c:4491 #, c-format msgid "WITH cannot be used in a query that is rewritten by rules into multiple queries" msgstr "WITH kann nicht in einer Anfrage verwendet werden, die durch Regeln in mehrere Anfragen umgeschrieben wird" -#: rewrite/rewriteManip.c:1175 +#: rewrite/rewriteManip.c:1186 #, c-format msgid "conditional utility statements are not implemented" msgstr "Utility-Anweisungen mit Bedingung sind nicht implementiert" -#: rewrite/rewriteManip.c:1520 -#, c-format -msgid "WHERE CURRENT OF on a view is not implemented" -msgstr "WHERE CURRENT OF mit einer Sicht ist nicht implementiert" - -#: rewrite/rewriteManip.c:1923 +#: rewrite/rewriteManip.c:1915 #, c-format msgid "NEW variables in ON UPDATE rules cannot reference columns that are part of a multiple assignment in the subject UPDATE command" msgstr "NEW-Variablen in ON UPDATE-Regeln können nicht auf Spalten verweisen, die Teil einer Mehrfachzuweisung in dem UPDATE-Befehl sind" @@ -24065,22 +24075,22 @@ msgstr "Nur Rollen mit dem %s-Attribut können Prozesse von Rollen mit dem %s-At msgid "Only roles with privileges of the role whose process is being terminated or with privileges of the \"%s\" role may terminate this process." msgstr "Nur Rollen mit den Privilegien der Rolle deren Prozess beendet werden soll oder den Privilegien der Rolle »%s« können diesen Prozess beenden." -#: storage/ipc/procsignal.c:451 +#: storage/ipc/procsignal.c:452 #, c-format msgid "still waiting for backend with PID %d to accept ProcSignalBarrier" msgstr "warte immer noch darauf, dass Backend mit PID %d ProcSignalBarrier annimmt" -#: storage/ipc/procsignal.c:733 +#: storage/ipc/procsignal.c:737 #, c-format msgid "invalid cancel request with PID 0" msgstr "ungültige Stornierungsanfrage mit PID 0" -#: storage/ipc/procsignal.c:788 +#: storage/ipc/procsignal.c:792 #, c-format msgid "wrong key in cancel request for process %d" msgstr "falscher Schlüssel in Stornierungsanfrage für Prozess %d" -#: storage/ipc/procsignal.c:797 +#: storage/ipc/procsignal.c:801 #, c-format msgid "PID %d in cancel request did not match any process" msgstr "PID %d in Stornierungsanfrage stimmte mit keinem Prozess überein" @@ -24199,12 +24209,12 @@ msgstr "Wiederherstellung wartet immer noch nach %ld,%03d ms: %s" msgid "recovery finished waiting after %ld.%03d ms: %s" msgstr "Warten der Wiederherstellung beendet nach %ld,%03d ms: %s" -#: storage/ipc/standby.c:921 tcop/postgres.c:3223 +#: storage/ipc/standby.c:921 tcop/postgres.c:3224 #, c-format msgid "canceling statement due to conflict with recovery" msgstr "storniere Anfrage wegen Konflikt mit der Wiederherstellung" -#: storage/ipc/standby.c:922 tcop/postgres.c:2573 +#: storage/ipc/standby.c:922 tcop/postgres.c:2574 #, c-format msgid "User transaction caused buffer deadlock with recovery." msgstr "Benutzertransaktion hat Verklemmung (Deadlock) mit Wiederherstellung verursacht." @@ -24785,8 +24795,8 @@ msgstr "Funktion »%s« kann nicht via Fastpath-Interface aufgerufen werden" msgid "fastpath function call: \"%s\" (OID %u)" msgstr "Fastpath-Funktionsaufruf: »%s« (OID %u)" -#: tcop/fastpath.c:312 tcop/postgres.c:1363 tcop/postgres.c:1599 -#: tcop/postgres.c:2077 tcop/postgres.c:2349 +#: tcop/fastpath.c:312 tcop/postgres.c:1364 tcop/postgres.c:1600 +#: tcop/postgres.c:2078 tcop/postgres.c:2350 #, c-format msgid "duration: %s ms" msgstr "Dauer: %s ms" @@ -24816,315 +24826,315 @@ msgstr "ungültige Argumentgröße %d in Funktionsaufruf-Message" msgid "incorrect binary data format in function argument %d" msgstr "falsches Binärdatenformat in Funktionsargument %d" -#: tcop/postgres.c:455 tcop/postgres.c:5018 +#: tcop/postgres.c:456 tcop/postgres.c:5022 #, c-format msgid "invalid frontend message type %d" msgstr "ungültiger Frontend-Message-Typ %d" -#: tcop/postgres.c:1070 +#: tcop/postgres.c:1071 #, c-format msgid "statement: %s" msgstr "Anweisung: %s" -#: tcop/postgres.c:1368 +#: tcop/postgres.c:1369 #, c-format msgid "duration: %s ms statement: %s" msgstr "Dauer: %s ms Anweisung: %s" -#: tcop/postgres.c:1474 +#: tcop/postgres.c:1475 #, c-format msgid "cannot insert multiple commands into a prepared statement" msgstr "kann nicht mehrere Befehle in vorbereitete Anweisung einfügen" -#: tcop/postgres.c:1604 +#: tcop/postgres.c:1605 #, c-format msgid "duration: %s ms parse %s: %s" msgstr "Dauer: %s ms Parsen %s: %s" -#: tcop/postgres.c:1671 tcop/postgres.c:2669 +#: tcop/postgres.c:1672 tcop/postgres.c:2670 #, c-format msgid "unnamed prepared statement does not exist" msgstr "unbenannte vorbereitete Anweisung existiert nicht" -#: tcop/postgres.c:1723 +#: tcop/postgres.c:1724 #, c-format msgid "bind message has %d parameter formats but %d parameters" msgstr "Binden-Nachricht hat %d Parameterformate aber %d Parameter" -#: tcop/postgres.c:1729 +#: tcop/postgres.c:1730 #, c-format msgid "bind message supplies %d parameters, but prepared statement \"%s\" requires %d" msgstr "Binden-Nachricht enthält %d Parameter, aber vorbereitete Anweisung »%s« erfordert %d" -#: tcop/postgres.c:1943 +#: tcop/postgres.c:1944 #, c-format msgid "incorrect binary data format in bind parameter %d" msgstr "falsches Binärdatenformat in Binden-Parameter %d" -#: tcop/postgres.c:2082 +#: tcop/postgres.c:2083 #, c-format msgid "duration: %s ms bind %s%s%s: %s" msgstr "Dauer: %s ms Binden %s%s%s: %s" -#: tcop/postgres.c:2137 tcop/postgres.c:2751 +#: tcop/postgres.c:2138 tcop/postgres.c:2752 #, c-format msgid "portal \"%s\" does not exist" msgstr "Portal »%s« existiert nicht" -#: tcop/postgres.c:2230 +#: tcop/postgres.c:2231 #, c-format msgid "%s %s%s%s: %s" msgstr "%s %s%s%s: %s" -#: tcop/postgres.c:2232 tcop/postgres.c:2357 +#: tcop/postgres.c:2233 tcop/postgres.c:2358 msgid "execute fetch from" msgstr "Ausführen Fetch von" -#: tcop/postgres.c:2233 tcop/postgres.c:2358 +#: tcop/postgres.c:2234 tcop/postgres.c:2359 msgid "execute" msgstr "Ausführen" -#: tcop/postgres.c:2354 +#: tcop/postgres.c:2355 #, c-format msgid "duration: %s ms %s %s%s%s: %s" msgstr "Dauer: %s ms %s %s%s%s: %s" -#: tcop/postgres.c:2502 +#: tcop/postgres.c:2503 #, c-format msgid "prepare: %s" msgstr "Vorbereiten: %s" -#: tcop/postgres.c:2527 +#: tcop/postgres.c:2528 #, c-format msgid "Parameters: %s" msgstr "Parameter: %s" -#: tcop/postgres.c:2542 +#: tcop/postgres.c:2543 #, c-format msgid "Abort reason: recovery conflict" msgstr "Abbruchgrund: Konflikt bei Wiederherstellung" -#: tcop/postgres.c:2558 +#: tcop/postgres.c:2559 #, c-format msgid "User was holding shared buffer pin for too long." msgstr "Benutzer hat Shared-Buffer-Pin zu lange gehalten." -#: tcop/postgres.c:2561 +#: tcop/postgres.c:2562 #, c-format msgid "User was holding a relation lock for too long." msgstr "Benutzer hat Relationssperre zu lange gehalten." -#: tcop/postgres.c:2564 +#: tcop/postgres.c:2565 #, c-format msgid "User was or might have been using tablespace that must be dropped." msgstr "Benutzer hat (möglicherweise) einen Tablespace verwendet, der gelöscht werden muss." -#: tcop/postgres.c:2567 +#: tcop/postgres.c:2568 #, c-format msgid "User query might have needed to see row versions that must be removed." msgstr "Benutzeranfrage hat möglicherweise Zeilenversionen sehen müssen, die entfernt werden müssen." -#: tcop/postgres.c:2570 +#: tcop/postgres.c:2571 #, c-format msgid "User was using a logical replication slot that must be invalidated." msgstr "Benutzer verwendete einen logischen Replikations-Slot, der ungültig gemacht werden muss." -#: tcop/postgres.c:2576 +#: tcop/postgres.c:2577 #, c-format msgid "User was connected to a database that must be dropped." msgstr "Benutzer war mit einer Datenbank verbunden, die gelöscht werden muss." -#: tcop/postgres.c:2615 +#: tcop/postgres.c:2616 #, c-format msgid "portal \"%s\" parameter $%d = %s" msgstr "Portal »%s« Parameter $%d = %s" -#: tcop/postgres.c:2618 +#: tcop/postgres.c:2619 #, c-format msgid "portal \"%s\" parameter $%d" msgstr "Portal »%s« Parameter $%d" -#: tcop/postgres.c:2624 +#: tcop/postgres.c:2625 #, c-format msgid "unnamed portal parameter $%d = %s" msgstr "unbenanntes Portal Parameter $%d = %s" -#: tcop/postgres.c:2627 +#: tcop/postgres.c:2628 #, c-format msgid "unnamed portal parameter $%d" msgstr "unbenanntes Portal Parameter $%d" -#: tcop/postgres.c:2982 +#: tcop/postgres.c:2983 #, c-format msgid "terminating connection because of unexpected SIGQUIT signal" msgstr "Verbindung wird abgebrochen wegen unerwartetem SIGQUIT-Signal" -#: tcop/postgres.c:2988 +#: tcop/postgres.c:2989 #, c-format msgid "terminating connection because of crash of another server process" msgstr "Verbindung wird abgebrochen wegen Absturz eines anderen Serverprozesses" -#: tcop/postgres.c:2989 +#: tcop/postgres.c:2990 #, c-format msgid "The postmaster has commanded this server process to roll back the current transaction and exit, because another server process exited abnormally and possibly corrupted shared memory." msgstr "Der Postmaster hat diesen Serverprozess angewiesen, die aktuelle Transaktion zurückzurollen und die Sitzung zu beenden, weil ein anderer Serverprozess abnormal beendet wurde und möglicherweise das Shared Memory verfälscht hat." -#: tcop/postgres.c:2993 tcop/postgres.c:3246 +#: tcop/postgres.c:2994 tcop/postgres.c:3247 #, c-format msgid "In a moment you should be able to reconnect to the database and repeat your command." msgstr "In einem Moment sollten Sie wieder mit der Datenbank verbinden und Ihren Befehl wiederholen können." -#: tcop/postgres.c:3000 +#: tcop/postgres.c:3001 #, c-format msgid "terminating connection due to immediate shutdown command" msgstr "Verbindung wird abgebrochen aufgrund von Befehl für sofortiges Herunterfahren" -#: tcop/postgres.c:3078 +#: tcop/postgres.c:3079 #, c-format msgid "floating-point exception" msgstr "Fließkommafehler" -#: tcop/postgres.c:3079 +#: tcop/postgres.c:3080 #, c-format msgid "An invalid floating-point operation was signaled. This probably means an out-of-range result or an invalid operation, such as division by zero." msgstr "Eine ungültige Fließkommaoperation wurde signalisiert. Das bedeutet wahrscheinlich ein Ergebnis außerhalb des gültigen Bereichs oder eine ungültige Operation, zum Beispiel Division durch null." -#: tcop/postgres.c:3244 +#: tcop/postgres.c:3245 #, c-format msgid "terminating connection due to conflict with recovery" msgstr "Verbindung wird abgebrochen wegen Konflikt mit der Wiederherstellung" -#: tcop/postgres.c:3316 +#: tcop/postgres.c:3317 #, c-format msgid "canceling authentication due to timeout" msgstr "storniere Authentifizierung wegen Zeitüberschreitung" -#: tcop/postgres.c:3320 +#: tcop/postgres.c:3321 #, c-format msgid "terminating autovacuum process due to administrator command" msgstr "Autovacuum-Prozess wird abgebrochen aufgrund von Anweisung des Administrators" -#: tcop/postgres.c:3324 +#: tcop/postgres.c:3325 #, c-format msgid "terminating logical replication worker due to administrator command" msgstr "Arbeitsprozess für logische Replikation wird abgebrochen aufgrund von Anweisung des Administrators" -#: tcop/postgres.c:3339 +#: tcop/postgres.c:3340 #, c-format msgid "terminating walreceiver process due to administrator command" msgstr "WAL-Receiver-Prozess wird abgebrochen aufgrund von Anweisung des Administrators" -#: tcop/postgres.c:3355 +#: tcop/postgres.c:3356 #, c-format msgid "terminating connection due to administrator command" msgstr "Verbindung wird abgebrochen aufgrund von Anweisung des Administrators" -#: tcop/postgres.c:3386 +#: tcop/postgres.c:3387 #, c-format msgid "connection to client lost" msgstr "Verbindung zum Client wurde verloren" -#: tcop/postgres.c:3438 +#: tcop/postgres.c:3439 #, c-format msgid "canceling statement due to lock timeout" msgstr "storniere Anfrage wegen Zeitüberschreitung einer Sperre" -#: tcop/postgres.c:3445 +#: tcop/postgres.c:3446 #, c-format msgid "canceling statement due to statement timeout" msgstr "storniere Anfrage wegen Zeitüberschreitung der Anfrage" -#: tcop/postgres.c:3452 +#: tcop/postgres.c:3453 #, c-format msgid "canceling autovacuum task" msgstr "storniere Autovacuum-Aufgabe" -#: tcop/postgres.c:3465 +#: tcop/postgres.c:3466 #, c-format msgid "canceling statement due to user request" msgstr "storniere Anfrage wegen Benutzeraufforderung" -#: tcop/postgres.c:3486 +#: tcop/postgres.c:3487 #, c-format msgid "terminating connection due to idle-in-transaction timeout" msgstr "Verbindung wird abgebrochen wegen Zeitüberschreitung in inaktiver Transaktion" -#: tcop/postgres.c:3499 +#: tcop/postgres.c:3500 #, c-format msgid "terminating connection due to transaction timeout" msgstr "Verbindung wird abgebrochen wegen Zeitüberschreitung in Transaktion" -#: tcop/postgres.c:3512 +#: tcop/postgres.c:3513 #, c-format msgid "terminating connection due to idle-session timeout" msgstr "Verbindung wird abgebrochen wegen Zeitüberschreitung in inaktiver Sitzung" -#: tcop/postgres.c:3548 +#: tcop/postgres.c:3552 #, c-format msgid "\"client_connection_check_interval\" must be set to 0 on this platform." msgstr "»client_connection_check_interval« muss auf dieser Plattform auf 0 gesetzt sein." -#: tcop/postgres.c:3569 +#: tcop/postgres.c:3573 #, c-format msgid "Cannot enable parameter when \"log_statement_stats\" is true." msgstr "Kann Parameter nicht einschalten, wenn »log_statement_stats« an ist." -#: tcop/postgres.c:3584 +#: tcop/postgres.c:3588 #, c-format msgid "Cannot enable \"log_statement_stats\" when \"log_parser_stats\", \"log_planner_stats\", or \"log_executor_stats\" is true." msgstr "Kann »log_statement_stats« nicht einschalten, wenn »log_parser_stats«, »log_planner_stats« oder »log_executor_stats« an ist." -#: tcop/postgres.c:4024 +#: tcop/postgres.c:4028 #, c-format msgid "invalid command-line argument for server process: %s" msgstr "ungültiges Kommandozeilenargument für Serverprozess: %s" -#: tcop/postgres.c:4025 tcop/postgres.c:4031 +#: tcop/postgres.c:4029 tcop/postgres.c:4035 #, c-format msgid "Try \"%s --help\" for more information." msgstr "Versuchen Sie »%s --help« für weitere Informationen." -#: tcop/postgres.c:4029 +#: tcop/postgres.c:4033 #, c-format msgid "%s: invalid command-line argument: %s" msgstr "%s: ungültiges Kommandozeilenargument: %s" -#: tcop/postgres.c:4082 +#: tcop/postgres.c:4086 #, c-format msgid "%s: no database nor user name specified" msgstr "%s: weder Datenbankname noch Benutzername angegeben" -#: tcop/postgres.c:4275 +#: tcop/postgres.c:4279 #, c-format msgid "could not generate random cancel key" msgstr "konnte zufälligen Stornierungsschlüssel nicht erzeugen" -#: tcop/postgres.c:4677 +#: tcop/postgres.c:4681 #, c-format msgid "connection ready: setup total=%.3f ms, fork=%.3f ms, authentication=%.3f ms" msgstr "Verbindung bereit: Setup gesamt=%.3f ms, Fork=%.3f ms, Authentifizierung=%.3f ms" -#: tcop/postgres.c:4908 +#: tcop/postgres.c:4912 #, c-format msgid "invalid CLOSE message subtype %d" msgstr "ungültiger Subtyp %d von CLOSE-Message" -#: tcop/postgres.c:4945 +#: tcop/postgres.c:4949 #, c-format msgid "invalid DESCRIBE message subtype %d" msgstr "ungültiger Subtyp %d von DESCRIBE-Message" -#: tcop/postgres.c:5039 +#: tcop/postgres.c:5043 #, c-format msgid "fastpath function calls not supported in a replication connection" msgstr "Fastpath-Funktionsaufrufe werden auf einer Replikationsverbindung nicht unterstützt" -#: tcop/postgres.c:5043 +#: tcop/postgres.c:5047 #, c-format msgid "extended query protocol not supported in a replication connection" msgstr "erweitertes Anfrageprotokoll wird nicht auf einer Replikationsverbindung unterstützt" -#: tcop/postgres.c:5189 +#: tcop/postgres.c:5193 #, c-format msgid "disconnection: session time: %d:%02d:%02d.%03d user=%s database=%s host=%s%s%s" msgstr "Verbindungsende: Sitzungszeit: %d:%02d:%02d.%03d Benutzer=%s Datenbank=%s Host=%s%s%s" @@ -25311,12 +25321,12 @@ msgid "missing Dictionary parameter" msgstr "Parameter »Dictionary« fehlt" #: tsearch/spell.c:384 tsearch/spell.c:401 tsearch/spell.c:410 -#: tsearch/spell.c:1041 +#: tsearch/spell.c:1053 #, c-format msgid "invalid affix flag \"%s\"" msgstr "ungültiges Affix-Flag »%s«" -#: tsearch/spell.c:388 tsearch/spell.c:1045 +#: tsearch/spell.c:388 tsearch/spell.c:1057 #, c-format msgid "affix flag \"%s\" is out of range" msgstr "Affix-Flag »%s« ist außerhalb des gültigen Bereichs" @@ -25336,33 +25346,33 @@ msgstr "ungültiges Affix-Flag »%s« mit Flag-Wert »long«" msgid "could not open dictionary file \"%s\": %m" msgstr "konnte Wörterbuchdatei »%s« nicht öffnen: %m" -#: tsearch/spell.c:1168 tsearch/spell.c:1180 tsearch/spell.c:1744 -#: tsearch/spell.c:1749 tsearch/spell.c:1754 +#: tsearch/spell.c:1182 tsearch/spell.c:1194 tsearch/spell.c:1758 +#: tsearch/spell.c:1763 tsearch/spell.c:1768 #, c-format msgid "invalid affix alias \"%s\"" msgstr "ungültiges Affixalias »%s«" -#: tsearch/spell.c:1221 tsearch/spell.c:1292 tsearch/spell.c:1441 +#: tsearch/spell.c:1235 tsearch/spell.c:1306 tsearch/spell.c:1455 #, c-format msgid "could not open affix file \"%s\": %m" msgstr "konnte Affixdatei »%s« nicht öffnen: %m" -#: tsearch/spell.c:1275 +#: tsearch/spell.c:1289 #, c-format msgid "Ispell dictionary supports only \"default\", \"long\", and \"num\" flag values" msgstr "Ispell-Wörterbuch unterstützt nur die Flag-Werte »default«, »long« und »num«" -#: tsearch/spell.c:1319 +#: tsearch/spell.c:1333 #, c-format msgid "invalid number of flag vector aliases" msgstr "ungültige Anzahl Flag-Vektor-Aliasse" -#: tsearch/spell.c:1342 +#: tsearch/spell.c:1356 #, c-format msgid "number of aliases exceeds specified number %d" msgstr "Anzahl der Aliasse überschreitet angegebene Zahl %d" -#: tsearch/spell.c:1556 +#: tsearch/spell.c:1570 #, c-format msgid "affix file contains both old-style and new-style commands" msgstr "Affixdatei enthält Befehle im alten und im neuen Stil" @@ -25640,20 +25650,20 @@ msgstr "Funktion »%s« existiert nicht" msgid "must be able to SET ROLE \"%s\"" msgstr "Berechtigung nur für Rollen, die SET ROLE \"%s\" ausführen können" -#: utils/adt/array_userfuncs.c:118 utils/adt/array_userfuncs.c:565 -#: utils/adt/array_userfuncs.c:942 utils/adt/json.c:611 utils/adt/json.c:749 +#: utils/adt/array_userfuncs.c:119 utils/adt/array_userfuncs.c:566 +#: utils/adt/array_userfuncs.c:943 utils/adt/json.c:611 utils/adt/json.c:749 #: utils/adt/json.c:799 utils/adt/jsonb.c:1025 utils/adt/jsonb.c:1098 #: utils/adt/jsonb.c:1530 utils/adt/jsonb.c:1718 utils/adt/jsonb.c:1728 #, c-format msgid "could not determine input data type" msgstr "konnte Eingabedatentypen nicht bestimmen" -#: utils/adt/array_userfuncs.c:123 +#: utils/adt/array_userfuncs.c:124 #, c-format msgid "input data type is not an array" msgstr "Eingabedatentyp ist kein Array" -#: utils/adt/array_userfuncs.c:167 utils/adt/array_userfuncs.c:249 +#: utils/adt/array_userfuncs.c:168 utils/adt/array_userfuncs.c:250 #: utils/adt/float.c:1229 utils/adt/float.c:1303 utils/adt/float.c:4107 #: utils/adt/float.c:4145 utils/adt/int.c:807 utils/adt/int.c:829 #: utils/adt/int.c:843 utils/adt/int.c:857 utils/adt/int.c:888 @@ -25669,55 +25679,60 @@ msgstr "Eingabedatentyp ist kein Array" msgid "integer out of range" msgstr "integer ist außerhalb des gültigen Bereichs" -#: utils/adt/array_userfuncs.c:174 utils/adt/array_userfuncs.c:259 +#: utils/adt/array_userfuncs.c:175 utils/adt/array_userfuncs.c:260 #, c-format msgid "argument must be empty or one-dimensional array" msgstr "Argument muss entweder leer oder ein eindimensionales Array sein" -#: utils/adt/array_userfuncs.c:371 utils/adt/array_userfuncs.c:410 -#: utils/adt/array_userfuncs.c:447 utils/adt/array_userfuncs.c:476 -#: utils/adt/array_userfuncs.c:504 +#: utils/adt/array_userfuncs.c:372 utils/adt/array_userfuncs.c:411 +#: utils/adt/array_userfuncs.c:448 utils/adt/array_userfuncs.c:477 +#: utils/adt/array_userfuncs.c:505 #, c-format msgid "cannot concatenate incompatible arrays" msgstr "inkompatible Arrays können nicht aneinandergehängt werden" -#: utils/adt/array_userfuncs.c:372 +#: utils/adt/array_userfuncs.c:373 #, c-format msgid "Arrays with element types %s and %s are not compatible for concatenation." msgstr "Arrays mit Elementtypen %s und %s sind nicht kompatibel für Aneinanderhängen." -#: utils/adt/array_userfuncs.c:411 +#: utils/adt/array_userfuncs.c:412 #, c-format msgid "Arrays of %d and %d dimensions are not compatible for concatenation." msgstr "Arrays mit %d und %d Dimensionen sind nicht kompatibel für Aneinanderhängen." -#: utils/adt/array_userfuncs.c:448 +#: utils/adt/array_userfuncs.c:449 #, c-format msgid "Arrays with differing element dimensions are not compatible for concatenation." msgstr "Arrays mit unterschiedlichen Elementdimensionen sind nicht kompatibel für Aneinanderhängen." -#: utils/adt/array_userfuncs.c:477 utils/adt/array_userfuncs.c:505 +#: utils/adt/array_userfuncs.c:478 utils/adt/array_userfuncs.c:506 #, c-format msgid "Arrays with differing dimensions are not compatible for concatenation." msgstr "Arrays mit unterschiedlichen Dimensionen sind nicht kompatibel für Aneinanderhängen." -#: utils/adt/array_userfuncs.c:1051 utils/adt/array_userfuncs.c:1059 +#: utils/adt/array_userfuncs.c:1053 utils/adt/array_userfuncs.c:1061 #: utils/adt/arrayfuncs.c:5634 utils/adt/arrayfuncs.c:5640 #, c-format msgid "cannot accumulate arrays of different dimensionality" msgstr "Arrays unterschiedlicher Dimensionalität können nicht akkumuliert werden" -#: utils/adt/array_userfuncs.c:1348 utils/adt/array_userfuncs.c:1502 +#: utils/adt/array_userfuncs.c:1073 +#, c-format +msgid "array size exceeds the maximum allowed (%zu)" +msgstr "Arraygröße überschreitet erlaubtes Maximum (%zu)" + +#: utils/adt/array_userfuncs.c:1357 utils/adt/array_userfuncs.c:1511 #, c-format msgid "searching for elements in multidimensional arrays is not supported" msgstr "Suche nach Elementen in mehrdimensionalen Arrays wird nicht unterstützt" -#: utils/adt/array_userfuncs.c:1377 +#: utils/adt/array_userfuncs.c:1386 #, c-format msgid "initial position must not be null" msgstr "Startposition darf nicht NULL sein" -#: utils/adt/array_userfuncs.c:1750 +#: utils/adt/array_userfuncs.c:1759 #, c-format msgid "sample size must be between 0 and %d" msgstr "Stichprobengröße muss zwischen 0 und %d sein" @@ -25836,7 +25851,7 @@ msgid "binary data has array element type %u (%s) instead of expected %u (%s)" msgstr "binäre Daten haben Array-Elementtyp %u (%s) statt erwartet %u (%s)" #: utils/adt/arrayfuncs.c:1378 utils/adt/multirangetypes.c:450 -#: utils/adt/rangetypes.c:353 utils/cache/lsyscache.c:3098 +#: utils/adt/rangetypes.c:353 utils/cache/lsyscache.c:3136 #, c-format msgid "no binary input function available for type %s" msgstr "keine binäre Eingabefunktion verfügbar für Typ %s" @@ -25847,7 +25862,7 @@ msgid "improper binary format in array element %d" msgstr "falsches Binärformat in Arrayelement %d" #: utils/adt/arrayfuncs.c:1588 utils/adt/multirangetypes.c:455 -#: utils/adt/rangetypes.c:358 utils/cache/lsyscache.c:3131 +#: utils/adt/rangetypes.c:358 utils/cache/lsyscache.c:3169 #, c-format msgid "no binary output function available for type %s" msgstr "keine binäre Ausgabefunktion verfügbar für Typ %s" @@ -26085,9 +26100,9 @@ msgstr "Präzision von TIME(%d)%s darf nicht negativ sein" msgid "TIME(%d)%s precision reduced to maximum allowed, %d" msgstr "Präzision von TIME(%d)%s auf erlaubten Höchstwert %d reduziert" -#: utils/adt/date.c:168 utils/adt/date.c:176 utils/adt/formatting.c:4172 -#: utils/adt/formatting.c:4181 utils/adt/formatting.c:4286 -#: utils/adt/formatting.c:4296 +#: utils/adt/date.c:168 utils/adt/date.c:176 utils/adt/formatting.c:4174 +#: utils/adt/formatting.c:4183 utils/adt/formatting.c:4288 +#: utils/adt/formatting.c:4298 #, c-format msgid "date out of range: \"%s\"" msgstr "date ist außerhalb des gültigen Bereichs: »%s«" @@ -26143,8 +26158,8 @@ msgstr "Einheit »%s« nicht erkannt für Typ %s" #: utils/adt/date.c:1379 utils/adt/date.c:1425 utils/adt/date.c:1984 #: utils/adt/date.c:2015 utils/adt/date.c:2044 utils/adt/date.c:2934 #: utils/adt/date.c:3166 utils/adt/datetime.c:432 utils/adt/datetime.c:1826 -#: utils/adt/formatting.c:4017 utils/adt/formatting.c:4053 -#: utils/adt/formatting.c:4140 utils/adt/formatting.c:4262 utils/adt/json.c:375 +#: utils/adt/formatting.c:4019 utils/adt/formatting.c:4055 +#: utils/adt/formatting.c:4142 utils/adt/formatting.c:4264 utils/adt/json.c:375 #: utils/adt/json.c:414 utils/adt/timestamp.c:250 utils/adt/timestamp.c:282 #: utils/adt/timestamp.c:707 utils/adt/timestamp.c:716 #: utils/adt/timestamp.c:794 utils/adt/timestamp.c:827 @@ -26174,7 +26189,7 @@ msgstr "Einheit »%s« nicht erkannt für Typ %s" msgid "timestamp out of range" msgstr "timestamp ist außerhalb des gültigen Bereichs" -#: utils/adt/date.c:1601 utils/adt/date.c:2417 utils/adt/formatting.c:4345 +#: utils/adt/date.c:1601 utils/adt/date.c:2417 utils/adt/formatting.c:4347 #, c-format msgid "time out of range" msgstr "time ist außerhalb des gültigen Bereichs" @@ -26456,265 +26471,265 @@ msgstr "ungültige Formatangabe für Intervall-Wert" msgid "Intervals are not tied to specific calendar dates." msgstr "Intervalle beziehen sich nicht auf bestimmte Kalenderdaten." -#: utils/adt/formatting.c:1197 +#: utils/adt/formatting.c:1199 #, c-format msgid "\"EEEE\" must be the last pattern used" msgstr "»EEEE« muss das letzte Muster sein" -#: utils/adt/formatting.c:1205 +#: utils/adt/formatting.c:1207 #, c-format msgid "\"9\" must be ahead of \"PR\"" msgstr "»9« muss vor »PR« stehen" -#: utils/adt/formatting.c:1221 +#: utils/adt/formatting.c:1223 #, c-format msgid "\"0\" must be ahead of \"PR\"" msgstr "»0« muss vor »PR« stehen" -#: utils/adt/formatting.c:1248 +#: utils/adt/formatting.c:1250 #, c-format msgid "multiple decimal points" msgstr "mehrere Dezimalpunkte" -#: utils/adt/formatting.c:1252 utils/adt/formatting.c:1339 +#: utils/adt/formatting.c:1254 utils/adt/formatting.c:1341 #, c-format msgid "cannot use \"V\" and decimal point together" msgstr "»V« und Dezimalpunkt können nicht zusammen verwendet werden" -#: utils/adt/formatting.c:1264 +#: utils/adt/formatting.c:1266 #, c-format msgid "cannot use \"S\" twice" msgstr "»S« kann nicht zweimal verwendet werden" -#: utils/adt/formatting.c:1268 +#: utils/adt/formatting.c:1270 #, c-format msgid "cannot use \"S\" and \"PL\"/\"MI\"/\"SG\"/\"PR\" together" msgstr "»S« und »PL«/»MI«/»SG«/»PR« können nicht zusammen verwendet werden" -#: utils/adt/formatting.c:1288 +#: utils/adt/formatting.c:1290 #, c-format msgid "cannot use \"S\" and \"MI\" together" msgstr "»S« und »MI« können nicht zusammen verwendet werden" -#: utils/adt/formatting.c:1298 +#: utils/adt/formatting.c:1300 #, c-format msgid "cannot use \"S\" and \"PL\" together" msgstr "»S« und »PL« können nicht zusammen verwendet werden" -#: utils/adt/formatting.c:1308 +#: utils/adt/formatting.c:1310 #, c-format msgid "cannot use \"S\" and \"SG\" together" msgstr "»S« und »SG« können nicht zusammen verwendet werden" -#: utils/adt/formatting.c:1317 +#: utils/adt/formatting.c:1319 #, c-format msgid "cannot use \"PR\" and \"S\"/\"PL\"/\"MI\"/\"SG\" together" msgstr "»PR« und »S«/»PL«/»MI«/»SG« können nicht zusammen verwendet werden" -#: utils/adt/formatting.c:1326 +#: utils/adt/formatting.c:1328 #, c-format msgid "cannot use \"RN\" twice" msgstr "»RN« kann nicht zweimal verwendet werden" -#: utils/adt/formatting.c:1347 +#: utils/adt/formatting.c:1349 #, c-format msgid "cannot use \"EEEE\" twice" msgstr "»EEEE« kann nicht zweimal verwendet werden" -#: utils/adt/formatting.c:1353 +#: utils/adt/formatting.c:1355 #, c-format msgid "\"EEEE\" is incompatible with other formats" msgstr "»EEEE« ist mit anderen Formaten inkompatibel" -#: utils/adt/formatting.c:1354 +#: utils/adt/formatting.c:1356 #, c-format msgid "\"EEEE\" may only be used together with digit and decimal point patterns." msgstr "»EEEE« kann nur zusammen mit Platzhaltern für Ziffern oder Dezimalpunkt verwendet werden." -#: utils/adt/formatting.c:1363 +#: utils/adt/formatting.c:1365 #, c-format msgid "\"RN\" is incompatible with other formats" msgstr "»RN« ist mit anderen Formaten inkompatibel" -#: utils/adt/formatting.c:1364 +#: utils/adt/formatting.c:1366 #, c-format msgid "\"RN\" may only be used together with \"FM\"." msgstr "»RN« kann nur zusammen mit »FM« verwendet werden." -#: utils/adt/formatting.c:1445 +#: utils/adt/formatting.c:1447 #, c-format msgid "invalid datetime format separator: \"%s\"" msgstr "ungültiges Datum-/Zeit-Formattrennzeichen: »%s«" -#: utils/adt/formatting.c:1572 +#: utils/adt/formatting.c:1574 #, c-format msgid "\"%s\" is not a number" msgstr "»%s« ist keine Zahl" -#: utils/adt/formatting.c:1653 utils/adt/formatting.c:1717 -#: utils/adt/formatting.c:1781 utils/adt/formatting.c:1845 +#: utils/adt/formatting.c:1655 utils/adt/formatting.c:1719 +#: utils/adt/formatting.c:1783 utils/adt/formatting.c:1847 #, c-format msgid "could not determine which collation to use for %s function" msgstr "konnte die für die Funktion %s zu verwendende Sortierfolge nicht bestimmen" -#: utils/adt/formatting.c:1853 +#: utils/adt/formatting.c:1855 #, c-format msgid "Unicode case folding can only be performed if server encoding is UTF8" msgstr "Unicode-Case-Folding kann nur durchgeführt werden, wenn die Serverkodierung UTF8 ist" -#: utils/adt/formatting.c:2150 +#: utils/adt/formatting.c:2152 #, c-format msgid "invalid combination of date conventions" msgstr "ungültige Kombination von Datumskonventionen" -#: utils/adt/formatting.c:2151 +#: utils/adt/formatting.c:2153 #, c-format msgid "Do not mix Gregorian and ISO week date conventions in a formatting template." msgstr "Die Gregorianische und die ISO-Konvention für Wochendaten können nicht einer Formatvorlage gemischt werden." -#: utils/adt/formatting.c:2173 +#: utils/adt/formatting.c:2175 #, c-format msgid "conflicting values for \"%s\" field in formatting string" msgstr "widersprüchliche Werte für das Feld »%s« in Formatzeichenkette" -#: utils/adt/formatting.c:2175 +#: utils/adt/formatting.c:2177 #, c-format msgid "This value contradicts a previous setting for the same field type." msgstr "Der Wert widerspricht einer vorherigen Einstellung für den selben Feldtyp." -#: utils/adt/formatting.c:2242 +#: utils/adt/formatting.c:2244 #, c-format msgid "source string too short for \"%s\" formatting field" msgstr "Quellzeichenkette zu kurz für Formatfeld »%s»" -#: utils/adt/formatting.c:2244 +#: utils/adt/formatting.c:2246 #, c-format msgid "Field requires %d characters, but only %d remain." msgstr "Feld benötigt %d Zeichen, aber nur %d verbleiben." -#: utils/adt/formatting.c:2246 utils/adt/formatting.c:2260 +#: utils/adt/formatting.c:2248 utils/adt/formatting.c:2262 #, c-format msgid "If your source string is not fixed-width, try using the \"FM\" modifier." msgstr "Wenn die Quellzeichenkette keine feste Breite hat, versuchen Sie den Modifikator »FM«." -#: utils/adt/formatting.c:2256 utils/adt/formatting.c:2269 -#: utils/adt/formatting.c:2490 utils/adt/formatting.c:3390 -#: utils/adt/formatting.c:3593 +#: utils/adt/formatting.c:2258 utils/adt/formatting.c:2271 +#: utils/adt/formatting.c:2492 utils/adt/formatting.c:3392 +#: utils/adt/formatting.c:3595 #, c-format msgid "invalid value \"%s\" for \"%s\"" msgstr "ungültiger Wert »%s« für »%s«" -#: utils/adt/formatting.c:2258 +#: utils/adt/formatting.c:2260 #, c-format msgid "Field requires %d characters, but only %d could be parsed." msgstr "Feld benötigt %d Zeichen, aber nur %d konnten geparst werden." -#: utils/adt/formatting.c:2271 +#: utils/adt/formatting.c:2273 #, c-format msgid "Value must be an integer." msgstr "Der Wert muss eine ganze Zahl sein." -#: utils/adt/formatting.c:2276 utils/adt/formatting.c:3601 +#: utils/adt/formatting.c:2278 utils/adt/formatting.c:3603 #, c-format msgid "value for \"%s\" in source string is out of range" msgstr "Wert für »%s« in der Eingabezeichenkette ist außerhalb des gültigen Bereichs" -#: utils/adt/formatting.c:2278 +#: utils/adt/formatting.c:2280 #, c-format msgid "Value must be in the range %d to %d." msgstr "Der Wert muss im Bereich %d bis %d sein." -#: utils/adt/formatting.c:2492 +#: utils/adt/formatting.c:2494 #, c-format msgid "The given value did not match any of the allowed values for this field." msgstr "Der angegebene Wert stimmte mit keinem der für dieses Feld zulässigen Werte überein." -#: utils/adt/formatting.c:2708 utils/adt/formatting.c:2728 -#: utils/adt/formatting.c:2748 utils/adt/formatting.c:2768 -#: utils/adt/formatting.c:2787 utils/adt/formatting.c:2806 -#: utils/adt/formatting.c:2830 utils/adt/formatting.c:2848 -#: utils/adt/formatting.c:2866 utils/adt/formatting.c:2884 -#: utils/adt/formatting.c:2901 utils/adt/formatting.c:2918 +#: utils/adt/formatting.c:2710 utils/adt/formatting.c:2730 +#: utils/adt/formatting.c:2750 utils/adt/formatting.c:2770 +#: utils/adt/formatting.c:2789 utils/adt/formatting.c:2808 +#: utils/adt/formatting.c:2832 utils/adt/formatting.c:2850 +#: utils/adt/formatting.c:2868 utils/adt/formatting.c:2886 +#: utils/adt/formatting.c:2903 utils/adt/formatting.c:2920 #, c-format msgid "localized string format value too long" msgstr "lokalisierter Formatwert ist zu lang" -#: utils/adt/formatting.c:3198 +#: utils/adt/formatting.c:3200 #, c-format msgid "unmatched format separator \"%c\"" msgstr "Formattrennzeichen »%c« ohne passende Eingabe" -#: utils/adt/formatting.c:3259 +#: utils/adt/formatting.c:3261 #, c-format msgid "unmatched format character \"%s\"" msgstr "Formatzeichen »%s« ohne passende Eingabe" -#: utils/adt/formatting.c:3392 +#: utils/adt/formatting.c:3394 #, c-format msgid "Time zone abbreviation is not recognized." msgstr "Zeitzonenabkürzung wird nicht erkannt." -#: utils/adt/formatting.c:3690 +#: utils/adt/formatting.c:3692 #, c-format msgid "input string is too short for datetime format" msgstr "Eingabezeichenkette ist zu kurz für Datum-/Zeitformat" -#: utils/adt/formatting.c:3698 +#: utils/adt/formatting.c:3700 #, c-format msgid "trailing characters remain in input string after datetime format" msgstr "nach dem Datum-/Zeitformat bleiben noch Zeichen in der Eingabezeichenkette" -#: utils/adt/formatting.c:4242 +#: utils/adt/formatting.c:4244 #, c-format msgid "missing time zone in input string for type timestamptz" msgstr "Zeitzone fehlt in Eingabezeichenkette für Typ timestamptz" -#: utils/adt/formatting.c:4248 +#: utils/adt/formatting.c:4250 #, c-format msgid "timestamptz out of range" msgstr "timestamptz ist außerhalb des gültigen Bereichs" -#: utils/adt/formatting.c:4276 +#: utils/adt/formatting.c:4278 #, c-format msgid "datetime format is zoned but not timed" msgstr "Datum-/Zeitformat hat Zeitzone aber keine Zeit" -#: utils/adt/formatting.c:4325 +#: utils/adt/formatting.c:4327 #, c-format msgid "missing time zone in input string for type timetz" msgstr "Zeitzone fehlt in Eingabezeichenkette für Typ timetz" -#: utils/adt/formatting.c:4331 +#: utils/adt/formatting.c:4333 #, c-format msgid "timetz out of range" msgstr "timetz ist außerhalb des gültigen Bereichs" -#: utils/adt/formatting.c:4357 +#: utils/adt/formatting.c:4359 #, c-format msgid "datetime format is not dated and not timed" msgstr "Datum-/Zeitformat hat kein Datum und keine Zeit" -#: utils/adt/formatting.c:4534 +#: utils/adt/formatting.c:4536 #, c-format msgid "hour \"%d\" is invalid for the 12-hour clock" msgstr "Stunde »%d« ist bei einer 12-Stunden-Uhr ungültig" -#: utils/adt/formatting.c:4536 +#: utils/adt/formatting.c:4538 #, c-format msgid "Use the 24-hour clock, or give an hour between 1 and 12." msgstr "Verwenden Sie die 24-Stunden-Uhr oder geben Sie eine Stunde zwischen 1 und 12 an." -#: utils/adt/formatting.c:4713 +#: utils/adt/formatting.c:4715 #, c-format msgid "cannot calculate day of year without year information" msgstr "kann Tag des Jahres nicht berechnen ohne Jahrinformationen" -#: utils/adt/formatting.c:5836 +#: utils/adt/formatting.c:5849 #, c-format msgid "\"EEEE\" not supported for input" msgstr "»E« wird nicht bei der Eingabe unterstützt" -#: utils/adt/formatting.c:6113 +#: utils/adt/formatting.c:6139 #, c-format msgid "invalid Roman numeral" msgstr "ungültige römische Zahl" @@ -27890,33 +27905,33 @@ msgstr "konnte Collator für Locale »%s« nicht öffnen: %s" msgid "could not open collator for locale \"%s\" with rules \"%s\": %s" msgstr "konnte Collator für Locale »%s« mit Regeln »%s« nicht öffnen: %s" -#: utils/adt/pg_locale_icu.c:488 +#: utils/adt/pg_locale_icu.c:490 #, c-format msgid "collation failed: %s" msgstr "Vergleichung fehlgeschlagen: %s" -#: utils/adt/pg_locale_icu.c:567 utils/adt/pg_locale_icu.c:831 +#: utils/adt/pg_locale_icu.c:569 utils/adt/pg_locale_icu.c:833 #, c-format msgid "sort key generation failed: %s" msgstr "Sortierschlüsselerzeugung fehlgeschlagen: %s" -#: utils/adt/pg_locale_icu.c:641 utils/adt/pg_locale_icu.c:653 -#: utils/adt/pg_locale_icu.c:878 utils/adt/pg_locale_icu.c:899 +#: utils/adt/pg_locale_icu.c:643 utils/adt/pg_locale_icu.c:655 +#: utils/adt/pg_locale_icu.c:883 utils/adt/pg_locale_icu.c:904 #, c-format msgid "%s failed: %s" msgstr "%s fehlgeschlagen: %s" -#: utils/adt/pg_locale_icu.c:682 +#: utils/adt/pg_locale_icu.c:684 #, c-format msgid "case conversion failed: %s" msgstr "Groß/Klein-Umwandlung fehlgeschlagen: %s" -#: utils/adt/pg_locale_icu.c:851 +#: utils/adt/pg_locale_icu.c:856 #, c-format msgid "encoding \"%s\" not supported by ICU" msgstr "Kodierung »%s« wird von ICU nicht unterstützt" -#: utils/adt/pg_locale_icu.c:858 +#: utils/adt/pg_locale_icu.c:863 #, c-format msgid "could not open ICU converter for encoding \"%s\": %s" msgstr "konnte ICU-Konverter für Kodierung »%s« nicht öffnen: %s" @@ -29025,23 +29040,23 @@ msgstr "XPath-Ausdruck für Spalte gab mehr als einen Wert zurück" msgid "could not determine actual argument type for polymorphic function \"%s\"" msgstr "konnte den tatsächlichen Argumenttyp der polymorphischen Funktion »%s« nicht ermitteln" -#: utils/cache/lsyscache.c:1109 +#: utils/cache/lsyscache.c:1147 #, c-format msgid "cast from type %s to type %s does not exist" msgstr "Typumwandlung von Typ %s in Typ %s existiert nicht" -#: utils/cache/lsyscache.c:3027 utils/cache/lsyscache.c:3060 -#: utils/cache/lsyscache.c:3093 utils/cache/lsyscache.c:3126 +#: utils/cache/lsyscache.c:3065 utils/cache/lsyscache.c:3098 +#: utils/cache/lsyscache.c:3131 utils/cache/lsyscache.c:3164 #, c-format msgid "type %s is only a shell" msgstr "Typ %s ist nur eine Hülle" -#: utils/cache/lsyscache.c:3032 +#: utils/cache/lsyscache.c:3070 #, c-format msgid "no input function available for type %s" msgstr "keine Eingabefunktion verfügbar für Typ %s" -#: utils/cache/lsyscache.c:3065 +#: utils/cache/lsyscache.c:3103 #, c-format msgid "no output function available for type %s" msgstr "keine Ausgabefunktion verfügbar für Typ %s" @@ -32578,8 +32593,8 @@ msgstr "Es existieren doppelte Schlüssel." #: utils/sort/tuplestore.c:552 utils/sort/tuplestore.c:562 #: utils/sort/tuplestore.c:921 utils/sort/tuplestore.c:1025 #: utils/sort/tuplestore.c:1089 utils/sort/tuplestore.c:1106 -#: utils/sort/tuplestore.c:1308 utils/sort/tuplestore.c:1373 -#: utils/sort/tuplestore.c:1382 +#: utils/sort/tuplestore.c:1320 utils/sort/tuplestore.c:1385 +#: utils/sort/tuplestore.c:1394 #, c-format msgid "could not seek in tuplestore temporary file" msgstr "konnte Positionszeiger in temporärer Datei für Tuplestore nicht setzen" diff --git a/src/backend/po/es.po b/src/backend/po/es.po index fa0e06417c9..93f873ce51a 100644 --- a/src/backend/po/es.po +++ b/src/backend/po/es.po @@ -65,7 +65,7 @@ msgstr "" "Project-Id-Version: PostgreSQL server 17\n" "Report-Msgid-Bugs-To: pgsql-bugs@lists.postgresql.org\n" "POT-Creation-Date: 2026-02-06 23:10+0000\n" -"PO-Revision-Date: 2026-02-07 10:17+0100\n" +"PO-Revision-Date: 2026-02-25 16:53+0100\n" "Last-Translator: Carlos Chapi \n" "Language-Team: PgSQL-es-Ayuda \n" "Language: es\n" @@ -22171,7 +22171,7 @@ msgstr "Cambie «hot_standby» a «on»." #: replication/slot.c:2666 #, c-format msgid "physical replication slot \"%s\" exists, but \"wal_level\" < \"replica\"" -msgstr "existe el slot de replicación lógica «%s», pero «wal_level» < «replica»" +msgstr "existe el slot de replicación física «%s», pero «wal_level» < «replica»" # <> hello vim #: replication/slot.c:2668 diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index e01539d6c93..c2c7b34b03b 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -313,12 +313,13 @@ static bool FatalError = false; /* T if recovering from backend crash */ * * When the startup process is ready to start archive recovery, it signals the * postmaster, and we switch to PM_RECOVERY state. The background writer and - * checkpointer are launched, while the startup process continues applying WAL. - * If Hot Standby is enabled, then, after reaching a consistent point in WAL - * redo, startup process signals us again, and we switch to PM_HOT_STANDBY - * state and begin accepting connections to perform read-only queries. When - * archive recovery is finished, the startup process exits with exit code 0 - * and we switch to PM_RUN state. + * checkpointer are already running (as these are launched during PM_STARTUP), + * and the startup process continues applying WAL. If Hot Standby is enabled, + * then, after reaching a consistent point in WAL redo, startup process + * signals us again, and we switch to PM_HOT_STANDBY state and begin accepting + * connections to perform read-only queries. When archive recovery is + * finished, the startup process exits with exit code 0 and we switch to + * PM_RUN state. * * Normal child backends can only be launched when we are in PM_RUN or * PM_HOT_STANDBY state. (connsAllowed can also restrict launching.) @@ -2389,29 +2390,13 @@ process_pm_child_exit(void) } /* - * Unexpected exit of startup process (including FATAL exit) - * during PM_STARTUP is treated as catastrophic. There are no - * other processes running yet, so we can just exit. - */ - if (pmState == PM_STARTUP && - StartupStatus != STARTUP_SIGNALED && - !EXIT_STATUS_0(exitstatus)) - { - LogChildExit(LOG, _("startup process"), - pid, exitstatus); - ereport(LOG, - (errmsg("aborting startup due to startup process failure"))); - ExitPostmaster(1); - } - - /* - * After PM_STARTUP, any unexpected exit (including FATAL exit) of - * the startup process is catastrophic, so kill other children, - * and set StartupStatus so we don't try to reinitialize after - * they're gone. Exception: if StartupStatus is STARTUP_SIGNALED, - * then we previously sent the startup process a SIGQUIT; so - * that's probably the reason it died, and we do want to try to - * restart in that case. + * Any unexpected exit (including FATAL exit) of the startup + * process is catastrophic, so kill other children, and set + * StartupStatus so we don't try to reinitialize after they're + * gone. Exception: if StartupStatus is STARTUP_SIGNALED, then we + * previously sent the startup process a SIGQUIT; so that's + * probably the reason it died, and we do want to try to restart + * in that case. * * This stanza also handles the case where we sent a SIGQUIT * during PM_STARTUP due to some dead-end child crashing: in that @@ -2846,12 +2831,9 @@ HandleFatalError(QuitSignalReason reason, bool consider_sigabrt) /* shouldn't have any children */ Assert(false); break; - case PM_STARTUP: - /* should have been handled in process_pm_child_exit */ - Assert(false); - break; /* wait for children to die */ + case PM_STARTUP: case PM_RECOVERY: case PM_HOT_STANDBY: case PM_RUN: diff --git a/src/backend/postmaster/walsummarizer.c b/src/backend/postmaster/walsummarizer.c index 11857356ce4..e0ff745f2dd 100644 --- a/src/backend/postmaster/walsummarizer.c +++ b/src/backend/postmaster/walsummarizer.c @@ -23,6 +23,7 @@ #include "postgres.h" #include "access/timeline.h" +#include "access/visibilitymap.h" #include "access/xlog.h" #include "access/xlog_internal.h" #include "access/xlogrecovery.h" @@ -1356,7 +1357,8 @@ SummarizeSmgrRecord(XLogReaderState *xlogreader, BlockRefTable *brtab) MAIN_FORKNUM, xlrec->blkno); if ((xlrec->flags & SMGR_TRUNCATE_VM) != 0) BlockRefTableSetLimitBlock(brtab, &xlrec->rlocator, - VISIBILITYMAP_FORKNUM, xlrec->blkno); + VISIBILITYMAP_FORKNUM, + visibilitymap_truncation_length(xlrec->blkno)); } } diff --git a/src/backend/regex/regc_color.c b/src/backend/regex/regc_color.c index 8ae788f5195..1587f452ea3 100644 --- a/src/backend/regex/regc_color.c +++ b/src/backend/regex/regc_color.c @@ -218,6 +218,7 @@ newcolor(struct colormap *cm) n = cm->ncds * 2; if (n > MAX_COLOR + 1) n = MAX_COLOR + 1; + /* the MAX_COLOR+1 limit ensures these alloc sizes can't overflow: */ if (cm->cd == cm->cdspace) { newCd = (struct colordesc *) MALLOC(n * sizeof(struct colordesc)); @@ -434,9 +435,8 @@ newhicolorrow(struct colormap *cm, CERR(REG_ESPACE); return 0; } - newarray = (color *) REALLOC(cm->hicolormap, - cm->maxarrayrows * 2 * - cm->hiarraycols * sizeof(color)); + newarray = REALLOC_ARRAY(cm->hicolormap, color, + cm->maxarrayrows * 2 * cm->hiarraycols); if (newarray == NULL) { CERR(REG_ESPACE); @@ -477,9 +477,8 @@ newhicolorcols(struct colormap *cm) CERR(REG_ESPACE); return; } - newarray = (color *) REALLOC(cm->hicolormap, - cm->maxarrayrows * - cm->hiarraycols * 2 * sizeof(color)); + newarray = REALLOC_ARRAY(cm->hicolormap, color, + cm->maxarrayrows * cm->hiarraycols * 2); if (newarray == NULL) { CERR(REG_ESPACE); @@ -652,8 +651,7 @@ subcoloronechr(struct vars *v, * Potentially, we could need two more colormapranges than we have now, if * the given chr is in the middle of some existing range. */ - newranges = (colormaprange *) - MALLOC((cm->numcmranges + 2) * sizeof(colormaprange)); + newranges = MALLOC_ARRAY(colormaprange, cm->numcmranges + 2); if (newranges == NULL) { CERR(REG_ESPACE); @@ -766,8 +764,7 @@ subcoloronerange(struct vars *v, * Potentially, if we have N non-adjacent ranges, we could need as many as * 2N+1 result ranges (consider case where new range spans 'em all). */ - newranges = (colormaprange *) - MALLOC((cm->numcmranges * 2 + 1) * sizeof(colormaprange)); + newranges = MALLOC_ARRAY(colormaprange, cm->numcmranges * 2 + 1); if (newranges == NULL) { CERR(REG_ESPACE); diff --git a/src/backend/regex/regc_cvec.c b/src/backend/regex/regc_cvec.c index 10306215596..8dbcf3c55e3 100644 --- a/src/backend/regex/regc_cvec.c +++ b/src/backend/regex/regc_cvec.c @@ -40,6 +40,9 @@ /* * newcvec - allocate a new cvec + * + * Note: in current usage, nchrs and nranges are never so large that we risk + * integer overflow in these size calculations, even with 32-bit size_t. */ static struct cvec * newcvec(int nchrs, /* to hold this many chrs... */ diff --git a/src/backend/regex/regc_nfa.c b/src/backend/regex/regc_nfa.c index acd2286defd..92b11116194 100644 --- a/src/backend/regex/regc_nfa.c +++ b/src/backend/regex/regc_nfa.c @@ -3523,6 +3523,10 @@ compact(struct nfa *nfa, assert(!NISERR()); + /* + * The REG_MAX_COMPILE_SPACE restriction ensures that integer overflow + * can't occur in this loop nor in the allocation requests below. + */ nstates = 0; narcs = 0; for (s = nfa->states; s != NULL; s = s->next) @@ -3575,6 +3579,12 @@ compact(struct nfa *nfa, case LACON: assert(s->no != cnfa->pre); assert(a->co >= 0); + /* make sure the modified color number will fit */ + if (a->co > MAX_COLOR - cnfa->ncolors) + { + NERR(REG_ECOLORS); + return; + } ca->co = (color) (cnfa->ncolors + a->co); ca->to = a->to->no; ca++; diff --git a/src/backend/regex/regcomp.c b/src/backend/regex/regcomp.c index 15b264e50f1..4b8eed1b384 100644 --- a/src/backend/regex/regcomp.c +++ b/src/backend/regex/regcomp.c @@ -561,6 +561,7 @@ moresubs(struct vars *v, assert(wanted > 0 && (size_t) wanted >= v->nsubs); n = (size_t) wanted * 3 / 2 + 1; + /* n is bounded by the number of states, so no chance of overflow here */ if (v->subs == v->sub10) { p = (struct subre **) MALLOC(n * sizeof(struct subre *)); @@ -2405,8 +2406,8 @@ newlacon(struct vars *v, else { n = v->nlacons; - newlacons = (struct subre *) REALLOC(v->lacons, - (n + 1) * sizeof(struct subre)); + /* better use REALLOC_ARRAY here, as struct subre is big */ + newlacons = REALLOC_ARRAY(v->lacons, struct subre, n + 1); } if (newlacons == NULL) { diff --git a/src/backend/regex/rege_dfa.c b/src/backend/regex/rege_dfa.c index 1f8f2ab1441..5b57fed60a9 100644 --- a/src/backend/regex/rege_dfa.c +++ b/src/backend/regex/rege_dfa.c @@ -640,20 +640,29 @@ newdfa(struct vars *v, } else { + /* + * Restrict the ranges of nstates and ncolors enough that the arrays + * we allocate here have no more than INT_MAX members. This protects + * not only the allocation calculations just below, but later indexing + * into these arrays. + */ + if (wordsper >= INT_MAX / (nss + WORK) || + cnfa->ncolors >= INT_MAX / nss) + { + ERR(REG_ETOOBIG); + return NULL; + } d = (struct dfa *) MALLOC(sizeof(struct dfa)); if (d == NULL) { ERR(REG_ESPACE); return NULL; } - d->ssets = (struct sset *) MALLOC(nss * sizeof(struct sset)); - d->statesarea = (unsigned *) MALLOC((nss + WORK) * wordsper * - sizeof(unsigned)); + d->ssets = MALLOC_ARRAY(struct sset, nss); + d->statesarea = MALLOC_ARRAY(unsigned, (nss + WORK) * wordsper); d->work = &d->statesarea[nss * wordsper]; - d->outsarea = (struct sset **) MALLOC(nss * cnfa->ncolors * - sizeof(struct sset *)); - d->incarea = (struct arcp *) MALLOC(nss * cnfa->ncolors * - sizeof(struct arcp)); + d->outsarea = MALLOC_ARRAY(struct sset *, nss * cnfa->ncolors); + d->incarea = MALLOC_ARRAY(struct arcp, nss * cnfa->ncolors); d->ismalloced = true; d->arraysmalloced = true; /* now freedfa() will behave sanely */ diff --git a/src/backend/regex/regexec.c b/src/backend/regex/regexec.c index 2a1d5bebda3..665aa31bd03 100644 --- a/src/backend/regex/regexec.c +++ b/src/backend/regex/regexec.c @@ -231,7 +231,7 @@ pg_regexec(regex_t *re, if (v->nmatch <= LOCALMAT) v->pmatch = mat; else - v->pmatch = (regmatch_t *) MALLOC(v->nmatch * sizeof(regmatch_t)); + v->pmatch = MALLOC_ARRAY(regmatch_t, v->nmatch); if (v->pmatch == NULL) return REG_ESPACE; zapallsubs(v->pmatch, v->nmatch); @@ -265,6 +265,7 @@ pg_regexec(regex_t *re, v->subdfas = subdfas; else { + /* ntree is surely less than the number of states, so this is safe: */ v->subdfas = (struct dfa **) MALLOC(n * sizeof(struct dfa *)); if (v->subdfas == NULL) { @@ -279,6 +280,7 @@ pg_regexec(regex_t *re, n = (size_t) v->g->nlacons; if (n > 0) { + /* nlacons is surely less than the number of arcs, so this is safe: */ v->ladfas = (struct dfa **) MALLOC(n * sizeof(struct dfa *)); if (v->ladfas == NULL) { @@ -1163,7 +1165,7 @@ citerdissect(struct vars *v, max_matches = t->max; if (max_matches < min_matches) max_matches = min_matches; - endpts = (chr **) MALLOC((max_matches + 1) * sizeof(chr *)); + endpts = MALLOC_ARRAY(chr *, max_matches + 1); if (endpts == NULL) return REG_ESPACE; endpts[0] = begin; @@ -1370,7 +1372,7 @@ creviterdissect(struct vars *v, max_matches = t->max; if (max_matches < min_matches) max_matches = min_matches; - endpts = (chr **) MALLOC((max_matches + 1) * sizeof(chr *)); + endpts = MALLOC_ARRAY(chr *, max_matches + 1); if (endpts == NULL) return REG_ESPACE; endpts[0] = begin; diff --git a/src/backend/replication/logical/applyparallelworker.c b/src/backend/replication/logical/applyparallelworker.c index 2d140e262c1..b70adf342a5 100644 --- a/src/backend/replication/logical/applyparallelworker.c +++ b/src/backend/replication/logical/applyparallelworker.c @@ -811,6 +811,15 @@ LogicalParallelApplyLoop(shm_mq_handle *mqh) if (rc & WL_LATCH_SET) ResetLatch(MyLatch); + + /* + * Force stats reporting to avoid long delays. There can be long + * idle gaps before the leader assigns the next transaction, and + * the only opportunity to report stats during such gaps is + * here. + */ + if ((rc & WL_TIMEOUT) && !IsTransactionState()) + pgstat_report_stat(true); } } else diff --git a/src/backend/replication/logical/slotsync.c b/src/backend/replication/logical/slotsync.c index f9e19771aeb..3cbcd77d12f 100644 --- a/src/backend/replication/logical/slotsync.c +++ b/src/backend/replication/logical/slotsync.c @@ -72,16 +72,20 @@ /* * Struct for sharing information to control slot synchronization. * - * The slot sync worker's pid is needed by the startup process to shut it - * down during promotion. The startup process shuts down the slot sync worker - * and also sets stopSignaled=true to handle the race condition when the - * postmaster has not noticed the promotion yet and thus may end up restarting - * the slot sync worker. If stopSignaled is set, the worker will exit in such a - * case. The SQL function pg_sync_replication_slots() will also error out if - * this flag is set. Note that we don't need to reset this variable as after - * promotion the slot sync worker won't be restarted because the pmState - * changes to PM_RUN from PM_HOT_STANDBY and we don't support demoting - * primary without restarting the server. See LaunchMissingBackgroundProcesses. + * The 'pid' is either the slot sync worker's pid or the backend's pid running + * the SQL function pg_sync_replication_slots(). On promotion, the startup + * process sets 'stopSignaled' and uses this 'pid' to signal the synchronizing + * process with PROCSIG_SLOTSYNC_MESSAGE and also to wake it up so that the + * process can immediately stop its synchronizing work. + * Setting 'stopSignaled' on the other hand is used to handle the race + * condition when the postmaster has not noticed the promotion yet and thus may + * end up restarting the slot sync worker. If 'stopSignaled' is set, the worker + * will exit in such a case. The SQL function pg_sync_replication_slots() will + * also error out if this flag is set. Note that we don't need to reset this + * variable as after promotion the slot sync worker won't be restarted because + * the pmState changes to PM_RUN from PM_HOT_STANDBY and we don't support + * demoting primary without restarting the server. + * See LaunchMissingBackgroundProcesses. * * The 'syncing' flag is needed to prevent concurrent slot syncs to avoid slot * overwrites. @@ -126,6 +130,13 @@ static long sleep_ms = MIN_SLOTSYNC_WORKER_NAPTIME_MS; */ static bool syncing_slots = false; +/* + * Interrupt flag set when PROCSIG_SLOTSYNC_MESSAGE is received, asking the + * slotsync worker or pg_sync_replication_slots() to stop because + * standby promotion has been triggered. + */ +volatile sig_atomic_t SlotSyncShutdownPending = false; + /* * Structure to hold information fetched from the primary server about a logical * replication slot. @@ -264,9 +275,15 @@ update_local_synced_slot(RemoteSlot *remote_slot, Oid remote_dbid, if (found_consistent_snapshot) *found_consistent_snapshot = true; + + updated_xmin_or_lsn = true; } else { + XLogRecPtr old_confirmed_lsn = slot->data.confirmed_flush; + XLogRecPtr old_restart_lsn = slot->data.restart_lsn; + XLogRecPtr old_catalog_xmin = slot->data.catalog_xmin; + LogicalSlotAdvanceAndCheckSnapState(remote_slot->confirmed_lsn, found_consistent_snapshot); @@ -278,9 +295,16 @@ update_local_synced_slot(RemoteSlot *remote_slot, Oid remote_dbid, errdetail_internal("Remote slot has LSN %X/%X but local slot has LSN %X/%X.", LSN_FORMAT_ARGS(remote_slot->confirmed_lsn), LSN_FORMAT_ARGS(slot->data.confirmed_flush))); - } - updated_xmin_or_lsn = true; + /* + * It is possible that the slot's xmin or LSNs are not updated, + * when the synced slot has reached consistent snapshot state or + * cannot build one at all. + */ + updated_xmin_or_lsn = (old_confirmed_lsn != slot->data.confirmed_flush || + old_restart_lsn != slot->data.restart_lsn || + old_catalog_xmin != slot->data.catalog_xmin); + } } if (remote_dbid != slot->data.database || @@ -1119,10 +1143,10 @@ ValidateSlotSyncParams(int elevel) } /* - * Re-read the config file. + * Re-read the config file for slot synchronization. * - * Exit if any of the slot sync GUCs have changed. The postmaster will - * restart it. + * Exit or throw error if relevant GUCs have changed depending on whether + * called from slot sync worker or from the SQL function pg_sync_replication_slots() */ static void slotsync_reread_config(void) @@ -1133,8 +1157,11 @@ slotsync_reread_config(void) bool old_hot_standby_feedback = hot_standby_feedback; bool conninfo_changed; bool primary_slotname_changed; + bool is_slotsync_worker = AmLogicalSlotSyncWorkerProcess(); + bool parameter_changed = false; - Assert(sync_replication_slots); + if (is_slotsync_worker) + Assert(sync_replication_slots); ConfigReloadPending = false; ProcessConfigFile(PGC_SIGHUP); @@ -1146,48 +1173,105 @@ slotsync_reread_config(void) if (old_sync_replication_slots != sync_replication_slots) { - ereport(LOG, - /* translator: %s is a GUC variable name */ - errmsg("replication slot synchronization worker will shut down because \"%s\" is disabled", "sync_replication_slots")); - proc_exit(0); - } + if (is_slotsync_worker) + { + ereport(LOG, + /* translator: %s is a GUC variable name */ + errmsg("replication slot synchronization worker will stop because \"%s\" is disabled", + "sync_replication_slots")); + + proc_exit(0); + } - if (conninfo_changed || - primary_slotname_changed || - (old_hot_standby_feedback != hot_standby_feedback)) + parameter_changed = true; + } + else { - ereport(LOG, - errmsg("replication slot synchronization worker will restart because of a parameter change")); + if (conninfo_changed || + primary_slotname_changed || + (old_hot_standby_feedback != hot_standby_feedback)) + { - /* - * Reset the last-start time for this worker so that the postmaster - * can restart it without waiting for SLOTSYNC_RESTART_INTERVAL_SEC. - */ - SlotSyncCtx->last_start_time = 0; + if (is_slotsync_worker) + { + ereport(LOG, + errmsg("replication slot synchronization worker will restart because of a parameter change")); - proc_exit(0); + /* + * Reset the last-start time for this worker so that the + * postmaster can restart it without waiting for + * SLOTSYNC_RESTART_INTERVAL_SEC. + */ + SlotSyncCtx->last_start_time = 0; + + proc_exit(0); + } + + parameter_changed = true; + } + } + + /* + * If we have reached here with a parameter change, we must be running in + * SQL function, emit error in such a case. + */ + if (parameter_changed) + { + Assert(!is_slotsync_worker); + ereport(ERROR, + errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("replication slot synchronization will stop because of a parameter change")); } } /* - * Interrupt handler for main loop of slot sync worker. + * Handle receipt of an interrupt indicating a slotsync shutdown message. + * + * This is called within the SIGUSR1 handler. All we do here is set a flag + * that will cause the next CHECK_FOR_INTERRUPTS() to invoke + * ProcessSlotSyncMessage(). */ -static void -ProcessSlotSyncInterrupts(WalReceiverConn *wrconn) +void +HandleSlotSyncMessageInterrupt(void) { - CHECK_FOR_INTERRUPTS(); + InterruptPending = true; + SlotSyncShutdownPending = true; + /* latch will be set by procsignal_sigusr1_handler */ +} - if (SlotSyncCtx->stopSignaled) +/* + * Handle a PROCSIG_SLOTSYNC_MESSAGE signal, called from ProcessInterrupts(). + * + * If the current process is the slotsync background worker, log a message + * and exit cleanly. If it is a backend executing pg_sync_replication_slots(), + * raise an error, unless the sync has already finished, in which case there + * is no need to interrupt the caller. + */ +void +ProcessSlotSyncMessage(void) +{ + SlotSyncShutdownPending = false; + + if (AmLogicalSlotSyncWorkerProcess()) { ereport(LOG, - errmsg("replication slot synchronization worker is shutting down because promotion is triggered")); - + errmsg("replication slot synchronization worker will stop because promotion is triggered")); proc_exit(0); } + else + { + /* + * If sync has already completed, there is no need to interrupt the + * caller with an error. + */ + if (!IsSyncingReplicationSlots()) + return; - if (ConfigReloadPending) - slotsync_reread_config(); + ereport(ERROR, + errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("replication slot synchronization will stop because promotion is triggered")); + } } /* @@ -1286,27 +1370,40 @@ wait_for_slot_activity(bool some_slot_updated) } /* - * Emit an error if a promotion or a concurrent sync call is in progress. + * Emit an error if a concurrent sync call is in progress. * Otherwise, advertise that a sync is in progress. */ static void -check_and_set_sync_info(pid_t worker_pid) +check_and_set_sync_info(pid_t sync_process_pid) { SpinLockAcquire(&SlotSyncCtx->mutex); - /* The worker pid must not be already assigned in SlotSyncCtx */ - Assert(worker_pid == InvalidPid || SlotSyncCtx->pid == InvalidPid); - /* - * Emit an error if startup process signaled the slot sync machinery to - * stop. See comments atop SlotSyncCtxStruct. + * Exit immediately if promotion has been triggered. This guards against + * a new worker (or a call to pg_sync_replication_slots()) that starts + * after the old worker was stopped by ShutDownSlotSync(). */ if (SlotSyncCtx->stopSignaled) { SpinLockRelease(&SlotSyncCtx->mutex); - ereport(ERROR, - errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), - errmsg("cannot synchronize replication slots when standby promotion is ongoing")); + + if (AmLogicalSlotSyncWorkerProcess()) + { + ereport(DEBUG1, + errmsg("replication slot synchronization worker will not start because promotion was triggered")); + + proc_exit(0); + } + else + { + /* + * For the backend executing SQL function + * pg_sync_replication_slots(). + */ + ereport(ERROR, + errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("replication slot synchronization will not start because promotion was triggered")); + } } if (SlotSyncCtx->syncing) @@ -1317,13 +1414,16 @@ check_and_set_sync_info(pid_t worker_pid) errmsg("cannot synchronize replication slots concurrently")); } + /* The pid must not be already assigned in SlotSyncCtx */ + Assert(SlotSyncCtx->pid == InvalidPid); + SlotSyncCtx->syncing = true; /* * Advertise the required PID so that the startup process can kill the - * slot sync worker on promotion. + * slot sync process on promotion. */ - SlotSyncCtx->pid = worker_pid; + SlotSyncCtx->pid = sync_process_pid; SpinLockRelease(&SlotSyncCtx->mutex); @@ -1338,6 +1438,7 @@ reset_syncing_flag() { SpinLockAcquire(&SlotSyncCtx->mutex); SlotSyncCtx->syncing = false; + SlotSyncCtx->pid = InvalidPid; SpinLockRelease(&SlotSyncCtx->mutex); syncing_slots = false; @@ -1510,7 +1611,10 @@ ReplSlotSyncWorkerMain(const void *startup_data, size_t startup_data_len) { bool some_slot_updated = false; - ProcessSlotSyncInterrupts(wrconn); + CHECK_FOR_INTERRUPTS(); + + if (ConfigReloadPending) + slotsync_reread_config(); some_slot_updated = synchronize_slots(wrconn); @@ -1546,7 +1650,7 @@ update_synced_slots_inactive_since(void) if (!StandbyMode) return; - /* The slot sync worker or SQL function mustn't be running by now */ + /* The slot sync worker or the SQL function mustn't be running by now */ Assert((SlotSyncCtx->pid == InvalidPid) && !SlotSyncCtx->syncing); LWLockAcquire(ReplicationSlotControlLock, LW_SHARED); @@ -1575,16 +1679,18 @@ update_synced_slots_inactive_since(void) } /* - * Shut down the slot sync worker. + * Shut down slot synchronization. * - * This function sends signal to shutdown slot sync worker, if required. It - * also waits till the slot sync worker has exited or + * This function sets stopSignaled=true and wakes up the slot sync process + * (either worker or backend running the SQL function pg_sync_replication_slots()) + * so that worker can exit or the SQL function pg_sync_replication_slots() can + * finish. It also waits till the slot sync worker has exited or * pg_sync_replication_slots() has finished. */ void ShutDownSlotSync(void) { - pid_t worker_pid; + pid_t sync_process_pid; SpinLockAcquire(&SlotSyncCtx->mutex); @@ -1601,16 +1707,16 @@ ShutDownSlotSync(void) return; } - worker_pid = SlotSyncCtx->pid; + sync_process_pid = SlotSyncCtx->pid; SpinLockRelease(&SlotSyncCtx->mutex); /* - * Signal slotsync worker if it was still running. The worker will stop - * upon detecting that the stopSignaled flag is set to true. + * Signal process doing slotsync, if any, asking it to stop. */ - if (worker_pid != InvalidPid) - kill(worker_pid, SIGUSR1); + if (sync_process_pid != InvalidPid) + SendProcSignal(sync_process_pid, PROCSIG_SLOTSYNC_MESSAGE, + INVALID_PROC_NUMBER); /* Wait for slot sync to end */ for (;;) @@ -1753,7 +1859,7 @@ SyncReplicationSlots(WalReceiverConn *wrconn) { PG_ENSURE_ERROR_CLEANUP(slotsync_failure_callback, PointerGetDatum(wrconn)); { - check_and_set_sync_info(InvalidPid); + check_and_set_sync_info(MyProcPid); validate_remote_info(wrconn); diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c index 3a076f447ef..70d90699cc6 100644 --- a/src/backend/replication/walsender.c +++ b/src/backend/replication/walsender.c @@ -1858,9 +1858,15 @@ WalSndWaitForWal(XLogRecPtr loc) * If we're shutting down, trigger pending WAL to be written out, * otherwise we'd possibly end up waiting for WAL that never gets * written, because walwriter has shut down already. + * + * Note that GetXLogInsertEndRecPtr() is used to obtain the WAL flush + * request location instead of GetXLogInsertRecPtr(). Because if the + * last WAL record ends at a page boundary, GetXLogInsertRecPtr() can + * return an LSN pointing past the page header, which may cause + * XLogFlush() to report an error. */ - if (got_STOPPING) - XLogBackgroundFlush(); + if (got_STOPPING && !RecoveryInProgress()) + XLogFlush(GetXLogInsertEndRecPtr()); /* * To avoid the scenario where standbys need to catch up to a newer @@ -2427,7 +2433,9 @@ ProcessStandbyReplyMessage(void) TimestampTz now; TimestampTz replyTime; - static bool fullyAppliedLastTime = false; + static XLogRecPtr prevWritePtr = InvalidXLogRecPtr; + static XLogRecPtr prevFlushPtr = InvalidXLogRecPtr; + static XLogRecPtr prevApplyPtr = InvalidXLogRecPtr; /* the caller already consumed the msgtype byte */ writePtr = pq_getmsgint64(&reply_message); @@ -2460,22 +2468,23 @@ ProcessStandbyReplyMessage(void) applyLag = LagTrackerRead(SYNC_REP_WAIT_APPLY, applyPtr, now); /* - * If the standby reports that it has fully replayed the WAL in two - * consecutive reply messages, then the second such message must result - * from wal_receiver_status_interval expiring on the standby. This is a - * convenient time to forget the lag times measured when it last - * wrote/flushed/applied a WAL record, to avoid displaying stale lag data - * until more WAL traffic arrives. + * If the standby reports that it has fully replayed the WAL, and the + * write/flush/apply positions remain unchanged across two consecutive + * reply messages, forget the lag times measured when it last + * wrote/flushed/applied a WAL record. + * + * The second message with unchanged positions typically results from + * wal_receiver_status_interval expiring on the standby, so lag values are + * usually cleared after that interval when there is no activity. This + * avoids displaying stale lag data until more WAL traffic arrives. */ - clearLagTimes = false; - if (applyPtr == sentPtr) - { - if (fullyAppliedLastTime) - clearLagTimes = true; - fullyAppliedLastTime = true; - } - else - fullyAppliedLastTime = false; + clearLagTimes = (applyPtr == sentPtr && flushPtr == sentPtr && + writePtr == prevWritePtr && flushPtr == prevFlushPtr && + applyPtr == prevApplyPtr); + + prevWritePtr = writePtr; + prevFlushPtr = flushPtr; + prevApplyPtr = applyPtr; /* Send a reply if the standby requested one. */ if (replyRequested) diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c index e5a99d6acba..11f11866485 100644 --- a/src/backend/rewrite/rewriteHandler.c +++ b/src/backend/rewrite/rewriteHandler.c @@ -100,8 +100,7 @@ static List *matchLocks(CmdType event, Relation relation, int varno, Query *parsetree, bool *hasUpdate); static Query *fireRIRrules(Query *parsetree, List *activeRIRs); static Bitmapset *adjust_view_column_set(Bitmapset *cols, List *targetlist); -static Node *expand_generated_columns_internal(Node *node, Relation rel, int rt_index, - RangeTblEntry *rte, int result_relation); +static List *get_generated_columns(Relation rel, int rt_index, bool include_stored); /* @@ -644,12 +643,46 @@ rewriteRuleAction(Query *parsetree, if ((event == CMD_INSERT || event == CMD_UPDATE) && sub_action->commandType != CMD_UTILITY) { + RangeTblEntry *new_rte = rt_fetch(new_varno, sub_action->rtable); + Relation new_rel; + List *gen_cols; + + /* + * The target list does not contain entries for generated columns + * (they are removed by rewriteTargetListIU), so we must build entries + * for them here, so that new.gen_col can be rewritten correctly. + */ + new_rel = relation_open(new_rte->relid, NoLock); + gen_cols = get_generated_columns(new_rel, new_varno, true); + relation_close(new_rel, NoLock); + + /* + * The generated column expressions refer to new.attribute, so they + * must be rewritten before they can be used as replacements. + */ + gen_cols = (List *) + ReplaceVarsFromTargetList((Node *) gen_cols, + new_varno, + 0, + new_rte, + parsetree->targetList, + sub_action->resultRelation, + (event == CMD_UPDATE) ? + REPLACEVARS_CHANGE_VARNO : + REPLACEVARS_SUBSTITUTE_NULL, + current_varno, + &sub_action->hasSubLinks); + + /* + * Now rewrite new.attribute in sub_action, using both the target list + * and the rewritten generated column expressions. + */ sub_action = (Query *) ReplaceVarsFromTargetList((Node *) sub_action, new_varno, 0, - rt_fetch(new_varno, sub_action->rtable), - parsetree->targetList, + new_rte, + list_concat(gen_cols, parsetree->targetList), sub_action->resultRelation, (event == CMD_UPDATE) ? REPLACEVARS_CHANGE_VARNO : @@ -2426,18 +2459,50 @@ CopyAndAddInvertedQual(Query *parsetree, ChangeVarNodes(new_qual, PRS2_OLD_VARNO, rt_index, 0); /* Fix references to NEW */ if (event == CMD_INSERT || event == CMD_UPDATE) + { + RangeTblEntry *rte = rt_fetch(rt_index, parsetree->rtable); + Relation rel; + List *gen_cols; + + /* + * As in rewriteRuleAction, build entries for generated columns so + * that new.gen_col in the rule qualification can be rewritten + * correctly. + */ + rel = relation_open(rte->relid, NoLock); + gen_cols = get_generated_columns(rel, PRS2_NEW_VARNO, true); + relation_close(rel, NoLock); + + /* + * The generated column expressions refer to new.attribute, so they + * must be rewritten before they can be used as replacements. + */ + gen_cols = (List *) + ReplaceVarsFromTargetList((Node *) gen_cols, + PRS2_NEW_VARNO, + 0, + rte, + parsetree->targetList, + parsetree->resultRelation, + (event == CMD_UPDATE) ? + REPLACEVARS_CHANGE_VARNO : + REPLACEVARS_SUBSTITUTE_NULL, + rt_index, + &parsetree->hasSubLinks); + new_qual = ReplaceVarsFromTargetList(new_qual, PRS2_NEW_VARNO, 0, - rt_fetch(rt_index, - parsetree->rtable), - parsetree->targetList, + rte, + list_concat(gen_cols, + parsetree->targetList), parsetree->resultRelation, (event == CMD_UPDATE) ? REPLACEVARS_CHANGE_VARNO : REPLACEVARS_SUBSTITUTE_NULL, rt_index, &parsetree->hasSubLinks); + } /* And attach the fixed qual */ AddInvertedQual(parsetree, new_qual); @@ -4527,36 +4592,31 @@ RewriteQuery(Query *parsetree, List *rewrite_events, int orig_rt_length, /* - * Expand virtual generated columns - * - * If the table contains virtual generated columns, build a target list - * containing the expanded expressions and use ReplaceVarsFromTargetList() to - * do the replacements. + * Get a table's generated columns * - * Vars matching rt_index at the current query level are replaced by the - * virtual generated column expressions from rel, if there are any. + * If include_stored is true, both stored and virtual generated columns are + * returned. Otherwise, only virtual generated columns are returned. * - * The caller must also provide rte, the RTE describing the target relation, - * in order to handle any whole-row Vars referencing the target, and - * result_relation, the index of the result relation, if this is part of an - * INSERT/UPDATE/DELETE/MERGE query. + * Returns a list of TargetEntry, one for each generated column, containing + * the attribute numbers and generation expressions. */ -static Node * -expand_generated_columns_internal(Node *node, Relation rel, int rt_index, - RangeTblEntry *rte, int result_relation) +static List * +get_generated_columns(Relation rel, int rt_index, bool include_stored) { + List *gen_cols = NIL; TupleDesc tupdesc; tupdesc = RelationGetDescr(rel); - if (tupdesc->constr && tupdesc->constr->has_generated_virtual) + if (tupdesc->constr && + (tupdesc->constr->has_generated_virtual || + (include_stored && tupdesc->constr->has_generated_stored))) { - List *tlist = NIL; - for (int i = 0; i < tupdesc->natts; i++) { Form_pg_attribute attr = TupleDescAttr(tupdesc, i); - if (attr->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL) + if (attr->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL || + (include_stored && attr->attgenerated == ATTRIBUTE_GENERATED_STORED)) { Node *defexpr; TargetEntry *te; @@ -4565,19 +4625,12 @@ expand_generated_columns_internal(Node *node, Relation rel, int rt_index, ChangeVarNodes(defexpr, 1, rt_index, 0); te = makeTargetEntry((Expr *) defexpr, i + 1, 0, false); - tlist = lappend(tlist, te); + gen_cols = lappend(gen_cols, te); } } - - Assert(list_length(tlist) > 0); - - node = ReplaceVarsFromTargetList(node, rt_index, 0, rte, tlist, - result_relation, - REPLACEVARS_CHANGE_VARNO, rt_index, - NULL); } - return node; + return gen_cols; } /* @@ -4594,6 +4647,7 @@ expand_generated_columns_in_expr(Node *node, Relation rel, int rt_index) if (tupdesc->constr && tupdesc->constr->has_generated_virtual) { RangeTblEntry *rte; + List *vcols; rte = makeNode(RangeTblEntry); /* eref needs to be set, but the actual name doesn't matter */ @@ -4601,14 +4655,26 @@ expand_generated_columns_in_expr(Node *node, Relation rel, int rt_index) rte->rtekind = RTE_RELATION; rte->relid = RelationGetRelid(rel); - node = expand_generated_columns_internal(node, rel, rt_index, rte, 0); + vcols = get_generated_columns(rel, rt_index, false); + + if (vcols) + { + /* + * Passing NULL for outer_hasSubLinks is safe because generation + * expressions cannot contain SubLinks, so the replacement cannot + * introduce any. + */ + node = ReplaceVarsFromTargetList(node, rt_index, 0, rte, vcols, 0, + REPLACEVARS_CHANGE_VARNO, rt_index, + NULL); + } } return node; } /* - * Build the generation expression for the virtual generated column. + * Build the generation expression for a generated column. * * Error out if there is no generation expression found for the given column. */ @@ -4620,8 +4686,11 @@ build_generation_expression(Relation rel, int attrno) Node *defexpr; Oid attcollid; - Assert(rd_att->constr && rd_att->constr->has_generated_virtual); - Assert(att_tup->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL); + Assert(rd_att->constr && + (rd_att->constr->has_generated_virtual || + rd_att->constr->has_generated_stored)); + Assert(att_tup->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL || + att_tup->attgenerated == ATTRIBUTE_GENERATED_STORED); defexpr = build_column_default(rel, attrno); if (defexpr == NULL) diff --git a/src/backend/rewrite/rewriteManip.c b/src/backend/rewrite/rewriteManip.c index 0fcd1fbd14e..2e75f286b8b 100644 --- a/src/backend/rewrite/rewriteManip.c +++ b/src/backend/rewrite/rewriteManip.c @@ -671,7 +671,7 @@ ChangeVarNodes_walker(Node *node, ChangeVarNodes_context *context) * value indicating if the given node should be skipped from further processing * by ChangeVarNodes_walker. The callback is called only for expressions and * other children nodes of a Query processed by a walker. Initial processing - * of the root Query doesn't involve the callback. + * of the root Query node doesn't invoke the callback. */ void ChangeVarNodesExtended(Node *node, int rt_index, int new_index, @@ -736,16 +736,27 @@ ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up) } /* - * ChangeVarNodesWalkExpression - process expression within the custom - * callback provided to the - * ChangeVarNodesExtended. + * ChangeVarNodesWalkExpression - process subexpression within a callback + * function passed to ChangeVarNodesExtended. + * + * This is intended to be used by a callback that needs to recursively + * process subexpressions of some node being visited by an outer + * ChangeVarNodesExtended call, instead of relying on ChangeVarNodes_walker's + * default recursion. We invoke ChangeVarNodes_walker directly rather than + * via expression_tree_walker, because expression_tree_walker only visits + * child nodes and would fail to process the passed node itself -- + * for example, a bare Var node would not get its varno adjusted. + * + * Because this calls ChangeVarNodes_walker directly, if the passed node is + * a Query, it will be treated as a sub-Query: sublevels_up is incremented + * before recursing into it, and Query-level fields (resultRelation, + * mergeTargetRelation, rowMarks, etc.) will not be adjusted. Do not apply + * this to a top-level Query node; use ChangeVarNodesExtended for that. */ bool ChangeVarNodesWalkExpression(Node *node, ChangeVarNodes_context *context) { - return expression_tree_walker(node, - ChangeVarNodes_walker, - (void *) context); + return ChangeVarNodes_walker(node, context); } /* @@ -1502,25 +1513,6 @@ replace_rte_variables_mutator(Node *node, } /* otherwise fall through to copy the var normally */ } - else if (IsA(node, CurrentOfExpr)) - { - CurrentOfExpr *cexpr = (CurrentOfExpr *) node; - - if (cexpr->cvarno == context->target_varno && - context->sublevels_up == 0) - { - /* - * We get here if a WHERE CURRENT OF expression turns out to apply - * to a view. Someday we might be able to translate the - * expression to apply to an underlying table of the view, but - * right now it's not implemented. - */ - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("WHERE CURRENT OF on a view is not implemented"))); - } - /* otherwise fall through to copy the expr normally */ - } else if (IsA(node, Query)) { /* Recurse into RTE subquery or not-yet-planned sublink subquery */ diff --git a/src/backend/statistics/attribute_stats.c b/src/backend/statistics/attribute_stats.c index 38cedaa3263..5c1c5749ad4 100644 --- a/src/backend/statistics/attribute_stats.c +++ b/src/backend/statistics/attribute_stats.c @@ -384,10 +384,27 @@ attribute_statistics_update(FunctionCallInfo fcinfo) if (converted) { - set_stats_slot(values, nulls, replaces, - STATISTIC_KIND_MCV, - eq_opr, atttypcoll, - stanumbers, false, stavalues, false); + ArrayType *vals_arr = DatumGetArrayTypeP(stavalues); + ArrayType *nums_arr = DatumGetArrayTypeP(stanumbers); + int nvals = ARR_DIMS(vals_arr)[0]; + int nnums = ARR_DIMS(nums_arr)[0]; + + if (nvals != nnums) + { + ereport(WARNING, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("could not parse \"%s\": incorrect number of elements (same as \"%s\" required)", + "most_common_vals", + "most_common_freqs"))); + result = false; + } + else + { + set_stats_slot(values, nulls, replaces, + STATISTIC_KIND_MCV, + eq_opr, atttypcoll, + stanumbers, false, stavalues, false); + } } else result = false; @@ -731,6 +748,15 @@ text_to_stavalues(const char *staname, FmgrInfo *array_in, Datum d, Oid typid, return (Datum) 0; } + if (ARR_NDIM(DatumGetArrayTypeP(result)) != 1) + { + ereport(WARNING, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("\"%s\" must be a one-dimensional array", staname))); + *ok = false; + return (Datum) 0; + } + if (array_contains_nulls(DatumGetArrayTypeP(result))) { ereport(WARNING, diff --git a/src/backend/statistics/extended_stats.c b/src/backend/statistics/extended_stats.c index dc04ee63c2e..03349baccfb 100644 --- a/src/backend/statistics/extended_stats.c +++ b/src/backend/statistics/extended_stats.c @@ -736,6 +736,16 @@ lookup_var_attr_stats(Bitmapset *attrs, List *exprs, stats[i] = examine_attribute(expr); + /* + * If the expression has been found as non-analyzable, give up. We + * will not be able to build extended stats with it. + */ + if (stats[i] == NULL) + { + pfree(stats); + return NULL; + } + /* * XXX We need tuple descriptor later, and we just grab it from * stats[0]->tupDesc (see e.g. statext_mcv_build). But as coded @@ -2396,6 +2406,9 @@ serialize_expr_stats(AnlExprData *exprdata, int nexprs) /* * Loads pg_statistic record from expression statistics for expression * identified by the supplied index. + * + * Returns the pg_statistic record found, or NULL if there is no statistics + * data to use. */ HeapTuple statext_expressions_load(Oid stxoid, bool inh, int idx) @@ -2424,6 +2437,13 @@ statext_expressions_load(Oid stxoid, bool inh, int idx) deconstruct_expanded_array(eah); + if (eah->dnulls && eah->dnulls[idx]) + { + /* No data found for this expression, give up. */ + ReleaseSysCache(htup); + return NULL; + } + td = DatumGetHeapTupleHeader(eah->dvalues[idx]); /* Build a temporary HeapTuple control structure */ diff --git a/src/backend/storage/aio/aio_funcs.c b/src/backend/storage/aio/aio_funcs.c index d7977387b8f..75349ab872e 100644 --- a/src/backend/storage/aio/aio_funcs.c +++ b/src/backend/storage/aio/aio_funcs.c @@ -149,7 +149,7 @@ pg_get_aios(PG_FUNCTION_ARGS) if (owner_pid != 0) values[0] = Int32GetDatum(owner_pid); else - nulls[0] = false; + nulls[0] = true; /* column: IO's id */ values[1] = Int32GetDatum(ioh_id); diff --git a/src/backend/storage/aio/read_stream.c b/src/backend/storage/aio/read_stream.c index 031fde9f4cb..6ab2e5a53f4 100644 --- a/src/backend/storage/aio/read_stream.c +++ b/src/backend/storage/aio/read_stream.c @@ -556,10 +556,9 @@ read_stream_begin_impl(int flags, Oid tablespace_id; /* - * Decide how many I/Os we will allow to run at the same time. That - * currently means advice to the kernel to tell it that we will soon read. - * This number also affects how far we look ahead for opportunities to - * start more I/Os. + * Decide how many I/Os we will allow to run at the same time. This + * number also affects how far we look ahead for opportunities to start + * more I/Os. */ tablespace_id = smgr->smgr_rlocator.locator.spcOid; if (!OidIsValid(MyDatabaseId) || diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index 0e87718b028..798e3b78b1f 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -1766,10 +1766,10 @@ AsyncReadBuffers(ReadBuffersOperation *operation, int *nblocks_progress) { Buffer *buffers = &operation->buffers[0]; int flags = operation->flags; - BlockNumber blocknum = operation->blocknum; ForkNumber forknum = operation->forknum; char persistence = operation->persistence; int16 nblocks_done = operation->nblocks_done; + BlockNumber blocknum = operation->blocknum + nblocks_done; Buffer *io_buffers = &operation->buffers[nblocks_done]; int io_buffers_len = 0; PgAioHandle *ioh; @@ -1881,7 +1881,7 @@ AsyncReadBuffers(ReadBuffersOperation *operation, int *nblocks_progress) * must have started out as a miss in PinBufferForBlock(). The other * backend will track this as a 'read'. */ - TRACE_POSTGRESQL_BUFFER_READ_DONE(forknum, blocknum + operation->nblocks_done, + TRACE_POSTGRESQL_BUFFER_READ_DONE(forknum, blocknum, operation->smgr->smgr_rlocator.locator.spcOid, operation->smgr->smgr_rlocator.locator.dbOid, operation->smgr->smgr_rlocator.locator.relNumber, @@ -1953,7 +1953,7 @@ AsyncReadBuffers(ReadBuffersOperation *operation, int *nblocks_progress) */ io_start = pgstat_prepare_io_time(track_io_timing); smgrstartreadv(ioh, operation->smgr, forknum, - blocknum + nblocks_done, + blocknum, io_pages, io_buffers_len); pgstat_count_io_op_time(io_object, io_context, IOOP_READ, io_start, 1, io_buffers_len * BLCKSZ); diff --git a/src/backend/storage/file/fd.c b/src/backend/storage/file/fd.c index 73fa05278a3..378c078c7c7 100644 --- a/src/backend/storage/file/fd.c +++ b/src/backend/storage/file/fd.c @@ -562,7 +562,7 @@ pg_flush_data(int fd, off_t offset, off_t nbytes) { int elevel; - if (rc == EINTR) + if (errno == EINTR) goto retry; /* diff --git a/src/backend/storage/freespace/freespace.c b/src/backend/storage/freespace/freespace.c index 4773a9cc65e..e5ec3829b18 100644 --- a/src/backend/storage/freespace/freespace.c +++ b/src/backend/storage/freespace/freespace.c @@ -231,8 +231,18 @@ XLogRecordPageWithFreeSpace(RelFileLocator rlocator, BlockNumber heapBlk, if (PageIsNew(page)) PageInit(page, BLCKSZ, 0); + /* + * Changes to FSM are usually marked as changed using MarkBufferDirtyHint; + * however, during recovery, it does nothing if checksums are enabled. It + * is assumed that the page should not be dirtied during recovery while + * modifying hints to prevent torn pages, since no new WAL data can be + * generated at this point to store FPI. This is not relevant to the FSM + * case, as its blocks are zeroed when a checksum mismatch occurs. So, we + * need to use regular MarkBufferDirty here to mark the FSM block as + * modified during recovery, otherwise changes to the FSM may be lost. + */ if (fsm_set_avail(page, slot, new_cat)) - MarkBufferDirtyHint(buf, false); + MarkBufferDirty(buf); UnlockReleaseBuffer(buf); } diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c index 087821311cc..05d99b452c3 100644 --- a/src/backend/storage/ipc/procsignal.c +++ b/src/backend/storage/ipc/procsignal.c @@ -23,6 +23,7 @@ #include "pgstat.h" #include "port/pg_bitutils.h" #include "replication/logicalworker.h" +#include "replication/slotsync.h" #include "replication/walsender.h" #include "storage/condition_variable.h" #include "storage/ipc.h" @@ -694,6 +695,9 @@ procsignal_sigusr1_handler(SIGNAL_ARGS) if (CheckProcSignal(PROCSIG_PARALLEL_APPLY_MESSAGE)) HandleParallelApplyMessageInterrupt(); + if (CheckProcSignal(PROCSIG_SLOTSYNC_MESSAGE)) + HandleSlotSyncMessageInterrupt(); + if (CheckProcSignal(PROCSIG_RECOVERY_CONFLICT_DATABASE)) HandleRecoveryConflictInterrupt(PROCSIG_RECOVERY_CONFLICT_DATABASE); diff --git a/src/backend/storage/ipc/shmem.c b/src/backend/storage/ipc/shmem.c index 21e12e2f527..df48d1f78e9 100644 --- a/src/backend/storage/ipc/shmem.c +++ b/src/backend/storage/ipc/shmem.c @@ -486,42 +486,6 @@ ShmemInitStruct(const char *name, Size size, bool *foundPtr) } -/* - * Add two Size values, checking for overflow - */ -Size -add_size(Size s1, Size s2) -{ - Size result; - - result = s1 + s2; - /* We are assuming Size is an unsigned type here... */ - if (result < s1 || result < s2) - ereport(ERROR, - (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), - errmsg("requested shared memory size overflows size_t"))); - return result; -} - -/* - * Multiply two Size values, checking for overflow - */ -Size -mul_size(Size s1, Size s2) -{ - Size result; - - if (s1 == 0 || s2 == 0) - return 0; - result = s1 * s2; - /* We are assuming Size is an unsigned type here... */ - if (result / s2 != s1) - ereport(ERROR, - (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), - errmsg("requested shared memory size overflows size_t"))); - return result; -} - /* SQL SRF showing allocated shared memory */ Datum pg_get_shmem_allocations(PG_FUNCTION_ARGS) diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c index fc0288a9622..0fcf6583736 100644 --- a/src/backend/storage/lmgr/proc.c +++ b/src/backend/storage/lmgr/proc.c @@ -310,7 +310,7 @@ InitProcGlobal(void) * dummy PGPROCs don't need these though - they're never associated * with a real process */ - if (i < MaxBackends + NUM_AUXILIARY_PROCS) + if (i < FIRST_PREPARED_XACT_PROC_NUMBER) { proc->sem = PGSemaphoreCreate(); InitSharedLatch(&(proc->procLatch)); @@ -375,7 +375,7 @@ InitProcGlobal(void) * processes and prepared transactions. */ AuxiliaryProcs = &procs[MaxBackends]; - PreparedXactProcs = &procs[MaxBackends + NUM_AUXILIARY_PROCS]; + PreparedXactProcs = &procs[FIRST_PREPARED_XACT_PROC_NUMBER]; /* Create ProcStructLock spinlock, too */ ProcStructLock = (slock_t *) ShmemInitStruct("ProcStructLock spinlock", @@ -1723,7 +1723,7 @@ ProcWakeup(PGPROC *proc, ProcWaitStatus waitStatus) proc->waitLock = NULL; proc->waitProcLock = NULL; proc->waitStatus = waitStatus; - pg_atomic_write_u64(&MyProc->waitStart, 0); + pg_atomic_write_u64(&proc->waitStart, 0); /* And awaken it */ SetLatch(&proc->procLatch); diff --git a/src/backend/tcop/backend_startup.c b/src/backend/tcop/backend_startup.c index 7667f1b2f21..c73153d54d7 100644 --- a/src/backend/tcop/backend_startup.c +++ b/src/backend/tcop/backend_startup.c @@ -548,6 +548,7 @@ ProcessStartupPacket(Port *port, bool ssl_done, bool gss_done) ProtocolVersion proto; MemoryContext oldcontext; +retry: pq_startmsgread(); /* @@ -684,7 +685,16 @@ ProcessStartupPacket(Port *port, bool ssl_done, bool gss_done) * another SSL negotiation request, and a GSS request should only * follow if SSL was rejected (client may negotiate in either order) */ - return ProcessStartupPacket(port, true, SSLok == 'S'); + ssl_done = true; + if (SSLok == 'S') + { + /* + * We are done with SSL and negotiated correctly, so consider the + * same for GSS. + */ + gss_done = true; + } + goto retry; } else if (proto == NEGOTIATE_GSS_CODE && !gss_done) { @@ -738,7 +748,16 @@ ProcessStartupPacket(Port *port, bool ssl_done, bool gss_done) * another GSS negotiation request, and an SSL request should only * follow if GSS was rejected (client may negotiate in either order) */ - return ProcessStartupPacket(port, GSSok == 'G', true); + gss_done = true; + if (GSSok == 'G') + { + /* + * We are done with GSS and negotiated correctly, so consider the + * same for SSL. + */ + ssl_done = true; + } + goto retry; } /* Could add additional special packet types here */ diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index ce2e928b2fb..57a2c92ec4c 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -58,6 +58,7 @@ #include "postmaster/postmaster.h" #include "replication/logicallauncher.h" #include "replication/logicalworker.h" +#include "replication/slotsync.h" #include "replication/slot.h" #include "replication/walsender.h" #include "rewrite/rewriteHandler.h" @@ -3742,6 +3743,9 @@ ProcessInterrupts(void) if (ParallelApplyMessagePending) ProcessParallelApplyMessages(); + + if (SlotSyncShutdownPending) + ProcessSlotSyncMessage(); } /* diff --git a/src/backend/tsearch/spell.c b/src/backend/tsearch/spell.c index 0b9ac2e1179..7f8c677a438 100644 --- a/src/backend/tsearch/spell.c +++ b/src/backend/tsearch/spell.c @@ -909,14 +909,20 @@ parse_ooaffentry(char *str, char *type, char *flag, char *find, * * An .affix file entry has the following format: * > [-,] + * + * Output buffers mask, find, repl must be of length BUFSIZ; + * we truncate the input to fit. */ static bool -parse_affentry(char *str, char *mask, char *find, char *repl) +parse_affentry(const char *str, char *mask, char *find, char *repl) { int state = PAE_WAIT_MASK; char *pmask = mask, *pfind = find, *prepl = repl; + char *emask = mask + BUFSIZ; + char *efind = find + BUFSIZ; + char *erepl = repl + BUFSIZ; *mask = *find = *repl = '\0'; @@ -930,7 +936,8 @@ parse_affentry(char *str, char *mask, char *find, char *repl) return false; else if (!isspace((unsigned char) *str)) { - pmask += ts_copychar_with_len(pmask, str, clen); + if (pmask < emask - clen) + pmask += ts_copychar_with_len(pmask, str, clen); state = PAE_INMASK; } } @@ -943,7 +950,8 @@ parse_affentry(char *str, char *mask, char *find, char *repl) } else if (!isspace((unsigned char) *str)) { - pmask += ts_copychar_with_len(pmask, str, clen); + if (pmask < emask - clen) + pmask += ts_copychar_with_len(pmask, str, clen); } } else if (state == PAE_WAIT_FIND) @@ -954,7 +962,8 @@ parse_affentry(char *str, char *mask, char *find, char *repl) } else if (t_isalpha_cstr(str) || t_iseq(str, '\'') /* english 's */ ) { - prepl += ts_copychar_with_len(prepl, str, clen); + if (prepl < erepl - clen) + prepl += ts_copychar_with_len(prepl, str, clen); state = PAE_INREPL; } else if (!isspace((unsigned char) *str)) @@ -971,7 +980,8 @@ parse_affentry(char *str, char *mask, char *find, char *repl) } else if (t_isalpha_cstr(str)) { - pfind += ts_copychar_with_len(pfind, str, clen); + if (pfind < efind - clen) + pfind += ts_copychar_with_len(pfind, str, clen); } else if (!isspace((unsigned char) *str)) ereport(ERROR, @@ -986,7 +996,8 @@ parse_affentry(char *str, char *mask, char *find, char *repl) } else if (t_isalpha_cstr(str)) { - prepl += ts_copychar_with_len(prepl, str, clen); + if (prepl < erepl - clen) + prepl += ts_copychar_with_len(prepl, str, clen); state = PAE_INREPL; } else if (!isspace((unsigned char) *str)) @@ -1003,7 +1014,8 @@ parse_affentry(char *str, char *mask, char *find, char *repl) } else if (t_isalpha_cstr(str)) { - prepl += ts_copychar_with_len(prepl, str, clen); + if (prepl < erepl - clen) + prepl += ts_copychar_with_len(prepl, str, clen); } else if (!isspace((unsigned char) *str)) ereport(ERROR, @@ -1061,7 +1073,7 @@ setCompoundAffixFlagValue(IspellDict *Conf, CompoundAffixFlag *entry, * val: affix parameter. */ static void -addCompoundAffixFlagValue(IspellDict *Conf, char *s, uint32 val) +addCompoundAffixFlagValue(IspellDict *Conf, const char *s, uint32 val) { CompoundAffixFlag *newValue; char sbuf[BUFSIZ]; @@ -1079,9 +1091,11 @@ addCompoundAffixFlagValue(IspellDict *Conf, char *s, uint32 val) sflag = sbuf; while (*s && !isspace((unsigned char) *s) && *s != '\n') { - int clen = ts_copychar_cstr(sflag, s); + int clen = pg_mblen_cstr(s); - sflag += clen; + /* Truncate the input to fit in BUFSIZ */ + if (sflag < sbuf + BUFSIZ - clen) + sflag += ts_copychar_with_len(sflag, s, clen); s += clen; } *sflag = '\0'; @@ -2065,9 +2079,32 @@ FindAffixes(AffixNode *node, const char *word, int wrdlen, int *level, int type) return NULL; } +/* + * Checks to see if affix applies to word, transforms word if so. + * The transformation consists of replacing Affix->replen leading or + * trailing bytes with the Affix->find string. + * + * word: input word + * len: length of input word + * Affix: affix to consider + * flagflags: context flags showing whether we are handling a compound word + * newword: output buffer (MUST be of length 2 * MAXNORMLEN) + * baselen: input/output argument + * + * If baselen isn't NULL, then *baselen is used to return the length of + * the non-changed part of the word when applying a suffix, and is used + * to detect whether the input contained only a prefix and suffix when + * later applying a prefix. + * + * Returns newword on success, or NULL if the affix can't be applied. + * On success, the modified word is stored into newword. + */ static char * CheckAffix(const char *word, size_t len, AFFIX *Affix, int flagflags, char *newword, int *baselen) { + size_t keeplen, + findlen; + /* * Check compound allow flags */ @@ -2100,15 +2137,27 @@ CheckAffix(const char *word, size_t len, AFFIX *Affix, int flagflags, char *neww return NULL; } + /* + * Protect against output buffer overrun (len < Affix->replen would be + * caller error, but check anyway) + */ + Assert(len == strlen(word)); + if (len < Affix->replen) + return NULL; + keeplen = len - Affix->replen; /* how much of word we will keep */ + findlen = strlen(Affix->find); + if (keeplen + findlen >= 2 * MAXNORMLEN) + return NULL; + /* * make replace pattern of affix */ if (Affix->type == FF_SUFFIX) { - strcpy(newword, word); - strcpy(newword + len - Affix->replen, Affix->find); + memcpy(newword, word, keeplen); + strcpy(newword + keeplen, Affix->find); if (baselen) /* store length of non-changed part of word */ - *baselen = len - Affix->replen; + *baselen = keeplen; } else { @@ -2116,10 +2165,10 @@ CheckAffix(const char *word, size_t len, AFFIX *Affix, int flagflags, char *neww * if prefix is an all non-changed part's length then all word * contains only prefix and suffix, so out */ - if (baselen && *baselen + strlen(Affix->find) <= Affix->replen) + if (baselen && *baselen + findlen <= Affix->replen) return NULL; - strcpy(newword, Affix->find); - strcat(newword, word + Affix->replen); + memcpy(newword, Affix->find, findlen); + strcpy(newword + findlen, word + Affix->replen); } /* @@ -2313,7 +2362,7 @@ CheckCompoundAffixes(CMPDAffix **ptr, const char *word, int len, bool CheckInPla } else { - char *affbegin; + const char *affbegin; while ((*ptr)->affix) { diff --git a/src/backend/tsearch/wparser_def.c b/src/backend/tsearch/wparser_def.c index 62c773179d6..471c452ec48 100644 --- a/src/backend/tsearch/wparser_def.c +++ b/src/backend/tsearch/wparser_def.c @@ -2628,6 +2628,9 @@ prsd_headline(PG_FUNCTION_ARGS) int max_fragments = 0; bool highlightall = false; ListCell *l; + size_t startsellen; + size_t stopsellen; + size_t fragdelimlen; /* Extract configuration option values */ prs->startsel = NULL; @@ -2717,9 +2720,24 @@ prsd_headline(PG_FUNCTION_ARGS) prs->fragdelim = pstrdup(" ... "); /* Caller will need these lengths, too */ - prs->startsellen = strlen(prs->startsel); - prs->stopsellen = strlen(prs->stopsel); - prs->fragdelimlen = strlen(prs->fragdelim); + startsellen = strlen(prs->startsel); + stopsellen = strlen(prs->stopsel); + fragdelimlen = strlen(prs->fragdelim); + if (startsellen > PG_INT16_MAX) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("value for \"%s\" is too long", "StartSel"))); + if (stopsellen > PG_INT16_MAX) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("value for \"%s\" is too long", "StopSel"))); + if (fragdelimlen > PG_INT16_MAX) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("value for \"%s\" is too long", "FragmentDelimiter"))); + prs->startsellen = startsellen; + prs->stopsellen = stopsellen; + prs->fragdelimlen = fragdelimlen; PG_RETURN_POINTER(prs); } diff --git a/src/backend/utils/activity/pgstat_database.c b/src/backend/utils/activity/pgstat_database.c index 2f83b9e333d..9f1a8633b4b 100644 --- a/src/backend/utils/activity/pgstat_database.c +++ b/src/backend/utils/activity/pgstat_database.c @@ -233,7 +233,7 @@ pgstat_report_connect(Oid dboid) pgLastSessionReportTime = MyStartTimestamp; - dbentry = pgstat_prep_database_pending(MyDatabaseId); + dbentry = pgstat_prep_database_pending(dboid); dbentry->sessions++; } @@ -248,7 +248,7 @@ pgstat_report_disconnect(Oid dboid) if (!pgstat_should_report_connstat()) return; - dbentry = pgstat_prep_database_pending(MyDatabaseId); + dbentry = pgstat_prep_database_pending(dboid); switch (pgStatSessionEndCause) { @@ -409,7 +409,7 @@ pgstat_reset_database_timestamp(Oid dboid, TimestampTz ts) PgStat_EntryRef *dbref; PgStatShared_Database *dbentry; - dbref = pgstat_get_entry_ref_locked(PGSTAT_KIND_DATABASE, MyDatabaseId, InvalidOid, + dbref = pgstat_get_entry_ref_locked(PGSTAT_KIND_DATABASE, dboid, InvalidOid, false); dbentry = (PgStatShared_Database *) dbref->shared_stats; diff --git a/src/backend/utils/activity/pgstat_shmem.c b/src/backend/utils/activity/pgstat_shmem.c index cd4476e7f06..ef876ad0376 100644 --- a/src/backend/utils/activity/pgstat_shmem.c +++ b/src/backend/utils/activity/pgstat_shmem.c @@ -142,8 +142,7 @@ StatsShmemSize(void) continue; Assert(kind_info->shared_size != 0); - - sz += MAXALIGN(kind_info->shared_size); + sz = add_size(sz, MAXALIGN(kind_info->shared_size)); } return sz; @@ -227,7 +226,8 @@ StatsShmemInit(void) int idx = kind - PGSTAT_KIND_CUSTOM_MIN; Assert(kind_info->shared_size != 0); - ctl->custom_data[idx] = ShmemAlloc(kind_info->shared_size); + ctl->custom_data[idx] = p; + p += MAXALIGN(kind_info->shared_size); ptr = ctl->custom_data[idx]; } diff --git a/src/backend/utils/adt/array_userfuncs.c b/src/backend/utils/adt/array_userfuncs.c index 8eb342e3382..f2d588fd4a3 100644 --- a/src/backend/utils/adt/array_userfuncs.c +++ b/src/backend/utils/adt/array_userfuncs.c @@ -24,6 +24,7 @@ #include "utils/builtins.h" #include "utils/datum.h" #include "utils/lsyscache.h" +#include "utils/memutils.h" #include "utils/tuplesort.h" #include "utils/typcache.h" @@ -1033,10 +1034,11 @@ array_agg_array_combine(PG_FUNCTION_ARGS) } /* We only need to combine the two states if state2 has any items */ - else if (state2->nitems > 0) + if (state2->nitems > 0) { MemoryContext oldContext; - int reqsize = state1->nbytes + state2->nbytes; + int reqsize; + int newnitems; int i; /* @@ -1059,6 +1061,17 @@ array_agg_array_combine(PG_FUNCTION_ARGS) errmsg("cannot accumulate arrays of different dimensionality"))); } + /* Types should match already. */ + Assert(state1->array_type == state2->array_type); + Assert(state1->element_type == state2->element_type); + + /* Calculate new sizes, guarding against overflow. */ + if (pg_add_s32_overflow(state1->nbytes, state2->nbytes, &reqsize) || + pg_add_s32_overflow(state1->nitems, state2->nitems, &newnitems)) + ereport(ERROR, + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), + errmsg("array size exceeds the maximum allowed (%zu)", + MaxArraySize))); oldContext = MemoryContextSwitchTo(state1->mcontext); @@ -1073,17 +1086,16 @@ array_agg_array_combine(PG_FUNCTION_ARGS) state1->data = (char *) repalloc(state1->data, state1->abytes); } - if (state2->nullbitmap) + /* Combine the null bitmaps, if present. */ + if (state1->nullbitmap || state2->nullbitmap) { - int newnitems = state1->nitems + state2->nitems; - if (state1->nullbitmap == NULL) { /* * First input with nulls; we must retrospectively handle any * previous inputs by marking all their items non-null. */ - state1->aitems = pg_nextpower2_32(Max(256, newnitems + 1)); + state1->aitems = pg_nextpower2_32(Max(256, newnitems)); state1->nullbitmap = (bits8 *) palloc((state1->aitems + 7) / 8); array_bitmap_copy(state1->nullbitmap, 0, NULL, 0, @@ -1091,17 +1103,17 @@ array_agg_array_combine(PG_FUNCTION_ARGS) } else if (newnitems > state1->aitems) { - int newaitems = state1->aitems + state2->aitems; - - state1->aitems = pg_nextpower2_32(newaitems); + state1->aitems = pg_nextpower2_32(newnitems); state1->nullbitmap = (bits8 *) repalloc(state1->nullbitmap, (state1->aitems + 7) / 8); } + /* This will do the right thing if state2->nullbitmap is NULL: */ array_bitmap_copy(state1->nullbitmap, state1->nitems, state2->nullbitmap, 0, state2->nitems); } + /* Finally, combine the data and adjust sizes. */ memcpy(state1->data + state1->nbytes, state2->data, state2->nbytes); state1->nbytes += state2->nbytes; state1->nitems += state2->nitems; @@ -1109,9 +1121,6 @@ array_agg_array_combine(PG_FUNCTION_ARGS) state1->dims[0] += state2->dims[0]; /* remaining dims already match, per test above */ - Assert(state1->array_type == state2->array_type); - Assert(state1->element_type == state2->element_type); - MemoryContextSwitchTo(oldContext); } diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c index 7f1fef9874d..760f2427d40 100644 --- a/src/backend/utils/adt/arrayfuncs.c +++ b/src/backend/utils/adt/arrayfuncs.c @@ -5587,6 +5587,7 @@ accumArrayResultArr(ArrayBuildStateArr *astate, ndatabytes; char *data; int i; + int newnitems; /* * We disallow accumulating null subarrays. Another plausible definition @@ -5616,6 +5617,14 @@ accumArrayResultArr(ArrayBuildStateArr *astate, nitems = ArrayGetNItems(ndims, dims); ndatabytes = ARR_SIZE(arg) - ARR_DATA_OFFSET(arg); + /* Check that the array doesn't grow too large */ + newnitems = astate->nitems + nitems; + if (newnitems > MaxArraySize) + ereport(ERROR, + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), + errmsg("array size exceeds the maximum allowed (%zu)", + MaxArraySize))); + if (astate->ndims == 0) { /* First input; check/save the dimensionality info */ @@ -5681,8 +5690,6 @@ accumArrayResultArr(ArrayBuildStateArr *astate, /* Deal with null bitmap if needed */ if (astate->nullbitmap || ARR_HASNULL(arg)) { - int newnitems = astate->nitems + nitems; - if (astate->nullbitmap == NULL) { /* @@ -5706,7 +5713,7 @@ accumArrayResultArr(ArrayBuildStateArr *astate, nitems); } - astate->nitems += nitems; + astate->nitems = newnitems; astate->dims[0] += 1; MemoryContextSwitchTo(oldcontext); diff --git a/src/backend/utils/adt/datum.c b/src/backend/utils/adt/datum.c index fcd5b1653dd..5aab1edb7bc 100644 --- a/src/backend/utils/adt/datum.c +++ b/src/backend/utils/adt/datum.c @@ -258,8 +258,13 @@ datumIsEqual(Datum value1, Datum value2, bool typByVal, int typLen) /*------------------------------------------------------------------------- * datum_image_eq * - * Compares two datums for identical contents, based on byte images. Return - * true if the two datums are equal, false otherwise. + * Compares two datums for identical contents when coerced to a signed integer + * of typLen bytes. Return true if the two datums are equal, false otherwise. + * + * The coercion is required as we're not always careful to use the correct + * PG_RETURN_* macro. If we didn't do this, a Datum that's been formed and + * deformed into a tuple may not have the same signed representation as the + * other datum value. *------------------------------------------------------------------------- */ bool @@ -271,7 +276,21 @@ datum_image_eq(Datum value1, Datum value2, bool typByVal, int typLen) if (typByVal) { - result = (value1 == value2); + switch (typLen) + { + case sizeof(char): + result = (DatumGetChar(value1) == DatumGetChar(value2)); + break; + case sizeof(int16): + result = (DatumGetInt16(value1) == DatumGetInt16(value2)); + break; + case sizeof(int32): + result = (DatumGetInt32(value1) == DatumGetInt32(value2)); + break; + default: + result = (value1 == value2); + break; + } } else if (typLen > 0) { @@ -328,10 +347,11 @@ datum_image_eq(Datum value1, Datum value2, bool typByVal, int typLen) /*------------------------------------------------------------------------- * datum_image_hash * - * Generate a hash value based on the binary representation of 'value'. Most - * use cases will want to use the hash function specific to the Datum's type, - * however, some corner cases require generating a hash value based on the - * actual bits rather than the logical value. + * Generate a hash value based on the binary representation of 'value' when + * represented as a signed integer of typLen bytes. Most use cases will want + * to use the hash function specific to the Datum's type, however, some corner + * cases require generating a hash value based on the actual bits rather than + * the logical value. *------------------------------------------------------------------------- */ uint32 @@ -341,7 +361,23 @@ datum_image_hash(Datum value, bool typByVal, int typLen) uint32 result; if (typByVal) + { + switch (typLen) + { + case sizeof(char): + value = CharGetDatum(DatumGetChar(value)); + break; + case sizeof(int16): + value = Int16GetDatum(DatumGetInt16(value)); + break; + case sizeof(int32): + value = Int32GetDatum(DatumGetInt32(value)); + break; + /* Nothing needs done for 64-bit types */ + } + result = hash_bytes((unsigned char *) &value, sizeof(Datum)); + } else if (typLen > 0) result = hash_bytes((unsigned char *) DatumGetPointer(value), typLen); else if (typLen == -1) diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.c index 8da5169c6f4..19c9225b091 100644 --- a/src/backend/utils/adt/formatting.c +++ b/src/backend/utils/adt/formatting.c @@ -1039,8 +1039,9 @@ typedef struct NUMProc char *number, /* string with number */ *number_p, /* pointer to current number position */ *inout, /* in / out buffer */ - *inout_p, /* pointer to current inout position */ - *last_relevant, /* last relevant number after decimal point */ + *inout_p; /* pointer to current inout position */ + + const char *last_relevant, /* last relevant number after decimal point */ *L_negative_sign, /* Locale */ *L_positive_sign, @@ -1116,6 +1117,7 @@ static void NUM_prepare_locale(NUMProc *Np); static char *get_last_relevant_decnum(char *num); static void NUM_numpart_from_char(NUMProc *Np, int id, int input_len); static void NUM_numpart_to_char(NUMProc *Np, int id); +static void NUM_add_locale_symbol(NUMProc *Np, const char *pattern); static char *NUM_processor(FormatNode *node, NUMDesc *Num, char *inout, char *number, int input_len, int to_char_out_pre_spaces, int sign, bool is_to_char, Oid collid); @@ -4577,7 +4579,7 @@ datetime_to_char_body(TmToChar *tmtc, text *fmt, bool is_interval, Oid collid) /* * Allocate workspace for result as C string */ - result = palloc((fmt_len * DCH_MAX_ITEM_SIZ) + 1); + result = palloc(mul_size(fmt_len, DCH_MAX_ITEM_SIZ) + 1); *result = '\0'; if (fmt_len > DCH_CACHE_SIZE) @@ -4588,7 +4590,7 @@ datetime_to_char_body(TmToChar *tmtc, text *fmt, bool is_interval, Oid collid) */ incache = false; - format = (FormatNode *) palloc((fmt_len + 1) * sizeof(FormatNode)); + format = palloc_array(FormatNode, fmt_len + 1); parse_format(format, fmt_str, DCH_keywords, DCH_suff, DCH_index, DCH_FLAG, NULL); @@ -5027,7 +5029,7 @@ datetime_format_has_tz(const char *fmt_str) */ incache = false; - format = (FormatNode *) palloc((fmt_len + 1) * sizeof(FormatNode)); + format = palloc_array(FormatNode, fmt_len + 1); parse_format(format, fmt_str, DCH_keywords, DCH_suff, DCH_index, DCH_FLAG, NULL); @@ -5115,7 +5117,7 @@ do_to_timestamp(text *date_txt, text *fmt, Oid collid, bool std, * Allocate new memory if format picture is bigger than static * cache and do not use cache (call parser always) */ - format = (FormatNode *) palloc((fmt_len + 1) * sizeof(FormatNode)); + format = palloc_array(FormatNode, fmt_len + 1); parse_format(format, fmt_str, DCH_keywords, DCH_suff, DCH_index, DCH_FLAG | (std ? STD_FLAG : 0), NULL); @@ -6091,7 +6093,7 @@ NUM_cache(int len, NUMDesc *Num, text *pars_str, bool *shouldFree) * Allocate new memory if format picture is bigger than static cache * and do not use cache (call parser always) */ - format = (FormatNode *) palloc((len + 1) * sizeof(FormatNode)); + format = palloc_array(FormatNode, len + 1); *shouldFree = true; @@ -6712,11 +6714,9 @@ NUM_numpart_to_char(NUMProc *Np, int id) { if (Np->Num->lsign == NUM_LSIGN_PRE) { - if (Np->sign == '-') - strcpy(Np->inout_p, Np->L_negative_sign); - else - strcpy(Np->inout_p, Np->L_positive_sign); - Np->inout_p += strlen(Np->inout_p); + NUM_add_locale_symbol(Np, (Np->sign == '-') ? + Np->L_negative_sign : + Np->L_positive_sign); Np->sign_wrote = true; } } @@ -6781,8 +6781,7 @@ NUM_numpart_to_char(NUMProc *Np, int id) { if (!Np->last_relevant || *Np->last_relevant != '.') { - strcpy(Np->inout_p, Np->decimal); /* Write DEC/D */ - Np->inout_p += strlen(Np->inout_p); + NUM_add_locale_symbol(Np, Np->decimal); /* Write DEC/D */ } /* @@ -6791,8 +6790,7 @@ NUM_numpart_to_char(NUMProc *Np, int id) else if (IS_FILLMODE(Np->Num) && Np->last_relevant && *Np->last_relevant == '.') { - strcpy(Np->inout_p, Np->decimal); /* Write DEC/D */ - Np->inout_p += strlen(Np->inout_p); + NUM_add_locale_symbol(Np, Np->decimal); /* Write DEC/D */ } } else @@ -6850,11 +6848,9 @@ NUM_numpart_to_char(NUMProc *Np, int id) } else if (IS_LSIGN(Np->Num) && Np->Num->lsign == NUM_LSIGN_POST) { - if (Np->sign == '-') - strcpy(Np->inout_p, Np->L_negative_sign); - else - strcpy(Np->inout_p, Np->L_positive_sign); - Np->inout_p += strlen(Np->inout_p); + NUM_add_locale_symbol(Np, (Np->sign == '-') ? + Np->L_negative_sign : + Np->L_positive_sign); } } } @@ -6862,6 +6858,23 @@ NUM_numpart_to_char(NUMProc *Np, int id) ++Np->num_curr; } +/* + * Append locale-specific symbol to Np->inout. + * Note we don't null-terminate the output + */ +static void +NUM_add_locale_symbol(NUMProc *Np, const char *pattern) +{ + size_t pattern_len = strlen(pattern); + + /* Truncate symbol if it's potentially too long */ + if (unlikely(pattern_len > NUM_MAX_ITEM_SIZ)) + pattern_len = pg_mbcliplen(pattern, pattern_len, + NUM_MAX_ITEM_SIZ); + memcpy(Np->inout_p, pattern, pattern_len); + Np->inout_p += pattern_len; +} + /* * Skip over "n" input characters, but only if they aren't numeric data */ @@ -7771,6 +7784,10 @@ NUM_processor(FormatNode *node, NUMDesc *Num, char *inout, pattern_len = strlen(pattern); if (Np->is_to_char) { + /* Truncate symbol if it's potentially too long */ + if (unlikely(pattern_len > NUM_MAX_ITEM_SIZ)) + pattern_len = pg_mbcliplen(pattern, pattern_len, + NUM_MAX_ITEM_SIZ); if (!Np->num_in) { if (IS_FILLMODE(Np->Num)) @@ -7778,19 +7795,21 @@ NUM_processor(FormatNode *node, NUMDesc *Num, char *inout, else { /* just in case there are MB chars */ - pattern_len = pg_mbstrlen(pattern); + pattern_len = pg_mbstrlen_with_len(pattern, + pattern_len); memset(Np->inout_p, ' ', pattern_len); Np->inout_p += pattern_len - 1; } } else { - strcpy(Np->inout_p, pattern); + memcpy(Np->inout_p, pattern, pattern_len); Np->inout_p += pattern_len - 1; } } else { + /* Here we do not truncate the symbol ... */ if (!Np->num_in) { if (IS_FILLMODE(Np->Num)) @@ -7815,11 +7834,18 @@ NUM_processor(FormatNode *node, NUMDesc *Num, char *inout, pattern = Np->L_currency_symbol; if (Np->is_to_char) { - strcpy(Np->inout_p, pattern); - Np->inout_p += strlen(pattern) - 1; + /* Truncate symbol if it's potentially too long */ + pattern_len = strlen(pattern); + if (unlikely(pattern_len > NUM_MAX_ITEM_SIZ)) + pattern_len = pg_mbcliplen(pattern, pattern_len, + NUM_MAX_ITEM_SIZ); + + memcpy(Np->inout_p, pattern, pattern_len); + Np->inout_p += pattern_len - 1; } else { + /* Here we do not truncate the symbol ... */ NUM_eat_non_data_chars(Np, pg_mbstrlen(pattern), input_len); continue; } diff --git a/src/backend/utils/adt/jsonpath_exec.c b/src/backend/utils/adt/jsonpath_exec.c index 9673d29b905..9bd3d119060 100644 --- a/src/backend/utils/adt/jsonpath_exec.c +++ b/src/backend/utils/adt/jsonpath_exec.c @@ -4419,7 +4419,7 @@ JsonTablePlanJoinNextRow(JsonTablePlanState *planstate) */ if (!JsonTablePlanNextRow(planstate->right)) { - /* Right sibling ran out of row, so there are more rows. */ + /* Right sibling ran out of rows too, so there are no more rows. */ return false; } } diff --git a/src/backend/utils/adt/multirangetypes.c b/src/backend/utils/adt/multirangetypes.c index 943961fe0ec..6aedf646c9b 100644 --- a/src/backend/utils/adt/multirangetypes.c +++ b/src/backend/utils/adt/multirangetypes.c @@ -340,7 +340,7 @@ multirange_recv(PG_FUNCTION_ARGS) Oid mltrngtypoid = PG_GETARG_OID(1); int32 typmod = PG_GETARG_INT32(2); MultirangeIOData *cache; - uint32 range_count; + int32 range_count; RangeType **ranges; MultirangeType *ret; StringInfoData tmpbuf; @@ -348,7 +348,8 @@ multirange_recv(PG_FUNCTION_ARGS) cache = get_multirange_io_data(fcinfo, mltrngtypoid, IOFunc_receive); range_count = pq_getmsgint(buf, 4); - ranges = palloc(range_count * sizeof(RangeType *)); + /* palloc_array will enforce a more-or-less-sane range_count value */ + ranges = palloc_array(RangeType *, range_count); initStringInfo(&tmpbuf); for (int i = 0; i < range_count; i++) @@ -835,7 +836,7 @@ multirange_deserialize(TypeCacheEntry *rangetyp, { int i; - *ranges = palloc(*range_count * sizeof(RangeType *)); + *ranges = palloc_array(RangeType *, *range_count); for (i = 0; i < *range_count; i++) (*ranges)[i] = multirange_get_range(rangetyp, multirange, i); } @@ -999,7 +1000,7 @@ multirange_constructor2(PG_FUNCTION_ARGS) deconstruct_array(rangeArray, rngtypid, rangetyp->typlen, rangetyp->typbyval, rangetyp->typalign, &elements, &nulls, &range_count); - ranges = palloc0(range_count * sizeof(RangeType *)); + ranges = palloc_array(RangeType *, range_count); for (i = 0; i < range_count; i++) { if (nulls[i]) diff --git a/src/backend/utils/adt/pg_locale.c b/src/backend/utils/adt/pg_locale.c index 493a93ed4c6..477b67aa62a 100644 --- a/src/backend/utils/adt/pg_locale.c +++ b/src/backend/utils/adt/pg_locale.c @@ -982,7 +982,7 @@ get_iso_localename(const char *winlocname) wchar_t wc_locale_name[LOCALE_NAME_MAX_LENGTH]; wchar_t buffer[LOCALE_NAME_MAX_LENGTH]; static char iso_lc_messages[LOCALE_NAME_MAX_LENGTH]; - char *period; + const char *period; int len; int ret_val; diff --git a/src/backend/utils/adt/pg_locale_builtin.c b/src/backend/utils/adt/pg_locale_builtin.c index f51768830cd..df5612b5a2d 100644 --- a/src/backend/utils/adt/pg_locale_builtin.c +++ b/src/backend/utils/adt/pg_locale_builtin.c @@ -91,7 +91,7 @@ strtitle_builtin(char *dest, size_t destsize, const char *src, ssize_t srclen, { struct WordBoundaryState wbstate = { .str = src, - .len = srclen, + .len = (srclen < 0) ? strlen(src) : srclen, .offset = 0, .posix = !locale->info.builtin.casemap_full, .init = false, diff --git a/src/backend/utils/adt/pg_locale_icu.c b/src/backend/utils/adt/pg_locale_icu.c index a32c32a0744..72c5fffa204 100644 --- a/src/backend/utils/adt/pg_locale_icu.c +++ b/src/backend/utils/adt/pg_locale_icu.c @@ -95,8 +95,8 @@ static size_t strnxfrm_prefix_icu_utf8(char *dest, size_t destsize, const char *src, ssize_t srclen, pg_locale_t locale); static void init_icu_converter(void); -static size_t uchar_length(UConverter *converter, - const char *str, int32_t len); +static int32_t uchar_length(UConverter *converter, + const char *str, int32_t len); static int32_t uchar_convert(UConverter *converter, UChar *dest, int32_t destlen, const char *src, int32_t srclen); @@ -349,7 +349,7 @@ make_icu_collator(const char *iculocstr, const char *icurules) total = u_strlen(std_rules) + u_strlen(my_rules) + 1; /* avoid leaking collator on OOM */ - all_rules = palloc_extended(sizeof(UChar) * total, MCXT_ALLOC_NO_OOM); + all_rules = palloc_array_extended(UChar, total, MCXT_ALLOC_NO_OOM); if (!all_rules) { ucol_close(collator_std_rules); @@ -375,6 +375,8 @@ make_icu_collator(const char *iculocstr, const char *icurules) iculocstr, icurules, u_errorName(status)))); } + pfree(my_rules); + pfree(all_rules); return collator_all_rules; } } @@ -496,11 +498,9 @@ size_t strnxfrm_icu(char *dest, size_t destsize, const char *src, ssize_t srclen, pg_locale_t locale) { - char sbuf[TEXTBUFLEN]; - char *buf = sbuf; - UChar *uchar; + UChar sbuf[TEXTBUFLEN / sizeof(UChar)]; + UChar *uchar = sbuf; int32_t ulen; - size_t uchar_bsize; Size result_bsize; Assert(locale->provider == COLLPROVIDER_ICU); @@ -509,12 +509,8 @@ strnxfrm_icu(char *dest, size_t destsize, const char *src, ssize_t srclen, ulen = uchar_length(icu_converter, src, srclen); - uchar_bsize = (ulen + 1) * sizeof(UChar); - - if (uchar_bsize > TEXTBUFLEN) - buf = palloc(uchar_bsize); - - uchar = (UChar *) buf; + if (ulen >= lengthof(sbuf)) + uchar = palloc_array(UChar, ulen + 1); ulen = uchar_convert(icu_converter, uchar, ulen + 1, src, srclen); @@ -529,8 +525,8 @@ strnxfrm_icu(char *dest, size_t destsize, const char *src, ssize_t srclen, Assert(result_bsize > 0); result_bsize--; - if (buf != sbuf) - pfree(buf); + if (uchar != sbuf) + pfree(uchar); /* if dest is defined, it should be nul-terminated */ Assert(result_bsize >= destsize || dest[result_bsize] == '\0'); @@ -607,7 +603,7 @@ icu_to_uchar(UChar **buff_uchar, const char *buff, size_t nbytes) len_uchar = uchar_length(icu_converter, buff, nbytes); - *buff_uchar = palloc((len_uchar + 1) * sizeof(**buff_uchar)); + *buff_uchar = palloc_array(UChar, len_uchar + 1); len_uchar = uchar_convert(icu_converter, *buff_uchar, len_uchar + 1, buff, nbytes); @@ -664,7 +660,7 @@ icu_convert_case(ICU_Convert_Func func, pg_locale_t mylocale, int32_t len_dest; len_dest = len_source; /* try first with same length */ - *buff_dest = palloc(len_dest * sizeof(**buff_dest)); + *buff_dest = palloc_array(UChar, len_dest); status = U_ZERO_ERROR; len_dest = func(*buff_dest, len_dest, buff_source, len_source, mylocale->info.icu.locale, &status); @@ -672,7 +668,7 @@ icu_convert_case(ICU_Convert_Func func, pg_locale_t mylocale, { /* try again with adjusted length */ pfree(*buff_dest); - *buff_dest = palloc(len_dest * sizeof(**buff_dest)); + *buff_dest = palloc_array(UChar, len_dest); status = U_ZERO_ERROR; len_dest = func(*buff_dest, len_dest, buff_source, len_source, mylocale->info.icu.locale, &status); @@ -700,7 +696,7 @@ u_strFoldCase_default(UChar *dest, int32_t destCapacity, UErrorCode *pErrorCode) { uint32 options = U_FOLD_CASE_DEFAULT; - char lang[3]; + char lang[ULOC_LANG_CAPACITY]; UErrorCode status; /* @@ -710,8 +706,8 @@ u_strFoldCase_default(UChar *dest, int32_t destCapacity, * languages to enable the option. */ status = U_ZERO_ERROR; - uloc_getLanguage(locale, lang, 3, &status); - if (U_SUCCESS(status)) + uloc_getLanguage(locale, lang, ULOC_LANG_CAPACITY, &status); + if (U_SUCCESS(status) && status != U_STRING_NOT_TERMINATED_WARNING) { /* * The option name is confusing, but it causes u_strFoldCase to use @@ -739,12 +735,11 @@ static int strncoll_icu(const char *arg1, ssize_t len1, const char *arg2, ssize_t len2, pg_locale_t locale) { - char sbuf[TEXTBUFLEN]; - char *buf = sbuf; + UChar sbuf[TEXTBUFLEN / sizeof(UChar)]; + UChar *buf = sbuf; int32_t ulen1; int32_t ulen2; - size_t bufsize1; - size_t bufsize2; + size_t bufsize; UChar *uchar1, *uchar2; int result; @@ -761,14 +756,13 @@ strncoll_icu(const char *arg1, ssize_t len1, ulen1 = uchar_length(icu_converter, arg1, len1); ulen2 = uchar_length(icu_converter, arg2, len2); - bufsize1 = (ulen1 + 1) * sizeof(UChar); - bufsize2 = (ulen2 + 1) * sizeof(UChar); + /* ulen1+1 or ulen2+1 doesn't risk overflow, but summing them might */ + bufsize = add_size(ulen1 + 1, ulen2 + 1); + if (bufsize > lengthof(sbuf)) + buf = palloc_array(UChar, bufsize); - if (bufsize1 + bufsize2 > TEXTBUFLEN) - buf = palloc(bufsize1 + bufsize2); - - uchar1 = (UChar *) buf; - uchar2 = (UChar *) (buf + bufsize1); + uchar1 = buf; + uchar2 = buf + ulen1 + 1; ulen1 = uchar_convert(icu_converter, uchar1, ulen1 + 1, arg1, len1); ulen2 = uchar_convert(icu_converter, uchar2, ulen2 + 1, arg2, len2); @@ -789,14 +783,12 @@ strnxfrm_prefix_icu(char *dest, size_t destsize, const char *src, ssize_t srclen, pg_locale_t locale) { - char sbuf[TEXTBUFLEN]; - char *buf = sbuf; + UChar sbuf[TEXTBUFLEN / sizeof(UChar)]; + UChar *uchar = sbuf; UCharIterator iter; uint32_t state[2]; UErrorCode status; - int32_t ulen = -1; - UChar *uchar = NULL; - size_t uchar_bsize; + int32_t ulen; Size result_bsize; Assert(locale->provider == COLLPROVIDER_ICU); @@ -808,12 +800,8 @@ strnxfrm_prefix_icu(char *dest, size_t destsize, ulen = uchar_length(icu_converter, src, srclen); - uchar_bsize = (ulen + 1) * sizeof(UChar); - - if (uchar_bsize > TEXTBUFLEN) - buf = palloc(uchar_bsize); - - uchar = (UChar *) buf; + if (ulen >= lengthof(sbuf)) + uchar = palloc_array(UChar, ulen + 1); ulen = uchar_convert(icu_converter, uchar, ulen + 1, src, srclen); @@ -831,6 +819,9 @@ strnxfrm_prefix_icu(char *dest, size_t destsize, (errmsg("sort key generation failed: %s", u_errorName(status)))); + if (uchar != sbuf) + pfree(uchar); + return result_bsize; } @@ -865,8 +856,12 @@ init_icu_converter(void) * Find length, in UChars, of given string if converted to UChar string. * * A length of -1 indicates that the input string is NUL-terminated. + * + * Note: given the assumption that the input string fits in MaxAllocSize, + * the result cannot overflow int32_t. But callers must be careful about + * multiplying the result by sizeof(UChar). */ -static size_t +static int32_t uchar_length(UConverter *converter, const char *str, int32_t len) { UErrorCode status = U_ZERO_ERROR; @@ -892,7 +887,6 @@ uchar_convert(UConverter *converter, UChar *dest, int32_t destlen, UErrorCode status = U_ZERO_ERROR; int32_t ulen; - status = U_ZERO_ERROR; ulen = ucnv_toUChars(converter, dest, destlen, src, srclen, &status); if (U_FAILURE(status)) ereport(ERROR, diff --git a/src/backend/utils/adt/pg_locale_libc.c b/src/backend/utils/adt/pg_locale_libc.c index c68fec2e585..31274f069d2 100644 --- a/src/backend/utils/adt/pg_locale_libc.c +++ b/src/backend/utils/adt/pg_locale_libc.c @@ -737,8 +737,9 @@ strncoll_libc_win32_utf8(const char *arg1, ssize_t len1, const char *arg2, char *buf = sbuf; char *a1p, *a2p; - int a1len; - int a2len; + size_t a1len, + a2len, + buflen; int r; int result; @@ -750,11 +751,16 @@ strncoll_libc_win32_utf8(const char *arg1, ssize_t len1, const char *arg2, if (len2 == -1) len2 = strlen(arg2); - a1len = len1 * 2 + 2; - a2len = len2 * 2 + 2; + /* + * In a 32-bit build, twice the input length can overflow size_t, so we + * must be careful. + */ + a1len = add_size(add_size(len1, len1), 2); + a2len = add_size(add_size(len2, len2), 2); + buflen = add_size(a1len, a2len); - if (a1len + a2len > TEXTBUFLEN) - buf = palloc(a1len + a2len); + if (buflen > TEXTBUFLEN) + buf = palloc(buflen); a1p = buf; a2p = buf + a1len; diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c index c33b4c63120..c9ff71844e7 100644 --- a/src/backend/utils/adt/selfuncs.c +++ b/src/backend/utils/adt/selfuncs.c @@ -2172,6 +2172,18 @@ estimate_array_length(PlannerInfo *root, Node *arrayexpr) AttStatsSlot sslot; double nelem = 0; + /* + * Skip calling examine_variable for Var with varno 0, which has no + * valid relation entry and would error in find_base_rel. Such a Var + * can appear when a nested set operation's output type doesn't match + * the parent's expected type, because recurse_set_operations builds a + * projection target list using generate_setop_tlist with varno 0, and + * if the required type coercion involves an ArrayCoerceExpr, we can + * be called on that Var. + */ + if (IsA(arrayexpr, Var) && ((Var *) arrayexpr)->varno == 0) + return 10; /* default guess, should match scalararraysel */ + examine_variable(root, arrayexpr, 0, &vardata); if (HeapTupleIsValid(vardata.statsTuple)) { @@ -5579,7 +5591,11 @@ examine_variable(PlannerInfo *root, Node *node, int varRelid, vardata->statsTuple = statext_expressions_load(info->statOid, rte->inh, pos); - vardata->freefunc = ReleaseDummy; + /* Nothing to release if no data found */ + if (vardata->statsTuple != NULL) + { + vardata->freefunc = ReleaseDummy; + } /* * Test if user has permission to access all rows from the diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c index 931eba438aa..6efc29c2040 100644 --- a/src/backend/utils/adt/timestamp.c +++ b/src/backend/utils/adt/timestamp.c @@ -1691,15 +1691,19 @@ Datum timeofday(PG_FUNCTION_ARGS) { struct timeval tp; - char templ[128]; - char buf[128]; pg_time_t tt; + struct pg_tm *tm; + char part1[128]; + char part2[128]; + char buf[128 + 128 + 10]; gettimeofday(&tp, NULL); tt = (pg_time_t) tp.tv_sec; - pg_strftime(templ, sizeof(templ), "%a %b %d %H:%M:%S.%%06d %Y %Z", - pg_localtime(&tt, session_timezone)); - snprintf(buf, sizeof(buf), templ, tp.tv_usec); + tm = pg_localtime(&tt, session_timezone); + + pg_strftime(part1, sizeof(part1), "%a %b %d %H:%M:%S", tm); + pg_strftime(part2, sizeof(part2), "%Y %Z", tm); + snprintf(buf, sizeof(buf), "%s.%06d %s", part1, (int) tp.tv_usec, part2); PG_RETURN_TEXT_P(cstring_to_text(buf)); } diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c index 34095da18f1..5ec38cb06fa 100644 --- a/src/backend/utils/adt/varlena.c +++ b/src/backend/utils/adt/varlena.c @@ -6986,18 +6986,18 @@ unicode_normalize_func(PG_FUNCTION_ARGS) text *input = PG_GETARG_TEXT_PP(0); char *formstr = text_to_cstring(PG_GETARG_TEXT_PP(1)); UnicodeNormalizationForm form; - int size; + size_t size; pg_wchar *input_chars; pg_wchar *output_chars; unsigned char *p; text *result; - int i; + size_t i; form = unicode_norm_form_from_string(formstr); /* convert to pg_wchar */ size = pg_mbstrlen_with_len(VARDATA_ANY(input), VARSIZE_ANY_EXHDR(input)); - input_chars = palloc((size + 1) * sizeof(pg_wchar)); + input_chars = palloc_array(pg_wchar, size + 1); p = (unsigned char *) VARDATA_ANY(input); for (i = 0; i < size; i++) { @@ -7052,20 +7052,20 @@ unicode_is_normalized(PG_FUNCTION_ARGS) text *input = PG_GETARG_TEXT_PP(0); char *formstr = text_to_cstring(PG_GETARG_TEXT_PP(1)); UnicodeNormalizationForm form; - int size; + size_t size; pg_wchar *input_chars; pg_wchar *output_chars; unsigned char *p; - int i; + size_t i; UnicodeNormalizationQC quickcheck; - int output_size; + size_t output_size; bool result; form = unicode_norm_form_from_string(formstr); /* convert to pg_wchar */ size = pg_mbstrlen_with_len(VARDATA_ANY(input), VARSIZE_ANY_EXHDR(input)); - input_chars = palloc((size + 1) * sizeof(pg_wchar)); + input_chars = palloc_array(pg_wchar, size + 1); p = (unsigned char *) VARDATA_ANY(input); for (i = 0; i < size; i++) { diff --git a/src/backend/utils/adt/xid8funcs.c b/src/backend/utils/adt/xid8funcs.c index 7dd64f207da..89c8caa53a2 100644 --- a/src/backend/utils/adt/xid8funcs.c +++ b/src/backend/utils/adt/xid8funcs.c @@ -193,7 +193,7 @@ is_visible_fxid(FullTransactionId value, const pg_snapshot *snap) #ifdef USE_BSEARCH_IF_NXIP_GREATER else if (snap->nxip > USE_BSEARCH_IF_NXIP_GREATER) { - void *res; + const void *res; res = bsearch(&value, snap->xip, snap->nxip, sizeof(FullTransactionId), cmp_fxid); diff --git a/src/backend/utils/cache/catcache.c b/src/backend/utils/cache/catcache.c index 9138b1ec0e5..c1bca66a092 100644 --- a/src/backend/utils/cache/catcache.c +++ b/src/backend/utils/cache/catcache.c @@ -205,6 +205,10 @@ nameeqfast(Datum a, Datum b) char *ca = NameStr(*DatumGetName(a)); char *cb = NameStr(*DatumGetName(b)); + /* + * Catalogs only use deterministic collations, so ignore column collation + * and use fast path. + */ return strncmp(ca, cb, NAMEDATALEN) == 0; } @@ -213,6 +217,10 @@ namehashfast(Datum datum) { char *key = NameStr(*DatumGetName(datum)); + /* + * Catalogs only use deterministic collations, so ignore column collation + * and use fast path. + */ return hash_any((unsigned char *) key, strlen(key)); } @@ -244,17 +252,20 @@ static bool texteqfast(Datum a, Datum b) { /* - * The use of DEFAULT_COLLATION_OID is fairly arbitrary here. We just - * want to take the fast "deterministic" path in texteq(). + * Catalogs only use deterministic collations, so ignore column collation + * and use "C" locale for efficiency. */ - return DatumGetBool(DirectFunctionCall2Coll(texteq, DEFAULT_COLLATION_OID, a, b)); + return DatumGetBool(DirectFunctionCall2Coll(texteq, C_COLLATION_OID, a, b)); } static uint32 texthashfast(Datum datum) { - /* analogously here as in texteqfast() */ - return DatumGetInt32(DirectFunctionCall1Coll(hashtext, DEFAULT_COLLATION_OID, datum)); + /* + * Catalogs only use deterministic collations, so ignore column collation + * and use "C" locale for efficiency. + */ + return DatumGetInt32(DirectFunctionCall1Coll(hashtext, C_COLLATION_OID, datum)); } static bool diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c index bb01646db99..42081b6902b 100644 --- a/src/backend/utils/cache/lsyscache.c +++ b/src/backend/utils/cache/lsyscache.c @@ -880,6 +880,44 @@ comparison_ops_are_compatible(Oid opno1, Oid opno2) return result; } +/* + * collations_agree_on_equality + * Return true if the two collations have equivalent notions of equality, + * so that a uniqueness or equality proof established under one side + * carries over to a comparison performed under the other side. + * + * Note: this is equality compatibility only. Do NOT use this to reason + * about ordering. + * + * An InvalidOid on either side denotes the absence of a collation -- that + * side's operation is not collation-sensitive (e.g. a non-collatable column + * type). Absence of a collation cannot conflict with the other side's + * collation, so we treat such pairs as agreeing on equality. This generalizes + * the asymmetric treatment in IndexCollMatchesExprColl(). + * + * Otherwise the collations have equivalent equality if they match, or if both + * are deterministic: by definition a deterministic collation treats two + * strings as equal iff they are byte-wise equal (see CREATE COLLATION), so any + * two deterministic collations share the same equality relation. A mismatch + * involving a nondeterministic collation, however, may mean the two equality + * relations disagree, and the proof is unsound. + */ +bool +collations_agree_on_equality(Oid coll1, Oid coll2) +{ + if (!OidIsValid(coll1) || !OidIsValid(coll2)) + return true; + + if (coll1 == coll2) + return true; + + if (!get_collation_isdeterministic(coll1) || + !get_collation_isdeterministic(coll2)) + return false; + + return true; +} + /* ---------- AMPROC CACHES ---------- */ diff --git a/src/backend/utils/misc/injection_point.c b/src/backend/utils/misc/injection_point.c index f795fc2563f..64f11d4ba93 100644 --- a/src/backend/utils/misc/injection_point.c +++ b/src/backend/utils/misc/injection_point.c @@ -336,6 +336,7 @@ InjectionPointAttach(const char *name, entry->library[INJ_LIB_MAXLEN - 1] = '\0'; strlcpy(entry->function, function, sizeof(entry->function)); entry->function[INJ_FUNC_MAXLEN - 1] = '\0'; + memset(entry->private_data, 0, INJ_PRIVATE_MAXLEN); if (private_data != NULL) memcpy(entry->private_data, private_data, private_data_size); diff --git a/src/backend/utils/mmgr/aset.c b/src/backend/utils/mmgr/aset.c index bcb55296c43..a6742d8d738 100644 --- a/src/backend/utils/mmgr/aset.c +++ b/src/backend/utils/mmgr/aset.c @@ -1125,7 +1125,26 @@ AllocSetFree(void *pointer) Assert(FreeListIdxIsValid(fidx)); link = GetFreeListLink(chunk); + /* + * It might seem odd that we use elevel ERROR for double-pfree but + * only WARNING for write-past-chunk-end. But the two conditions are + * not very comparable. In the double-pfree case we can prevent + * corruption before it happens; while if we let it go through, the + * result would be a corrupted freelist that allows this chunk to get + * re-allocated twice. Thus the original bug could cascade into + * hard-to-understand misbehavior that might manifest far away from + * the actual source of the problem. On the other hand, a write past + * chunk end can be relatively benign if just a few bytes too many + * were written: often, only padding or unused space gets affected. + * Moreover, whatever damage was done is already done, and we're just + * reporting after the fact with no ability to clean it up. So just + * warn, like AllocSetCheck would do if the chunk didn't get freed. + */ #ifdef MEMORY_CONTEXT_CHECKING + /* Test for previously-freed chunk */ + if (unlikely(chunk->requested_size == InvalidAllocSize)) + elog(ERROR, "detected double pfree in %s %p", + set->header.name, chunk); /* Test for someone scribbling on unused space in chunk */ if (chunk->requested_size < GetChunkSizeFromFreeListIdx(fidx)) if (!sentinel_ok(pointer, chunk->requested_size)) @@ -1316,6 +1335,11 @@ AllocSetRealloc(void *pointer, Size size, int flags) oldchksize = GetChunkSizeFromFreeListIdx(fidx); #ifdef MEMORY_CONTEXT_CHECKING + /* See comments in AllocSetFree about uses of ERROR and WARNING here */ + /* Test for previously-freed chunk */ + if (unlikely(chunk->requested_size == InvalidAllocSize)) + elog(ERROR, "detected realloc of freed chunk in %s %p", + set->header.name, chunk); /* Test for someone scribbling on unused space in chunk */ if (chunk->requested_size < oldchksize) if (!sentinel_ok(pointer, chunk->requested_size)) diff --git a/src/backend/utils/mmgr/dsa.c b/src/backend/utils/mmgr/dsa.c index 361867d1060..0a55bff00da 100644 --- a/src/backend/utils/mmgr/dsa.c +++ b/src/backend/utils/mmgr/dsa.c @@ -2146,6 +2146,8 @@ make_new_segment(dsa_area *area, size_t requested_pages) /* See if that is enough... */ if (requested_pages > usable_pages) { + size_t total_requested_pages PG_USED_FOR_ASSERTS_ONLY; + /* * We'll make an odd-sized segment, working forward from the requested * number of pages. @@ -2156,10 +2158,37 @@ make_new_segment(dsa_area *area, size_t requested_pages) MAXALIGN(sizeof(FreePageManager)) + usable_pages * sizeof(dsa_pointer); + /* + * We must also account for pagemap entries needed to cover the + * metadata pages themselves. The pagemap must track all pages in the + * segment, including the pages occupied by metadata. + * + * This formula uses integer ceiling division to compute the exact + * number of additional entries needed. The divisor (FPM_PAGE_SIZE - + * sizeof(dsa_pointer)) accounts for the fact that each metadata page + * consumes one pagemap entry of sizeof(dsa_pointer) bytes, leaving + * only (FPM_PAGE_SIZE - sizeof(dsa_pointer)) net bytes per metadata + * page. + */ + metadata_bytes += + ((metadata_bytes + (FPM_PAGE_SIZE - sizeof(dsa_pointer)) - 1) / + (FPM_PAGE_SIZE - sizeof(dsa_pointer))) * + sizeof(dsa_pointer); + /* Add padding up to next page boundary. */ if (metadata_bytes % FPM_PAGE_SIZE != 0) metadata_bytes += FPM_PAGE_SIZE - (metadata_bytes % FPM_PAGE_SIZE); total_size = metadata_bytes + usable_pages * FPM_PAGE_SIZE; + total_requested_pages = total_size / FPM_PAGE_SIZE; + + /* + * Verify that we allocated enough pagemap entries for metadata and + * usable pages. This reverse-engineers the new calculation of + * "metadata_bytes" done based on the new "requested_pages" for an + * odd-sized segment. + */ + Assert((metadata_bytes - MAXALIGN(sizeof(dsa_segment_header)) - + MAXALIGN(sizeof(FreePageManager))) / sizeof(dsa_pointer) >= total_requested_pages); /* Is that too large for dsa_pointer's addressing scheme? */ if (total_size > DSA_MAX_SEGMENT_SIZE) diff --git a/src/backend/utils/mmgr/generation.c b/src/backend/utils/mmgr/generation.c index 18679ad4f1e..e4573674491 100644 --- a/src/backend/utils/mmgr/generation.c +++ b/src/backend/utils/mmgr/generation.c @@ -733,6 +733,11 @@ GenerationFree(void *pointer) } #ifdef MEMORY_CONTEXT_CHECKING + /* See comments in AllocSetFree about uses of ERROR and WARNING here */ + /* Test for previously-freed chunk */ + if (unlikely(chunk->requested_size == InvalidAllocSize)) + elog(ERROR, "detected double pfree in %s %p", + ((MemoryContext) block->context)->name, chunk); /* Test for someone scribbling on unused space in chunk */ Assert(chunk->requested_size < chunksize); if (!sentinel_ok(pointer, chunk->requested_size)) @@ -838,6 +843,11 @@ GenerationRealloc(void *pointer, Size size, int flags) set = block->context; #ifdef MEMORY_CONTEXT_CHECKING + /* See comments in AllocSetFree about uses of ERROR and WARNING here */ + /* Test for previously-freed chunk */ + if (unlikely(chunk->requested_size == InvalidAllocSize)) + elog(ERROR, "detected realloc of freed chunk in %s %p", + ((MemoryContext) set)->name, chunk); /* Test for someone scribbling on unused space in chunk */ Assert(chunk->requested_size < oldsize); if (!sentinel_ok(pointer, chunk->requested_size)) diff --git a/src/backend/utils/mmgr/mcxt.c b/src/backend/utils/mmgr/mcxt.c index 69dd6165e82..ac662b9bc37 100644 --- a/src/backend/utils/mmgr/mcxt.c +++ b/src/backend/utils/mmgr/mcxt.c @@ -21,6 +21,7 @@ #include "postgres.h" +#include "common/int.h" #include "mb/pg_wchar.h" #include "miscadmin.h" #include "utils/memdebug.h" @@ -169,6 +170,8 @@ static void MemoryContextStatsInternal(MemoryContext context, int level, static void MemoryContextStatsPrint(MemoryContext context, void *passthru, const char *stats_string, bool print_to_stderr); +pg_noreturn static pg_noinline void add_size_error(Size s1, Size s2); +pg_noreturn static pg_noinline void mul_size_error(Size s1, Size s2); /* * You should not do memory allocations within a critical section, because @@ -1659,6 +1662,132 @@ repalloc0(void *pointer, Size oldsize, Size size) return ret; } +/* + * Support for safe calculation of memory request sizes + * + * These functions perform the requested calculation, but throw error if the + * result overflows. + * + * An important property of these functions is that if an argument was a + * negative signed int before promotion (implying overflow in calculating it) + * we will detect that as an error. That happens because we reject results + * larger than SIZE_MAX / 2 later on, in the actual allocation step. + */ +Size +add_size(Size s1, Size s2) +{ + Size result; + + if (unlikely(pg_add_size_overflow(s1, s2, &result))) + add_size_error(s1, s2); + return result; +} + +pg_noreturn static pg_noinline void +add_size_error(Size s1, Size s2) +{ + ereport(ERROR, + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), + errmsg("invalid memory allocation request size %zu + %zu", + s1, s2))); +} + +Size +mul_size(Size s1, Size s2) +{ + Size result; + + if (unlikely(pg_mul_size_overflow(s1, s2, &result))) + mul_size_error(s1, s2); + return result; +} + +pg_noreturn static pg_noinline void +mul_size_error(Size s1, Size s2) +{ + ereport(ERROR, + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), + errmsg("invalid memory allocation request size %zu * %zu", + s1, s2))); +} + +/* + * palloc_mul + * Equivalent to palloc(mul_size(s1, s2)). + */ +void * +palloc_mul(Size s1, Size s2) +{ + /* inline mul_size() for efficiency */ + Size req; + + if (unlikely(pg_mul_size_overflow(s1, s2, &req))) + mul_size_error(s1, s2); + return palloc(req); +} + +/* + * palloc0_mul + * Equivalent to palloc0(mul_size(s1, s2)). + * + * This is comparable to standard calloc's behavior. + */ +void * +palloc0_mul(Size s1, Size s2) +{ + /* inline mul_size() for efficiency */ + Size req; + + if (unlikely(pg_mul_size_overflow(s1, s2, &req))) + mul_size_error(s1, s2); + return palloc0(req); +} + +/* + * palloc_mul_extended + * Equivalent to palloc_extended(mul_size(s1, s2), flags). + */ +void * +palloc_mul_extended(Size s1, Size s2, int flags) +{ + /* inline mul_size() for efficiency */ + Size req; + + if (unlikely(pg_mul_size_overflow(s1, s2, &req))) + mul_size_error(s1, s2); + return palloc_extended(req, flags); +} + +/* + * repalloc_mul + * Equivalent to repalloc(p, mul_size(s1, s2)). + */ +void * +repalloc_mul(void *p, Size s1, Size s2) +{ + /* inline mul_size() for efficiency */ + Size req; + + if (unlikely(pg_mul_size_overflow(s1, s2, &req))) + mul_size_error(s1, s2); + return repalloc(p, req); +} + +/* + * repalloc_mul_extended + * Equivalent to repalloc_extended(p, mul_size(s1, s2), flags). + */ +void * +repalloc_mul_extended(void *p, Size s1, Size s2, int flags) +{ + /* inline mul_size() for efficiency */ + Size req; + + if (unlikely(pg_mul_size_overflow(s1, s2, &req))) + mul_size_error(s1, s2); + return repalloc_extended(p, req, flags); +} + /* * MemoryContextAllocHuge * Allocate (possibly-expansive) space within the specified context. diff --git a/src/backend/utils/mmgr/slab.c b/src/backend/utils/mmgr/slab.c index d32c0d318fb..2e4ed1c7837 100644 --- a/src/backend/utils/mmgr/slab.c +++ b/src/backend/utils/mmgr/slab.c @@ -514,6 +514,7 @@ SlabAllocSetupNewChunk(MemoryContext context, SlabBlock *block, MemoryChunkSetHdrMask(chunk, block, MAXALIGN(slab->chunkSize), MCTX_SLAB_ID); #ifdef MEMORY_CONTEXT_CHECKING + chunk->requested_size = size; /* slab mark to catch clobber of "unused" space */ Assert(slab->chunkSize < (slab->fullChunkSize - Slab_CHUNKHDRSZ)); set_sentinel(MemoryChunkGetPointer(chunk), size); @@ -720,11 +721,18 @@ SlabFree(void *pointer) slab = block->slab; #ifdef MEMORY_CONTEXT_CHECKING + /* See comments in AllocSetFree about uses of ERROR and WARNING here */ + /* Test for previously-freed chunk */ + if (unlikely(chunk->requested_size == InvalidAllocSize)) + elog(ERROR, "detected double pfree in %s %p", + slab->header.name, chunk); /* Test for someone scribbling on unused space in chunk */ Assert(slab->chunkSize < (slab->fullChunkSize - Slab_CHUNKHDRSZ)); if (!sentinel_ok(pointer, slab->chunkSize)) elog(WARNING, "detected write past chunk end in %s %p", slab->header.name, chunk); + /* Reset requested_size to InvalidAllocSize in free chunks */ + chunk->requested_size = InvalidAllocSize; #endif /* push this chunk onto the head of the block's free list */ diff --git a/src/backend/utils/sort/tuplestore.c b/src/backend/utils/sort/tuplestore.c index c9aecab8d66..5a6ef2e746b 100644 --- a/src/backend/utils/sort/tuplestore.c +++ b/src/backend/utils/sort/tuplestore.c @@ -707,10 +707,10 @@ grow_memtuples(Tuplestorestate *state) /* OK, do it */ FREEMEM(state, GetMemoryChunkSpace(state->memtuples)); - state->memtupsize = newmemtupsize; state->memtuples = (void **) repalloc_huge(state->memtuples, - state->memtupsize * sizeof(void *)); + newmemtupsize * sizeof(void *)); + state->memtupsize = newmemtupsize; USEMEM(state, GetMemoryChunkSpace(state->memtuples)); if (LACKMEM(state)) elog(ERROR, "unexpected out-of-memory situation in tuplestore"); @@ -1273,7 +1273,19 @@ dumptuples(Tuplestorestate *state) if (i >= state->memtupcount) break; WRITETUP(state, state->memtuples[i]); + + /* + * Increase memtupdeleted to track the fact that we just deleted that + * tuple. Think not to remove this on the grounds that we'll reset + * memtupdeleted to zero below. We might not reach that if some later + * WRITETUP fails (e.g. due to overrunning temp_file_limit). If so, + * we'd error out leaving an effectively-corrupt tuplestore, which + * would be quite bad if it's a persistent data structure such as a + * Portal's holdStore. + */ + state->memtupdeleted++; } + /* Now we can reset memtupdeleted along with memtupcount */ state->memtupdeleted = 0; state->memtupcount = 0; } @@ -1463,8 +1475,10 @@ tuplestore_trim(Tuplestorestate *state) FREEMEM(state, GetMemoryChunkSpace(state->memtuples[i])); pfree(state->memtuples[i]); state->memtuples[i] = NULL; + /* As in dumptuples(), increment memtupdeleted synchronously */ + state->memtupdeleted++; } - state->memtupdeleted = nremove; + Assert(state->memtupdeleted == nremove); /* mark tuplestore as truncated (used for Assert crosschecks only) */ state->truncated = true; diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c index d393536a601..c326ab8bf96 100644 --- a/src/bin/initdb/initdb.c +++ b/src/bin/initdb/initdb.c @@ -2511,7 +2511,7 @@ icu_validate_locale(const char *loc_str) /* validate that we can extract the language */ status = U_ZERO_ERROR; uloc_getLanguage(loc_str, lang, ULOC_LANG_CAPACITY, &status); - if (U_FAILURE(status)) + if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING) { pg_fatal("could not get language from locale \"%s\": %s", loc_str, u_errorName(status)); @@ -2531,7 +2531,7 @@ icu_validate_locale(const char *loc_str) status = U_ZERO_ERROR; uloc_getLanguage(otherloc, otherlang, ULOC_LANG_CAPACITY, &status); - if (U_FAILURE(status)) + if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING) continue; if (strcmp(lang, otherlang) == 0) diff --git a/src/bin/pg_basebackup/astreamer_inject.c b/src/bin/pg_basebackup/astreamer_inject.c index 15334e458ad..3fb3d4ecfd5 100644 --- a/src/bin/pg_basebackup/astreamer_inject.c +++ b/src/bin/pg_basebackup/astreamer_inject.c @@ -224,8 +224,9 @@ astreamer_inject_file(astreamer *streamer, char *pathname, char *data, strlcpy(member.pathname, pathname, MAXPGPATH); member.size = len; member.mode = pg_file_create_mode; + member.is_regular = true; member.is_directory = false; - member.is_link = false; + member.is_symlink = false; member.linktarget[0] = '\0'; /* diff --git a/src/bin/pg_basebackup/pg_createsubscriber.c b/src/bin/pg_basebackup/pg_createsubscriber.c index eb436121a87..48374a4ef12 100644 --- a/src/bin/pg_basebackup/pg_createsubscriber.c +++ b/src/bin/pg_basebackup/pg_createsubscriber.c @@ -1118,18 +1118,23 @@ drop_existing_subscriptions(PGconn *conn, const char *subname, const char *dbnam { PQExpBuffer query = createPQExpBuffer(); PGresult *res; + char *subname_esc; Assert(conn != NULL); + subname_esc = PQescapeIdentifier(conn, subname, strlen(subname)); + /* * Construct a query string. These commands are allowed to be executed * within a transaction. */ appendPQExpBuffer(query, "ALTER SUBSCRIPTION %s DISABLE;", - subname); + subname_esc); appendPQExpBuffer(query, " ALTER SUBSCRIPTION %s SET (slot_name = NONE);", - subname); - appendPQExpBuffer(query, " DROP SUBSCRIPTION %s;", subname); + subname_esc); + appendPQExpBuffer(query, " DROP SUBSCRIPTION %s;", subname_esc); + + PQfreemem(subname_esc); if (dry_run) pg_log_info("dry-run: would drop subscription \"%s\" in database \"%s\"", diff --git a/src/bin/pg_basebackup/po/de.po b/src/bin/pg_basebackup/po/de.po index 16ea9c6fe5a..0c10f397abc 100644 --- a/src/bin/pg_basebackup/po/de.po +++ b/src/bin/pg_basebackup/po/de.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: PostgreSQL 18\n" "Report-Msgid-Bugs-To: pgsql-bugs@lists.postgresql.org\n" -"POT-Creation-Date: 2026-02-04 18:50+0000\n" -"PO-Revision-Date: 2026-02-05 14:24+0100\n" +"POT-Creation-Date: 2026-05-05 12:11+0000\n" +"PO-Revision-Date: 2026-05-06 15:44+0200\n" "Last-Translator: Peter Eisentraut \n" "Language-Team: German \n" "Language: de\n" @@ -41,8 +41,8 @@ msgstr "Tipp: " #: ../../common/compression.c:132 ../../common/compression.c:141 #: ../../common/compression.c:150 ../../fe_utils/astreamer_gzip.c:140 #: ../../fe_utils/astreamer_gzip.c:273 ../../fe_utils/astreamer_lz4.c:102 -#: ../../fe_utils/astreamer_lz4.c:300 ../../fe_utils/astreamer_zstd.c:133 -#: ../../fe_utils/astreamer_zstd.c:288 +#: ../../fe_utils/astreamer_lz4.c:300 ../../fe_utils/astreamer_zstd.c:130 +#: ../../fe_utils/astreamer_zstd.c:285 #, c-format msgid "this build does not support compression with %s" msgstr "diese Installation unterstützt keine Komprimierung mit %s" @@ -108,7 +108,8 @@ msgid "could not read file \"%s\": read %d of %zu" msgstr "konnte Datei »%s« nicht lesen: %d von %zu gelesen" #: ../../common/controldata_utils.c:132 ../../common/controldata_utils.c:280 -#: ../../fe_utils/astreamer_file.c:141 pg_recvlogical.c:653 +#: ../../fe_utils/astreamer_file.c:141 ../../fe_utils/astreamer_file.c:270 +#: pg_recvlogical.c:653 #, c-format msgid "could not close file \"%s\": %m" msgstr "konnte Datei »%s« nicht schließen: %m" @@ -225,7 +226,7 @@ msgstr "konnte Prozess nicht mit beschränktem Token neu starten: Fehlercode %lu msgid "could not get exit code from subprocess: error code %lu" msgstr "konnte Statuscode des Subprozesses nicht ermitteln: Fehlercode %lu" -#: ../../fe_utils/astreamer_file.c:96 ../../fe_utils/astreamer_file.c:364 +#: ../../fe_utils/astreamer_file.c:96 ../../fe_utils/astreamer_file.c:366 #: ../../fe_utils/recovery_gen.c:153 pg_basebackup.c:1498 pg_basebackup.c:1707 #, c-format msgid "could not create file \"%s\": %m" @@ -237,28 +238,28 @@ msgstr "konnte Datei »%s« nicht erstellen: %m" msgid "could not write to file \"%s\": %m" msgstr "konnte nicht in Datei »%s« schreiben: %m" -#: ../../fe_utils/astreamer_file.c:278 +#: ../../fe_utils/astreamer_file.c:280 #, c-format msgid "unexpected state while extracting archive" msgstr "unerwarteter Zustand beim Extrahieren des Archivs" -#: ../../fe_utils/astreamer_file.c:324 pg_basebackup.c:699 pg_basebackup.c:713 +#: ../../fe_utils/astreamer_file.c:326 pg_basebackup.c:699 pg_basebackup.c:713 #: pg_basebackup.c:758 #, c-format msgid "could not create directory \"%s\": %m" msgstr "konnte Verzeichnis »%s« nicht erzeugen: %m" -#: ../../fe_utils/astreamer_file.c:329 +#: ../../fe_utils/astreamer_file.c:331 #, c-format msgid "could not set permissions on directory \"%s\": %m" msgstr "konnte Zugriffsrechte für Verzeichnis »%s« nicht setzen: %m" -#: ../../fe_utils/astreamer_file.c:348 +#: ../../fe_utils/astreamer_file.c:350 #, c-format msgid "could not create symbolic link from \"%s\" to \"%s\": %m" msgstr "konnte symbolische Verknüpfung von »%s« nach »%s« nicht erzeugen: %m" -#: ../../fe_utils/astreamer_file.c:368 +#: ../../fe_utils/astreamer_file.c:370 #, c-format msgid "could not set permissions on file \"%s\": %m" msgstr "konnte Zugriffsrechte von Datei »%s« nicht setzen: %m" @@ -299,7 +300,7 @@ msgid "could not initialize compression library" msgstr "konnte Komprimierungsbibliothek nicht initialisieren" #: ../../fe_utils/astreamer_gzip.c:320 ../../fe_utils/astreamer_lz4.c:356 -#: ../../fe_utils/astreamer_zstd.c:333 +#: ../../fe_utils/astreamer_zstd.c:330 #, c-format msgid "could not decompress data: %s" msgstr "konnte Daten nicht dekomprimieren: %s" @@ -314,8 +315,8 @@ msgstr "konnte lz4-Komprimierungskontext nicht erzeugen: %s" msgid "could not write lz4 header: %s" msgstr "konnte lz4-Header nicht schreiben: %s" -#: ../../fe_utils/astreamer_lz4.c:191 ../../fe_utils/astreamer_zstd.c:185 -#: ../../fe_utils/astreamer_zstd.c:227 +#: ../../fe_utils/astreamer_lz4.c:191 ../../fe_utils/astreamer_zstd.c:182 +#: ../../fe_utils/astreamer_zstd.c:224 #, c-format msgid "could not compress data: %s" msgstr "konnte Daten nicht komprimieren: %s" @@ -330,22 +331,27 @@ msgstr "konnte lz4-Komprimierung nicht beenden: %s" msgid "could not initialize compression library: %s" msgstr "konnte Komprimierungsbibliothek nicht initialisieren: %s" -#: ../../fe_utils/astreamer_tar.c:244 -#, c-format -msgid "tar file trailer exceeds 2 blocks" -msgstr "Tar-Datei-Trailer überschreitet 2 Blöcke" - -#: ../../fe_utils/astreamer_tar.c:249 +#: ../../fe_utils/astreamer_tar.c:254 #, c-format msgid "unexpected state while parsing tar archive" msgstr "unerwarteter Zustand beim Parsen des Tar-Archivs" -#: ../../fe_utils/astreamer_tar.c:292 +#: ../../fe_utils/astreamer_tar.c:300 +#, c-format +msgid "input file does not appear to be a valid tar archive" +msgstr "Eingabedatei scheint kein gültiges Tar-Archiv zu sein" + +#: ../../fe_utils/astreamer_tar.c:307 #, c-format msgid "tar member has empty name" msgstr "Tar-Mitglied hat leeren Namen" -#: ../../fe_utils/astreamer_tar.c:326 +#: ../../fe_utils/astreamer_tar.c:328 +#, c-format +msgid "pax extensions to tar format are not supported" +msgstr "PAX-Erweiterungen des Tar-Formats werden nicht unterstützt" + +#: ../../fe_utils/astreamer_tar.c:357 #, c-format msgid "COPY stream ended before last file was finished" msgstr "COPY-Strom endete vor dem Ende der letzten Datei" @@ -365,12 +371,12 @@ msgstr "konnte zstd-Komprimierungsniveau nicht auf %d setzen: %s" msgid "could not set compression worker count to %d: %s" msgstr "konnte Komprimierungs-Worker-Anzahl nicht auf %d setzen: %s" -#: ../../fe_utils/astreamer_zstd.c:120 +#: ../../fe_utils/astreamer_zstd.c:119 #, c-format msgid "could not enable long-distance mode: %s" msgstr "konnte Long-Distance-Modus nicht einschalten: %s" -#: ../../fe_utils/astreamer_zstd.c:279 +#: ../../fe_utils/astreamer_zstd.c:276 #, c-format msgid "could not create zstd decompression context" msgstr "konnte zstd-Dekomprimierungskontext nicht erzeugen" diff --git a/src/bin/pg_basebackup/po/fr.po b/src/bin/pg_basebackup/po/fr.po index c935cdfe49d..19dc59a3de7 100644 --- a/src/bin/pg_basebackup/po/fr.po +++ b/src/bin/pg_basebackup/po/fr.po @@ -10,8 +10,8 @@ msgid "" msgstr "" "Project-Id-Version: PostgreSQL 17\n" "Report-Msgid-Bugs-To: pgsql-bugs@lists.postgresql.org\n" -"POT-Creation-Date: 2026-02-18 04:49+0000\n" -"PO-Revision-Date: 2026-02-18 14:28+0100\n" +"POT-Creation-Date: 2026-05-08 18:50+0000\n" +"PO-Revision-Date: 2026-05-08 21:48+0200\n" "Last-Translator: Guillaume Lelarge \n" "Language-Team: French \n" "Language: fr\n" @@ -19,7 +19,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" -"X-Generator: Poedit 3.8\n" +"X-Generator: Poedit 3.9\n" #: ../../../src/common/logging.c:279 #, c-format @@ -44,8 +44,8 @@ msgstr "astuce : " #: ../../common/compression.c:132 ../../common/compression.c:141 #: ../../common/compression.c:150 ../../fe_utils/astreamer_gzip.c:140 #: ../../fe_utils/astreamer_gzip.c:273 ../../fe_utils/astreamer_lz4.c:102 -#: ../../fe_utils/astreamer_lz4.c:300 ../../fe_utils/astreamer_zstd.c:133 -#: ../../fe_utils/astreamer_zstd.c:288 +#: ../../fe_utils/astreamer_lz4.c:300 ../../fe_utils/astreamer_zstd.c:130 +#: ../../fe_utils/astreamer_zstd.c:285 #, c-format msgid "this build does not support compression with %s" msgstr "cette construction ne supporte pas la compression avec %s" @@ -111,7 +111,8 @@ msgid "could not read file \"%s\": read %d of %zu" msgstr "n'a pas pu lire le fichier « %s » : a lu %d sur %zu" #: ../../common/controldata_utils.c:132 ../../common/controldata_utils.c:280 -#: ../../fe_utils/astreamer_file.c:141 pg_recvlogical.c:653 +#: ../../fe_utils/astreamer_file.c:141 ../../fe_utils/astreamer_file.c:270 +#: pg_recvlogical.c:653 #, c-format msgid "could not close file \"%s\": %m" msgstr "n'a pas pu fermer le fichier « %s » : %m" @@ -228,7 +229,7 @@ msgstr "n'a pas pu ré-exécuter le jeton restreint : code d'erreur %lu" msgid "could not get exit code from subprocess: error code %lu" msgstr "n'a pas pu récupérer le code de statut du sous-processus : code d'erreur %lu" -#: ../../fe_utils/astreamer_file.c:96 ../../fe_utils/astreamer_file.c:364 +#: ../../fe_utils/astreamer_file.c:96 ../../fe_utils/astreamer_file.c:366 #: ../../fe_utils/recovery_gen.c:153 pg_basebackup.c:1498 pg_basebackup.c:1707 #, c-format msgid "could not create file \"%s\": %m" @@ -240,28 +241,28 @@ msgstr "n'a pas pu créer le fichier « %s » : %m" msgid "could not write to file \"%s\": %m" msgstr "n'a pas pu écrire dans le fichier « %s » : %m" -#: ../../fe_utils/astreamer_file.c:278 +#: ../../fe_utils/astreamer_file.c:280 #, c-format msgid "unexpected state while extracting archive" msgstr "état inattendu lors de l'extraction de l'archive" -#: ../../fe_utils/astreamer_file.c:324 pg_basebackup.c:699 pg_basebackup.c:713 +#: ../../fe_utils/astreamer_file.c:326 pg_basebackup.c:699 pg_basebackup.c:713 #: pg_basebackup.c:758 #, c-format msgid "could not create directory \"%s\": %m" msgstr "n'a pas pu créer le répertoire « %s » : %m" -#: ../../fe_utils/astreamer_file.c:329 +#: ../../fe_utils/astreamer_file.c:331 #, c-format msgid "could not set permissions on directory \"%s\": %m" msgstr "n'a pas pu configurer les droits du répertoire « %s » : %m" -#: ../../fe_utils/astreamer_file.c:348 +#: ../../fe_utils/astreamer_file.c:350 #, c-format msgid "could not create symbolic link from \"%s\" to \"%s\": %m" msgstr "n'a pas pu créer le lien symbolique de « %s » vers « %s » : %m" -#: ../../fe_utils/astreamer_file.c:368 +#: ../../fe_utils/astreamer_file.c:370 #, c-format msgid "could not set permissions on file \"%s\": %m" msgstr "n'a pas pu initialiser les droits du fichier « %s » : %m" @@ -302,7 +303,7 @@ msgid "could not initialize compression library" msgstr "n'a pas pu initialiser la bibliothèque de compression" #: ../../fe_utils/astreamer_gzip.c:320 ../../fe_utils/astreamer_lz4.c:356 -#: ../../fe_utils/astreamer_zstd.c:333 +#: ../../fe_utils/astreamer_zstd.c:330 #, c-format msgid "could not decompress data: %s" msgstr "n'a pas pu décompresser les données : %s" @@ -317,8 +318,8 @@ msgstr "n'a pas pu créer le contexte de compression lz4 : %s" msgid "could not write lz4 header: %s" msgstr "n'a pas pu écrire l'entête lz4 : %s" -#: ../../fe_utils/astreamer_lz4.c:191 ../../fe_utils/astreamer_zstd.c:185 -#: ../../fe_utils/astreamer_zstd.c:227 +#: ../../fe_utils/astreamer_lz4.c:191 ../../fe_utils/astreamer_zstd.c:182 +#: ../../fe_utils/astreamer_zstd.c:224 #, c-format msgid "could not compress data: %s" msgstr "n'a pas pu compresser les données : %s" @@ -333,22 +334,27 @@ msgstr "n'a pas pu terminer la compression lz4 : %s" msgid "could not initialize compression library: %s" msgstr "n'a pas pu initialiser la bibliothèque de compression : %s" -#: ../../fe_utils/astreamer_tar.c:244 -#, c-format -msgid "tar file trailer exceeds 2 blocks" -msgstr "la fin du fichier tar fait plus de 2 blocs" - -#: ../../fe_utils/astreamer_tar.c:249 +#: ../../fe_utils/astreamer_tar.c:254 #, c-format msgid "unexpected state while parsing tar archive" msgstr "état inattendu lors de l'analyse de l'archive tar" -#: ../../fe_utils/astreamer_tar.c:292 +#: ../../fe_utils/astreamer_tar.c:300 +#, c-format +msgid "input file does not appear to be a valid tar archive" +msgstr "le fichier en entrée ne semble pas être une archive tar valide" + +#: ../../fe_utils/astreamer_tar.c:307 #, c-format msgid "tar member has empty name" msgstr "le membre de tar a un nom vide" -#: ../../fe_utils/astreamer_tar.c:326 +#: ../../fe_utils/astreamer_tar.c:328 +#, c-format +msgid "pax extensions to tar format are not supported" +msgstr "les extensions pax au format tar ne sont pas supportés" + +#: ../../fe_utils/astreamer_tar.c:357 #, c-format msgid "COPY stream ended before last file was finished" msgstr "le flux COPY s'est terminé avant que le dernier fichier soit terminé" @@ -368,12 +374,12 @@ msgstr "n'a pas pu configurer le niveau de compression zstd à %d : %s" msgid "could not set compression worker count to %d: %s" msgstr "n'a pas pu configurer le nombre de workers de compression à %d : %s" -#: ../../fe_utils/astreamer_zstd.c:120 +#: ../../fe_utils/astreamer_zstd.c:119 #, c-format msgid "could not enable long-distance mode: %s" msgstr "n'a pas pu activer le mode distance longue : %s" -#: ../../fe_utils/astreamer_zstd.c:279 +#: ../../fe_utils/astreamer_zstd.c:276 #, c-format msgid "could not create zstd decompression context" msgstr "n'a pas pu créer le contexte de décompression zstd" @@ -942,7 +948,7 @@ msgstr "n'a pas pu analyser l'archive « %s »" #: pg_basebackup.c:1133 #, c-format msgid "Only tar archives can be parsed." -msgstr "Seules les archives tar peuvent être analysées" +msgstr "Seules les archives tar peuvent être analysées." #: pg_basebackup.c:1135 #, c-format @@ -1239,7 +1245,7 @@ msgstr "spécification de compression invalide : %s" #: pg_basebackup.c:2678 #, c-format msgid "client-side compression is not possible when a backup target is specified" -msgstr "la compression client n'est pas possible quand une cible de restauration est indiquée." +msgstr "la compression client n'est pas possible quand une cible de restauration est indiquée" #: pg_basebackup.c:2689 #, c-format @@ -1249,7 +1255,7 @@ msgstr "seules les sauvegardes en mode tar peuvent être compressées" #: pg_basebackup.c:2699 #, c-format msgid "WAL cannot be streamed when a backup target is specified" -msgstr "Les journaux de transactions ne peuvent pas être envoyés en flux quand une cible de sauvegarde est indiquée." +msgstr "les journaux de transactions ne peuvent pas être envoyés en flux quand une cible de sauvegarde est indiquée" #: pg_basebackup.c:2705 #, c-format @@ -2705,7 +2711,7 @@ msgstr "l'option d'accès du groupe n'a pas pu être analysé : %s" #: streamutil.c:430 streamutil.c:467 #, c-format msgid "could not identify system: got %d rows and %d fields, expected %d rows and %d or more fields" -msgstr "n'a pas pu identifier le système : a récupéré %d lignes et %d champs, attendait %d lignes et %d champs (ou plus)." +msgstr "n'a pas pu identifier le système : a récupéré %d lignes et %d champs, attendait %d lignes et %d champs (ou plus)" #: streamutil.c:519 #, c-format @@ -2780,3 +2786,7 @@ msgstr "n'a pas pu fermer le flux de compression" #, c-format #~ msgid "subscriber successfully changed the system identifier" #~ msgstr "l'abonné a modifié avec succès l'identifieur système" + +#, c-format +#~ msgid "tar file trailer exceeds 2 blocks" +#~ msgstr "la fin du fichier tar fait plus de 2 blocs" diff --git a/src/bin/pg_combinebackup/t/011_ib_truncation.pl b/src/bin/pg_combinebackup/t/011_ib_truncation.pl index 47d84434452..c5e0124c04d 100644 --- a/src/bin/pg_combinebackup/t/011_ib_truncation.pl +++ b/src/bin/pg_combinebackup/t/011_ib_truncation.pl @@ -1,7 +1,8 @@ # Copyright (c) 2025-2026, PostgreSQL Global Development Group # -# This test aims to validate that the calculated truncation block never exceeds -# the segment size. +# This test aims to validate two things: (1) that the calculated truncation +# block never exceeds the segment size and (2) that the correct limit block +# length is calculated for the VM fork. use strict; use warnings FATAL => 'all'; @@ -39,7 +40,7 @@ CREATE TABLE t ( id int, data text STORAGE PLAIN - ); + ) WITH (autovacuum_enabled = false); }); # The tuple size should be enough to prevent two tuples from being on the same @@ -83,6 +84,23 @@ $primary->backup('incr', backup_options => [ '--incremental', "$full_backup/backup_manifest" ]); +# We used to have a bug where the wrong limit block was calculated for the +# VM fork, so verify that the WAL summary records the correct VM fork +# truncation limit. We can't just check whether the restored VM fork is +# the right size on disk, because it's so small that the incremental backup +# code will send the entire file. +my $relfilenode = $primary->safe_psql('postgres', + "SELECT pg_relation_filenode('t');"); +my $vm_limits = $primary->safe_psql('postgres', + "SELECT string_agg(relblocknumber::text, ',') + FROM pg_available_wal_summaries() s, + pg_wal_summary_contents(s.tli, s.start_lsn, s.end_lsn) c + WHERE c.relfilenode = $relfilenode + AND c.relforknumber = 2 + AND c.is_limit_block;"); +is($vm_limits, '1', + 'WAL summary has correct VM fork truncation limit'); + # Combine full and incremental backups. Before the fix, this failed because # the INCREMENTAL file header contained an incorrect truncation_block value. my $restored = PostgreSQL::Test::Cluster->new('node2'); diff --git a/src/bin/pg_dump/compress_lz4.c b/src/bin/pg_dump/compress_lz4.c index de947303da7..93233ff3eb2 100644 --- a/src/bin/pg_dump/compress_lz4.c +++ b/src/bin/pg_dump/compress_lz4.c @@ -677,6 +677,7 @@ LZ4Stream_close(CompressFileHandle *CFH) LZ4State *state = (LZ4State *) CFH->private_data; size_t status; int ret; + bool success = true; fp = state->fp; if (state->inited) @@ -688,6 +689,7 @@ LZ4Stream_close(CompressFileHandle *CFH) { pg_log_error("could not end compression: %s", LZ4F_getErrorName(status)); + success = false; } else { @@ -696,20 +698,27 @@ LZ4Stream_close(CompressFileHandle *CFH) { errno = (errno) ? errno : ENOSPC; pg_log_error("could not write to output file: %m"); + success = false; } } status = LZ4F_freeCompressionContext(state->ctx); if (LZ4F_isError(status)) + { pg_log_error("could not end compression: %s", LZ4F_getErrorName(status)); + success = false; + } } else { status = LZ4F_freeDecompressionContext(state->dtx); if (LZ4F_isError(status)) + { pg_log_error("could not end decompression: %s", LZ4F_getErrorName(status)); + success = false; + } pg_free(state->overflowbuf); } @@ -724,10 +733,10 @@ LZ4Stream_close(CompressFileHandle *CFH) if (ret != 0) { pg_log_error("could not close file: %m"); - return false; + success = false; } - return true; + return success; } static bool diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c index a6d4690fd8e..9ad9eeb6bad 100644 --- a/src/bin/pg_dump/pg_backup_archiver.c +++ b/src/bin/pg_dump/pg_backup_archiver.c @@ -43,6 +43,7 @@ #include "pg_backup_archiver.h" #include "pg_backup_db.h" #include "pg_backup_utils.h" +#include "pgtar.h" #define TEXT_DUMP_HEADER "--\n-- PostgreSQL database dump\n--\n\n" #define TEXT_DUMPALL_HEADER "--\n-- PostgreSQL database cluster dump\n--\n\n" @@ -2349,7 +2350,7 @@ _discoverArchiveFormat(ArchiveHandle *AH) } if (!isValidTarHeader(AH->lookahead)) - pg_fatal("input file does not appear to be a valid archive"); + pg_fatal("input file does not appear to be a valid tar archive"); AH->format = archTar; } diff --git a/src/bin/pg_dump/pg_backup_archiver.h b/src/bin/pg_dump/pg_backup_archiver.h index 325b53fc9bd..c01d450697f 100644 --- a/src/bin/pg_dump/pg_backup_archiver.h +++ b/src/bin/pg_dump/pg_backup_archiver.h @@ -464,8 +464,6 @@ extern void InitArchiveFmt_Null(ArchiveHandle *AH); extern void InitArchiveFmt_Directory(ArchiveHandle *AH); extern void InitArchiveFmt_Tar(ArchiveHandle *AH); -extern bool isValidTarHeader(char *header); - extern void ReconnectToServer(ArchiveHandle *AH, const char *dbname); extern void IssueCommandPerBlob(ArchiveHandle *AH, TocEntry *te, const char *cmdBegin, const char *cmdEnd); diff --git a/src/bin/pg_dump/pg_backup_tar.c b/src/bin/pg_dump/pg_backup_tar.c index b5ba3b46dd9..ec42a2cb19d 100644 --- a/src/bin/pg_dump/pg_backup_tar.c +++ b/src/bin/pg_dump/pg_backup_tar.c @@ -984,31 +984,6 @@ tarPrintf(TAR_MEMBER *th, const char *fmt,...) return (int) cnt; } -bool -isValidTarHeader(char *header) -{ - int sum; - int chk = tarChecksum(header); - - sum = read_tar_number(&header[TAR_OFFSET_CHECKSUM], 8); - - if (sum != chk) - return false; - - /* POSIX tar format */ - if (memcmp(&header[TAR_OFFSET_MAGIC], "ustar\0", 6) == 0 && - memcmp(&header[TAR_OFFSET_VERSION], "00", 2) == 0) - return true; - /* GNU tar format */ - if (memcmp(&header[TAR_OFFSET_MAGIC], "ustar \0", 8) == 0) - return true; - /* not-quite-POSIX format written by pre-9.3 pg_dump */ - if (memcmp(&header[TAR_OFFSET_MAGIC], "ustar00\0", 8) == 0) - return true; - - return false; -} - /* Given the member, write the TAR header & copy the file */ static void _tarAddFile(ArchiveHandle *AH, TAR_MEMBER *th) diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 95e96aae9db..b9c9785bc4c 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -10087,7 +10087,7 @@ determineNotNullFlags(Archive *fout, PGresult *res, int r, */ if ((dopt->binary_upgrade && !tbinfo->ispartition && - !tbinfo->notnull_islocal) || + !tbinfo->notnull_islocal[j]) || !PQgetisnull(res, r, i_notnull_comment)) { tbinfo->notnull_constrs[j] = @@ -17539,6 +17539,9 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo) appendPQExpBuffer(q, "CONSTRAINT %s NOT NULL %s", tbinfo->notnull_constrs[j], fmtId(tbinfo->attnames[j])); + + if (tbinfo->notnull_noinh[j]) + appendPQExpBufferStr(q, " NO INHERIT"); } } diff --git a/src/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.c index 266c24a304d..a5d9a5426bc 100644 --- a/src/bin/pg_dump/pg_dumpall.c +++ b/src/bin/pg_dump/pg_dumpall.c @@ -1065,7 +1065,7 @@ dumpRoleMembership(PGconn *conn) * that no longer exist. If we find such cases, print a warning and skip * the entry. */ - dump_grantors = (PQserverVersion(conn) >= 160000); + dump_grantors = (server_version >= 160000); /* * Previous versions of PostgreSQL also did not have grant-level options. @@ -1130,7 +1130,7 @@ dumpRoleMembership(PGconn *conn) if (PQgetisnull(res, start, i_role)) { /* translator: %s represents a numeric role OID */ - pg_log_warning("found orphaned pg_auth_members entry for role %s", + pg_log_warning("ignoring role grant for missing role with OID %s", PQgetvalue(res, start, i_roleid)); break; } @@ -1147,6 +1147,11 @@ dumpRoleMembership(PGconn *conn) remaining = end - start; done = pg_malloc0(remaining * sizeof(bool)); + + /* + * We use a hashtable to track the member names that have been granted + * admin option. Usually a hashtable is overkill, but sometimes not. + */ ht = rolename_create(remaining, NULL); /* @@ -1174,50 +1179,56 @@ dumpRoleMembership(PGconn *conn) for (i = start; i < end; ++i) { char *member; - char *admin_option; char *grantorid; - char *grantor; + char *grantor = NULL; + bool dump_this_grantor = dump_grantors; char *set_option = "true"; + char *admin_option; bool found; /* If we already did this grant, don't do it again. */ if (done[i - start]) continue; - /* Complain about, then ignore, entries with orphaned OIDs. */ + /* Complain about, then ignore, entries for unknown members. */ if (PQgetisnull(res, i, i_member)) { /* translator: %s represents a numeric role OID */ - pg_log_warning("found orphaned pg_auth_members entry for role %s", + pg_log_warning("ignoring role grant to missing role with OID %s", PQgetvalue(res, i, i_memberid)); done[i - start] = true; --remaining; continue; } - if (PQgetisnull(res, i, i_grantor)) + member = PQgetvalue(res, i, i_member); + + /* If the grantor is unknown, complain and dump without it. */ + grantorid = PQgetvalue(res, i, i_grantorid); + if (dump_this_grantor) { - /* translator: %s represents a numeric role OID */ - pg_log_warning("found orphaned pg_auth_members entry for role %s", - PQgetvalue(res, i, i_grantorid)); - done[i - start] = true; - --remaining; - continue; + if (PQgetisnull(res, i, i_grantor)) + { + /* translator: %s represents a numeric role OID */ + pg_log_warning("grant of role \"%s\" to \"%s\" has invalid grantor OID %s", + role, member, grantorid); + pg_log_warning_detail("This grant will be dumped without GRANTED BY."); + dump_this_grantor = false; + } + else + grantor = PQgetvalue(res, i, i_grantor); } - member = PQgetvalue(res, i, i_member); - grantor = PQgetvalue(res, i, i_grantor); - grantorid = PQgetvalue(res, i, i_grantorid); admin_option = PQgetvalue(res, i, i_admin_option); if (dump_grant_options) set_option = PQgetvalue(res, i, i_set_option); /* - * If we're not dumping grantors or if the grantor is the + * If we're not dumping the grantor or if the grantor is the * bootstrap superuser, it's fine to dump this now. Otherwise, * it's got to be someone who has already been granted ADMIN * OPTION. */ - if (dump_grantors && + if (dump_this_grantor && atooid(grantorid) != BOOTSTRAP_SUPERUSERID && rolename_lookup(ht, grantor) == NULL) continue; @@ -1258,7 +1269,7 @@ dumpRoleMembership(PGconn *conn) } if (optbuf->data[0] != '\0') fprintf(OPF, " WITH %s", optbuf->data); - if (dump_grantors) + if (dump_this_grantor) fprintf(OPF, " GRANTED BY %s", fmtId(grantor)); fprintf(OPF, ";\n"); } diff --git a/src/bin/pg_dump/po/de.po b/src/bin/pg_dump/po/de.po index 8fc1b46ebfd..f7b8c7689ae 100644 --- a/src/bin/pg_dump/po/de.po +++ b/src/bin/pg_dump/po/de.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: PostgreSQL 18\n" "Report-Msgid-Bugs-To: pgsql-bugs@lists.postgresql.org\n" -"POT-Creation-Date: 2026-02-04 18:52+0000\n" -"PO-Revision-Date: 2026-02-05 14:55+0100\n" +"POT-Creation-Date: 2026-05-05 12:13+0000\n" +"PO-Revision-Date: 2026-05-06 16:12+0200\n" "Last-Translator: Peter Eisentraut \n" "Language-Team: German \n" "Language: de\n" @@ -39,7 +39,7 @@ msgstr "Tipp: " #: ../../common/compression.c:132 ../../common/compression.c:141 #: ../../common/compression.c:150 compress_gzip.c:441 compress_gzip.c:448 -#: compress_io.c:108 compress_lz4.c:800 compress_lz4.c:807 compress_zstd.c:26 +#: compress_io.c:108 compress_lz4.c:809 compress_lz4.c:816 compress_zstd.c:26 #: compress_zstd.c:32 #, c-format msgid "this build does not support compression with %s" @@ -534,7 +534,7 @@ msgstr "konnte nicht dekomprimieren: %s" msgid "could not free LZ4 decompression context: %s" msgstr "konnte LZ4-Dekomprimierungskontext nicht freigeben: %s" -#: compress_lz4.c:260 compress_lz4.c:267 compress_lz4.c:689 compress_lz4.c:704 +#: compress_lz4.c:260 compress_lz4.c:267 compress_lz4.c:690 compress_lz4.c:708 #, c-format msgid "could not end compression: %s" msgstr "konnte Komprimierung nicht beenden: %s" @@ -559,17 +559,17 @@ msgstr "Fehler beim Schreiben: %s" msgid "error during writing: %m" msgstr "Fehler beim Schreiben: %m" -#: compress_lz4.c:698 +#: compress_lz4.c:700 #, c-format msgid "could not write to output file: %m" msgstr "konnte nicht in Ausgabedatei schreiben: %m" -#: compress_lz4.c:711 +#: compress_lz4.c:718 #, c-format msgid "could not end decompression: %s" msgstr "konnte Dekomprimierung nicht beenden: %s" -#: compress_lz4.c:726 compress_none.c:156 +#: compress_lz4.c:735 compress_none.c:156 #, c-format msgid "could not close file: %m" msgstr "konnte Datei nicht schließen: %m" @@ -630,17 +630,17 @@ msgstr "Abbruch wegen unpassender Serverversion" msgid "server version: %s; %s version: %s" msgstr "Version des Servers: %s; Version von %s: %s" -#: connectdb.c:282 pg_dumpall.c:1790 +#: connectdb.c:282 pg_dumpall.c:1801 #, c-format msgid "executing %s" msgstr "führe %s aus" -#: connectdb.c:288 pg_backup_db.c:210 pg_dumpall.c:1796 +#: connectdb.c:288 pg_backup_db.c:210 pg_dumpall.c:1807 #, c-format msgid "query failed: %s" msgstr "Anfrage fehlgeschlagen: %s" -#: connectdb.c:289 pg_backup_db.c:212 pg_dumpall.c:1797 +#: connectdb.c:289 pg_backup_db.c:212 pg_dumpall.c:1808 #, c-format msgid "Query was: %s" msgstr "Anfrage war: %s" @@ -789,457 +789,457 @@ msgstr "pgpipe: konnte Socket nicht verbinden: Fehlercode %d" msgid "pgpipe: could not accept connection: error code %d" msgstr "pgpipe: konnte Verbindung nicht annehmen: Fehlercode %d" -#: pg_backup_archiver.c:269 pg_backup_archiver.c:1745 +#: pg_backup_archiver.c:270 pg_backup_archiver.c:1746 #, c-format msgid "could not close output file: %m" msgstr "konnte Ausgabedatei nicht schließen: %m" -#: pg_backup_archiver.c:313 pg_backup_archiver.c:317 +#: pg_backup_archiver.c:314 pg_backup_archiver.c:318 #, c-format msgid "archive items not in correct section order" msgstr "Archivelemente nicht in richtiger Abschnittsreihenfolge" -#: pg_backup_archiver.c:323 +#: pg_backup_archiver.c:324 #, c-format msgid "unexpected section code %d" msgstr "unerwarteter Abschnittscode %d" -#: pg_backup_archiver.c:360 +#: pg_backup_archiver.c:361 #, c-format msgid "parallel restore is not supported with this archive file format" msgstr "parallele Wiederherstellung wird von diesem Archivdateiformat nicht unterstützt" -#: pg_backup_archiver.c:364 +#: pg_backup_archiver.c:365 #, c-format msgid "parallel restore is not supported with archives made by pre-8.0 pg_dump" msgstr "parallele Wiederherstellung wird mit Archiven, die mit pg_dump vor 8.0 erstellt worden sind, nicht unterstützt" -#: pg_backup_archiver.c:385 +#: pg_backup_archiver.c:386 #, c-format msgid "cannot restore from compressed archive (%s)" msgstr "kann komprimiertes Archiv nicht wiederherstellen (%s)" -#: pg_backup_archiver.c:405 +#: pg_backup_archiver.c:406 #, c-format msgid "connecting to database for restore" msgstr "verbinde mit der Datenbank zur Wiederherstellung" -#: pg_backup_archiver.c:407 +#: pg_backup_archiver.c:408 #, c-format msgid "direct database connections are not supported in pre-1.3 archives" msgstr "direkte Datenbankverbindungen sind in Archiven vor Version 1.3 nicht unterstützt" -#: pg_backup_archiver.c:450 +#: pg_backup_archiver.c:451 #, c-format msgid "implied no-schema restore" msgstr "implizit wird das Schema nicht wiederhergestellt" -#: pg_backup_archiver.c:529 +#: pg_backup_archiver.c:530 #, c-format msgid "dropping %s %s" msgstr "entferne %s %s" -#: pg_backup_archiver.c:661 +#: pg_backup_archiver.c:662 #, c-format msgid "could not find where to insert IF EXISTS in statement \"%s\"" msgstr "konnte nicht bestimmen, wo IF EXISTS in die Anweisung »%s« eingefügt werden soll" -#: pg_backup_archiver.c:855 pg_backup_archiver.c:857 +#: pg_backup_archiver.c:856 pg_backup_archiver.c:858 #, c-format msgid "warning from original dump file: %s" msgstr "Warnung aus der ursprünglichen Ausgabedatei: %s" -#: pg_backup_archiver.c:891 +#: pg_backup_archiver.c:892 #, c-format msgid "creating %s \"%s.%s\"" msgstr "erstelle %s »%s.%s«" -#: pg_backup_archiver.c:894 +#: pg_backup_archiver.c:895 #, c-format msgid "creating %s \"%s\"" msgstr "erstelle %s »%s«" -#: pg_backup_archiver.c:944 +#: pg_backup_archiver.c:945 #, c-format msgid "connecting to new database \"%s\"" msgstr "verbinde mit neuer Datenbank »%s«" -#: pg_backup_archiver.c:971 +#: pg_backup_archiver.c:972 #, c-format msgid "processing %s" msgstr "verarbeite %s" -#: pg_backup_archiver.c:993 +#: pg_backup_archiver.c:994 #, c-format msgid "processing data for table \"%s.%s\"" msgstr "verarbeite Daten für Tabelle »%s.%s«" -#: pg_backup_archiver.c:1063 +#: pg_backup_archiver.c:1064 #, c-format msgid "executing %s %s" msgstr "führe %s %s aus" -#: pg_backup_archiver.c:1132 +#: pg_backup_archiver.c:1133 #, c-format msgid "disabling triggers for %s" msgstr "schalte Trigger für %s aus" -#: pg_backup_archiver.c:1158 +#: pg_backup_archiver.c:1159 #, c-format msgid "enabling triggers for %s" msgstr "schalte Trigger für %s ein" -#: pg_backup_archiver.c:1223 +#: pg_backup_archiver.c:1224 #, c-format msgid "internal error -- WriteData cannot be called outside the context of a DataDumper routine" msgstr "interner Fehler -- WriteData kann nicht außerhalb des Kontexts einer DataDumper-Routine aufgerufen werden" -#: pg_backup_archiver.c:1418 +#: pg_backup_archiver.c:1419 #, c-format msgid "large-object output not supported in chosen format" msgstr "Large-Object-Ausgabe im gewählten Format nicht unterstützt" -#: pg_backup_archiver.c:1481 +#: pg_backup_archiver.c:1482 #, c-format msgid "restored %d large object" msgid_plural "restored %d large objects" msgstr[0] "%d Large Object wiederhergestellt" msgstr[1] "%d Large Objects wiederhergestellt" -#: pg_backup_archiver.c:1508 pg_backup_tar.c:683 +#: pg_backup_archiver.c:1509 pg_backup_tar.c:683 #, c-format msgid "restoring large object with OID %u" msgstr "Wiederherstellung von Large Object mit OID %u" -#: pg_backup_archiver.c:1520 +#: pg_backup_archiver.c:1521 #, c-format msgid "could not create large object %u: %s" msgstr "konnte Large Object %u nicht erstellen: %s" -#: pg_backup_archiver.c:1525 pg_dump.c:4100 +#: pg_backup_archiver.c:1526 pg_dump.c:4100 #, c-format msgid "could not open large object %u: %s" msgstr "konnte Large Object %u nicht öffnen: %s" -#: pg_backup_archiver.c:1581 +#: pg_backup_archiver.c:1582 #, c-format msgid "could not open TOC file \"%s\": %m" msgstr "konnte Inhaltsverzeichnisdatei »%s« nicht öffnen: %m" -#: pg_backup_archiver.c:1609 +#: pg_backup_archiver.c:1610 #, c-format msgid "line ignored: %s" msgstr "Zeile ignoriert: %s" -#: pg_backup_archiver.c:1616 pg_backup_db.c:548 +#: pg_backup_archiver.c:1617 pg_backup_db.c:548 #, c-format msgid "could not find entry for ID %d" msgstr "konnte Eintrag für ID %d nicht finden" -#: pg_backup_archiver.c:1639 pg_backup_directory.c:187 +#: pg_backup_archiver.c:1640 pg_backup_directory.c:187 #: pg_backup_directory.c:563 #, c-format msgid "could not close TOC file: %m" msgstr "konnte Inhaltsverzeichnisdatei nicht schließen: %m" -#: pg_backup_archiver.c:1726 pg_backup_custom.c:151 pg_backup_directory.c:301 +#: pg_backup_archiver.c:1727 pg_backup_custom.c:151 pg_backup_directory.c:301 #: pg_backup_directory.c:550 pg_backup_directory.c:616 #: pg_backup_directory.c:634 pg_dumpall.c:554 #, c-format msgid "could not open output file \"%s\": %m" msgstr "konnte Ausgabedatei »%s« nicht öffnen: %m" -#: pg_backup_archiver.c:1728 pg_backup_custom.c:157 +#: pg_backup_archiver.c:1729 pg_backup_custom.c:157 #, c-format msgid "could not open output file: %m" msgstr "konnte Ausgabedatei nicht öffnen: %m" -#: pg_backup_archiver.c:1811 +#: pg_backup_archiver.c:1812 #, c-format msgid "wrote %zu byte of large object data (result = %d)" msgid_plural "wrote %zu bytes of large object data (result = %d)" msgstr[0] "%zu Byte Large-Object-Daten geschrieben (Ergebnis = %d)" msgstr[1] "%zu Bytes Large-Object-Daten geschrieben (Ergebnis = %d)" -#: pg_backup_archiver.c:1817 +#: pg_backup_archiver.c:1818 #, c-format msgid "could not write to large object: %s" msgstr "konnte Large Object nicht schreiben: %s" -#: pg_backup_archiver.c:1907 +#: pg_backup_archiver.c:1908 #, c-format msgid "while INITIALIZING:" msgstr "in Phase INITIALIZING:" -#: pg_backup_archiver.c:1912 +#: pg_backup_archiver.c:1913 #, c-format msgid "while PROCESSING TOC:" msgstr "in Phase PROCESSING TOC:" -#: pg_backup_archiver.c:1917 +#: pg_backup_archiver.c:1918 #, c-format msgid "while FINALIZING:" msgstr "in Phase FINALIZING:" -#: pg_backup_archiver.c:1922 +#: pg_backup_archiver.c:1923 #, c-format msgid "from TOC entry %d; %u %u %s %s %s" msgstr "in Inhaltsverzeichniseintrag %d; %u %u %s %s %s" -#: pg_backup_archiver.c:1998 +#: pg_backup_archiver.c:1999 #, c-format msgid "bad dumpId" msgstr "ungültige DumpId" -#: pg_backup_archiver.c:2019 +#: pg_backup_archiver.c:2020 #, c-format msgid "bad table dumpId for TABLE DATA item" msgstr "ungültige Tabellen-DumpId für »TABLE DATA«-Eintrag" -#: pg_backup_archiver.c:2111 +#: pg_backup_archiver.c:2112 #, c-format msgid "unexpected data offset flag %d" msgstr "unerwartete Datenoffsetmarkierung %d" -#: pg_backup_archiver.c:2124 +#: pg_backup_archiver.c:2125 #, c-format msgid "file offset in dump file is too large" msgstr "Dateioffset in Dumpdatei ist zu groß" -#: pg_backup_archiver.c:2235 +#: pg_backup_archiver.c:2236 #, c-format msgid "directory name too long: \"%s\"" msgstr "Verzeichnisname zu lang: »%s«" -#: pg_backup_archiver.c:2285 +#: pg_backup_archiver.c:2286 #, c-format msgid "directory \"%s\" does not appear to be a valid archive (\"toc.dat\" does not exist)" msgstr "Verzeichnis »%s« scheint kein gültiges Archiv zu sein (»toc.dat« existiert nicht)" -#: pg_backup_archiver.c:2293 pg_backup_custom.c:168 pg_backup_custom.c:813 +#: pg_backup_archiver.c:2294 pg_backup_custom.c:168 pg_backup_custom.c:813 #: pg_backup_directory.c:172 pg_backup_directory.c:358 #, c-format msgid "could not open input file \"%s\": %m" msgstr "konnte Eingabedatei »%s« nicht öffnen: %m" -#: pg_backup_archiver.c:2300 pg_backup_custom.c:174 +#: pg_backup_archiver.c:2301 pg_backup_custom.c:174 #, c-format msgid "could not open input file: %m" msgstr "konnte Eingabedatei nicht öffnen: %m" -#: pg_backup_archiver.c:2306 +#: pg_backup_archiver.c:2307 #, c-format msgid "could not read input file: %m" msgstr "konnte Eingabedatei nicht lesen: %m" -#: pg_backup_archiver.c:2308 +#: pg_backup_archiver.c:2309 #, c-format msgid "input file is too short (read %lu, expected 5)" msgstr "Eingabedatei ist zu kurz (gelesen: %lu, erwartet: 5)" -#: pg_backup_archiver.c:2340 +#: pg_backup_archiver.c:2341 #, c-format msgid "input file appears to be a text format dump. Please use psql." msgstr "Eingabedatei ist anscheinend ein Dump im Textformat. Bitte verwenden Sie psql." -#: pg_backup_archiver.c:2346 +#: pg_backup_archiver.c:2347 #, c-format msgid "input file does not appear to be a valid archive (too short?)" msgstr "Eingabedatei scheint kein gültiges Archiv zu sein (zu kurz?)" -#: pg_backup_archiver.c:2352 +#: pg_backup_archiver.c:2353 #, c-format -msgid "input file does not appear to be a valid archive" -msgstr "Eingabedatei scheint kein gültiges Archiv zu sein" +msgid "input file does not appear to be a valid tar archive" +msgstr "Eingabedatei scheint kein gültiges Tar-Archiv zu sein" -#: pg_backup_archiver.c:2361 +#: pg_backup_archiver.c:2362 #, c-format msgid "could not close input file: %m" msgstr "konnte Eingabedatei nicht schließen: %m" -#: pg_backup_archiver.c:2440 +#: pg_backup_archiver.c:2441 #, c-format msgid "could not open stdout for appending: %m" msgstr "konnte Standardausgabe nicht zum Anhängen öffnen: %m" -#: pg_backup_archiver.c:2485 +#: pg_backup_archiver.c:2486 #, c-format msgid "unrecognized file format \"%d\"" msgstr "nicht erkanntes Dateiformat »%d«" -#: pg_backup_archiver.c:2566 pg_backup_archiver.c:4797 +#: pg_backup_archiver.c:2567 pg_backup_archiver.c:4798 #, c-format msgid "finished item %d %s %s" msgstr "Element %d %s %s abgeschlossen" -#: pg_backup_archiver.c:2570 pg_backup_archiver.c:4810 +#: pg_backup_archiver.c:2571 pg_backup_archiver.c:4811 #, c-format msgid "worker process failed: exit code %d" msgstr "Arbeitsprozess fehlgeschlagen: Code %d" -#: pg_backup_archiver.c:2668 +#: pg_backup_archiver.c:2669 #, c-format msgid "unexpected TOC entry in WriteToc(): %d %s %s" msgstr "unerwarteter TOC-Eintrag in WriteToc(): %d %s %s" -#: pg_backup_archiver.c:2672 pg_backup_custom.c:440 pg_backup_custom.c:506 -#: pg_backup_custom.c:635 pg_backup_custom.c:871 pg_backup_tar.c:1029 -#: pg_backup_tar.c:1034 +#: pg_backup_archiver.c:2673 pg_backup_custom.c:440 pg_backup_custom.c:506 +#: pg_backup_custom.c:635 pg_backup_custom.c:871 pg_backup_tar.c:1004 +#: pg_backup_tar.c:1009 #, c-format msgid "error during file seek: %m" msgstr "Fehler beim Suchen in Datei: %m" -#: pg_backup_archiver.c:2730 +#: pg_backup_archiver.c:2731 #, c-format msgid "entry ID %d out of range -- perhaps a corrupt TOC" msgstr "ID %d des Eintrags außerhalb des gültigen Bereichs -- vielleicht ein verfälschtes Inhaltsverzeichnis" -#: pg_backup_archiver.c:2813 +#: pg_backup_archiver.c:2814 #, c-format msgid "restoring tables WITH OIDS is not supported anymore" msgstr "Wiederherstellung von Tabellen mit WITH OIDS wird nicht mehr unterstützt" -#: pg_backup_archiver.c:2895 +#: pg_backup_archiver.c:2896 #, c-format msgid "unrecognized encoding \"%s\"" msgstr "nicht erkannte Kodierung »%s«" -#: pg_backup_archiver.c:2901 +#: pg_backup_archiver.c:2902 #, c-format msgid "invalid ENCODING item: %s" msgstr "ungültiger ENCODING-Eintrag: %s" -#: pg_backup_archiver.c:2919 +#: pg_backup_archiver.c:2920 #, c-format msgid "invalid STDSTRINGS item: %s" msgstr "ungültiger STDSTRINGS-Eintrag: %s" -#: pg_backup_archiver.c:2944 +#: pg_backup_archiver.c:2945 #, c-format msgid "schema \"%s\" not found" msgstr "Schema »%s« nicht gefunden" -#: pg_backup_archiver.c:2951 +#: pg_backup_archiver.c:2952 #, c-format msgid "table \"%s\" not found" msgstr "Tabelle »%s« nicht gefunden" -#: pg_backup_archiver.c:2958 +#: pg_backup_archiver.c:2959 #, c-format msgid "index \"%s\" not found" msgstr "Index »%s« nicht gefunden" -#: pg_backup_archiver.c:2965 +#: pg_backup_archiver.c:2966 #, c-format msgid "function \"%s\" not found" msgstr "Funktion »%s« nicht gefunden" -#: pg_backup_archiver.c:2972 +#: pg_backup_archiver.c:2973 #, c-format msgid "trigger \"%s\" not found" msgstr "Trigger »%s« nicht gefunden" -#: pg_backup_archiver.c:3469 +#: pg_backup_archiver.c:3470 #, c-format msgid "could not set session user to \"%s\": %s" msgstr "konnte Sitzungsbenutzer nicht auf »%s« setzen: %s" -#: pg_backup_archiver.c:3611 +#: pg_backup_archiver.c:3612 #, c-format msgid "could not set \"search_path\" to \"%s\": %s" msgstr "konnte »search_path« nicht auf »%s« setzen: %s" -#: pg_backup_archiver.c:3672 +#: pg_backup_archiver.c:3673 #, c-format msgid "could not set \"default_tablespace\" to %s: %s" msgstr "konnte »default_tablespace« nicht auf »%s« setzen: %s" -#: pg_backup_archiver.c:3721 +#: pg_backup_archiver.c:3722 #, c-format msgid "could not set \"default_table_access_method\": %s" msgstr "konnte »default_table_access_method« nicht setzen: %s" -#: pg_backup_archiver.c:3770 +#: pg_backup_archiver.c:3771 #, c-format msgid "could not alter table access method: %s" msgstr "konnte Tabellenzugriffsmethode nicht ändern: %s" -#: pg_backup_archiver.c:3871 +#: pg_backup_archiver.c:3872 #, c-format msgid "don't know how to set owner for object type \"%s\"" msgstr "kann Eigentümer für Objekttyp »%s« nicht setzen" -#: pg_backup_archiver.c:4006 +#: pg_backup_archiver.c:4007 #, c-format msgid "unexpected TOC entry in _printTocEntry(): %d %s %s" msgstr "unerwarteter TOC-Eintrag in _printTocEntry(): %d %s %s" -#: pg_backup_archiver.c:4154 +#: pg_backup_archiver.c:4155 #, c-format msgid "did not find magic string in file header" msgstr "magische Zeichenkette im Dateikopf nicht gefunden" -#: pg_backup_archiver.c:4168 +#: pg_backup_archiver.c:4169 #, c-format msgid "unsupported version (%d.%d) in file header" msgstr "nicht unterstützte Version (%d.%d) im Dateikopf" -#: pg_backup_archiver.c:4173 +#: pg_backup_archiver.c:4174 #, c-format msgid "sanity check on integer size (%lu) failed" msgstr "Prüfung der Integer-Größe (%lu) fehlgeschlagen" -#: pg_backup_archiver.c:4177 +#: pg_backup_archiver.c:4178 #, c-format msgid "archive was made on a machine with larger integers, some operations might fail" msgstr "Archiv wurde auf einer Maschine mit größeren Integers erstellt; einige Operationen könnten fehlschlagen" -#: pg_backup_archiver.c:4187 +#: pg_backup_archiver.c:4188 #, c-format msgid "expected format (%d) differs from format found in file (%d)" msgstr "erwartetes Format (%d) ist nicht das gleiche wie das in der Datei gefundene (%d)" -#: pg_backup_archiver.c:4209 +#: pg_backup_archiver.c:4210 #, c-format msgid "archive is compressed, but this installation does not support compression (%s) -- no data will be available" msgstr "Archiv ist komprimiert, aber diese Installation unterstützt keine Komprimierung (%s) -- keine Daten verfügbar" -#: pg_backup_archiver.c:4245 +#: pg_backup_archiver.c:4246 #, c-format msgid "invalid creation date in header" msgstr "ungültiges Erstellungsdatum im Kopf" -#: pg_backup_archiver.c:4379 +#: pg_backup_archiver.c:4380 #, c-format msgid "processing item %d %s %s" msgstr "verarbeite Element %d %s %s" -#: pg_backup_archiver.c:4464 +#: pg_backup_archiver.c:4465 #, c-format msgid "entering main parallel loop" msgstr "Eintritt in Hauptparallelschleife" -#: pg_backup_archiver.c:4475 +#: pg_backup_archiver.c:4476 #, c-format msgid "skipping item %d %s %s" msgstr "Element %d %s %s wird übersprungen" -#: pg_backup_archiver.c:4484 +#: pg_backup_archiver.c:4485 #, c-format msgid "launching item %d %s %s" msgstr "starte Element %d %s %s" -#: pg_backup_archiver.c:4538 +#: pg_backup_archiver.c:4539 #, c-format msgid "finished main parallel loop" msgstr "Hauptparallelschleife beendet" -#: pg_backup_archiver.c:4574 +#: pg_backup_archiver.c:4575 #, c-format msgid "processing missed item %d %s %s" msgstr "verarbeite verpasstes Element %d %s %s" -#: pg_backup_archiver.c:5116 +#: pg_backup_archiver.c:5117 #, c-format msgid "table \"%s\" could not be created, will not restore its data" msgstr "Tabelle »%s« konnte nicht erzeugt werden, ihre Daten werden nicht wiederhergestellt werden" @@ -1280,7 +1280,7 @@ msgid "unrecognized data block type %d while restoring archive" msgstr "unerkannter Datenblocktyp %d beim Wiederherstellen des Archivs gefunden" #: pg_backup_custom.c:750 pg_backup_custom.c:804 pg_backup_custom.c:946 -#: pg_backup_tar.c:1032 +#: pg_backup_tar.c:1007 #, c-format msgid "could not determine seek position in archive file: %m" msgstr "konnte Positionszeiger in Archivdatei nicht ermitteln: %m" @@ -1470,34 +1470,34 @@ msgstr "unerwartete Syntax der COPY-Anweisung: »%s«" msgid "invalid OID for large object (%u)" msgstr "Large Object hat ungültige OID (%u)" -#: pg_backup_tar.c:1048 +#: pg_backup_tar.c:1023 #, c-format msgid "could not close temporary file: %m" msgstr "konnte temporäre Datei nicht schließen: %m" -#: pg_backup_tar.c:1051 +#: pg_backup_tar.c:1026 #, c-format msgid "actual file length (%lld) does not match expected (%lld)" msgstr "tatsächliche Dateilänge (%lld) stimmt nicht mit erwarteter Länge (%lld) überein" -#: pg_backup_tar.c:1097 pg_backup_tar.c:1128 +#: pg_backup_tar.c:1072 pg_backup_tar.c:1103 #, c-format msgid "could not find header for file \"%s\" in tar archive" msgstr "konnte Kopf für Datei »%s« im Tar-Archiv nicht finden" -#: pg_backup_tar.c:1115 +#: pg_backup_tar.c:1090 #, c-format msgid "restoring data out of order is not supported in this archive format: \"%s\" is required, but comes before \"%s\" in the archive file." msgstr "Ausgabe der Daten in anderer Reihenfolge wird in diesem Archivformat nicht unterstützt: »%s« wird benötigt, aber es kommt vor »%s« in der Archivdatei." -#: pg_backup_tar.c:1162 +#: pg_backup_tar.c:1137 #, c-format msgid "incomplete tar header found (%lu byte)" msgid_plural "incomplete tar header found (%lu bytes)" msgstr[0] "unvollständiger Tar-Dateikopf gefunden (%lu Byte)" msgstr[1] "unvollständiger Tar-Dateikopf gefunden (%lu Bytes)" -#: pg_backup_tar.c:1201 +#: pg_backup_tar.c:1176 #, c-format msgid "corrupt tar header found in %s (expected %d, computed %d) file position %llu" msgstr "beschädigter Tar-Kopf in %s gefunden (%d erwartet, %d berechnet), Dateiposition %llu" @@ -2131,7 +2131,7 @@ msgstr "parallele Dumps von Standby-Servern werden von dieser Serverversion nich msgid "invalid output format \"%s\" specified" msgstr "ungültiges Ausgabeformat »%s« angegeben" -#: pg_dump.c:1641 pg_dump.c:1697 pg_dump.c:1750 pg_dumpall.c:1594 +#: pg_dump.c:1641 pg_dump.c:1697 pg_dump.c:1750 pg_dumpall.c:1605 #, c-format msgid "improper qualified name (too many dotted names): %s" msgstr "falscher qualifizierter Name (zu viele Namensteile): %s" @@ -2256,8 +2256,8 @@ msgstr "lese Policys für Sicherheit auf Zeilenebene" msgid "unexpected policy command type: %c" msgstr "unerwarteter Policy-Befehlstyp: %c" -#: pg_dump.c:4801 pg_dump.c:5358 pg_dump.c:7987 pg_dump.c:13467 pg_dump.c:19678 -#: pg_dump.c:19680 pg_dump.c:20312 +#: pg_dump.c:4801 pg_dump.c:5358 pg_dump.c:7987 pg_dump.c:13467 pg_dump.c:19681 +#: pg_dump.c:19683 pg_dump.c:20315 #, c-format msgid "could not parse %s array" msgstr "konnte %s-Array nicht interpretieren" @@ -2292,7 +2292,7 @@ msgstr "Schema mit OID %u existiert nicht" msgid "cannot dump statistics for relation kind \"%c\"" msgstr "für Relationstyp »%c« können keine Statistiken ausgegeben werden" -#: pg_dump.c:7521 pg_dump.c:19005 +#: pg_dump.c:7521 pg_dump.c:19008 #, c-format msgid "failed sanity check, parent table with OID %u of sequence with OID %u not found" msgstr "Sanity-Check fehlgeschlagen, Elterntabelle mit OID %u von Sequenz mit OID %u nicht gefunden" @@ -2511,89 +2511,89 @@ msgstr "Definition der Sicht »%s« scheint leer zu sein (Länge null)" msgid "WITH OIDS is not supported anymore (table \"%s\")" msgstr "WITH OIDS wird nicht mehr unterstützt (Tabelle »%s«)" -#: pg_dump.c:18082 +#: pg_dump.c:18085 #, c-format msgid "invalid column number %d for table \"%s\"" msgstr "ungültige Spaltennummer %d in Tabelle »%s«" -#: pg_dump.c:18160 +#: pg_dump.c:18163 #, c-format msgid "could not parse index statistic columns" msgstr "konnte Indexstatistikspalten nicht interpretieren" -#: pg_dump.c:18162 +#: pg_dump.c:18165 #, c-format msgid "could not parse index statistic values" msgstr "konnte Indexstatistikwerte nicht interpretieren" -#: pg_dump.c:18164 +#: pg_dump.c:18167 #, c-format msgid "mismatched number of columns and values for index statistics" msgstr "Anzahl Spalten und Werte für Indexstatistiken stimmt nicht überein" -#: pg_dump.c:18393 +#: pg_dump.c:18396 #, c-format msgid "missing index for constraint \"%s\"" msgstr "fehlender Index für Constraint »%s«" -#: pg_dump.c:18662 +#: pg_dump.c:18665 #, c-format msgid "unrecognized constraint type: %c" msgstr "unbekannter Constraint-Typ: %c" -#: pg_dump.c:18715 +#: pg_dump.c:18718 #, c-format msgid "unrecognized sequence type: %s" msgstr "unbekannter Sequenztyp: %s" -#: pg_dump.c:18848 pg_dump.c:19086 +#: pg_dump.c:18851 pg_dump.c:19089 #, c-format msgid "query to get data of sequence \"%s\" returned %d row (expected 1)" msgid_plural "query to get data of sequence \"%s\" returned %d rows (expected 1)" msgstr[0] "Anfrage nach Daten der Sequenz %s ergab %d Zeile (erwartete 1)" msgstr[1] "Anfrage nach Daten der Sequenz %s ergab %d Zeilen (erwartete 1)" -#: pg_dump.c:18884 +#: pg_dump.c:18887 #, c-format msgid "unrecognized sequence type: %d" msgstr "unbekannter Sequenztyp: %d" -#: pg_dump.c:19109 +#: pg_dump.c:19112 #, c-format msgid "failed to get data for sequence \"%s\"; user may lack SELECT privilege on the sequence or the sequence may have been concurrently dropped" msgstr "konnte Daten für Sequenz »%s« nicht ermitteln; möglicherweise hat der Anwender nicht das SELECT-Privileg für die Sequenz oder die Sequenz würde möglicherweise gleichzeitig gelöscht" -#: pg_dump.c:19430 +#: pg_dump.c:19433 #, c-format msgid "query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned" msgstr "Anfrage nach Regel »%s« der Tabelle »%s« fehlgeschlagen: falsche Anzahl Zeilen zurückgegeben" -#: pg_dump.c:19583 +#: pg_dump.c:19586 #, c-format msgid "could not find referenced extension %u" msgstr "konnte referenzierte Erweiterung %u nicht finden" -#: pg_dump.c:19682 +#: pg_dump.c:19685 #, c-format msgid "mismatched number of configurations and conditions for extension" msgstr "Anzahl Konfigurationen und Bedingungen für Erweiterung stimmt nicht überein" -#: pg_dump.c:19814 +#: pg_dump.c:19817 #, c-format msgid "reading dependency data" msgstr "lese Abhängigkeitsdaten" -#: pg_dump.c:19900 +#: pg_dump.c:19903 #, c-format msgid "no referencing object %u %u" msgstr "kein referenzierendes Objekt %u %u" -#: pg_dump.c:19911 +#: pg_dump.c:19914 #, c-format msgid "no referenced object %u %u" msgstr "kein referenziertes Objekt %u %u" -#: pg_dump.c:20346 pg_dump.c:20384 pg_dumpall.c:1842 pg_restore.c:642 +#: pg_dump.c:20349 pg_dump.c:20387 pg_dumpall.c:1853 pg_restore.c:642 #: pg_restore.c:688 #, c-format msgid "%s filter for \"%s\" is not allowed" @@ -2763,52 +2763,69 @@ msgid "role name starting with \"pg_\" skipped (%s)" msgstr "mit »pg_« anfangender Rollenname übersprungen (%s)" #. translator: %s represents a numeric role OID -#: pg_dumpall.c:1127 pg_dumpall.c:1185 pg_dumpall.c:1194 +#: pg_dumpall.c:1127 #, c-format -msgid "found orphaned pg_auth_members entry for role %s" -msgstr "verwaister pg_auth_members-Eintrag für Rolle %s gefunden" +msgid "ignoring role grant for missing role with OID %s" +msgstr "Rollen-Grant für fehlende Rolle mit OID %s wird ignoriert" -#: pg_dumpall.c:1160 +#: pg_dumpall.c:1165 #, c-format msgid "could not find a legal dump ordering for memberships in role \"%s\"" msgstr "konnte keine legale Dump-Reihenfolge für Mitgliedschaften in Rolle »%s« finden" -#: pg_dumpall.c:1315 +#. translator: %s represents a numeric role OID +#: pg_dumpall.c:1191 +#, c-format +msgid "ignoring role grant to missing role with OID %s" +msgstr "Rollen-Grant an fehlende Rolle mit OID %s wird ignoriert" + +#. translator: %s represents a numeric role OID +#: pg_dumpall.c:1206 +#, c-format +msgid "grant of role \"%s\" to \"%s\" has invalid grantor OID %s" +msgstr "Grant von Rolle »%s« an »%s« hat ungültige Grantor-OID %s" + +#: pg_dumpall.c:1208 +#, c-format +msgid "This grant will be dumped without GRANTED BY." +msgstr "Dieser Grant wird ohne GRANTED BY ausgegeben werden." + +#: pg_dumpall.c:1326 #, c-format msgid "could not parse ACL list (%s) for parameter \"%s\"" msgstr "konnte ACL-Zeichenkette (%s) für Parameter »%s« nicht interpretieren" -#: pg_dumpall.c:1442 +#: pg_dumpall.c:1453 #, c-format msgid "could not parse ACL list (%s) for tablespace \"%s\"" msgstr "konnte ACL-Zeichenkette (%s) für Tablespace »%s« nicht interpretieren" -#: pg_dumpall.c:1656 +#: pg_dumpall.c:1667 #, c-format msgid "excluding database \"%s\"" msgstr "Datenbank »%s« übersprungen" -#: pg_dumpall.c:1660 +#: pg_dumpall.c:1671 #, c-format msgid "dumping database \"%s\"" msgstr "Ausgabe der Datenbank »%s«" -#: pg_dumpall.c:1693 +#: pg_dumpall.c:1704 #, c-format msgid "pg_dump failed on database \"%s\", exiting" msgstr "pg_dump für Datenbank »%s« fehlgeschlagen; beende" -#: pg_dumpall.c:1699 +#: pg_dumpall.c:1710 #, c-format msgid "could not re-open the output file \"%s\": %m" msgstr "konnte die Ausgabedatei »%s« nicht neu öffnen: %m" -#: pg_dumpall.c:1743 +#: pg_dumpall.c:1754 #, c-format msgid "running \"%s\"" msgstr "führe »%s« aus" -#: pg_dumpall.c:1862 +#: pg_dumpall.c:1873 msgid "unsupported filter object" msgstr "nicht unterstütztes Filterobjekt" @@ -3101,113 +3118,3 @@ msgstr "" "\n" "Wenn keine Eingabedatei angegeben ist, wird die Standardeingabe verwendet.\n" "\n" - -#, c-format -#~ msgid " --exclude-database=PATTERN do not restore the specified database(s)\n" -#~ msgstr " --exclude-database=MUSTER die angegebene(n) Datenbank(en) NICHT wiederherstellen\n" - -#, c-format -#~ msgid " -g, --globals-only restore only global objects, no databases\n" -#~ msgstr " -g, --globals-only nur globale Objekte wiederherstellen, keine Datenbanken\n" - -#, c-format -#~ msgid "Individual databases can be restored using their specific archives." -#~ msgstr "Individuelle Datenbanken können aus ihren eigenen Archiven wiederhergestellt werden." - -#, c-format -#~ msgid "considering PATTERN as NAME for --exclude-database option as no database connection while doing pg_restore" -#~ msgstr "MUSTER wird als NAME betrachtet für Option --exclude-database, weil pg_restore keine Datenbankverbindung hat" - -#, c-format -#~ msgid "could not execute query: %s" -#~ msgstr "konnte Anfrage nicht ausführen: %s" - -#, c-format -#~ msgid "could not open file: \"%s\"" -#~ msgstr "konnte Datei nicht öffnen: »%s«" - -#, c-format -#~ msgid "database name \"%s\" matches exclude pattern \"%s\"" -#~ msgstr "Datenbankname »%s« stimmt mit Ausschlussmuster »%s« überein" - -#, c-format -#~ msgid "database restoring is skipped because file \"%s\" does not exist in directory \"%s\"" -#~ msgstr "Wiederherstellung der Datenbank übersprungen, weil Datei »%s« nicht in Verzeichnis »%s« existiert" - -#, c-format -#~ msgid "database restoring skipped because option -g/--globals-only was specified" -#~ msgstr "Wiederherstellung der Datenbank wurde übersprungen, weil Option -g/--globals-only angegeben wurde" - -#, c-format -#~ msgid "errors ignored on database \"%s\" restore: %d" -#~ msgstr "bei Wiederherstellung von Datenbank »%s« ignorierte Fehler: %d" - -#, c-format -#~ msgid "executing query: %s" -#~ msgstr "führe Anfrage aus: %s" - -#, c-format -#~ msgid "found %d database name in \"%s\"" -#~ msgid_plural "found %d database names in \"%s\"" -#~ msgstr[0] "%d Datenbankname in »%s« gefunden" -#~ msgstr[1] "%d Datenbanknamen in »%s« gefunden" - -#, c-format -#~ msgid "found database \"%s\" (OID: %u) in file \"%s\"" -#~ msgstr "Datenbank »%s« (OID: %u) in Datei »%s« gefunden" - -#, c-format -#~ msgid "ignored %d error in file \"%s\"" -#~ msgid_plural "ignored %d errors in file \"%s\"" -#~ msgstr[0] "%d Fehler in Datei »%s« ignoriert" -#~ msgstr[1] "%d Fehler in Datei »%s« ignoriert" - -#, c-format -#~ msgid "invalid entry in file \"%s\" on line %d" -#~ msgstr "ungültiger Eintrag in Datei »%s« auf Zeile %d" - -#, c-format -#~ msgid "need to restore %d databases out of %d databases" -#~ msgstr "%d Datenbanken aus %d Datenbanken müssen wiederhergestellt werden" - -#, c-format -#~ msgid "no database needs restoring out of %d database" -#~ msgid_plural "no database needs restoring out of %d databases" -#~ msgstr[0] "keine Datenbank aus %d Datenbank muss wiederhergestellt werden" -#~ msgstr[1] "keine Datenbank aus %d Datenbanken muss wiederhergestellt werden" - -#, c-format -#~ msgid "number of restored databases is %d" -#~ msgstr "Anzahl wiederhergestellter Datenbanken ist %d" - -#, c-format -#~ msgid "option --exclude-database can be used only when restoring an archive created by pg_dumpall" -#~ msgstr "Option --exclude-database kann nur verwendet werden, wenn ein von pg_dumpall erzeugtes Archiv wiederhergestellt wird" - -#, c-format -#~ msgid "option -C/--create must be specified when restoring an archive created by pg_dumpall" -#~ msgstr "Option -C/--create muss angegeben werden, wenn ein von pg_dumpall erzeugtes Archiv wiederhergestellt wird" - -#, c-format -#~ msgid "option -L/--use-list cannot be used when restoring an archive created by pg_dumpall" -#~ msgstr "Option -L/--use-list kann nicht verwendet werden, wenn ein von pg_dumpall erzeugtes Archiv wiederhergestellt wird" - -#, c-format -#~ msgid "option -g/--globals-only can be used only when restoring an archive created by pg_dumpall" -#~ msgstr "Option -g/--globals-only kann nur verwendet werden, wenn ein von pg_dumpall erzeugtes Archiv wiederhergestellt wird" - -#, c-format -#~ msgid "option -l/--list cannot be used when restoring an archive created by pg_dumpall" -#~ msgstr "Option -l/--list kann nicht verwendet werden, wenn ein von pg_dumpall erzeugtes Archiv wiederhergestellt wird" - -#, c-format -#~ msgid "restoring database \"%s\"" -#~ msgstr "Datenbank »%s« wird wiederhergestellt" - -#, c-format -#~ msgid "trying to connect to database \"%s\"" -#~ msgstr "versuche mit Datenbank »%s« zu verbinden" - -#, c-format -#~ msgid "unrecognized output format \"%s\"; please specify \"c\", \"d\", \"p\", or \"t\"" -#~ msgstr "unbekanntes Ausgabeformat »%s«; bitte »c«, »d«, »p« oder »t« angeben" diff --git a/src/bin/pg_dump/po/fr.po b/src/bin/pg_dump/po/fr.po index d07470743f0..79f16a5faa6 100644 --- a/src/bin/pg_dump/po/fr.po +++ b/src/bin/pg_dump/po/fr.po @@ -12,8 +12,8 @@ msgid "" msgstr "" "Project-Id-Version: PostgreSQL 17\n" "Report-Msgid-Bugs-To: pgsql-bugs@lists.postgresql.org\n" -"POT-Creation-Date: 2026-02-18 04:51+0000\n" -"PO-Revision-Date: 2026-02-18 14:30+0100\n" +"POT-Creation-Date: 2026-05-08 18:52+0000\n" +"PO-Revision-Date: 2026-05-08 21:51+0200\n" "Last-Translator: Guillaume Lelarge \n" "Language-Team: French \n" "Language: fr\n" @@ -21,7 +21,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" -"X-Generator: Poedit 3.8\n" +"X-Generator: Poedit 3.9\n" #: ../../../src/common/logging.c:279 #, c-format @@ -45,7 +45,7 @@ msgstr "astuce : " #: ../../common/compression.c:132 ../../common/compression.c:141 #: ../../common/compression.c:150 compress_gzip.c:441 compress_gzip.c:448 -#: compress_io.c:108 compress_lz4.c:800 compress_lz4.c:807 compress_zstd.c:26 +#: compress_io.c:108 compress_lz4.c:809 compress_lz4.c:816 compress_zstd.c:26 #: compress_zstd.c:32 #, c-format msgid "this build does not support compression with %s" @@ -540,7 +540,7 @@ msgstr "n'a pas pu décompresser : %s" msgid "could not free LZ4 decompression context: %s" msgstr "n'a pas pu libérer le contexte de décompression LZ4 : %s" -#: compress_lz4.c:260 compress_lz4.c:267 compress_lz4.c:689 compress_lz4.c:704 +#: compress_lz4.c:260 compress_lz4.c:267 compress_lz4.c:690 compress_lz4.c:708 #, c-format msgid "could not end compression: %s" msgstr "n'a pas pu terminer la compression : %s" @@ -565,17 +565,17 @@ msgstr "erreur lors de l'écriture : %s" msgid "error during writing: %m" msgstr "erreur lors de l'écriture : %m" -#: compress_lz4.c:698 +#: compress_lz4.c:700 #, c-format msgid "could not write to output file: %m" msgstr "n'a pas pu écrire dans le fichier en sortie : %m" -#: compress_lz4.c:711 +#: compress_lz4.c:718 #, c-format msgid "could not end decompression: %s" msgstr "n'a pas pu terminer la décompression : %s" -#: compress_lz4.c:726 compress_none.c:156 +#: compress_lz4.c:735 compress_none.c:156 #, c-format msgid "could not close file: %m" msgstr "n'a pas pu fermer le fichier : %m" @@ -636,17 +636,17 @@ msgstr "annulation à cause de la différence des versions" msgid "server version: %s; %s version: %s" msgstr "version du serveur : %s ; %s version : %s" -#: connectdb.c:282 pg_dumpall.c:1790 +#: connectdb.c:282 pg_dumpall.c:1801 #, c-format msgid "executing %s" msgstr "exécution %s" -#: connectdb.c:288 pg_backup_db.c:210 pg_dumpall.c:1796 +#: connectdb.c:288 pg_backup_db.c:210 pg_dumpall.c:1807 #, c-format msgid "query failed: %s" msgstr "échec de la requête : %s" -#: connectdb.c:289 pg_backup_db.c:212 pg_dumpall.c:1797 +#: connectdb.c:289 pg_backup_db.c:212 pg_dumpall.c:1808 #, c-format msgid "Query was: %s" msgstr "La requête était : %s" @@ -795,457 +795,457 @@ msgstr "pgpipe: n'a pas pu se connecter au socket: code d'erreur %d" msgid "pgpipe: could not accept connection: error code %d" msgstr "pgpipe: n'a pas pu accepter de connexion: code d'erreur %d" -#: pg_backup_archiver.c:269 pg_backup_archiver.c:1745 +#: pg_backup_archiver.c:270 pg_backup_archiver.c:1746 #, c-format msgid "could not close output file: %m" msgstr "n'a pas pu fermer le fichier en sortie : %m" -#: pg_backup_archiver.c:313 pg_backup_archiver.c:317 +#: pg_backup_archiver.c:314 pg_backup_archiver.c:318 #, c-format msgid "archive items not in correct section order" msgstr "les éléments de l'archive ne sont pas dans l'ordre correct de la section" -#: pg_backup_archiver.c:323 +#: pg_backup_archiver.c:324 #, c-format msgid "unexpected section code %d" msgstr "code de section inattendu %d" -#: pg_backup_archiver.c:360 +#: pg_backup_archiver.c:361 #, c-format msgid "parallel restore is not supported with this archive file format" msgstr "la restauration parallélisée n'est pas supportée avec ce format de fichier d'archive" -#: pg_backup_archiver.c:364 +#: pg_backup_archiver.c:365 #, c-format msgid "parallel restore is not supported with archives made by pre-8.0 pg_dump" msgstr "la restauration parallélisée n'est pas supportée avec les archives réalisées par un pg_dump antérieur à la 8.0" -#: pg_backup_archiver.c:385 +#: pg_backup_archiver.c:386 #, c-format msgid "cannot restore from compressed archive (%s)" msgstr "ne peut pas restaurer l'archive compressée (%s)" -#: pg_backup_archiver.c:405 +#: pg_backup_archiver.c:406 #, c-format msgid "connecting to database for restore" msgstr "connexion à la base de données pour la restauration" -#: pg_backup_archiver.c:407 +#: pg_backup_archiver.c:408 #, c-format msgid "direct database connections are not supported in pre-1.3 archives" msgstr "les connexions directes à la base de données ne sont pas supportées dans les archives pre-1.3" -#: pg_backup_archiver.c:450 +#: pg_backup_archiver.c:451 #, c-format msgid "implied no-schema restore" msgstr "a impliqué une restauration sans la structure" -#: pg_backup_archiver.c:529 +#: pg_backup_archiver.c:530 #, c-format msgid "dropping %s %s" msgstr "suppression de %s %s" -#: pg_backup_archiver.c:661 +#: pg_backup_archiver.c:662 #, c-format msgid "could not find where to insert IF EXISTS in statement \"%s\"" msgstr "n'a pas pu trouver où insérer IF EXISTS dans l'instruction « %s »" -#: pg_backup_archiver.c:855 pg_backup_archiver.c:857 +#: pg_backup_archiver.c:856 pg_backup_archiver.c:858 #, c-format msgid "warning from original dump file: %s" msgstr "message d'avertissement du fichier de sauvegarde original : %s" -#: pg_backup_archiver.c:891 +#: pg_backup_archiver.c:892 #, c-format msgid "creating %s \"%s.%s\"" msgstr "création de %s « %s.%s »" -#: pg_backup_archiver.c:894 +#: pg_backup_archiver.c:895 #, c-format msgid "creating %s \"%s\"" msgstr "création de %s « %s »" -#: pg_backup_archiver.c:944 +#: pg_backup_archiver.c:945 #, c-format msgid "connecting to new database \"%s\"" msgstr "connexion à la nouvelle base de données « %s »" -#: pg_backup_archiver.c:971 +#: pg_backup_archiver.c:972 #, c-format msgid "processing %s" msgstr "traitement de %s" -#: pg_backup_archiver.c:993 +#: pg_backup_archiver.c:994 #, c-format msgid "processing data for table \"%s.%s\"" msgstr "traitement des données de la table « %s.%s »" -#: pg_backup_archiver.c:1063 +#: pg_backup_archiver.c:1064 #, c-format msgid "executing %s %s" msgstr "exécution de %s %s" -#: pg_backup_archiver.c:1132 +#: pg_backup_archiver.c:1133 #, c-format msgid "disabling triggers for %s" msgstr "désactivation des triggers pour %s" -#: pg_backup_archiver.c:1158 +#: pg_backup_archiver.c:1159 #, c-format msgid "enabling triggers for %s" msgstr "activation des triggers pour %s" -#: pg_backup_archiver.c:1223 +#: pg_backup_archiver.c:1224 #, c-format msgid "internal error -- WriteData cannot be called outside the context of a DataDumper routine" msgstr "erreur interne -- WriteData ne peut pas être appelé en dehors du contexte de la routine DataDumper" -#: pg_backup_archiver.c:1418 +#: pg_backup_archiver.c:1419 #, c-format msgid "large-object output not supported in chosen format" msgstr "la sauvegarde des « Large Objects » n'est pas supportée dans le format choisi" -#: pg_backup_archiver.c:1481 +#: pg_backup_archiver.c:1482 #, c-format msgid "restored %d large object" msgid_plural "restored %d large objects" msgstr[0] "restauration de %d « Large Object »" msgstr[1] "restauration de %d « Large Objects »" -#: pg_backup_archiver.c:1508 pg_backup_tar.c:683 +#: pg_backup_archiver.c:1509 pg_backup_tar.c:683 #, c-format msgid "restoring large object with OID %u" msgstr "restauration du « Large Object » d'OID %u" -#: pg_backup_archiver.c:1520 +#: pg_backup_archiver.c:1521 #, c-format msgid "could not create large object %u: %s" msgstr "n'a pas pu créer le « Large Object » %u : %s" -#: pg_backup_archiver.c:1525 pg_dump.c:4100 +#: pg_backup_archiver.c:1526 pg_dump.c:4100 #, c-format msgid "could not open large object %u: %s" msgstr "n'a pas pu ouvrir le « Large Object » %u : %s" -#: pg_backup_archiver.c:1581 +#: pg_backup_archiver.c:1582 #, c-format msgid "could not open TOC file \"%s\": %m" msgstr "n'a pas pu ouvrir le fichier TOC « %s » : %m" -#: pg_backup_archiver.c:1609 +#: pg_backup_archiver.c:1610 #, c-format msgid "line ignored: %s" msgstr "ligne ignorée : %s" -#: pg_backup_archiver.c:1616 pg_backup_db.c:548 +#: pg_backup_archiver.c:1617 pg_backup_db.c:548 #, c-format msgid "could not find entry for ID %d" msgstr "n'a pas pu trouver l'entrée pour l'ID %d" -#: pg_backup_archiver.c:1639 pg_backup_directory.c:187 +#: pg_backup_archiver.c:1640 pg_backup_directory.c:187 #: pg_backup_directory.c:563 #, c-format msgid "could not close TOC file: %m" msgstr "n'a pas pu fermer le fichier TOC : %m" -#: pg_backup_archiver.c:1726 pg_backup_custom.c:151 pg_backup_directory.c:301 +#: pg_backup_archiver.c:1727 pg_backup_custom.c:151 pg_backup_directory.c:301 #: pg_backup_directory.c:550 pg_backup_directory.c:616 #: pg_backup_directory.c:634 pg_dumpall.c:554 #, c-format msgid "could not open output file \"%s\": %m" msgstr "n'a pas pu ouvrir le fichier de sauvegarde « %s » : %m" -#: pg_backup_archiver.c:1728 pg_backup_custom.c:157 +#: pg_backup_archiver.c:1729 pg_backup_custom.c:157 #, c-format msgid "could not open output file: %m" msgstr "n'a pas pu ouvrir le fichier de sauvegarde : %m" -#: pg_backup_archiver.c:1811 +#: pg_backup_archiver.c:1812 #, c-format msgid "wrote %zu byte of large object data (result = %d)" msgid_plural "wrote %zu bytes of large object data (result = %d)" msgstr[0] "a écrit %zu octet de données d'un « Large Object » (résultat = %d)" msgstr[1] "a écrit %zu octets de données d'un « Large Object » (résultat = %d)" -#: pg_backup_archiver.c:1817 +#: pg_backup_archiver.c:1818 #, c-format msgid "could not write to large object: %s" msgstr "n'a pas pu écrire dans le « Large Object » : %s" -#: pg_backup_archiver.c:1907 +#: pg_backup_archiver.c:1908 #, c-format msgid "while INITIALIZING:" msgstr "pendant l'initialisation (« INITIALIZING ») :" -#: pg_backup_archiver.c:1912 +#: pg_backup_archiver.c:1913 #, c-format msgid "while PROCESSING TOC:" msgstr "pendant le traitement de la TOC (« PROCESSING TOC ») :" -#: pg_backup_archiver.c:1917 +#: pg_backup_archiver.c:1918 #, c-format msgid "while FINALIZING:" msgstr "pendant la finalisation (« FINALIZING ») :" -#: pg_backup_archiver.c:1922 +#: pg_backup_archiver.c:1923 #, c-format msgid "from TOC entry %d; %u %u %s %s %s" msgstr "de l'entrée TOC %d ; %u %u %s %s %s" -#: pg_backup_archiver.c:1998 +#: pg_backup_archiver.c:1999 #, c-format msgid "bad dumpId" msgstr "mauvais dumpId" -#: pg_backup_archiver.c:2019 +#: pg_backup_archiver.c:2020 #, c-format msgid "bad table dumpId for TABLE DATA item" msgstr "mauvais dumpId de table pour l'élément TABLE DATA" -#: pg_backup_archiver.c:2111 +#: pg_backup_archiver.c:2112 #, c-format msgid "unexpected data offset flag %d" msgstr "drapeau de décalage de données inattendu %d" -#: pg_backup_archiver.c:2124 +#: pg_backup_archiver.c:2125 #, c-format msgid "file offset in dump file is too large" msgstr "le décalage dans le fichier de sauvegarde est trop important" -#: pg_backup_archiver.c:2235 +#: pg_backup_archiver.c:2236 #, c-format msgid "directory name too long: \"%s\"" msgstr "nom du répertoire trop long : « %s »" -#: pg_backup_archiver.c:2285 +#: pg_backup_archiver.c:2286 #, c-format msgid "directory \"%s\" does not appear to be a valid archive (\"toc.dat\" does not exist)" msgstr "le répertoire « %s » ne semble pas être une archive valide (« toc.dat » n'existe pas)" -#: pg_backup_archiver.c:2293 pg_backup_custom.c:168 pg_backup_custom.c:813 +#: pg_backup_archiver.c:2294 pg_backup_custom.c:168 pg_backup_custom.c:813 #: pg_backup_directory.c:172 pg_backup_directory.c:358 #, c-format msgid "could not open input file \"%s\": %m" msgstr "n'a pas pu ouvrir le fichier en entrée « %s » : %m" -#: pg_backup_archiver.c:2300 pg_backup_custom.c:174 +#: pg_backup_archiver.c:2301 pg_backup_custom.c:174 #, c-format msgid "could not open input file: %m" msgstr "n'a pas pu ouvrir le fichier en entrée : %m" -#: pg_backup_archiver.c:2306 +#: pg_backup_archiver.c:2307 #, c-format msgid "could not read input file: %m" msgstr "n'a pas pu lire le fichier en entrée : %m" -#: pg_backup_archiver.c:2308 +#: pg_backup_archiver.c:2309 #, c-format msgid "input file is too short (read %lu, expected 5)" msgstr "le fichier en entrée est trop petit (%lu lus, 5 attendus)" -#: pg_backup_archiver.c:2340 +#: pg_backup_archiver.c:2341 #, c-format msgid "input file appears to be a text format dump. Please use psql." -msgstr "Le fichier en entrée semble être une sauvegarde au format texte. Merci d'utiliser psql." +msgstr "le fichier en entrée semble être une sauvegarde au format texte. Merci d'utiliser psql." -#: pg_backup_archiver.c:2346 +#: pg_backup_archiver.c:2347 #, c-format msgid "input file does not appear to be a valid archive (too short?)" msgstr "le fichier en entrée ne semble pas être une archive valide (trop petit ?)" -#: pg_backup_archiver.c:2352 +#: pg_backup_archiver.c:2353 #, c-format -msgid "input file does not appear to be a valid archive" -msgstr "le fichier en entrée ne semble pas être une archive valide" +msgid "input file does not appear to be a valid tar archive" +msgstr "le fichier en entrée ne semble pas être une archive tar valide" -#: pg_backup_archiver.c:2361 +#: pg_backup_archiver.c:2362 #, c-format msgid "could not close input file: %m" msgstr "n'a pas pu fermer le fichier en entrée : %m" -#: pg_backup_archiver.c:2440 +#: pg_backup_archiver.c:2441 #, c-format msgid "could not open stdout for appending: %m" msgstr "n'a pas pu ouvrir stdout pour l'ajout : %m" -#: pg_backup_archiver.c:2485 +#: pg_backup_archiver.c:2486 #, c-format msgid "unrecognized file format \"%d\"" msgstr "format de fichier « %d » non reconnu" -#: pg_backup_archiver.c:2566 pg_backup_archiver.c:4797 +#: pg_backup_archiver.c:2567 pg_backup_archiver.c:4798 #, c-format msgid "finished item %d %s %s" msgstr "élément terminé %d %s %s" -#: pg_backup_archiver.c:2570 pg_backup_archiver.c:4810 +#: pg_backup_archiver.c:2571 pg_backup_archiver.c:4811 #, c-format msgid "worker process failed: exit code %d" msgstr "échec du processus worker : code de sortie %d" -#: pg_backup_archiver.c:2668 +#: pg_backup_archiver.c:2669 #, c-format msgid "unexpected TOC entry in WriteToc(): %d %s %s" msgstr "entrée TOC inattendu dans WriteToc() : %d %s %s" -#: pg_backup_archiver.c:2672 pg_backup_custom.c:440 pg_backup_custom.c:506 -#: pg_backup_custom.c:635 pg_backup_custom.c:871 pg_backup_tar.c:1029 -#: pg_backup_tar.c:1034 +#: pg_backup_archiver.c:2673 pg_backup_custom.c:440 pg_backup_custom.c:506 +#: pg_backup_custom.c:635 pg_backup_custom.c:871 pg_backup_tar.c:1004 +#: pg_backup_tar.c:1009 #, c-format msgid "error during file seek: %m" msgstr "erreur lors de la recherche dans le fichier : %m" -#: pg_backup_archiver.c:2730 +#: pg_backup_archiver.c:2731 #, c-format msgid "entry ID %d out of range -- perhaps a corrupt TOC" -msgstr "ID %d de l'entrée en dehors de la plage -- peut-être un TOC corrompu" +msgstr "l'identifiant %d de l'entrée en dehors de la plage -- peut-être un TOC corrompu" -#: pg_backup_archiver.c:2813 +#: pg_backup_archiver.c:2814 #, c-format msgid "restoring tables WITH OIDS is not supported anymore" msgstr "la restauration des tables avec WITH OIDS n'est plus supportée" -#: pg_backup_archiver.c:2895 +#: pg_backup_archiver.c:2896 #, c-format msgid "unrecognized encoding \"%s\"" msgstr "encodage « %s » non reconnu" -#: pg_backup_archiver.c:2901 +#: pg_backup_archiver.c:2902 #, c-format msgid "invalid ENCODING item: %s" msgstr "élément ENCODING invalide : %s" -#: pg_backup_archiver.c:2919 +#: pg_backup_archiver.c:2920 #, c-format msgid "invalid STDSTRINGS item: %s" msgstr "élément STDSTRINGS invalide : %s" -#: pg_backup_archiver.c:2944 +#: pg_backup_archiver.c:2945 #, c-format msgid "schema \"%s\" not found" msgstr "schéma « %s » non trouvé" -#: pg_backup_archiver.c:2951 +#: pg_backup_archiver.c:2952 #, c-format msgid "table \"%s\" not found" msgstr "table « %s » non trouvée" -#: pg_backup_archiver.c:2958 +#: pg_backup_archiver.c:2959 #, c-format msgid "index \"%s\" not found" msgstr "index « %s » non trouvé" -#: pg_backup_archiver.c:2965 +#: pg_backup_archiver.c:2966 #, c-format msgid "function \"%s\" not found" msgstr "fonction « %s » non trouvée" -#: pg_backup_archiver.c:2972 +#: pg_backup_archiver.c:2973 #, c-format msgid "trigger \"%s\" not found" msgstr "trigger « %s » non trouvé" -#: pg_backup_archiver.c:3469 +#: pg_backup_archiver.c:3470 #, c-format msgid "could not set session user to \"%s\": %s" msgstr "n'a pas pu initialiser la session utilisateur à « %s »: %s" -#: pg_backup_archiver.c:3611 +#: pg_backup_archiver.c:3612 #, c-format msgid "could not set \"search_path\" to \"%s\": %s" msgstr "n'a pas pu configurer « search_path » à « %s » : %s" -#: pg_backup_archiver.c:3672 +#: pg_backup_archiver.c:3673 #, c-format msgid "could not set \"default_tablespace\" to %s: %s" msgstr "n'a pas pu configurer « default_tablespace » à %s : %s" -#: pg_backup_archiver.c:3721 +#: pg_backup_archiver.c:3722 #, c-format msgid "could not set \"default_table_access_method\": %s" msgstr "n'a pas pu configurer la méthode « default_table_access_method » : %s" -#: pg_backup_archiver.c:3770 +#: pg_backup_archiver.c:3771 #, c-format msgid "could not alter table access method: %s" msgstr "n'a pas pu modifier la méthode d'accès aux tables : %s" -#: pg_backup_archiver.c:3871 +#: pg_backup_archiver.c:3872 #, c-format msgid "don't know how to set owner for object type \"%s\"" msgstr "ne sait pas comment initialiser le propriétaire du type d'objet « %s »" -#: pg_backup_archiver.c:4006 +#: pg_backup_archiver.c:4007 #, c-format msgid "unexpected TOC entry in _printTocEntry(): %d %s %s" msgstr "entrée TOC inattendue dans : %d %s %s" -#: pg_backup_archiver.c:4154 +#: pg_backup_archiver.c:4155 #, c-format msgid "did not find magic string in file header" msgstr "n'a pas trouver la chaîne magique dans le fichier d'en-tête" -#: pg_backup_archiver.c:4168 +#: pg_backup_archiver.c:4169 #, c-format msgid "unsupported version (%d.%d) in file header" msgstr "version non supportée (%d.%d) dans le fichier d'en-tête" -#: pg_backup_archiver.c:4173 +#: pg_backup_archiver.c:4174 #, c-format msgid "sanity check on integer size (%lu) failed" msgstr "échec de la vérification sur la taille de l'entier (%lu)" -#: pg_backup_archiver.c:4177 +#: pg_backup_archiver.c:4178 #, c-format msgid "archive was made on a machine with larger integers, some operations might fail" msgstr "l'archive a été créée sur une machine disposant d'entiers plus larges, certaines opérations peuvent échouer" -#: pg_backup_archiver.c:4187 +#: pg_backup_archiver.c:4188 #, c-format msgid "expected format (%d) differs from format found in file (%d)" msgstr "le format attendu (%d) diffère du format du fichier (%d)" -#: pg_backup_archiver.c:4209 +#: pg_backup_archiver.c:4210 #, c-format msgid "archive is compressed, but this installation does not support compression (%s) -- no data will be available" msgstr "l'archive est compressée mais cette installation ne supporte pas la compression (%s) -- aucune donnée ne sera disponible" -#: pg_backup_archiver.c:4245 +#: pg_backup_archiver.c:4246 #, c-format msgid "invalid creation date in header" msgstr "date de création invalide dans l'en-tête" -#: pg_backup_archiver.c:4379 +#: pg_backup_archiver.c:4380 #, c-format msgid "processing item %d %s %s" msgstr "traitement de l'élément %d %s %s" -#: pg_backup_archiver.c:4464 +#: pg_backup_archiver.c:4465 #, c-format msgid "entering main parallel loop" msgstr "entrée dans la boucle parallèle principale" -#: pg_backup_archiver.c:4475 +#: pg_backup_archiver.c:4476 #, c-format msgid "skipping item %d %s %s" msgstr "omission de l'élément %d %s %s" -#: pg_backup_archiver.c:4484 +#: pg_backup_archiver.c:4485 #, c-format msgid "launching item %d %s %s" msgstr "lancement de l'élément %d %s %s" -#: pg_backup_archiver.c:4538 +#: pg_backup_archiver.c:4539 #, c-format msgid "finished main parallel loop" msgstr "fin de la boucle parallèle principale" -#: pg_backup_archiver.c:4574 +#: pg_backup_archiver.c:4575 #, c-format msgid "processing missed item %d %s %s" msgstr "traitement de l'élément manquant %d %s %s" -#: pg_backup_archiver.c:5116 +#: pg_backup_archiver.c:5117 #, c-format msgid "table \"%s\" could not be created, will not restore its data" msgstr "la table « %s » n'a pas pu être créée, ses données ne seront pas restaurées" @@ -1282,7 +1282,7 @@ msgstr "n'a pas pu trouver l'identifiant de bloc %d dans l'archive -- possible c #: pg_backup_custom.c:530 #, c-format msgid "found unexpected block ID (%d) when reading data -- expected %d" -msgstr "ID de bloc inattendu (%d) lors de la lecture des données -- %d attendu" +msgstr "identifiant de bloc inattendu (%d) lors de la lecture des données -- %d attendu" #: pg_backup_custom.c:544 #, c-format @@ -1290,7 +1290,7 @@ msgid "unrecognized data block type %d while restoring archive" msgstr "type de bloc de données %d non reconnu lors de la restauration de l'archive" #: pg_backup_custom.c:750 pg_backup_custom.c:804 pg_backup_custom.c:946 -#: pg_backup_tar.c:1032 +#: pg_backup_tar.c:1007 #, c-format msgid "could not determine seek position in archive file: %m" msgstr "n'a pas pu déterminer la position de recherche dans le fichier d'archive : %m" @@ -1480,34 +1480,34 @@ msgstr "syntaxe inattendue de l'instruction COPY : « %s »" msgid "invalid OID for large object (%u)" msgstr "OID invalide pour le « Large Object » (%u)" -#: pg_backup_tar.c:1048 +#: pg_backup_tar.c:1023 #, c-format msgid "could not close temporary file: %m" msgstr "n'a pas pu fermer le fichier temporaire : m" -#: pg_backup_tar.c:1051 +#: pg_backup_tar.c:1026 #, c-format msgid "actual file length (%lld) does not match expected (%lld)" msgstr "la longueur réelle du fichier (%lld) ne correspond pas à ce qui était attendu (%lld)" -#: pg_backup_tar.c:1097 pg_backup_tar.c:1128 +#: pg_backup_tar.c:1072 pg_backup_tar.c:1103 #, c-format msgid "could not find header for file \"%s\" in tar archive" msgstr "n'a pas pu trouver l'en-tête du fichier « %s » dans l'archive tar" -#: pg_backup_tar.c:1115 +#: pg_backup_tar.c:1090 #, c-format msgid "restoring data out of order is not supported in this archive format: \"%s\" is required, but comes before \"%s\" in the archive file." msgstr "la restauration désordonnée de données n'est pas supportée avec ce format d'archive : « %s » est requis mais vient avant « %s » dans le fichier d'archive." -#: pg_backup_tar.c:1162 +#: pg_backup_tar.c:1137 #, c-format msgid "incomplete tar header found (%lu byte)" msgid_plural "incomplete tar header found (%lu bytes)" msgstr[0] "en-tête incomplet du fichier tar (%lu octet)" msgstr[1] "en-tête incomplet du fichier tar (%lu octets)" -#: pg_backup_tar.c:1201 +#: pg_backup_tar.c:1176 #, c-format msgid "corrupt tar header found in %s (expected %d, computed %d) file position %llu" msgstr "en-tête tar corrompu trouvé dans %s (%d attendu, %d calculé ) à la position %llu du fichier" @@ -2164,7 +2164,7 @@ msgstr "les sauvegardes parallélisées sur un serveur standby ne sont pas suppo msgid "invalid output format \"%s\" specified" msgstr "format de sortie « %s » invalide" -#: pg_dump.c:1641 pg_dump.c:1697 pg_dump.c:1750 pg_dumpall.c:1594 +#: pg_dump.c:1641 pg_dump.c:1697 pg_dump.c:1750 pg_dumpall.c:1605 #, c-format msgid "improper qualified name (too many dotted names): %s" msgstr "mauvaise qualification du nom (trop de points entre les noms) : %s" @@ -2289,8 +2289,8 @@ msgstr "lecture des politiques de sécurité au niveau ligne" msgid "unexpected policy command type: %c" msgstr "type de commande inattendu pour la politique : %c" -#: pg_dump.c:4801 pg_dump.c:5358 pg_dump.c:7987 pg_dump.c:13467 pg_dump.c:19678 -#: pg_dump.c:19680 pg_dump.c:20312 +#: pg_dump.c:4801 pg_dump.c:5358 pg_dump.c:7987 pg_dump.c:13467 pg_dump.c:19681 +#: pg_dump.c:19683 pg_dump.c:20315 #, c-format msgid "could not parse %s array" msgstr "n'a pas pu analyser le tableau %s" @@ -2325,7 +2325,7 @@ msgstr "le schéma d'OID %u n'existe pas" msgid "cannot dump statistics for relation kind \"%c\"" msgstr "ne peut pas exporter les statistiques pour le type de relation « %c »" -#: pg_dump.c:7521 pg_dump.c:19005 +#: pg_dump.c:7521 pg_dump.c:19008 #, c-format msgid "failed sanity check, parent table with OID %u of sequence with OID %u not found" msgstr "vérification échouée, OID %u de la table parent de l'OID %u de la séquence introuvable" @@ -2544,89 +2544,89 @@ msgstr "la définition de la vue « %s » semble être vide (longueur nulle)" msgid "WITH OIDS is not supported anymore (table \"%s\")" msgstr "WITH OIDS n'est plus supporté (table « %s »)" -#: pg_dump.c:18082 +#: pg_dump.c:18085 #, c-format msgid "invalid column number %d for table \"%s\"" msgstr "numéro de colonne %d invalide pour la table « %s »" -#: pg_dump.c:18160 +#: pg_dump.c:18163 #, c-format msgid "could not parse index statistic columns" msgstr "n'a pas pu analyser les colonnes statistiques de l'index" -#: pg_dump.c:18162 +#: pg_dump.c:18165 #, c-format msgid "could not parse index statistic values" msgstr "n'a pas pu analyser les valeurs statistiques de l'index" -#: pg_dump.c:18164 +#: pg_dump.c:18167 #, c-format msgid "mismatched number of columns and values for index statistics" msgstr "nombre de colonnes et de valeurs différentes pour les statistiques des index" -#: pg_dump.c:18393 +#: pg_dump.c:18396 #, c-format msgid "missing index for constraint \"%s\"" msgstr "index manquant pour la contrainte « %s »" -#: pg_dump.c:18662 +#: pg_dump.c:18665 #, c-format msgid "unrecognized constraint type: %c" msgstr "type de contrainte inconnu : %c" -#: pg_dump.c:18715 +#: pg_dump.c:18718 #, c-format msgid "unrecognized sequence type: %s" msgstr "type de séquence non reconnu : « %s »" -#: pg_dump.c:18848 pg_dump.c:19086 +#: pg_dump.c:18851 pg_dump.c:19089 #, c-format msgid "query to get data of sequence \"%s\" returned %d row (expected 1)" msgid_plural "query to get data of sequence \"%s\" returned %d rows (expected 1)" msgstr[0] "la requête permettant d'obtenir les données de la séquence « %s » a renvoyé %d ligne (une seule attendue)" msgstr[1] "la requête permettant d'obtenir les données de la séquence « %s » a renvoyé %d ligne (une seule attendue)" -#: pg_dump.c:18884 +#: pg_dump.c:18887 #, c-format msgid "unrecognized sequence type: %d" msgstr "type de séquence non reconnu : %d" -#: pg_dump.c:19109 +#: pg_dump.c:19112 #, c-format msgid "failed to get data for sequence \"%s\"; user may lack SELECT privilege on the sequence or the sequence may have been concurrently dropped" -msgstr "" +msgstr "échec pour obtenir les données de la séquence « %s » ; l'utilisateur pourrait ne pas avoir le droit SELECT sur la séquence ou la séquence pourrait avoir été supprimée" -#: pg_dump.c:19430 +#: pg_dump.c:19433 #, c-format msgid "query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned" msgstr "la requête permettant d'obtenir la règle « %s » associée à la table « %s » a échoué : mauvais nombre de lignes renvoyées" -#: pg_dump.c:19583 +#: pg_dump.c:19586 #, c-format msgid "could not find referenced extension %u" msgstr "n'a pas pu trouver l'extension référencée %u" -#: pg_dump.c:19682 +#: pg_dump.c:19685 #, c-format msgid "mismatched number of configurations and conditions for extension" msgstr "nombre différent de configurations et de conditions pour l'extension" -#: pg_dump.c:19814 +#: pg_dump.c:19817 #, c-format msgid "reading dependency data" msgstr "lecture des données de dépendance" -#: pg_dump.c:19900 +#: pg_dump.c:19903 #, c-format msgid "no referencing object %u %u" msgstr "pas d'objet référant %u %u" -#: pg_dump.c:19911 +#: pg_dump.c:19914 #, c-format msgid "no referenced object %u %u" msgstr "pas d'objet référencé %u %u" -#: pg_dump.c:20346 pg_dump.c:20384 pg_dumpall.c:1842 pg_restore.c:642 +#: pg_dump.c:20349 pg_dump.c:20387 pg_dumpall.c:1853 pg_restore.c:642 #: pg_restore.c:688 #, c-format msgid "%s filter for \"%s\" is not allowed" @@ -2651,8 +2651,8 @@ msgstr "n'a pas pu identifier la boucle de dépendance" #, c-format msgid "there are circular foreign-key constraints on this table:" msgid_plural "there are circular foreign-key constraints among these tables:" -msgstr[0] "NOTE : il existe des contraintes de clés étrangères circulaires sur cette table :" -msgstr[1] "NOTE : il existe des contraintes de clés étrangères circulaires sur ces tables :" +msgstr[0] "il existe des contraintes de clés étrangères circulaires sur cette table :" +msgstr[1] "il existe des contraintes de clés étrangères circulaires sur ces tables :" #: pg_dump_sort.c:1479 #, c-format @@ -2799,52 +2799,69 @@ msgid "role name starting with \"pg_\" skipped (%s)" msgstr "nom de rôle commençant par « pg_ » ignoré (« %s »)" #. translator: %s represents a numeric role OID -#: pg_dumpall.c:1127 pg_dumpall.c:1185 pg_dumpall.c:1194 +#: pg_dumpall.c:1127 #, c-format -msgid "found orphaned pg_auth_members entry for role %s" -msgstr "a trouvé une entrée pg_auth_members orpheline pour le rôle %s" +msgid "ignoring role grant for missing role with OID %s" +msgstr "ignore le don du rôle pour le rôle manquant d'OID %s" -#: pg_dumpall.c:1160 +#: pg_dumpall.c:1165 #, c-format msgid "could not find a legal dump ordering for memberships in role \"%s\"" msgstr "n'a pas pu trouver un ordre de sauvegarde correct pour les appartenances au rôle « %s »" -#: pg_dumpall.c:1315 +#. translator: %s represents a numeric role OID +#: pg_dumpall.c:1191 +#, c-format +msgid "ignoring role grant to missing role with OID %s" +msgstr "ignore le don du rôle au rôle manquant d'OID %s" + +#. translator: %s represents a numeric role OID +#: pg_dumpall.c:1206 +#, c-format +msgid "grant of role \"%s\" to \"%s\" has invalid grantor OID %s" +msgstr "le don du rôle « %s » à « %s » a un OID de donneur %s invalide" + +#: pg_dumpall.c:1208 +#, c-format +msgid "This grant will be dumped without GRANTED BY." +msgstr "Ce don sera sauvegardé sans GRANTED BY." + +#: pg_dumpall.c:1326 #, c-format msgid "could not parse ACL list (%s) for parameter \"%s\"" msgstr "n'a pas pu analyser la liste d'ACL (%s) pour le paramètre « %s »" -#: pg_dumpall.c:1442 +#: pg_dumpall.c:1453 #, c-format msgid "could not parse ACL list (%s) for tablespace \"%s\"" msgstr "n'a pas pu analyser la liste d'ACL (%s) pour le tablespace « %s »" -#: pg_dumpall.c:1656 +#: pg_dumpall.c:1667 #, c-format msgid "excluding database \"%s\"" msgstr "exclusion de la base de données « %s »" -#: pg_dumpall.c:1660 +#: pg_dumpall.c:1671 #, c-format msgid "dumping database \"%s\"" msgstr "sauvegarde de la base de données « %s »" -#: pg_dumpall.c:1693 +#: pg_dumpall.c:1704 #, c-format msgid "pg_dump failed on database \"%s\", exiting" msgstr "échec de pg_dump sur la base de données « %s », quitte" -#: pg_dumpall.c:1699 +#: pg_dumpall.c:1710 #, c-format msgid "could not re-open the output file \"%s\": %m" msgstr "n'a pas pu ré-ouvrir le fichier de sortie « %s » : %m" -#: pg_dumpall.c:1743 +#: pg_dumpall.c:1754 #, c-format msgid "running \"%s\"" msgstr "exécute « %s »" -#: pg_dumpall.c:1862 +#: pg_dumpall.c:1873 msgid "unsupported filter object" msgstr "objet de filtre non supporté" @@ -3228,6 +3245,10 @@ msgstr "" #~ msgid "found database \"%s\" (OID: %u) in file \"%s\"" #~ msgstr "a trouvé la base « %s » (OID : %u) dans le fichier « %s »" +#, c-format +#~ msgid "found orphaned pg_auth_members entry for role %s" +#~ msgstr "a trouvé une entrée pg_auth_members orpheline pour le rôle %s" + #, c-format #~ msgid "ignored %d error in file \"%s\"" #~ msgid_plural "ignored %d errors in file \"%s\"" diff --git a/src/bin/pg_dump/t/002_pg_dump.pl b/src/bin/pg_dump/t/002_pg_dump.pl index 978c82174d4..509244b26f8 100644 --- a/src/bin/pg_dump/t/002_pg_dump.pl +++ b/src/bin/pg_dump/t/002_pg_dump.pl @@ -1336,6 +1336,43 @@ }, }, + 'CONSTRAINT NOT NULL / NO INHERIT' => { + create_sql => 'CREATE TABLE dump_test.test_table_nonn ( + col1 int NOT NULL NO INHERIT, + col2 int); + CREATE TABLE dump_test.test_table_nonn_chld1 ( + CONSTRAINT nn NOT NULL col2 NO INHERIT) + INHERITS (dump_test.test_table_nonn); ', + regexp => qr/^ + \QCREATE TABLE dump_test.test_table_nonn (\E \n^\s+ + \Qcol1 integer NOT NULL NO INHERIT\E + /xm, + like => { + %full_runs, %dump_test_schema_runs, + section_pre_data => 1, + binary_upgrade => 1, + }, + unlike => { + exclude_dump_test_schema => 1, + only_dump_measurement => 1, + }, + }, + + 'CONSTRAINT NOT NULL / NO INHERIT (child1)' => { + regexp => qr/^ + \QCREATE TABLE dump_test.test_table_nonn_chld1 (\E \n^\s+ + \QCONSTRAINT nn NOT NULL col2 NO INHERIT\E + /xm, + like => { + %full_runs, %dump_test_schema_runs, section_pre_data => 1, + }, + unlike => { + exclude_dump_test_schema => 1, + only_dump_measurement => 1, + binary_upgrade => 1, + }, + }, + 'CONSTRAINT PRIMARY KEY / WITHOUT OVERLAPS' => { create_sql => 'CREATE TABLE dump_test.test_table_tpk ( col1 int4range, diff --git a/src/bin/pg_rewind/file_ops.c b/src/bin/pg_rewind/file_ops.c index 649fdd15591..074ac41b026 100644 --- a/src/bin/pg_rewind/file_ops.c +++ b/src/bin/pg_rewind/file_ops.c @@ -48,6 +48,9 @@ open_target_file(const char *path, bool trunc) { int mode; + if (!path_is_safe_for_extraction(path)) + pg_fatal("target file path is unsafe for open: \"%s\"", path); + if (dry_run) return; @@ -188,6 +191,9 @@ remove_target_file(const char *path, bool missing_ok) { char dstpath[MAXPGPATH]; + if (!path_is_safe_for_extraction(path)) + pg_fatal("target file path is unsafe for removal: \"%s\"", path); + if (dry_run) return; @@ -208,6 +214,9 @@ truncate_target_file(const char *path, off_t newsize) char dstpath[MAXPGPATH]; int fd; + if (!path_is_safe_for_extraction(path)) + pg_fatal("target file path is unsafe for truncation: \"%s\"", path); + if (dry_run) return; @@ -230,6 +239,10 @@ create_target_dir(const char *path) { char dstpath[MAXPGPATH]; + if (!path_is_safe_for_extraction(path)) + pg_fatal("target directory path is unsafe for directory creation: \"%s\"", + path); + if (dry_run) return; @@ -244,6 +257,10 @@ remove_target_dir(const char *path) { char dstpath[MAXPGPATH]; + if (!path_is_safe_for_extraction(path)) + pg_fatal("target directory path is unsafe for directory removal: \"%s\"", + path); + if (dry_run) return; @@ -258,6 +275,9 @@ create_target_symlink(const char *path, const char *link) { char dstpath[MAXPGPATH]; + if (!path_is_safe_for_extraction(path)) + pg_fatal("target symlink path is unsafe for creation: \"%s\"", path); + if (dry_run) return; @@ -272,6 +292,9 @@ remove_target_symlink(const char *path) { char dstpath[MAXPGPATH]; + if (!path_is_safe_for_extraction(path)) + pg_fatal("target symlink path is unsafe for removal: \"%s\"", path); + if (dry_run) return; diff --git a/src/bin/pg_test_timing/pg_test_timing.c b/src/bin/pg_test_timing/pg_test_timing.c index ce7aad4b25a..8b358006388 100644 --- a/src/bin/pg_test_timing/pg_test_timing.c +++ b/src/bin/pg_test_timing/pg_test_timing.c @@ -149,7 +149,7 @@ test_timing(unsigned int duration) if (diff < 0) { fprintf(stderr, _("Detected clock going backwards in time.\n")); - fprintf(stderr, _("Time warp: %d ms\n"), diff); + fprintf(stderr, _("Time warp: %d us\n"), diff); exit(1); } diff --git a/src/bin/pg_test_timing/po/de.po b/src/bin/pg_test_timing/po/de.po index 288d7e6af2d..a2dc1da6317 100644 --- a/src/bin/pg_test_timing/po/de.po +++ b/src/bin/pg_test_timing/po/de.po @@ -1,15 +1,15 @@ # German message translation file for pg_test_timing -# Copyright (C) 2021 PostgreSQL Global Development Group +# Copyright (C) 2026 PostgreSQL Global Development Group # This file is distributed under the same license as the PostgreSQL package. # # Use these quotes: »%s« # msgid "" msgstr "" -"Project-Id-Version: pg_test_timing (PostgreSQL) 13\n" +"Project-Id-Version: pg_test_timing (PostgreSQL) 18\n" "Report-Msgid-Bugs-To: pgsql-bugs@lists.postgresql.org\n" -"POT-Creation-Date: 2024-06-16 07:51+0000\n" -"PO-Revision-Date: 2021-04-12 16:37+0200\n" +"POT-Creation-Date: 2026-05-05 12:12+0000\n" +"PO-Revision-Date: 2026-05-06 15:50+0200\n" "Last-Translator: Peter Eisentraut \n" "Language-Team: German \n" "Language: de\n" @@ -68,8 +68,8 @@ msgstr "Rückwärts gehende Uhr festgestellt.\n" #: pg_test_timing.c:152 #, c-format -msgid "Time warp: %d ms\n" -msgstr "Zeitdifferenz: %d ms\n" +msgid "Time warp: %d us\n" +msgstr "Zeitdifferenz: %d µs\n" #: pg_test_timing.c:175 #, c-format diff --git a/src/bin/pg_test_timing/po/fr.po b/src/bin/pg_test_timing/po/fr.po index 3be64c4b32a..106e0c44f87 100644 --- a/src/bin/pg_test_timing/po/fr.po +++ b/src/bin/pg_test_timing/po/fr.po @@ -10,8 +10,8 @@ msgid "" msgstr "" "Project-Id-Version: PostgreSQL 17\n" "Report-Msgid-Bugs-To: pgsql-bugs@lists.postgresql.org\n" -"POT-Creation-Date: 2024-08-22 10:20+0000\n" -"PO-Revision-Date: 2024-09-16 16:28+0200\n" +"POT-Creation-Date: 2026-05-08 18:51+0000\n" +"PO-Revision-Date: 2026-05-08 21:51+0200\n" "Last-Translator: Guillaume Lelarge \n" "Language-Team: French \n" "Language: fr\n" @@ -19,7 +19,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" -"X-Generator: Poedit 3.5\n" +"X-Generator: Poedit 3.9\n" #: ../../common/fe_memutils.c:35 ../../common/fe_memutils.c:75 #: ../../common/fe_memutils.c:98 ../../common/fe_memutils.c:161 @@ -71,8 +71,8 @@ msgstr "Détection d'une horloge partant à rebours.\n" #: pg_test_timing.c:152 #, c-format -msgid "Time warp: %d ms\n" -msgstr "Décalage de temps : %d ms\n" +msgid "Time warp: %d us\n" +msgstr "Décalage de temps : %d us\n" #: pg_test_timing.c:175 #, c-format diff --git a/src/bin/pg_upgrade/dump.c b/src/bin/pg_upgrade/dump.c index 55f6e7b4d9c..806bf3bef97 100644 --- a/src/bin/pg_upgrade/dump.c +++ b/src/bin/pg_upgrade/dump.c @@ -21,9 +21,10 @@ generate_old_dump(void) /* run new pg_dumpall binary for globals */ exec_prog(UTILITY_LOG_FILE, NULL, true, true, - "\"%s/pg_dumpall\" %s --globals-only --quote-all-identifiers " + "\"%s/pg_dumpall\" %s%s --globals-only --quote-all-identifiers " "--binary-upgrade %s --no-sync -f \"%s/%s\"", new_cluster.bindir, cluster_conn_opts(&old_cluster), + protocol_negotiation_supported(&old_cluster) ? "" : " -d \"max_protocol_version=3.0\"", log_opts.verbose ? "--verbose" : "", log_opts.dumpdir, GLOBALS_DUMP_FILE); @@ -43,6 +44,9 @@ generate_old_dump(void) initPQExpBuffer(&connstr); appendPQExpBufferStr(&connstr, "dbname="); appendConnStrVal(&connstr, old_db->db_name); + if (!protocol_negotiation_supported(&old_cluster)) + appendPQExpBufferStr(&connstr, " max_protocol_version=3.0"); + initPQExpBuffer(&escaped_connstr); appendShellString(&escaped_connstr, connstr.data); termPQExpBuffer(&connstr); diff --git a/src/bin/pg_upgrade/pg_upgrade.h b/src/bin/pg_upgrade/pg_upgrade.h index 730edaca140..b10599e4587 100644 --- a/src/bin/pg_upgrade/pg_upgrade.h +++ b/src/bin/pg_upgrade/pg_upgrade.h @@ -499,6 +499,7 @@ unsigned int str2uint(const char *str); /* version.c */ bool jsonb_9_4_check_applicable(ClusterInfo *cluster); +bool protocol_negotiation_supported(const ClusterInfo *cluster); void old_9_6_invalidate_hash_indexes(ClusterInfo *cluster, bool check_mode); diff --git a/src/bin/pg_upgrade/server.c b/src/bin/pg_upgrade/server.c index 4f49715cdc5..f23ce52faa2 100644 --- a/src/bin/pg_upgrade/server.c +++ b/src/bin/pg_upgrade/server.c @@ -75,6 +75,8 @@ get_db_conn(ClusterInfo *cluster, const char *db_name) appendPQExpBufferStr(&conn_opts, " host="); appendConnStrVal(&conn_opts, cluster->sockdir); } + if (!protocol_negotiation_supported(cluster)) + appendPQExpBufferStr(&conn_opts, " max_protocol_version=3.0"); conn = PQconnectdb(conn_opts.data); termPQExpBuffer(&conn_opts); diff --git a/src/bin/pg_upgrade/task.c b/src/bin/pg_upgrade/task.c index ee0e2457152..a19ea8445a0 100644 --- a/src/bin/pg_upgrade/task.c +++ b/src/bin/pg_upgrade/task.c @@ -188,6 +188,8 @@ start_conn(const ClusterInfo *cluster, UpgradeTaskSlot *slot) appendPQExpBufferStr(&conn_opts, " host="); appendConnStrVal(&conn_opts, cluster->sockdir); } + if (!protocol_negotiation_supported(cluster)) + appendPQExpBufferStr(&conn_opts, " max_protocol_version=3.0"); slot->conn = PQconnectStart(conn_opts.data); diff --git a/src/bin/pg_upgrade/version.c b/src/bin/pg_upgrade/version.c index 7e70fc8affd..c0cd7c7ec2f 100644 --- a/src/bin/pg_upgrade/version.c +++ b/src/bin/pg_upgrade/version.c @@ -30,6 +30,24 @@ jsonb_9_4_check_applicable(ClusterInfo *cluster) return false; } +/* + * Older servers can't support newer protocol versions, so their connection + * strings will need to lock max_protocol_version to 3.0. + */ +bool +protocol_negotiation_supported(const ClusterInfo *cluster) +{ + /* + * The February 2018 patch release (9.3.21, 9.4.16, 9.5.11, 9.6.7, and + * 10.2) added support for NegotiateProtocolVersion. But ClusterInfo only + * has information about the major version number. To ensure we can still + * upgrade older unpatched servers, just assume anything prior to PG11 + * can't negotiate. It's not possible for those servers to make use of + * newer protocols anyway, so nothing is lost. + */ + return (GET_MAJOR_VERSION(cluster->major_version) >= 1100); +} + /* * old_9_6_invalidate_hash_indexes() * 9.6 -> 10 diff --git a/src/bin/pg_verifybackup/astreamer_verify.c b/src/bin/pg_verifybackup/astreamer_verify.c index 33cf67670a7..ba49a0520e2 100644 --- a/src/bin/pg_verifybackup/astreamer_verify.c +++ b/src/bin/pg_verifybackup/astreamer_verify.c @@ -165,7 +165,7 @@ member_verify_header(astreamer *streamer, astreamer_member *member) char pathname[MAXPGPATH]; /* We are only interested in normal files. */ - if (member->is_directory || member->is_link) + if (!member->is_regular) return; /* diff --git a/src/bin/pg_verifybackup/po/de.po b/src/bin/pg_verifybackup/po/de.po index a9e24931100..a04ee41add8 100644 --- a/src/bin/pg_verifybackup/po/de.po +++ b/src/bin/pg_verifybackup/po/de.po @@ -1,13 +1,13 @@ # German message translation file for pg_verifybackup -# Copyright (C) 2020-2025 PostgreSQL Global Development Group +# Copyright (C) 2020-2026 PostgreSQL Global Development Group # This file is distributed under the same license as the pg_verifybackup (PostgreSQL) package. # msgid "" msgstr "" "Project-Id-Version: pg_verifybackup (PostgreSQL) 18\n" "Report-Msgid-Bugs-To: pgsql-bugs@lists.postgresql.org\n" -"POT-Creation-Date: 2025-04-29 14:48+0000\n" -"PO-Revision-Date: 2025-04-29 18:57+0200\n" +"POT-Creation-Date: 2026-05-05 12:10+0000\n" +"PO-Revision-Date: 2026-05-06 16:09+0200\n" "Last-Translator: Peter Eisentraut \n" "Language-Team: German \n" "Language: de\n" @@ -92,7 +92,7 @@ msgid "could not fsync file \"%s\": %m" msgstr "konnte Datei »%s« nicht fsyncen: %m" #: ../../common/cryptohash.c:261 ../../common/cryptohash_openssl.c:356 -#: ../../common/jsonapi.c:2407 ../../common/parse_manifest.c:157 +#: ../../common/jsonapi.c:2459 ../../common/parse_manifest.c:157 #: ../../common/parse_manifest.c:852 #, c-format msgid "out of memory" @@ -122,103 +122,103 @@ msgstr "Speicher aufgebraucht\n" msgid "cannot duplicate null pointer (internal error)\n" msgstr "kann NULL-Zeiger nicht kopieren (interner Fehler)\n" -#: ../../common/jsonapi.c:2432 +#: ../../common/jsonapi.c:2484 msgid "Recursive descent parser cannot use incremental lexer." msgstr "Parser mit rekursivem Abstieg kann inkrementellen Lexer nicht benutzen." -#: ../../common/jsonapi.c:2434 +#: ../../common/jsonapi.c:2486 msgid "Incremental parser requires incremental lexer." msgstr "Inkrementeller Parser benötigt inkrementellen Lexer." -#: ../../common/jsonapi.c:2436 +#: ../../common/jsonapi.c:2488 msgid "JSON nested too deep, maximum permitted depth is 6400." msgstr "JSON zu tief geschachtelt, maximale erlaubte Tiefe ist 6400." -#: ../../common/jsonapi.c:2438 +#: ../../common/jsonapi.c:2490 #, c-format msgid "Escape sequence \"\\%.*s\" is invalid." msgstr "Escape-Sequenz »\\%.*s« ist nicht gültig." -#: ../../common/jsonapi.c:2442 +#: ../../common/jsonapi.c:2494 #, c-format msgid "Character with value 0x%02x must be escaped." msgstr "Zeichen mit Wert 0x%02x muss escapt werden." -#: ../../common/jsonapi.c:2446 +#: ../../common/jsonapi.c:2498 #, c-format msgid "Expected end of input, but found \"%.*s\"." msgstr "Ende der Eingabe erwartet, aber »%.*s« gefunden." -#: ../../common/jsonapi.c:2449 +#: ../../common/jsonapi.c:2501 #, c-format msgid "Expected array element or \"]\", but found \"%.*s\"." msgstr "Array-Element oder »]« erwartet, aber »%.*s« gefunden." -#: ../../common/jsonapi.c:2452 +#: ../../common/jsonapi.c:2504 #, c-format msgid "Expected \",\" or \"]\", but found \"%.*s\"." msgstr "»,« oder »]« erwartet, aber »%.*s« gefunden." -#: ../../common/jsonapi.c:2455 +#: ../../common/jsonapi.c:2507 #, c-format msgid "Expected \":\", but found \"%.*s\"." msgstr "»:« erwartet, aber »%.*s« gefunden." -#: ../../common/jsonapi.c:2458 +#: ../../common/jsonapi.c:2510 #, c-format msgid "Expected JSON value, but found \"%.*s\"." msgstr "JSON-Wert erwartet, aber »%.*s« gefunden." -#: ../../common/jsonapi.c:2461 +#: ../../common/jsonapi.c:2513 msgid "The input string ended unexpectedly." msgstr "Die Eingabezeichenkette endete unerwartet." -#: ../../common/jsonapi.c:2463 +#: ../../common/jsonapi.c:2515 #, c-format msgid "Expected string or \"}\", but found \"%.*s\"." msgstr "Zeichenkette oder »}« erwartet, aber »%.*s« gefunden." -#: ../../common/jsonapi.c:2466 +#: ../../common/jsonapi.c:2518 #, c-format msgid "Expected \",\" or \"}\", but found \"%.*s\"." msgstr "»,« oder »}« erwartet, aber »%.*s« gefunden." -#: ../../common/jsonapi.c:2469 +#: ../../common/jsonapi.c:2521 #, c-format msgid "Expected string, but found \"%.*s\"." msgstr "Zeichenkette erwartet, aber »%.*s« gefunden." -#: ../../common/jsonapi.c:2472 +#: ../../common/jsonapi.c:2524 #, c-format msgid "Token \"%.*s\" is invalid." msgstr "Token »%.*s« ist ungültig." -#: ../../common/jsonapi.c:2478 +#: ../../common/jsonapi.c:2530 msgid "\\u0000 cannot be converted to text." msgstr "\\u0000 kann nicht in »text« umgewandelt werden." -#: ../../common/jsonapi.c:2480 +#: ../../common/jsonapi.c:2532 msgid "\"\\u\" must be followed by four hexadecimal digits." msgstr "Nach »\\u« müssen vier Hexadezimalziffern folgen." -#: ../../common/jsonapi.c:2483 +#: ../../common/jsonapi.c:2535 msgid "Unicode escape values cannot be used for code point values above 007F when the encoding is not UTF8." msgstr "Unicode-Escape-Werte können nicht für Code-Punkt-Werte über 007F verwendet werden, wenn die Kodierung nicht UTF8 ist." -#: ../../common/jsonapi.c:2492 +#: ../../common/jsonapi.c:2544 #, c-format msgid "Unicode escape value could not be translated to the server's encoding %s." msgstr "Unicode-Escape-Wert konnte nicht in die Serverkodierung %s umgewandelt werden." -#: ../../common/jsonapi.c:2499 +#: ../../common/jsonapi.c:2551 msgid "Unicode high surrogate must not follow a high surrogate." msgstr "Unicode-High-Surrogate darf nicht auf ein High-Surrogate folgen." -#: ../../common/jsonapi.c:2501 +#: ../../common/jsonapi.c:2553 msgid "Unicode low surrogate must follow a high surrogate." msgstr "Unicode-Low-Surrogate muss auf ein High-Surrogate folgen." -#: ../../common/jsonapi.c:2523 +#: ../../common/jsonapi.c:2575 msgid "out of memory while constructing error description" msgstr "Speicher aufgebraucht beim Konstruieren der Fehlerbeschreibung" @@ -401,7 +401,7 @@ msgstr "konnte Komprimierungsniveau %d nicht setzen: %s" #: ../../fe_utils/astreamer_gzip.c:140 ../../fe_utils/astreamer_gzip.c:273 #: ../../fe_utils/astreamer_lz4.c:102 ../../fe_utils/astreamer_lz4.c:300 -#: ../../fe_utils/astreamer_zstd.c:133 ../../fe_utils/astreamer_zstd.c:288 +#: ../../fe_utils/astreamer_zstd.c:130 ../../fe_utils/astreamer_zstd.c:285 #, c-format msgid "this build does not support compression with %s" msgstr "diese Installation unterstützt keine Komprimierung mit %s" @@ -422,7 +422,7 @@ msgid "could not initialize compression library" msgstr "konnte Komprimierungsbibliothek nicht initialisieren" #: ../../fe_utils/astreamer_gzip.c:320 ../../fe_utils/astreamer_lz4.c:356 -#: ../../fe_utils/astreamer_zstd.c:333 +#: ../../fe_utils/astreamer_zstd.c:330 #, c-format msgid "could not decompress data: %s" msgstr "konnte Daten nicht dekomprimieren: %s" @@ -437,8 +437,8 @@ msgstr "konnte lz4-Komprimierungskontext nicht erzeugen: %s" msgid "could not write lz4 header: %s" msgstr "konnte lz4-Header nicht schreiben: %s" -#: ../../fe_utils/astreamer_lz4.c:191 ../../fe_utils/astreamer_zstd.c:185 -#: ../../fe_utils/astreamer_zstd.c:227 +#: ../../fe_utils/astreamer_lz4.c:191 ../../fe_utils/astreamer_zstd.c:182 +#: ../../fe_utils/astreamer_zstd.c:224 #, c-format msgid "could not compress data: %s" msgstr "konnte Daten nicht komprimieren: %s" @@ -453,22 +453,27 @@ msgstr "konnte lz4-Komprimierung nicht beenden: %s" msgid "could not initialize compression library: %s" msgstr "konnte Komprimierungsbibliothek nicht initialisieren: %s" -#: ../../fe_utils/astreamer_tar.c:244 -#, c-format -msgid "tar file trailer exceeds 2 blocks" -msgstr "Tar-Datei-Trailer überschreitet 2 Blöcke" - -#: ../../fe_utils/astreamer_tar.c:249 astreamer_verify.c:130 +#: ../../fe_utils/astreamer_tar.c:254 astreamer_verify.c:130 #, c-format msgid "unexpected state while parsing tar archive" msgstr "unerwarteter Zustand beim Parsen des Tar-Archivs" -#: ../../fe_utils/astreamer_tar.c:292 +#: ../../fe_utils/astreamer_tar.c:300 +#, c-format +msgid "input file does not appear to be a valid tar archive" +msgstr "Eingabedatei scheint kein gültiges Tar-Archiv zu sein" + +#: ../../fe_utils/astreamer_tar.c:307 #, c-format msgid "tar member has empty name" msgstr "Tar-Mitglied hat leeren Namen" -#: ../../fe_utils/astreamer_tar.c:326 +#: ../../fe_utils/astreamer_tar.c:328 +#, c-format +msgid "pax extensions to tar format are not supported" +msgstr "PAX-Erweiterungen des Tar-Formats werden nicht unterstützt" + +#: ../../fe_utils/astreamer_tar.c:357 #, c-format msgid "COPY stream ended before last file was finished" msgstr "COPY-Strom endete vor dem Ende der letzten Datei" @@ -488,12 +493,12 @@ msgstr "konnte zstd-Komprimierungsniveau nicht auf %d setzen: %s" msgid "could not set compression worker count to %d: %s" msgstr "konnte Komprimierungs-Worker-Anzahl nicht auf %d setzen: %s" -#: ../../fe_utils/astreamer_zstd.c:120 +#: ../../fe_utils/astreamer_zstd.c:119 #, c-format msgid "could not enable long-distance mode: %s" msgstr "konnte Long-Distance-Modus nicht einschalten: %s" -#: ../../fe_utils/astreamer_zstd.c:279 +#: ../../fe_utils/astreamer_zstd.c:276 #, c-format msgid "could not create zstd decompression context" msgstr "konnte zstd-Dekomprimierungskontext nicht erzeugen" diff --git a/src/bin/pg_verifybackup/po/fr.po b/src/bin/pg_verifybackup/po/fr.po index e2923aa647e..421a315c400 100644 --- a/src/bin/pg_verifybackup/po/fr.po +++ b/src/bin/pg_verifybackup/po/fr.po @@ -10,8 +10,8 @@ msgid "" msgstr "" "Project-Id-Version: PostgreSQL 17\n" "Report-Msgid-Bugs-To: pgsql-bugs@lists.postgresql.org\n" -"POT-Creation-Date: 2025-07-09 13:18+0000\n" -"PO-Revision-Date: 2025-07-09 17:49+0200\n" +"POT-Creation-Date: 2026-05-08 18:48+0000\n" +"PO-Revision-Date: 2026-05-08 21:52+0200\n" "Last-Translator: Guillaume Lelarge \n" "Language-Team: French \n" "Language: fr\n" @@ -19,7 +19,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" -"X-Generator: Poedit 3.6\n" +"X-Generator: Poedit 3.9\n" #: ../../../src/common/logging.c:279 #, c-format @@ -98,7 +98,7 @@ msgid "could not fsync file \"%s\": %m" msgstr "n'a pas pu synchroniser sur disque (fsync) le fichier « %s » : %m" #: ../../common/cryptohash.c:261 ../../common/cryptohash_openssl.c:356 -#: ../../common/jsonapi.c:2410 ../../common/parse_manifest.c:157 +#: ../../common/jsonapi.c:2459 ../../common/parse_manifest.c:157 #: ../../common/parse_manifest.c:852 #, c-format msgid "out of memory" @@ -128,103 +128,103 @@ msgstr "mémoire épuisée\n" msgid "cannot duplicate null pointer (internal error)\n" msgstr "ne peut pas dupliquer un pointeur nul (erreur interne)\n" -#: ../../common/jsonapi.c:2435 +#: ../../common/jsonapi.c:2484 msgid "Recursive descent parser cannot use incremental lexer." msgstr "L'analyseur (parser) en descente récursive ne peut pas utiliser l'analyseur (lexer) incrémental." -#: ../../common/jsonapi.c:2437 +#: ../../common/jsonapi.c:2486 msgid "Incremental parser requires incremental lexer." msgstr "L'analyser (parser) incrémental nécessite l'analyseur (lexer) incrémental." -#: ../../common/jsonapi.c:2439 +#: ../../common/jsonapi.c:2488 msgid "JSON nested too deep, maximum permitted depth is 6400." msgstr "JSON trop profondément imbriqué, profondeur maximum permise est 6400." -#: ../../common/jsonapi.c:2441 +#: ../../common/jsonapi.c:2490 #, c-format msgid "Escape sequence \"\\%.*s\" is invalid." msgstr "La séquence d'échappement « \\%.*s » est invalide." -#: ../../common/jsonapi.c:2445 +#: ../../common/jsonapi.c:2494 #, c-format msgid "Character with value 0x%02x must be escaped." msgstr "Le caractère de valeur 0x%02x doit être échappé." -#: ../../common/jsonapi.c:2449 +#: ../../common/jsonapi.c:2498 #, c-format msgid "Expected end of input, but found \"%.*s\"." msgstr "Fin de l'entrée attendue, mais trouvé « %.*s »." -#: ../../common/jsonapi.c:2452 +#: ../../common/jsonapi.c:2501 #, c-format msgid "Expected array element or \"]\", but found \"%.*s\"." msgstr "Élément de tableau ou « ] » attendu, mais trouvé « %.*s »." -#: ../../common/jsonapi.c:2455 +#: ../../common/jsonapi.c:2504 #, c-format msgid "Expected \",\" or \"]\", but found \"%.*s\"." msgstr "« , » ou « ] » attendu, mais trouvé « %.*s »." -#: ../../common/jsonapi.c:2458 +#: ../../common/jsonapi.c:2507 #, c-format msgid "Expected \":\", but found \"%.*s\"." msgstr "« : » attendu, mais trouvé « %.*s »." -#: ../../common/jsonapi.c:2461 +#: ../../common/jsonapi.c:2510 #, c-format msgid "Expected JSON value, but found \"%.*s\"." msgstr "Valeur JSON attendue, mais « %.*s » trouvé." -#: ../../common/jsonapi.c:2464 +#: ../../common/jsonapi.c:2513 msgid "The input string ended unexpectedly." msgstr "La chaîne en entrée se ferme de manière inattendue." -#: ../../common/jsonapi.c:2466 +#: ../../common/jsonapi.c:2515 #, c-format msgid "Expected string or \"}\", but found \"%.*s\"." msgstr "Chaîne ou « } » attendu, mais « %.*s » trouvé." -#: ../../common/jsonapi.c:2469 +#: ../../common/jsonapi.c:2518 #, c-format msgid "Expected \",\" or \"}\", but found \"%.*s\"." msgstr "« , » ou « } » attendu, mais trouvé « %.*s »." -#: ../../common/jsonapi.c:2472 +#: ../../common/jsonapi.c:2521 #, c-format msgid "Expected string, but found \"%.*s\"." msgstr "Chaîne attendue, mais « %.*s » trouvé." -#: ../../common/jsonapi.c:2475 +#: ../../common/jsonapi.c:2524 #, c-format msgid "Token \"%.*s\" is invalid." msgstr "Le jeton « %.*s » n'est pas valide." -#: ../../common/jsonapi.c:2481 +#: ../../common/jsonapi.c:2530 msgid "\\u0000 cannot be converted to text." msgstr "\\u0000 ne peut pas être converti en texte." -#: ../../common/jsonapi.c:2483 +#: ../../common/jsonapi.c:2532 msgid "\"\\u\" must be followed by four hexadecimal digits." msgstr "« \\u » doit être suivi par quatre chiffres hexadécimaux." -#: ../../common/jsonapi.c:2486 +#: ../../common/jsonapi.c:2535 msgid "Unicode escape values cannot be used for code point values above 007F when the encoding is not UTF8." msgstr "Les valeurs d'échappement Unicode ne peuvent pas être utilisées pour des valeurs de point code au-dessus de 007F quand l'encodage n'est pas UTF8." -#: ../../common/jsonapi.c:2495 +#: ../../common/jsonapi.c:2544 #, c-format msgid "Unicode escape value could not be translated to the server's encoding %s." msgstr "La valeur d'échappement unicode ne peut pas être traduite dans l'encodage du serveur %s." -#: ../../common/jsonapi.c:2502 +#: ../../common/jsonapi.c:2551 msgid "Unicode high surrogate must not follow a high surrogate." msgstr "Une substitution unicode haute ne doit pas suivre une substitution haute." -#: ../../common/jsonapi.c:2504 +#: ../../common/jsonapi.c:2553 msgid "Unicode low surrogate must follow a high surrogate." msgstr "Une substitution unicode basse ne doit pas suivre une substitution haute." -#: ../../common/jsonapi.c:2526 +#: ../../common/jsonapi.c:2575 msgid "out of memory while constructing error description" msgstr "manque mémoire lors de la construction de la description de l'erreur" @@ -407,7 +407,7 @@ msgstr "n'a pas pu configurer le niveau de compression %d : %s" #: ../../fe_utils/astreamer_gzip.c:140 ../../fe_utils/astreamer_gzip.c:273 #: ../../fe_utils/astreamer_lz4.c:102 ../../fe_utils/astreamer_lz4.c:300 -#: ../../fe_utils/astreamer_zstd.c:133 ../../fe_utils/astreamer_zstd.c:288 +#: ../../fe_utils/astreamer_zstd.c:130 ../../fe_utils/astreamer_zstd.c:285 #, c-format msgid "this build does not support compression with %s" msgstr "cette construction ne supporte pas la compression avec %s" @@ -428,7 +428,7 @@ msgid "could not initialize compression library" msgstr "n'a pas pu initialiser la bibliothèque de compression" #: ../../fe_utils/astreamer_gzip.c:320 ../../fe_utils/astreamer_lz4.c:356 -#: ../../fe_utils/astreamer_zstd.c:333 +#: ../../fe_utils/astreamer_zstd.c:330 #, c-format msgid "could not decompress data: %s" msgstr "n'a pas pu décompresser les données : %s" @@ -443,8 +443,8 @@ msgstr "n'a pas pu créer le contexte de compression lz4 : %s" msgid "could not write lz4 header: %s" msgstr "n'a pas pu écrire l'entête lz4 : %s" -#: ../../fe_utils/astreamer_lz4.c:191 ../../fe_utils/astreamer_zstd.c:185 -#: ../../fe_utils/astreamer_zstd.c:227 +#: ../../fe_utils/astreamer_lz4.c:191 ../../fe_utils/astreamer_zstd.c:182 +#: ../../fe_utils/astreamer_zstd.c:224 #, c-format msgid "could not compress data: %s" msgstr "n'a pas pu compresser les données : %s" @@ -459,22 +459,27 @@ msgstr "n'a pas pu terminer la compression lz4 : %s" msgid "could not initialize compression library: %s" msgstr "n'a pas pu initialiser la bibliothèque de compression : %s" -#: ../../fe_utils/astreamer_tar.c:244 -#, c-format -msgid "tar file trailer exceeds 2 blocks" -msgstr "la fin du fichier tar fait plus de 2 blocs" - -#: ../../fe_utils/astreamer_tar.c:249 astreamer_verify.c:130 +#: ../../fe_utils/astreamer_tar.c:254 astreamer_verify.c:130 #, c-format msgid "unexpected state while parsing tar archive" msgstr "état inattendu lors de l'analyse de l'archive tar" -#: ../../fe_utils/astreamer_tar.c:292 +#: ../../fe_utils/astreamer_tar.c:300 +#, c-format +msgid "input file does not appear to be a valid tar archive" +msgstr "le fichier en entrée ne semble pas être une archive tar valide" + +#: ../../fe_utils/astreamer_tar.c:307 #, c-format msgid "tar member has empty name" msgstr "le membre de tar a un nom vide" -#: ../../fe_utils/astreamer_tar.c:326 +#: ../../fe_utils/astreamer_tar.c:328 +#, c-format +msgid "pax extensions to tar format are not supported" +msgstr "les extensions pax au format tar ne sont pas supportés" + +#: ../../fe_utils/astreamer_tar.c:357 #, c-format msgid "COPY stream ended before last file was finished" msgstr "le flux COPY s'est terminé avant que le dernier fichier soit terminé" @@ -494,12 +499,12 @@ msgstr "n'a pas pu configurer le niveau de compression zstd à %d : %s" msgid "could not set compression worker count to %d: %s" msgstr "n'a pas pu configurer le nombre de workers de compression à %d : %s" -#: ../../fe_utils/astreamer_zstd.c:120 +#: ../../fe_utils/astreamer_zstd.c:119 #, c-format msgid "could not enable long-distance mode: %s" msgstr "n'a pas pu activer le mode distance longue : %s" -#: ../../fe_utils/astreamer_zstd.c:279 +#: ../../fe_utils/astreamer_zstd.c:276 #, c-format msgid "could not create zstd decompression context" msgstr "n'a pas pu créer le contexte de décompression zstd" @@ -823,3 +828,7 @@ msgstr "Page d'accueil de %s : <%s>\n" #, c-format #~ msgid "%s: manifest system identifier is %llu, but control file has %llu" #~ msgstr "%s: l'identifieur système du manifeste est %llu, mais le fichier de contrôle a %llu" + +#, c-format +#~ msgid "tar file trailer exceeds 2 blocks" +#~ msgstr "la fin du fichier tar fait plus de 2 blocs" diff --git a/src/bin/pg_verifybackup/t/003_corruption.pl b/src/bin/pg_verifybackup/t/003_corruption.pl index 0c564dceece..9d089f8984e 100644 --- a/src/bin/pg_verifybackup/t/003_corruption.pl +++ b/src/bin/pg_verifybackup/t/003_corruption.pl @@ -13,6 +13,7 @@ use Test::More; my $tar = $ENV{TAR}; +my @tar_p_flags = tar_portability_options($tar); my $primary = PostgreSQL::Test::Cluster->new('primary'); $primary->init(allows_streaming => 1); @@ -154,8 +155,8 @@ # have a TAR program available. Note that this destructively modifies # the backup directory. if ( !$scenario->{'needs_unix_permissions'} - || !defined $tar - || $tar eq '') + && defined $tar + && $tar ne '') { my $tar_backup_path = $primary->backup_dir . '/tar_' . $name; mkdir($tar_backup_path) || die "mkdir $tar_backup_path: $!"; @@ -171,14 +172,23 @@ chdir($tspath) || die "chdir: $!"; command_ok( - [ $tar, '-cf', "$tar_backup_path/$tsoid.tar", '.' ]); + [ + $tar, @tar_p_flags, + '-cf' => "$tar_backup_path/$tsoid.tar", + '.' + ]); chdir($cwd) || die "chdir: $!"; rmtree($tspath); } # tar and remove pg_wal chdir($backup_path . '/pg_wal') || die "chdir: $!"; - command_ok([ $tar, '-cf', "$tar_backup_path/pg_wal.tar", '.' ]); + command_ok( + [ + $tar, @tar_p_flags, + '-cf' => "$tar_backup_path/pg_wal.tar", + '.' + ]); chdir($cwd) || die "chdir: $!"; rmtree($backup_path . '/pg_wal'); @@ -190,7 +200,12 @@ # Construct base.tar with what's left. chdir($backup_path) || die "chdir: $!"; - command_ok([ $tar, '-cf' => "$tar_backup_path/base.tar", '.' ]); + command_ok( + [ + $tar, @tar_p_flags, + '-cf' => "$tar_backup_path/base.tar", + '.' + ]); chdir($cwd) || die "chdir: $!"; # Now check that the backup no longer verifies. We must use -n diff --git a/src/bin/pg_waldump/pg_waldump.c b/src/bin/pg_waldump/pg_waldump.c index 51fb76efc48..a3c0368f196 100644 --- a/src/bin/pg_waldump/pg_waldump.c +++ b/src/bin/pg_waldump/pg_waldump.c @@ -160,7 +160,7 @@ create_fullpage_directory(char *path) static void split_path(const char *path, char **dir, char **fname) { - char *sep; + const char *sep; /* split filepath into directory & filename */ sep = strrchr(path, '/'); diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c index 7bdc7ee74a3..479a67cea9e 100644 --- a/src/bin/pgbench/pgbench.c +++ b/src/bin/pgbench/pgbench.c @@ -6241,7 +6241,7 @@ findBuiltin(const char *name) static int parseScriptWeight(const char *option, char **script) { - char *sep; + const char *sep; int weight; if ((sep = strrchr(option, WSEP))) diff --git a/src/bin/psql/po/ka.po b/src/bin/psql/po/ka.po index 49cc506dc47..7d7c7e0c869 100644 --- a/src/bin/psql/po/ka.po +++ b/src/bin/psql/po/ka.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: psql (PostgreSQL) 18\n" "Report-Msgid-Bugs-To: pgsql-bugs@lists.postgresql.org\n" -"POT-Creation-Date: 2025-08-15 21:17+0000\n" -"PO-Revision-Date: 2025-08-16 16:34+0200\n" +"POT-Creation-Date: 2025-12-11 05:48+0000\n" +"PO-Revision-Date: 2025-12-13 13:10+0100\n" "Last-Translator: Temuri Doghonadze \n" "Language-Team: Georgian \n" "Language: ka\n" @@ -16,7 +16,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Poedit 3.6\n" +"X-Generator: Poedit 3.8\n" #: ../../../src/common/logging.c:279 #, c-format @@ -482,7 +482,6 @@ msgstr "დროის დათვლა გამორთულია." #: command.c:3208 #, c-format -#| msgid "\\%s not allowed in pipeline mode" msgid "\\%s: not currently in restricted mode" msgstr "\\%s: არ იმყოფებით შეზღუდულ რეჟიმში" @@ -2729,7 +2728,7 @@ msgstr "" "psql PostgreSQL-ის ინტერაქტიური ტერმინალია.\n" "\n" -#: help.c:61 help.c:389 help.c:476 help.c:522 +#: help.c:61 help.c:389 help.c:476 help.c:525 msgid "Usage:\n" msgstr "გამოყენება:\n" @@ -3013,9 +3012,6 @@ msgid " \\q quit psql\n" msgstr " \\q psql-დან გასვლა\n" #: help.c:174 -#| msgid "" -#| " \\close_prepared STMT_NAME\n" -#| " close an existing prepared statement\n" msgid "" " \\restrict RESTRICT_KEY\n" " enter restricted mode with provided key\n" @@ -3955,6 +3951,15 @@ msgstr "" " სამიზნის სიგანე გადატანილი ფორმატისთვის\n" #: help.c:483 +#, c-format +msgid "" +" csv_fieldsep\n" +" field separator for CSV output format (default \"%c\")\n" +msgstr "" +" csv_fieldsep\n" +" ველების გამყოფი CSV გამოტანის ფორმატისთვის (ნაგულისხმევია \"%c\")\n" + +#: help.c:486 msgid "" " expanded (or x)\n" " expanded output [on, off, auto]\n" @@ -3962,7 +3967,7 @@ msgstr "" " expanded (or x)\n" " გაფართოებული გამოტანა [on, off, auto]\n" -#: help.c:485 +#: help.c:488 #, c-format msgid "" " fieldsep\n" @@ -3971,7 +3976,7 @@ msgstr "" " fieldsep\n" " ველების გამყოფი დაულაგების გამოტანისათვის (ნაგულისხმევი \"%s\")\n" -#: help.c:488 +#: help.c:491 msgid "" " fieldsep_zero\n" " set field separator for unaligned output to a zero byte\n" @@ -3979,7 +3984,7 @@ msgstr "" " fieldsep_zero\n" " დაულაგებელი გამოტანის ველების გამყოფის ნულოვან ბაიტზე დაყენება\n" -#: help.c:490 +#: help.c:493 msgid "" " footer\n" " enable or disable display of the table footer [on, off]\n" @@ -3987,7 +3992,7 @@ msgstr "" " footer\n" " ცხრილის მინაწერების ჩვენების ჩაართ/გამორთ[on, off]\n" -#: help.c:492 +#: help.c:495 msgid "" " format\n" " set output format [unaligned, aligned, wrapped, html, asciidoc, ...]\n" @@ -3995,7 +4000,7 @@ msgstr "" " format\n" " გამოტანის ფორმატის დაყენება [unaligned, aligned, wrapped, html, asciidoc, ...]\n" -#: help.c:494 +#: help.c:497 msgid "" " linestyle\n" " set the border line drawing style [ascii, old-ascii, unicode]\n" @@ -4003,7 +4008,7 @@ msgstr "" " linestyle\n" " საზღვრის ხაზის ხატვის სტილი [ascii, old-ascii, unicode]\n" -#: help.c:496 +#: help.c:499 msgid "" " null\n" " set the string to be printed in place of a null value\n" @@ -4011,7 +4016,7 @@ msgstr "" " null\n" " ნულოვანი ბაიტის მიერ ნაჩვენები სიმბოლო\n" -#: help.c:498 +#: help.c:501 msgid "" " numericlocale\n" " enable display of a locale-specific character to separate groups of digits\n" @@ -4019,7 +4024,7 @@ msgstr "" " numericlocale\n" " ციფრის ჯგუფების გასაყოფად ენის სპეციფიკური სიმბოლოს გამოყენება\n" -#: help.c:500 +#: help.c:503 msgid "" " pager\n" " control when an external pager is used [yes, no, always]\n" @@ -4027,7 +4032,7 @@ msgstr "" " pager\n" " გვერდების გარე გადამრთველის გამოყენება[yes, no, always]\n" -#: help.c:502 +#: help.c:505 msgid "" " recordsep\n" " record (line) separator for unaligned output\n" @@ -4035,7 +4040,7 @@ msgstr "" " recordsep\n" " დაულაგებელი გამოტანის ჩანაწერების(ხაზების) გამყოფი\n" -#: help.c:504 +#: help.c:507 msgid "" " recordsep_zero\n" " set record separator for unaligned output to a zero byte\n" @@ -4043,7 +4048,7 @@ msgstr "" " recordsep_zero\n" " დაულაგებელი გამოტანის ველების გამყოფის ნულოვან ბაიტზე დაყენება\n" -#: help.c:506 +#: help.c:509 msgid "" " tableattr (or T)\n" " specify attributes for table tag in html format, or proportional\n" @@ -4053,7 +4058,7 @@ msgstr "" " მიუთითებს HTML ფორმატის table ჭდის ატრიბუტებს ან სვეტების პოპორციულ სიგანეს\n" " მარცხნივ სწორებული მონაცემების ტიპებისთვის latex-longtable ფორმატში\n" -#: help.c:509 +#: help.c:512 msgid "" " title\n" " set the table title for subsequently printed tables\n" @@ -4061,7 +4066,7 @@ msgstr "" " title\n" " ცხრილის სათაურის დაყენება შემდგომ დაბეჭდილი ცხრილებისთვის\n" -#: help.c:511 +#: help.c:514 msgid "" " tuples_only\n" " if set, only actual table data is shown\n" @@ -4069,7 +4074,7 @@ msgstr "" " tuples_only\n" " თუ დაყენებულია, ნაჩვენები იქნება მხოლოდ მიმდინარე მონაცემები\n" -#: help.c:513 +#: help.c:516 msgid "" " unicode_border_linestyle\n" " unicode_column_linestyle\n" @@ -4081,7 +4086,7 @@ msgstr "" " unicode_header_linestyle\n" " უნიკოდის ხაზის დახატვის სტილი [single, double]\n" -#: help.c:517 +#: help.c:520 msgid "" " xheader_width\n" " set the maximum width of the header for expanded output\n" @@ -4091,7 +4096,7 @@ msgstr "" " აყენებს თავსართის მაქსიმალურ სიგანეს გაფართოებული გამოტანისთვის\n" " [სრული, სვეტი, გვერდი, მთელი_რიცხვი]\n" -#: help.c:521 +#: help.c:524 msgid "" "\n" "Environment variables:\n" @@ -4099,7 +4104,7 @@ msgstr "" "\n" "გარემოს ცვლადები:\n" -#: help.c:525 +#: help.c:528 msgid "" " NAME=VALUE [NAME=VALUE] psql ...\n" " or \\setenv NAME [VALUE] inside psql\n" @@ -4109,7 +4114,7 @@ msgstr "" " ან \\setenv სახელი[მნიშვნელობა ] psql-ის სიგნით\n" "\n" -#: help.c:527 +#: help.c:530 msgid "" " set NAME=VALUE\n" " psql ...\n" @@ -4121,7 +4126,7 @@ msgstr "" " ან \\setenv სახელი [მნიშვნელობა] psql-ში\n" "\n" -#: help.c:530 +#: help.c:533 msgid "" " COLUMNS\n" " number of columns for wrapped format\n" @@ -4129,7 +4134,7 @@ msgstr "" " COLUMNS\n" " გადასატანი ფორმატის სვეტების რაოდენობა\n" -#: help.c:532 +#: help.c:535 msgid "" " PGAPPNAME\n" " same as the application_name connection parameter\n" @@ -4137,7 +4142,7 @@ msgstr "" " PGAPPNAME\n" " იგივე, რაც შეერთების პარამეტრი აპლიკაციის_სახელი\n" -#: help.c:534 +#: help.c:537 msgid "" " PGDATABASE\n" " same as the dbname connection parameter\n" @@ -4145,7 +4150,7 @@ msgstr "" " PGDATABASE\n" " იგივე, რაც შეერთების dbname პარამეტრი\n" -#: help.c:536 +#: help.c:539 msgid "" " PGHOST\n" " same as the host connection parameter\n" @@ -4153,7 +4158,7 @@ msgstr "" " PGHOST\n" " იგივე, რაც ჰოსტი შეერთების პარამეტრებში\n" -#: help.c:538 +#: help.c:541 msgid "" " PGPASSFILE\n" " password file name\n" @@ -4161,7 +4166,7 @@ msgstr "" " PGPASSFILE\n" " პაროლების ფაილის სახელი\n" -#: help.c:540 +#: help.c:543 msgid "" " PGPASSWORD\n" " connection password (not recommended)\n" @@ -4169,7 +4174,7 @@ msgstr "" " PGPASSWORD\n" " შეერთების პაროლი (რეკომენდებული არაა)\n" -#: help.c:542 +#: help.c:545 msgid "" " PGPORT\n" " same as the port connection parameter\n" @@ -4177,7 +4182,7 @@ msgstr "" " PGPORT\n" " იგივე, რაც პორტი შეერთების პარამეტრებში\n" -#: help.c:544 +#: help.c:547 msgid "" " PGUSER\n" " same as the user connection parameter\n" @@ -4185,7 +4190,7 @@ msgstr "" " PGUSER\n" " იგივე, რაც მომხმარებლის სახელი შეერთების პარამეტრებში\n" -#: help.c:546 +#: help.c:549 msgid "" " PSQL_EDITOR, EDITOR, VISUAL\n" " editor used by the \\e, \\ef, and \\ev commands\n" @@ -4193,7 +4198,7 @@ msgstr "" " PSQL_EDITOR, EDITOR, VISUAL\n" " \\e, \\ef, და \\ev ბრძანების მიერ გამოყენებული რედაქტორი\n" -#: help.c:548 +#: help.c:551 msgid "" " PSQL_EDITOR_LINENUMBER_ARG\n" " how to specify a line number when invoking the editor\n" @@ -4201,7 +4206,7 @@ msgstr "" " PSQL_EDITOR_LINENUMBER_ARG\n" " რედაქტორის გამოძახებისას ხაზის ნომრის მითითების ხერხი\n" -#: help.c:550 +#: help.c:553 msgid "" " PSQL_HISTORY\n" " alternative location for the command history file\n" @@ -4209,7 +4214,7 @@ msgstr "" " PSQL_HISTORY\n" " ბრძანებების ისტორიის ფაილის ალტერნატიული მდებარეობა\n" -#: help.c:552 +#: help.c:555 msgid "" " PSQL_PAGER, PAGER\n" " name of external pager program\n" @@ -4217,7 +4222,7 @@ msgstr "" " PSQL_PAGER, PAGER\n" " გვერდების გადამრთველი გარე პროგრამის სახელი\n" -#: help.c:555 +#: help.c:558 msgid "" " PSQL_WATCH_PAGER\n" " name of external pager program used for \\watch\n" @@ -4225,7 +4230,7 @@ msgstr "" " PSQL_WATCH_PAGER\n" " \\watch-ისთვის გამოყენებული გვერდების გადამრთველი გარე პროგრამა\n" -#: help.c:558 +#: help.c:561 msgid "" " PSQLRC\n" " alternative location for the user's .psqlrc file\n" @@ -4233,7 +4238,7 @@ msgstr "" " PSQLRC\n" " მომხმარებლის .psqlrc ფაილის ალტერნატიული მდებარეობა\n" -#: help.c:560 +#: help.c:563 msgid "" " SHELL\n" " shell used by the \\! command\n" @@ -4241,7 +4246,7 @@ msgstr "" " SHELL\n" " \\! ბრძანების მიერ გამოყენებული გარსი\n" -#: help.c:562 +#: help.c:565 msgid "" " TMPDIR\n" " directory for temporary files\n" @@ -4249,11 +4254,11 @@ msgstr "" " TMPDIR\n" " დროებითი ფაილების საქაღალდე\n" -#: help.c:622 +#: help.c:625 msgid "Available help:\n" msgstr "ხელმისაწვდომი დახმარება:\n" -#: help.c:717 +#: help.c:720 #, c-format msgid "" "Command: %s\n" @@ -4272,7 +4277,7 @@ msgstr "" "URL: %s\n" "\n" -#: help.c:740 +#: help.c:743 #, c-format msgid "" "No help available for \"%s\".\n" @@ -4404,189 +4409,189 @@ msgstr "%s: არასაკმარისი მეხსიერება" #: sql_help.c:746 sql_help.c:750 sql_help.c:771 sql_help.c:774 sql_help.c:777 #: sql_help.c:806 sql_help.c:818 sql_help.c:826 sql_help.c:829 sql_help.c:832 #: sql_help.c:847 sql_help.c:850 sql_help.c:879 sql_help.c:884 sql_help.c:889 -#: sql_help.c:894 sql_help.c:899 sql_help.c:926 sql_help.c:928 sql_help.c:930 -#: sql_help.c:932 sql_help.c:935 sql_help.c:937 sql_help.c:984 sql_help.c:1029 -#: sql_help.c:1034 sql_help.c:1039 sql_help.c:1044 sql_help.c:1049 -#: sql_help.c:1068 sql_help.c:1079 sql_help.c:1081 sql_help.c:1102 -#: sql_help.c:1112 sql_help.c:1113 sql_help.c:1115 sql_help.c:1117 -#: sql_help.c:1129 sql_help.c:1133 sql_help.c:1135 sql_help.c:1147 -#: sql_help.c:1149 sql_help.c:1151 sql_help.c:1153 sql_help.c:1172 -#: sql_help.c:1174 sql_help.c:1178 sql_help.c:1182 sql_help.c:1186 -#: sql_help.c:1189 sql_help.c:1190 sql_help.c:1191 sql_help.c:1194 -#: sql_help.c:1197 sql_help.c:1199 sql_help.c:1341 sql_help.c:1343 -#: sql_help.c:1346 sql_help.c:1349 sql_help.c:1351 sql_help.c:1353 -#: sql_help.c:1356 sql_help.c:1359 sql_help.c:1487 sql_help.c:1489 -#: sql_help.c:1491 sql_help.c:1494 sql_help.c:1515 sql_help.c:1518 -#: sql_help.c:1521 sql_help.c:1524 sql_help.c:1528 sql_help.c:1530 -#: sql_help.c:1532 sql_help.c:1534 sql_help.c:1548 sql_help.c:1551 -#: sql_help.c:1553 sql_help.c:1555 sql_help.c:1565 sql_help.c:1567 -#: sql_help.c:1577 sql_help.c:1579 sql_help.c:1589 sql_help.c:1592 -#: sql_help.c:1615 sql_help.c:1617 sql_help.c:1619 sql_help.c:1621 -#: sql_help.c:1624 sql_help.c:1626 sql_help.c:1629 sql_help.c:1632 -#: sql_help.c:1683 sql_help.c:1726 sql_help.c:1729 sql_help.c:1731 -#: sql_help.c:1733 sql_help.c:1736 sql_help.c:1738 sql_help.c:1740 -#: sql_help.c:1743 sql_help.c:1793 sql_help.c:1809 sql_help.c:2044 -#: sql_help.c:2113 sql_help.c:2132 sql_help.c:2145 sql_help.c:2203 -#: sql_help.c:2211 sql_help.c:2221 sql_help.c:2249 sql_help.c:2282 -#: sql_help.c:2300 sql_help.c:2328 sql_help.c:2451 sql_help.c:2497 -#: sql_help.c:2522 sql_help.c:2545 sql_help.c:2549 sql_help.c:2583 -#: sql_help.c:2603 sql_help.c:2625 sql_help.c:2639 sql_help.c:2660 -#: sql_help.c:2689 sql_help.c:2722 sql_help.c:2745 sql_help.c:2794 -#: sql_help.c:3098 sql_help.c:3111 sql_help.c:3128 sql_help.c:3144 -#: sql_help.c:3184 sql_help.c:3238 sql_help.c:3242 sql_help.c:3244 -#: sql_help.c:3251 sql_help.c:3270 sql_help.c:3297 sql_help.c:3332 -#: sql_help.c:3344 sql_help.c:3353 sql_help.c:3399 sql_help.c:3413 -#: sql_help.c:3441 sql_help.c:3449 sql_help.c:3461 sql_help.c:3471 -#: sql_help.c:3479 sql_help.c:3487 sql_help.c:3495 sql_help.c:3503 -#: sql_help.c:3512 sql_help.c:3523 sql_help.c:3531 sql_help.c:3539 -#: sql_help.c:3547 sql_help.c:3555 sql_help.c:3565 sql_help.c:3574 -#: sql_help.c:3583 sql_help.c:3591 sql_help.c:3601 sql_help.c:3612 -#: sql_help.c:3620 sql_help.c:3629 sql_help.c:3640 sql_help.c:3649 -#: sql_help.c:3657 sql_help.c:3665 sql_help.c:3673 sql_help.c:3681 -#: sql_help.c:3689 sql_help.c:3697 sql_help.c:3705 sql_help.c:3713 -#: sql_help.c:3721 sql_help.c:3729 sql_help.c:3746 sql_help.c:3755 -#: sql_help.c:3763 sql_help.c:3780 sql_help.c:3795 sql_help.c:4110 -#: sql_help.c:4233 sql_help.c:4262 sql_help.c:4278 sql_help.c:4280 -#: sql_help.c:4784 sql_help.c:4832 sql_help.c:4991 +#: sql_help.c:894 sql_help.c:899 sql_help.c:935 sql_help.c:937 sql_help.c:939 +#: sql_help.c:941 sql_help.c:944 sql_help.c:946 sql_help.c:998 sql_help.c:1043 +#: sql_help.c:1048 sql_help.c:1053 sql_help.c:1058 sql_help.c:1063 +#: sql_help.c:1082 sql_help.c:1093 sql_help.c:1095 sql_help.c:1116 +#: sql_help.c:1126 sql_help.c:1127 sql_help.c:1129 sql_help.c:1131 +#: sql_help.c:1143 sql_help.c:1147 sql_help.c:1149 sql_help.c:1161 +#: sql_help.c:1163 sql_help.c:1165 sql_help.c:1167 sql_help.c:1186 +#: sql_help.c:1188 sql_help.c:1192 sql_help.c:1196 sql_help.c:1200 +#: sql_help.c:1203 sql_help.c:1204 sql_help.c:1205 sql_help.c:1208 +#: sql_help.c:1211 sql_help.c:1213 sql_help.c:1355 sql_help.c:1357 +#: sql_help.c:1360 sql_help.c:1363 sql_help.c:1365 sql_help.c:1367 +#: sql_help.c:1370 sql_help.c:1373 sql_help.c:1501 sql_help.c:1503 +#: sql_help.c:1505 sql_help.c:1508 sql_help.c:1529 sql_help.c:1532 +#: sql_help.c:1535 sql_help.c:1538 sql_help.c:1542 sql_help.c:1544 +#: sql_help.c:1546 sql_help.c:1548 sql_help.c:1562 sql_help.c:1565 +#: sql_help.c:1567 sql_help.c:1569 sql_help.c:1579 sql_help.c:1581 +#: sql_help.c:1591 sql_help.c:1593 sql_help.c:1603 sql_help.c:1606 +#: sql_help.c:1629 sql_help.c:1631 sql_help.c:1633 sql_help.c:1635 +#: sql_help.c:1638 sql_help.c:1640 sql_help.c:1643 sql_help.c:1646 +#: sql_help.c:1697 sql_help.c:1740 sql_help.c:1743 sql_help.c:1745 +#: sql_help.c:1747 sql_help.c:1750 sql_help.c:1752 sql_help.c:1754 +#: sql_help.c:1757 sql_help.c:1807 sql_help.c:1823 sql_help.c:2058 +#: sql_help.c:2127 sql_help.c:2146 sql_help.c:2159 sql_help.c:2217 +#: sql_help.c:2225 sql_help.c:2235 sql_help.c:2263 sql_help.c:2296 +#: sql_help.c:2314 sql_help.c:2342 sql_help.c:2465 sql_help.c:2511 +#: sql_help.c:2536 sql_help.c:2559 sql_help.c:2563 sql_help.c:2597 +#: sql_help.c:2617 sql_help.c:2639 sql_help.c:2653 sql_help.c:2674 +#: sql_help.c:2707 sql_help.c:2742 sql_help.c:2765 sql_help.c:2814 +#: sql_help.c:3118 sql_help.c:3131 sql_help.c:3148 sql_help.c:3164 +#: sql_help.c:3204 sql_help.c:3258 sql_help.c:3262 sql_help.c:3264 +#: sql_help.c:3271 sql_help.c:3290 sql_help.c:3317 sql_help.c:3352 +#: sql_help.c:3364 sql_help.c:3373 sql_help.c:3419 sql_help.c:3433 +#: sql_help.c:3461 sql_help.c:3469 sql_help.c:3481 sql_help.c:3491 +#: sql_help.c:3499 sql_help.c:3507 sql_help.c:3515 sql_help.c:3523 +#: sql_help.c:3532 sql_help.c:3543 sql_help.c:3551 sql_help.c:3559 +#: sql_help.c:3567 sql_help.c:3575 sql_help.c:3585 sql_help.c:3594 +#: sql_help.c:3603 sql_help.c:3611 sql_help.c:3621 sql_help.c:3632 +#: sql_help.c:3640 sql_help.c:3649 sql_help.c:3660 sql_help.c:3669 +#: sql_help.c:3677 sql_help.c:3685 sql_help.c:3693 sql_help.c:3701 +#: sql_help.c:3709 sql_help.c:3717 sql_help.c:3725 sql_help.c:3733 +#: sql_help.c:3741 sql_help.c:3749 sql_help.c:3766 sql_help.c:3775 +#: sql_help.c:3783 sql_help.c:3800 sql_help.c:3815 sql_help.c:4130 +#: sql_help.c:4253 sql_help.c:4282 sql_help.c:4298 sql_help.c:4300 +#: sql_help.c:4804 sql_help.c:4852 sql_help.c:5011 msgid "name" msgstr "name" -#: sql_help.c:36 sql_help.c:39 sql_help.c:42 sql_help.c:354 sql_help.c:1886 -#: sql_help.c:3414 sql_help.c:4551 +#: sql_help.c:36 sql_help.c:39 sql_help.c:42 sql_help.c:354 sql_help.c:1900 +#: sql_help.c:3434 sql_help.c:4571 msgid "aggregate_signature" msgstr "აგრეგატის სახელმოწერა" #: sql_help.c:37 sql_help.c:67 sql_help.c:82 sql_help.c:120 sql_help.c:274 #: sql_help.c:295 sql_help.c:426 sql_help.c:473 sql_help.c:552 sql_help.c:600 #: sql_help.c:618 sql_help.c:645 sql_help.c:698 sql_help.c:773 sql_help.c:828 -#: sql_help.c:849 sql_help.c:888 sql_help.c:938 sql_help.c:985 sql_help.c:1038 -#: sql_help.c:1070 sql_help.c:1080 sql_help.c:1116 sql_help.c:1136 -#: sql_help.c:1150 sql_help.c:1200 sql_help.c:1350 sql_help.c:1488 -#: sql_help.c:1531 sql_help.c:1552 sql_help.c:1566 sql_help.c:1578 -#: sql_help.c:1591 sql_help.c:1618 sql_help.c:1684 sql_help.c:1737 +#: sql_help.c:849 sql_help.c:888 sql_help.c:947 sql_help.c:999 sql_help.c:1052 +#: sql_help.c:1084 sql_help.c:1094 sql_help.c:1130 sql_help.c:1150 +#: sql_help.c:1164 sql_help.c:1214 sql_help.c:1364 sql_help.c:1502 +#: sql_help.c:1545 sql_help.c:1566 sql_help.c:1580 sql_help.c:1592 +#: sql_help.c:1605 sql_help.c:1632 sql_help.c:1698 sql_help.c:1751 msgid "new_name" msgstr "ახალი_სახელი" #: sql_help.c:40 sql_help.c:69 sql_help.c:84 sql_help.c:122 sql_help.c:272 #: sql_help.c:293 sql_help.c:424 sql_help.c:509 sql_help.c:557 sql_help.c:647 #: sql_help.c:656 sql_help.c:721 sql_help.c:745 sql_help.c:776 sql_help.c:831 -#: sql_help.c:893 sql_help.c:936 sql_help.c:1043 sql_help.c:1082 -#: sql_help.c:1114 sql_help.c:1134 sql_help.c:1148 sql_help.c:1198 -#: sql_help.c:1417 sql_help.c:1490 sql_help.c:1533 sql_help.c:1554 -#: sql_help.c:1616 sql_help.c:1732 sql_help.c:3084 +#: sql_help.c:893 sql_help.c:945 sql_help.c:1057 sql_help.c:1096 +#: sql_help.c:1128 sql_help.c:1148 sql_help.c:1162 sql_help.c:1212 +#: sql_help.c:1431 sql_help.c:1504 sql_help.c:1547 sql_help.c:1568 +#: sql_help.c:1630 sql_help.c:1746 sql_help.c:3104 msgid "new_owner" msgstr "ახალი_მფლობელი" #: sql_help.c:43 sql_help.c:71 sql_help.c:86 sql_help.c:276 sql_help.c:346 #: sql_help.c:475 sql_help.c:562 sql_help.c:700 sql_help.c:749 sql_help.c:779 -#: sql_help.c:834 sql_help.c:898 sql_help.c:1048 sql_help.c:1118 -#: sql_help.c:1152 sql_help.c:1352 sql_help.c:1535 sql_help.c:1556 -#: sql_help.c:1568 sql_help.c:1580 sql_help.c:1620 sql_help.c:1739 +#: sql_help.c:834 sql_help.c:898 sql_help.c:1062 sql_help.c:1132 +#: sql_help.c:1166 sql_help.c:1366 sql_help.c:1549 sql_help.c:1570 +#: sql_help.c:1582 sql_help.c:1594 sql_help.c:1634 sql_help.c:1753 msgid "new_schema" msgstr "ახალი_სქემა" -#: sql_help.c:44 sql_help.c:1950 sql_help.c:3415 sql_help.c:4580 +#: sql_help.c:44 sql_help.c:1964 sql_help.c:3435 sql_help.c:4600 msgid "where aggregate_signature is:" msgstr "სადაც aggregate_signature არის:" #: sql_help.c:45 sql_help.c:48 sql_help.c:51 sql_help.c:364 sql_help.c:377 #: sql_help.c:381 sql_help.c:397 sql_help.c:400 sql_help.c:403 sql_help.c:544 #: sql_help.c:549 sql_help.c:554 sql_help.c:559 sql_help.c:564 sql_help.c:880 -#: sql_help.c:885 sql_help.c:890 sql_help.c:895 sql_help.c:900 sql_help.c:1030 -#: sql_help.c:1035 sql_help.c:1040 sql_help.c:1045 sql_help.c:1050 -#: sql_help.c:1904 sql_help.c:1921 sql_help.c:1927 sql_help.c:1951 -#: sql_help.c:1954 sql_help.c:1957 sql_help.c:2114 sql_help.c:2133 -#: sql_help.c:2136 sql_help.c:2452 sql_help.c:2661 sql_help.c:3416 -#: sql_help.c:3419 sql_help.c:3422 sql_help.c:3513 sql_help.c:3602 -#: sql_help.c:3630 sql_help.c:3983 sql_help.c:4450 sql_help.c:4557 -#: sql_help.c:4564 sql_help.c:4570 sql_help.c:4581 sql_help.c:4584 -#: sql_help.c:4587 +#: sql_help.c:885 sql_help.c:890 sql_help.c:895 sql_help.c:900 sql_help.c:1044 +#: sql_help.c:1049 sql_help.c:1054 sql_help.c:1059 sql_help.c:1064 +#: sql_help.c:1918 sql_help.c:1935 sql_help.c:1941 sql_help.c:1965 +#: sql_help.c:1968 sql_help.c:1971 sql_help.c:2128 sql_help.c:2147 +#: sql_help.c:2150 sql_help.c:2466 sql_help.c:2675 sql_help.c:3436 +#: sql_help.c:3439 sql_help.c:3442 sql_help.c:3533 sql_help.c:3622 +#: sql_help.c:3650 sql_help.c:4003 sql_help.c:4470 sql_help.c:4577 +#: sql_help.c:4584 sql_help.c:4590 sql_help.c:4601 sql_help.c:4604 +#: sql_help.c:4607 msgid "argmode" msgstr "არგრეჟიმი" #: sql_help.c:46 sql_help.c:49 sql_help.c:52 sql_help.c:365 sql_help.c:378 #: sql_help.c:382 sql_help.c:398 sql_help.c:401 sql_help.c:404 sql_help.c:545 #: sql_help.c:550 sql_help.c:555 sql_help.c:560 sql_help.c:565 sql_help.c:881 -#: sql_help.c:886 sql_help.c:891 sql_help.c:896 sql_help.c:901 sql_help.c:1031 -#: sql_help.c:1036 sql_help.c:1041 sql_help.c:1046 sql_help.c:1051 -#: sql_help.c:1905 sql_help.c:1922 sql_help.c:1928 sql_help.c:1952 -#: sql_help.c:1955 sql_help.c:1958 sql_help.c:2115 sql_help.c:2134 -#: sql_help.c:2137 sql_help.c:2453 sql_help.c:2662 sql_help.c:3417 -#: sql_help.c:3420 sql_help.c:3423 sql_help.c:3514 sql_help.c:3603 -#: sql_help.c:3631 sql_help.c:4558 sql_help.c:4565 sql_help.c:4571 -#: sql_help.c:4582 sql_help.c:4585 sql_help.c:4588 +#: sql_help.c:886 sql_help.c:891 sql_help.c:896 sql_help.c:901 sql_help.c:1045 +#: sql_help.c:1050 sql_help.c:1055 sql_help.c:1060 sql_help.c:1065 +#: sql_help.c:1919 sql_help.c:1936 sql_help.c:1942 sql_help.c:1966 +#: sql_help.c:1969 sql_help.c:1972 sql_help.c:2129 sql_help.c:2148 +#: sql_help.c:2151 sql_help.c:2467 sql_help.c:2676 sql_help.c:3437 +#: sql_help.c:3440 sql_help.c:3443 sql_help.c:3534 sql_help.c:3623 +#: sql_help.c:3651 sql_help.c:4578 sql_help.c:4585 sql_help.c:4591 +#: sql_help.c:4602 sql_help.c:4605 sql_help.c:4608 msgid "argname" msgstr "არგსახელი" #: sql_help.c:47 sql_help.c:50 sql_help.c:53 sql_help.c:366 sql_help.c:379 #: sql_help.c:383 sql_help.c:399 sql_help.c:402 sql_help.c:405 sql_help.c:546 #: sql_help.c:551 sql_help.c:556 sql_help.c:561 sql_help.c:566 sql_help.c:882 -#: sql_help.c:887 sql_help.c:892 sql_help.c:897 sql_help.c:902 sql_help.c:1032 -#: sql_help.c:1037 sql_help.c:1042 sql_help.c:1047 sql_help.c:1052 -#: sql_help.c:1906 sql_help.c:1923 sql_help.c:1929 sql_help.c:1953 -#: sql_help.c:1956 sql_help.c:1959 sql_help.c:2454 sql_help.c:2663 -#: sql_help.c:3418 sql_help.c:3421 sql_help.c:3424 sql_help.c:3515 -#: sql_help.c:3604 sql_help.c:3632 sql_help.c:4559 sql_help.c:4566 -#: sql_help.c:4572 sql_help.c:4583 sql_help.c:4586 sql_help.c:4589 +#: sql_help.c:887 sql_help.c:892 sql_help.c:897 sql_help.c:902 sql_help.c:1046 +#: sql_help.c:1051 sql_help.c:1056 sql_help.c:1061 sql_help.c:1066 +#: sql_help.c:1920 sql_help.c:1937 sql_help.c:1943 sql_help.c:1967 +#: sql_help.c:1970 sql_help.c:1973 sql_help.c:2468 sql_help.c:2677 +#: sql_help.c:3438 sql_help.c:3441 sql_help.c:3444 sql_help.c:3535 +#: sql_help.c:3624 sql_help.c:3652 sql_help.c:4579 sql_help.c:4586 +#: sql_help.c:4592 sql_help.c:4603 sql_help.c:4606 sql_help.c:4609 msgid "argtype" msgstr "არგტიპი" -#: sql_help.c:114 sql_help.c:421 sql_help.c:498 sql_help.c:510 sql_help.c:979 -#: sql_help.c:1131 sql_help.c:1549 sql_help.c:1678 sql_help.c:1710 -#: sql_help.c:1762 sql_help.c:1821 sql_help.c:2011 sql_help.c:2018 -#: sql_help.c:2331 sql_help.c:2389 sql_help.c:2398 sql_help.c:2407 -#: sql_help.c:2498 sql_help.c:2723 sql_help.c:2816 sql_help.c:3113 -#: sql_help.c:3298 sql_help.c:3320 sql_help.c:3462 sql_help.c:3819 -#: sql_help.c:4027 sql_help.c:4277 sql_help.c:4279 sql_help.c:5059 +#: sql_help.c:114 sql_help.c:421 sql_help.c:498 sql_help.c:510 sql_help.c:993 +#: sql_help.c:1145 sql_help.c:1563 sql_help.c:1692 sql_help.c:1724 +#: sql_help.c:1776 sql_help.c:1835 sql_help.c:2025 sql_help.c:2032 +#: sql_help.c:2345 sql_help.c:2403 sql_help.c:2412 sql_help.c:2421 +#: sql_help.c:2512 sql_help.c:2743 sql_help.c:2836 sql_help.c:3133 +#: sql_help.c:3318 sql_help.c:3340 sql_help.c:3482 sql_help.c:3839 +#: sql_help.c:4047 sql_help.c:4297 sql_help.c:4299 sql_help.c:5079 msgid "option" msgstr "მორგება" -#: sql_help.c:115 sql_help.c:980 sql_help.c:1679 sql_help.c:2499 -#: sql_help.c:2724 sql_help.c:3299 sql_help.c:3463 +#: sql_help.c:115 sql_help.c:994 sql_help.c:1693 sql_help.c:2513 +#: sql_help.c:2744 sql_help.c:3319 sql_help.c:3483 msgid "where option can be:" msgstr "სადაც option შეიძლება იყოს:" -#: sql_help.c:116 sql_help.c:2263 +#: sql_help.c:116 sql_help.c:2277 msgid "allowconn" msgstr "შეერთ_ნებართვ" -#: sql_help.c:117 sql_help.c:981 sql_help.c:1680 sql_help.c:2264 -#: sql_help.c:2500 sql_help.c:2725 sql_help.c:3300 +#: sql_help.c:117 sql_help.c:995 sql_help.c:1694 sql_help.c:2278 +#: sql_help.c:2514 sql_help.c:2745 sql_help.c:3320 msgid "connlimit" msgstr "შეერთ_ლიმიტი" -#: sql_help.c:118 sql_help.c:2265 +#: sql_help.c:118 sql_help.c:2279 msgid "istemplate" msgstr "შაბლონია" -#: sql_help.c:124 sql_help.c:635 sql_help.c:703 sql_help.c:717 sql_help.c:1355 -#: sql_help.c:1410 sql_help.c:4283 +#: sql_help.c:124 sql_help.c:635 sql_help.c:703 sql_help.c:717 sql_help.c:1369 +#: sql_help.c:1424 sql_help.c:4303 msgid "new_tablespace" msgstr "ცხრილების_ახალი_სივრცე" #: sql_help.c:127 sql_help.c:130 sql_help.c:132 sql_help.c:572 sql_help.c:574 -#: sql_help.c:575 sql_help.c:905 sql_help.c:907 sql_help.c:908 sql_help.c:988 -#: sql_help.c:992 sql_help.c:995 sql_help.c:1057 sql_help.c:1059 -#: sql_help.c:1060 sql_help.c:1211 sql_help.c:1213 sql_help.c:1687 -#: sql_help.c:1691 sql_help.c:1694 sql_help.c:2464 sql_help.c:2667 -#: sql_help.c:3995 sql_help.c:4301 sql_help.c:4462 sql_help.c:4772 +#: sql_help.c:575 sql_help.c:905 sql_help.c:907 sql_help.c:908 sql_help.c:1002 +#: sql_help.c:1006 sql_help.c:1009 sql_help.c:1071 sql_help.c:1073 +#: sql_help.c:1074 sql_help.c:1225 sql_help.c:1227 sql_help.c:1701 +#: sql_help.c:1705 sql_help.c:1708 sql_help.c:2478 sql_help.c:2681 +#: sql_help.c:4015 sql_help.c:4321 sql_help.c:4482 sql_help.c:4792 msgid "configuration_parameter" msgstr "კონფიგურაციის_პარამეტრი" #: sql_help.c:128 sql_help.c:422 sql_help.c:493 sql_help.c:499 sql_help.c:511 #: sql_help.c:573 sql_help.c:627 sql_help.c:709 sql_help.c:719 sql_help.c:906 -#: sql_help.c:934 sql_help.c:989 sql_help.c:1058 sql_help.c:1132 -#: sql_help.c:1177 sql_help.c:1181 sql_help.c:1185 sql_help.c:1188 -#: sql_help.c:1193 sql_help.c:1196 sql_help.c:1212 sql_help.c:1388 -#: sql_help.c:1412 sql_help.c:1465 sql_help.c:1473 sql_help.c:1493 -#: sql_help.c:1550 sql_help.c:1634 sql_help.c:1688 sql_help.c:1711 -#: sql_help.c:2332 sql_help.c:2390 sql_help.c:2399 sql_help.c:2408 -#: sql_help.c:2465 sql_help.c:2466 sql_help.c:2530 sql_help.c:2533 -#: sql_help.c:2567 sql_help.c:2668 sql_help.c:2669 sql_help.c:2692 -#: sql_help.c:2817 sql_help.c:2856 sql_help.c:2967 sql_help.c:2980 -#: sql_help.c:2994 sql_help.c:3040 sql_help.c:3048 sql_help.c:3070 -#: sql_help.c:3087 sql_help.c:3114 sql_help.c:3321 sql_help.c:4028 -#: sql_help.c:4773 sql_help.c:4774 sql_help.c:4775 sql_help.c:4776 +#: sql_help.c:943 sql_help.c:1003 sql_help.c:1072 sql_help.c:1146 +#: sql_help.c:1191 sql_help.c:1195 sql_help.c:1199 sql_help.c:1202 +#: sql_help.c:1207 sql_help.c:1210 sql_help.c:1226 sql_help.c:1402 +#: sql_help.c:1426 sql_help.c:1479 sql_help.c:1487 sql_help.c:1507 +#: sql_help.c:1564 sql_help.c:1648 sql_help.c:1702 sql_help.c:1725 +#: sql_help.c:2346 sql_help.c:2404 sql_help.c:2413 sql_help.c:2422 +#: sql_help.c:2479 sql_help.c:2480 sql_help.c:2544 sql_help.c:2547 +#: sql_help.c:2581 sql_help.c:2682 sql_help.c:2683 sql_help.c:2710 +#: sql_help.c:2837 sql_help.c:2876 sql_help.c:2987 sql_help.c:3000 +#: sql_help.c:3014 sql_help.c:3060 sql_help.c:3068 sql_help.c:3090 +#: sql_help.c:3107 sql_help.c:3134 sql_help.c:3341 sql_help.c:4048 +#: sql_help.c:4793 sql_help.c:4794 sql_help.c:4795 sql_help.c:4796 msgid "value" msgstr "მნიშვნელობა" @@ -4594,10 +4599,10 @@ msgstr "მნიშვნელობა" msgid "target_role" msgstr "სამიზნე_როლი" -#: sql_help.c:215 sql_help.c:943 sql_help.c:2316 sql_help.c:2697 -#: sql_help.c:2770 sql_help.c:2775 sql_help.c:3958 sql_help.c:3967 -#: sql_help.c:3986 sql_help.c:3998 sql_help.c:4425 sql_help.c:4434 -#: sql_help.c:4453 sql_help.c:4465 +#: sql_help.c:215 sql_help.c:950 sql_help.c:953 sql_help.c:2330 sql_help.c:2713 +#: sql_help.c:2790 sql_help.c:2795 sql_help.c:3978 sql_help.c:3987 +#: sql_help.c:4006 sql_help.c:4018 sql_help.c:4445 sql_help.c:4454 +#: sql_help.c:4473 sql_help.c:4485 msgid "schema_name" msgstr "schema_name" @@ -4612,57 +4617,57 @@ msgstr "სადაც abbreviated_grant_or_revoke ერთ-ერთია #: sql_help.c:218 sql_help.c:219 sql_help.c:220 sql_help.c:221 sql_help.c:222 #: sql_help.c:223 sql_help.c:224 sql_help.c:225 sql_help.c:226 sql_help.c:227 #: sql_help.c:228 sql_help.c:229 sql_help.c:598 sql_help.c:634 sql_help.c:702 -#: sql_help.c:852 sql_help.c:999 sql_help.c:1354 sql_help.c:1698 -#: sql_help.c:2503 sql_help.c:2504 sql_help.c:2505 sql_help.c:2506 -#: sql_help.c:2507 sql_help.c:2641 sql_help.c:2728 sql_help.c:2729 -#: sql_help.c:2730 sql_help.c:3303 sql_help.c:3304 sql_help.c:3305 -#: sql_help.c:3306 sql_help.c:3307 sql_help.c:4007 sql_help.c:4011 -#: sql_help.c:4474 sql_help.c:4478 sql_help.c:4794 +#: sql_help.c:852 sql_help.c:1013 sql_help.c:1368 sql_help.c:1712 +#: sql_help.c:2517 sql_help.c:2518 sql_help.c:2519 sql_help.c:2520 +#: sql_help.c:2521 sql_help.c:2655 sql_help.c:2748 sql_help.c:2749 +#: sql_help.c:2750 sql_help.c:3323 sql_help.c:3324 sql_help.c:3325 +#: sql_help.c:3326 sql_help.c:3327 sql_help.c:4027 sql_help.c:4031 +#: sql_help.c:4494 sql_help.c:4498 sql_help.c:4814 msgid "role_name" msgstr "role_name" -#: sql_help.c:260 sql_help.c:279 sql_help.c:486 sql_help.c:942 sql_help.c:1370 -#: sql_help.c:1372 sql_help.c:1376 sql_help.c:1427 sql_help.c:1439 -#: sql_help.c:1469 sql_help.c:1728 sql_help.c:2285 sql_help.c:2289 -#: sql_help.c:2411 sql_help.c:2417 sql_help.c:2526 sql_help.c:2696 -#: sql_help.c:2833 sql_help.c:2838 sql_help.c:2840 sql_help.c:2962 -#: sql_help.c:2975 sql_help.c:2989 sql_help.c:2998 sql_help.c:3010 -#: sql_help.c:3044 sql_help.c:4060 sql_help.c:4076 sql_help.c:4078 -#: sql_help.c:4176 sql_help.c:4179 sql_help.c:4181 sql_help.c:4644 -#: sql_help.c:4645 sql_help.c:4654 sql_help.c:4701 sql_help.c:4702 -#: sql_help.c:4703 sql_help.c:4704 sql_help.c:4705 sql_help.c:4706 -#: sql_help.c:4747 sql_help.c:4748 sql_help.c:4753 sql_help.c:4758 -#: sql_help.c:4902 sql_help.c:4903 sql_help.c:4912 sql_help.c:4959 -#: sql_help.c:4960 sql_help.c:4961 sql_help.c:4962 sql_help.c:4963 -#: sql_help.c:4964 sql_help.c:5020 sql_help.c:5022 sql_help.c:5089 -#: sql_help.c:5149 sql_help.c:5150 sql_help.c:5159 sql_help.c:5206 -#: sql_help.c:5207 sql_help.c:5208 sql_help.c:5209 sql_help.c:5210 -#: sql_help.c:5211 +#: sql_help.c:260 sql_help.c:279 sql_help.c:486 sql_help.c:957 sql_help.c:1384 +#: sql_help.c:1386 sql_help.c:1390 sql_help.c:1441 sql_help.c:1453 +#: sql_help.c:1483 sql_help.c:1742 sql_help.c:2299 sql_help.c:2303 +#: sql_help.c:2425 sql_help.c:2431 sql_help.c:2540 sql_help.c:2717 +#: sql_help.c:2853 sql_help.c:2858 sql_help.c:2860 sql_help.c:2982 +#: sql_help.c:2995 sql_help.c:3009 sql_help.c:3018 sql_help.c:3030 +#: sql_help.c:3064 sql_help.c:4080 sql_help.c:4096 sql_help.c:4098 +#: sql_help.c:4196 sql_help.c:4199 sql_help.c:4201 sql_help.c:4664 +#: sql_help.c:4665 sql_help.c:4674 sql_help.c:4721 sql_help.c:4722 +#: sql_help.c:4723 sql_help.c:4724 sql_help.c:4725 sql_help.c:4726 +#: sql_help.c:4767 sql_help.c:4768 sql_help.c:4773 sql_help.c:4778 +#: sql_help.c:4922 sql_help.c:4923 sql_help.c:4932 sql_help.c:4979 +#: sql_help.c:4980 sql_help.c:4981 sql_help.c:4982 sql_help.c:4983 +#: sql_help.c:4984 sql_help.c:5040 sql_help.c:5042 sql_help.c:5109 +#: sql_help.c:5169 sql_help.c:5170 sql_help.c:5179 sql_help.c:5226 +#: sql_help.c:5227 sql_help.c:5228 sql_help.c:5229 sql_help.c:5230 +#: sql_help.c:5231 msgid "expression" -msgstr "გამსახულება" +msgstr "expression" -#: sql_help.c:263 sql_help.c:2286 +#: sql_help.c:263 sql_help.c:2300 msgid "domain_constraint" msgstr "დომენის_შეზღუდვა" #: sql_help.c:265 sql_help.c:267 sql_help.c:270 sql_help.c:278 sql_help.c:501 -#: sql_help.c:502 sql_help.c:1347 sql_help.c:1396 sql_help.c:1397 -#: sql_help.c:1398 sql_help.c:1399 sql_help.c:1426 sql_help.c:1438 -#: sql_help.c:1460 sql_help.c:1892 sql_help.c:1894 sql_help.c:2288 -#: sql_help.c:2410 sql_help.c:2415 sql_help.c:2997 sql_help.c:3009 -#: sql_help.c:4073 +#: sql_help.c:502 sql_help.c:1361 sql_help.c:1410 sql_help.c:1411 +#: sql_help.c:1412 sql_help.c:1413 sql_help.c:1440 sql_help.c:1452 +#: sql_help.c:1474 sql_help.c:1906 sql_help.c:1908 sql_help.c:2302 +#: sql_help.c:2424 sql_help.c:2429 sql_help.c:3017 sql_help.c:3029 +#: sql_help.c:4093 msgid "constraint_name" msgstr "შეზღუდვის_სახელი" -#: sql_help.c:268 sql_help.c:1348 +#: sql_help.c:268 sql_help.c:1362 msgid "new_constraint_name" msgstr "ახალი_შეზღუდვის_სახელი" -#: sql_help.c:277 sql_help.c:2287 +#: sql_help.c:277 sql_help.c:2301 msgid "where domain_constraint is:" msgstr "სადაც domain_constraint არის:" -#: sql_help.c:344 sql_help.c:1130 +#: sql_help.c:344 sql_help.c:1144 msgid "new_version" msgstr "ახალი_მნიშვნელობა" @@ -4678,82 +4683,82 @@ msgstr "სადაც member_object არის:" #: sql_help.c:361 sql_help.c:362 sql_help.c:367 sql_help.c:371 sql_help.c:373 #: sql_help.c:375 sql_help.c:384 sql_help.c:385 sql_help.c:386 sql_help.c:387 #: sql_help.c:388 sql_help.c:389 sql_help.c:390 sql_help.c:391 sql_help.c:394 -#: sql_help.c:395 sql_help.c:1884 sql_help.c:1889 sql_help.c:1896 -#: sql_help.c:1897 sql_help.c:1898 sql_help.c:1899 sql_help.c:1900 -#: sql_help.c:1901 sql_help.c:1902 sql_help.c:1907 sql_help.c:1909 -#: sql_help.c:1913 sql_help.c:1915 sql_help.c:1919 sql_help.c:1924 -#: sql_help.c:1925 sql_help.c:1932 sql_help.c:1933 sql_help.c:1934 -#: sql_help.c:1935 sql_help.c:1936 sql_help.c:1937 sql_help.c:1938 -#: sql_help.c:1939 sql_help.c:1940 sql_help.c:1941 sql_help.c:1942 -#: sql_help.c:1947 sql_help.c:1948 sql_help.c:4547 sql_help.c:4552 -#: sql_help.c:4553 sql_help.c:4554 sql_help.c:4555 sql_help.c:4561 -#: sql_help.c:4562 sql_help.c:4567 sql_help.c:4568 sql_help.c:4573 -#: sql_help.c:4574 sql_help.c:4575 sql_help.c:4576 sql_help.c:4577 -#: sql_help.c:4578 +#: sql_help.c:395 sql_help.c:1898 sql_help.c:1903 sql_help.c:1910 +#: sql_help.c:1911 sql_help.c:1912 sql_help.c:1913 sql_help.c:1914 +#: sql_help.c:1915 sql_help.c:1916 sql_help.c:1921 sql_help.c:1923 +#: sql_help.c:1927 sql_help.c:1929 sql_help.c:1933 sql_help.c:1938 +#: sql_help.c:1939 sql_help.c:1946 sql_help.c:1947 sql_help.c:1948 +#: sql_help.c:1949 sql_help.c:1950 sql_help.c:1951 sql_help.c:1952 +#: sql_help.c:1953 sql_help.c:1954 sql_help.c:1955 sql_help.c:1956 +#: sql_help.c:1961 sql_help.c:1962 sql_help.c:4567 sql_help.c:4572 +#: sql_help.c:4573 sql_help.c:4574 sql_help.c:4575 sql_help.c:4581 +#: sql_help.c:4582 sql_help.c:4587 sql_help.c:4588 sql_help.c:4593 +#: sql_help.c:4594 sql_help.c:4595 sql_help.c:4596 sql_help.c:4597 +#: sql_help.c:4598 msgid "object_name" msgstr "ობიექტის_სახელი" -#: sql_help.c:353 sql_help.c:1885 sql_help.c:4550 +#: sql_help.c:353 sql_help.c:1899 sql_help.c:4570 msgid "aggregate_name" msgstr "აგრეგატის სახელი" -#: sql_help.c:355 sql_help.c:1887 sql_help.c:2179 sql_help.c:2183 -#: sql_help.c:2185 sql_help.c:3432 +#: sql_help.c:355 sql_help.c:1901 sql_help.c:2193 sql_help.c:2197 +#: sql_help.c:2199 sql_help.c:3452 msgid "source_type" msgstr "წყაროს_ტიპი" -#: sql_help.c:356 sql_help.c:1888 sql_help.c:2180 sql_help.c:2184 -#: sql_help.c:2186 sql_help.c:3433 +#: sql_help.c:356 sql_help.c:1902 sql_help.c:2194 sql_help.c:2198 +#: sql_help.c:2200 sql_help.c:3453 msgid "target_type" msgstr "სამიზნის_ტიპი" -#: sql_help.c:363 sql_help.c:816 sql_help.c:1903 sql_help.c:2181 -#: sql_help.c:2224 sql_help.c:2304 sql_help.c:2584 sql_help.c:2615 -#: sql_help.c:3190 sql_help.c:4449 sql_help.c:4556 sql_help.c:4673 -#: sql_help.c:4677 sql_help.c:4681 sql_help.c:4684 sql_help.c:4931 -#: sql_help.c:4935 sql_help.c:4939 sql_help.c:4942 sql_help.c:5178 -#: sql_help.c:5182 sql_help.c:5186 sql_help.c:5189 +#: sql_help.c:363 sql_help.c:816 sql_help.c:1917 sql_help.c:2195 +#: sql_help.c:2238 sql_help.c:2318 sql_help.c:2598 sql_help.c:2629 +#: sql_help.c:3210 sql_help.c:4469 sql_help.c:4576 sql_help.c:4693 +#: sql_help.c:4697 sql_help.c:4701 sql_help.c:4704 sql_help.c:4951 +#: sql_help.c:4955 sql_help.c:4959 sql_help.c:4962 sql_help.c:5198 +#: sql_help.c:5202 sql_help.c:5206 sql_help.c:5209 msgid "function_name" msgstr "ფუნქციის_სახელი" -#: sql_help.c:368 sql_help.c:809 sql_help.c:1910 sql_help.c:2608 +#: sql_help.c:368 sql_help.c:809 sql_help.c:1924 sql_help.c:2622 msgid "operator_name" msgstr "ოპერატორის_სახელი" -#: sql_help.c:369 sql_help.c:743 sql_help.c:747 sql_help.c:751 sql_help.c:1911 -#: sql_help.c:2585 sql_help.c:3556 +#: sql_help.c:369 sql_help.c:743 sql_help.c:747 sql_help.c:751 sql_help.c:1925 +#: sql_help.c:2599 sql_help.c:3576 msgid "left_type" msgstr "მარჯვენა ტიპი" -#: sql_help.c:370 sql_help.c:744 sql_help.c:748 sql_help.c:752 sql_help.c:1912 -#: sql_help.c:2586 sql_help.c:3557 +#: sql_help.c:370 sql_help.c:744 sql_help.c:748 sql_help.c:752 sql_help.c:1926 +#: sql_help.c:2600 sql_help.c:3577 msgid "right_type" msgstr "right_type" #: sql_help.c:372 sql_help.c:374 sql_help.c:772 sql_help.c:775 sql_help.c:778 #: sql_help.c:807 sql_help.c:819 sql_help.c:827 sql_help.c:830 sql_help.c:833 -#: sql_help.c:1447 sql_help.c:1914 sql_help.c:1916 sql_help.c:2605 -#: sql_help.c:2626 sql_help.c:3018 sql_help.c:3566 sql_help.c:3575 +#: sql_help.c:1461 sql_help.c:1928 sql_help.c:1930 sql_help.c:2619 +#: sql_help.c:2640 sql_help.c:3038 sql_help.c:3586 sql_help.c:3595 msgid "index_method" msgstr "ინდექსის_მეთოდი" -#: sql_help.c:376 sql_help.c:1920 sql_help.c:4563 +#: sql_help.c:376 sql_help.c:1934 sql_help.c:4583 msgid "procedure_name" msgstr "პროცედურის სახელი" -#: sql_help.c:380 sql_help.c:1926 sql_help.c:3982 sql_help.c:4569 +#: sql_help.c:380 sql_help.c:1940 sql_help.c:4002 sql_help.c:4589 msgid "routine_name" msgstr "ქვეპროგრამის სახელი" -#: sql_help.c:392 sql_help.c:1416 sql_help.c:1943 sql_help.c:2460 -#: sql_help.c:2666 sql_help.c:2970 sql_help.c:3157 sql_help.c:3737 -#: sql_help.c:4004 sql_help.c:4471 +#: sql_help.c:392 sql_help.c:1430 sql_help.c:1957 sql_help.c:2474 +#: sql_help.c:2680 sql_help.c:2990 sql_help.c:3177 sql_help.c:3757 +#: sql_help.c:4024 sql_help.c:4491 msgid "type_name" msgstr "ტიპის სახელი" -#: sql_help.c:393 sql_help.c:1944 sql_help.c:2459 sql_help.c:2665 -#: sql_help.c:3158 sql_help.c:3390 sql_help.c:3738 sql_help.c:3989 -#: sql_help.c:4456 +#: sql_help.c:393 sql_help.c:1958 sql_help.c:2473 sql_help.c:2679 +#: sql_help.c:3178 sql_help.c:3410 sql_help.c:3758 sql_help.c:4009 +#: sql_help.c:4476 msgid "lang_name" msgstr "ენის_სახელი" @@ -4761,149 +4766,149 @@ msgstr "ენის_სახელი" msgid "and aggregate_signature is:" msgstr "და აგრეგატული_ხელმოწერა არის:" -#: sql_help.c:419 sql_help.c:2046 sql_help.c:2329 +#: sql_help.c:419 sql_help.c:2060 sql_help.c:2343 msgid "handler_function" msgstr "დამმუშავებელი_ფუნქცია" -#: sql_help.c:420 sql_help.c:2330 +#: sql_help.c:420 sql_help.c:2344 msgid "validator_function" msgstr "შემმოწმებელი_ფუნქცია" -#: sql_help.c:468 sql_help.c:547 sql_help.c:691 sql_help.c:883 sql_help.c:1033 -#: sql_help.c:1342 sql_help.c:1625 +#: sql_help.c:468 sql_help.c:547 sql_help.c:691 sql_help.c:883 sql_help.c:1047 +#: sql_help.c:1356 sql_help.c:1639 msgid "action" msgstr "ქმედება" #: sql_help.c:470 sql_help.c:477 sql_help.c:481 sql_help.c:482 sql_help.c:485 #: sql_help.c:487 sql_help.c:488 sql_help.c:489 sql_help.c:491 sql_help.c:494 #: sql_help.c:496 sql_help.c:497 sql_help.c:695 sql_help.c:705 sql_help.c:707 -#: sql_help.c:710 sql_help.c:712 sql_help.c:713 sql_help.c:941 sql_help.c:1111 -#: sql_help.c:1344 sql_help.c:1362 sql_help.c:1366 sql_help.c:1367 -#: sql_help.c:1371 sql_help.c:1373 sql_help.c:1374 sql_help.c:1375 -#: sql_help.c:1377 sql_help.c:1378 sql_help.c:1380 sql_help.c:1383 -#: sql_help.c:1384 sql_help.c:1386 sql_help.c:1389 sql_help.c:1391 -#: sql_help.c:1392 sql_help.c:1440 sql_help.c:1441 sql_help.c:1442 -#: sql_help.c:1444 sql_help.c:1445 sql_help.c:1452 sql_help.c:1453 -#: sql_help.c:1463 sql_help.c:1468 sql_help.c:1475 sql_help.c:1476 -#: sql_help.c:1727 sql_help.c:1730 sql_help.c:1734 sql_help.c:1770 -#: sql_help.c:1891 sql_help.c:2008 sql_help.c:2014 sql_help.c:2028 -#: sql_help.c:2029 sql_help.c:2030 sql_help.c:2387 sql_help.c:2402 -#: sql_help.c:2416 sql_help.c:2457 sql_help.c:2525 sql_help.c:2531 -#: sql_help.c:2564 sql_help.c:2695 sql_help.c:2802 sql_help.c:2837 -#: sql_help.c:2839 sql_help.c:2952 sql_help.c:2961 sql_help.c:2971 -#: sql_help.c:2974 sql_help.c:2984 sql_help.c:2988 sql_help.c:3011 -#: sql_help.c:3012 sql_help.c:3013 sql_help.c:3015 sql_help.c:3016 -#: sql_help.c:3023 sql_help.c:3024 sql_help.c:3038 sql_help.c:3043 -#: sql_help.c:3050 sql_help.c:3051 sql_help.c:3067 sql_help.c:3193 -#: sql_help.c:3333 sql_help.c:3961 sql_help.c:3962 sql_help.c:4059 -#: sql_help.c:4075 sql_help.c:4077 sql_help.c:4079 sql_help.c:4175 -#: sql_help.c:4178 sql_help.c:4180 sql_help.c:4182 sql_help.c:4428 -#: sql_help.c:4429 sql_help.c:4549 sql_help.c:4710 sql_help.c:4717 -#: sql_help.c:4719 sql_help.c:4968 sql_help.c:4975 sql_help.c:4977 -#: sql_help.c:5019 sql_help.c:5021 sql_help.c:5023 sql_help.c:5077 -#: sql_help.c:5215 sql_help.c:5222 sql_help.c:5224 +#: sql_help.c:710 sql_help.c:712 sql_help.c:713 sql_help.c:956 sql_help.c:1125 +#: sql_help.c:1358 sql_help.c:1376 sql_help.c:1380 sql_help.c:1381 +#: sql_help.c:1385 sql_help.c:1387 sql_help.c:1388 sql_help.c:1389 +#: sql_help.c:1391 sql_help.c:1392 sql_help.c:1394 sql_help.c:1397 +#: sql_help.c:1398 sql_help.c:1400 sql_help.c:1403 sql_help.c:1405 +#: sql_help.c:1406 sql_help.c:1454 sql_help.c:1455 sql_help.c:1456 +#: sql_help.c:1458 sql_help.c:1459 sql_help.c:1466 sql_help.c:1467 +#: sql_help.c:1477 sql_help.c:1482 sql_help.c:1489 sql_help.c:1490 +#: sql_help.c:1741 sql_help.c:1744 sql_help.c:1748 sql_help.c:1784 +#: sql_help.c:1905 sql_help.c:2022 sql_help.c:2028 sql_help.c:2042 +#: sql_help.c:2043 sql_help.c:2044 sql_help.c:2401 sql_help.c:2416 +#: sql_help.c:2430 sql_help.c:2471 sql_help.c:2539 sql_help.c:2545 +#: sql_help.c:2578 sql_help.c:2716 sql_help.c:2822 sql_help.c:2857 +#: sql_help.c:2859 sql_help.c:2972 sql_help.c:2981 sql_help.c:2991 +#: sql_help.c:2994 sql_help.c:3004 sql_help.c:3008 sql_help.c:3031 +#: sql_help.c:3032 sql_help.c:3033 sql_help.c:3035 sql_help.c:3036 +#: sql_help.c:3043 sql_help.c:3044 sql_help.c:3058 sql_help.c:3063 +#: sql_help.c:3070 sql_help.c:3071 sql_help.c:3087 sql_help.c:3213 +#: sql_help.c:3353 sql_help.c:3981 sql_help.c:3982 sql_help.c:4079 +#: sql_help.c:4095 sql_help.c:4097 sql_help.c:4099 sql_help.c:4195 +#: sql_help.c:4198 sql_help.c:4200 sql_help.c:4202 sql_help.c:4448 +#: sql_help.c:4449 sql_help.c:4569 sql_help.c:4730 sql_help.c:4737 +#: sql_help.c:4739 sql_help.c:4988 sql_help.c:4995 sql_help.c:4997 +#: sql_help.c:5039 sql_help.c:5041 sql_help.c:5043 sql_help.c:5097 +#: sql_help.c:5235 sql_help.c:5242 sql_help.c:5244 msgid "column_name" msgstr "column_name" -#: sql_help.c:471 sql_help.c:696 sql_help.c:1345 sql_help.c:1735 +#: sql_help.c:471 sql_help.c:696 sql_help.c:1359 sql_help.c:1749 msgid "new_column_name" msgstr "ახალი_სვეტის_სახელი" -#: sql_help.c:476 sql_help.c:568 sql_help.c:704 sql_help.c:904 sql_help.c:1054 -#: sql_help.c:1361 sql_help.c:1635 +#: sql_help.c:476 sql_help.c:568 sql_help.c:704 sql_help.c:904 sql_help.c:1068 +#: sql_help.c:1375 sql_help.c:1649 msgid "where action is one of:" msgstr "და როცა ქმედება არის ერთერთი სიიდან:" -#: sql_help.c:478 sql_help.c:483 sql_help.c:1103 sql_help.c:1363 -#: sql_help.c:1368 sql_help.c:1637 sql_help.c:1641 sql_help.c:2283 -#: sql_help.c:2388 sql_help.c:2604 sql_help.c:2795 sql_help.c:2953 -#: sql_help.c:3240 sql_help.c:4234 +#: sql_help.c:478 sql_help.c:483 sql_help.c:1117 sql_help.c:1377 +#: sql_help.c:1382 sql_help.c:1651 sql_help.c:1655 sql_help.c:2297 +#: sql_help.c:2402 sql_help.c:2618 sql_help.c:2815 sql_help.c:2973 +#: sql_help.c:3260 sql_help.c:4254 msgid "data_type" msgstr "მონაცემების_ტიპი" -#: sql_help.c:479 sql_help.c:484 sql_help.c:1364 sql_help.c:1369 -#: sql_help.c:1470 sql_help.c:1638 sql_help.c:1642 sql_help.c:2284 -#: sql_help.c:2391 sql_help.c:2527 sql_help.c:2955 sql_help.c:2963 -#: sql_help.c:2976 sql_help.c:2990 sql_help.c:3045 sql_help.c:3241 -#: sql_help.c:3247 sql_help.c:4070 +#: sql_help.c:479 sql_help.c:484 sql_help.c:1378 sql_help.c:1383 +#: sql_help.c:1484 sql_help.c:1652 sql_help.c:1656 sql_help.c:2298 +#: sql_help.c:2405 sql_help.c:2541 sql_help.c:2975 sql_help.c:2983 +#: sql_help.c:2996 sql_help.c:3010 sql_help.c:3065 sql_help.c:3261 +#: sql_help.c:3267 sql_help.c:4090 msgid "collation" msgstr "კოლაცია" -#: sql_help.c:480 sql_help.c:1365 sql_help.c:2392 sql_help.c:2403 -#: sql_help.c:2956 sql_help.c:2972 sql_help.c:2985 +#: sql_help.c:480 sql_help.c:1379 sql_help.c:2406 sql_help.c:2417 +#: sql_help.c:2976 sql_help.c:2992 sql_help.c:3005 msgid "column_constraint" msgstr "column_constraint" -#: sql_help.c:490 sql_help.c:632 sql_help.c:706 sql_help.c:1385 sql_help.c:5071 +#: sql_help.c:490 sql_help.c:632 sql_help.c:706 sql_help.c:1399 sql_help.c:5091 msgid "integer" msgstr "მთელი რიცხვი" -#: sql_help.c:492 sql_help.c:495 sql_help.c:708 sql_help.c:711 sql_help.c:1387 -#: sql_help.c:1390 +#: sql_help.c:492 sql_help.c:495 sql_help.c:708 sql_help.c:711 sql_help.c:1401 +#: sql_help.c:1404 msgid "attribute_option" msgstr "ატრიბუტის პარამეტრი" -#: sql_help.c:500 sql_help.c:1394 sql_help.c:2393 sql_help.c:2404 -#: sql_help.c:2957 sql_help.c:2973 sql_help.c:2986 +#: sql_help.c:500 sql_help.c:1408 sql_help.c:2407 sql_help.c:2418 +#: sql_help.c:2977 sql_help.c:2993 sql_help.c:3006 msgid "table_constraint" msgstr "ცხრილის_შეზღუდვები" -#: sql_help.c:503 sql_help.c:504 sql_help.c:505 sql_help.c:506 sql_help.c:1400 -#: sql_help.c:1401 sql_help.c:1402 sql_help.c:1403 sql_help.c:1945 +#: sql_help.c:503 sql_help.c:504 sql_help.c:505 sql_help.c:506 sql_help.c:1414 +#: sql_help.c:1415 sql_help.c:1416 sql_help.c:1417 sql_help.c:1959 msgid "trigger_name" msgstr "ტრიგერის_სახელი" -#: sql_help.c:507 sql_help.c:508 sql_help.c:1414 sql_help.c:1415 -#: sql_help.c:2396 sql_help.c:2401 sql_help.c:2960 sql_help.c:2983 +#: sql_help.c:507 sql_help.c:508 sql_help.c:1428 sql_help.c:1429 +#: sql_help.c:2410 sql_help.c:2415 sql_help.c:2980 sql_help.c:3003 msgid "parent_table" msgstr "მშობელი_ცხრილი" -#: sql_help.c:567 sql_help.c:624 sql_help.c:693 sql_help.c:903 sql_help.c:1053 -#: sql_help.c:1594 sql_help.c:2315 +#: sql_help.c:567 sql_help.c:624 sql_help.c:693 sql_help.c:903 sql_help.c:1067 +#: sql_help.c:1608 sql_help.c:2329 msgid "extension_name" msgstr "გაფართოების სახელი" -#: sql_help.c:569 sql_help.c:1055 sql_help.c:2461 +#: sql_help.c:569 sql_help.c:1069 sql_help.c:2475 msgid "execution_cost" msgstr "გაშვების_ფასი" -#: sql_help.c:570 sql_help.c:1056 sql_help.c:2462 +#: sql_help.c:570 sql_help.c:1070 sql_help.c:2476 msgid "result_rows" msgstr "მწკრივები_შედეგში" -#: sql_help.c:571 sql_help.c:2463 +#: sql_help.c:571 sql_help.c:2477 msgid "support_function" msgstr "დამხმარე_ფუნქცია" -#: sql_help.c:593 sql_help.c:595 sql_help.c:978 sql_help.c:986 sql_help.c:990 -#: sql_help.c:993 sql_help.c:996 sql_help.c:1677 sql_help.c:1685 -#: sql_help.c:1689 sql_help.c:1692 sql_help.c:1695 sql_help.c:2771 -#: sql_help.c:2773 sql_help.c:2776 sql_help.c:2777 sql_help.c:3959 -#: sql_help.c:3960 sql_help.c:3964 sql_help.c:3965 sql_help.c:3968 -#: sql_help.c:3969 sql_help.c:3971 sql_help.c:3972 sql_help.c:3974 -#: sql_help.c:3975 sql_help.c:3977 sql_help.c:3978 sql_help.c:3980 -#: sql_help.c:3981 sql_help.c:3987 sql_help.c:3988 sql_help.c:3990 -#: sql_help.c:3991 sql_help.c:3993 sql_help.c:3994 sql_help.c:3996 -#: sql_help.c:3997 sql_help.c:3999 sql_help.c:4000 sql_help.c:4002 -#: sql_help.c:4003 sql_help.c:4005 sql_help.c:4006 sql_help.c:4008 -#: sql_help.c:4009 sql_help.c:4426 sql_help.c:4427 sql_help.c:4431 -#: sql_help.c:4432 sql_help.c:4435 sql_help.c:4436 sql_help.c:4438 -#: sql_help.c:4439 sql_help.c:4441 sql_help.c:4442 sql_help.c:4444 -#: sql_help.c:4445 sql_help.c:4447 sql_help.c:4448 sql_help.c:4454 -#: sql_help.c:4455 sql_help.c:4457 sql_help.c:4458 sql_help.c:4460 -#: sql_help.c:4461 sql_help.c:4463 sql_help.c:4464 sql_help.c:4466 -#: sql_help.c:4467 sql_help.c:4469 sql_help.c:4470 sql_help.c:4472 -#: sql_help.c:4473 sql_help.c:4475 sql_help.c:4476 +#: sql_help.c:593 sql_help.c:595 sql_help.c:992 sql_help.c:1000 sql_help.c:1004 +#: sql_help.c:1007 sql_help.c:1010 sql_help.c:1691 sql_help.c:1699 +#: sql_help.c:1703 sql_help.c:1706 sql_help.c:1709 sql_help.c:2791 +#: sql_help.c:2793 sql_help.c:2796 sql_help.c:2797 sql_help.c:3979 +#: sql_help.c:3980 sql_help.c:3984 sql_help.c:3985 sql_help.c:3988 +#: sql_help.c:3989 sql_help.c:3991 sql_help.c:3992 sql_help.c:3994 +#: sql_help.c:3995 sql_help.c:3997 sql_help.c:3998 sql_help.c:4000 +#: sql_help.c:4001 sql_help.c:4007 sql_help.c:4008 sql_help.c:4010 +#: sql_help.c:4011 sql_help.c:4013 sql_help.c:4014 sql_help.c:4016 +#: sql_help.c:4017 sql_help.c:4019 sql_help.c:4020 sql_help.c:4022 +#: sql_help.c:4023 sql_help.c:4025 sql_help.c:4026 sql_help.c:4028 +#: sql_help.c:4029 sql_help.c:4446 sql_help.c:4447 sql_help.c:4451 +#: sql_help.c:4452 sql_help.c:4455 sql_help.c:4456 sql_help.c:4458 +#: sql_help.c:4459 sql_help.c:4461 sql_help.c:4462 sql_help.c:4464 +#: sql_help.c:4465 sql_help.c:4467 sql_help.c:4468 sql_help.c:4474 +#: sql_help.c:4475 sql_help.c:4477 sql_help.c:4478 sql_help.c:4480 +#: sql_help.c:4481 sql_help.c:4483 sql_help.c:4484 sql_help.c:4486 +#: sql_help.c:4487 sql_help.c:4489 sql_help.c:4490 sql_help.c:4492 +#: sql_help.c:4493 sql_help.c:4495 sql_help.c:4496 msgid "role_specification" msgstr "role_specification" -#: sql_help.c:594 sql_help.c:596 sql_help.c:1708 sql_help.c:2250 -#: sql_help.c:2779 sql_help.c:3318 sql_help.c:3771 sql_help.c:4804 +#: sql_help.c:594 sql_help.c:596 sql_help.c:1722 sql_help.c:2264 +#: sql_help.c:2799 sql_help.c:3338 sql_help.c:3791 sql_help.c:4824 msgid "user_name" msgstr "მომხმარებლის_სახელი" -#: sql_help.c:597 sql_help.c:998 sql_help.c:1697 sql_help.c:2778 -#: sql_help.c:4010 sql_help.c:4477 +#: sql_help.c:597 sql_help.c:1012 sql_help.c:1711 sql_help.c:2798 +#: sql_help.c:4030 sql_help.c:4497 msgid "where role_specification can be:" msgstr "სადაც role_specification შეიძლება იყოს:" @@ -4911,22 +4916,22 @@ msgstr "სადაც role_specification შეიძლება იყოს msgid "group_name" msgstr "ჯგუფის_სახელი" -#: sql_help.c:620 sql_help.c:1466 sql_help.c:2262 sql_help.c:2534 -#: sql_help.c:2568 sql_help.c:2968 sql_help.c:2981 sql_help.c:2995 -#: sql_help.c:3041 sql_help.c:3071 sql_help.c:3083 sql_help.c:4001 -#: sql_help.c:4468 +#: sql_help.c:620 sql_help.c:1480 sql_help.c:2276 sql_help.c:2548 +#: sql_help.c:2582 sql_help.c:2988 sql_help.c:3001 sql_help.c:3015 +#: sql_help.c:3061 sql_help.c:3091 sql_help.c:3103 sql_help.c:4021 +#: sql_help.c:4488 msgid "tablespace_name" msgstr "ცხრილების_სივრცის_სახელი" -#: sql_help.c:622 sql_help.c:715 sql_help.c:1408 sql_help.c:1418 -#: sql_help.c:1461 sql_help.c:1823 +#: sql_help.c:622 sql_help.c:715 sql_help.c:1422 sql_help.c:1432 +#: sql_help.c:1475 sql_help.c:1837 msgid "index_name" msgstr "ინდექსის_სახელი" -#: sql_help.c:626 sql_help.c:629 sql_help.c:718 sql_help.c:720 sql_help.c:1411 -#: sql_help.c:1413 sql_help.c:1464 sql_help.c:2532 sql_help.c:2566 -#: sql_help.c:2966 sql_help.c:2979 sql_help.c:2993 sql_help.c:3039 -#: sql_help.c:3069 +#: sql_help.c:626 sql_help.c:629 sql_help.c:718 sql_help.c:720 sql_help.c:1425 +#: sql_help.c:1427 sql_help.c:1478 sql_help.c:2546 sql_help.c:2580 +#: sql_help.c:2986 sql_help.c:2999 sql_help.c:3013 sql_help.c:3059 +#: sql_help.c:3089 msgid "storage_parameter" msgstr "საცავის_პარამეტრი" @@ -4934,1916 +4939,1924 @@ msgstr "საცავის_პარამეტრი" msgid "column_number" msgstr "column_number" -#: sql_help.c:655 sql_help.c:1908 sql_help.c:4560 +#: sql_help.c:655 sql_help.c:1922 sql_help.c:4580 msgid "large_object_oid" msgstr "დიდი_ობიექტის_oid" -#: sql_help.c:714 sql_help.c:1393 sql_help.c:2954 +#: sql_help.c:714 sql_help.c:1407 sql_help.c:2974 msgid "compression_method" msgstr "შეკუმშვის_მეთოდი" -#: sql_help.c:716 sql_help.c:1409 +#: sql_help.c:716 sql_help.c:1423 msgid "new_access_method" msgstr "წვდომის_ახალი_მეთოდი" -#: sql_help.c:753 sql_help.c:2589 +#: sql_help.c:753 sql_help.c:2603 msgid "res_proc" msgstr "შეზღუდვის_პროცედურა" -#: sql_help.c:754 sql_help.c:2590 +#: sql_help.c:754 sql_help.c:2604 msgid "join_proc" msgstr "შეერთების_პროცედურა" -#: sql_help.c:755 sql_help.c:2587 +#: sql_help.c:755 sql_help.c:2601 msgid "com_op" msgstr "კომუტ_ოპერ" -#: sql_help.c:756 sql_help.c:2588 +#: sql_help.c:756 sql_help.c:2602 msgid "neg_op" msgstr "უარყ_ოპერატ" -#: sql_help.c:808 sql_help.c:820 sql_help.c:2607 +#: sql_help.c:808 sql_help.c:820 sql_help.c:2621 msgid "strategy_number" msgstr "strategy_number" #: sql_help.c:810 sql_help.c:811 sql_help.c:814 sql_help.c:815 sql_help.c:821 -#: sql_help.c:822 sql_help.c:824 sql_help.c:825 sql_help.c:2609 sql_help.c:2610 -#: sql_help.c:2613 sql_help.c:2614 +#: sql_help.c:822 sql_help.c:824 sql_help.c:825 sql_help.c:2623 sql_help.c:2624 +#: sql_help.c:2627 sql_help.c:2628 msgid "op_type" msgstr "ოპ_ტიპი" -#: sql_help.c:812 sql_help.c:2611 +#: sql_help.c:812 sql_help.c:2625 msgid "sort_family_name" msgstr "დალაგების_ოჯახის_სახელი" -#: sql_help.c:813 sql_help.c:823 sql_help.c:2612 +#: sql_help.c:813 sql_help.c:823 sql_help.c:2626 msgid "support_number" msgstr "დამხმარე_რიცხვი" -#: sql_help.c:817 sql_help.c:2182 sql_help.c:2616 sql_help.c:3160 -#: sql_help.c:3162 +#: sql_help.c:817 sql_help.c:2196 sql_help.c:2630 sql_help.c:3180 +#: sql_help.c:3182 msgid "argument_type" msgstr "არგუმენტის_ტიპი" -#: sql_help.c:848 sql_help.c:851 sql_help.c:940 sql_help.c:1069 sql_help.c:1110 -#: sql_help.c:1590 sql_help.c:1593 sql_help.c:1769 sql_help.c:1822 -#: sql_help.c:1893 sql_help.c:1918 sql_help.c:1931 sql_help.c:1946 -#: sql_help.c:2007 sql_help.c:2013 sql_help.c:2386 sql_help.c:2400 -#: sql_help.c:2523 sql_help.c:2563 sql_help.c:2640 sql_help.c:2694 -#: sql_help.c:2747 sql_help.c:2801 sql_help.c:2834 sql_help.c:2841 -#: sql_help.c:2951 sql_help.c:2969 sql_help.c:2982 sql_help.c:3066 -#: sql_help.c:3186 sql_help.c:3368 sql_help.c:3592 sql_help.c:3641 -#: sql_help.c:3747 sql_help.c:3957 sql_help.c:3963 sql_help.c:4024 -#: sql_help.c:4057 sql_help.c:4424 sql_help.c:4430 sql_help.c:4548 -#: sql_help.c:4661 sql_help.c:4724 sql_help.c:4763 sql_help.c:4919 -#: sql_help.c:4982 sql_help.c:5017 sql_help.c:5076 sql_help.c:5166 -#: sql_help.c:5229 +#: sql_help.c:848 sql_help.c:851 sql_help.c:952 sql_help.c:955 sql_help.c:1083 +#: sql_help.c:1124 sql_help.c:1604 sql_help.c:1607 sql_help.c:1783 +#: sql_help.c:1836 sql_help.c:1907 sql_help.c:1932 sql_help.c:1945 +#: sql_help.c:1960 sql_help.c:2021 sql_help.c:2027 sql_help.c:2400 +#: sql_help.c:2414 sql_help.c:2537 sql_help.c:2577 sql_help.c:2654 +#: sql_help.c:2715 sql_help.c:2767 sql_help.c:2821 sql_help.c:2854 +#: sql_help.c:2861 sql_help.c:2971 sql_help.c:2989 sql_help.c:3002 +#: sql_help.c:3086 sql_help.c:3206 sql_help.c:3388 sql_help.c:3612 +#: sql_help.c:3661 sql_help.c:3767 sql_help.c:3977 sql_help.c:3983 +#: sql_help.c:4044 sql_help.c:4077 sql_help.c:4444 sql_help.c:4450 +#: sql_help.c:4568 sql_help.c:4681 sql_help.c:4744 sql_help.c:4783 +#: sql_help.c:4939 sql_help.c:5002 sql_help.c:5037 sql_help.c:5096 +#: sql_help.c:5186 sql_help.c:5249 msgid "table_name" msgstr "ცხრილის_სახელი" -#: sql_help.c:853 sql_help.c:2642 +#: sql_help.c:853 sql_help.c:2656 msgid "using_expression" -msgstr "გამოყენების_გამოხატულება" +msgstr "using_expression" -#: sql_help.c:854 sql_help.c:2643 +#: sql_help.c:854 sql_help.c:2657 msgid "check_expression" msgstr "გამოსახულების_შემოწმება" -#: sql_help.c:927 sql_help.c:929 sql_help.c:931 sql_help.c:2690 +#: sql_help.c:936 sql_help.c:938 sql_help.c:2708 msgid "publication_object" -msgstr "გამოცემის_ობიექტი" +msgstr "publication_object" + +#: sql_help.c:940 +msgid "publication_drop_object" +msgstr "publication_drop_object" -#: sql_help.c:933 sql_help.c:2691 +#: sql_help.c:942 sql_help.c:2709 msgid "publication_parameter" -msgstr "გამოცემის_პარამეტრი" +msgstr "publication_parameter" -#: sql_help.c:939 sql_help.c:2693 +#: sql_help.c:948 sql_help.c:2711 msgid "where publication_object is one of:" msgstr "სადაც publication_object ერთ-ერთია სიიდან:" -#: sql_help.c:982 sql_help.c:1681 sql_help.c:2501 sql_help.c:2726 -#: sql_help.c:3301 +#: sql_help.c:949 sql_help.c:1777 sql_help.c:2712 sql_help.c:5080 +msgid "table_and_columns" +msgstr "ცხრილი_და სვეტები" + +#: sql_help.c:951 +msgid "and publication_drop_object is one of:" +msgstr "და publication_drop_object ერთ-ერთია სიიდან:" + +#: sql_help.c:954 sql_help.c:1782 sql_help.c:2714 sql_help.c:5095 +msgid "and table_and_columns is:" +msgstr "და table_and_columns არის:" + +#: sql_help.c:996 sql_help.c:1695 sql_help.c:2515 sql_help.c:2746 +#: sql_help.c:3321 msgid "password" msgstr "პაროლი" -#: sql_help.c:983 sql_help.c:1682 sql_help.c:2502 sql_help.c:2727 -#: sql_help.c:3302 +#: sql_help.c:997 sql_help.c:1696 sql_help.c:2516 sql_help.c:2747 +#: sql_help.c:3322 msgid "timestamp" msgstr "დროის შტამპი" -#: sql_help.c:987 sql_help.c:991 sql_help.c:994 sql_help.c:997 sql_help.c:1686 -#: sql_help.c:1690 sql_help.c:1693 sql_help.c:1696 sql_help.c:3970 -#: sql_help.c:4437 +#: sql_help.c:1001 sql_help.c:1005 sql_help.c:1008 sql_help.c:1011 +#: sql_help.c:1700 sql_help.c:1704 sql_help.c:1707 sql_help.c:1710 +#: sql_help.c:3990 sql_help.c:4457 msgid "database_name" msgstr "ბაზის_სახელი" -#: sql_help.c:1104 sql_help.c:2796 +#: sql_help.c:1118 sql_help.c:2816 msgid "increment" msgstr "გაზრდა" -#: sql_help.c:1105 sql_help.c:2797 +#: sql_help.c:1119 sql_help.c:2817 msgid "minvalue" msgstr "მინ_მნიშვნელობა" -#: sql_help.c:1106 sql_help.c:2798 +#: sql_help.c:1120 sql_help.c:2818 msgid "maxvalue" msgstr "მაქს_მნიშვნელობა" -#: sql_help.c:1107 sql_help.c:2799 sql_help.c:4657 sql_help.c:4761 -#: sql_help.c:4915 sql_help.c:5093 sql_help.c:5162 +#: sql_help.c:1121 sql_help.c:2819 sql_help.c:4677 sql_help.c:4781 +#: sql_help.c:4935 sql_help.c:5113 sql_help.c:5182 msgid "start" msgstr "დაწყება" -#: sql_help.c:1108 sql_help.c:1382 +#: sql_help.c:1122 sql_help.c:1396 msgid "restart" msgstr "გადატვრთვა" -#: sql_help.c:1109 sql_help.c:2800 +#: sql_help.c:1123 sql_help.c:2820 msgid "cache" msgstr "კეში" -#: sql_help.c:1154 +#: sql_help.c:1168 msgid "new_target" msgstr "ახალი_სამიზნე" -#: sql_help.c:1173 sql_help.c:2853 +#: sql_help.c:1187 sql_help.c:2873 msgid "conninfo" msgstr "შეერთ_ინფო" -#: sql_help.c:1175 sql_help.c:1179 sql_help.c:1183 sql_help.c:2854 +#: sql_help.c:1189 sql_help.c:1193 sql_help.c:1197 sql_help.c:2874 msgid "publication_name" -msgstr "გამოცემის_სახელი" +msgstr "publication_name" -#: sql_help.c:1176 sql_help.c:1180 sql_help.c:1184 +#: sql_help.c:1190 sql_help.c:1194 sql_help.c:1198 msgid "publication_option" -msgstr "გამოცემის_მორგება" +msgstr "publication_option" -#: sql_help.c:1187 +#: sql_help.c:1201 msgid "refresh_option" -msgstr "განახლების_პარამეტრები" +msgstr "refresh_option" -#: sql_help.c:1192 sql_help.c:2855 +#: sql_help.c:1206 sql_help.c:2875 msgid "subscription_parameter" -msgstr "გამოწერის_პარამეტრი" +msgstr "subscription_parameter" -#: sql_help.c:1195 +#: sql_help.c:1209 msgid "skip_option" msgstr "პარამეტრის_გამოტოვება" -#: sql_help.c:1357 sql_help.c:1360 +#: sql_help.c:1371 sql_help.c:1374 msgid "partition_name" msgstr "დანაყოფის_სახელი" -#: sql_help.c:1358 sql_help.c:2405 sql_help.c:2987 +#: sql_help.c:1372 sql_help.c:2419 sql_help.c:3007 msgid "partition_bound_spec" msgstr "დანაყოფის_საზღვრის_მითითება" -#: sql_help.c:1379 sql_help.c:1430 sql_help.c:3001 +#: sql_help.c:1393 sql_help.c:1444 sql_help.c:3021 msgid "sequence_options" msgstr "მიმდევრობის_პარამეტრები" -#: sql_help.c:1381 +#: sql_help.c:1395 msgid "sequence_option" msgstr "მიმდევრობის_პარამეტრი" -#: sql_help.c:1395 +#: sql_help.c:1409 msgid "table_constraint_using_index" msgstr "ცხრილის_შეზღუდვა_ინდექსით" -#: sql_help.c:1404 sql_help.c:1405 sql_help.c:1406 sql_help.c:1407 +#: sql_help.c:1418 sql_help.c:1419 sql_help.c:1420 sql_help.c:1421 msgid "rewrite_rule_name" msgstr "გადაწერის_წესის_სახელი" -#: sql_help.c:1419 sql_help.c:2419 sql_help.c:3031 +#: sql_help.c:1433 sql_help.c:2433 sql_help.c:3051 msgid "and partition_bound_spec is:" msgstr "და დანაყოფის_საზღვარის_სპეციფიკაცია არის:" -#: sql_help.c:1420 sql_help.c:1421 sql_help.c:1422 sql_help.c:2420 -#: sql_help.c:2421 sql_help.c:2422 sql_help.c:3032 sql_help.c:3033 -#: sql_help.c:3034 +#: sql_help.c:1434 sql_help.c:1435 sql_help.c:1436 sql_help.c:2434 +#: sql_help.c:2435 sql_help.c:2436 sql_help.c:3052 sql_help.c:3053 +#: sql_help.c:3054 msgid "partition_bound_expr" msgstr "დანაყოფის_საზღვრის_გამოსახულება" -#: sql_help.c:1423 sql_help.c:1424 sql_help.c:2423 sql_help.c:2424 -#: sql_help.c:3035 sql_help.c:3036 +#: sql_help.c:1437 sql_help.c:1438 sql_help.c:2437 sql_help.c:2438 +#: sql_help.c:3055 sql_help.c:3056 msgid "numeric_literal" msgstr "numeric_literal" -#: sql_help.c:1425 +#: sql_help.c:1439 msgid "and column_constraint is:" msgstr "და სვეტის_შეზღუდვა არის:" -#: sql_help.c:1428 sql_help.c:2412 sql_help.c:2455 sql_help.c:2664 -#: sql_help.c:2999 +#: sql_help.c:1442 sql_help.c:2426 sql_help.c:2469 sql_help.c:2678 +#: sql_help.c:3019 msgid "default_expr" msgstr "ნაგულისხმევი_გამოსახულება" -#: sql_help.c:1429 sql_help.c:2413 sql_help.c:3000 +#: sql_help.c:1443 sql_help.c:2427 sql_help.c:3020 msgid "generation_expr" msgstr "გენერირებული_გამოსახულება" -#: sql_help.c:1431 sql_help.c:1432 sql_help.c:1443 sql_help.c:1446 -#: sql_help.c:1450 sql_help.c:3002 sql_help.c:3003 sql_help.c:3014 -#: sql_help.c:3017 sql_help.c:3021 +#: sql_help.c:1445 sql_help.c:1446 sql_help.c:1457 sql_help.c:1460 +#: sql_help.c:1464 sql_help.c:3022 sql_help.c:3023 sql_help.c:3034 +#: sql_help.c:3037 sql_help.c:3041 msgid "index_parameters" msgstr "ინდექსის_პარამეტრები" -#: sql_help.c:1433 sql_help.c:1454 sql_help.c:3004 sql_help.c:3025 +#: sql_help.c:1447 sql_help.c:1468 sql_help.c:3024 sql_help.c:3045 msgid "reftable" msgstr "მიბმების_ცხრილი" -#: sql_help.c:1434 sql_help.c:1455 sql_help.c:1456 sql_help.c:3005 -#: sql_help.c:3026 sql_help.c:3027 +#: sql_help.c:1448 sql_help.c:1469 sql_help.c:1470 sql_help.c:3025 +#: sql_help.c:3046 sql_help.c:3047 msgid "refcolumn" msgstr "მიბმული_სვეტი" -#: sql_help.c:1435 sql_help.c:1436 sql_help.c:1457 sql_help.c:1458 -#: sql_help.c:3006 sql_help.c:3007 sql_help.c:3028 sql_help.c:3029 +#: sql_help.c:1449 sql_help.c:1450 sql_help.c:1471 sql_help.c:1472 +#: sql_help.c:3026 sql_help.c:3027 sql_help.c:3048 sql_help.c:3049 msgid "referential_action" msgstr "მიბმის_ქმედებები" -#: sql_help.c:1437 sql_help.c:2414 sql_help.c:3008 +#: sql_help.c:1451 sql_help.c:2428 sql_help.c:3028 msgid "and table_constraint is:" msgstr "და table_constraint არის:" -#: sql_help.c:1448 sql_help.c:3019 +#: sql_help.c:1462 sql_help.c:3039 msgid "exclude_element" msgstr "ელემენტის_ამოღება" -#: sql_help.c:1449 sql_help.c:3020 sql_help.c:4655 sql_help.c:4759 -#: sql_help.c:4913 sql_help.c:5091 sql_help.c:5160 +#: sql_help.c:1463 sql_help.c:3040 sql_help.c:4675 sql_help.c:4779 +#: sql_help.c:4933 sql_help.c:5111 sql_help.c:5180 msgid "operator" msgstr "ოპერატორი" -#: sql_help.c:1451 sql_help.c:2535 sql_help.c:3022 +#: sql_help.c:1465 sql_help.c:2549 sql_help.c:3042 msgid "predicate" msgstr "პრედიკატი" -#: sql_help.c:1459 +#: sql_help.c:1473 msgid "and table_constraint_using_index is:" msgstr "და table_constraint_using_index არის:" -#: sql_help.c:1462 sql_help.c:3037 +#: sql_help.c:1476 sql_help.c:3057 msgid "index_parameters in UNIQUE, PRIMARY KEY, and EXCLUDE constraints are:" msgstr "ინდექსის_პარამეტრები UNIQUE, PRIMARY KEY და EXCLUDE შეზღუდვებში:" -#: sql_help.c:1467 sql_help.c:3042 +#: sql_help.c:1481 sql_help.c:3062 msgid "exclude_element in an EXCLUDE constraint is:" msgstr "ელემენტის_ამოღება EXCLUDE შეზღუდვაში წარმოადგენს:" -#: sql_help.c:1471 sql_help.c:2528 sql_help.c:2964 sql_help.c:2977 -#: sql_help.c:2991 sql_help.c:3046 sql_help.c:4071 +#: sql_help.c:1485 sql_help.c:2542 sql_help.c:2984 sql_help.c:2997 +#: sql_help.c:3011 sql_help.c:3066 sql_help.c:4091 msgid "opclass" msgstr "ოპერატ_კლასი" -#: sql_help.c:1472 sql_help.c:2529 sql_help.c:3047 +#: sql_help.c:1486 sql_help.c:2543 sql_help.c:3067 msgid "opclass_parameter" msgstr "ოპერატ_კლასის_პარამეტრი" -#: sql_help.c:1474 sql_help.c:3049 +#: sql_help.c:1488 sql_help.c:3069 msgid "referential_action in a FOREIGN KEY/REFERENCES constraint is:" msgstr "მიბმის ქმედება FOREIGN KEY/REFERENCES შეზღუდვაში წარმოადგენს:" -#: sql_help.c:1492 sql_help.c:1495 sql_help.c:3086 +#: sql_help.c:1506 sql_help.c:1509 sql_help.c:3106 msgid "tablespace_option" msgstr "ცხრილების_სივრცის_პარამეტრი" -#: sql_help.c:1516 sql_help.c:1519 sql_help.c:1525 sql_help.c:1529 +#: sql_help.c:1530 sql_help.c:1533 sql_help.c:1539 sql_help.c:1543 msgid "token_type" msgstr "კოდის_ტიპი" -#: sql_help.c:1517 sql_help.c:1520 +#: sql_help.c:1531 sql_help.c:1534 msgid "dictionary_name" msgstr "ლექსიკონის_სახელი" -#: sql_help.c:1522 sql_help.c:1526 +#: sql_help.c:1536 sql_help.c:1540 msgid "old_dictionary" msgstr "ძველი_ლექსიკონი" -#: sql_help.c:1523 sql_help.c:1527 +#: sql_help.c:1537 sql_help.c:1541 msgid "new_dictionary" msgstr "ახალი_ლექსიკონი" -#: sql_help.c:1622 sql_help.c:1636 sql_help.c:1639 sql_help.c:1640 -#: sql_help.c:3239 +#: sql_help.c:1636 sql_help.c:1650 sql_help.c:1653 sql_help.c:1654 +#: sql_help.c:3259 msgid "attribute_name" msgstr "ატრიბუტის_სახელი" -#: sql_help.c:1623 +#: sql_help.c:1637 msgid "new_attribute_name" msgstr "ახალი_ატრიბუტის_სახელი" -#: sql_help.c:1627 sql_help.c:1631 +#: sql_help.c:1641 sql_help.c:1645 msgid "new_enum_value" msgstr "ათვლის_ახალი_მნიშვნელობა" -#: sql_help.c:1628 +#: sql_help.c:1642 msgid "neighbor_enum_value" msgstr "მეზობლად_ათვლის_მნიშვნელობა" -#: sql_help.c:1630 +#: sql_help.c:1644 msgid "existing_enum_value" msgstr "აღრიცხვის_არსებული_მნიშვნელობა" -#: sql_help.c:1633 +#: sql_help.c:1647 msgid "property" msgstr "თვისება" -#: sql_help.c:1709 sql_help.c:2397 sql_help.c:2406 sql_help.c:2812 -#: sql_help.c:3319 sql_help.c:3772 sql_help.c:3979 sql_help.c:4025 -#: sql_help.c:4446 +#: sql_help.c:1723 sql_help.c:2411 sql_help.c:2420 sql_help.c:2832 +#: sql_help.c:3339 sql_help.c:3792 sql_help.c:3999 sql_help.c:4045 +#: sql_help.c:4466 msgid "server_name" msgstr "server_name" -#: sql_help.c:1741 sql_help.c:1744 sql_help.c:3334 +#: sql_help.c:1755 sql_help.c:1758 sql_help.c:3354 msgid "view_option_name" msgstr "ხედის_პარამეტრის_სახელი" -#: sql_help.c:1742 sql_help.c:3335 +#: sql_help.c:1756 sql_help.c:3355 msgid "view_option_value" msgstr "ხედის_პარამეტრის_მნიშვნელობა" -#: sql_help.c:1763 sql_help.c:5060 -msgid "table_and_columns" -msgstr "ცხრილი_და სვეტები" - -#: sql_help.c:1764 sql_help.c:1824 sql_help.c:2019 sql_help.c:3821 -#: sql_help.c:4281 sql_help.c:5061 +#: sql_help.c:1778 sql_help.c:1838 sql_help.c:2033 sql_help.c:3841 +#: sql_help.c:4301 sql_help.c:5081 msgid "where option can be one of:" msgstr "სადაც option შეიძლება იყოს ერთ-ერთი სიიდან:" -#: sql_help.c:1765 sql_help.c:1766 sql_help.c:1825 sql_help.c:2021 -#: sql_help.c:2025 sql_help.c:2208 sql_help.c:3822 sql_help.c:3823 -#: sql_help.c:3824 sql_help.c:3825 sql_help.c:3826 sql_help.c:3827 -#: sql_help.c:3828 sql_help.c:3829 sql_help.c:3830 sql_help.c:3831 -#: sql_help.c:4282 sql_help.c:4284 sql_help.c:5062 sql_help.c:5063 -#: sql_help.c:5064 sql_help.c:5065 sql_help.c:5066 sql_help.c:5067 -#: sql_help.c:5068 sql_help.c:5069 sql_help.c:5070 sql_help.c:5072 -#: sql_help.c:5073 +#: sql_help.c:1779 sql_help.c:1780 sql_help.c:1839 sql_help.c:2035 +#: sql_help.c:2039 sql_help.c:2222 sql_help.c:3842 sql_help.c:3843 +#: sql_help.c:3844 sql_help.c:3845 sql_help.c:3846 sql_help.c:3847 +#: sql_help.c:3848 sql_help.c:3849 sql_help.c:3850 sql_help.c:3851 +#: sql_help.c:4302 sql_help.c:4304 sql_help.c:5082 sql_help.c:5083 +#: sql_help.c:5084 sql_help.c:5085 sql_help.c:5086 sql_help.c:5087 +#: sql_help.c:5088 sql_help.c:5089 sql_help.c:5090 sql_help.c:5092 +#: sql_help.c:5093 msgid "boolean" msgstr "ლოგიკური" -#: sql_help.c:1767 sql_help.c:5074 +#: sql_help.c:1781 sql_help.c:5094 msgid "size" msgstr "ზომა" -#: sql_help.c:1768 sql_help.c:5075 -msgid "and table_and_columns is:" -msgstr "და table_and_columns არის:" - -#: sql_help.c:1784 sql_help.c:4820 sql_help.c:4822 sql_help.c:4846 +#: sql_help.c:1798 sql_help.c:4840 sql_help.c:4842 sql_help.c:4866 msgid "transaction_mode" msgstr "ტრანზაქციის_რეჟიმი" -#: sql_help.c:1785 sql_help.c:4823 sql_help.c:4847 +#: sql_help.c:1799 sql_help.c:4843 sql_help.c:4867 msgid "where transaction_mode is one of:" msgstr "სადაც transaction_mode შეიძლება იყოს ერთ-ერთი სიიდან:" -#: sql_help.c:1794 sql_help.c:4665 sql_help.c:4674 sql_help.c:4678 -#: sql_help.c:4682 sql_help.c:4685 sql_help.c:4923 sql_help.c:4932 -#: sql_help.c:4936 sql_help.c:4940 sql_help.c:4943 sql_help.c:5170 -#: sql_help.c:5179 sql_help.c:5183 sql_help.c:5187 sql_help.c:5190 +#: sql_help.c:1808 sql_help.c:4685 sql_help.c:4694 sql_help.c:4698 +#: sql_help.c:4702 sql_help.c:4705 sql_help.c:4943 sql_help.c:4952 +#: sql_help.c:4956 sql_help.c:4960 sql_help.c:4963 sql_help.c:5190 +#: sql_help.c:5199 sql_help.c:5203 sql_help.c:5207 sql_help.c:5210 msgid "argument" msgstr "არგიმენტი" -#: sql_help.c:1890 +#: sql_help.c:1904 msgid "relation_name" msgstr "ურთიერთობის_სახელი" -#: sql_help.c:1895 sql_help.c:3973 sql_help.c:4440 +#: sql_help.c:1909 sql_help.c:3993 sql_help.c:4460 msgid "domain_name" msgstr "დომენის_სახელი" -#: sql_help.c:1917 +#: sql_help.c:1931 msgid "policy_name" msgstr "policy_name" -#: sql_help.c:1930 +#: sql_help.c:1944 msgid "rule_name" msgstr "rule_name" -#: sql_help.c:1949 sql_help.c:4579 +#: sql_help.c:1963 sql_help.c:4599 msgid "string_literal" msgstr "string_literal" -#: sql_help.c:1974 sql_help.c:4243 sql_help.c:4493 +#: sql_help.c:1988 sql_help.c:4263 sql_help.c:4513 msgid "transaction_id" msgstr "ტრანზაქციის_id" -#: sql_help.c:2009 sql_help.c:2016 sql_help.c:4097 +#: sql_help.c:2023 sql_help.c:2030 sql_help.c:4117 msgid "filename" msgstr "ფაილის სახელი" -#: sql_help.c:2010 sql_help.c:2017 sql_help.c:2749 sql_help.c:2750 -#: sql_help.c:2751 +#: sql_help.c:2024 sql_help.c:2031 sql_help.c:2769 sql_help.c:2770 +#: sql_help.c:2771 msgid "command" msgstr "ბრძანება" -#: sql_help.c:2012 sql_help.c:2748 sql_help.c:3189 sql_help.c:3371 -#: sql_help.c:4081 sql_help.c:4166 sql_help.c:4169 sql_help.c:4172 -#: sql_help.c:4648 sql_help.c:4650 sql_help.c:4752 sql_help.c:4754 -#: sql_help.c:4906 sql_help.c:4908 sql_help.c:5026 sql_help.c:5153 -#: sql_help.c:5155 +#: sql_help.c:2026 sql_help.c:2768 sql_help.c:3209 sql_help.c:3391 +#: sql_help.c:4101 sql_help.c:4186 sql_help.c:4189 sql_help.c:4192 +#: sql_help.c:4668 sql_help.c:4670 sql_help.c:4772 sql_help.c:4774 +#: sql_help.c:4926 sql_help.c:4928 sql_help.c:5046 sql_help.c:5173 +#: sql_help.c:5175 msgid "condition" msgstr "მდგომარეობა" -#: sql_help.c:2015 sql_help.c:2569 sql_help.c:3072 sql_help.c:3336 -#: sql_help.c:3354 sql_help.c:4061 +#: sql_help.c:2029 sql_help.c:2583 sql_help.c:3092 sql_help.c:3356 +#: sql_help.c:3374 sql_help.c:4081 msgid "query" msgstr "მოთხოვნა" -#: sql_help.c:2020 +#: sql_help.c:2034 msgid "format_name" msgstr "ფორმატის_სახელი" -#: sql_help.c:2022 +#: sql_help.c:2036 msgid "delimiter_character" msgstr "გამყოფი_სიმბოლო" -#: sql_help.c:2023 +#: sql_help.c:2037 msgid "null_string" msgstr "ნულოვანი_სტრიქონი" -#: sql_help.c:2024 +#: sql_help.c:2038 msgid "default_string" msgstr "default_string" -#: sql_help.c:2026 +#: sql_help.c:2040 msgid "quote_character" msgstr "ციტატის_სიმბოლო" -#: sql_help.c:2027 +#: sql_help.c:2041 msgid "escape_character" msgstr "escape_character" -#: sql_help.c:2031 +#: sql_help.c:2045 msgid "error_action" msgstr "error_action" -#: sql_help.c:2032 +#: sql_help.c:2046 msgid "maxerror" msgstr "მაქსშეცდომა" -#: sql_help.c:2033 +#: sql_help.c:2047 msgid "encoding_name" msgstr "კოდირების-სახელი" -#: sql_help.c:2034 +#: sql_help.c:2048 msgid "verbosity" msgstr "დეტალურობა" -#: sql_help.c:2045 +#: sql_help.c:2059 msgid "access_method_type" msgstr "წვდომის_მეთოდის_ტიპი" -#: sql_help.c:2116 sql_help.c:2135 sql_help.c:2138 +#: sql_help.c:2130 sql_help.c:2149 sql_help.c:2152 msgid "arg_data_type" msgstr "არგ_მონაც_ტიპი" -#: sql_help.c:2117 sql_help.c:2139 sql_help.c:2147 +#: sql_help.c:2131 sql_help.c:2153 sql_help.c:2161 msgid "sfunc" msgstr "მდგომარეობის_ფუნქცია" -#: sql_help.c:2118 sql_help.c:2140 sql_help.c:2148 +#: sql_help.c:2132 sql_help.c:2154 sql_help.c:2162 msgid "state_data_type" msgstr "მდგომარეობის_მონაცემების_ტიპი" -#: sql_help.c:2119 sql_help.c:2141 sql_help.c:2149 +#: sql_help.c:2133 sql_help.c:2155 sql_help.c:2163 msgid "state_data_size" msgstr "მდგომარეობის_მონაცემების_ზომა" -#: sql_help.c:2120 sql_help.c:2142 sql_help.c:2150 +#: sql_help.c:2134 sql_help.c:2156 sql_help.c:2164 msgid "ffunc" msgstr "დასრულების ფუნქცია" -#: sql_help.c:2121 sql_help.c:2151 +#: sql_help.c:2135 sql_help.c:2165 msgid "combinefunc" msgstr "კომბინ_ფუნქც" -#: sql_help.c:2122 sql_help.c:2152 +#: sql_help.c:2136 sql_help.c:2166 msgid "serialfunc" msgstr "დესერიალიზაციის_ფუნქცია" -#: sql_help.c:2123 sql_help.c:2153 +#: sql_help.c:2137 sql_help.c:2167 msgid "deserialfunc" msgstr "დესერიალიზაციის_ფუნქც" -#: sql_help.c:2124 sql_help.c:2143 sql_help.c:2154 +#: sql_help.c:2138 sql_help.c:2157 sql_help.c:2168 msgid "initial_condition" msgstr "საწყისი_მდგომარეობა" -#: sql_help.c:2125 sql_help.c:2155 +#: sql_help.c:2139 sql_help.c:2169 msgid "msfunc" msgstr "გადაადგ_მდგომ_ფუნქცია" -#: sql_help.c:2126 sql_help.c:2156 +#: sql_help.c:2140 sql_help.c:2170 msgid "minvfunc" msgstr "გადაადგ_მინ_მნიშვნ_ფუნქცია" -#: sql_help.c:2127 sql_help.c:2157 +#: sql_help.c:2141 sql_help.c:2171 msgid "mstate_data_type" msgstr "გადაადგ_მონაც_ტიპი" -#: sql_help.c:2128 sql_help.c:2158 +#: sql_help.c:2142 sql_help.c:2172 msgid "mstate_data_size" msgstr "გადაადგ_მონაც_ზომ" -#: sql_help.c:2129 sql_help.c:2159 +#: sql_help.c:2143 sql_help.c:2173 msgid "mffunc" msgstr "გადადგ_დასრულ_ფუნქცია" -#: sql_help.c:2130 sql_help.c:2160 +#: sql_help.c:2144 sql_help.c:2174 msgid "minitial_condition" msgstr "გადაადგ­_დასაწყ_ფუნქცია" -#: sql_help.c:2131 sql_help.c:2161 +#: sql_help.c:2145 sql_help.c:2175 msgid "sort_operator" msgstr "დალაგების_ოპერატორი" -#: sql_help.c:2144 +#: sql_help.c:2158 msgid "or the old syntax" msgstr "ან ძველი სინტაქსი" -#: sql_help.c:2146 +#: sql_help.c:2160 msgid "base_type" msgstr "base_type" -#: sql_help.c:2204 sql_help.c:2254 +#: sql_help.c:2218 sql_help.c:2268 msgid "locale" msgstr "ლოკალი" -#: sql_help.c:2205 sql_help.c:2255 +#: sql_help.c:2219 sql_help.c:2269 msgid "lc_collate" msgstr "lc_collate" -#: sql_help.c:2206 sql_help.c:2256 +#: sql_help.c:2220 sql_help.c:2270 msgid "lc_ctype" msgstr "lc_ctype" -#: sql_help.c:2207 sql_help.c:4546 +#: sql_help.c:2221 sql_help.c:4566 msgid "provider" msgstr "მომწოდებელი" -#: sql_help.c:2209 +#: sql_help.c:2223 msgid "rules" msgstr "rules" -#: sql_help.c:2210 sql_help.c:2317 +#: sql_help.c:2224 sql_help.c:2331 msgid "version" msgstr "ვერსია" -#: sql_help.c:2212 +#: sql_help.c:2226 msgid "existing_collation" msgstr "არსებული_კოლაცია" -#: sql_help.c:2222 +#: sql_help.c:2236 msgid "source_encoding" msgstr "წყაროს_კოდირება" -#: sql_help.c:2223 +#: sql_help.c:2237 msgid "dest_encoding" msgstr "სამიზნე_კოდირება" -#: sql_help.c:2251 sql_help.c:3112 +#: sql_help.c:2265 sql_help.c:3132 msgid "template" msgstr "შაბლონი" -#: sql_help.c:2252 +#: sql_help.c:2266 msgid "encoding" msgstr "კოდირება" -#: sql_help.c:2253 +#: sql_help.c:2267 msgid "strategy" msgstr "სტრატეგია" -#: sql_help.c:2257 +#: sql_help.c:2271 msgid "builtin_locale" msgstr "builtin_locale" -#: sql_help.c:2258 +#: sql_help.c:2272 msgid "icu_locale" msgstr "icu_ენა" -#: sql_help.c:2259 +#: sql_help.c:2273 msgid "icu_rules" msgstr "icu_rules" -#: sql_help.c:2260 +#: sql_help.c:2274 msgid "locale_provider" msgstr "locale_provider" -#: sql_help.c:2261 +#: sql_help.c:2275 msgid "collation_version" msgstr "კოლაციის ვერსია" -#: sql_help.c:2266 +#: sql_help.c:2280 msgid "oid" msgstr "oid" -#: sql_help.c:2301 sql_help.c:2746 sql_help.c:3185 +#: sql_help.c:2315 sql_help.c:2766 sql_help.c:3205 msgid "event" msgstr "მოვლენა" -#: sql_help.c:2302 +#: sql_help.c:2316 msgid "filter_variable" msgstr "ფილტრის_ცვლადი" -#: sql_help.c:2303 +#: sql_help.c:2317 msgid "filter_value" msgstr "ფილტრის_მნიშვნელობა" -#: sql_help.c:2394 sql_help.c:2958 +#: sql_help.c:2408 sql_help.c:2978 msgid "source_table" msgstr "წყაროს_ცხრილი" -#: sql_help.c:2395 sql_help.c:2959 +#: sql_help.c:2409 sql_help.c:2979 msgid "like_option" msgstr "მსგავსების_პარამეტრი" -#: sql_help.c:2409 sql_help.c:2996 +#: sql_help.c:2423 sql_help.c:3016 msgid "where column_constraint is:" msgstr "სადაც column_constraint არის:" -#: sql_help.c:2418 sql_help.c:3030 +#: sql_help.c:2432 sql_help.c:3050 msgid "and like_option is:" msgstr "და like_option არის:" -#: sql_help.c:2456 +#: sql_help.c:2470 msgid "rettype" msgstr "დაბრუნების_ტიპი" -#: sql_help.c:2458 +#: sql_help.c:2472 msgid "column_type" msgstr "column_type" -#: sql_help.c:2467 sql_help.c:2670 +#: sql_help.c:2481 sql_help.c:2684 msgid "definition" msgstr "აღწერა" -#: sql_help.c:2468 sql_help.c:2671 +#: sql_help.c:2482 sql_help.c:2685 msgid "obj_file" msgstr "ობიექტის_ფაილი" -#: sql_help.c:2469 sql_help.c:2672 +#: sql_help.c:2483 sql_help.c:2686 msgid "link_symbol" msgstr "link_symbol" -#: sql_help.c:2470 sql_help.c:2673 +#: sql_help.c:2484 sql_help.c:2687 msgid "sql_body" msgstr "sql_ის_სხეული" -#: sql_help.c:2508 sql_help.c:2731 sql_help.c:3308 +#: sql_help.c:2522 sql_help.c:2751 sql_help.c:3328 msgid "uid" msgstr "uid" -#: sql_help.c:2524 sql_help.c:2565 sql_help.c:2965 sql_help.c:2978 -#: sql_help.c:2992 sql_help.c:3068 +#: sql_help.c:2538 sql_help.c:2579 sql_help.c:2985 sql_help.c:2998 +#: sql_help.c:3012 sql_help.c:3088 msgid "method" msgstr "მეთოდი" -#: sql_help.c:2546 +#: sql_help.c:2560 msgid "call_handler" -msgstr "გამოძახების_დამმუშავებელი" +msgstr "call_handler" -#: sql_help.c:2547 +#: sql_help.c:2561 msgid "inline_handler" msgstr "ჩადგმული_კოდის_დამმუშავებელი" -#: sql_help.c:2548 +#: sql_help.c:2562 msgid "valfunction" msgstr "მნიშვნფუნქცია" -#: sql_help.c:2606 +#: sql_help.c:2620 msgid "family_name" msgstr "ოჯახის_სახელი" -#: sql_help.c:2617 +#: sql_help.c:2631 msgid "storage_type" msgstr "საცავის_ტიპი" -#: sql_help.c:2752 sql_help.c:3192 +#: sql_help.c:2772 sql_help.c:3212 msgid "where event can be one of:" msgstr "სადაც event შეიძლება იყოს ერთ-ერთი:" -#: sql_help.c:2772 sql_help.c:2774 +#: sql_help.c:2792 sql_help.c:2794 msgid "schema_element" msgstr "schema_element" -#: sql_help.c:2813 +#: sql_help.c:2833 msgid "server_type" msgstr "server_type" -#: sql_help.c:2814 +#: sql_help.c:2834 msgid "server_version" msgstr "server_version" -#: sql_help.c:2815 sql_help.c:3976 sql_help.c:4443 +#: sql_help.c:2835 sql_help.c:3996 sql_help.c:4463 msgid "fdw_name" msgstr "fdw_name" -#: sql_help.c:2832 sql_help.c:2835 +#: sql_help.c:2852 sql_help.c:2855 msgid "statistics_name" msgstr "statistics_name" -#: sql_help.c:2836 +#: sql_help.c:2856 msgid "statistics_kind" msgstr "statistics_kind" -#: sql_help.c:2852 +#: sql_help.c:2872 msgid "subscription_name" -msgstr "გამოწერის_სახელი" +msgstr "subscription_name" -#: sql_help.c:3085 +#: sql_help.c:3105 msgid "directory" msgstr "საქაღალდე" -#: sql_help.c:3099 +#: sql_help.c:3119 msgid "parser_name" msgstr "დამმუშავებლის_სახელი" -#: sql_help.c:3100 +#: sql_help.c:3120 msgid "source_config" msgstr "წყაროს_კონფიგურაცია" -#: sql_help.c:3129 +#: sql_help.c:3149 msgid "start_function" msgstr "გაშვების_ფუნქცია" -#: sql_help.c:3130 +#: sql_help.c:3150 msgid "gettoken_function" msgstr "კოდის_მიღების_ფუნქცია" -#: sql_help.c:3131 +#: sql_help.c:3151 msgid "end_function" msgstr "დასრულების ფუნქცია" -#: sql_help.c:3132 +#: sql_help.c:3152 msgid "lextypes_function" msgstr "ლექს_ტიპების_ფუნქცია" -#: sql_help.c:3133 +#: sql_help.c:3153 msgid "headline_function" msgstr "headline_function" -#: sql_help.c:3145 +#: sql_help.c:3165 msgid "init_function" msgstr "ინიციალიზაციის_ფუნქცია" -#: sql_help.c:3146 +#: sql_help.c:3166 msgid "lexize_function" msgstr "ლექსით_გამოყოფის_ფუნქცია" -#: sql_help.c:3159 +#: sql_help.c:3179 msgid "from_sql_function_name" msgstr "sql_ფუნქციის_სახელიდან" -#: sql_help.c:3161 +#: sql_help.c:3181 msgid "to_sql_function_name" msgstr "ფუნქციის_სახელი_sql_ში" -#: sql_help.c:3187 +#: sql_help.c:3207 msgid "referenced_table_name" msgstr "მიბმული_ცხრილის_სახელი" -#: sql_help.c:3188 +#: sql_help.c:3208 msgid "transition_relation_name" msgstr "გარდამავალი_ურთიერთობის_სახელი" -#: sql_help.c:3191 +#: sql_help.c:3211 msgid "arguments" msgstr "არგუმენტები" -#: sql_help.c:3243 +#: sql_help.c:3263 msgid "label" msgstr "ჭდე" -#: sql_help.c:3245 +#: sql_help.c:3265 msgid "subtype" msgstr "ქვეტიპი" -#: sql_help.c:3246 +#: sql_help.c:3266 msgid "subtype_operator_class" msgstr "ქვეტიპის_ოპერატორის_კლასი" -#: sql_help.c:3248 +#: sql_help.c:3268 msgid "canonical_function" msgstr "კანონიკური_ფუნქცია" -#: sql_help.c:3249 +#: sql_help.c:3269 msgid "subtype_diff_function" msgstr "ქვეტიპის_სხვაობის_ფუნქცია" -#: sql_help.c:3250 +#: sql_help.c:3270 msgid "multirange_type_name" msgstr "მრავალდიაპაზონიანი_ტიპის_სახელი" -#: sql_help.c:3252 +#: sql_help.c:3272 msgid "input_function" msgstr "შეყვანის_ფუნქცია" -#: sql_help.c:3253 +#: sql_help.c:3273 msgid "output_function" msgstr "გამოტანის_ფუნქცია" -#: sql_help.c:3254 +#: sql_help.c:3274 msgid "receive_function" msgstr "მიღების_ფუნქცია" -#: sql_help.c:3255 +#: sql_help.c:3275 msgid "send_function" msgstr "საწყისი_მნიშვნელობის_ფუნქცია" -#: sql_help.c:3256 +#: sql_help.c:3276 msgid "type_modifier_input_function" msgstr "ტიპის_მოდიფიკატორის_შემყვანის_ფუნქცია" -#: sql_help.c:3257 +#: sql_help.c:3277 msgid "type_modifier_output_function" msgstr "ტიპის_მოტიფიკატორის_გამოტანის_ფუნქცია" -#: sql_help.c:3258 +#: sql_help.c:3278 msgid "analyze_function" msgstr "ფუნქციის_ანალიზი" -#: sql_help.c:3259 +#: sql_help.c:3279 msgid "subscript_function" msgstr "ინდექსით_მიმართვის_ფუნქცია" -#: sql_help.c:3260 +#: sql_help.c:3280 msgid "internallength" msgstr "შიდასიგრძე" -#: sql_help.c:3261 +#: sql_help.c:3281 msgid "alignment" msgstr "სწორება" -#: sql_help.c:3262 +#: sql_help.c:3282 msgid "storage" msgstr "საცავი" -#: sql_help.c:3263 +#: sql_help.c:3283 msgid "like_type" msgstr "მსგავსების_ტიპი" -#: sql_help.c:3264 +#: sql_help.c:3284 msgid "category" msgstr "კატეგორია" -#: sql_help.c:3265 +#: sql_help.c:3285 msgid "preferred" msgstr "რჩეული" -#: sql_help.c:3266 +#: sql_help.c:3286 msgid "default" msgstr "ნაგულისხმევი" -#: sql_help.c:3267 +#: sql_help.c:3287 msgid "element" msgstr "ელემენტი" -#: sql_help.c:3268 +#: sql_help.c:3288 msgid "delimiter" msgstr "გამყოფი" -#: sql_help.c:3269 +#: sql_help.c:3289 msgid "collatable" msgstr "დალაგებადი" -#: sql_help.c:3367 sql_help.c:4056 sql_help.c:4152 sql_help.c:4643 -#: sql_help.c:4746 sql_help.c:4901 sql_help.c:5016 sql_help.c:5148 +#: sql_help.c:3387 sql_help.c:4076 sql_help.c:4172 sql_help.c:4663 +#: sql_help.c:4766 sql_help.c:4921 sql_help.c:5036 sql_help.c:5168 msgid "with_query" msgstr "მოთხოვნით" -#: sql_help.c:3369 sql_help.c:4058 sql_help.c:4662 sql_help.c:4668 -#: sql_help.c:4671 sql_help.c:4675 sql_help.c:4679 sql_help.c:4687 -#: sql_help.c:4920 sql_help.c:4926 sql_help.c:4929 sql_help.c:4933 -#: sql_help.c:4937 sql_help.c:4945 sql_help.c:5018 sql_help.c:5167 -#: sql_help.c:5173 sql_help.c:5176 sql_help.c:5180 sql_help.c:5184 -#: sql_help.c:5192 +#: sql_help.c:3389 sql_help.c:4078 sql_help.c:4682 sql_help.c:4688 +#: sql_help.c:4691 sql_help.c:4695 sql_help.c:4699 sql_help.c:4707 +#: sql_help.c:4940 sql_help.c:4946 sql_help.c:4949 sql_help.c:4953 +#: sql_help.c:4957 sql_help.c:4965 sql_help.c:5038 sql_help.c:5187 +#: sql_help.c:5193 sql_help.c:5196 sql_help.c:5200 sql_help.c:5204 +#: sql_help.c:5212 msgid "alias" msgstr "მეტსახელი" -#: sql_help.c:3370 sql_help.c:4647 sql_help.c:4689 sql_help.c:4691 -#: sql_help.c:4695 sql_help.c:4697 sql_help.c:4698 sql_help.c:4699 -#: sql_help.c:4751 sql_help.c:4905 sql_help.c:4947 sql_help.c:4949 -#: sql_help.c:4953 sql_help.c:4955 sql_help.c:4956 sql_help.c:4957 -#: sql_help.c:5025 sql_help.c:5152 sql_help.c:5194 sql_help.c:5196 -#: sql_help.c:5200 sql_help.c:5202 sql_help.c:5203 sql_help.c:5204 +#: sql_help.c:3390 sql_help.c:4667 sql_help.c:4709 sql_help.c:4711 +#: sql_help.c:4715 sql_help.c:4717 sql_help.c:4718 sql_help.c:4719 +#: sql_help.c:4771 sql_help.c:4925 sql_help.c:4967 sql_help.c:4969 +#: sql_help.c:4973 sql_help.c:4975 sql_help.c:4976 sql_help.c:4977 +#: sql_help.c:5045 sql_help.c:5172 sql_help.c:5214 sql_help.c:5216 +#: sql_help.c:5220 sql_help.c:5222 sql_help.c:5223 sql_help.c:5224 msgid "from_item" msgstr "ჩანაწერიდან" -#: sql_help.c:3372 sql_help.c:3857 sql_help.c:4210 sql_help.c:5027 +#: sql_help.c:3392 sql_help.c:3877 sql_help.c:4230 sql_help.c:5047 msgid "cursor_name" msgstr "კურსორის_სახელი" -#: sql_help.c:3373 sql_help.c:4064 sql_help.c:4158 sql_help.c:5028 +#: sql_help.c:3393 sql_help.c:4084 sql_help.c:4178 sql_help.c:5048 msgid "output_alias" msgstr "გამოტანის_ფსევდონიმი" -#: sql_help.c:3374 sql_help.c:4065 sql_help.c:4159 sql_help.c:5029 +#: sql_help.c:3394 sql_help.c:4085 sql_help.c:4179 sql_help.c:5049 msgid "output_expression" msgstr "გამოტანის_გამოსახულება" -#: sql_help.c:3375 sql_help.c:4066 sql_help.c:4160 sql_help.c:4646 -#: sql_help.c:4749 sql_help.c:4904 sql_help.c:5030 sql_help.c:5151 +#: sql_help.c:3395 sql_help.c:4086 sql_help.c:4180 sql_help.c:4666 +#: sql_help.c:4769 sql_help.c:4924 sql_help.c:5050 sql_help.c:5171 msgid "output_name" msgstr "გამოტანის_სახელი" -#: sql_help.c:3391 +#: sql_help.c:3411 msgid "code" msgstr "კოდი" -#: sql_help.c:3796 +#: sql_help.c:3816 msgid "parameter" msgstr "Პარამეტრი" -#: sql_help.c:3820 sql_help.c:4235 +#: sql_help.c:3840 sql_help.c:4255 msgid "statement" msgstr "ოპერატორი" -#: sql_help.c:3856 sql_help.c:4209 +#: sql_help.c:3876 sql_help.c:4229 msgid "direction" msgstr "მიმართულება" -#: sql_help.c:3858 sql_help.c:4211 +#: sql_help.c:3878 sql_help.c:4231 msgid "where direction can be one of:" msgstr "სადაც direction შეიძლება იყოს ერთ-ერთი:" -#: sql_help.c:3859 sql_help.c:3860 sql_help.c:3861 sql_help.c:3862 -#: sql_help.c:3863 sql_help.c:4212 sql_help.c:4213 sql_help.c:4214 -#: sql_help.c:4215 sql_help.c:4216 sql_help.c:4656 sql_help.c:4658 -#: sql_help.c:4760 sql_help.c:4762 sql_help.c:4914 sql_help.c:4916 -#: sql_help.c:5092 sql_help.c:5094 sql_help.c:5161 sql_help.c:5163 +#: sql_help.c:3879 sql_help.c:3880 sql_help.c:3881 sql_help.c:3882 +#: sql_help.c:3883 sql_help.c:4232 sql_help.c:4233 sql_help.c:4234 +#: sql_help.c:4235 sql_help.c:4236 sql_help.c:4676 sql_help.c:4678 +#: sql_help.c:4780 sql_help.c:4782 sql_help.c:4934 sql_help.c:4936 +#: sql_help.c:5112 sql_help.c:5114 sql_help.c:5181 sql_help.c:5183 msgid "count" msgstr "რაოდენობა" -#: sql_help.c:3966 sql_help.c:4433 +#: sql_help.c:3986 sql_help.c:4453 msgid "sequence_name" msgstr "მიმდევრობის _სახელი" -#: sql_help.c:3984 sql_help.c:4451 +#: sql_help.c:4004 sql_help.c:4471 msgid "arg_name" msgstr "არგ_სახელი" -#: sql_help.c:3985 sql_help.c:4452 +#: sql_help.c:4005 sql_help.c:4472 msgid "arg_type" msgstr "არგ_ტიპი" -#: sql_help.c:3992 sql_help.c:4459 +#: sql_help.c:4012 sql_help.c:4479 msgid "loid" msgstr "loid" -#: sql_help.c:4023 +#: sql_help.c:4043 msgid "remote_schema" msgstr "დაშორებული_სქემა" -#: sql_help.c:4026 +#: sql_help.c:4046 msgid "local_schema" msgstr "ლოკალური_სქემა" -#: sql_help.c:4062 +#: sql_help.c:4082 msgid "conflict_target" msgstr "კონფლიქტის_ობიექტი" -#: sql_help.c:4063 +#: sql_help.c:4083 msgid "conflict_action" msgstr "ქმედება_კონფლიქტის_დროს" -#: sql_help.c:4067 +#: sql_help.c:4087 msgid "where conflict_target can be one of:" msgstr "სადაც conflict_target შეიძლება იყოს სიიდან:" -#: sql_help.c:4068 +#: sql_help.c:4088 msgid "index_column_name" msgstr "ინდექსის_სვეტის_სახელი" -#: sql_help.c:4069 +#: sql_help.c:4089 msgid "index_expression" msgstr "გამოსახულების_ინდექსი" -#: sql_help.c:4072 +#: sql_help.c:4092 msgid "index_predicate" msgstr "ინდექსის_პრედიკატი" -#: sql_help.c:4074 +#: sql_help.c:4094 msgid "and conflict_action is one of:" msgstr "და conflict_action შეიძლება იყოს სიიდან:" -#: sql_help.c:4080 sql_help.c:4183 sql_help.c:5024 +#: sql_help.c:4100 sql_help.c:4203 sql_help.c:5044 msgid "sub-SELECT" msgstr "ქვე-SELECT" -#: sql_help.c:4089 sql_help.c:4224 sql_help.c:4999 +#: sql_help.c:4109 sql_help.c:4244 sql_help.c:5019 msgid "channel" msgstr "არხი" -#: sql_help.c:4111 +#: sql_help.c:4131 msgid "lockmode" msgstr "ბლოკის_რეჟიმი" -#: sql_help.c:4112 +#: sql_help.c:4132 msgid "where lockmode is one of:" msgstr "სადაც lockmode ერთერთია სიიდან:" -#: sql_help.c:4153 +#: sql_help.c:4173 msgid "target_table_name" msgstr "სამიზნე ცხრილის სახელი" -#: sql_help.c:4154 +#: sql_help.c:4174 msgid "target_alias" msgstr "სამიზნე_მეტსახელი" -#: sql_help.c:4155 +#: sql_help.c:4175 msgid "data_source" msgstr "მონაცემების_წყარო" -#: sql_help.c:4156 sql_help.c:4692 sql_help.c:4950 sql_help.c:5197 +#: sql_help.c:4176 sql_help.c:4712 sql_help.c:4970 sql_help.c:5217 msgid "join_condition" msgstr "შეერთების პირობა" -#: sql_help.c:4157 +#: sql_help.c:4177 msgid "when_clause" msgstr "პირობა_როდის" -#: sql_help.c:4161 +#: sql_help.c:4181 msgid "where data_source is:" msgstr "სადაც data_source არის:" -#: sql_help.c:4162 +#: sql_help.c:4182 msgid "source_table_name" msgstr "წყაროს_ცხრილის_სახელი" -#: sql_help.c:4163 +#: sql_help.c:4183 msgid "source_query" msgstr "წყაროს_მოთხოვნა" -#: sql_help.c:4164 +#: sql_help.c:4184 msgid "source_alias" msgstr "წყაროს_მეტსახელი" -#: sql_help.c:4165 +#: sql_help.c:4185 msgid "and when_clause is:" msgstr "და when_clause არის:" -#: sql_help.c:4167 sql_help.c:4170 +#: sql_help.c:4187 sql_help.c:4190 msgid "merge_update" -msgstr "განახლების_შერწყმა" +msgstr "merge_update" -#: sql_help.c:4168 sql_help.c:4171 +#: sql_help.c:4188 sql_help.c:4191 msgid "merge_delete" msgstr "merge_delete" -#: sql_help.c:4173 +#: sql_help.c:4193 msgid "merge_insert" msgstr "ჩასმის_შერწყმა" -#: sql_help.c:4174 +#: sql_help.c:4194 msgid "and merge_insert is:" msgstr "და merge_insert არის:" -#: sql_help.c:4177 +#: sql_help.c:4197 msgid "and merge_update is:" msgstr "და merge_update არის:" -#: sql_help.c:4184 +#: sql_help.c:4204 msgid "and merge_delete is:" msgstr "და merge_delete არის:" -#: sql_help.c:4225 +#: sql_help.c:4245 msgid "payload" msgstr "შემცველობა" -#: sql_help.c:4252 +#: sql_help.c:4272 msgid "old_role" msgstr "ძველი_როლი" -#: sql_help.c:4253 +#: sql_help.c:4273 msgid "new_role" msgstr "ახალი_როლი" -#: sql_help.c:4292 sql_help.c:4501 sql_help.c:4509 +#: sql_help.c:4312 sql_help.c:4521 sql_help.c:4529 msgid "savepoint_name" msgstr "შენახვის_წერტილის_სახელი" -#: sql_help.c:4649 sql_help.c:4707 sql_help.c:4907 sql_help.c:4965 -#: sql_help.c:5154 sql_help.c:5212 +#: sql_help.c:4669 sql_help.c:4727 sql_help.c:4927 sql_help.c:4985 +#: sql_help.c:5174 sql_help.c:5232 msgid "grouping_element" msgstr "დაჯგუფების_ელემენტი" -#: sql_help.c:4651 sql_help.c:4755 sql_help.c:4909 sql_help.c:5156 +#: sql_help.c:4671 sql_help.c:4775 sql_help.c:4929 sql_help.c:5176 msgid "window_name" msgstr "ფანჯრის_სახელი" -#: sql_help.c:4652 sql_help.c:4756 sql_help.c:4910 sql_help.c:5157 +#: sql_help.c:4672 sql_help.c:4776 sql_help.c:4930 sql_help.c:5177 msgid "window_definition" msgstr "ფანჯრის_აღწერა" -#: sql_help.c:4653 sql_help.c:4667 sql_help.c:4711 sql_help.c:4757 -#: sql_help.c:4911 sql_help.c:4925 sql_help.c:4969 sql_help.c:5158 -#: sql_help.c:5172 sql_help.c:5216 +#: sql_help.c:4673 sql_help.c:4687 sql_help.c:4731 sql_help.c:4777 +#: sql_help.c:4931 sql_help.c:4945 sql_help.c:4989 sql_help.c:5178 +#: sql_help.c:5192 sql_help.c:5236 msgid "select" msgstr "არჩევა" -#: sql_help.c:4659 sql_help.c:4917 sql_help.c:5164 +#: sql_help.c:4679 sql_help.c:4937 sql_help.c:5184 msgid "from_reference" msgstr "from_reference" -#: sql_help.c:4660 sql_help.c:4918 sql_help.c:5165 +#: sql_help.c:4680 sql_help.c:4938 sql_help.c:5185 msgid "where from_item can be one of:" msgstr "სადაც from_item შეიძლება იყოს სიიდან ერთი:" -#: sql_help.c:4663 sql_help.c:4669 sql_help.c:4672 sql_help.c:4676 -#: sql_help.c:4688 sql_help.c:4921 sql_help.c:4927 sql_help.c:4930 -#: sql_help.c:4934 sql_help.c:4946 sql_help.c:5168 sql_help.c:5174 -#: sql_help.c:5177 sql_help.c:5181 sql_help.c:5193 +#: sql_help.c:4683 sql_help.c:4689 sql_help.c:4692 sql_help.c:4696 +#: sql_help.c:4708 sql_help.c:4941 sql_help.c:4947 sql_help.c:4950 +#: sql_help.c:4954 sql_help.c:4966 sql_help.c:5188 sql_help.c:5194 +#: sql_help.c:5197 sql_help.c:5201 sql_help.c:5213 msgid "column_alias" msgstr "column_alias" -#: sql_help.c:4664 sql_help.c:4922 sql_help.c:5169 +#: sql_help.c:4684 sql_help.c:4942 sql_help.c:5189 msgid "sampling_method" msgstr "sampling_method" -#: sql_help.c:4666 sql_help.c:4924 sql_help.c:5171 +#: sql_help.c:4686 sql_help.c:4944 sql_help.c:5191 msgid "seed" msgstr "საწყისი მნიშვნელობა" -#: sql_help.c:4670 sql_help.c:4709 sql_help.c:4928 sql_help.c:4967 -#: sql_help.c:5175 sql_help.c:5214 +#: sql_help.c:4690 sql_help.c:4729 sql_help.c:4948 sql_help.c:4987 +#: sql_help.c:5195 sql_help.c:5234 msgid "with_query_name" msgstr "მოთხოვნის_სახელით" -#: sql_help.c:4680 sql_help.c:4683 sql_help.c:4686 sql_help.c:4938 -#: sql_help.c:4941 sql_help.c:4944 sql_help.c:5185 sql_help.c:5188 -#: sql_help.c:5191 +#: sql_help.c:4700 sql_help.c:4703 sql_help.c:4706 sql_help.c:4958 +#: sql_help.c:4961 sql_help.c:4964 sql_help.c:5205 sql_help.c:5208 +#: sql_help.c:5211 msgid "column_definition" msgstr "column_definition" -#: sql_help.c:4690 sql_help.c:4696 sql_help.c:4948 sql_help.c:4954 -#: sql_help.c:5195 sql_help.c:5201 +#: sql_help.c:4710 sql_help.c:4716 sql_help.c:4968 sql_help.c:4974 +#: sql_help.c:5215 sql_help.c:5221 msgid "join_type" msgstr "შეერთების_ტიპი" -#: sql_help.c:4693 sql_help.c:4951 sql_help.c:5198 +#: sql_help.c:4713 sql_help.c:4971 sql_help.c:5218 msgid "join_column" msgstr "join_column" -#: sql_help.c:4694 sql_help.c:4952 sql_help.c:5199 +#: sql_help.c:4714 sql_help.c:4972 sql_help.c:5219 msgid "join_using_alias" msgstr "მეტსახელით_შეერთბა" -#: sql_help.c:4700 sql_help.c:4958 sql_help.c:5205 +#: sql_help.c:4720 sql_help.c:4978 sql_help.c:5225 msgid "and grouping_element can be one of:" msgstr "და grouping_element შეძლება იყოს სიიდან ერთი:" -#: sql_help.c:4708 sql_help.c:4966 sql_help.c:5213 +#: sql_help.c:4728 sql_help.c:4986 sql_help.c:5233 msgid "and with_query is:" msgstr "და with_query არის:" -#: sql_help.c:4712 sql_help.c:4970 sql_help.c:5217 +#: sql_help.c:4732 sql_help.c:4990 sql_help.c:5237 msgid "values" msgstr "მნიშვნელობები" -#: sql_help.c:4713 sql_help.c:4971 sql_help.c:5218 +#: sql_help.c:4733 sql_help.c:4991 sql_help.c:5238 msgid "insert" msgstr "ჩასმა" -#: sql_help.c:4714 sql_help.c:4972 sql_help.c:5219 +#: sql_help.c:4734 sql_help.c:4992 sql_help.c:5239 msgid "update" msgstr "განახლება" -#: sql_help.c:4715 sql_help.c:4973 sql_help.c:5220 +#: sql_help.c:4735 sql_help.c:4993 sql_help.c:5240 msgid "delete" msgstr "delete" -#: sql_help.c:4716 sql_help.c:4974 sql_help.c:5221 +#: sql_help.c:4736 sql_help.c:4994 sql_help.c:5241 msgid "merge" msgstr "შერწყმა" -#: sql_help.c:4718 sql_help.c:4976 sql_help.c:5223 +#: sql_help.c:4738 sql_help.c:4996 sql_help.c:5243 msgid "search_seq_col_name" msgstr "ბოლო_ძებნის_სვეტის_სახელი" -#: sql_help.c:4720 sql_help.c:4978 sql_help.c:5225 +#: sql_help.c:4740 sql_help.c:4998 sql_help.c:5245 msgid "cycle_mark_col_name" msgstr "ციკლის_ნიშნიანი_სვეტის_სახელი" -#: sql_help.c:4721 sql_help.c:4979 sql_help.c:5226 +#: sql_help.c:4741 sql_help.c:4999 sql_help.c:5246 msgid "cycle_mark_value" msgstr "ციკლის ნიშნის მნიშვნელობა" -#: sql_help.c:4722 sql_help.c:4980 sql_help.c:5227 +#: sql_help.c:4742 sql_help.c:5000 sql_help.c:5247 msgid "cycle_mark_default" msgstr "ციკლის_ნაგულისხმევი_ნიშანი" -#: sql_help.c:4723 sql_help.c:4981 sql_help.c:5228 +#: sql_help.c:4743 sql_help.c:5001 sql_help.c:5248 msgid "cycle_path_col_name" msgstr "ციკლის_ბილიკის_სვეტის_სახელი" -#: sql_help.c:4750 +#: sql_help.c:4770 msgid "new_table" msgstr "ახალი_ცხრილის" -#: sql_help.c:4821 +#: sql_help.c:4841 msgid "snapshot_id" msgstr "snapshot_id" -#: sql_help.c:5090 +#: sql_help.c:5110 msgid "sort_expression" msgstr "დალაგების_გამოსახულება" -#: sql_help.c:5235 sql_help.c:6219 +#: sql_help.c:5255 sql_help.c:6239 msgid "abort the current transaction" msgstr "მიმდინარე ტრანზაქციის გაუქმება" -#: sql_help.c:5241 +#: sql_help.c:5261 msgid "change the definition of an aggregate function" msgstr "აგრეგატული ფუნქციის აღწერის შექმნა" -#: sql_help.c:5247 +#: sql_help.c:5267 msgid "change the definition of a collation" msgstr "კოლაციის აღწერის შეცვლა" -#: sql_help.c:5253 +#: sql_help.c:5273 msgid "change the definition of a conversion" msgstr "გადაყვანის აღწერის შეცვლა" -#: sql_help.c:5259 +#: sql_help.c:5279 msgid "change a database" msgstr "მონაცემთა ბაზის შეცვლა" -#: sql_help.c:5265 +#: sql_help.c:5285 msgid "define default access privileges" msgstr "წვდომის ნაგულისხმევი უფლებების აღწერა" -#: sql_help.c:5271 +#: sql_help.c:5291 msgid "change the definition of a domain" msgstr "დომენის აღწერის შეცვლა" -#: sql_help.c:5277 +#: sql_help.c:5297 msgid "change the definition of an event trigger" msgstr "დომენის აღწერის შეცვლა" -#: sql_help.c:5283 +#: sql_help.c:5303 msgid "change the definition of an extension" msgstr "გაფართოების აღწერის შეცვლა" -#: sql_help.c:5289 +#: sql_help.c:5309 msgid "change the definition of a foreign-data wrapper" msgstr "გარე-მონაცემების გადამტანის აღწერის შეცვლა" -#: sql_help.c:5295 +#: sql_help.c:5315 msgid "change the definition of a foreign table" msgstr "გარე ცხრილის აღწერის შეცვლა" -#: sql_help.c:5301 +#: sql_help.c:5321 msgid "change the definition of a function" msgstr "ფუნქციის აღწერის შეცვლა" -#: sql_help.c:5307 +#: sql_help.c:5327 msgid "change role name or membership" msgstr "როლის სახელის ან წევრობის შეცვლა" -#: sql_help.c:5313 +#: sql_help.c:5333 msgid "change the definition of an index" msgstr "ინდექსის აღწერის შეცვლა" -#: sql_help.c:5319 +#: sql_help.c:5339 msgid "change the definition of a procedural language" msgstr "პროცედურული ენის აღწერის შეცვლა" -#: sql_help.c:5325 +#: sql_help.c:5345 msgid "change the definition of a large object" msgstr "დიდი ობიექტის აღწერის შეცვლა" -#: sql_help.c:5331 +#: sql_help.c:5351 msgid "change the definition of a materialized view" msgstr "მატერიალიზებული ხედის აღწერის შეცვლა" -#: sql_help.c:5337 +#: sql_help.c:5357 msgid "change the definition of an operator" msgstr "ოპერატორის აღწერის შეცვლა" -#: sql_help.c:5343 +#: sql_help.c:5363 msgid "change the definition of an operator class" msgstr "ოპერატორის კლასის აღწერის შეცვლა" -#: sql_help.c:5349 +#: sql_help.c:5369 msgid "change the definition of an operator family" msgstr "ოპერატორის ოჯახის აღწერის შეცვლა" -#: sql_help.c:5355 +#: sql_help.c:5375 msgid "change the definition of a row-level security policy" msgstr "მწკრივის-დონის-უსაფრთხოების წესების აღწერის შეცვლა" -#: sql_help.c:5361 +#: sql_help.c:5381 msgid "change the definition of a procedure" msgstr "პროცედურის აღწერის შეცვლა" -#: sql_help.c:5367 +#: sql_help.c:5387 msgid "change the definition of a publication" msgstr "გამოცემის აღწერის შეცვლა" -#: sql_help.c:5373 sql_help.c:5475 +#: sql_help.c:5393 sql_help.c:5495 msgid "change a database role" msgstr "მონაცემთა ბაზის როლის შეცვლა" -#: sql_help.c:5379 +#: sql_help.c:5399 msgid "change the definition of a routine" msgstr "ქვეპროგრამის აღწერის შეცვლა" -#: sql_help.c:5385 +#: sql_help.c:5405 msgid "change the definition of a rule" msgstr "წესის აღწერის შეცვლა" -#: sql_help.c:5391 +#: sql_help.c:5411 msgid "change the definition of a schema" msgstr "სქემის აღწერის შეცვლა" -#: sql_help.c:5397 +#: sql_help.c:5417 msgid "change the definition of a sequence generator" msgstr "მიმდევრობის გენერატორის აღწერის შეცვლა" -#: sql_help.c:5403 +#: sql_help.c:5423 msgid "change the definition of a foreign server" msgstr "გარე სერვერის აღწერის შეცვლა" -#: sql_help.c:5409 +#: sql_help.c:5429 msgid "change the definition of an extended statistics object" msgstr "სტატისტიკის გაფართოებული ობიექტის აღწერის შეცვლა" -#: sql_help.c:5415 +#: sql_help.c:5435 msgid "change the definition of a subscription" msgstr "გამოწერის აღწერის შეცვლა" -#: sql_help.c:5421 +#: sql_help.c:5441 msgid "change a server configuration parameter" msgstr "სერვერის კონფიგურაციის პარამეტრის შეცვლა" -#: sql_help.c:5427 +#: sql_help.c:5447 msgid "change the definition of a table" msgstr "ცხრილის აღწერის შეცვლა" -#: sql_help.c:5433 +#: sql_help.c:5453 msgid "change the definition of a tablespace" msgstr "ცხრილების სივრცის აღწერის შეცვლა" -#: sql_help.c:5439 +#: sql_help.c:5459 msgid "change the definition of a text search configuration" msgstr "ტექსტის ძებნის კონფიგურაციის აღწერის შეცვლა" -#: sql_help.c:5445 +#: sql_help.c:5465 msgid "change the definition of a text search dictionary" msgstr "ტექსტის ძებნის ლექსიკონის აღწერის შეცვლა" -#: sql_help.c:5451 +#: sql_help.c:5471 msgid "change the definition of a text search parser" msgstr "ტექსტის ძებნის დამმუშავებლის აღწერს შეცვლა" -#: sql_help.c:5457 +#: sql_help.c:5477 msgid "change the definition of a text search template" msgstr "ტექსტის ძებნის შაბლონის აღწერის შეცვლა" -#: sql_help.c:5463 +#: sql_help.c:5483 msgid "change the definition of a trigger" msgstr "ტრიგერის აღწერის შეცვლა" -#: sql_help.c:5469 +#: sql_help.c:5489 msgid "change the definition of a type" msgstr "ტიპის აღწერის შეცვლა" -#: sql_help.c:5481 +#: sql_help.c:5501 msgid "change the definition of a user mapping" msgstr "მომხარებლის მიბმის აღწერის შეცვლა" -#: sql_help.c:5487 +#: sql_help.c:5507 msgid "change the definition of a view" msgstr "ხედის აღწერის შეცვლა" -#: sql_help.c:5493 +#: sql_help.c:5513 msgid "collect statistics about a database" msgstr "მონაცემების სტატისტიკის მოგროვება" -#: sql_help.c:5499 sql_help.c:6297 +#: sql_help.c:5519 sql_help.c:6317 msgid "start a transaction block" msgstr "ტრანზაქციის ბლოკის დაწყება" -#: sql_help.c:5505 +#: sql_help.c:5525 msgid "invoke a procedure" msgstr "პროცედურის ჩაწოდება" -#: sql_help.c:5511 +#: sql_help.c:5531 msgid "force a write-ahead log checkpoint" msgstr "წინასწარ-ჩაწერად ჟურნალში საკონტროლო წერტილის დასმა" -#: sql_help.c:5517 +#: sql_help.c:5537 msgid "close a cursor" msgstr "კურსორის დახურვა" -#: sql_help.c:5523 +#: sql_help.c:5543 msgid "cluster a table according to an index" msgstr "ცხრილის გადაჯგუფება ინდექსის მიხედვით" -#: sql_help.c:5529 +#: sql_help.c:5549 msgid "define or change the comment of an object" msgstr "ობიექტის კომენტარის აღწერა ან შეცვლა" -#: sql_help.c:5535 sql_help.c:6093 +#: sql_help.c:5555 sql_help.c:6113 msgid "commit the current transaction" msgstr "მიმდინარე ტრანზაქციის გადაცემა" -#: sql_help.c:5541 +#: sql_help.c:5561 msgid "commit a transaction that was earlier prepared for two-phase commit" msgstr "წინასწარ ორ ფაზაში გადასაცემად მომზადებული ტრანზაქციის გადაცემა" -#: sql_help.c:5547 +#: sql_help.c:5567 msgid "copy data between a file and a table" msgstr "მონაცემების კოპირება ფაილსა და ცხრილს შორის" -#: sql_help.c:5553 +#: sql_help.c:5573 msgid "define a new access method" msgstr "წვდომის ახალი მეთოდის აღწერა" -#: sql_help.c:5559 +#: sql_help.c:5579 msgid "define a new aggregate function" msgstr "ახალი აგრეგატული ფუნქციის აღწერა" -#: sql_help.c:5565 +#: sql_help.c:5585 msgid "define a new cast" msgstr "ახალი კასტის აღწერა" -#: sql_help.c:5571 +#: sql_help.c:5591 msgid "define a new collation" msgstr "ახალი კოლაციის აღწერა" -#: sql_help.c:5577 +#: sql_help.c:5597 msgid "define a new encoding conversion" msgstr "კოდირების ახალი გადაყვანის აღწერა" -#: sql_help.c:5583 +#: sql_help.c:5603 msgid "create a new database" msgstr "ახალი მონაცემთა ბაზის შექმნა" -#: sql_help.c:5589 +#: sql_help.c:5609 msgid "define a new domain" msgstr "ახალი დომენის შექმნა" -#: sql_help.c:5595 +#: sql_help.c:5615 msgid "define a new event trigger" msgstr "მოვლენის ახალი ტრიგერის აღწერა" -#: sql_help.c:5601 +#: sql_help.c:5621 msgid "install an extension" msgstr "გაფართოების დაყენება" -#: sql_help.c:5607 +#: sql_help.c:5627 msgid "define a new foreign-data wrapper" msgstr "გარე მონაცემების ახალი გადამტანის აღწერა" -#: sql_help.c:5613 +#: sql_help.c:5633 msgid "define a new foreign table" msgstr "მონაცემების გარე ცხრილის აღწერა" -#: sql_help.c:5619 +#: sql_help.c:5639 msgid "define a new function" msgstr "ახალი ფუნქციის აღწერა" -#: sql_help.c:5625 sql_help.c:5685 sql_help.c:5787 +#: sql_help.c:5645 sql_help.c:5705 sql_help.c:5807 msgid "define a new database role" msgstr "მონაცემთა ბაზის ახალი როლის აღწერა" -#: sql_help.c:5631 +#: sql_help.c:5651 msgid "define a new index" msgstr "ახალი ინდექსის აღწერა" -#: sql_help.c:5637 +#: sql_help.c:5657 msgid "define a new procedural language" msgstr "ახალი პროცედურული ენის აღწერა" -#: sql_help.c:5643 +#: sql_help.c:5663 msgid "define a new materialized view" msgstr "ახალი მატერიალიზებული ხედის აღწერა" -#: sql_help.c:5649 +#: sql_help.c:5669 msgid "define a new operator" msgstr "ახალი ოპერატორის აღწერა" -#: sql_help.c:5655 +#: sql_help.c:5675 msgid "define a new operator class" msgstr "ოპერატორის ახალი კლასის აღწერა" -#: sql_help.c:5661 +#: sql_help.c:5681 msgid "define a new operator family" msgstr "ოპერატორის ახალი ოჯახის აღწერა" -#: sql_help.c:5667 +#: sql_help.c:5687 msgid "define a new row-level security policy for a table" msgstr "ცხრილისთვის ახალი მწკრივის-დონის-უსაფრთხოების წესის აღწერა" -#: sql_help.c:5673 +#: sql_help.c:5693 msgid "define a new procedure" msgstr "ახალი პროცედურის აღწერა" -#: sql_help.c:5679 +#: sql_help.c:5699 msgid "define a new publication" msgstr "ახალი გამოცემის აღწერა" -#: sql_help.c:5691 +#: sql_help.c:5711 msgid "define a new rewrite rule" msgstr "ახალი გადაწერის წესის აღწერა" -#: sql_help.c:5697 +#: sql_help.c:5717 msgid "define a new schema" msgstr "ახალი სქემის აღწერა" -#: sql_help.c:5703 +#: sql_help.c:5723 msgid "define a new sequence generator" msgstr "მიმდევრობის ახალი გენერატორის აღწერა" -#: sql_help.c:5709 +#: sql_help.c:5729 msgid "define a new foreign server" msgstr "ახალი გარე სერვერის აღწერა" -#: sql_help.c:5715 +#: sql_help.c:5735 msgid "define extended statistics" msgstr "გაფართოებული სტატისტიკის აღწერა" -#: sql_help.c:5721 +#: sql_help.c:5741 msgid "define a new subscription" msgstr "ახალი გამოწერის აღწერა" -#: sql_help.c:5727 +#: sql_help.c:5747 msgid "define a new table" msgstr "ახალი ცხრილის აღწერა" -#: sql_help.c:5733 sql_help.c:6255 +#: sql_help.c:5753 sql_help.c:6275 msgid "define a new table from the results of a query" msgstr "მოთხოვნის შედეგებიდან ახალი ცხრილის აღწერა" -#: sql_help.c:5739 +#: sql_help.c:5759 msgid "define a new tablespace" msgstr "ცხრილების ახალი სივრცის აღწერა" -#: sql_help.c:5745 +#: sql_help.c:5765 msgid "define a new text search configuration" msgstr "ტექსტის ძებნის ახალი კონფიგურაციის აღწერა" -#: sql_help.c:5751 +#: sql_help.c:5771 msgid "define a new text search dictionary" msgstr "ტექსტის ძებნის ახალ ლექსიკონის აღწერა" -#: sql_help.c:5757 +#: sql_help.c:5777 msgid "define a new text search parser" msgstr "ტექსტის ძებნის ახალი დამმუშავებლის აღწერა" -#: sql_help.c:5763 +#: sql_help.c:5783 msgid "define a new text search template" msgstr "ტექსტის ძებნის ახალი შაბლონის აღწერა" -#: sql_help.c:5769 +#: sql_help.c:5789 msgid "define a new transform" msgstr "ახალი გარდაქმნის აღწერა" -#: sql_help.c:5775 +#: sql_help.c:5795 msgid "define a new trigger" msgstr "ახალი ტრიგერის აღწერა" -#: sql_help.c:5781 +#: sql_help.c:5801 msgid "define a new data type" msgstr "მონაცემების ახალი ტიპის აღწერა" -#: sql_help.c:5793 +#: sql_help.c:5813 msgid "define a new mapping of a user to a foreign server" msgstr "მომხმარებლის გარე სერვერთან ახალი ბმის აღწერა" -#: sql_help.c:5799 +#: sql_help.c:5819 msgid "define a new view" msgstr "ახალი ხედის აღწერა" -#: sql_help.c:5805 +#: sql_help.c:5825 msgid "deallocate a prepared statement" msgstr "მომზადებული ოპერატორის გათავისუფლება" -#: sql_help.c:5811 +#: sql_help.c:5831 msgid "define a cursor" msgstr "კურსორის აღწერა" -#: sql_help.c:5817 +#: sql_help.c:5837 msgid "delete rows of a table" msgstr "ცხრილში მწკრივების წაშლა" -#: sql_help.c:5823 +#: sql_help.c:5843 msgid "discard session state" msgstr "სესიის მდგომარეობის მოშორება" -#: sql_help.c:5829 +#: sql_help.c:5849 msgid "execute an anonymous code block" msgstr "კოდის ანონიმური ბლოკის შესრულება" -#: sql_help.c:5835 +#: sql_help.c:5855 msgid "remove an access method" msgstr "წვდომის მეთოდის წაშლა" -#: sql_help.c:5841 +#: sql_help.c:5861 msgid "remove an aggregate function" msgstr "აგრეგატული ფუნქციის წაშლა" -#: sql_help.c:5847 +#: sql_help.c:5867 msgid "remove a cast" msgstr "კასტის წაშლა" -#: sql_help.c:5853 +#: sql_help.c:5873 msgid "remove a collation" msgstr "კოლაციის წაშლა" -#: sql_help.c:5859 +#: sql_help.c:5879 msgid "remove a conversion" msgstr "გადაყვანის წაშლა" -#: sql_help.c:5865 +#: sql_help.c:5885 msgid "remove a database" msgstr "მონაცემთა ბაზის წაშლა" -#: sql_help.c:5871 +#: sql_help.c:5891 msgid "remove a domain" msgstr "დომენის წაშლა" -#: sql_help.c:5877 +#: sql_help.c:5897 msgid "remove an event trigger" msgstr "მოვლენის ტრიგერის წაშლა" -#: sql_help.c:5883 +#: sql_help.c:5903 msgid "remove an extension" msgstr "გაფართოების წაშლა" -#: sql_help.c:5889 +#: sql_help.c:5909 msgid "remove a foreign-data wrapper" msgstr "გარე-მონაცემების გადამტანის წაშლა" -#: sql_help.c:5895 +#: sql_help.c:5915 msgid "remove a foreign table" msgstr "გარე ცხრილის წაშლა" -#: sql_help.c:5901 +#: sql_help.c:5921 msgid "remove a function" msgstr "ფუნქციის წაშლა" -#: sql_help.c:5907 sql_help.c:5973 sql_help.c:6075 +#: sql_help.c:5927 sql_help.c:5993 sql_help.c:6095 msgid "remove a database role" msgstr "მონაცემთა ბაზის როლის წაშლა" -#: sql_help.c:5913 +#: sql_help.c:5933 msgid "remove an index" msgstr "ინდექსის წაშლა" -#: sql_help.c:5919 +#: sql_help.c:5939 msgid "remove a procedural language" msgstr "პროცედურული ენის წაშლა" -#: sql_help.c:5925 +#: sql_help.c:5945 msgid "remove a materialized view" msgstr "მატერიალიზებული ხედის წაშლა" -#: sql_help.c:5931 +#: sql_help.c:5951 msgid "remove an operator" msgstr "ოპერატორის წაშლა" -#: sql_help.c:5937 +#: sql_help.c:5957 msgid "remove an operator class" msgstr "ოპერატორის კლასის წაშლა" -#: sql_help.c:5943 +#: sql_help.c:5963 msgid "remove an operator family" msgstr "ოპერატორის ოჯახის წაშლა" -#: sql_help.c:5949 +#: sql_help.c:5969 msgid "remove database objects owned by a database role" msgstr "მონაცემთა ბაზის როლის მფლობელობაში მყოფი ბაზის ობიექტების წაშლა" -#: sql_help.c:5955 +#: sql_help.c:5975 msgid "remove a row-level security policy from a table" msgstr "ცხრილიდან მწკრივის-დონის უსაფრთხოების წესის წაშლა" -#: sql_help.c:5961 +#: sql_help.c:5981 msgid "remove a procedure" msgstr "პროცედურის წაშლა" -#: sql_help.c:5967 +#: sql_help.c:5987 msgid "remove a publication" msgstr "გამოცემის წაშლა" -#: sql_help.c:5979 +#: sql_help.c:5999 msgid "remove a routine" msgstr "წესრიგის წაშლა" -#: sql_help.c:5985 +#: sql_help.c:6005 msgid "remove a rewrite rule" msgstr "გადაწერის წესის წაშლა" -#: sql_help.c:5991 +#: sql_help.c:6011 msgid "remove a schema" msgstr "სქემის წაშლა" -#: sql_help.c:5997 +#: sql_help.c:6017 msgid "remove a sequence" msgstr "მიმდევრობის წაშლა" -#: sql_help.c:6003 +#: sql_help.c:6023 msgid "remove a foreign server descriptor" msgstr "გარე სერვერის დესკრიპტორის წაშლა" -#: sql_help.c:6009 +#: sql_help.c:6029 msgid "remove extended statistics" msgstr "გაფართოებული სტატისტიკის წაშლა" -#: sql_help.c:6015 +#: sql_help.c:6035 msgid "remove a subscription" msgstr "გამოწერის წაშლა" -#: sql_help.c:6021 +#: sql_help.c:6041 msgid "remove a table" msgstr "ცხრილის წაშლა" -#: sql_help.c:6027 +#: sql_help.c:6047 msgid "remove a tablespace" msgstr "ცხრილების სივრცის წაშლა" -#: sql_help.c:6033 +#: sql_help.c:6053 msgid "remove a text search configuration" msgstr "ტექსტის ძებნის კონფიგურაციის წაშლა" -#: sql_help.c:6039 +#: sql_help.c:6059 msgid "remove a text search dictionary" msgstr "ტექსტის ძებნის ლექსიკონის წაშლა" -#: sql_help.c:6045 +#: sql_help.c:6065 msgid "remove a text search parser" msgstr "ტექსტის ძებნის დამმუშავებლის წაშლა" -#: sql_help.c:6051 +#: sql_help.c:6071 msgid "remove a text search template" msgstr "ტექსტის ძებნის შაბლონის წაშლა" -#: sql_help.c:6057 +#: sql_help.c:6077 msgid "remove a transform" msgstr "გარდაქმნის წაშლა" -#: sql_help.c:6063 +#: sql_help.c:6083 msgid "remove a trigger" msgstr "ტრიგერის წაშლა" -#: sql_help.c:6069 +#: sql_help.c:6089 msgid "remove a data type" msgstr "მონაცემების ტიპის წაშლა" -#: sql_help.c:6081 +#: sql_help.c:6101 msgid "remove a user mapping for a foreign server" msgstr "მომხმარებლის გარე სერვერისთვის მიბმის წაშლა" -#: sql_help.c:6087 +#: sql_help.c:6107 msgid "remove a view" msgstr "ხედის წაშლა" -#: sql_help.c:6099 +#: sql_help.c:6119 msgid "execute a prepared statement" msgstr "მზა ოპერატორის შესრულება" -#: sql_help.c:6105 +#: sql_help.c:6125 msgid "show the execution plan of a statement" msgstr "ოპერატორის შესრულების გეგმის ჩვენება" -#: sql_help.c:6111 +#: sql_help.c:6131 msgid "retrieve rows from a query using a cursor" msgstr "კურსორის გამოყენებით მოთხოვნიდან მწკრივების მიღება" -#: sql_help.c:6117 +#: sql_help.c:6137 msgid "define access privileges" msgstr "წვდომის უფლებების აღწერა" -#: sql_help.c:6123 +#: sql_help.c:6143 msgid "import table definitions from a foreign server" msgstr "ცხრილის აღწერების უცხო სერვერიდან შემოტანა" -#: sql_help.c:6129 +#: sql_help.c:6149 msgid "create new rows in a table" msgstr "ცხრილში ახალი მწკრივების შექმნა" -#: sql_help.c:6135 +#: sql_help.c:6155 msgid "listen for a notification" msgstr "შეტყობინების მოლოდინი" -#: sql_help.c:6141 +#: sql_help.c:6161 msgid "load a shared library file" msgstr "გაზიარებული ბიბლიოთეკის ფაილის ჩატვირთვა" -#: sql_help.c:6147 +#: sql_help.c:6167 msgid "lock a table" msgstr "ცხრილის დაბლოკვა" -#: sql_help.c:6153 +#: sql_help.c:6173 msgid "conditionally insert, update, or delete rows of a table" msgstr "ცხრილის მწკრივების ჩასმა, განახლება ან წაშლა პირობის მიხედვით" -#: sql_help.c:6159 +#: sql_help.c:6179 msgid "position a cursor" msgstr "კურსორის მოთავსება" -#: sql_help.c:6165 +#: sql_help.c:6185 msgid "generate a notification" msgstr "შეტყობინების გენერაცია" -#: sql_help.c:6171 +#: sql_help.c:6191 msgid "prepare a statement for execution" msgstr "ოპერატორის გასაშვებად მომზადება" -#: sql_help.c:6177 +#: sql_help.c:6197 msgid "prepare the current transaction for two-phase commit" msgstr "ტრანზაქციის მომზადება ორ ფაზაში გადასაცემად" -#: sql_help.c:6183 +#: sql_help.c:6203 msgid "change the ownership of database objects owned by a database role" msgstr "ბაზის როლის მფლობელობაში მყოფი ბაზის ობიექტების მფლობელის შეცვლა" -#: sql_help.c:6189 +#: sql_help.c:6209 msgid "replace the contents of a materialized view" msgstr "მატერიალიზებული ხედის შემცველობის ჩანაცვლება" -#: sql_help.c:6195 +#: sql_help.c:6215 msgid "rebuild indexes" msgstr "ინდექსების თავიდან აგება" -#: sql_help.c:6201 +#: sql_help.c:6221 msgid "release a previously defined savepoint" msgstr "ადრე აღწერილი შენახვის წერტილის მოხსნა" -#: sql_help.c:6207 +#: sql_help.c:6227 msgid "restore the value of a run-time parameter to the default value" msgstr "გაშვების პარამეტრის მნიშვნელობის საწყის მნიშვნელობაზე აღდგენა" -#: sql_help.c:6213 +#: sql_help.c:6233 msgid "remove access privileges" msgstr "წვდომის უფლებების წაშლა" -#: sql_help.c:6225 +#: sql_help.c:6245 msgid "cancel a transaction that was earlier prepared for two-phase commit" msgstr "წინასწარ ორ ფაზაში გადასაცემად მომზადებული ტრანზაქციის გაუქმება" -#: sql_help.c:6231 +#: sql_help.c:6251 msgid "roll back to a savepoint" msgstr "შენახვის წერტილზე დაბრუნება" -#: sql_help.c:6237 +#: sql_help.c:6257 msgid "define a new savepoint within the current transaction" msgstr "ახალი შესანახი წერტილის აღწერა მიმდინარე ტრანზაქციაში" -#: sql_help.c:6243 +#: sql_help.c:6263 msgid "define or change a security label applied to an object" msgstr "ობიექტზე გადატარებული უსაფრთხოების ჭდის აღწერა ან შეცვლა" -#: sql_help.c:6249 sql_help.c:6303 sql_help.c:6339 +#: sql_help.c:6269 sql_help.c:6323 sql_help.c:6359 msgid "retrieve rows from a table or view" msgstr "მწკრივის მიღება ცხრილიდან ან ხედიდან" -#: sql_help.c:6261 +#: sql_help.c:6281 msgid "change a run-time parameter" msgstr "გაშვების პარამეტრის შეცვლა" -#: sql_help.c:6267 +#: sql_help.c:6287 msgid "set constraint check timing for the current transaction" msgstr "მიმდინარე ტრანზაქციის შეზღუდვის შემოწმების დროის დაყენება" -#: sql_help.c:6273 +#: sql_help.c:6293 msgid "set the current user identifier of the current session" msgstr "მიმდინარე სესიის მიმდინარე მომხმარებლის იდენტიფიკატორის დაყენება" -#: sql_help.c:6279 +#: sql_help.c:6299 msgid "set the session user identifier and the current user identifier of the current session" msgstr "სესიის მომხმარებლის იდენტიფიკატორისა და მიმდინარე სესიის მიმდინარე მომხმარებლის იდენტიფიკატორის დაყენება" -#: sql_help.c:6285 +#: sql_help.c:6305 msgid "set the characteristics of the current transaction" msgstr "მიმდინარე ტრანზაქციის თვისებების დაყენება" -#: sql_help.c:6291 +#: sql_help.c:6311 msgid "show the value of a run-time parameter" msgstr "გაშვების პარამეტრის მნიშვნელობის ჩვენება" -#: sql_help.c:6309 +#: sql_help.c:6329 msgid "empty a table or set of tables" msgstr "ცხრილის ან ცხრილების სეტის დაცარიელება" -#: sql_help.c:6315 +#: sql_help.c:6335 msgid "stop listening for a notification" msgstr "გაფრთხილებების მოსმენის შეწყვეტა" -#: sql_help.c:6321 +#: sql_help.c:6341 msgid "update rows of a table" msgstr "ცხრილის მწკრივების განახლება" -#: sql_help.c:6327 +#: sql_help.c:6347 msgid "garbage-collect and optionally analyze a database" msgstr "ნაგვის-მოგროვება და ბაზის არასავალდებულო ანალიზი" -#: sql_help.c:6333 +#: sql_help.c:6353 msgid "compute a set of rows" msgstr "მწკრივების სეტის გამოთვლა" diff --git a/src/common/blkreftable.c b/src/common/blkreftable.c index b935baf9ad4..5c85d6a5c6d 100644 --- a/src/common/blkreftable.c +++ b/src/common/blkreftable.c @@ -497,7 +497,7 @@ WriteBlockRefTable(BlockRefTable *brtab, /* Extract entries into serializable format and sort them. */ sdata = - palloc(brtab->hash->members * sizeof(BlockRefTableSerializedEntry)); + palloc_array(BlockRefTableSerializedEntry, brtab->hash->members); blockreftable_start_iterate(brtab->hash, &it); while ((brtentry = blockreftable_iterate(brtab->hash, &it)) != NULL) { @@ -657,10 +657,24 @@ BlockRefTableReaderNextRelation(BlockRefTableReader *reader, return false; } + /* + * Sanity-check the nchunks value. In the backend, palloc_array would + * enforce this anyway (with a more generic error message); but in + * frontend it would not, potentially allowing BlockRefTableRead's length + * parameter to overflow. + */ + if (sentry.nchunks > MaxAllocSize / sizeof(uint16)) + { + reader->error_callback(reader->error_callback_arg, + "file \"%s\" has oversized chunk size array", + reader->error_filename); + return false; + } + /* Read chunk size array. */ if (reader->chunk_size != NULL) pfree(reader->chunk_size); - reader->chunk_size = palloc(sentry.nchunks * sizeof(uint16)); + reader->chunk_size = palloc_array(uint16, sentry.nchunks); BlockRefTableRead(reader, reader->chunk_size, sentry.nchunks * sizeof(uint16)); @@ -997,10 +1011,9 @@ BlockRefTableEntryMarkBlockModified(BlockRefTableEntry *entry, if (entry->nchunks == 0) { - entry->chunk_size = palloc0(sizeof(uint16) * max_chunks); - entry->chunk_usage = palloc0(sizeof(uint16) * max_chunks); - entry->chunk_data = - palloc0(sizeof(BlockRefTableChunk) * max_chunks); + entry->chunk_size = palloc0_array(uint16, max_chunks); + entry->chunk_usage = palloc0_array(uint16, max_chunks); + entry->chunk_data = palloc0_array(BlockRefTableChunk, max_chunks); } else { @@ -1029,7 +1042,7 @@ BlockRefTableEntryMarkBlockModified(BlockRefTableEntry *entry, if (entry->chunk_size[chunkno] == 0) { entry->chunk_data[chunkno] = - palloc(sizeof(uint16) * INITIAL_ENTRIES_PER_CHUNK); + palloc_array(uint16, INITIAL_ENTRIES_PER_CHUNK); entry->chunk_size[chunkno] = INITIAL_ENTRIES_PER_CHUNK; entry->chunk_data[chunkno][0] = chunkoffset; entry->chunk_usage[chunkno] = 1; diff --git a/src/common/compression.c b/src/common/compression.c index 4c3c9fd7b50..eb434542fbd 100644 --- a/src/common/compression.c +++ b/src/common/compression.c @@ -425,7 +425,7 @@ validate_compress_specification(pg_compress_specification *spec) void parse_compress_options(const char *option, char **algorithm, char **detail) { - char *sep; + const char *sep; char *endp; long result; diff --git a/src/common/encnames.c b/src/common/encnames.c index 7a6036c0361..7084885018d 100644 --- a/src/common/encnames.c +++ b/src/common/encnames.c @@ -61,8 +61,9 @@ static const pg_encname pg_encname_tbl[] = * Japanese, standard OSF */ { "euckr", PG_EUC_KR - }, /* EUC-KR; Extended Unix Code for Korean , KS - * X 1001 standard */ + }, /* EUC-KR; Extended Unix Code for Korean + * precomposed (Wansung) encoding, standard KS + * X 1001 */ { "euctw", PG_EUC_TW }, /* EUC-TW; Extended Unix Code for @@ -119,8 +120,8 @@ static const pg_encname pg_encname_tbl[] = }, /* ISO-8859-9; RFC1345,KXS2 */ { "johab", PG_JOHAB - }, /* JOHAB; Extended Unix Code for simplified - * Chinese */ + }, /* JOHAB; Korean combining (Johab) encoding, + * standard KS X 1001 annex 3 */ { "koi8", PG_KOI8R }, /* _dirty_ alias for KOI8-R (backward @@ -189,7 +190,9 @@ static const pg_encname pg_encname_tbl[] = }, /* alias for WIN1258 */ { "uhc", PG_UHC - }, /* UHC; Korean Windows CodePage 949 */ + }, /* UHC; Unified Hangul Code, Microsoft Windows + * CodePage 949; superset of EUC-KR covering + * all 11,172 precomposed Hangul syllables */ { "unicode", PG_UTF8 }, /* alias for UTF8 */ diff --git a/src/common/fe_memutils.c b/src/common/fe_memutils.c index 4ba793a6132..f2f073c5caf 100644 --- a/src/common/fe_memutils.c +++ b/src/common/fe_memutils.c @@ -19,6 +19,12 @@ #include "postgres_fe.h" +#include "common/int.h" + +pg_noreturn static pg_noinline void add_size_error(Size s1, Size s2); +pg_noreturn static pg_noinline void mul_size_error(Size s1, Size s2); + + static inline void * pg_malloc_internal(size_t size, int flags) { @@ -173,3 +179,185 @@ repalloc(void *pointer, Size size) { return pg_realloc(pointer, size); } + +/* + * Support for safe calculation of memory request sizes + * + * These functions perform the requested calculation, but throw error if the + * result overflows. + * + * An important property of these functions is that if an argument was a + * negative signed int before promotion (implying overflow in calculating it) + * we will detect that as an error. That happens because we reject results + * larger than SIZE_MAX / 2. In the backend we rely on later checks to do + * that, but in frontend we must do it here. + */ +Size +add_size(Size s1, Size s2) +{ + Size result; + + if (unlikely(pg_add_size_overflow(s1, s2, &result) || + result > (SIZE_MAX / 2))) + add_size_error(s1, s2); + return result; +} + +pg_noreturn static pg_noinline void +add_size_error(Size s1, Size s2) +{ + fprintf(stderr, _("invalid memory allocation request size %zu + %zu\n"), + s1, s2); + exit(EXIT_FAILURE); +} + +Size +mul_size(Size s1, Size s2) +{ + Size result; + + if (unlikely(pg_mul_size_overflow(s1, s2, &result) || + result > (SIZE_MAX / 2))) + mul_size_error(s1, s2); + return result; +} + +pg_noreturn static pg_noinline void +mul_size_error(Size s1, Size s2) +{ + fprintf(stderr, _("invalid memory allocation request size %zu * %zu\n"), + s1, s2); + exit(EXIT_FAILURE); +} + +/* + * pg_malloc_mul + * Equivalent to pg_malloc(mul_size(s1, s2)). + */ +void * +pg_malloc_mul(Size s1, Size s2) +{ + /* inline mul_size() for efficiency */ + Size req; + + if (unlikely(pg_mul_size_overflow(s1, s2, &req) || + req > (SIZE_MAX / 2))) + mul_size_error(s1, s2); + return pg_malloc(req); +} + +/* + * pg_malloc0_mul + * Equivalent to pg_malloc0(mul_size(s1, s2)). + * + * This is comparable to standard calloc's behavior. + */ +void * +pg_malloc0_mul(Size s1, Size s2) +{ + /* inline mul_size() for efficiency */ + Size req; + + if (unlikely(pg_mul_size_overflow(s1, s2, &req) || + req > (SIZE_MAX / 2))) + mul_size_error(s1, s2); + return pg_malloc0(req); +} + +/* + * pg_malloc_mul_extended + * Equivalent to pg_malloc_extended(mul_size(s1, s2), flags). + */ +void * +pg_malloc_mul_extended(Size s1, Size s2, int flags) +{ + /* inline mul_size() for efficiency */ + Size req; + + if (unlikely(pg_mul_size_overflow(s1, s2, &req) || + req > (SIZE_MAX / 2))) + mul_size_error(s1, s2); + return pg_malloc_extended(req, flags); +} + +/* + * pg_realloc_mul + * Equivalent to pg_realloc(p, mul_size(s1, s2)). + */ +void * +pg_realloc_mul(void *p, Size s1, Size s2) +{ + /* inline mul_size() for efficiency */ + Size req; + + if (unlikely(pg_mul_size_overflow(s1, s2, &req) || + req > (SIZE_MAX / 2))) + mul_size_error(s1, s2); + return pg_realloc(p, req); +} + +/* + * palloc_mul + * Equivalent to palloc(mul_size(s1, s2)). + */ +void * +palloc_mul(Size s1, Size s2) +{ + /* inline mul_size() for efficiency */ + Size req; + + if (unlikely(pg_mul_size_overflow(s1, s2, &req) || + req > (SIZE_MAX / 2))) + mul_size_error(s1, s2); + return palloc(req); +} + +/* + * palloc0_mul + * Equivalent to palloc0(mul_size(s1, s2)). + * + * This is comparable to standard calloc's behavior. + */ +void * +palloc0_mul(Size s1, Size s2) +{ + /* inline mul_size() for efficiency */ + Size req; + + if (unlikely(pg_mul_size_overflow(s1, s2, &req) || + req > (SIZE_MAX / 2))) + mul_size_error(s1, s2); + return palloc0(req); +} + +/* + * palloc_mul_extended + * Equivalent to palloc_extended(mul_size(s1, s2), flags). + */ +void * +palloc_mul_extended(Size s1, Size s2, int flags) +{ + /* inline mul_size() for efficiency */ + Size req; + + if (unlikely(pg_mul_size_overflow(s1, s2, &req) || + req > (SIZE_MAX / 2))) + mul_size_error(s1, s2); + return palloc_extended(req, flags); +} + +/* + * repalloc_mul + * Equivalent to repalloc(p, mul_size(s1, s2)). + */ +void * +repalloc_mul(void *p, Size s1, Size s2) +{ + /* inline mul_size() for efficiency */ + Size req; + + if (unlikely(pg_mul_size_overflow(s1, s2, &req) || + req > (SIZE_MAX / 2))) + mul_size_error(s1, s2); + return repalloc(p, req); +} diff --git a/src/common/jsonapi.c b/src/common/jsonapi.c index 7dad4da65f6..f0d51c56782 100644 --- a/src/common/jsonapi.c +++ b/src/common/jsonapi.c @@ -1670,9 +1670,31 @@ json_lex(JsonLexContext *lex) if (c == '-' || (c >= '0' && c <= '9')) { - /* for numbers look for possible numeric continuations */ - + /* + * Accumulate numeric continuations, respecting JSON number + * grammar: -? int [frac] [exp] + * + * We must track what parts of the number we've already seen + * so we don't over-consume. '.' is valid only once and not + * after 'e'/'E'; 'e'/'E' is valid only once; '+'/'-' are + * valid only immediately after 'e'/'E'. + */ bool numend = false; + bool seen_dot = false; + bool seen_exp = false; + char prev; + + /* Scan existing partial token for state */ + for (int j = 0; j < ptok->len; j++) + { + char pc = ptok->data[j]; + + if (pc == '.') + seen_dot = true; + else if (pc == 'e' || pc == 'E') + seen_exp = true; + } + prev = ptok->data[ptok->len - 1]; for (size_t i = 0; i < lex->input_length && !numend; i++) { @@ -1682,8 +1704,35 @@ json_lex(JsonLexContext *lex) { case '+': case '-': + if (prev != 'e' && prev != 'E') + { + numend = true; + break; + } + jsonapi_appendStringInfoCharMacro(ptok, cc); + added++; + break; + case '.': + if (seen_dot || seen_exp) + { + numend = true; + break; + } + seen_dot = true; + jsonapi_appendStringInfoCharMacro(ptok, cc); + added++; + break; case 'e': case 'E': + if (seen_exp) + { + numend = true; + break; + } + seen_exp = true; + jsonapi_appendStringInfoCharMacro(ptok, cc); + added++; + break; case '0': case '1': case '2': @@ -1694,14 +1743,14 @@ json_lex(JsonLexContext *lex) case '7': case '8': case '9': - { - jsonapi_appendStringInfoCharMacro(ptok, cc); - added++; - } + jsonapi_appendStringInfoCharMacro(ptok, cc); + added++; break; default: numend = true; } + if (!numend) + prev = cc; } } diff --git a/src/common/pg_lzcompress.c b/src/common/pg_lzcompress.c index 86354d660fd..51ae3c1c610 100644 --- a/src/common/pg_lzcompress.c +++ b/src/common/pg_lzcompress.c @@ -727,22 +727,33 @@ pglz_decompress(const char *source, int32 slen, char *dest, int32 len; int32 off; + /* + * A match tag is at least 2 bytes; if the length nibble is + * 0x0f the tag is 3 bytes (extended length). Verify we have + * enough source data before reading them. + */ + if (unlikely(sp + 2 > srcend)) + return -1; + len = (sp[0] & 0x0f) + 3; off = ((sp[0] & 0xf0) << 4) | sp[1]; sp += 2; if (len == 18) + { + if (unlikely(sp >= srcend)) + return -1; len += *sp++; + } /* - * Check for corrupt data: if we fell off the end of the - * source, or if we obtained off = 0, or if off is more than - * the distance back to the buffer start, we have problems. - * (We must check for off = 0, else we risk an infinite loop - * below in the face of corrupt data. Likewise, the upper - * limit on off prevents accessing outside the buffer - * boundaries.) + * Check for corrupt data: if we obtained off = 0, or if off + * is more than the distance back to the buffer start, we have + * problems. (We must check for off = 0, else we risk an + * infinite loop below in the face of corrupt data. Likewise, + * the upper limit on off prevents accessing outside the + * buffer boundaries.) */ - if (unlikely(sp > srcend || off == 0 || + if (unlikely(off == 0 || off > (dp - (unsigned char *) dest))) return -1; diff --git a/src/common/unicode/case_test.c b/src/common/unicode/case_test.c index fdfb62e8552..6dfc4d130ea 100644 --- a/src/common/unicode/case_test.c +++ b/src/common/unicode/case_test.c @@ -303,7 +303,7 @@ tfunc_title(char *dst, size_t dstsize, const char *src, { struct WordBoundaryState wbstate = { .str = src, - .len = srclen, + .len = (srclen < 0) ? strlen(src) : srclen, .offset = 0, .init = false, .prev_alnum = false, diff --git a/src/common/unicode_norm.c b/src/common/unicode_norm.c index 6654b4cbc49..0bb7523f422 100644 --- a/src/common/unicode_norm.c +++ b/src/common/unicode_norm.c @@ -23,6 +23,7 @@ #include "common/unicode_norm_hashfunc.h" #include "common/unicode_normprops_table.h" #include "port/pg_bswap.h" +#include "utils/memutils.h" #else #include "common/unicode_norm_table.h" #endif @@ -420,10 +421,28 @@ unicode_normalize(UnicodeNormalizationForm form, const pg_wchar *input) /* * Calculate how many characters long the decomposed version will be. + * + * Some characters decompose to quite a few code points, so that the + * decomposed version's size could overrun MaxAllocSize, and even 32-bit + * size_t, even though the input string presumably fits in that. In + * frontend we want to just return NULL in that case, so monitor the sum + * and exit early once we'd need more than MaxAllocSize bytes. */ decomp_size = 0; for (p = input; *p; p++) + { decomp_size += get_decomposed_size(*p, compat); + if (unlikely(decomp_size > MaxAllocSize / sizeof(pg_wchar))) + { +#ifndef FRONTEND + /* Exit loop and let palloc() throw error below */ + break; +#else + /* Just return NULL with no explicit error */ + return NULL; +#endif + } + } decomp_chars = (pg_wchar *) ALLOC((decomp_size + 1) * sizeof(pg_wchar)); if (decomp_chars == NULL) diff --git a/src/fe_utils/astreamer_file.c b/src/fe_utils/astreamer_file.c index c6856285086..175396bd205 100644 --- a/src/fe_utils/astreamer_file.c +++ b/src/fe_utils/astreamer_file.c @@ -218,6 +218,10 @@ astreamer_extractor_content(astreamer *streamer, astreamer_member *member, case ASTREAMER_MEMBER_HEADER: Assert(mystreamer->file == NULL); + if (!path_is_safe_for_extraction(member->pathname)) + pg_fatal("tar member has unsafe path name: \"%s\"", + member->pathname); + /* Prepend basepath. */ snprintf(mystreamer->filename, sizeof(mystreamer->filename), "%s/%s", mystreamer->basepath, member->pathname); @@ -228,20 +232,28 @@ astreamer_extractor_content(astreamer *streamer, astreamer_member *member, mystreamer->filename[fnamelen - 1] = '\0'; /* Dispatch based on file type. */ - if (member->is_directory) + if (member->is_regular) + mystreamer->file = + create_file_for_extract(mystreamer->filename, + member->mode); + else if (member->is_directory) extract_directory(mystreamer->filename, member->mode); - else if (member->is_link) + else if (member->is_symlink) { const char *linktarget = member->linktarget; if (mystreamer->link_map) linktarget = mystreamer->link_map(linktarget); + + if (!is_absolute_path(linktarget) && + !path_is_safe_for_extraction(member->linktarget)) + { + pg_fatal("link target has unsafe path name: \"%s\"", + member->linktarget); + } + extract_link(mystreamer->filename, linktarget); } - else - mystreamer->file = - create_file_for_extract(mystreamer->filename, - member->mode); /* Report output file change. */ if (mystreamer->report_output_file) @@ -266,7 +278,9 @@ astreamer_extractor_content(astreamer *streamer, astreamer_member *member, case ASTREAMER_MEMBER_TRAILER: if (mystreamer->file == NULL) break; - fclose(mystreamer->file); + if (fclose(mystreamer->file) != 0) + pg_fatal("could not close file \"%s\": %m", + mystreamer->filename); mystreamer->file = NULL; break; diff --git a/src/fe_utils/astreamer_gzip.c b/src/fe_utils/astreamer_gzip.c index a395f57edcd..671275f941d 100644 --- a/src/fe_utils/astreamer_gzip.c +++ b/src/fe_utils/astreamer_gzip.c @@ -316,8 +316,9 @@ astreamer_gzip_decompressor_content(astreamer *streamer, */ res = inflate(zs, Z_NO_FLUSH); - if (res == Z_STREAM_ERROR) - pg_log_error("could not decompress data: %s", zs->msg); + if (res != Z_OK && res != Z_STREAM_END && res != Z_BUF_ERROR) + pg_fatal("could not decompress data: %s", + zs->msg ? zs->msg : "unknown error"); mystreamer->bytes_written = mystreamer->base.bbs_buffer.maxlen - zs->avail_out; @@ -347,10 +348,11 @@ astreamer_gzip_decompressor_finalize(astreamer *streamer) * End of the stream, if there is some pending data in output buffers then * we must forward it to next streamer. */ - astreamer_content(mystreamer->base.bbs_next, NULL, - mystreamer->base.bbs_buffer.data, - mystreamer->base.bbs_buffer.maxlen, - ASTREAMER_UNKNOWN); + if (mystreamer->bytes_written > 0) + astreamer_content(mystreamer->base.bbs_next, NULL, + mystreamer->base.bbs_buffer.data, + mystreamer->bytes_written, + ASTREAMER_UNKNOWN); astreamer_finalize(mystreamer->base.bbs_next); } @@ -361,7 +363,12 @@ astreamer_gzip_decompressor_finalize(astreamer *streamer) static void astreamer_gzip_decompressor_free(astreamer *streamer) { + astreamer_gzip_decompressor *mystreamer; + + mystreamer = (astreamer_gzip_decompressor *) streamer; + astreamer_free(streamer->bbs_next); + inflateEnd(&mystreamer->zstream); pfree(streamer->bbs_buffer.data); pfree(streamer); } diff --git a/src/fe_utils/astreamer_lz4.c b/src/fe_utils/astreamer_lz4.c index 5f581d1de37..d08caf2809d 100644 --- a/src/fe_utils/astreamer_lz4.c +++ b/src/fe_utils/astreamer_lz4.c @@ -94,8 +94,8 @@ astreamer_lz4_compressor_new(astreamer *next, pg_compress_specification *compres ctxError = LZ4F_createCompressionContext(&streamer->cctx, LZ4F_VERSION); if (LZ4F_isError(ctxError)) - pg_log_error("could not create lz4 compression context: %s", - LZ4F_getErrorName(ctxError)); + pg_fatal("could not create lz4 compression context: %s", + LZ4F_getErrorName(ctxError)); return &streamer->base; #else @@ -139,8 +139,8 @@ astreamer_lz4_compressor_content(astreamer *streamer, &mystreamer->prefs); if (LZ4F_isError(compressed_size)) - pg_log_error("could not write lz4 header: %s", - LZ4F_getErrorName(compressed_size)); + pg_fatal("could not write lz4 header: %s", + LZ4F_getErrorName(compressed_size)); mystreamer->bytes_written += compressed_size; mystreamer->header_written = true; @@ -188,8 +188,8 @@ astreamer_lz4_compressor_content(astreamer *streamer, next_in, len, NULL); if (LZ4F_isError(compressed_size)) - pg_log_error("could not compress data: %s", - LZ4F_getErrorName(compressed_size)); + pg_fatal("could not compress data: %s", + LZ4F_getErrorName(compressed_size)); mystreamer->bytes_written += compressed_size; } @@ -240,8 +240,8 @@ astreamer_lz4_compressor_finalize(astreamer *streamer) next_out, avail_out, NULL); if (LZ4F_isError(compressed_size)) - pg_log_error("could not end lz4 compression: %s", - LZ4F_getErrorName(compressed_size)); + pg_fatal("could not end lz4 compression: %s", + LZ4F_getErrorName(compressed_size)); mystreamer->bytes_written += compressed_size; @@ -353,18 +353,21 @@ astreamer_lz4_decompressor_content(astreamer *streamer, next_in, &read_size, NULL); if (LZ4F_isError(ret)) - pg_log_error("could not decompress data: %s", - LZ4F_getErrorName(ret)); + pg_fatal("could not decompress data: %s", + LZ4F_getErrorName(ret)); /* Update input buffer based on number of bytes consumed */ avail_in -= read_size; next_in += read_size; + /* Update output buffer based on number of bytes produced */ + avail_out -= out_size; + next_out += out_size; mystreamer->bytes_written += out_size; /* * If output buffer is full then forward the content to next streamer - * and update the output buffer. + * and reset the output buffer. */ if (mystreamer->bytes_written >= mystreamer->base.bbs_buffer.maxlen) { @@ -374,13 +377,8 @@ astreamer_lz4_decompressor_content(astreamer *streamer, context); avail_out = mystreamer->base.bbs_buffer.maxlen; - mystreamer->bytes_written = 0; next_out = (uint8 *) mystreamer->base.bbs_buffer.data; - } - else - { - avail_out = mystreamer->base.bbs_buffer.maxlen - mystreamer->bytes_written; - next_out += mystreamer->bytes_written; + mystreamer->bytes_written = 0; } } } @@ -399,10 +397,11 @@ astreamer_lz4_decompressor_finalize(astreamer *streamer) * End of the stream, if there is some pending data in output buffers then * we must forward it to next streamer. */ - astreamer_content(mystreamer->base.bbs_next, NULL, - mystreamer->base.bbs_buffer.data, - mystreamer->base.bbs_buffer.maxlen, - ASTREAMER_UNKNOWN); + if (mystreamer->bytes_written > 0) + astreamer_content(mystreamer->base.bbs_next, NULL, + mystreamer->base.bbs_buffer.data, + mystreamer->bytes_written, + ASTREAMER_UNKNOWN); astreamer_finalize(mystreamer->base.bbs_next); } diff --git a/src/fe_utils/astreamer_tar.c b/src/fe_utils/astreamer_tar.c index 088e2357920..90bfab8832c 100644 --- a/src/fe_utils/astreamer_tar.c +++ b/src/fe_utils/astreamer_tar.c @@ -224,7 +224,8 @@ astreamer_tar_parser_content(astreamer *streamer, astreamer_member *member, /* OK, now we can send it. */ astreamer_content(mystreamer->base.bbs_next, &mystreamer->member, - data, mystreamer->pad_bytes_expected, + mystreamer->base.bbs_buffer.data, + mystreamer->pad_bytes_expected, ASTREAMER_MEMBER_TRAILER); /* Expect next file header. */ @@ -236,12 +237,16 @@ astreamer_tar_parser_content(astreamer *streamer, astreamer_member *member, /* * We've seen an end-of-archive indicator, so anything more is - * buffered and sent as part of the archive trailer. But we - * don't expect more than 2 blocks. + * buffered and sent as part of the archive trailer. + * + * Per POSIX, the last physical block of a tar archive is + * always full-sized, so there may be undefined data after the + * two zero blocks that mark end-of-archive. GNU tar, for + * example, zero-pads to a 10kB boundary by default. We just + * buffer whatever we receive and pass it along at finalize + * time. */ astreamer_buffer_bytes(streamer, &data, &len, len); - if (len > 2 * TAR_BLOCK_SIZE) - pg_fatal("tar file trailer exceeds 2 blocks"); return; default: @@ -255,7 +260,8 @@ astreamer_tar_parser_content(astreamer *streamer, astreamer_member *member, * Parse a file header within a tar stream. * * The return value is true if we found a file header and passed it on to the - * next astreamer; it is false if we have reached the archive trailer. + * next astreamer; it is false if we have found the archive trailer. + * We throw error if we see invalid data. */ static bool astreamer_tar_header(astreamer_tar_parser *mystreamer) @@ -267,6 +273,9 @@ astreamer_tar_header(astreamer_tar_parser *mystreamer) Assert(mystreamer->base.bbs_buffer.len == TAR_BLOCK_SIZE); + /* Zero out fields of *member, just for consistency. */ + memset(member, 0, sizeof(astreamer_member)); + /* Check whether we've got a block of all zero bytes. */ for (i = 0; i < TAR_BLOCK_SIZE; ++i) { @@ -284,22 +293,48 @@ astreamer_tar_header(astreamer_tar_parser *mystreamer) if (!has_nonzero_byte) return false; + /* + * Verify that we have a reasonable-looking header. + */ + if (!isValidTarHeader(buffer)) + pg_fatal("input file does not appear to be a valid tar archive"); + /* * Parse key fields out of the header. */ strlcpy(member->pathname, &buffer[TAR_OFFSET_NAME], MAXPGPATH); if (member->pathname[0] == '\0') pg_fatal("tar member has empty name"); + if (!path_is_safe_for_extraction(member->pathname)) + pg_fatal("tar member has unsafe path name: \"%s\"", + member->pathname); + member->size = read_tar_number(&buffer[TAR_OFFSET_SIZE], 12); member->mode = read_tar_number(&buffer[TAR_OFFSET_MODE], 8); member->uid = read_tar_number(&buffer[TAR_OFFSET_UID], 8); member->gid = read_tar_number(&buffer[TAR_OFFSET_GID], 8); - member->is_directory = - (buffer[TAR_OFFSET_TYPEFLAG] == TAR_FILETYPE_DIRECTORY); - member->is_link = - (buffer[TAR_OFFSET_TYPEFLAG] == TAR_FILETYPE_SYMLINK); - if (member->is_link) - strlcpy(member->linktarget, &buffer[TAR_OFFSET_LINKNAME], 100); + + switch (buffer[TAR_OFFSET_TYPEFLAG]) + { + case TAR_FILETYPE_PLAIN: + case TAR_FILETYPE_PLAIN_OLD: + member->is_regular = true; + break; + case TAR_FILETYPE_DIRECTORY: + member->is_directory = true; + break; + case TAR_FILETYPE_SYMLINK: + member->is_symlink = true; + strlcpy(member->linktarget, &buffer[TAR_OFFSET_LINKNAME], 100); + break; + case TAR_FILETYPE_PAX_EXTENDED: + case TAR_FILETYPE_PAX_EXTENDED_GLOBAL: + pg_fatal("pax extensions to tar format are not supported"); + break; + default: + /* For special filetypes, set none of the three is_xxx flags */ + break; + } /* Compute number of padding bytes. */ mystreamer->pad_bytes_expected = tarPaddingBytesRequired(member->size); @@ -342,6 +377,7 @@ astreamer_tar_parser_free(astreamer *streamer) { pfree(streamer->bbs_buffer.data); astreamer_free(streamer->bbs_next); + pfree(streamer); } /* diff --git a/src/fe_utils/astreamer_zstd.c b/src/fe_utils/astreamer_zstd.c index bacdcc150c4..24c9ec2ed60 100644 --- a/src/fe_utils/astreamer_zstd.c +++ b/src/fe_utils/astreamer_zstd.c @@ -116,11 +116,8 @@ astreamer_zstd_compressor_new(astreamer *next, pg_compress_specification *compre ZSTD_c_enableLongDistanceMatching, compress->long_distance); if (ZSTD_isError(ret)) - { - pg_log_error("could not enable long-distance mode: %s", - ZSTD_getErrorName(ret)); - exit(1); - } + pg_fatal("could not enable long-distance mode: %s", + ZSTD_getErrorName(ret)); } /* Initialize the ZSTD output buffer. */ @@ -182,8 +179,8 @@ astreamer_zstd_compressor_content(astreamer *streamer, &inBuf, ZSTD_e_continue); if (ZSTD_isError(yet_to_flush)) - pg_log_error("could not compress data: %s", - ZSTD_getErrorName(yet_to_flush)); + pg_fatal("could not compress data: %s", + ZSTD_getErrorName(yet_to_flush)); } } @@ -224,8 +221,8 @@ astreamer_zstd_compressor_finalize(astreamer *streamer) &in, ZSTD_e_end); if (ZSTD_isError(yet_to_flush)) - pg_log_error("could not compress data: %s", - ZSTD_getErrorName(yet_to_flush)); + pg_fatal("could not compress data: %s", + ZSTD_getErrorName(yet_to_flush)); } while (yet_to_flush > 0); @@ -330,8 +327,8 @@ astreamer_zstd_decompressor_content(astreamer *streamer, &mystreamer->zstd_outBuf, &inBuf); if (ZSTD_isError(ret)) - pg_log_error("could not decompress data: %s", - ZSTD_getErrorName(ret)); + pg_fatal("could not decompress data: %s", + ZSTD_getErrorName(ret)); } } @@ -350,7 +347,7 @@ astreamer_zstd_decompressor_finalize(astreamer *streamer) if (mystreamer->zstd_outBuf.pos > 0) astreamer_content(mystreamer->base.bbs_next, NULL, mystreamer->base.bbs_buffer.data, - mystreamer->base.bbs_buffer.maxlen, + mystreamer->zstd_outBuf.pos, ASTREAMER_UNKNOWN); astreamer_finalize(mystreamer->base.bbs_next); diff --git a/src/include/access/slru.h b/src/include/access/slru.h index f8bf1f1430f..d5ca3447208 100644 --- a/src/include/access/slru.h +++ b/src/include/access/slru.h @@ -110,9 +110,7 @@ typedef struct SlruSharedData /* * latest_page_number is the page number of the current end of the log; * this is not critical data, since we use it only to avoid swapping out - * the latest page. (An exception: an accurate latest_page_number is - * needed on pg_multixact/offsets to replay WAL generated with older minor - * versions correctly. See RecordNewMultiXact().) + * the latest page. */ pg_atomic_uint64 latest_page_number; diff --git a/src/include/access/visibilitymap.h b/src/include/access/visibilitymap.h index be21c6dd1a3..ea889bf9ec7 100644 --- a/src/include/access/visibilitymap.h +++ b/src/include/access/visibilitymap.h @@ -41,5 +41,6 @@ extern uint8 visibilitymap_get_status(Relation rel, BlockNumber heapBlk, Buffer extern void visibilitymap_count(Relation rel, BlockNumber *all_visible, BlockNumber *all_frozen); extern BlockNumber visibilitymap_prepare_truncate(Relation rel, BlockNumber nheapblocks); +extern BlockNumber visibilitymap_truncation_length(BlockNumber nheapblocks); #endif /* VISIBILITYMAP_H */ diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index d9be77e3b7c..ffeef562176 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -228,6 +228,7 @@ extern bool RecoveryInProgress(void); extern RecoveryState GetRecoveryState(void); extern bool XLogInsertAllowed(void); extern XLogRecPtr GetXLogInsertRecPtr(void); +extern XLogRecPtr GetXLogInsertEndRecPtr(void); extern XLogRecPtr GetXLogWriteRecPtr(void); extern uint64 GetSystemIdentifier(void); diff --git a/src/include/c.h b/src/include/c.h index 8bf2387ddb4..f4684ce37b5 100644 --- a/src/include/c.h +++ b/src/include/c.h @@ -225,6 +225,16 @@ #define PG_USED_FOR_ASSERTS_ONLY pg_attribute_unused() #endif +/* + * Our C and C++ compilers may have different ideas about which printf + * archetype best represents what src/port/snprintf.c can do. + */ +#ifndef __cplusplus +#define PG_PRINTF_ATTRIBUTE PG_C_PRINTF_ATTRIBUTE +#else +#define PG_PRINTF_ATTRIBUTE PG_CXX_PRINTF_ATTRIBUTE +#endif + /* GCC supports format attributes */ #if defined(__GNUC__) #define pg_attribute_format_arg(a) __attribute__((format_arg(a))) diff --git a/src/include/common/fe_memutils.h b/src/include/common/fe_memutils.h index cd205287861..0ca134499e1 100644 --- a/src/include/common/fe_memutils.h +++ b/src/include/common/fe_memutils.h @@ -41,6 +41,16 @@ extern void *pg_malloc_extended(size_t size, int flags); extern void *pg_realloc(void *ptr, size_t size); extern void pg_free(void *ptr); +/* + * Support for safe calculation of memory request sizes + */ +extern Size add_size(Size s1, Size s2); +extern Size mul_size(Size s1, Size s2); +extern void *pg_malloc_mul(Size s1, Size s2); +extern void *pg_malloc0_mul(Size s1, Size s2); +extern void *pg_malloc_mul_extended(Size s1, Size s2, int flags); +extern void *pg_realloc_mul(void *p, Size s1, Size s2); + /* * Variants with easier notation and more type safety */ @@ -54,14 +64,15 @@ extern void pg_free(void *ptr); /* * Allocate space for "count" objects of type "type" */ -#define pg_malloc_array(type, count) ((type *) pg_malloc(sizeof(type) * (count))) -#define pg_malloc0_array(type, count) ((type *) pg_malloc0(sizeof(type) * (count))) +#define pg_malloc_array(type, count) ((type *) pg_malloc_mul(sizeof(type), count)) +#define pg_malloc0_array(type, count) ((type *) pg_malloc0_mul(sizeof(type), count)) +#define pg_malloc_array_extended(type, count, flags) ((type *) pg_malloc_mul_extended(sizeof(type), count, flags)) /* * Change size of allocation pointed to by "pointer" to have space for "count" * objects of type "type" */ -#define pg_realloc_array(pointer, type, count) ((type *) pg_realloc(pointer, sizeof(type) * (count))) +#define pg_realloc_array(pointer, type, count) ((type *) pg_realloc_mul(pointer, sizeof(type), count)) /* Equivalent functions, deliberately named the same as backend functions */ extern char *pstrdup(const char *in); @@ -71,12 +82,17 @@ extern void *palloc0(Size size); extern void *palloc_extended(Size size, int flags); extern void *repalloc(void *pointer, Size size); extern void pfree(void *pointer); +extern void *palloc_mul(Size s1, Size s2); +extern void *palloc0_mul(Size s1, Size s2); +extern void *palloc_mul_extended(Size s1, Size s2, int flags); +extern void *repalloc_mul(void *p, Size s1, Size s2); #define palloc_object(type) ((type *) palloc(sizeof(type))) #define palloc0_object(type) ((type *) palloc0(sizeof(type))) -#define palloc_array(type, count) ((type *) palloc(sizeof(type) * (count))) -#define palloc0_array(type, count) ((type *) palloc0(sizeof(type) * (count))) -#define repalloc_array(pointer, type, count) ((type *) repalloc(pointer, sizeof(type) * (count))) +#define palloc_array(type, count) ((type *) palloc_mul(sizeof(type), count)) +#define palloc0_array(type, count) ((type *) palloc0_mul(sizeof(type), count)) +#define palloc_array_extended(type, count, flags) ((type *) palloc_mul_extended(sizeof(type), count, flags)) +#define repalloc_array(pointer, type, count) ((type *) repalloc_mul(pointer, sizeof(type), count)) /* sprintf into a palloc'd buffer --- these are in psprintf.c */ extern char *psprintf(const char *fmt,...) pg_attribute_printf(1, 2); diff --git a/src/include/common/int.h b/src/include/common/int.h index 3973f13379d..435716b7906 100644 --- a/src/include/common/int.h +++ b/src/include/common/int.h @@ -601,6 +601,73 @@ pg_neg_u64_overflow(uint64 a, int64 *result) #endif } +/* + * size_t + */ +static inline bool +pg_add_size_overflow(size_t a, size_t b, size_t *result) +{ +#if defined(HAVE__BUILTIN_OP_OVERFLOW) + return __builtin_add_overflow(a, b, result); +#else + size_t res = a + b; + + if (res < a) + { + *result = 0x5EED; /* to avoid spurious warnings */ + return true; + } + *result = res; + return false; +#endif +} + +static inline bool +pg_sub_size_overflow(size_t a, size_t b, size_t *result) +{ +#if defined(HAVE__BUILTIN_OP_OVERFLOW) + return __builtin_sub_overflow(a, b, result); +#else + if (b > a) + { + *result = 0x5EED; /* to avoid spurious warnings */ + return true; + } + *result = a - b; + return false; +#endif +} + +static inline bool +pg_mul_size_overflow(size_t a, size_t b, size_t *result) +{ +#if defined(HAVE__BUILTIN_OP_OVERFLOW) + return __builtin_mul_overflow(a, b, result); +#else + size_t res = a * b; + + if (a != 0 && b != res / a) + { + *result = 0x5EED; /* to avoid spurious warnings */ + return true; + } + *result = res; + return false; +#endif +} + +/* + * pg_neg_size_overflow is currently omitted, to avoid having to reason about + * the portability of SSIZE_MIN/_MAX before a use case exists. + */ +/* + * static inline bool + * pg_neg_size_overflow(size_t a, ssize_t *result) + * { + * ... + * } + */ + /*------------------------------------------------------------------------ * * Comparison routines for integer types. diff --git a/src/include/executor/execExpr.h b/src/include/executor/execExpr.h index 8a9546157eb..4c0229ee3a0 100644 --- a/src/include/executor/execExpr.h +++ b/src/include/executor/execExpr.h @@ -652,6 +652,10 @@ typedef struct ExprEvalStep { bool has_nulls; bool inclause; /* true for IN and false for NOT IN */ + bool null_lhs_result; /* for non-strict lookups, we + * cache what looking up NULL + * returns. */ + bool null_lhs_isnull; struct ScalarArrayOpExprHashTable *elements_tab; FmgrInfo *finfo; /* function's lookup data */ FunctionCallInfo fcinfo_data; /* arguments etc */ diff --git a/src/include/fe_utils/astreamer.h b/src/include/fe_utils/astreamer.h index 0e0031741fa..005141ea8b3 100644 --- a/src/include/fe_utils/astreamer.h +++ b/src/include/fe_utils/astreamer.h @@ -83,8 +83,10 @@ typedef struct mode_t mode; uid_t uid; gid_t gid; + /* note: special filetypes will set none of these flags */ + bool is_regular; bool is_directory; - bool is_link; + bool is_symlink; char linktarget[MAXPGPATH]; } astreamer_member; diff --git a/src/include/jit/SectionMemoryManager.h b/src/include/jit/SectionMemoryManager.h index 924a99b0d33..4c9bd1c7f01 100644 --- a/src/include/jit/SectionMemoryManager.h +++ b/src/include/jit/SectionMemoryManager.h @@ -1,5 +1,5 @@ /* - * This is a copy LLVM source code modified by the PostgreSQL project. + * This is a copy of LLVM source code modified by the PostgreSQL project. * See SectionMemoryManager.cpp for notes on provenance and license. */ diff --git a/src/include/jit/llvmjit_backport.h b/src/include/jit/llvmjit_backport.h index cba8eafc4f3..71cfdfc832f 100644 --- a/src/include/jit/llvmjit_backport.h +++ b/src/include/jit/llvmjit_backport.h @@ -8,14 +8,14 @@ #include /* - * LLVM's RuntimeDyld can produce code that crashes on larger memory ARM + * Pre-LLVM 22 RuntimeDyld can produce code that crashes on large memory ARM * systems, because llvm::SectionMemoryManager allocates multiple pieces of * memory that can be placed too far apart for the generated code. See * src/backend/jit/llvm/SectionMemoryManager.cpp for the patched replacement * class llvm::backport::SectionMemoryManager that we use as a workaround. * This header controls whether we use it. */ -#if defined(__aarch64__) +#if defined(__aarch64__) && LLVM_VERSION_MAJOR < 22 #define USE_LLVM_BACKPORT_SECTION_MEMORY_MANAGER #endif diff --git a/src/include/optimizer/placeholder.h b/src/include/optimizer/placeholder.h index db92d8861ba..0186f18bb06 100644 --- a/src/include/optimizer/placeholder.h +++ b/src/include/optimizer/placeholder.h @@ -32,5 +32,6 @@ extern bool contain_placeholder_references_to(PlannerInfo *root, Node *clause, int relid); extern Relids get_placeholder_nulling_relids(PlannerInfo *root, PlaceHolderInfo *phinfo); +extern Node *strip_noop_phvs(Node *node); #endif /* PLACEHOLDER_H */ diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in index c628a168782..81d1fa7bb8c 100644 --- a/src/include/pg_config.h.in +++ b/src/include/pg_config.h.in @@ -605,6 +605,14 @@ /* Define to the version of this package. */ #undef PACKAGE_VERSION +/* Define to best C++ printf format archetype, usually gnu_printf if + available. */ +#undef PG_CXX_PRINTF_ATTRIBUTE + +/* Define to best C printf format archetype, usually gnu_printf if available. + */ +#undef PG_C_PRINTF_ATTRIBUTE + /* Define to the name of a signed 128-bit integer type. */ #undef PG_INT128_TYPE @@ -621,9 +629,6 @@ /* PostgreSQL minor version number */ #undef PG_MINORVERSION_NUM -/* Define to best printf format archetype, usually gnu_printf if available. */ -#undef PG_PRINTF_ATTRIBUTE - /* PostgreSQL version as a string */ #undef PG_VERSION diff --git a/src/include/pgtar.h b/src/include/pgtar.h index b2677578a3d..84c98dd3f6e 100644 --- a/src/include/pgtar.h +++ b/src/include/pgtar.h @@ -55,11 +55,15 @@ enum tarHeaderOffset /* last 12 bytes of the 512-byte block are unassigned */ }; +/* See POSIX (not all the standard file type codes are listed here) */ enum tarFileType { TAR_FILETYPE_PLAIN = '0', + TAR_FILETYPE_PLAIN_OLD = '\0', /* backwards compatibility, per POSIX */ TAR_FILETYPE_SYMLINK = '2', TAR_FILETYPE_DIRECTORY = '5', + TAR_FILETYPE_PAX_EXTENDED = 'x', + TAR_FILETYPE_PAX_EXTENDED_GLOBAL = 'g', }; extern enum tarError tarCreateHeader(char *h, const char *filename, @@ -68,7 +72,8 @@ extern enum tarError tarCreateHeader(char *h, const char *filename, time_t mtime); extern uint64 read_tar_number(const char *s, int len); extern void print_tar_number(char *s, int len, uint64 val); -extern int tarChecksum(char *header); +extern int tarChecksum(const char *header); +extern bool isValidTarHeader(const char *header); /* * Compute the number of padding bytes required for an entry in a tar diff --git a/src/include/port.h b/src/include/port.h index 938dc7b60e1..2425fc5351e 100644 --- a/src/include/port.h +++ b/src/include/port.h @@ -59,6 +59,7 @@ extern void make_native_path(char *filename); extern void cleanup_path(char *path); extern bool path_contains_parent_reference(const char *path); extern bool path_is_relative_and_below_cwd(const char *path); +extern bool path_is_safe_for_extraction(const char *path); extern bool path_is_prefix_of_path(const char *path1, const char *path2); extern char *make_absolute_path(const char *path); extern const char *get_progname(const char *argv0); diff --git a/src/include/port/pg_crc32c.h b/src/include/port/pg_crc32c.h index ae008118ea8..833d4b7df96 100644 --- a/src/include/port/pg_crc32c.h +++ b/src/include/port/pg_crc32c.h @@ -70,6 +70,7 @@ static inline pg_crc32c pg_comp_crc32c_dispatch(pg_crc32c crc, const void *data, size_t len) { +#ifdef HAVE__BUILTIN_CONSTANT_P if (__builtin_constant_p(len) && len < 32) { const unsigned char *p = (const unsigned char *) data; @@ -91,6 +92,9 @@ pg_comp_crc32c_dispatch(pg_crc32c crc, const void *data, size_t len) else /* Otherwise, use a runtime check for AVX-512 instructions. */ return pg_comp_crc32c(crc, data, len); +#else + return pg_comp_crc32c(crc, data, len); +#endif /* HAVE__BUILTIN_CONSTANT_P */ } #elif defined(USE_SSE42_CRC32C_WITH_RUNTIME_CHECK) diff --git a/src/include/regex/regcustom.h b/src/include/regex/regcustom.h index af0fe97c796..91b5fc80ae8 100644 --- a/src/include/regex/regcustom.h +++ b/src/include/regex/regcustom.h @@ -52,6 +52,8 @@ #define MALLOC(n) palloc_extended((n), MCXT_ALLOC_NO_OOM) #define FREE(p) pfree(VS(p)) #define REALLOC(p,n) repalloc_extended(VS(p),(n), MCXT_ALLOC_NO_OOM) +#define MALLOC_ARRAY(type, n) palloc_array_extended(type, n, MCXT_ALLOC_NO_OOM) +#define REALLOC_ARRAY(p, type, n) repalloc_array_extended(p, type, n, MCXT_ALLOC_NO_OOM) #define INTERRUPT(re) CHECK_FOR_INTERRUPTS() #define assert(x) Assert(x) diff --git a/src/include/regex/regguts.h b/src/include/regex/regguts.h index fd69299a16d..6fb9551721d 100644 --- a/src/include/regex/regguts.h +++ b/src/include/regex/regguts.h @@ -76,6 +76,14 @@ #ifndef FREE #define FREE(p) free(VS(p)) #endif +#ifndef MALLOC_ARRAY +/* we don't depend on calloc's zeroing behavior, we do need overflow check */ +#define MALLOC_ARRAY(type, n) ((type *) calloc(sizeof(type), n)) +#endif +#ifndef REALLOC_ARRAY +/* XXX this definition does not provide the desired overflow check */ +#define REALLOC_ARRAY(p, type, n) ((type *) REALLOC(p, sizeof(type) * (n))) +#endif /* interruption */ #ifndef INTERRUPT @@ -446,6 +454,11 @@ struct cnfa * (the compacted NFA and the colormap). * The scaling here is based on an empirical measurement that very large * NFAs tend to have about 4 arcs/state. + * + * Do not raise this so high as to allow more than INT_MAX/8 states or arcs, + * or you risk integer overflows in various space allocation requests. + * (We could be more defensive in those places, but that's so far beyond the + * practical range of NFA sizes that it doesn't seem worth additional code.) */ #ifndef REG_MAX_COMPILE_SPACE #define REG_MAX_COMPILE_SPACE \ diff --git a/src/include/replication/slotsync.h b/src/include/replication/slotsync.h index 16b721463dd..882c46581b3 100644 --- a/src/include/replication/slotsync.h +++ b/src/include/replication/slotsync.h @@ -12,10 +12,15 @@ #ifndef SLOTSYNC_H #define SLOTSYNC_H +#include + #include "replication/walreceiver.h" extern PGDLLIMPORT bool sync_replication_slots; +/* Interrupt flag set by HandleSlotSyncMessageInterrupt() */ +extern PGDLLIMPORT volatile sig_atomic_t SlotSyncShutdownPending; + /* * GUCs needed by slot sync worker to connect to the primary * server and carry on with slots synchronization. @@ -34,5 +39,7 @@ extern bool IsSyncingReplicationSlots(void); extern Size SlotSyncShmemSize(void); extern void SlotSyncShmemInit(void); extern void SyncReplicationSlots(WalReceiverConn *wrconn); +extern void HandleSlotSyncMessageInterrupt(void); +extern void ProcessSlotSyncMessage(void); #endif /* SLOTSYNC_H */ diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h index 834fd8c6af4..7343b87830c 100644 --- a/src/include/storage/proc.h +++ b/src/include/storage/proc.h @@ -461,6 +461,7 @@ extern PGDLLIMPORT PGPROC *PreparedXactProcs; #define MAX_IO_WORKERS 32 #define NUM_AUXILIARY_PROCS (6 + MAX_IO_WORKERS) +#define FIRST_PREPARED_XACT_PROC_NUMBER (MaxBackends + NUM_AUXILIARY_PROCS) /* configurable options */ extern PGDLLIMPORT int DeadlockTimeout; diff --git a/src/include/storage/procsignal.h b/src/include/storage/procsignal.h index afeeb1ca019..234cfcb364a 100644 --- a/src/include/storage/procsignal.h +++ b/src/include/storage/procsignal.h @@ -47,9 +47,11 @@ typedef enum PROCSIG_RECOVERY_CONFLICT_BUFFERPIN, PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK, PROCSIG_RECOVERY_CONFLICT_LAST = PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK, + + PROCSIG_SLOTSYNC_MESSAGE, /* ask slot synchronization to stop */ } ProcSignalReason; -#define NUM_PROCSIGNALS (PROCSIG_RECOVERY_CONFLICT_LAST + 1) +#define NUM_PROCSIGNALS (PROCSIG_SLOTSYNC_MESSAGE + 1) typedef enum { diff --git a/src/include/storage/shmem.h b/src/include/storage/shmem.h index c1f668ded95..bcf7d9ea36c 100644 --- a/src/include/storage/shmem.h +++ b/src/include/storage/shmem.h @@ -38,8 +38,6 @@ extern void InitShmemIndex(void); extern HTAB *ShmemInitHash(const char *name, long init_size, long max_size, HASHCTL *infoP, int hash_flags); extern void *ShmemInitStruct(const char *name, Size size, bool *foundPtr); -extern Size add_size(Size s1, Size s2); -extern Size mul_size(Size s1, Size s2); extern PGDLLIMPORT Size pg_get_shmem_pagesize(void); diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h index fa22f7a05ea..92daec0d638 100644 --- a/src/include/utils/lsyscache.h +++ b/src/include/utils/lsyscache.h @@ -92,6 +92,7 @@ extern bool get_op_hash_functions(Oid opno, extern List *get_op_index_interpretation(Oid opno); extern bool equality_ops_are_compatible(Oid opno1, Oid opno2); extern bool comparison_ops_are_compatible(Oid opno1, Oid opno2); +extern bool collations_agree_on_equality(Oid coll1, Oid coll2); extern Oid get_opfamily_proc(Oid opfamily, Oid lefttype, Oid righttype, int16 procnum); extern char *get_attname(Oid relid, AttrNumber attnum, bool missing_ok); diff --git a/src/include/utils/memutils.h b/src/include/utils/memutils.h index 8abc26abce2..1375683fb8e 100644 --- a/src/include/utils/memutils.h +++ b/src/include/utils/memutils.h @@ -41,7 +41,7 @@ #define AllocSizeIsValid(size) ((Size) (size) <= MaxAllocSize) -/* Must be less than SIZE_MAX */ +/* Do not make this any bigger; see add_size() and mul_size() */ #define MaxAllocHugeSize (SIZE_MAX / 2) #define InvalidAllocSize SIZE_MAX diff --git a/src/include/utils/palloc.h b/src/include/utils/palloc.h index e1b42267b22..e5d3f0947f4 100644 --- a/src/include/utils/palloc.h +++ b/src/include/utils/palloc.h @@ -85,6 +85,18 @@ pg_nodiscard extern void *repalloc_extended(void *pointer, pg_nodiscard extern void *repalloc0(void *pointer, Size oldsize, Size size); extern void pfree(void *pointer); +/* + * Support for safe calculation of memory request sizes + */ +extern Size add_size(Size s1, Size s2); +extern Size mul_size(Size s1, Size s2); +extern void *palloc_mul(Size s1, Size s2); +extern void *palloc0_mul(Size s1, Size s2); +extern void *palloc_mul_extended(Size s1, Size s2, int flags); +pg_nodiscard extern void *repalloc_mul(void *p, Size s1, Size s2); +pg_nodiscard extern void *repalloc_mul_extended(void *p, Size s1, Size s2, + int flags); + /* * Variants with easier notation and more type safety */ @@ -98,15 +110,17 @@ extern void pfree(void *pointer); /* * Allocate space for "count" objects of type "type" */ -#define palloc_array(type, count) ((type *) palloc(sizeof(type) * (count))) -#define palloc0_array(type, count) ((type *) palloc0(sizeof(type) * (count))) +#define palloc_array(type, count) ((type *) palloc_mul(sizeof(type), count)) +#define palloc0_array(type, count) ((type *) palloc0_mul(sizeof(type), count)) +#define palloc_array_extended(type, count, flags) ((type *) palloc_mul_extended(sizeof(type), count, flags)) /* * Change size of allocation pointed to by "pointer" to have space for "count" * objects of type "type" */ -#define repalloc_array(pointer, type, count) ((type *) repalloc(pointer, sizeof(type) * (count))) -#define repalloc0_array(pointer, type, oldcount, count) ((type *) repalloc0(pointer, sizeof(type) * (oldcount), sizeof(type) * (count))) +#define repalloc_array(pointer, type, count) ((type *) repalloc_mul(pointer, sizeof(type), count)) +#define repalloc0_array(pointer, type, oldcount, count) ((type *) repalloc0(pointer, mul_size(sizeof(type), oldcount), mul_size(sizeof(type), count))) +#define repalloc_array_extended(pointer, type, count, flags) ((type *) repalloc_mul_extended(pointer, sizeof(type), count, flags)) /* Higher-limit allocators. */ extern void *MemoryContextAllocHuge(MemoryContext context, Size size); diff --git a/src/interfaces/ecpg/ecpglib/descriptor.c b/src/interfaces/ecpg/ecpglib/descriptor.c index c6ef441d139..0486b157eee 100644 --- a/src/interfaces/ecpg/ecpglib/descriptor.c +++ b/src/interfaces/ecpg/ecpglib/descriptor.c @@ -475,6 +475,16 @@ ECPGget_desc(int lineno, const char *desc_name, int index,...) memset(&stmt, 0, sizeof stmt); stmt.lineno = lineno; + /* desperate try to guess something sensible */ + stmt.connection = ecpg_get_connection(NULL); + if (stmt.connection == NULL) + { + ecpg_raise(lineno, ECPG_NO_CONN, ECPG_SQLSTATE_CONNECTION_DOES_NOT_EXIST, + ecpg_gettext("NULL")); + va_end(args); + return false; + } + /* Make sure we do NOT honor the locale for numeric input */ /* since the database gives the standard decimal point */ /* (see comments in execute.c) */ @@ -497,8 +507,6 @@ ECPGget_desc(int lineno, const char *desc_name, int index,...) setlocale(LC_NUMERIC, "C"); #endif - /* desperate try to guess something sensible */ - stmt.connection = ecpg_get_connection(NULL); ecpg_store_result(ECPGresult, index, &stmt, &data_var); #ifdef HAVE_USELOCALE diff --git a/src/interfaces/ecpg/ecpglib/prepare.c b/src/interfaces/ecpg/ecpglib/prepare.c index ea1146f520f..998c790c176 100644 --- a/src/interfaces/ecpg/ecpglib/prepare.c +++ b/src/interfaces/ecpg/ecpglib/prepare.c @@ -349,8 +349,12 @@ ecpg_deallocate_all_conn(int lineno, enum COMPAT_MODE c, struct connection *con) bool ECPGdeallocate_all(int lineno, int compat, const char *connection_name) { - return ecpg_deallocate_all_conn(lineno, compat, - ecpg_get_connection(connection_name)); + struct connection *con = ecpg_get_connection(connection_name); + + if (!ecpg_init(con, connection_name, lineno)) + return false; + + return ecpg_deallocate_all_conn(lineno, compat, con); } char * @@ -363,13 +367,15 @@ ecpg_prepared(const char *name, struct connection *con) } /* return the prepared statement */ -/* lineno is not used here, but kept in to not break API */ char * ECPGprepared_statement(const char *connection_name, const char *name, int lineno) { - (void) lineno; /* keep the compiler quiet */ + struct connection *con = ecpg_get_connection(connection_name); + + if (!ecpg_init(con, connection_name, lineno)) + return NULL; - return ecpg_prepared(name, ecpg_get_connection(connection_name)); + return ecpg_prepared(name, con); } /* @@ -466,10 +472,18 @@ ecpg_freeStmtCacheEntry(int lineno, int compat, con = ecpg_get_connection(entry->connection); - /* free the 'prepared_statement' list entry */ - this = ecpg_find_prepared_statement(entry->stmtID, con, &prev); - if (this && !deallocate_one(lineno, compat, con, prev, this)) - return -1; + /* + * If the connection is gone, the prepared_statement list it owned is + * already unreachable, so just skip that cleanup. We must still clear + * the cache slot below so it can be reused. + */ + if (con) + { + /* free the 'prepared_statement' list entry */ + this = ecpg_find_prepared_statement(entry->stmtID, con, &prev); + if (this && !deallocate_one(lineno, compat, con, prev, this)) + return -1; + } entry->stmtID[0] = '\0'; diff --git a/src/interfaces/ecpg/oracle_test/connect/.gitignore b/src/interfaces/ecpg/oracle_test/connect/.gitignore index e0639f3c8d1..02236847444 100644 --- a/src/interfaces/ecpg/oracle_test/connect/.gitignore +++ b/src/interfaces/ecpg/oracle_test/connect/.gitignore @@ -8,3 +8,5 @@ /test4.c /test5 /test5.c +/test6 +/test6.c diff --git a/src/interfaces/ecpg/oracle_test/connect/Makefile b/src/interfaces/ecpg/oracle_test/connect/Makefile index b5b215a346e..088201ed875 100644 --- a/src/interfaces/ecpg/oracle_test/connect/Makefile +++ b/src/interfaces/ecpg/oracle_test/connect/Makefile @@ -7,6 +7,7 @@ TESTS = test1 test1.c \ test2 test2.c \ test3 test3.c \ test4 test4.c \ - test5 test5.c + test5 test5.c \ + test6 test6.c all: $(TESTS) diff --git a/src/interfaces/ecpg/oracle_test/connect/meson.build b/src/interfaces/ecpg/oracle_test/connect/meson.build index 7cfdb7b8140..9a08487b856 100644 --- a/src/interfaces/ecpg/oracle_test/connect/meson.build +++ b/src/interfaces/ecpg/oracle_test/connect/meson.build @@ -7,6 +7,7 @@ pgc_files = [ 'test3', 'test4', 'test5', + 'test6', ] foreach pgc_file : pgc_files diff --git a/src/interfaces/ecpg/oracle_test/connect/test6.pgc b/src/interfaces/ecpg/oracle_test/connect/test6.pgc new file mode 100644 index 00000000000..d2c10dffb03 --- /dev/null +++ b/src/interfaces/ecpg/oracle_test/connect/test6.pgc @@ -0,0 +1,68 @@ +/* + * This test verifies that ecpg functions properly handle NULL connections + * (i.e., when a connection name doesn't exist or has been disconnected). + * Before the fix, these operations would cause a segmentation fault. + */ + +#include +#include +#include + +exec sql include ../regression; + +int +main(void) +{ +exec sql begin declare section; + int val1output = 2; + int val1 = 1; + char val2[6] = "data1"; + char *stmt1 = "SELECT * from test1 where a = $1 and b = $2"; +exec sql end declare section; + + ECPGdebug(1, stderr); + + /* Connect to the database */ + exec sql connect to REGRESSDB1 as myconn; + + /* Test 1: Try to get descriptor on a disconnected connection */ + printf("Test 1: Try to get descriptor on a disconnected connection\n"); + exec sql create table test1 (a int, b text); + exec sql insert into test1 (a,b) values (1, 'data1'); + + exec sql allocate descriptor indesc; + exec sql allocate descriptor outdesc; + + exec sql prepare foo2 from :stmt1; + + exec sql set descriptor indesc value 1 DATA = :val1; + exec sql set descriptor indesc value 2 DATA = :val2; + + exec sql execute foo2 using sql descriptor indesc into sql descriptor outdesc; + + exec sql rollback; + exec sql disconnect; + exec sql get descriptor outdesc value 1 :val1output = DATA; + printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode); + + /* Test 2: Try to deallocate all on a non-existent connection */ + printf("Test 2: deallocate all with non-existent connection\n"); + exec sql at nonexistent deallocate all; + printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode); + + /* Test 3: deallocate on disconnected connection */ + printf("Test 3: deallocate all on disconnected connection\n"); + exec sql deallocate all; + printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode); + + /* Test 4: Use prepared statement from non-existent connection */ + printf("Test 4: Use prepared statement from non-existent connection\n"); + exec sql at nonexistent prepare stmt1 FROM "SELECT 1"; + exec sql at nonexistent declare cur1 cursor for stmt1; + exec sql at nonexistent open cur1; + printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode); + + printf("All tests completed !\n"); + + return 0; +} diff --git a/src/interfaces/ecpg/oracle_test/ecpg_schedule b/src/interfaces/ecpg/oracle_test/ecpg_schedule index 254a0bacc75..202110e9fc6 100644 --- a/src/interfaces/ecpg/oracle_test/ecpg_schedule +++ b/src/interfaces/ecpg/oracle_test/ecpg_schedule @@ -13,6 +13,7 @@ test: connect/test2 test: connect/test3 test: connect/test4 test: connect/test5 +test: connect/test6 test: pgtypeslib/dt_test test: pgtypeslib/dt_test2 test: pgtypeslib/num_test diff --git a/src/interfaces/ecpg/oracle_test/expected/connect-test6.c b/src/interfaces/ecpg/oracle_test/expected/connect-test6.c new file mode 100644 index 00000000000..eed3c46a38c --- /dev/null +++ b/src/interfaces/ecpg/oracle_test/expected/connect-test6.c @@ -0,0 +1,146 @@ +/* Processed by ecpg (regression mode) */ +/* These include files are added by the preprocessor */ +#include +#include +#include +/* End of automatic include section */ +#define ECPGdebug(X,Y) ECPGdebug((X)+100,(Y)) + +#line 1 "test6.pgc" +/* + * This test verifies that ecpg functions properly handle NULL connections + * (i.e., when a connection name doesn't exist or has been disconnected). + * Before the fix, these operations would cause a segmentation fault. + */ + +#include +#include +#include + + +#line 1 "regression.h" + + + + + + +#line 11 "test6.pgc" + + +int +main(void) +{ +/* exec sql begin declare section */ + + + + + +#line 17 "test6.pgc" + int val1output = 2 ; + +#line 18 "test6.pgc" + int val1 = 1 ; + +#line 19 "test6.pgc" + char val2 [ 6 ] = "data1" ; + +#line 20 "test6.pgc" + char * stmt1 = "SELECT * from test1 where a = $1 and b = $2" ; +/* exec sql end declare section */ +#line 21 "test6.pgc" + + + ECPGdebug(1, stderr); + + /* Connect to the database */ + { ECPGconnect(__LINE__, 0, "ecpg1_regression" , NULL, NULL , "myconn", 0); } +#line 26 "test6.pgc" + + + /* Test 1: Try to get descriptor on a disconnected connection */ + printf("Test 1: Try to get descriptor on a disconnected connection\n"); + { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "create table test1 ( a int , b text )", ECPGt_EOIT, ECPGt_EORT);} +#line 30 "test6.pgc" + + { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into test1 ( a , b ) values ( 1 , 'data1' )", ECPGt_EOIT, ECPGt_EORT);} +#line 31 "test6.pgc" + + + ECPGallocate_desc(__LINE__, "indesc"); +#line 33 "test6.pgc" + + ECPGallocate_desc(__LINE__, "outdesc"); +#line 34 "test6.pgc" + + + { ECPGprepare(__LINE__, NULL, 0, "foo2", stmt1);} +#line 36 "test6.pgc" + + + { ECPGset_desc(__LINE__, "indesc", 1,ECPGd_data, + ECPGt_int,&(val1),(long)1,(long)1,sizeof(int), ECPGd_EODT); +} +#line 38 "test6.pgc" + + { ECPGset_desc(__LINE__, "indesc", 2,ECPGd_data, + ECPGt_char,(val2),(long)6,(long)1,(6)*sizeof(char), ECPGd_EODT); +} +#line 39 "test6.pgc" + + + { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_execute, "foo2", + ECPGt_descriptor, "indesc", 1L, 1L, 1L, + ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, + ECPGt_descriptor, "outdesc", 1L, 1L, 1L, + ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);} +#line 41 "test6.pgc" + + + { ECPGtrans(__LINE__, NULL, "rollback");} +#line 43 "test6.pgc" + + { ECPGdisconnect(__LINE__, "CURRENT");} +#line 44 "test6.pgc" + + { ECPGget_desc(__LINE__, "outdesc", 1,ECPGd_data, + ECPGt_int,&(val1output),(long)1,(long)1,sizeof(int), ECPGd_EODT); +} +#line 45 "test6.pgc" + + printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode); + + /* Test 2: Try to deallocate all on a non-existent connection */ + printf("Test 2: deallocate all with non-existent connection\n"); + { ECPGdeallocate_all(__LINE__, 0, "nonexistent");} +#line 50 "test6.pgc" + + printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode); + + /* Test 3: deallocate on disconnected connection */ + printf("Test 3: deallocate all on disconnected connection\n"); + { ECPGdeallocate_all(__LINE__, 0, NULL);} +#line 55 "test6.pgc" + + printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode); + + /* Test 4: Use prepared statement from non-existent connection */ + printf("Test 4: Use prepared statement from non-existent connection\n"); + { ECPGprepare(__LINE__, "nonexistent", 0, "stmt1", "SELECT 1");} +#line 60 "test6.pgc" + + /* declare cur1 cursor for $1 */ +#line 61 "test6.pgc" + + { ECPGdo(__LINE__, 0, 1, "nonexistent", 0, ECPGst_normal, "declare cur1 cursor for $1", + ECPGt_char_variable,(ECPGprepared_statement("nonexistent", "stmt1", __LINE__)),(long)1,(long)1,(1)*sizeof(char), + ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);} +#line 62 "test6.pgc" + + printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode); + + printf("All tests completed !\n"); + + return 0; +} diff --git a/src/interfaces/ecpg/oracle_test/expected/connect-test6.stderr b/src/interfaces/ecpg/oracle_test/expected/connect-test6.stderr new file mode 100644 index 00000000000..8784d5a9d40 --- /dev/null +++ b/src/interfaces/ecpg/oracle_test/expected/connect-test6.stderr @@ -0,0 +1,50 @@ +[NO_PID]: ECPGdebug: set to 1 +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ECPGconnect: opening database ecpg1_regression on port +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 30: query: create table test1 ( a int , b text ); with 0 parameter(s) on connection myconn +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 30: using PQexec +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_process_output on line 30: OK: CREATE TABLE +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 31: query: insert into test1 ( a , b ) values ( 1 , 'data1' ); with 0 parameter(s) on connection myconn +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 31: using PQexec +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_process_output on line 31: OK: INSERT 0 1 +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: prepare_common on line 36: name foo2; query: "SELECT * from test1 where a = $1 and b = $2" +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 41: query: SELECT * from test1 where a = $1 and b = $2; with 2 parameter(s) on connection myconn +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 41: using PQexecPrepared for "SELECT * from test1 where a = $1 and b = $2" +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_free_params on line 41: parameter 1 = 1 +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_free_params on line 41: parameter 2 = data1 +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_process_output on line 41: correctly got 1 tuples with 2 fields +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_process_output on line 41: putting result (1 tuples) into descriptor outdesc +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ECPGtrans on line 43: action "rollback"; connection "myconn" +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: deallocate_one on line 0: name foo2 +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_finish: connection myconn closed +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ECPGget_desc: reading items for tuple 1 +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: raising sqlcode -220 on line 45: connection "NULL" does not exist on line 45 +[NO_PID]: sqlca: code: -220, state: 08003 +[NO_PID]: raising sqlcode -220 on line 50: connection "nonexistent" does not exist on line 50 +[NO_PID]: sqlca: code: -220, state: 08003 +[NO_PID]: raising sqlcode -220 on line 55: connection "NULL" does not exist on line 55 +[NO_PID]: sqlca: code: -220, state: 08003 +[NO_PID]: raising sqlcode -220 on line 60: connection "nonexistent" does not exist on line 60 +[NO_PID]: sqlca: code: -220, state: 08003 +[NO_PID]: raising sqlcode -220 on line 63: connection "nonexistent" does not exist on line 63 +[NO_PID]: sqlca: code: -220, state: 08003 +[NO_PID]: raising sqlcode -220 on line 62: connection "nonexistent" does not exist on line 62 +[NO_PID]: sqlca: code: -220, state: 08003 diff --git a/src/interfaces/ecpg/oracle_test/expected/connect-test6.stdout b/src/interfaces/ecpg/oracle_test/expected/connect-test6.stdout new file mode 100644 index 00000000000..bf9a2e91051 --- /dev/null +++ b/src/interfaces/ecpg/oracle_test/expected/connect-test6.stdout @@ -0,0 +1,9 @@ +Test 1: Try to get descriptor on a disconnected connection +sqlca.sqlcode = -220 +Test 2: deallocate all with non-existent connection +sqlca.sqlcode = -220 +Test 3: deallocate all on disconnected connection +sqlca.sqlcode = -220 +Test 4: Use prepared statement from non-existent connection +sqlca.sqlcode = -220 +All tests completed ! diff --git a/src/interfaces/ecpg/pgtypeslib/datetime.c b/src/interfaces/ecpg/pgtypeslib/datetime.c index 1b253747fc4..f43343b4594 100644 --- a/src/interfaces/ecpg/pgtypeslib/datetime.c +++ b/src/interfaces/ecpg/pgtypeslib/datetime.c @@ -335,8 +335,8 @@ PGTYPESdate_defmt_asc(date * d, const char *fmt, const char *str) */ int token[3][2]; int token_values[3] = {-1, -1, -1}; - char *fmt_token_order; - char *fmt_ystart, + const char *fmt_token_order; + const char *fmt_ystart, *fmt_mstart, *fmt_dstart; unsigned int i; diff --git a/src/interfaces/ecpg/preproc/ecpg.trailer b/src/interfaces/ecpg/preproc/ecpg.trailer index 6f94b832a03..390e7713bfb 100644 --- a/src/interfaces/ecpg/preproc/ecpg.trailer +++ b/src/interfaces/ecpg/preproc/ecpg.trailer @@ -1975,7 +1975,7 @@ civarind: cvariable indicator char_civar: char_variable { - char *ptr = strstr(@1, ".arr"); + char *ptr = (char *) strstr(@1, ".arr"); if (ptr) /* varchar, we need the struct name here, not * the struct element */ diff --git a/src/interfaces/ecpg/preproc/variable.c b/src/interfaces/ecpg/preproc/variable.c index 2c67e33e92e..9179b4fb5cf 100644 --- a/src/interfaces/ecpg/preproc/variable.c +++ b/src/interfaces/ecpg/preproc/variable.c @@ -197,7 +197,7 @@ find_variable(const char *name) struct variable *p; int count; - next = strpbrk(name, ".[-"); + next = (char *) strpbrk(name, ".[-"); if (next) { if (*next == '[') diff --git a/src/interfaces/ecpg/test/connect/.gitignore b/src/interfaces/ecpg/test/connect/.gitignore index e0639f3c8d1..02236847444 100644 --- a/src/interfaces/ecpg/test/connect/.gitignore +++ b/src/interfaces/ecpg/test/connect/.gitignore @@ -8,3 +8,5 @@ /test4.c /test5 /test5.c +/test6 +/test6.c diff --git a/src/interfaces/ecpg/test/connect/Makefile b/src/interfaces/ecpg/test/connect/Makefile index 2602d5d286f..17fa2667bf7 100644 --- a/src/interfaces/ecpg/test/connect/Makefile +++ b/src/interfaces/ecpg/test/connect/Makefile @@ -7,6 +7,7 @@ TESTS = test1 test1.c \ test2 test2.c \ test3 test3.c \ test4 test4.c \ - test5 test5.c + test5 test5.c \ + test6 test6.c all: $(TESTS) diff --git a/src/interfaces/ecpg/test/connect/meson.build b/src/interfaces/ecpg/test/connect/meson.build index 5154167663d..a49aec33ebf 100644 --- a/src/interfaces/ecpg/test/connect/meson.build +++ b/src/interfaces/ecpg/test/connect/meson.build @@ -6,6 +6,7 @@ pgc_files = [ 'test3', 'test4', 'test5', + 'test6', ] foreach pgc_file : pgc_files diff --git a/src/interfaces/ecpg/test/connect/test6.pgc b/src/interfaces/ecpg/test/connect/test6.pgc new file mode 100644 index 00000000000..d2c10dffb03 --- /dev/null +++ b/src/interfaces/ecpg/test/connect/test6.pgc @@ -0,0 +1,68 @@ +/* + * This test verifies that ecpg functions properly handle NULL connections + * (i.e., when a connection name doesn't exist or has been disconnected). + * Before the fix, these operations would cause a segmentation fault. + */ + +#include +#include +#include + +exec sql include ../regression; + +int +main(void) +{ +exec sql begin declare section; + int val1output = 2; + int val1 = 1; + char val2[6] = "data1"; + char *stmt1 = "SELECT * from test1 where a = $1 and b = $2"; +exec sql end declare section; + + ECPGdebug(1, stderr); + + /* Connect to the database */ + exec sql connect to REGRESSDB1 as myconn; + + /* Test 1: Try to get descriptor on a disconnected connection */ + printf("Test 1: Try to get descriptor on a disconnected connection\n"); + exec sql create table test1 (a int, b text); + exec sql insert into test1 (a,b) values (1, 'data1'); + + exec sql allocate descriptor indesc; + exec sql allocate descriptor outdesc; + + exec sql prepare foo2 from :stmt1; + + exec sql set descriptor indesc value 1 DATA = :val1; + exec sql set descriptor indesc value 2 DATA = :val2; + + exec sql execute foo2 using sql descriptor indesc into sql descriptor outdesc; + + exec sql rollback; + exec sql disconnect; + exec sql get descriptor outdesc value 1 :val1output = DATA; + printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode); + + /* Test 2: Try to deallocate all on a non-existent connection */ + printf("Test 2: deallocate all with non-existent connection\n"); + exec sql at nonexistent deallocate all; + printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode); + + /* Test 3: deallocate on disconnected connection */ + printf("Test 3: deallocate all on disconnected connection\n"); + exec sql deallocate all; + printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode); + + /* Test 4: Use prepared statement from non-existent connection */ + printf("Test 4: Use prepared statement from non-existent connection\n"); + exec sql at nonexistent prepare stmt1 FROM "SELECT 1"; + exec sql at nonexistent declare cur1 cursor for stmt1; + exec sql at nonexistent open cur1; + printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode); + + printf("All tests completed !\n"); + + return 0; +} diff --git a/src/interfaces/ecpg/test/ecpg_schedule b/src/interfaces/ecpg/test/ecpg_schedule index 254a0bacc75..202110e9fc6 100644 --- a/src/interfaces/ecpg/test/ecpg_schedule +++ b/src/interfaces/ecpg/test/ecpg_schedule @@ -13,6 +13,7 @@ test: connect/test2 test: connect/test3 test: connect/test4 test: connect/test5 +test: connect/test6 test: pgtypeslib/dt_test test: pgtypeslib/dt_test2 test: pgtypeslib/num_test diff --git a/src/interfaces/ecpg/test/expected/connect-test6.c b/src/interfaces/ecpg/test/expected/connect-test6.c new file mode 100644 index 00000000000..eed3c46a38c --- /dev/null +++ b/src/interfaces/ecpg/test/expected/connect-test6.c @@ -0,0 +1,146 @@ +/* Processed by ecpg (regression mode) */ +/* These include files are added by the preprocessor */ +#include +#include +#include +/* End of automatic include section */ +#define ECPGdebug(X,Y) ECPGdebug((X)+100,(Y)) + +#line 1 "test6.pgc" +/* + * This test verifies that ecpg functions properly handle NULL connections + * (i.e., when a connection name doesn't exist or has been disconnected). + * Before the fix, these operations would cause a segmentation fault. + */ + +#include +#include +#include + + +#line 1 "regression.h" + + + + + + +#line 11 "test6.pgc" + + +int +main(void) +{ +/* exec sql begin declare section */ + + + + + +#line 17 "test6.pgc" + int val1output = 2 ; + +#line 18 "test6.pgc" + int val1 = 1 ; + +#line 19 "test6.pgc" + char val2 [ 6 ] = "data1" ; + +#line 20 "test6.pgc" + char * stmt1 = "SELECT * from test1 where a = $1 and b = $2" ; +/* exec sql end declare section */ +#line 21 "test6.pgc" + + + ECPGdebug(1, stderr); + + /* Connect to the database */ + { ECPGconnect(__LINE__, 0, "ecpg1_regression" , NULL, NULL , "myconn", 0); } +#line 26 "test6.pgc" + + + /* Test 1: Try to get descriptor on a disconnected connection */ + printf("Test 1: Try to get descriptor on a disconnected connection\n"); + { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "create table test1 ( a int , b text )", ECPGt_EOIT, ECPGt_EORT);} +#line 30 "test6.pgc" + + { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into test1 ( a , b ) values ( 1 , 'data1' )", ECPGt_EOIT, ECPGt_EORT);} +#line 31 "test6.pgc" + + + ECPGallocate_desc(__LINE__, "indesc"); +#line 33 "test6.pgc" + + ECPGallocate_desc(__LINE__, "outdesc"); +#line 34 "test6.pgc" + + + { ECPGprepare(__LINE__, NULL, 0, "foo2", stmt1);} +#line 36 "test6.pgc" + + + { ECPGset_desc(__LINE__, "indesc", 1,ECPGd_data, + ECPGt_int,&(val1),(long)1,(long)1,sizeof(int), ECPGd_EODT); +} +#line 38 "test6.pgc" + + { ECPGset_desc(__LINE__, "indesc", 2,ECPGd_data, + ECPGt_char,(val2),(long)6,(long)1,(6)*sizeof(char), ECPGd_EODT); +} +#line 39 "test6.pgc" + + + { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_execute, "foo2", + ECPGt_descriptor, "indesc", 1L, 1L, 1L, + ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, + ECPGt_descriptor, "outdesc", 1L, 1L, 1L, + ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);} +#line 41 "test6.pgc" + + + { ECPGtrans(__LINE__, NULL, "rollback");} +#line 43 "test6.pgc" + + { ECPGdisconnect(__LINE__, "CURRENT");} +#line 44 "test6.pgc" + + { ECPGget_desc(__LINE__, "outdesc", 1,ECPGd_data, + ECPGt_int,&(val1output),(long)1,(long)1,sizeof(int), ECPGd_EODT); +} +#line 45 "test6.pgc" + + printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode); + + /* Test 2: Try to deallocate all on a non-existent connection */ + printf("Test 2: deallocate all with non-existent connection\n"); + { ECPGdeallocate_all(__LINE__, 0, "nonexistent");} +#line 50 "test6.pgc" + + printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode); + + /* Test 3: deallocate on disconnected connection */ + printf("Test 3: deallocate all on disconnected connection\n"); + { ECPGdeallocate_all(__LINE__, 0, NULL);} +#line 55 "test6.pgc" + + printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode); + + /* Test 4: Use prepared statement from non-existent connection */ + printf("Test 4: Use prepared statement from non-existent connection\n"); + { ECPGprepare(__LINE__, "nonexistent", 0, "stmt1", "SELECT 1");} +#line 60 "test6.pgc" + + /* declare cur1 cursor for $1 */ +#line 61 "test6.pgc" + + { ECPGdo(__LINE__, 0, 1, "nonexistent", 0, ECPGst_normal, "declare cur1 cursor for $1", + ECPGt_char_variable,(ECPGprepared_statement("nonexistent", "stmt1", __LINE__)),(long)1,(long)1,(1)*sizeof(char), + ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);} +#line 62 "test6.pgc" + + printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode); + + printf("All tests completed !\n"); + + return 0; +} diff --git a/src/interfaces/ecpg/test/expected/connect-test6.stderr b/src/interfaces/ecpg/test/expected/connect-test6.stderr new file mode 100644 index 00000000000..8784d5a9d40 --- /dev/null +++ b/src/interfaces/ecpg/test/expected/connect-test6.stderr @@ -0,0 +1,50 @@ +[NO_PID]: ECPGdebug: set to 1 +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ECPGconnect: opening database ecpg1_regression on port +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 30: query: create table test1 ( a int , b text ); with 0 parameter(s) on connection myconn +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 30: using PQexec +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_process_output on line 30: OK: CREATE TABLE +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 31: query: insert into test1 ( a , b ) values ( 1 , 'data1' ); with 0 parameter(s) on connection myconn +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 31: using PQexec +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_process_output on line 31: OK: INSERT 0 1 +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: prepare_common on line 36: name foo2; query: "SELECT * from test1 where a = $1 and b = $2" +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 41: query: SELECT * from test1 where a = $1 and b = $2; with 2 parameter(s) on connection myconn +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 41: using PQexecPrepared for "SELECT * from test1 where a = $1 and b = $2" +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_free_params on line 41: parameter 1 = 1 +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_free_params on line 41: parameter 2 = data1 +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_process_output on line 41: correctly got 1 tuples with 2 fields +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_process_output on line 41: putting result (1 tuples) into descriptor outdesc +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ECPGtrans on line 43: action "rollback"; connection "myconn" +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: deallocate_one on line 0: name foo2 +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_finish: connection myconn closed +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ECPGget_desc: reading items for tuple 1 +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: raising sqlcode -220 on line 45: connection "NULL" does not exist on line 45 +[NO_PID]: sqlca: code: -220, state: 08003 +[NO_PID]: raising sqlcode -220 on line 50: connection "nonexistent" does not exist on line 50 +[NO_PID]: sqlca: code: -220, state: 08003 +[NO_PID]: raising sqlcode -220 on line 55: connection "NULL" does not exist on line 55 +[NO_PID]: sqlca: code: -220, state: 08003 +[NO_PID]: raising sqlcode -220 on line 60: connection "nonexistent" does not exist on line 60 +[NO_PID]: sqlca: code: -220, state: 08003 +[NO_PID]: raising sqlcode -220 on line 63: connection "nonexistent" does not exist on line 63 +[NO_PID]: sqlca: code: -220, state: 08003 +[NO_PID]: raising sqlcode -220 on line 62: connection "nonexistent" does not exist on line 62 +[NO_PID]: sqlca: code: -220, state: 08003 diff --git a/src/interfaces/ecpg/test/expected/connect-test6.stdout b/src/interfaces/ecpg/test/expected/connect-test6.stdout new file mode 100644 index 00000000000..bf9a2e91051 --- /dev/null +++ b/src/interfaces/ecpg/test/expected/connect-test6.stdout @@ -0,0 +1,9 @@ +Test 1: Try to get descriptor on a disconnected connection +sqlca.sqlcode = -220 +Test 2: deallocate all with non-existent connection +sqlca.sqlcode = -220 +Test 3: deallocate all on disconnected connection +sqlca.sqlcode = -220 +Test 4: Use prepared statement from non-existent connection +sqlca.sqlcode = -220 +All tests completed ! diff --git a/src/interfaces/libpq/fe-auth-scram.c b/src/interfaces/libpq/fe-auth-scram.c index f6d6a5aa977..f0feeeaca51 100644 --- a/src/interfaces/libpq/fe-auth-scram.c +++ b/src/interfaces/libpq/fe-auth-scram.c @@ -631,7 +631,7 @@ read_server_first_message(fe_scram_state *state, char *input) /* Verify immediately that the server used our part of the nonce */ if (strlen(nonce) < strlen(state->client_nonce) || - memcmp(nonce, state->client_nonce, strlen(state->client_nonce)) != 0) + timingsafe_bcmp(nonce, state->client_nonce, strlen(state->client_nonce)) != 0) { libpq_append_conn_error(conn, "invalid SCRAM response (nonce mismatch)"); return false; @@ -896,8 +896,8 @@ verify_server_signature(fe_scram_state *state, bool *match, pg_hmac_free(ctx); /* signature processed, so now check after it */ - if (memcmp(expected_ServerSignature, state->ServerSignature, - state->key_length) != 0) + if (timingsafe_bcmp(expected_ServerSignature, state->ServerSignature, + state->key_length) != 0) *match = false; else *match = true; diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c index 72518ef7bb8..968e90c5ba3 100644 --- a/src/interfaces/libpq/fe-exec.c +++ b/src/interfaces/libpq/fe-exec.c @@ -24,6 +24,7 @@ #include #endif +#include "common/int.h" #include "libpq-fe.h" #include "libpq-int.h" #include "mb/pg_wchar.h" @@ -2998,6 +2999,20 @@ PQfn(PGconn *conn, int result_is_int, const PQArgBlock *args, int nargs) +{ + return PQnfn(conn, fnid, result_buf, -1, result_len, + result_is_int, args, nargs); +} + +/* + * PQnfn + * Private version of PQfn() with verification that returned data fits in + * result_buf when result_is_int == 0. Setting buf_size to -1 disables + * this verification. + */ +PGresult * +PQnfn(PGconn *conn, int fnid, int *result_buf, int buf_size, int *result_len, + int result_is_int, const PQArgBlock *args, int nargs) { *result_len = 0; @@ -3026,7 +3041,7 @@ PQfn(PGconn *conn, } return pqFunctionCall3(conn, fnid, - result_buf, result_len, + result_buf, buf_size, result_len, result_is_int, args, nargs); } @@ -4217,27 +4232,6 @@ PQescapeString(char *to, const char *from, size_t length) } -/* - * Frontend version of the backend's add_size(), intended to be API-compatible - * with the pg_add_*_overflow() helpers. Stores the result into *dst on success. - * Returns true instead if the addition overflows. - * - * TODO: move to common/int.h - */ -static bool -add_size_overflow(size_t s1, size_t s2, size_t *dst) -{ - size_t result; - - result = s1 + s2; - if (result < s1 || result < s2) - return true; - - *dst = result; - return false; -} - - /* * Escape arbitrary strings. If as_ident is true, we escape the result * as an identifier; if false, as a literal. The result is returned in @@ -4321,14 +4315,14 @@ PQescapeInternal(PGconn *conn, const char *str, size_t len, bool as_ident) * Allocate output buffer. Protect against overflow, in case the caller * has allocated a large fraction of the available size_t. */ - if (add_size_overflow(input_len, num_quotes, &result_size) || - add_size_overflow(result_size, 3, &result_size)) /* two quotes plus a NUL */ + if (pg_add_size_overflow(input_len, num_quotes, &result_size) || + pg_add_size_overflow(result_size, 3, &result_size)) /* two quotes plus a NUL */ goto overflow; if (!as_ident && num_backslashes > 0) { - if (add_size_overflow(result_size, num_backslashes, &result_size) || - add_size_overflow(result_size, 2, &result_size)) /* for " E" prefix */ + if (pg_add_size_overflow(result_size, num_backslashes, &result_size) || + pg_add_size_overflow(result_size, 2, &result_size)) /* for " E" prefix */ goto overflow; } @@ -4490,9 +4484,9 @@ PQescapeByteaInternal(PGconn *conn, if (use_hex) { /* We prepend "\x" and double each input character. */ - if (add_size_overflow(len, bslash_len + 1, &len) || - add_size_overflow(len, from_length, &len) || - add_size_overflow(len, from_length, &len)) + if (pg_add_size_overflow(len, bslash_len + 1, &len) || + pg_add_size_overflow(len, from_length, &len) || + pg_add_size_overflow(len, from_length, &len)) goto overflow; } else @@ -4502,22 +4496,22 @@ PQescapeByteaInternal(PGconn *conn, { if (*vp < 0x20 || *vp > 0x7e) { - if (add_size_overflow(len, bslash_len + 3, &len)) /* octal "\ooo" */ + if (pg_add_size_overflow(len, bslash_len + 3, &len)) /* octal "\ooo" */ goto overflow; } else if (*vp == '\'') { - if (add_size_overflow(len, 2, &len)) /* double each quote */ + if (pg_add_size_overflow(len, 2, &len)) /* double each quote */ goto overflow; } else if (*vp == '\\') { - if (add_size_overflow(len, bslash_len * 2, &len)) /* double each backslash */ + if (pg_add_size_overflow(len, bslash_len * 2, &len)) /* double each backslash */ goto overflow; } else { - if (add_size_overflow(len, 1, &len)) + if (pg_add_size_overflow(len, 1, &len)) goto overflow; } } diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c index a6de13447a6..377f8270a4e 100644 --- a/src/interfaces/libpq/fe-lobj.c +++ b/src/interfaces/libpq/fe-lobj.c @@ -271,8 +271,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len) argv[1].len = 4; argv[1].u.integer = (int) len; - res = PQfn(conn, conn->lobjfuncs->fn_lo_read, - (void *) buf, &result_len, 0, argv, 2); + res = PQnfn(conn, conn->lobjfuncs->fn_lo_read, + (void *) buf, len, &result_len, 0, argv, 2); if (PQresultStatus(res) == PGRES_COMMAND_OK) { PQclear(res); @@ -412,8 +412,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence) argv[2].len = 4; argv[2].u.integer = whence; - res = PQfn(conn, conn->lobjfuncs->fn_lo_lseek64, - (void *) &retval, &result_len, 0, argv, 3); + res = PQnfn(conn, conn->lobjfuncs->fn_lo_lseek64, + (void *) &retval, sizeof(retval), &result_len, 0, argv, 3); if (PQresultStatus(res) == PGRES_COMMAND_OK && result_len == 8) { PQclear(res); @@ -566,8 +566,8 @@ lo_tell64(PGconn *conn, int fd) argv[0].len = 4; argv[0].u.integer = fd; - res = PQfn(conn, conn->lobjfuncs->fn_lo_tell64, - (void *) &retval, &result_len, 0, argv, 1); + res = PQnfn(conn, conn->lobjfuncs->fn_lo_tell64, + (void *) &retval, sizeof(retval), &result_len, 0, argv, 1); if (PQresultStatus(res) == PGRES_COMMAND_OK && result_len == 8) { PQclear(res); diff --git a/src/interfaces/libpq/fe-print.c b/src/interfaces/libpq/fe-print.c index 0d889b2f4c0..107c1eec69d 100644 --- a/src/interfaces/libpq/fe-print.c +++ b/src/interfaces/libpq/fe-print.c @@ -33,6 +33,7 @@ #endif #endif +#include "common/int.h" #include "libpq-fe.h" #include "libpq-int.h" @@ -451,27 +452,6 @@ do_field(const PQprintOpt *po, const PGresult *res, } -/* - * Frontend version of the backend's add_size(), intended to be API-compatible - * with the pg_add_*_overflow() helpers. Stores the result into *dst on success. - * Returns true instead if the addition overflows. - * - * TODO: move to common/int.h - */ -static bool -add_size_overflow(size_t s1, size_t s2, size_t *dst) -{ - size_t result; - - result = s1 + s2; - if (result < s1 || result < s2) - return true; - - *dst = result; - return false; -} - - static char * do_header(FILE *fout, const PQprintOpt *po, const int nFields, int *fieldMax, const char **fieldNames, unsigned char *fieldNotNum, @@ -492,20 +472,20 @@ do_header(FILE *fout, const PQprintOpt *po, const int nFields, int *fieldMax, for (; n < nFields; n++) { /* Field plus separator, plus 2 extra '-' in standard format. */ - if (add_size_overflow(tot, fieldMax[n], &tot) || - add_size_overflow(tot, fs_len, &tot) || - (po->standard && add_size_overflow(tot, 2, &tot))) + if (pg_add_size_overflow(tot, fieldMax[n], &tot) || + pg_add_size_overflow(tot, fs_len, &tot) || + (po->standard && pg_add_size_overflow(tot, 2, &tot))) goto overflow; } if (po->standard) { /* An extra separator at the front and back. */ - if (add_size_overflow(tot, fs_len, &tot) || - add_size_overflow(tot, fs_len, &tot) || - add_size_overflow(tot, 2, &tot)) + if (pg_add_size_overflow(tot, fs_len, &tot) || + pg_add_size_overflow(tot, fs_len, &tot) || + pg_add_size_overflow(tot, 2, &tot)) goto overflow; } - if (add_size_overflow(tot, 1, &tot)) /* terminator */ + if (pg_add_size_overflow(tot, 1, &tot)) /* terminator */ goto overflow; border = malloc(tot); diff --git a/src/interfaces/libpq/fe-protocol3.c b/src/interfaces/libpq/fe-protocol3.c index 38d01cbc024..45b80455b0f 100644 --- a/src/interfaces/libpq/fe-protocol3.c +++ b/src/interfaces/libpq/fe-protocol3.c @@ -25,6 +25,7 @@ #include #endif +#include "common/int.h" #include "libpq-fe.h" #include "libpq-int.h" #include "mb/pg_wchar.h" @@ -2154,7 +2155,7 @@ pqEndcopy3(PGconn *conn) */ PGresult * pqFunctionCall3(PGconn *conn, Oid fnid, - int *result_buf, int *actual_result_len, + int *result_buf, int buf_size, int *actual_result_len, int result_is_int, const PQArgBlock *args, int nargs) { @@ -2288,6 +2289,17 @@ pqFunctionCall3(PGconn *conn, Oid fnid, } else { + /* + * If the server returned too much data for the + * buffer, something fishy is going on. Abandon ship. + */ + if (buf_size != -1 && *actual_result_len > buf_size) + { + libpq_append_conn_error(conn, "server returned too much data"); + handleFatalError(conn); + return pqPrepareAsyncResult(conn); + } + if (pqGetnchar(result_buf, *actual_result_len, conn)) @@ -2404,26 +2416,6 @@ pqBuildStartupPacket3(PGconn *conn, int *packetlen, return startpacket; } -/* - * Frontend version of the backend's add_size(), intended to be API-compatible - * with the pg_add_*_overflow() helpers. Stores the result into *dst on success. - * Returns true instead if the addition overflows. - * - * TODO: move to common/int.h - */ -static bool -add_size_overflow(size_t s1, size_t s2, size_t *dst) -{ - size_t result; - - result = s1 + s2; - if (result < s1 || result < s2) - return true; - - *dst = result; - return false; -} - /* * Build a startup packet given a filled-in PGconn structure. * @@ -2456,11 +2448,11 @@ build_startup_packet(const PGconn *conn, char *packet, do { \ if (packet) \ strcpy(packet + packet_len, optname); \ - if (add_size_overflow(packet_len, strlen(optname) + 1, &packet_len)) \ + if (pg_add_size_overflow(packet_len, strlen(optname) + 1, &packet_len)) \ return 0; \ if (packet) \ strcpy(packet + packet_len, optval); \ - if (add_size_overflow(packet_len, strlen(optval) + 1, &packet_len)) \ + if (pg_add_size_overflow(packet_len, strlen(optval) + 1, &packet_len)) \ return 0; \ } while(0) @@ -2496,7 +2488,7 @@ build_startup_packet(const PGconn *conn, char *packet, /* Add trailing terminator */ if (packet) packet[packet_len] = '\0'; - if (add_size_overflow(packet_len, 1, &packet_len)) + if (pg_add_size_overflow(packet_len, 1, &packet_len)) return 0; return packet_len; diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h index 8f2cd764542..c969e137825 100644 --- a/src/interfaces/libpq/libpq-int.h +++ b/src/interfaces/libpq/libpq-int.h @@ -762,6 +762,9 @@ extern int pqRowProcessor(PGconn *conn, const char **errmsgp); extern void pqCommandQueueAdvance(PGconn *conn, bool isReadyForQuery, bool gotSync); extern int PQsendQueryContinue(PGconn *conn, const char *query); +extern PGresult *PQnfn(PGconn *conn, int fnid, int *result_buf, int buf_size, + int *result_len, int result_is_int, + const PQArgBlock *args, int nargs); /* === in fe-protocol3.c === */ @@ -777,7 +780,8 @@ extern int pqGetline3(PGconn *conn, char *s, int maxlen); extern int pqGetlineAsync3(PGconn *conn, char *buffer, int bufsize); extern int pqEndcopy3(PGconn *conn); extern PGresult *pqFunctionCall3(PGconn *conn, Oid fnid, - int *result_buf, int *actual_result_len, + int *result_buf, int buf_size, + int *actual_result_len, int result_is_int, const PQArgBlock *args, int nargs); diff --git a/src/interfaces/libpq/po/fr.po b/src/interfaces/libpq/po/fr.po index 825184fe3cd..528459ab88d 100644 --- a/src/interfaces/libpq/po/fr.po +++ b/src/interfaces/libpq/po/fr.po @@ -12,8 +12,8 @@ msgid "" msgstr "" "Project-Id-Version: PostgreSQL 17\n" "Report-Msgid-Bugs-To: pgsql-bugs@lists.postgresql.org\n" -"POT-Creation-Date: 2026-02-18 04:40+0000\n" -"PO-Revision-Date: 2026-02-18 14:28+0100\n" +"POT-Creation-Date: 2026-05-08 20:10+0000\n" +"PO-Revision-Date: 2026-05-10 17:11+0200\n" "Last-Translator: Guillaume Lelarge \n" "Language-Team: French \n" "Language: fr\n" @@ -21,7 +21,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" -"X-Generator: Poedit 3.8\n" +"X-Generator: Poedit 3.9\n" #: ../libpq-oauth/oauth-curl.c:308 ../libpq-oauth/oauth-curl.c:2011 #, c-format @@ -45,28 +45,24 @@ msgstr "échec lors de la réception de %s à partir de la réponse OAuth : %s" #: ../libpq-oauth/oauth-curl.c:485 fe-auth-oauth.c:209 fe-auth-oauth.c:271 #: fe-auth-oauth.c:333 -#, fuzzy, c-format -#| msgid "field \"%s\" is missing" +#, c-format msgid "field \"%s\" must be a string" -msgstr "le champ « %s » est manquant" +msgstr "le champ « %s » doit être une chaîne de caractères" #: ../libpq-oauth/oauth-curl.c:489 -#, fuzzy, c-format -#| msgid "\"%s\" is not a number" +#, c-format msgid "field \"%s\" must be a number" -msgstr "« %s » n'est pas un nombre" +msgstr "le champ « %s » doit être un nombre" #: ../libpq-oauth/oauth-curl.c:493 -#, fuzzy, c-format -#| msgid "argument of %s must be an array of objects" +#, c-format msgid "field \"%s\" must be an array of strings" -msgstr "l'argument de %s doit être un tableau d'objets" +msgstr "le champ « %s » doit être un tableau de chaînes" #: ../libpq-oauth/oauth-curl.c:498 -#, fuzzy, c-format -#| msgid "field \"%s\" is duplicated" +#, c-format msgid "field \"%s\" has unexpected type" -msgstr "le champ « %s » est dupliqué" +msgstr "le champ « %s » a un type inattendu" #: ../libpq-oauth/oauth-curl.c:522 ../libpq-oauth/oauth-curl.c:632 #: fe-auth-oauth.c:215 fe-auth-oauth.c:277 @@ -111,10 +107,8 @@ msgid "field \"%s\" is missing" msgstr "le champ « %s » est manquant" #: ../libpq-oauth/oauth-curl.c:1097 -#, fuzzy -#| msgid "failed to send SSL negotiation response: %m" msgid "failed to parse token error response" -msgstr "échec lors de l'envoi de la réponse de négociation SSL : %m" +msgstr "a échoué à analyser la répondu en erreur du jeton" #: ../libpq-oauth/oauth-curl.c:1125 #, c-format @@ -122,10 +116,9 @@ msgid "provider rejected the oauth_client_secret" msgstr "le fournisseur a rejeté oauth_client_secret" #: ../libpq-oauth/oauth-curl.c:1126 -#, fuzzy, c-format -#| msgid "provider rejected the oauth_client_secret" +#, c-format msgid "provider requires client authentication, and no oauth_client_secret is set" -msgstr "le fournisseur a rejeté oauth_client_secret" +msgstr "le fournisseur requiert l'authentification du client, et aucun oauth_client_secret n'est configuré" #: ../libpq-oauth/oauth-curl.c:1559 #, c-format @@ -199,7 +192,7 @@ msgstr "code de réponse inattendu %ld" #: ../libpq-oauth/oauth-curl.c:2162 msgid "failed to parse OpenID discovery document" -msgstr "" +msgstr "échec lors de l'analyse du document découverte OpenID" #: ../libpq-oauth/oauth-curl.c:2227 #, c-format @@ -222,16 +215,12 @@ msgid "token endpoint \"%s\" must use HTTPS" msgstr "le endpoint « %s » du jeton doit utiliser HTTPS" #: ../libpq-oauth/oauth-curl.c:2430 -#, fuzzy -#| msgid "permission denied to set session authorization" msgid "failed to parse device authorization" -msgstr "droit refusé pour initialiser une autorisation de session" +msgstr "a échoué à analyser l'autorisation du périphérique" #: ../libpq-oauth/oauth-curl.c:2518 -#, fuzzy -#| msgid "failed to send SSL negotiation response: %m" msgid "failed to parse access token response" -msgstr "échec lors de l'envoi de la réponse de négociation SSL : %m" +msgstr "a échoué à analyser la réponse du jeton" #: ../libpq-oauth/oauth-curl.c:2598 #, c-format @@ -277,166 +266,149 @@ msgstr "" #: ../libpq-oauth/oauth-curl.c:2897 msgid "failed to fetch OpenID discovery document" -msgstr "" +msgstr "échec de la récupération du document découverte OpenID" #: ../libpq-oauth/oauth-curl.c:2911 -#, fuzzy -#| msgid "%s cannot run inside a subtransaction" msgid "cannot run OAuth device authorization" -msgstr "%s ne peut pas être exécuté dans une sous-transaction" +msgstr "ne peut pas exécuter l'autorisation du périphérique OAuth" #: ../libpq-oauth/oauth-curl.c:2915 -#, fuzzy -#| msgid "permission denied to set session authorization" msgid "failed to obtain device authorization" -msgstr "droit refusé pour initialiser une autorisation de session" +msgstr "a échoué à obtenir l'autorisation du périphérique" #: ../libpq-oauth/oauth-curl.c:2926 ../libpq-oauth/oauth-curl.c:2977 msgid "failed to obtain access token" -msgstr "" +msgstr "échec lors de l'obtention du jeton d'accès" #: fe-auth-oauth.c:133 -#, fuzzy, c-format -#| msgid "internal error: async authentication has no handler" +#, c-format msgid "internal error: no OAuth token was set for the connection" -msgstr "erreur interne : async authentication n'a pas de gestionnaire" +msgstr "erreur interne : aucun jeton OAuth n'était configuré pour la connexion" #: fe-auth-oauth.c:396 -#, fuzzy, c-format -#| msgid "token endpoint \"%s\" must use HTTPS" +#, c-format msgid "OAuth discovery URI \"%s\" must use HTTPS" -msgstr "le endpoint « %s » du jeton doit utiliser HTTPS" +msgstr "l'URI de découverte d'OAuth « %s » doit utiliser HTTPS" #: fe-auth-oauth.c:413 #, c-format msgid "OAuth discovery URI \"%s\" must not contain query or fragment components" -msgstr "" +msgstr "L'URI de découverte OAuth « %s » ne doit pas contenir des composants requête ou fragment" #: fe-auth-oauth.c:428 #, c-format msgid "OAuth discovery URI \"%s\" is not a .well-known URI" -msgstr "" +msgstr "L'URI de découverte OAuth « %s » n'est pas une URI .well-known" #: fe-auth-oauth.c:454 #, c-format msgid "OAuth discovery URI \"%s\" uses an unsupported .well-known suffix" -msgstr "" +msgstr "L'URI de découverte OAuth « %s » utilisé un suffixe .well-known non supporté" #: fe-auth-oauth.c:479 #, c-format msgid "OAuth discovery URI \"%s\" uses an invalid format" -msgstr "" +msgstr "L'URI de découverte OAuth « %s » utilise un format invalide" #: fe-auth-oauth.c:528 #, c-format msgid "server's error message contained an embedded NULL, and was discarded" -msgstr "" +msgstr "le message d'erreur du serveur contenait un NULL embarqué, et a été annulé" #: fe-auth-oauth.c:539 -#, fuzzy, c-format -#| msgid "response is not valid UTF-8" +#, c-format msgid "server's error response is not valid UTF-8" -msgstr "la réponse n'est pas de l'UTF-8 valide" +msgstr "la réponse en erreur du serveur n'est pas de l'UTF-8 valide" #: fe-auth-oauth.c:579 -#, fuzzy, c-format -#| msgid "failed to get %s from OAuth response: %s" +#, c-format msgid "failed to parse server's error response: %s" -msgstr "échec lors de la réception de %s à partir de la réponse OAuth : %s" +msgstr "a échoué à analyser la réponse du serveur : %s" #: fe-auth-oauth.c:610 -#, fuzzy, c-format -#| msgid "the issuer identifier (%s) does not match oauth_issuer (%s)" +#, c-format msgid "server's discovery document at %s (issuer \"%s\") is incompatible with oauth_issuer (%s)" -msgstr "l'identifiant du demandeur (%s) ne correspond pas à oauth_issuer (« %s »)" +msgstr "le document de découverte du serveur à %s (émetteur « %s ») est incompatible avec oauth_issuer (%s)" #: fe-auth-oauth.c:631 #, c-format msgid "server's discovery document has moved to %s (previous location was %s)" -msgstr "" +msgstr "le document de découverte du serveur a été déplacé dans %s (l'emplacement précédent était %s)" #: fe-auth-oauth.c:652 -#, fuzzy, c-format -#| msgid "server sent an error response during SSL exchange" +#, c-format msgid "server sent error response without a status" -msgstr "le serveur a envoyé une erreur lors de l'échange SSL" +msgstr "le serveur a répondu avec une erreur sans statut" #: fe-auth-oauth.c:663 -#, fuzzy, c-format -#| msgid "server requested SASL authentication" +#, c-format msgid "server rejected OAuth bearer token: %s" -msgstr "le serveur a demandé l'authentification SASL" +msgstr "le serveur a rejeté le jeton porteur OAuth : %s" #: fe-auth-oauth.c:696 #, c-format msgid "user-defined OAuth flow provided neither a token nor an async callback" -msgstr "" +msgstr "le flux OAuth défini par l'utilisateur n'a fourni ni un jeton ni un appel fonction asynchrone" #: fe-auth-oauth.c:703 fe-auth-oauth.c:1041 -#, fuzzy, c-format -#| msgid "reading user-defined operator families" +#, c-format msgid "user-defined OAuth flow failed" -msgstr "lecture des familles d'opérateurs utilisateur" +msgstr "échec du flux OAuth défini par l'utilisateur" #: fe-auth-oauth.c:716 #, c-format msgid "user-defined OAuth flow did not provide a token" -msgstr "" +msgstr "le flux OAuth défini par l'utilisateur n'a pas fourni de jeton" #: fe-auth-oauth.c:734 -#, fuzzy, c-format -#| msgid "internal error: async authentication did not set a socket for polling" +#, c-format msgid "user-defined OAuth flow did not provide a socket for polling" -msgstr "erreur interne : une authentification asynchrone n'a pas configuré une socket pour le polling" +msgstr "le flux OAuth défini par l'utilisateur n'a pas fourni de socket pour l'interrogation" #: fe-auth-oauth.c:917 -#, fuzzy, c-format -#| msgid "failed to create kqueue: %m" +#, c-format msgid "failed to lock mutex (%d)" -msgstr "a échoué à créer kqueue : %m" +msgstr "a échoué à verrouiller le mutex (%d)" #: fe-auth-oauth.c:1046 #, c-format msgid "no OAuth flows are available (try installing the libpq-oauth package)" -msgstr "" +msgstr "aucun flux OAuth n'est disponible (essayez d'installer le paquet libpq-oauth)" #: fe-auth-oauth.c:1095 #, c-format msgid "server requires OAuth authentication, but oauth_issuer and oauth_client_id are not both set" -msgstr "" +msgstr "le serveur requiert une authentification OAuth mais oauth_issuer et oauth_client_id ne sont pas configurés" #: fe-auth-oauth.c:1255 #, c-format msgid "server sent unexpected additional OAuth data" -msgstr "" +msgstr "le serveur a envoyé des données OAuth supplémentaires inattendues" #: fe-auth-oauth.c:1295 #, c-format msgid "server requires OAuth authentication, but no discovery metadata was provided" -msgstr "" +msgstr "le serveur réclame une authentification OAuth mais aucune métadonnée de découverte n'a été fournie" #: fe-auth-oauth.c:1333 -#, fuzzy, c-format -#| msgid "internal error: async authentication did not set a socket for polling" +#, c-format msgid "internal error: OAuth flow did not set a token" -msgstr "erreur interne : une authentification asynchrone n'a pas configuré une socket pour le polling" +msgstr "erreur interne : le flux OAuth n'a pas configuré un jeton" #: fe-auth-oauth.c:1351 #, c-format msgid "server sent additional OAuth data after error" -msgstr "" +msgstr "le serveur a envoyé des données OAuth supplémentaire après l'erreur" #: fe-auth-oauth.c:1355 -#, fuzzy, c-format -#| msgid "invalid SCRAM exchange state" +#, c-format msgid "invalid OAuth exchange state" -msgstr "état d'échange SCRAM invalide" +msgstr "état d'échange OAuth invalide" #: fe-auth-oauth.c:1368 -#, fuzzy, c-format -#| msgid "no connection to the server" +#, c-format msgid "retrying connection with new bearer token" -msgstr "aucune connexion au serveur" +msgstr "nouvelle tentative de connexion avec un nouveau jeton porteur" #: fe-auth-scram.c:228 #, c-format @@ -603,7 +575,7 @@ msgstr "la demande de la méthode d'authentification « %s » a échoué : le se #: fe-auth.c:580 #, c-format msgid "channel binding is required, but server did not offer an authentication method that supports channel binding" -msgstr "Lien de canal requis, mais le serveur ne propose pas de méthode d'authentification le supportant" +msgstr "lien de canal requis, mais le serveur ne propose pas de méthode d'authentification le supportant" #: fe-auth.c:716 #, c-format @@ -701,7 +673,7 @@ msgstr "authentification SSPI non supportée" #: fe-auth.c:1193 #, c-format msgid "Crypt authentication not supported" -msgstr "authentification crypt non supportée" +msgstr "Authentification crypt non supportée" #: fe-auth.c:1267 #, c-format diff --git a/src/oracle_test/isolation/expected/insert-conflict-do-update-4.out b/src/oracle_test/isolation/expected/insert-conflict-do-update-4.out index 6e96e0d12da..80af2798a94 100644 --- a/src/oracle_test/isolation/expected/insert-conflict-do-update-4.out +++ b/src/oracle_test/isolation/expected/insert-conflict-do-update-4.out @@ -12,11 +12,11 @@ step insert1: INSERT INTO upsert VALUES (1, 11, 111) step update2a: UPDATE upsert SET i = i + 10 WHERE i = 1; step c2: COMMIT; step insert1: <... completed> -step select1: SELECT * FROM upsert; +step select1: SELECT * FROM upsert ORDER BY i; i| j| k --+--+--- -11|10|100 1|11|111 +11|10|100 (2 rows) step c1: COMMIT; @@ -33,7 +33,7 @@ step insert1: INSERT INTO upsert VALUES (1, 11, 111) step update2b: UPDATE upsert SET i = i + 150 WHERE i = 1; step c2: COMMIT; step insert1: <... completed> -step select1: SELECT * FROM upsert; +step select1: SELECT * FROM upsert ORDER BY i; i| j| k ---+--+--- 1|11|111 @@ -54,7 +54,7 @@ step insert1: INSERT INTO upsert VALUES (1, 11, 111) step delete2: DELETE FROM upsert WHERE i = 1; step c2: COMMIT; step insert1: <... completed> -step select1: SELECT * FROM upsert; +step select1: SELECT * FROM upsert ORDER BY i; i| j| k -+--+--- 1|11|111 diff --git a/src/oracle_test/isolation/expected/merge-update.out b/src/oracle_test/isolation/expected/merge-update.out index 8f3d5d3a700..b8c28e3656e 100755 --- a/src/oracle_test/isolation/expected/merge-update.out +++ b/src/oracle_test/isolation/expected/merge-update.out @@ -457,3 +457,36 @@ key|val (2 rows) step c2: COMMIT; + +starting permutation: merge2a c1 s1beginrr merge1 c2 +step merge2a: + MERGE INTO target t + USING (SELECT 1 as key, 'merge2a' as val) s + ON s.key = t.key + WHEN NOT MATCHED THEN + INSERT VALUES (s.key, s.val) + WHEN MATCHED THEN + UPDATE set key = t.key + 1, val = t.val || ' updated by ' || s.val + WHEN NOT MATCHED BY SOURCE THEN + UPDATE set key = t.key + 1, val = t.val || ' source not matched by merge2a' + RETURNING merge_action(), old, new, t.*; + +merge_action|old |new |key|val +------------+----------+-------------------------------+---+------------------------- +UPDATE |(1,setup1)|(2,"setup1 updated by merge2a")| 2|setup1 updated by merge2a +(1 row) + +step c1: COMMIT; +step s1beginrr: BEGIN ISOLATION LEVEL REPEATABLE READ; +step merge1: + MERGE INTO target t + USING (SELECT 1 as key, 'merge1' as val) s + ON s.key = t.key + WHEN NOT MATCHED THEN + INSERT VALUES (s.key, s.val) + WHEN MATCHED THEN + UPDATE set key = t.key + 1, val = t.val || ' updated by ' || s.val; + +step c2: COMMIT; +step merge1: <... completed> +ERROR: could not serialize access due to concurrent update diff --git a/src/oracle_test/isolation/specs/insert-conflict-do-update-4.spec b/src/oracle_test/isolation/specs/insert-conflict-do-update-4.spec index 6297b1d1d6c..a62531660d3 100644 --- a/src/oracle_test/isolation/specs/insert-conflict-do-update-4.spec +++ b/src/oracle_test/isolation/specs/insert-conflict-do-update-4.spec @@ -23,7 +23,7 @@ session s1 setup { BEGIN ISOLATION LEVEL READ COMMITTED; } step insert1 { INSERT INTO upsert VALUES (1, 11, 111) ON CONFLICT (i) DO UPDATE SET k = EXCLUDED.k; } -step select1 { SELECT * FROM upsert; } +step select1 { SELECT * FROM upsert ORDER BY i; } step c1 { COMMIT; } session s2 diff --git a/src/oracle_test/modules/Makefile b/src/oracle_test/modules/Makefile index 2ba65f0fde0..9fd752635d4 100644 --- a/src/oracle_test/modules/Makefile +++ b/src/oracle_test/modules/Makefile @@ -20,6 +20,7 @@ SUBDIRS = \ test_cloexec \ test_copy_callbacks \ test_custom_rmgrs \ + test_custom_types \ test_ddl_deparse \ test_dsa \ test_dsm_registry \ diff --git a/src/oracle_test/modules/injection_points/injection_stats_fixed.c b/src/oracle_test/modules/injection_points/injection_stats_fixed.c index 09cd5f5a154..1eb71c25eb0 100644 --- a/src/oracle_test/modules/injection_points/injection_stats_fixed.c +++ b/src/oracle_test/modules/injection_points/injection_stats_fixed.c @@ -52,7 +52,7 @@ static const PgStat_KindInfo injection_stats_fixed = { .fixed_amount = true, .write_to_file = true, - .shared_size = sizeof(PgStat_StatInjFixedEntry), + .shared_size = sizeof(PgStatShared_InjectionPointFixed), .shared_data_off = offsetof(PgStatShared_InjectionPointFixed, stats), .shared_data_len = sizeof(((PgStatShared_InjectionPointFixed *) 0)->stats), diff --git a/src/oracle_test/modules/meson.build b/src/oracle_test/modules/meson.build index 9cdc0666ffb..9a957351ab6 100644 --- a/src/oracle_test/modules/meson.build +++ b/src/oracle_test/modules/meson.build @@ -18,6 +18,7 @@ subdir('test_bloomfilter') subdir('test_cloexec') subdir('test_copy_callbacks') subdir('test_custom_rmgrs') +subdir('test_custom_types') subdir('test_ddl_deparse') subdir('test_dsa') subdir('test_dsm_registry') diff --git a/src/oracle_test/modules/test_custom_types/.gitignore b/src/oracle_test/modules/test_custom_types/.gitignore new file mode 100644 index 00000000000..5dcb3ff9723 --- /dev/null +++ b/src/oracle_test/modules/test_custom_types/.gitignore @@ -0,0 +1,4 @@ +# Generated subdirectories +/log/ +/results/ +/tmp_check/ diff --git a/src/oracle_test/modules/test_custom_types/Makefile b/src/oracle_test/modules/test_custom_types/Makefile new file mode 100644 index 00000000000..9f8e31c7c91 --- /dev/null +++ b/src/oracle_test/modules/test_custom_types/Makefile @@ -0,0 +1,20 @@ +# src/oracle_test/modules/test_custom_types/Makefile + +MODULES = test_custom_types + +EXTENSION = test_custom_types +DATA = test_custom_types--1.0.sql +PGFILEDESC = "test_custom_types - tests for dummy custom types" + +REGRESS = test_custom_types + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = src/oracle_test/modules/test_custom_types +top_builddir = ../../../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/src/oracle_test/modules/test_custom_types/README b/src/oracle_test/modules/test_custom_types/README new file mode 100644 index 00000000000..a37d2db577e --- /dev/null +++ b/src/oracle_test/modules/test_custom_types/README @@ -0,0 +1,9 @@ +test_custom_types +================= + +This module contains a set of custom data types, with some of the following +patterns: + +- typanalyze function registered to a custom type, returning false. +- typanalyze function registered to a custom type, registering invalid stats + data. diff --git a/src/oracle_test/modules/test_custom_types/expected/test_custom_types.out b/src/oracle_test/modules/test_custom_types/expected/test_custom_types.out new file mode 100644 index 00000000000..2fb6b0b10ee --- /dev/null +++ b/src/oracle_test/modules/test_custom_types/expected/test_custom_types.out @@ -0,0 +1,174 @@ +-- Tests with various custom types +CREATE EXTENSION test_custom_types; +-- Test comparison functions +SELECT '42'::int_custom = '42'::int_custom AS eq_test; + eq_test +--------- + t +(1 row) + +SELECT '42'::int_custom <> '42'::int_custom AS nt_test; + nt_test +--------- + f +(1 row) + +SELECT '42'::int_custom < '100'::int_custom AS lt_test; + lt_test +--------- + t +(1 row) + +SELECT '100'::int_custom > '42'::int_custom AS gt_test; + gt_test +--------- + t +(1 row) + +SELECT '42'::int_custom <= '100'::int_custom AS le_test; + le_test +--------- + t +(1 row) + +SELECT '100'::int_custom >= '42'::int_custom AS ge_test; + ge_test +--------- + t +(1 row) + +-- Create a table with the int_custom type +CREATE TABLE test_table ( + id int, + data int_custom +); +INSERT INTO test_table VALUES (1, '42'), (2, '100'), (3, '200'); +-- Verify data was inserted correctly +SELECT * FROM test_table ORDER BY id; + id | data +----+------ + 1 | 42 + 2 | 100 + 3 | 200 +(3 rows) + +-- Dummy function used for expression evaluations. +-- Note that this function does not use a SQL-standard function body on +-- purpose, so as external statistics can be loaded from it. +CREATE OR REPLACE FUNCTION func_int_custom (p_value int_custom) + RETURNS int_custom LANGUAGE plpgsql AS $$ + BEGIN + RETURN p_value; + END; $$; +-- Switch type to use typanalyze function that always returns false. +ALTER TYPE int_custom SET (ANALYZE = int_custom_typanalyze_false); +-- Extended statistics with an attribute that cannot be analyzed. +-- This includes all statistics kinds. +CREATE STATISTICS test_stats ON data, id FROM test_table; +-- Computation of the stats fails, no data generated. +ANALYZE test_table; +WARNING: statistics object "public.test_stats" could not be computed for relation "public.test_table" +SELECT stxname, stxdexpr IS NULL as expr_stats_is_null + FROM pg_statistic_ext s + LEFT JOIN pg_statistic_ext_data d ON s.oid = d.stxoid + WHERE stxname = 'test_stats'; + stxname | expr_stats_is_null +------------+-------------------- + test_stats | t +(1 row) + +DROP STATISTICS test_stats; +-- Extended statistics with an expression that cannot be analyzed. +CREATE STATISTICS test_stats ON func_int_custom(data), (id) FROM test_table; +-- Computation of the stats fails, no data generated. +ANALYZE test_table; +WARNING: statistics object "public.test_stats" could not be computed for relation "public.test_table" +SELECT stxname, stxdexpr IS NULL as expr_stats_is_null + FROM pg_statistic_ext s + LEFT JOIN pg_statistic_ext_data d ON s.oid = d.stxoid + WHERE stxname = 'test_stats'; + stxname | expr_stats_is_null +------------+-------------------- + test_stats | t +(1 row) + +DROP STATISTICS test_stats; +-- There should be no data stored for the expression. +SELECT tablename, + statistics_name, + null_frac, + avg_width + FROM pg_stats_ext_exprs WHERE statistics_name = 'test_stats' \gx +(0 rows) + +-- Switch type to use typanalyze function that generates invalid data. +ALTER TYPE int_custom SET (ANALYZE = int_custom_typanalyze_invalid); +-- Extended statistics with an attribute that generates invalid stats. +CREATE STATISTICS test_stats ON data, id FROM test_table; +-- Computation of the stats fails, no data generated. +ANALYZE test_table; +SELECT stxname, stxdexpr IS NULL as expr_stats_is_null + FROM pg_statistic_ext s + LEFT JOIN pg_statistic_ext_data d ON s.oid = d.stxoid + WHERE stxname = 'test_stats'; + stxname | expr_stats_is_null +------------+-------------------- + test_stats | t +(1 row) + +DROP STATISTICS test_stats; +-- Extended statistics with an expression that generates invalid data. +CREATE STATISTICS test_stats ON func_int_custom(data), (id) FROM test_table; +-- Computation of the stats fails, some data generated. +ANALYZE test_table; +SELECT stxname, stxdexpr IS NULL as expr_stats_is_null + FROM pg_statistic_ext s + LEFT JOIN pg_statistic_ext_data d ON s.oid = d.stxoid + WHERE stxname = 'test_stats'; + stxname | expr_stats_is_null +------------+-------------------- + test_stats | f +(1 row) + +-- There should be some data stored for the expression, stored as NULL. +SELECT tablename, + statistics_name, + null_frac, + avg_width, + n_distinct, + most_common_vals, + most_common_freqs, + histogram_bounds, + correlation, + most_common_elems, + most_common_elem_freqs, + elem_count_histogram + FROM pg_stats_ext_exprs WHERE statistics_name = 'test_stats' \gx +-[ RECORD 1 ]----------+----------- +tablename | test_table +statistics_name | test_stats +null_frac | +avg_width | +n_distinct | +most_common_vals | +most_common_freqs | +histogram_bounds | +correlation | +most_common_elems | +most_common_elem_freqs | +elem_count_histogram | + +-- Run a query able to load the extended stats, including the NULL data. +SELECT COUNT(*) FROM test_table GROUP BY (func_int_custom(data)); + count +------- + 1 + 1 + 1 +(3 rows) + +DROP STATISTICS test_stats; +-- Cleanup +DROP FUNCTION func_int_custom; +DROP TABLE test_table; +DROP EXTENSION test_custom_types; diff --git a/src/oracle_test/modules/test_custom_types/meson.build b/src/oracle_test/modules/test_custom_types/meson.build new file mode 100644 index 00000000000..3d4f433dd51 --- /dev/null +++ b/src/oracle_test/modules/test_custom_types/meson.build @@ -0,0 +1,33 @@ +# Copyright (c) 2026, PostgreSQL Global Development Group + +test_custom_types_sources = files( + 'test_custom_types.c', +) + +if host_system == 'windows' + test_custom_types_sources += rc_lib_gen.process(win32ver_rc, extra_args: [ + '--NAME', 'test_custom_types', + '--FILEDESC', 'test_custom_types - tests for dummy custom types',]) +endif + +test_custom_types = shared_module('test_custom_types', + test_custom_types_sources, + kwargs: pg_test_mod_args, +) +test_install_libs += test_custom_types + +test_install_data += files( + 'test_custom_types.control', + 'test_custom_types--1.0.sql', +) + +tests += { + 'name': 'test_custom_types', + 'sd': meson.current_source_dir(), + 'bd': meson.current_build_dir(), + 'regress': { + 'sql': [ + 'test_custom_types', + ], + }, +} diff --git a/src/oracle_test/modules/test_custom_types/sql/test_custom_types.sql b/src/oracle_test/modules/test_custom_types/sql/test_custom_types.sql new file mode 100644 index 00000000000..68cdf8718a5 --- /dev/null +++ b/src/oracle_test/modules/test_custom_types/sql/test_custom_types.sql @@ -0,0 +1,105 @@ +-- Tests with various custom types + +CREATE EXTENSION test_custom_types; + +-- Test comparison functions +SELECT '42'::int_custom = '42'::int_custom AS eq_test; +SELECT '42'::int_custom <> '42'::int_custom AS nt_test; +SELECT '42'::int_custom < '100'::int_custom AS lt_test; +SELECT '100'::int_custom > '42'::int_custom AS gt_test; +SELECT '42'::int_custom <= '100'::int_custom AS le_test; +SELECT '100'::int_custom >= '42'::int_custom AS ge_test; + +-- Create a table with the int_custom type +CREATE TABLE test_table ( + id int, + data int_custom +); +INSERT INTO test_table VALUES (1, '42'), (2, '100'), (3, '200'); + +-- Verify data was inserted correctly +SELECT * FROM test_table ORDER BY id; + +-- Dummy function used for expression evaluations. +-- Note that this function does not use a SQL-standard function body on +-- purpose, so as external statistics can be loaded from it. +CREATE OR REPLACE FUNCTION func_int_custom (p_value int_custom) + RETURNS int_custom LANGUAGE plpgsql AS $$ + BEGIN + RETURN p_value; + END; $$; +/ + +-- Switch type to use typanalyze function that always returns false. +ALTER TYPE int_custom SET (ANALYZE = int_custom_typanalyze_false); + +-- Extended statistics with an attribute that cannot be analyzed. +-- This includes all statistics kinds. +CREATE STATISTICS test_stats ON data, id FROM test_table; +-- Computation of the stats fails, no data generated. +ANALYZE test_table; +SELECT stxname, stxdexpr IS NULL as expr_stats_is_null + FROM pg_statistic_ext s + LEFT JOIN pg_statistic_ext_data d ON s.oid = d.stxoid + WHERE stxname = 'test_stats'; +DROP STATISTICS test_stats; + +-- Extended statistics with an expression that cannot be analyzed. +CREATE STATISTICS test_stats ON func_int_custom(data), (id) FROM test_table; +-- Computation of the stats fails, no data generated. +ANALYZE test_table; +SELECT stxname, stxdexpr IS NULL as expr_stats_is_null + FROM pg_statistic_ext s + LEFT JOIN pg_statistic_ext_data d ON s.oid = d.stxoid + WHERE stxname = 'test_stats'; +DROP STATISTICS test_stats; +-- There should be no data stored for the expression. +SELECT tablename, + statistics_name, + null_frac, + avg_width + FROM pg_stats_ext_exprs WHERE statistics_name = 'test_stats' \gx + +-- Switch type to use typanalyze function that generates invalid data. +ALTER TYPE int_custom SET (ANALYZE = int_custom_typanalyze_invalid); + +-- Extended statistics with an attribute that generates invalid stats. +CREATE STATISTICS test_stats ON data, id FROM test_table; +-- Computation of the stats fails, no data generated. +ANALYZE test_table; +SELECT stxname, stxdexpr IS NULL as expr_stats_is_null + FROM pg_statistic_ext s + LEFT JOIN pg_statistic_ext_data d ON s.oid = d.stxoid + WHERE stxname = 'test_stats'; +DROP STATISTICS test_stats; + +-- Extended statistics with an expression that generates invalid data. +CREATE STATISTICS test_stats ON func_int_custom(data), (id) FROM test_table; +-- Computation of the stats fails, some data generated. +ANALYZE test_table; +SELECT stxname, stxdexpr IS NULL as expr_stats_is_null + FROM pg_statistic_ext s + LEFT JOIN pg_statistic_ext_data d ON s.oid = d.stxoid + WHERE stxname = 'test_stats'; +-- There should be some data stored for the expression, stored as NULL. +SELECT tablename, + statistics_name, + null_frac, + avg_width, + n_distinct, + most_common_vals, + most_common_freqs, + histogram_bounds, + correlation, + most_common_elems, + most_common_elem_freqs, + elem_count_histogram + FROM pg_stats_ext_exprs WHERE statistics_name = 'test_stats' \gx +-- Run a query able to load the extended stats, including the NULL data. +SELECT COUNT(*) FROM test_table GROUP BY (func_int_custom(data)); +DROP STATISTICS test_stats; + +-- Cleanup +DROP FUNCTION func_int_custom; +DROP TABLE test_table; +DROP EXTENSION test_custom_types; diff --git a/src/oracle_test/modules/test_custom_types/test_custom_types--1.0.sql b/src/oracle_test/modules/test_custom_types/test_custom_types--1.0.sql new file mode 100644 index 00000000000..c85bcbd24ff --- /dev/null +++ b/src/oracle_test/modules/test_custom_types/test_custom_types--1.0.sql @@ -0,0 +1,175 @@ +/* src/oracle_test/modules/test_custom_types/test_custom_types--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION test_custom_types" to load this file. \quit + +-- +-- Input/output functions for int_custom type +-- +CREATE FUNCTION int_custom_in(cstring) +RETURNS int_custom +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; +/ + +CREATE FUNCTION int_custom_out(int_custom) +RETURNS cstring +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; +/ + +-- +-- Typanalyze function that returns false +-- +CREATE FUNCTION int_custom_typanalyze_false(internal) +RETURNS boolean +AS 'MODULE_PATHNAME' +LANGUAGE C STRICT; +/ + +-- +-- Typanalyze function that returns invalid stats +-- +CREATE FUNCTION int_custom_typanalyze_invalid(internal) +RETURNS boolean +AS 'MODULE_PATHNAME' +LANGUAGE C STRICT; +/ + +-- +-- The int_custom type definition +-- +-- This type is identical to int4 in storage, and is used in subsequent +-- tests to have different properties. +-- +CREATE TYPE int_custom ( + INPUT = int_custom_in, + OUTPUT = int_custom_out, + LIKE = int4 +); + +-- +-- Comparison functions for int_custom +-- +-- These are required to create a btree operator class, which is needed +-- for the type to be usable in extended statistics objects. +-- +CREATE FUNCTION int_custom_eq(int_custom, int_custom) +RETURNS boolean +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; +/ + +CREATE FUNCTION int_custom_ne(int_custom, int_custom) +RETURNS boolean +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; +/ + +CREATE FUNCTION int_custom_lt(int_custom, int_custom) +RETURNS boolean +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; +/ + +CREATE FUNCTION int_custom_le(int_custom, int_custom) +RETURNS boolean +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; +/ + +CREATE FUNCTION int_custom_gt(int_custom, int_custom) +RETURNS boolean +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; +/ + +CREATE FUNCTION int_custom_ge(int_custom, int_custom) +RETURNS boolean +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; +/ + +CREATE FUNCTION int_custom_cmp(int_custom, int_custom) +RETURNS integer +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; +/ + +-- Operators for int_custom, for btree operator class +CREATE OPERATOR = ( + LEFTARG = int_custom, + RIGHTARG = int_custom, + FUNCTION = int_custom_eq, + COMMUTATOR = =, + NEGATOR = <>, + RESTRICT = eqsel, + JOIN = eqjoinsel, + HASHES, + MERGES +); + +CREATE OPERATOR <> ( + LEFTARG = int_custom, + RIGHTARG = int_custom, + FUNCTION = int_custom_ne, + COMMUTATOR = <>, + NEGATOR = =, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR < ( + LEFTARG = int_custom, + RIGHTARG = int_custom, + FUNCTION = int_custom_lt, + COMMUTATOR = >, + NEGATOR = >=, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR <= ( + LEFTARG = int_custom, + RIGHTARG = int_custom, + FUNCTION = int_custom_le, + COMMUTATOR = >=, + NEGATOR = >, + RESTRICT = scalarlesel, + JOIN = scalarlejoinsel +); + +CREATE OPERATOR > ( + LEFTARG = int_custom, + RIGHTARG = int_custom, + FUNCTION = int_custom_gt, + COMMUTATOR = <, + NEGATOR = <=, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = int_custom, + RIGHTARG = int_custom, + FUNCTION = int_custom_ge, + COMMUTATOR = <=, + NEGATOR = <, + RESTRICT = scalargesel, + JOIN = scalargejoinsel +); + +-- +-- Btree operator class for int_custom +-- +-- This is required for the type to be usable in extended statistics objects, +-- for attributes and expressions. +-- +CREATE OPERATOR CLASS int_custom_ops + DEFAULT FOR TYPE int_custom USING btree AS + OPERATOR 1 <, + OPERATOR 2 <=, + OPERATOR 3 =, + OPERATOR 4 >=, + OPERATOR 5 >, + FUNCTION 1 int_custom_cmp(int_custom, int_custom); diff --git a/src/oracle_test/modules/test_custom_types/test_custom_types.c b/src/oracle_test/modules/test_custom_types/test_custom_types.c new file mode 100644 index 00000000000..45e72056a1f --- /dev/null +++ b/src/oracle_test/modules/test_custom_types/test_custom_types.c @@ -0,0 +1,182 @@ +/*-------------------------------------------------------------------------- + * + * test_custom_types.c + * Test module for a set of functions for custom types. + * + * The custom type used in this module is similar to int4 for simplicity, + * except that it is able to use various typanalyze functions to enforce + * check patterns with ANALYZE. + * + * Copyright (c) 1996-2026, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/oracle_test/modules/test_custom_types/test_custom_types.c + * + *-------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "fmgr.h" +#include "commands/vacuum.h" +#include "utils/builtins.h" + +PG_MODULE_MAGIC; + +/* Function declarations */ +PG_FUNCTION_INFO_V1(int_custom_in); +PG_FUNCTION_INFO_V1(int_custom_out); +PG_FUNCTION_INFO_V1(int_custom_typanalyze_false); +PG_FUNCTION_INFO_V1(int_custom_typanalyze_invalid); +PG_FUNCTION_INFO_V1(int_custom_eq); +PG_FUNCTION_INFO_V1(int_custom_ne); +PG_FUNCTION_INFO_V1(int_custom_lt); +PG_FUNCTION_INFO_V1(int_custom_le); +PG_FUNCTION_INFO_V1(int_custom_gt); +PG_FUNCTION_INFO_V1(int_custom_ge); +PG_FUNCTION_INFO_V1(int_custom_cmp); + +/* + * int_custom_in - input function for int_custom type + * + * Converts a string to a int_custom (which is just an int32 internally). + */ +Datum +int_custom_in(PG_FUNCTION_ARGS) +{ + char *num = PG_GETARG_CSTRING(0); + + PG_RETURN_INT32(pg_strtoint32_safe(num, fcinfo->context)); +} + +/* + * int_custom_out - output function for int_custom type + * + * Converts a int_custom to a string. + */ +Datum +int_custom_out(PG_FUNCTION_ARGS) +{ + int32 arg1 = PG_GETARG_INT32(0); + char *result = (char *) palloc(12); /* sign, 10 digits, '\0' */ + + pg_ltoa(arg1, result); + PG_RETURN_CSTRING(result); +} + +/* + * int_custom_typanalyze_false - typanalyze function that returns false + * + * This function returns false, to simulate a type that cannot be analyzed. + */ +Datum +int_custom_typanalyze_false(PG_FUNCTION_ARGS) +{ + PG_RETURN_BOOL(false); +} + +/* + * Callback used to compute invalid statistics. + */ +static void +int_custom_invalid_stats(VacAttrStats *stats, AnalyzeAttrFetchFunc fetchfunc, + int samplerows, double totalrows) +{ + /* We are not valid, and do not want to be. */ + stats->stats_valid = false; +} + +/* + * int_custom_typanalyze_invalid + * + * This function sets some invalid stats data, letting the caller know that + * we are safe for an analyze, returning true. + */ +Datum +int_custom_typanalyze_invalid(PG_FUNCTION_ARGS) +{ + VacAttrStats *stats = (VacAttrStats *) PG_GETARG_POINTER(0); + + /* If the attstattarget column is negative, use the default value */ + if (stats->attstattarget < 0) + stats->attstattarget = default_statistics_target; + + /* Buggy number, no need to care as long as it is positive */ + stats->minrows = 300; + + /* Set callback to compute some invalid stats */ + stats->compute_stats = int_custom_invalid_stats; + + PG_RETURN_BOOL(true); +} + +/* + * Comparison functions for int_custom type + */ +Datum +int_custom_eq(PG_FUNCTION_ARGS) +{ + int32 arg1 = PG_GETARG_INT32(0); + int32 arg2 = PG_GETARG_INT32(1); + + PG_RETURN_BOOL(arg1 == arg2); +} + +Datum +int_custom_ne(PG_FUNCTION_ARGS) +{ + int32 arg1 = PG_GETARG_INT32(0); + int32 arg2 = PG_GETARG_INT32(1); + + PG_RETURN_BOOL(arg1 != arg2); +} + +Datum +int_custom_lt(PG_FUNCTION_ARGS) +{ + int32 arg1 = PG_GETARG_INT32(0); + int32 arg2 = PG_GETARG_INT32(1); + + PG_RETURN_BOOL(arg1 < arg2); +} + +Datum +int_custom_le(PG_FUNCTION_ARGS) +{ + int32 arg1 = PG_GETARG_INT32(0); + int32 arg2 = PG_GETARG_INT32(1); + + PG_RETURN_BOOL(arg1 <= arg2); +} + +Datum +int_custom_gt(PG_FUNCTION_ARGS) +{ + int32 arg1 = PG_GETARG_INT32(0); + int32 arg2 = PG_GETARG_INT32(1); + + PG_RETURN_BOOL(arg1 > arg2); +} + +Datum +int_custom_ge(PG_FUNCTION_ARGS) +{ + int32 arg1 = PG_GETARG_INT32(0); + int32 arg2 = PG_GETARG_INT32(1); + + PG_RETURN_BOOL(arg1 >= arg2); +} + +Datum +int_custom_cmp(PG_FUNCTION_ARGS) +{ + int32 arg1 = PG_GETARG_INT32(0); + int32 arg2 = PG_GETARG_INT32(1); + + if (arg1 < arg2) + PG_RETURN_INT32(-1); + else if (arg1 > arg2) + PG_RETURN_INT32(1); + else + PG_RETURN_INT32(0); +} diff --git a/src/oracle_test/modules/test_custom_types/test_custom_types.control b/src/oracle_test/modules/test_custom_types/test_custom_types.control new file mode 100644 index 00000000000..d25a74ef5c4 --- /dev/null +++ b/src/oracle_test/modules/test_custom_types/test_custom_types.control @@ -0,0 +1,5 @@ +# test_custom_types extension +comment = 'Tests for dummy custom types' +default_version = '1.0' +module_pathname = '$libdir/test_custom_types' +relocatable = true diff --git a/src/oracle_test/modules/test_ddl_deparse/Makefile b/src/oracle_test/modules/test_ddl_deparse/Makefile index be70a99b2a0..163443bb477 100644 --- a/src/oracle_test/modules/test_ddl_deparse/Makefile +++ b/src/oracle_test/modules/test_ddl_deparse/Makefile @@ -28,6 +28,7 @@ REGRESS = test_ddl_deparse \ alter_type_enum \ opfamily \ defprivs \ + textsearch \ matviews EXTRA_INSTALL = contrib/pg_stat_statements diff --git a/src/oracle_test/modules/test_ddl_deparse/expected/textsearch.out b/src/oracle_test/modules/test_ddl_deparse/expected/textsearch.out new file mode 100644 index 00000000000..da0d89e9704 --- /dev/null +++ b/src/oracle_test/modules/test_ddl_deparse/expected/textsearch.out @@ -0,0 +1,5 @@ +CREATE TEXT SEARCH CONFIGURATION evttrig_tscfg (COPY = pg_catalog.simple); +NOTICE: DDL test: type simple, tag CREATE TEXT SEARCH CONFIGURATION +ALTER TEXT SEARCH CONFIGURATION evttrig_tscfg + DROP MAPPING FOR word; +NOTICE: DDL test: type alter text search configuration, tag ALTER TEXT SEARCH CONFIGURATION diff --git a/src/oracle_test/modules/test_ddl_deparse/meson.build b/src/oracle_test/modules/test_ddl_deparse/meson.build index 640c0226413..8f3cda4fcd4 100644 --- a/src/oracle_test/modules/test_ddl_deparse/meson.build +++ b/src/oracle_test/modules/test_ddl_deparse/meson.build @@ -47,6 +47,7 @@ tests += { 'alter_type_enum', 'opfamily', 'defprivs', + 'textsearch', 'matviews', ], }, diff --git a/src/oracle_test/modules/test_ddl_deparse/sql/textsearch.sql b/src/oracle_test/modules/test_ddl_deparse/sql/textsearch.sql new file mode 100644 index 00000000000..633899a31cb --- /dev/null +++ b/src/oracle_test/modules/test_ddl_deparse/sql/textsearch.sql @@ -0,0 +1,3 @@ +CREATE TEXT SEARCH CONFIGURATION evttrig_tscfg (COPY = pg_catalog.simple); +ALTER TEXT SEARCH CONFIGURATION evttrig_tscfg + DROP MAPPING FOR word; diff --git a/src/oracle_test/modules/test_dsa/expected/test_dsa.out b/src/oracle_test/modules/test_dsa/expected/test_dsa.out index 266010e77fe..4b53a7de4a4 100644 --- a/src/oracle_test/modules/test_dsa/expected/test_dsa.out +++ b/src/oracle_test/modules/test_dsa/expected/test_dsa.out @@ -11,3 +11,19 @@ SELECT test_dsa_resowners(); (1 row) +-- Test allocations across a pre-defined range of pages. This covers enough +-- range to check for the case of odd-sized segments, without making the test +-- too slow. +SELECT test_dsa_allocate(1001, 2000, 100); + test_dsa_allocate +------------------- + +(1 row) + +-- Larger size with odd-sized segment. +SELECT test_dsa_allocate(6501, 6600, 100); + test_dsa_allocate +------------------- + +(1 row) + diff --git a/src/oracle_test/modules/test_dsa/sql/test_dsa.sql b/src/oracle_test/modules/test_dsa/sql/test_dsa.sql index c3d8db94372..99b4a60dd14 100644 --- a/src/oracle_test/modules/test_dsa/sql/test_dsa.sql +++ b/src/oracle_test/modules/test_dsa/sql/test_dsa.sql @@ -2,3 +2,10 @@ CREATE EXTENSION test_dsa; SELECT test_dsa_basic(); SELECT test_dsa_resowners(); + +-- Test allocations across a pre-defined range of pages. This covers enough +-- range to check for the case of odd-sized segments, without making the test +-- too slow. +SELECT test_dsa_allocate(1001, 2000, 100); +-- Larger size with odd-sized segment. +SELECT test_dsa_allocate(6501, 6600, 100); diff --git a/src/oracle_test/modules/test_dsa/test_dsa--1.0.sql b/src/oracle_test/modules/test_dsa/test_dsa--1.0.sql index 87bd7a26f4f..df9aa090726 100644 --- a/src/oracle_test/modules/test_dsa/test_dsa--1.0.sql +++ b/src/oracle_test/modules/test_dsa/test_dsa--1.0.sql @@ -10,3 +10,7 @@ CREATE FUNCTION test_dsa_basic() CREATE FUNCTION test_dsa_resowners() RETURNS pg_catalog.void AS 'MODULE_PATHNAME' LANGUAGE C; + +CREATE FUNCTION test_dsa_allocate(int, int, int) + RETURNS pg_catalog.void + AS 'MODULE_PATHNAME' LANGUAGE C; diff --git a/src/oracle_test/modules/test_dsa/test_dsa.c b/src/oracle_test/modules/test_dsa/test_dsa.c index 47b8e5d7078..4d021ed90c2 100644 --- a/src/oracle_test/modules/test_dsa/test_dsa.c +++ b/src/oracle_test/modules/test_dsa/test_dsa.c @@ -14,8 +14,10 @@ #include "postgres.h" #include "fmgr.h" +#include "storage/dsm_registry.h" #include "storage/lwlock.h" #include "utils/dsa.h" +#include "utils/freepage.h" #include "utils/resowner.h" PG_MODULE_MAGIC; @@ -112,3 +114,42 @@ test_dsa_resowners(PG_FUNCTION_ARGS) PG_RETURN_VOID(); } + +/* + * test_dsa_allocate + * + * Test DSA allocation across a range of sizes to exercise the pagemap + * sizing logic in make_new_segment(). A fresh DSA is created for each + * iteration so that each allocation triggers a new segment creation, + * including the odd-sized segment path. + */ +PG_FUNCTION_INFO_V1(test_dsa_allocate); +Datum +test_dsa_allocate(PG_FUNCTION_ARGS) +{ + int start_num_pages = PG_GETARG_INT32(0); + int end_num_pages = PG_GETARG_INT32(1); + int step = PG_GETARG_INT32(2); + size_t usable_pages; + int tranche_id; + dsa_area *a; + dsa_pointer dp; + + if (start_num_pages > end_num_pages) + elog(ERROR, "incorrect start and end parameters"); + + /* XXX: this tranche is leaked */ + tranche_id = LWLockNewTrancheId(); + LWLockRegisterTranche(tranche_id, "test_dsa"); + + for (usable_pages = start_num_pages; usable_pages < end_num_pages; usable_pages += step) + { + a = dsa_create(tranche_id); + dp = dsa_allocate(a, usable_pages * FPM_PAGE_SIZE); + + dsa_free(a, dp); + dsa_detach(a); + } + + PG_RETURN_VOID(); +} diff --git a/src/oracle_test/modules/test_ginpostinglist/test_ginpostinglist.c b/src/oracle_test/modules/test_ginpostinglist/test_ginpostinglist.c index eb0b8a755a0..1ec757d7e43 100644 --- a/src/oracle_test/modules/test_ginpostinglist/test_ginpostinglist.c +++ b/src/oracle_test/modules/test_ginpostinglist/test_ginpostinglist.c @@ -74,12 +74,12 @@ test_itemptr_pair(BlockNumber blk, OffsetNumber off, int maxsize) ItemPointerGetOffsetNumber(&decoded_itemptrs[0])); if (ndecoded == 2 && - !ItemPointerEquals(&orig_itemptrs[0], &decoded_itemptrs[0])) + !ItemPointerEquals(&orig_itemptrs[1], &decoded_itemptrs[1])) { elog(ERROR, "mismatch on second itemptr: (%u, %d) vs (%u, %d)", - 0, 1, - ItemPointerGetBlockNumber(&decoded_itemptrs[0]), - ItemPointerGetOffsetNumber(&decoded_itemptrs[0])); + blk, off, + ItemPointerGetBlockNumber(&decoded_itemptrs[1]), + ItemPointerGetOffsetNumber(&decoded_itemptrs[1])); } } diff --git a/src/oracle_test/modules/test_tidstore/test_tidstore.c b/src/oracle_test/modules/test_tidstore/test_tidstore.c index 94ff8b6a016..e14a6e9066c 100644 --- a/src/oracle_test/modules/test_tidstore/test_tidstore.c +++ b/src/oracle_test/modules/test_tidstore/test_tidstore.c @@ -76,6 +76,19 @@ itemptr_cmp(const void *left, const void *right) return 0; } +static int +offsetnumber_cmp(const void *a, const void *b) +{ + OffsetNumber l = *(const OffsetNumber *) a; + OffsetNumber r = *(const OffsetNumber *) b; + + if (l < r) + return -1; + else if (l > r) + return 1; + return 0; +} + /* * Create a TidStore. If shared is false, the tidstore is created * on TopMemoryContext, otherwise on DSA. Although the tidstore @@ -180,6 +193,9 @@ do_set_block_offsets(PG_FUNCTION_ARGS) noffs = ArrayGetNItems(ARR_NDIM(ta), ARR_DIMS(ta)); offs = ((OffsetNumber *) ARR_DATA_PTR(ta)); + /* TidStoreSetBlockOffsets() requires offsets to be strictly ascending. */ + qsort(offs, noffs, sizeof(OffsetNumber), offsetnumber_cmp); + /* Set TIDs in the store */ TidStoreLockExclusive(tidstore); TidStoreSetBlockOffsets(tidstore, blkno, offs, noffs); diff --git a/src/oracle_test/perl/PostgreSQL/Test/Utils.pm b/src/oracle_test/perl/PostgreSQL/Test/Utils.pm index d0ff92c32bb..204c6a27be8 100644 --- a/src/oracle_test/perl/PostgreSQL/Test/Utils.pm +++ b/src/oracle_test/perl/PostgreSQL/Test/Utils.pm @@ -92,6 +92,8 @@ our @EXPORT = qw( command_ok_or_fails_like command_checks_all + tar_portability_options + $windows_os $is_msys2 $use_unix_sockets @@ -1150,6 +1152,51 @@ sub command_checks_all =pod +=item tar_portability_options(tar) + +Check for non-default options we need to give to tar to create +a tarfile we can decode (i.e., no "pax" extensions). +Not needed in tests that only use tar to read tarfiles. + +Returns options as an array. + +=cut + +sub tar_portability_options +{ + local $Test::Builder::Level = $Test::Builder::Level + 1; + + my ($tar) = @_; + + my @tar_p_flags = (); + + return @tar_p_flags if (!defined $tar || $tar eq ''); + + # GNU tar typically produces gnu-format archives, which we can read fine. + # But some platforms configure it to default to posix/pax format, and + # apparently they enable --sparse too. Override that. + # + # ustar format supports UIDs only up to 2^21 - 1 (2097151). Override + # owner/group to avoid failures on systems where the running user's UID/GID + # exceeds that limit. + my $devnull = File::Spec->devnull(); + if (system( + "$tar --format=ustar --owner=0 --group=0 -cf $devnull $devnull 2>$devnull" + ) == 0) + { + # GNU tar (Linux), BSD tar (FreeBSD, NetBSD, macOS, Windows) + push(@tar_p_flags, "--format=ustar", "--owner=0", "--group=0"); + } + elsif (system("$tar -F ustar -cf $devnull $devnull 2>$devnull") == 0) + { + # OpenBSD tar + push(@tar_p_flags, "-F", "ustar"); + } + return @tar_p_flags; +} + +=pod + =back =cut diff --git a/src/oracle_test/postmaster/meson.build b/src/oracle_test/postmaster/meson.build index c2de2e0eb5b..af1c3018b5d 100644 --- a/src/oracle_test/postmaster/meson.build +++ b/src/oracle_test/postmaster/meson.build @@ -7,6 +7,7 @@ tests += { 'tap': { 'tests': [ 't/001_connection_limits.pl', + 't/004_negotiate.pl', ], }, } diff --git a/src/oracle_test/postmaster/t/004_negotiate.pl b/src/oracle_test/postmaster/t/004_negotiate.pl new file mode 100644 index 00000000000..f01b7519571 --- /dev/null +++ b/src/oracle_test/postmaster/t/004_negotiate.pl @@ -0,0 +1,82 @@ +# Copyright (c) 2026, PostgreSQL Global Development Group + +# Test the negotiation of combined SSL and GSS requests. This test +# relies on both SSL and GSS requests to be rejected first, followed +# by more requests. + +use strict; +use warnings FATAL => 'all'; +use PostgreSQL::Test::Cluster; +use PostgreSQL::Test::Utils; +use Test::More; +use Time::HiRes qw(usleep); + +my $node = PostgreSQL::Test::Cluster->new('main'); +$node->init; +$node->append_conf('postgresql.conf', "log_min_messages = debug2"); +$node->append_conf('postgresql.conf', + "log_connections = 'receipt,authentication,authorization'"); +$node->append_conf('postgresql.conf', 'trace_connection_negotiation=on'); +$node->start; + +if (!$node->raw_connect_works()) +{ + plan skip_all => "this test requires working raw_connect()"; +} + +my $sock = $node->raw_connect(); + +# SSLRequest: packet length followed by NEGOTIATE_SSL_CODE. +my $ssl_request = pack("Nnn", 8, 1234, 5679); + +# GSSENCRequest: packet length followed by NEGOTIATE_GSS_CODE. +my $gss_request = pack("Nnn", 8, 1234, 5680); + +# Send SSLRequest, reject or bypass. +$sock->send($ssl_request); +my $reply = ""; +$sock->recv($reply, 1); +if ($reply ne 'N') +{ + $sock->close(); + plan skip_all => + "server accepted SSL; test requires SSL to be rejected"; +} + +# Send GSSENCRequest, reject or bypass test. +$sock->send($gss_request); +$reply = ""; +$sock->recv($reply, 1); +if ($reply ne 'N') +{ + $sock->close(); + plan skip_all => + "server accepted GSS; test requires GSS to be rejected"; +} + +my $log_offset = -s $node->logfile; + +# Send a second SSLRequest, now that we know that both SSL and GSS have +# been rejected for this connection. We are done with both requests, so +# extra requests will be rejected and fail with an invalid protocol +# version, and the connection should be closed by the server. +$sock->send($ssl_request); + +# Try to read a response, there should be nothing, and certainly not an +# extra 'N' message indicating a rejection. +$reply = ""; +my $bytes = $sock->recv($reply, 1024); +isnt($reply, 'N', + "server does not re-enter SSL negotiation after SSL+GSS were both tried"); + +$sock->close(); +$node->wait_for_log(qr/FATAL: .* unsupported frontend protocol 1234.5679/, + $log_offset); + +# Check extra connection with a simple query. +my $result = $node->safe_psql('postgres', 'select 1;'); +is($result, '1', 'server able to accept connection'); + +$node->stop; + +done_testing(); diff --git a/src/oracle_test/recovery/t/004_timeline_switch.pl b/src/oracle_test/recovery/t/004_timeline_switch.pl index 684838cbab7..f88e54a0603 100644 --- a/src/oracle_test/recovery/t/004_timeline_switch.pl +++ b/src/oracle_test/recovery/t/004_timeline_switch.pl @@ -34,11 +34,10 @@ $node_primary->safe_psql('postgres', "CREATE TABLE tab_int AS SELECT generate_series(1,1000) AS a"); -# Wait until standby has replayed enough data on standby 1 -$node_primary->wait_for_catchup($node_standby_1); - -# Stop and remove primary -$node_primary->teardown_node; +# Cleanly stop and remove primary. A clean stop is required so as all +# the records generated on the primary are received and flushed by the two +# standbys. +$node_primary->stop; # promote standby 1 using "pg_promote", switching it to a new timeline my $psql_out = ''; diff --git a/src/oracle_test/recovery/t/009_twophase.pl b/src/oracle_test/recovery/t/009_twophase.pl index 1adc09c1fb8..7a886fba5b5 100644 --- a/src/oracle_test/recovery/t/009_twophase.pl +++ b/src/oracle_test/recovery/t/009_twophase.pl @@ -222,7 +222,7 @@ sub configure_and_reload SAVEPOINT s1; INSERT INTO t_009_tbl VALUES (22, 'issued to ${cur_primary_name}'); PREPARE TRANSACTION 'xact_009_10';"); -$cur_primary->teardown_node; +$cur_primary->stop; $cur_standby->promote; # change roles diff --git a/src/oracle_test/regress/expected/aggregates.out b/src/oracle_test/regress/expected/aggregates.out index fd7d34b893e..c06037521f3 100644 --- a/src/oracle_test/regress/expected/aggregates.out +++ b/src/oracle_test/regress/expected/aggregates.out @@ -1516,6 +1516,37 @@ explain (costs off) select y,z from t2 group by y,z; -> Seq Scan on t2 (3 rows) +-- A unique index proves uniqueness only under its own opfamily. When the +-- GROUP BY's eqop comes from a different opfamily with looser equality, +-- rows the index regards as distinct can collapse into one GROUP BY group, +-- so the index is not usable for removing redundant columns. +create type t_rec as (x numeric); +create temp table t_opf (a t_rec not null, b text); +create unique index on t_opf (a record_image_ops); +-- (1.0) and (1.00) are bytewise distinct but logically equal as records; +-- the index admits both, but GROUP BY a (default record_ops) would merge +-- them, so b must be retained as a grouping key. +insert into t_opf values (row(1.0)::t_rec, 'X'), (row(1.00)::t_rec, 'Y'); +explain (costs off) +select a, b from t_opf group by a, b order by b; + QUERY PLAN +------------------------------- + Group + Group Key: b, a + -> Sort + Sort Key: b, a + -> Seq Scan on t_opf +(5 rows) + +select a, b from t_opf group by a, b order by b; + a | b +--------+--- + (1.0) | X + (1.00) | Y +(2 rows) + +drop table t_opf; +drop type t_rec; drop table t1 cascade; NOTICE: drop cascades to table t1c drop table t2; @@ -1562,6 +1593,19 @@ group by f2; ----+------- (0 rows) +-- check that we preserve join alias in GROUP BY expressions +create temp view v1 as +select f1::int from t1 left join t2 using (f1) group by f1; +select pg_get_viewdef('v1'::regclass); + pg_get_viewdef +------------------------------------- + SELECT (f1)::pg_catalog.int4 AS f1+ + FROM (t1 + + LEFT JOIN t2 USING (f1)) + + GROUP BY f1; +(1 row) + +drop view v1; drop table t1, t2; -- -- Test planner's selection of pathkeys for ORDER BY aggregates diff --git a/src/oracle_test/regress/expected/alter_table.out b/src/oracle_test/regress/expected/alter_table.out index 90351fcb021..743cd78b408 100644 --- a/src/oracle_test/regress/expected/alter_table.out +++ b/src/oracle_test/regress/expected/alter_table.out @@ -3854,6 +3854,16 @@ Referenced by: ALTER TABLE test_add_column ADD COLUMN IF NOT EXISTS c5 SERIAL CHECK (c5 > 10); NOTICE: column "c5" of relation "test_add_column" already exists, skipping +ALTER TABLE test_add_column + ADD c6 integer; -- omit COLUMN +ALTER TABLE test_add_column + ADD IF NOT EXISTS c6 integer; +NOTICE: column "c6" of relation "test_add_column" already exists, skipping +ALTER TABLE test_add_column + DROP c6; -- omit COLUMN +ALTER TABLE test_add_column + DROP IF EXISTS c6; +NOTICE: column "c6" of relation "test_add_column" does not exist, skipping \d test_add_column* Table "public.test_add_column" Column | Type | Collation | Nullable | Default diff --git a/src/oracle_test/regress/expected/collate.icu.utf8.out b/src/oracle_test/regress/expected/collate.icu.utf8.out index 9a69332cc09..b2921093804 100644 --- a/src/oracle_test/regress/expected/collate.icu.utf8.out +++ b/src/oracle_test/regress/expected/collate.icu.utf8.out @@ -1650,6 +1650,310 @@ SELECT string_to_array('ABCDEFGHI' COLLATE case_sensitive, NULL, 'b'); {A,B,C,D,E,F,G,H,I} (1 row) +-- +-- A unique index under one collation does not prove uniqueness under +-- another, so the planner must not use such a proof for any optimization. +-- +-- Ensure that we do not use inner-unique join execution +EXPLAIN (VERBOSE, COSTS OFF) +SELECT * FROM test1cs t1, test3cs t2 +WHERE t1.x = t2.x COLLATE case_insensitive +ORDER BY 1, 2; + QUERY PLAN +---------------------------------------------------------------------- + Sort + Output: t1.x, t2.x + Sort Key: t1.x COLLATE case_sensitive, t2.x COLLATE case_sensitive + -> Hash Join + Output: t1.x, t2.x + Hash Cond: ((t2.x)::text = (t1.x)::text) + -> Seq Scan on collate_tests.test3cs t2 + Output: t2.x + -> Hash + Output: t1.x + -> Seq Scan on collate_tests.test1cs t1 + Output: t1.x +(12 rows) + +SELECT * FROM test1cs t1, test3cs t2 +WHERE t1.x = t2.x COLLATE case_insensitive +ORDER BY 1, 2; + x | x +-----+----- + abc | abc + abc | ABC + ABC | abc + ABC | ABC + def | def + ghi | ghi +(6 rows) + +-- Ensure that left-join is not removed +EXPLAIN (COSTS OFF) +SELECT t1.* FROM test3cs t1 + LEFT JOIN test3cs t2 ON t1.x = t2.x COLLATE case_insensitive +ORDER BY 1; + QUERY PLAN +------------------------------------------ + Sort + Sort Key: t1.x COLLATE case_sensitive + -> Hash Left Join + Hash Cond: (t1.x = (t2.x)::text) + -> Seq Scan on test3cs t1 + -> Hash + -> Seq Scan on test3cs t2 +(7 rows) + +SELECT t1.* FROM test3cs t1 + LEFT JOIN test3cs t2 ON t1.x = t2.x COLLATE case_insensitive +ORDER BY 1; + x +----- + abc + abc + ABC + ABC + def + ghi +(6 rows) + +-- Ensure that self-join is not removed +EXPLAIN (COSTS OFF) +SELECT * FROM test3cs t1, test3cs t2 +WHERE t1.x = t2.x COLLATE case_insensitive +ORDER BY 1, 2; + QUERY PLAN +---------------------------------------------------------------------- + Sort + Sort Key: t1.x COLLATE case_sensitive, t2.x COLLATE case_sensitive + -> Hash Join + Hash Cond: ((t1.x)::text = (t2.x)::text) + -> Seq Scan on test3cs t1 + -> Hash + -> Seq Scan on test3cs t2 +(7 rows) + +SELECT * FROM test3cs t1, test3cs t2 +WHERE t1.x = t2.x COLLATE case_insensitive +ORDER BY 1, 2; + x | x +-----+----- + abc | abc + abc | ABC + ABC | abc + ABC | ABC + def | def + ghi | ghi +(6 rows) + +-- Ensure that semijoin is not reduced to innerjoin +EXPLAIN (COSTS OFF) +SELECT * FROM test3cs t1 + WHERE EXISTS (SELECT 1 FROM test3cs t2 WHERE t1.x = t2.x COLLATE case_insensitive) +ORDER BY 1; + QUERY PLAN +-------------------------------------------------- + Sort + Sort Key: t1.x COLLATE case_sensitive + -> Hash Semi Join + Hash Cond: ((t1.x)::text = (t2.x)::text) + -> Seq Scan on test3cs t1 + -> Hash + -> Seq Scan on test3cs t2 +(7 rows) + +SELECT * FROM test3cs t1 + WHERE EXISTS (SELECT 1 FROM test3cs t2 WHERE t1.x = t2.x COLLATE case_insensitive) +ORDER BY 1; + x +----- + abc + ABC + def + ghi +(4 rows) + +-- +-- A DISTINCT / GROUP BY / set-op on a subquery does not prove uniqueness +-- under a different collation, so the planner must not use such a proof for +-- any optimization. +-- +-- Ensure that we do not use inner-unique join execution +EXPLAIN (VERBOSE, COSTS OFF) +SELECT * FROM test1cs t1, (SELECT DISTINCT x FROM test3cs) t2 +WHERE t1.x = t2.x COLLATE case_insensitive +ORDER BY 1, 2; + QUERY PLAN +--------------------------------------------------------------------------- + Sort + Output: t1.x, test3cs.x + Sort Key: t1.x COLLATE case_sensitive, test3cs.x COLLATE case_sensitive + -> Hash Join + Output: t1.x, test3cs.x + Hash Cond: ((t1.x)::text = (test3cs.x)::text) + -> Seq Scan on collate_tests.test1cs t1 + Output: t1.x + -> Hash + Output: test3cs.x + -> HashAggregate + Output: test3cs.x + Group Key: test3cs.x + -> Seq Scan on collate_tests.test3cs + Output: test3cs.x +(15 rows) + +SELECT * FROM test1cs t1, (SELECT DISTINCT x FROM test3cs) t2 +WHERE t1.x = t2.x COLLATE case_insensitive +ORDER BY 1, 2; + x | x +-----+----- + abc | abc + abc | ABC + ABC | abc + ABC | ABC + def | def + ghi | ghi +(6 rows) + +-- Same with GROUP BY +EXPLAIN (VERBOSE, COSTS OFF) +SELECT * FROM test1cs t1, (SELECT x FROM test3cs GROUP BY x) t2 +WHERE t1.x = t2.x COLLATE case_insensitive +ORDER BY 1, 2; + QUERY PLAN +--------------------------------------------------------------------------- + Sort + Output: t1.x, test3cs.x + Sort Key: t1.x COLLATE case_sensitive, test3cs.x COLLATE case_sensitive + -> Hash Join + Output: t1.x, test3cs.x + Hash Cond: ((t1.x)::text = (test3cs.x)::text) + -> Seq Scan on collate_tests.test1cs t1 + Output: t1.x + -> Hash + Output: test3cs.x + -> HashAggregate + Output: test3cs.x + Group Key: test3cs.x + -> Seq Scan on collate_tests.test3cs + Output: test3cs.x +(15 rows) + +SELECT * FROM test1cs t1, (SELECT x FROM test3cs GROUP BY x) t2 +WHERE t1.x = t2.x COLLATE case_insensitive +ORDER BY 1, 2; + x | x +-----+----- + abc | abc + abc | ABC + ABC | abc + ABC | ABC + def | def + ghi | ghi +(6 rows) + +-- Same with set-op +EXPLAIN (VERBOSE, COSTS OFF) +SELECT * FROM test1cs t1, (SELECT x FROM test3cs UNION SELECT x FROM test3cs) t2 +WHERE t1.x = t2.x COLLATE case_insensitive +ORDER BY 1, 2; + QUERY PLAN +--------------------------------------------------------------------------- + Sort + Output: t1.x, test3cs.x + Sort Key: t1.x COLLATE case_sensitive, test3cs.x COLLATE case_sensitive + -> Hash Join + Output: t1.x, test3cs.x + Hash Cond: ((test3cs.x)::text = (t1.x)::text) + -> HashAggregate + Output: test3cs.x + Group Key: test3cs.x + -> Append + -> Seq Scan on collate_tests.test3cs + Output: test3cs.x + -> Seq Scan on collate_tests.test3cs test3cs_1 + Output: test3cs_1.x + -> Hash + Output: t1.x + -> Seq Scan on collate_tests.test1cs t1 + Output: t1.x +(18 rows) + +SELECT * FROM test1cs t1, (SELECT x FROM test3cs UNION SELECT x FROM test3cs) t2 +WHERE t1.x = t2.x COLLATE case_insensitive +ORDER BY 1, 2; + x | x +-----+----- + abc | abc + abc | ABC + ABC | abc + ABC | ABC + def | def + ghi | ghi +(6 rows) + +-- Ensure that left-join is not removed +EXPLAIN (COSTS OFF) +SELECT t1.* FROM test3cs t1 + LEFT JOIN (SELECT DISTINCT x FROM test3cs) t2 ON t1.x = t2.x COLLATE case_insensitive +ORDER BY 1; + QUERY PLAN +----------------------------------------------- + Sort + Sort Key: t1.x COLLATE case_sensitive + -> Hash Left Join + Hash Cond: (t1.x = (test3cs.x)::text) + -> Seq Scan on test3cs t1 + -> Hash + -> HashAggregate + Group Key: test3cs.x + -> Seq Scan on test3cs +(9 rows) + +SELECT t1.* FROM test3cs t1 + LEFT JOIN (SELECT DISTINCT x FROM test3cs) t2 ON t1.x = t2.x COLLATE case_insensitive +ORDER BY 1; + x +----- + abc + abc + ABC + ABC + def + ghi +(6 rows) + +-- Ensure that semijoin is not reduced to innerjoin +EXPLAIN (COSTS OFF) +SELECT * FROM test3cs t1 + WHERE EXISTS (SELECT 1 FROM (SELECT DISTINCT x FROM test3cs) t2 + WHERE t1.x = t2.x COLLATE case_insensitive) +ORDER BY 1; + QUERY PLAN +------------------------------------------------------- + Sort + Sort Key: t1.x COLLATE case_sensitive + -> Hash Semi Join + Hash Cond: ((t1.x)::text = (test3cs.x)::text) + -> Seq Scan on test3cs t1 + -> Hash + -> HashAggregate + Group Key: test3cs.x + -> Seq Scan on test3cs +(9 rows) + +SELECT * FROM test3cs t1 + WHERE EXISTS (SELECT 1 FROM (SELECT DISTINCT x FROM test3cs) t2 + WHERE t1.x = t2.x COLLATE case_insensitive) +ORDER BY 1; + x +----- + abc + ABC + def + ghi +(4 rows) + CREATE TABLE test1ci (x text COLLATE case_insensitive); CREATE TABLE test2ci (x text COLLATE case_insensitive); CREATE TABLE test3ci (x text COLLATE case_insensitive); @@ -1776,6 +2080,270 @@ SELECT string_to_array('ABCDEFGHI' COLLATE case_insensitive, NULL, 'b'); {A,NULL,C,D,E,F,G,H,I} (1 row) +-- Test HAVING-to-WHERE pushdown with nondeterministic collations. +-- When a HAVING clause uses a different collation than the GROUP BY's +-- nondeterministic collation, it must not be pushed to WHERE, otherwise +-- aggregate results can change because the stricter filter eliminates rows +-- before grouping. +-- Negative: collation conflict, HAVING must not be pushed to WHERE +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING x = 'abc' COLLATE case_sensitive; + QUERY PLAN +---------------------------------------------------- + HashAggregate + Group Key: x + Filter: (x = 'abc'::text COLLATE case_sensitive) + -> Seq Scan on test3ci +(4 rows) + +SELECT x, count(*) FROM test3ci GROUP BY x HAVING x = 'abc' COLLATE case_sensitive; + x | count +-----+------- + abc | 2 +(1 row) + +-- Positive: same collation, safe to push HAVING to WHERE +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING x = 'abc' COLLATE case_insensitive; + QUERY PLAN +------------------------------------------------------------ + GroupAggregate + -> Seq Scan on test3ci + Filter: (x = 'abc'::text COLLATE case_insensitive) +(3 rows) + +SELECT x, count(*) FROM test3ci GROUP BY x HAVING x = 'abc' COLLATE case_insensitive; + x | count +-----+------- + abc | 2 +(1 row) + +-- Negative: function applied to grouped column with conflicting collation +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING upper(x) = 'ABC' COLLATE case_sensitive; + QUERY PLAN +----------------------------------------------------------- + HashAggregate + Group Key: x + Filter: (upper(x) = 'ABC'::text COLLATE case_sensitive) + -> Seq Scan on test3ci +(4 rows) + +SELECT x, count(*) FROM test3ci GROUP BY x HAVING upper(x) = 'ABC' COLLATE case_sensitive; + x | count +-----+------- + abc | 2 +(1 row) + +-- Positive: function with same collation as GROUP BY +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING upper(x) = 'ABC' COLLATE case_insensitive; + QUERY PLAN +------------------------------------------------------------------------- + GroupAggregate + Group Key: x + -> Sort + Sort Key: x COLLATE case_insensitive + -> Seq Scan on test3ci + Filter: (upper(x) = 'ABC'::text COLLATE case_insensitive) +(6 rows) + +SELECT x, count(*) FROM test3ci GROUP BY x HAVING upper(x) = 'ABC' COLLATE case_insensitive; + x | count +-----+------- + abc | 2 +(1 row) + +-- Negative: inner function has conflicting collation, even though outer +-- operator's collation matches GROUP BY due to a COLLATE override +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING upper(x COLLATE case_sensitive) COLLATE case_insensitive = 'ABC'; + QUERY PLAN +---------------------------------------------------- + HashAggregate + Group Key: x + Filter: ((upper((x)::text))::text = 'ABC'::text) + -> Seq Scan on test3ci +(4 rows) + +SELECT x, count(*) FROM test3ci GROUP BY x HAVING upper(x COLLATE case_sensitive) COLLATE case_insensitive = 'ABC'; + x | count +-----+------- + abc | 2 +(1 row) + +-- Mixed AND: conflicting clause stays in HAVING, safe clause pushed to WHERE +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING x = 'abc' COLLATE case_sensitive AND length(x) > 1; + QUERY PLAN +---------------------------------------------------- + HashAggregate + Group Key: x + Filter: (x = 'abc'::text COLLATE case_sensitive) + -> Seq Scan on test3ci + Filter: (length(x) > 1) +(5 rows) + +SELECT x, count(*) FROM test3ci GROUP BY x HAVING x = 'abc' COLLATE case_sensitive AND length(x) > 1; + x | count +-----+------- + abc | 2 +(1 row) + +-- Positive: AND of two safe clauses, both can be pushed +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING x = 'abc' COLLATE case_insensitive AND length(x) > 1; + QUERY PLAN +---------------------------------------------------------------------------------- + GroupAggregate + -> Seq Scan on test3ci + Filter: ((x = 'abc'::text COLLATE case_insensitive) AND (length(x) > 1)) +(3 rows) + +SELECT x, count(*) FROM test3ci GROUP BY x HAVING x = 'abc' COLLATE case_insensitive AND length(x) > 1; + x | count +-----+------- + abc | 2 +(1 row) + +-- Negative: OR with a conflicting clause: must stay in HAVING +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING x = 'abc' COLLATE case_sensitive OR x = 'def' COLLATE case_sensitive ORDER BY 1; + QUERY PLAN +-------------------------------------------------------------------------------------------------------- + Sort + Sort Key: x COLLATE case_insensitive + -> HashAggregate + Group Key: x + Filter: ((x = 'abc'::text COLLATE case_sensitive) OR (x = 'def'::text COLLATE case_sensitive)) + -> Seq Scan on test3ci +(6 rows) + +SELECT x, count(*) FROM test3ci GROUP BY x HAVING x = 'abc' COLLATE case_sensitive OR x = 'def' COLLATE case_sensitive ORDER BY 1; + x | count +-----+------- + abc | 2 + def | 1 +(2 rows) + +-- Negative: collation conflict inside a RowCompareExpr +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING ROW(x, 1) < ROW('ABC' COLLATE case_sensitive, 1) ORDER BY 1; + QUERY PLAN +-------------------------------------------------------------------------- + Sort + Sort Key: x COLLATE case_insensitive + -> HashAggregate + Group Key: x + Filter: (ROW(x, 1) < ROW('ABC'::text COLLATE case_sensitive, 1)) + -> Seq Scan on test3ci +(6 rows) + +SELECT x, count(*) FROM test3ci GROUP BY x HAVING ROW(x, 1) < ROW('ABC' COLLATE case_sensitive, 1) ORDER BY 1; + x | count +-----+------- + abc | 2 +(1 row) + +-- Negative: simple-CASE form with conflicting WHEN comparison collation +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING (CASE x WHEN 'abc' COLLATE case_sensitive THEN true ELSE false END); + QUERY PLAN +----------------------------------------------------------------------------------- + HashAggregate + Group Key: x + Filter: CASE x WHEN 'abc'::text COLLATE case_sensitive THEN true ELSE false END + -> Seq Scan on test3ci +(4 rows) + +SELECT x, count(*) FROM test3ci GROUP BY x HAVING (CASE x WHEN 'abc' COLLATE case_sensitive THEN true ELSE false END); + x | count +-----+------- + abc | 2 +(1 row) + +-- Positive: simple-CASE form with matching collation, safe to push +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING (CASE x WHEN 'abc' COLLATE case_insensitive THEN true ELSE false END); + QUERY PLAN +------------------------------------------------------------------------------------------- + HashAggregate + Group Key: x + -> Seq Scan on test3ci + Filter: CASE x WHEN 'abc'::text COLLATE case_insensitive THEN true ELSE false END +(4 rows) + +SELECT x, count(*) FROM test3ci GROUP BY x HAVING (CASE x WHEN 'abc' COLLATE case_insensitive THEN true ELSE false END); + x | count +-----+------- + abc | 2 +(1 row) + +-- Negative: nested CASE with collation conflict +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING (CASE WHEN (CASE x WHEN 'abc' COLLATE case_sensitive THEN 1 ELSE 0 END) = 1 THEN true ELSE false END); + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------- + HashAggregate + Group Key: x + Filter: CASE WHEN (CASE x WHEN 'abc'::text COLLATE case_sensitive THEN 1 ELSE 0 END = 1) THEN true ELSE false END + -> Seq Scan on test3ci +(4 rows) + +SELECT x, count(*) FROM test3ci GROUP BY x HAVING (CASE WHEN (CASE x WHEN 'abc' COLLATE case_sensitive THEN 1 ELSE 0 END) = 1 THEN true ELSE false END); + x | count +-----+------- + abc | 2 +(1 row) + +-- Positive: conflicting collation but no grouping expression reference +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING current_setting('server_version') = 'abc' COLLATE case_sensitive; + QUERY PLAN +--------------------------------------------------------------------------------------------------------- + HashAggregate + Group Key: x + -> Result + One-Time Filter: (current_setting('server_version'::text) = 'abc'::text COLLATE case_sensitive) + -> Seq Scan on test3ci +(5 rows) + +-- Positive: deterministic collation in GROUP BY: always safe to push, even if +-- HAVING uses a nondeterministic collation +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3cs GROUP BY x HAVING x = 'abc' COLLATE case_sensitive; + QUERY PLAN +---------------------------------------------------------- + GroupAggregate + -> Seq Scan on test3cs + Filter: (x = 'abc'::text COLLATE case_sensitive) +(3 rows) + +SELECT x, count(*) FROM test3cs GROUP BY x HAVING x = 'abc' COLLATE case_sensitive; + x | count +-----+------- + abc | 1 +(1 row) + +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3cs GROUP BY x HAVING x = 'abc' COLLATE case_insensitive ORDER BY 1; + QUERY PLAN +------------------------------------------------------------------ + GroupAggregate + Group Key: x + -> Sort + Sort Key: x COLLATE case_sensitive + -> Seq Scan on test3cs + Filter: (x = 'abc'::text COLLATE case_insensitive) +(6 rows) + +SELECT x, count(*) FROM test3cs GROUP BY x HAVING x = 'abc' COLLATE case_insensitive ORDER BY 1; + x | count +-----+------- + abc | 1 + ABC | 1 +(2 rows) + -- bpchar CREATE TABLE test1bpci (x char(3) COLLATE case_insensitive); CREATE TABLE test2bpci (x char(3) COLLATE case_insensitive); @@ -2687,6 +3255,38 @@ DROP TABLE pagg_tab6; RESET enable_partitionwise_aggregate; RESET max_parallel_workers_per_gather; RESET enable_incremental_sort; +-- +-- A unique index can prove functional dependency for GROUP BY column +-- removal only if its per-column collation agrees on equality with +-- the GROUP BY column's collation. An index built under a different +-- (deterministic) collation would otherwise let remove_useless_groupby_columns +-- drop other columns whose values still differ within a nondeterministic +-- group. +-- +CREATE TABLE groupby_collation_t (a text COLLATE case_insensitive NOT NULL, b text); +INSERT INTO groupby_collation_t VALUES ('foo', 'X'), ('FOO', 'Y'); +CREATE UNIQUE INDEX ON groupby_collation_t (a COLLATE "C"); +-- Column b must NOT be dropped: under case_insensitive on a, 'foo' and +-- 'FOO' would merge, but they have distinct b values. +EXPLAIN (COSTS OFF) +SELECT a, b FROM groupby_collation_t GROUP BY a, b ORDER BY a, b; + QUERY PLAN +------------------------------------------------- + Group + Group Key: a, b + -> Sort + Sort Key: a COLLATE case_insensitive, b + -> Seq Scan on groupby_collation_t +(5 rows) + +SELECT a, b FROM groupby_collation_t GROUP BY a, b ORDER BY a, b; + a | b +-----+--- + foo | X + FOO | Y +(2 rows) + +DROP TABLE groupby_collation_t; -- virtual generated columns CREATE TABLE t5 ( a int, diff --git a/src/oracle_test/regress/expected/compression_pglz.out b/src/oracle_test/regress/expected/compression_pglz.out new file mode 100644 index 00000000000..8c519d86b22 --- /dev/null +++ b/src/oracle_test/regress/expected/compression_pglz.out @@ -0,0 +1,67 @@ +-- +-- Tests for PGLZ compression +-- +-- directory paths and dlsuffix are passed to us in environment variables +\getenv libdir PG_LIBDIR +\getenv dlsuffix PG_DLSUFFIX +\set regresslib :libdir '/oraregress' :dlsuffix +CREATE FUNCTION test_pglz_compress(bytea) + RETURNS bytea + AS :'regresslib' LANGUAGE C STRICT; +/ +CREATE FUNCTION test_pglz_decompress(bytea, int4, bool) + RETURNS bytea + AS :'regresslib' LANGUAGE C STRICT; +/ +-- Round-trip with pglz: compress then decompress. +SELECT test_pglz_decompress(test_pglz_compress( + decode(repeat('abcd', 100), 'escape')), 400, false) = + decode(repeat('abcd', 100), 'escape') AS roundtrip_ok; + roundtrip_ok +-------------- + t +(1 row) + +SELECT test_pglz_decompress(test_pglz_compress( + decode(repeat('abcd', 100), 'escape')), 400, true) = + decode(repeat('abcd', 100), 'escape') AS roundtrip_ok; + roundtrip_ok +-------------- + t +(1 row) + +-- Decompression with rawsize too large, fails to fill the destination +-- buffer. +SELECT test_pglz_decompress(test_pglz_compress( + decode(repeat('abcd', 100), 'escape')), 500, true); +ERROR: pglz_decompress failed +-- Decompression with rawsize too small, fails with source not fully +-- consumed. +SELECT test_pglz_decompress(test_pglz_compress( + decode(repeat('abcd', 100), 'escape')), 100, true); +ERROR: pglz_decompress failed +-- Corrupted compressed data. Set control bit with read of a match tag, +-- no data follows. +SELECT length(test_pglz_decompress('\x01'::bytea, 1024, false)) AS ctrl_only_len; + ctrl_only_len +--------------- + 0 +(1 row) + +SELECT test_pglz_decompress('\x01'::bytea, 1024, true); +ERROR: pglz_decompress failed +-- Corrupted compressed data. Set control bit with read of a match tag, +-- 1 byte follows. +SELECT test_pglz_decompress('\x01ff'::bytea, 1024, false); +ERROR: pglz_decompress failed +SELECT test_pglz_decompress('\x01ff'::bytea, 1024, true); +ERROR: pglz_decompress failed +-- Corrupted compressed data. Set control bit with match tag where length +-- nibble is 3 bytes (extended length), no data follows. +SELECT test_pglz_decompress('\x010f01'::bytea, 1024, false); +ERROR: pglz_decompress failed +SELECT test_pglz_decompress('\x010f01'::bytea, 1024, true); +ERROR: pglz_decompress failed +-- Clean up +DROP FUNCTION test_pglz_compress; +DROP FUNCTION test_pglz_decompress; diff --git a/src/oracle_test/regress/expected/create_index.out b/src/oracle_test/regress/expected/create_index.out index d94aa675cad..9bb363c43b2 100644 --- a/src/oracle_test/regress/expected/create_index.out +++ b/src/oracle_test/regress/expected/create_index.out @@ -32,6 +32,20 @@ COMMENT ON INDEX six_wrong IS 'bad index'; ERROR: relation "six_wrong" does not exist COMMENT ON INDEX six IS 'good index'; COMMENT ON INDEX six IS NULL; +SELECT obj_description('six'::regclass, 'pg_class') IS NULL AS six_comment_is_null; + six_comment_is_null +--------------------- + t +(1 row) + +COMMENT ON INDEX six IS 'add the comment back'; +COMMENT ON INDEX six IS ''; -- empty string removes the comment, same as NULL +SELECT obj_description('six'::regclass, 'pg_class') IS NULL AS six_comment_is_null; + six_comment_is_null +--------------------- + t +(1 row) + -- -- BTREE partial indices -- diff --git a/src/oracle_test/regress/expected/create_role.out b/src/oracle_test/regress/expected/create_role.out index 46d4f9efe99..5d0f21820ed 100644 --- a/src/oracle_test/regress/expected/create_role.out +++ b/src/oracle_test/regress/expected/create_role.out @@ -102,6 +102,33 @@ CREATE ROLE regress_rolecreator CREATEROLE; CREATE ROLE regress_hasprivs CREATEROLE LOGIN INHERIT CONNECTION LIMIT 5; -- ok, we should be able to modify a role we created COMMENT ON ROLE regress_hasprivs IS 'some comment'; +SELECT shobj_description('regress_hasprivs'::regrole, 'pg_authid') IS NOT NULL AS has_comment; + has_comment +------------- + t +(1 row) + +COMMENT ON ROLE regress_hasprivs IS NULL; +SELECT shobj_description('regress_hasprivs'::regrole, 'pg_authid') IS NULL AS no_comment; + no_comment +------------ + t +(1 row) + +COMMENT ON ROLE regress_hasprivs IS 'add the comment back'; +SELECT shobj_description('regress_hasprivs'::regrole, 'pg_authid') IS NOT NULL AS has_comment; + has_comment +------------- + t +(1 row) + +COMMENT ON ROLE regress_hasprivs IS ''; -- empty string removes the comment, same as NULL +SELECT shobj_description('regress_hasprivs'::regrole, 'pg_authid') IS NULL AS no_comment; + no_comment +------------ + t +(1 row) + ALTER ROLE regress_hasprivs RENAME TO regress_tenant; ALTER ROLE regress_tenant NOINHERIT NOLOGIN CONNECTION LIMIT 7; -- fail, we should be unable to modify a role we did not create diff --git a/src/oracle_test/regress/expected/create_table_like.out b/src/oracle_test/regress/expected/create_table_like.out index caa6d2d4caf..d021f0a0cf0 100644 --- a/src/oracle_test/regress/expected/create_table_like.out +++ b/src/oracle_test/regress/expected/create_table_like.out @@ -694,6 +694,37 @@ SELECT attname, attcompression FROM pg_attribute e | (5 rows) +-- LIKE ... INCLUDING STATISTICS with dropped columns in the parent, +-- so stxkeys attnums are not contiguous. +CREATE TABLE ctl_stats3_parent (a int, b int, c int); +ALTER TABLE ctl_stats3_parent DROP COLUMN b; +CREATE STATISTICS ctl_stats3_stat ON a, c FROM ctl_stats3_parent; +CREATE TABLE ctl_stats3_child (LIKE ctl_stats3_parent INCLUDING STATISTICS); +CREATE TABLE ctl_stats4_parent (a int, b int, c int, d int); +ALTER TABLE ctl_stats4_parent DROP COLUMN b; +CREATE STATISTICS ctl_stats4_stat ON a, c FROM ctl_stats4_parent; +CREATE TABLE ctl_stats4_child (LIKE ctl_stats4_parent INCLUDING STATISTICS); +SELECT s.stxrelid::regclass AS relation, + array_agg(a.attname ORDER BY u.ord) AS stats_columns +FROM pg_statistic_ext s +CROSS JOIN LATERAL + unnest(s.stxkeys::int2[]) WITH ORDINALITY AS u(attnum, ord) +JOIN pg_attribute a + ON a.attrelid = s.stxrelid AND a.attnum = u.attnum +WHERE s.stxrelid IN ('ctl_stats3_child'::regclass, + 'ctl_stats4_child'::regclass) +GROUP BY s.stxrelid +ORDER BY s.stxrelid::regclass::text; + relation | stats_columns +------------------+--------------- + ctl_stats3_child | {a,c} + ctl_stats4_child | {a,c} +(2 rows) + +DROP TABLE ctl_stats3_parent; +DROP TABLE ctl_stats3_child; +DROP TABLE ctl_stats4_parent; +DROP TABLE ctl_stats4_child; DROP TABLE ctl_table; DROP FOREIGN TABLE ctl_foreign_table1; DROP FOREIGN TABLE ctl_foreign_table2; diff --git a/src/oracle_test/regress/expected/expressions.out b/src/oracle_test/regress/expected/expressions.out index 7c3708d24ee..dfcc5ca371d 100644 --- a/src/oracle_test/regress/expected/expressions.out +++ b/src/oracle_test/regress/expected/expressions.out @@ -389,42 +389,179 @@ default for type myint using hash as operator 1 = (myint, myint), function 1 myinthash(myint); create table inttest (a myint); -insert into inttest values(1::myint),(null); --- try an array with enough elements to cause hashing -select * from inttest where a in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint,9::myint, null); - a ---- - 1 - -(2 rows) +insert into inttest values (null), (0::myint), (1::myint); +-- Test EEOP_HASHED_SCALARARRAYOP against EEOP_SCALARARRAYOP. Ensure the +-- result of non-hashed vs hashed is the same. +select + a, + a in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as not_hashed, + a in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint,9::myint) as hashed +from inttest; + a | not_hashed | hashed +---+------------+-------- + | | + 0 | f | f + 1 | t | t +(3 rows) -select * from inttest where a not in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint,9::myint, null); - a ---- -(0 rows) - -select * from inttest where a not in (0::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint,9::myint, null); - a ---- -(0 rows) - --- ensure the result matched with the non-hashed version. We simply remove --- some array elements so that we don't reach the hashing threshold. -select * from inttest where a in (1::myint,2::myint,3::myint,4::myint,5::myint, null); - a ---- - 1 - -(2 rows) +select + a, + a in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint) as not_hashed, + a in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as hashed + from inttest; + a | not_hashed | hashed +---+------------+-------- + | t | t + 0 | | + 1 | t | t +(3 rows) + +select + a, + a not in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as not_hashed, + a not in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint,9::myint) as hashed +from inttest; + a | not_hashed | hashed +---+------------+-------- + | | + 0 | t | t + 1 | f | f +(3 rows) + +select + a, + a not in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint) as not_hashed, + a not in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as hashed +from inttest; + a | not_hashed | hashed +---+------------+-------- + | f | f + 0 | | + 1 | f | f +(3 rows) -select * from inttest where a not in (1::myint,2::myint,3::myint,4::myint,5::myint, null); - a ---- -(0 rows) +-- Now make the equal function return false when given two NULLs +create or replace function myinteq(myint, myint) returns bool as $$ +begin + if $1 is null and $2 is null then + return false; + else + return $1::int = $2::int; + end if; +end; +$$ language plpgsql immutable; +/ +-- And try the same again to ensure EEOP_HASHED_SCALARARRAYOP does the same +-- thing as EEOP_SCALARARRAYOP. +select + a, + a in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as not_hashed, + a in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint,9::myint) as hashed +from inttest; + a | not_hashed | hashed +---+------------+-------- + | | + 0 | f | f + 1 | t | t +(3 rows) -select * from inttest where a not in (0::myint,2::myint,3::myint,4::myint,5::myint, null); - a ---- -(0 rows) +select + a, + a in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint) as not_hashed, + a in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as hashed + from inttest; + a | not_hashed | hashed +---+------------+-------- + | | + 0 | | + 1 | t | t +(3 rows) + +select + a, + a not in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as not_hashed, + a not in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint,9::myint) as hashed +from inttest; + a | not_hashed | hashed +---+------------+-------- + | | + 0 | t | t + 1 | f | f +(3 rows) + +select + a, + a not in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint) as not_hashed, + a not in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as hashed +from inttest; + a | not_hashed | hashed +---+------------+-------- + | | + 0 | | + 1 | f | f +(3 rows) + +-- Try again with an equality function that treats NULLs as equal to 0. +create or replace function myinteq(myint, myint) returns bool as $$ +begin + if $1 is null and $2 is null then + return false; + else + return coalesce($1::int,0) = coalesce($2::int, 0); + end if; +end; +$$ language plpgsql immutable; +/ +select + a, + a in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as not_hashed, + a in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint,9::myint) as hashed, + a in (0::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint) as not_hashed_zero, + a in (0::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as hashed_zero +from inttest; + a | not_hashed | hashed | not_hashed_zero | hashed_zero +---+------------+--------+-----------------+------------- + | f | f | t | t + 0 | f | f | t | t + 1 | t | t | t | t +(3 rows) + +select + a, + a in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint) as not_hashed, + a in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as hashed + from inttest; + a | not_hashed | hashed +---+------------+-------- + | f | f + 0 | t | t + 1 | t | t +(3 rows) + +select + a, + a not in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as not_hashed, + a not in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint,9::myint) as hashed, + a not in (0::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint) as not_hashed_zero, + a not in (0::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as hashed_zero +from inttest; + a | not_hashed | hashed | not_hashed_zero | hashed_zero +---+------------+--------+-----------------+------------- + | t | t | f | f + 0 | t | t | f | f + 1 | f | f | f | f +(3 rows) + +select + a, + a not in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint) as not_hashed, + a not in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as hashed +from inttest; + a | not_hashed | hashed +---+------------+-------- + | t | t + 0 | f | f + 1 | f | f +(3 rows) rollback; diff --git a/src/oracle_test/regress/expected/foreign_data.out b/src/oracle_test/regress/expected/foreign_data.out index eabd069b2af..d54bb7c0c4f 100644 --- a/src/oracle_test/regress/expected/foreign_data.out +++ b/src/oracle_test/regress/expected/foreign_data.out @@ -109,6 +109,13 @@ ERROR: conflicting or redundant options LINE 1: ...GN DATA WRAPPER test_fdw HANDLER test_fdw_handler HANDLER in... ^ CREATE FOREIGN DATA WRAPPER test_fdw HANDLER test_fdw_handler; +-- should preserve dependency on test_fdw_handler +ALTER FOREIGN DATA WRAPPER test_fdw VALIDATOR postgresql_fdw_validator; +WARNING: changing the foreign-data wrapper validator can cause the options for dependent objects to become invalid +DROP FUNCTION test_fdw_handler(); -- ERROR +ERROR: cannot drop function test_fdw_handler() because other objects depend on it +DETAIL: foreign-data wrapper test_fdw depends on function test_fdw_handler() +HINT: Use DROP ... CASCADE to drop the dependent objects too. DROP FOREIGN DATA WRAPPER test_fdw; -- ALTER FOREIGN DATA WRAPPER ALTER FOREIGN DATA WRAPPER foo OPTIONS (nonexistent 'fdw'); -- ERROR @@ -831,10 +838,13 @@ COMMENT ON COLUMN ft1.c1 IS NULL; ALTER FOREIGN TABLE ft1 ADD COLUMN c4 integer; ALTER FOREIGN TABLE ft1 ADD COLUMN c5 integer DEFAULT 0; ALTER FOREIGN TABLE ft1 ADD COLUMN c6 integer; +ALTER FOREIGN TABLE ft1 ADD COLUMN IF NOT EXISTS c6 integer; +NOTICE: column "c6" of relation "ft1" already exists, skipping ALTER FOREIGN TABLE ft1 ADD COLUMN c7 integer NOT NULL; ALTER FOREIGN TABLE ft1 ADD COLUMN c8 integer; ALTER FOREIGN TABLE ft1 ADD COLUMN c9 integer; ALTER FOREIGN TABLE ft1 ADD COLUMN c10 integer OPTIONS (p1 'v1'); +ALTER FOREIGN TABLE ft1 ADD c11 integer; ALTER FOREIGN TABLE ft1 ALTER COLUMN c4 SET DEFAULT 0; ALTER FOREIGN TABLE ft1 ALTER COLUMN c5 DROP DEFAULT; ALTER FOREIGN TABLE ft1 ALTER COLUMN c6 SET NOT NULL; @@ -866,6 +876,7 @@ ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 SET STORAGE PLAIN; c8 | text | | | | (p2 'V2') | plain | | c9 | pg_catalog.int4 | | | | | plain | | c10 | pg_catalog.int4 | | | | (p1 'v1') | plain | | + c11 | pg_catalog.int4 | | | | | plain | | Check constraints: "ft1_c2_check" CHECK (c2 <> ''::text) "ft1_c3_check" CHECK (c3 >= '1994-01-01'::date AND c3 <= '1994-01-31'::date) @@ -900,6 +911,7 @@ ERROR: column "no_column" of relation "ft1" does not exist ALTER FOREIGN TABLE ft1 DROP COLUMN IF EXISTS no_column; NOTICE: column "no_column" of relation "ft1" does not exist, skipping ALTER FOREIGN TABLE ft1 DROP COLUMN c9; +ALTER FOREIGN TABLE ft1 DROP c11; ALTER FOREIGN TABLE ft1 ADD COLUMN c11 serial; ALTER FOREIGN TABLE ft1 SET SCHEMA foreign_schema; ALTER FOREIGN TABLE ft1 SET TABLESPACE ts; -- ERROR @@ -934,6 +946,8 @@ ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 ADD COLUMN c4 integer; NOTICE: relation "doesnt_exist_ft1" does not exist, skipping ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 ADD COLUMN c6 integer; NOTICE: relation "doesnt_exist_ft1" does not exist, skipping +ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 ADD COLUMN IF NOT EXISTS c6 integer; +NOTICE: relation "doesnt_exist_ft1" does not exist, skipping ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 ADD COLUMN c7 integer NOT NULL; NOTICE: relation "doesnt_exist_ft1" does not exist, skipping ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 ADD COLUMN c8 integer; @@ -942,6 +956,8 @@ ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 ADD COLUMN c9 integer; NOTICE: relation "doesnt_exist_ft1" does not exist, skipping ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 ADD COLUMN c10 integer OPTIONS (p1 'v1'); NOTICE: relation "doesnt_exist_ft1" does not exist, skipping +ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 ADD c11 integer; +NOTICE: relation "doesnt_exist_ft1" does not exist, skipping ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 ALTER COLUMN c6 SET NOT NULL; NOTICE: relation "doesnt_exist_ft1" does not exist, skipping ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 ALTER COLUMN c7 DROP NOT NULL; @@ -963,10 +979,14 @@ ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 OWNER TO regress_test_role; NOTICE: relation "doesnt_exist_ft1" does not exist, skipping ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 OPTIONS (DROP delimiter, SET quote '~', ADD escape '@'); NOTICE: relation "doesnt_exist_ft1" does not exist, skipping +ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 DROP COLUMN no_column; +NOTICE: relation "doesnt_exist_ft1" does not exist, skipping ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 DROP COLUMN IF EXISTS no_column; NOTICE: relation "doesnt_exist_ft1" does not exist, skipping ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 DROP COLUMN c9; NOTICE: relation "doesnt_exist_ft1" does not exist, skipping +ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 DROP c11; +NOTICE: relation "doesnt_exist_ft1" does not exist, skipping ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 SET SCHEMA foreign_schema; NOTICE: relation "doesnt_exist_ft1" does not exist, skipping ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 RENAME c1 TO foreign_column_1; diff --git a/src/oracle_test/regress/expected/foreign_key.out b/src/oracle_test/regress/expected/foreign_key.out index 9fd0191f1ca..5bc6eda33d0 100644 --- a/src/oracle_test/regress/expected/foreign_key.out +++ b/src/oracle_test/regress/expected/foreign_key.out @@ -1157,6 +1157,59 @@ INSERT INTO fktable VALUES (500, 1000); ERROR: insert or update on table "fktable" violates foreign key constraint "fktable_fk_fkey" DETAIL: Key (fk)=(1000) is not present in table "pktable". COMMIT; +-- Check that the existing FK trigger is both deferrable and initially deferred +SELECT conname, tgrelid::regclass as tgrel, + regexp_replace(tgname, '[0-9]+', 'N') as tgname, tgtype, + tgdeferrable, tginitdeferred +FROM pg_trigger t JOIN pg_constraint c ON (t.tgconstraint = c.oid) +WHERE conrelid = 'fktable'::regclass AND conname = 'fktable_fk_fkey' +ORDER BY tgrelid, tgtype; + conname | tgrel | tgname | tgtype | tgdeferrable | tginitdeferred +-----------------+---------+--------------------------+--------+--------------+---------------- + fktable_fk_fkey | pktable | RI_ConstraintTrigger_a_N | 9 | t | t + fktable_fk_fkey | pktable | RI_ConstraintTrigger_a_N | 17 | t | t + fktable_fk_fkey | fktable | RI_ConstraintTrigger_c_N | 5 | t | t + fktable_fk_fkey | fktable | RI_ConstraintTrigger_c_N | 17 | t | t +(4 rows) + +-- Changing the constraint to NOT ENFORCED drops the associated FK triggers +ALTER TABLE FKTABLE ALTER CONSTRAINT fktable_fk_fkey NOT ENFORCED; +SELECT conname, tgrelid::regclass as tgrel, + regexp_replace(tgname, '[0-9]+', 'N') as tgname, tgtype, + tgdeferrable, tginitdeferred +FROM pg_trigger t JOIN pg_constraint c ON (t.tgconstraint = c.oid) +WHERE conrelid = 'fktable'::regclass AND conname = 'fktable_fk_fkey' +ORDER BY tgrelid, tgtype; + conname | tgrel | tgname | tgtype | tgdeferrable | tginitdeferred +---------+-------+--------+--------+--------------+---------------- +(0 rows) + +-- Changing it back to ENFORCED will recreate the necessary FK triggers +-- that are deferrable and initially deferred +ALTER TABLE FKTABLE ALTER CONSTRAINT fktable_fk_fkey ENFORCED; +SELECT conname, tgrelid::regclass as tgrel, + regexp_replace(tgname, '[0-9]+', 'N') as tgname, tgtype, + tgdeferrable, tginitdeferred +FROM pg_trigger t JOIN pg_constraint c ON (t.tgconstraint = c.oid) +WHERE conrelid = 'fktable'::regclass AND conname = 'fktable_fk_fkey' +ORDER BY tgrelid, tgtype; + conname | tgrel | tgname | tgtype | tgdeferrable | tginitdeferred +-----------------+---------+--------------------------+--------+--------------+---------------- + fktable_fk_fkey | pktable | RI_ConstraintTrigger_a_N | 9 | t | t + fktable_fk_fkey | pktable | RI_ConstraintTrigger_a_N | 17 | t | t + fktable_fk_fkey | fktable | RI_ConstraintTrigger_c_N | 5 | t | t + fktable_fk_fkey | fktable | RI_ConstraintTrigger_c_N | 17 | t | t +(4 rows) + +-- Verify that a deferrable, initially deferred foreign key still works +-- as expected after being set to NOT ENFORCED and then re-enabled +BEGIN; +-- doesn't match PK, but no error yet +INSERT INTO fktable VALUES (2, 20); +-- should catch error from INSERT at commit +COMMIT; +ERROR: insert or update on table "fktable" violates foreign key constraint "fktable_fk_fkey" +DETAIL: Key (fk)=(20) is not present in table "pktable". DROP TABLE fktable, pktable; -- tricky behavior: according to SQL99, if a deferred constraint is set -- to 'immediate' mode, it should be checked for validity *immediately*, diff --git a/src/oracle_test/regress/expected/generated_stored.out b/src/oracle_test/regress/expected/generated_stored.out index 5863876d360..0db45e0b4cd 100644 --- a/src/oracle_test/regress/expected/generated_stored.out +++ b/src/oracle_test/regress/expected/generated_stored.out @@ -1510,6 +1510,40 @@ CREATE TABLE gtest28b (LIKE gtest28a INCLUDING GENERATED); c | pg_catalog.int4 | | | x | pg_catalog.int4 | | | generated always as (b * 2) stored +-- rule actions referring to generated columns: +-- NEW.b in a rule action should reflect the generated column's new value +CREATE TABLE gtest_rule (a int, b int GENERATED ALWAYS AS (a * 2) STORED); +CREATE TABLE gtest_rule_log (op text, old_b int, new_b int); +CREATE RULE gtest_rule_upd AS ON UPDATE TO gtest_rule + DO ALSO INSERT INTO gtest_rule_log VALUES ('UPD', OLD.b, NEW.b); +CREATE RULE gtest_rule_ins AS ON INSERT TO gtest_rule + DO ALSO INSERT INTO gtest_rule_log VALUES ('INS', NULL, NEW.b); +INSERT INTO gtest_rule (a) VALUES (1); +UPDATE gtest_rule SET a = 10; +UPDATE gtest_rule SET a = (SELECT max(b) FROM gtest_rule); +SELECT * FROM gtest_rule_log; + op | old_b | new_b +-----+-------+------- + INS | | 2 + UPD | 2 | 20 + UPD | 20 | 40 +(3 rows) + +DROP RULE gtest_rule_upd ON gtest_rule; +DROP RULE gtest_rule_ins ON gtest_rule; +DROP TABLE gtest_rule_log; +-- rule quals referring to generated columns: +-- NEW.b in the rule qual should reflect the generated column's new value +CREATE RULE gtest_rule_qual AS ON UPDATE TO gtest_rule WHERE NEW.b > 100 + DO INSTEAD NOTHING; +UPDATE gtest_rule SET a = 100; +SELECT * FROM gtest_rule; + a | b +----+---- + 20 | 40 +(1 row) + +DROP TABLE gtest_rule; -- sanity check of system catalog SELECT attrelid, attname, attgenerated FROM pg_attribute WHERE attgenerated NOT IN ('', 's', 'v'); attrelid | attname | attgenerated diff --git a/src/oracle_test/regress/expected/generated_virtual.out b/src/oracle_test/regress/expected/generated_virtual.out index 7e677192440..e8277289cb1 100644 --- a/src/oracle_test/regress/expected/generated_virtual.out +++ b/src/oracle_test/regress/expected/generated_virtual.out @@ -1488,6 +1488,40 @@ CREATE TABLE gtest28b (LIKE gtest28a INCLUDING GENERATED); c | pg_catalog.int4 | | | x | pg_catalog.int4 | | | generated always as (b * 2) +-- rule actions referring to generated columns: +-- NEW.b in a rule action should reflect the generated column's new value +CREATE TABLE gtest_rule (a int, b int GENERATED ALWAYS AS (a * 2) VIRTUAL); +CREATE TABLE gtest_rule_log (op text, old_b int, new_b int); +CREATE RULE gtest_rule_upd AS ON UPDATE TO gtest_rule + DO ALSO INSERT INTO gtest_rule_log VALUES ('UPD', OLD.b, NEW.b); +CREATE RULE gtest_rule_ins AS ON INSERT TO gtest_rule + DO ALSO INSERT INTO gtest_rule_log VALUES ('INS', NULL, NEW.b); +INSERT INTO gtest_rule (a) VALUES (1); +UPDATE gtest_rule SET a = 10; +UPDATE gtest_rule SET a = (SELECT max(b) FROM gtest_rule); +SELECT * FROM gtest_rule_log; + op | old_b | new_b +-----+-------+------- + INS | | 2 + UPD | 2 | 20 + UPD | 20 | 40 +(3 rows) + +DROP RULE gtest_rule_upd ON gtest_rule; +DROP RULE gtest_rule_ins ON gtest_rule; +DROP TABLE gtest_rule_log; +-- rule quals referring to generated columns: +-- NEW.b in the rule qual should reflect the generated column's new value +CREATE RULE gtest_rule_qual AS ON UPDATE TO gtest_rule WHERE NEW.b > 100 + DO INSTEAD NOTHING; +UPDATE gtest_rule SET a = 100; +SELECT * FROM gtest_rule; + a | b +----+---- + 20 | 40 +(1 row) + +DROP TABLE gtest_rule; -- sanity check of system catalog SELECT attrelid, attname, attgenerated FROM pg_attribute WHERE attgenerated NOT IN ('', 's', 'v'); attrelid | attname | attgenerated @@ -1652,3 +1686,81 @@ select * from gtest33 where b is null; reset constraint_exclusion; drop table gtest33; +-- Ensure that EXCLUDED. in INSERT ... ON CONFLICT +-- DO UPDATE is expanded to the generation expression, both for plain and +-- partitioned target relations. +create table gtest34 (id int primary key, a int, + c int generated always as (a * 10) virtual); +insert into gtest34 values (1, 5); +insert into gtest34 values (1, 7) + on conflict (id) do update set a = excluded.c returning *; + id | a | c +----+----+----- + 1 | 70 | 700 +(1 row) + +insert into gtest34 values (1, 2) + on conflict (id) do update set a = gtest34.c + excluded.c returning *; + id | a | c +----+-----+------ + 1 | 720 | 7200 +(1 row) + +insert into gtest34 values (1, 3) + on conflict (id) do update set a = 999 where excluded.c > 20 returning *; + id | a | c +----+-----+------ + 1 | 999 | 9990 +(1 row) + +drop table gtest34; +create table gtest34p (id int primary key, a int, + c int generated always as (a * 10) virtual) + partition by range (id); +create table gtest34p_1 partition of gtest34p for values from (1) to (100); +insert into gtest34p values (1, 5); +insert into gtest34p values (1, 7) + on conflict (id) do update set a = excluded.c returning *; + id | a | c +----+----+----- + 1 | 70 | 700 +(1 row) + +insert into gtest34p values (1, 2) + on conflict (id) do update set a = gtest34p.c + excluded.c returning *; + id | a | c +----+-----+------ + 1 | 720 | 7200 +(1 row) + +drop table gtest34p; +-- Ensure that virtual generated columns work with WHERE CURRENT OF +create table gtest_cursor (id int primary key, a int, b int generated always as (a * 2) virtual); +insert into gtest_cursor values (1, 10), (2, 20), (3, 30); +begin; +declare curs cursor for select * from gtest_cursor order by id for update; +fetch 1 from curs; + id | a | b +----+----+---- + 1 | 10 | 20 +(1 row) + +update gtest_cursor set a = 99 where current of curs; +select * from gtest_cursor order by id; + id | a | b +----+----+----- + 1 | 99 | 198 + 2 | 20 | 40 + 3 | 30 | 60 +(3 rows) + +delete from gtest_cursor where current of curs; +select * from gtest_cursor order by id; + id | a | b +----+----+---- + 2 | 20 | 40 + 3 | 30 | 60 +(2 rows) + +commit; +drop table gtest_cursor; diff --git a/src/oracle_test/regress/expected/indexing.out b/src/oracle_test/regress/expected/indexing.out index c74e937a02f..5b4069ef6bd 100644 --- a/src/oracle_test/regress/expected/indexing.out +++ b/src/oracle_test/regress/expected/indexing.out @@ -540,6 +540,111 @@ select relname, indisvalid from pg_class join pg_index on indexrelid = oid idxpart_a_idx | t (3 rows) +drop table idxpart; +-- Verify that re-attaching an already-attached partition index can +-- validate the parent index if it was still invalid, including +-- indirect ancestors in subpartitions. +create table idxpart (a int, b int) partition by range (a); +create table idxpart1 partition of idxpart for values from (0) to (1000) partition by range (a); +create table idxpart11 partition of idxpart1 for values from (0) to (500); +-- Partitioned table with no partitions +create table idxpart2 partition of idxpart for values from (1000) to (2000) partition by range (a); +-- create parent indexes +create index on only idxpart ((a/b)); +create index on only idxpart1 ((a/b)); +create index on only idxpart2 ((a/b)); +-- fail, leaves behind an invalid index on the leaf partition +insert into idxpart11 values (1, 0); +create index concurrently on idxpart11 ((a/b)); +ERROR: division by zero +select relname, indisvalid from pg_class join pg_index on indexrelid = oid + where relname like 'idxpart%' order by relname; + relname | indisvalid +--------------------+------------ + idxpart11_expr_idx | f + idxpart1_expr_idx | f + idxpart2_expr_idx | t + idxpart_expr_idx | f +(4 rows) + +-- attach the indexes; parents stay invalid +alter index idxpart1_expr_idx attach partition idxpart11_expr_idx; +alter index idxpart_expr_idx attach partition idxpart1_expr_idx; +alter index idxpart_expr_idx attach partition idxpart2_expr_idx; +select relname, indisvalid from pg_class join pg_index on indexrelid = oid + where relname like 'idxpart%' order by relname; + relname | indisvalid +--------------------+------------ + idxpart11_expr_idx | f + idxpart1_expr_idx | f + idxpart2_expr_idx | t + idxpart_expr_idx | f +(4 rows) + +-- fix the index on the leaf partition +delete from idxpart11 where b = 0; +reindex index concurrently idxpart11_expr_idx; +-- reattach the leaf partition index; parents should now be valid +alter index idxpart1_expr_idx attach partition idxpart11_expr_idx; +select relname, indisvalid from pg_class join pg_index on indexrelid = oid + where relname like 'idxpart%' order by relname; + relname | indisvalid +--------------------+------------ + idxpart11_expr_idx | t + idxpart1_expr_idx | t + idxpart2_expr_idx | t + idxpart_expr_idx | t +(4 rows) + +drop table idxpart; +-- Verify that re-attaching does not validate the parent when another +-- child index is still invalid. +create table idxpart (a int, b int) partition by range (a); +create table idxpart1 partition of idxpart for values from (0) to (500); +create table idxpart2 partition of idxpart for values from (500) to (1000); +create index on only idxpart ((a/b)); +-- create invalid indexes on both children +insert into idxpart1 values (1, 0); +insert into idxpart2 values (501, 0); +create index concurrently on idxpart1 ((a/b)); +ERROR: division by zero +create index concurrently on idxpart2 ((a/b)); +ERROR: division by zero +select relname, indisvalid from pg_class join pg_index on indexrelid = oid + where relname like 'idxpart%' order by relname; + relname | indisvalid +-------------------+------------ + idxpart1_expr_idx | f + idxpart2_expr_idx | f + idxpart_expr_idx | f +(3 rows) + +-- attach both; parent stays invalid +alter index idxpart_expr_idx attach partition idxpart1_expr_idx; +alter index idxpart_expr_idx attach partition idxpart2_expr_idx; +select relname, indisvalid from pg_class join pg_index on indexrelid = oid + where relname like 'idxpart%' order by relname; + relname | indisvalid +-------------------+------------ + idxpart1_expr_idx | f + idxpart2_expr_idx | f + idxpart_expr_idx | f +(3 rows) + +-- fix only idxpart1's index, leave idxpart2's still invalid +delete from idxpart1 where b = 0; +reindex index concurrently idxpart1_expr_idx; +-- re-attach the fixed child; parent should stay invalid +alter index idxpart_expr_idx attach partition idxpart1_expr_idx; +select relname, indisvalid from pg_class join pg_index on indexrelid = oid + where relname like 'idxpart%' order by relname; + relname | indisvalid +-------------------+------------ + idxpart1_expr_idx | t + idxpart2_expr_idx | f + idxpart_expr_idx | f +(3 rows) + drop table idxpart; -- verify dependency handling during ALTER TABLE DETACH PARTITION create table idxpart (a int) partition by range (a); diff --git a/src/oracle_test/regress/expected/join.out b/src/oracle_test/regress/expected/join.out index 2225517fa0a..ddc381779e9 100644 --- a/src/oracle_test/regress/expected/join.out +++ b/src/oracle_test/regress/expected/join.out @@ -6130,6 +6130,45 @@ from int8_tbl t1 -> Seq Scan on onek t4 (13 rows) +-- bug #19460: we need to clean up RestrictInfos more than we had been doing +explain (costs off) +select * from + (select 1::int as id) as lhs +full join + (select dummy_source.id + from (select null::int as id) as dummy_source + left join (select a.id from a where a.id = 42) as sub + on sub.id = dummy_source.id + ) as rhs +on lhs.id = rhs.id; + QUERY PLAN +---------------------------------------------- + Hash Full Join + Hash Cond: ((1) = (NULL::pg_catalog.int4)) + -> Result + -> Hash + -> Result +(5 rows) + +explain (costs off) +select * from + (select 1::int as id) as lhs +full join + (select dummy_source.id + from (select 2::int as id) as dummy_source + left join (select a.id from a) as sub + on sub.id = dummy_source.id + ) as rhs +on lhs.id = rhs.id; + QUERY PLAN +-------------------------- + Hash Full Join + Hash Cond: ((1) = (2)) + -> Result + -> Hash + -> Result +(5 rows) + -- More tests of correct placement of pseudoconstant quals -- simple constant-false condition explain (costs off) @@ -7900,6 +7939,22 @@ WHERE q0.a = 1; -> Seq Scan on sj n1 (7 rows) +-- Do not forget to replace relid in bare Var join clause (bug #19435) +ALTER TABLE sl ADD COLUMN bool_col boolean; +EXPLAIN (COSTS OFF) +SELECT 1 AS c1 FROM sl sl1 LEFT JOIN (sl AS sl2 NATURAL JOIN sl AS sl3) + ON sl2.bool_col LEFT JOIN sl AS sl4 ON sl2.bool_col; + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------- + Nested Loop Left Join + -> Seq Scan on sl sl1 + -> Nested Loop Left Join + Join Filter: sl3.bool_col + -> Seq Scan on sl sl3 + Filter: (bool_col AND (a IS NOT NULL) AND (b IS NOT NULL) AND (c IS NOT NULL) AND (bool_col IS NOT NULL)) + -> Seq Scan on sl sl4 +(7 rows) + -- Check optimization disabling if it will violate special join conditions. -- Two identical joined relations satisfies self join removal conditions but -- stay in different special join infos. diff --git a/src/oracle_test/regress/expected/multirangetypes.out b/src/oracle_test/regress/expected/multirangetypes.out index 26ecd438c33..f0b7b49abea 100644 --- a/src/oracle_test/regress/expected/multirangetypes.out +++ b/src/oracle_test/regress/expected/multirangetypes.out @@ -3146,6 +3146,22 @@ drop type textrange1; reset role; drop role regress_multirange_owner; -- +-- CREATE TYPE checks for CREATE on multirange schema +-- +create role regress_mr; +create schema mr_sch; +set role regress_mr; +create type mytype as range (subtype=int4, multirange_type_name=mr_sch.mr_type); +ERROR: permission denied for schema mr_sch +reset role; +grant create on schema mr_sch to regress_mr; +set role regress_mr; +create type mytype as range (subtype=int4, multirange_type_name=mr_sch.mr_type); +reset role; +drop type mytype; +drop schema mr_sch; +drop role regress_mr; +-- -- Test polymorphic type system -- create function anyarray_anymultirange_func(a anyarray, r anymultirange) @@ -3306,6 +3322,9 @@ select *, row_to_json(upper(t)) as u from {["(5,6)","(7,8)")} | {"a":7,"b":8} (2 rows) +-- this must be rejected to avoid self-inclusion issues: +alter type two_ints add attribute c two_ints_multirange; +ERROR: composite type two_ints cannot be made a member of itself drop type two_ints cascade; NOTICE: drop cascades to type two_ints_range -- diff --git a/src/oracle_test/regress/expected/partition_prune.out b/src/oracle_test/regress/expected/partition_prune.out index 7b1274db093..627578d92b6 100644 --- a/src/oracle_test/regress/expected/partition_prune.out +++ b/src/oracle_test/regress/expected/partition_prune.out @@ -4704,3 +4704,135 @@ select min(a) over (partition by a order by a) from part_abc where a >= stable_o drop view part_abc_view; drop table part_abc; +-- +-- Check that operands wrapped in PlaceHolderVars are matched to partition +-- keys, allowing partition pruning to occur. PlaceHolderVars can be +-- introduced when a subquery's output is used with grouping sets. +-- +create table phv_part (a int, b text) partition by list (a); +create table phv_part_1 partition of phv_part for values in (1); +create table phv_part_2 partition of phv_part for values in (2); +create table phv_part_null partition of phv_part for values in (null); +insert into phv_part values (1, 'one'), (2, 'two'), (null, 'null'); +-- OpExpr: PHV-wrapped operand matched via equal() +explain (costs off) +select * from (select a, b from phv_part) t + where a = 1 + group by grouping sets (a, b); + QUERY PLAN +--------------------------------------- + MixedAggregate + Hash Key: phv_part.b + Group Key: phv_part.a + -> Seq Scan on phv_part_1 phv_part + Filter: (a = 1) +(5 rows) + +select * from (select a, b from phv_part) t + where a = 1 + group by grouping sets (a, b); + a | b +---+----- + 1 | + | one +(2 rows) + +-- OpExpr with RelabelType: PHV wrapped around a casted column +explain (costs off) +select * from (select a::oid as x, b from phv_part) t + where x::int = 1 + group by grouping sets (x, b); + QUERY PLAN +--------------------------------------------------- + HashAggregate + Hash Key: (phv_part.a)::oid + Hash Key: phv_part.b + -> Seq Scan on phv_part_1 phv_part + Filter: (((a)::oid)::pg_catalog.int4 = 1) +(5 rows) + +select * from (select a::oid as x, b from phv_part) t + where x::int = 1 + group by grouping sets (x, b); + x | b +---+----- + 1 | + | one +(2 rows) + +-- ScalarArrayOpExpr: IN clause with PHV-wrapped operand +explain (costs off) +select * from (select a, b from phv_part) t + where a in (1, null) + group by grouping sets (a, b); + QUERY PLAN +----------------------------------------------------------- + HashAggregate + Hash Key: phv_part.a + Hash Key: phv_part.b + -> Seq Scan on phv_part_1 phv_part + Filter: (a = ANY ('{1,NULL}'::pg_catalog.int4[])) +(5 rows) + +select * from (select a, b from phv_part) t + where a in (1, null) + group by grouping sets (a, b); + a | b +---+----- + 1 | + | one +(2 rows) + +-- NullTest: IS NULL with PHV-wrapped operand +explain (costs off) +select * from (select a, b from phv_part) t + where a is null + group by grouping sets (a, b); + QUERY PLAN +------------------------------------------ + HashAggregate + Hash Key: phv_part.a + Hash Key: phv_part.b + -> Seq Scan on phv_part_null phv_part + Filter: (a IS NULL) +(5 rows) + +select * from (select a, b from phv_part) t + where a is null + group by grouping sets (a, b); + a | b +---+------ + | + | null +(2 rows) + +drop table phv_part; +-- BooleanTest: IS TRUE with PHV-wrapped boolean partition key +create table phv_boolpart (a bool, b text) partition by list (a); +create table phv_boolpart_t partition of phv_boolpart for values in (true); +create table phv_boolpart_f partition of phv_boolpart for values in (false); +create table phv_boolpart_null partition of phv_boolpart default; +insert into phv_boolpart values (true, 'yes'), (false, 'no'), (null, 'unknown'); +explain (costs off) +select * from (select a, b from phv_boolpart) t + where a is true + group by grouping sets (a, b); + QUERY PLAN +----------------------------------------------- + HashAggregate + Hash Key: phv_boolpart.a + Hash Key: phv_boolpart.b + -> Seq Scan on phv_boolpart_t phv_boolpart + Filter: (a IS TRUE) +(5 rows) + +select * from (select a, b from phv_boolpart) t + where a is true + group by grouping sets (a, b); + a | b +---+----- + t | + | yes +(2 rows) + +drop table phv_boolpart; diff --git a/src/oracle_test/regress/expected/portals.out b/src/oracle_test/regress/expected/portals.out index 70e57a0f2f1..fe019c3f827 100644 --- a/src/oracle_test/regress/expected/portals.out +++ b/src/oracle_test/regress/expected/portals.out @@ -1340,6 +1340,17 @@ FETCH FROM c1; DELETE FROM ucview WHERE CURRENT OF c1; -- fail, views not supported ERROR: WHERE CURRENT OF on a view is not implemented ROLLBACK; +BEGIN; +DECLARE c1 CURSOR FOR SELECT * FROM ucview; +FETCH FROM c1; + f1 | f2 +----+------- + 13 | three +(1 row) + +UPDATE ucview SET f1 = f1 + 10 WHERE CURRENT OF c1; -- fail, views not supported +ERROR: WHERE CURRENT OF on a view is not implemented +ROLLBACK; -- Check WHERE CURRENT OF with an index-only scan BEGIN; EXPLAIN (costs off) diff --git a/src/oracle_test/regress/expected/prepared_xacts.out b/src/oracle_test/regress/expected/prepared_xacts.out index 47cc5bd959e..6ba4cb41ab6 100644 --- a/src/oracle_test/regress/expected/prepared_xacts.out +++ b/src/oracle_test/regress/expected/prepared_xacts.out @@ -1,3 +1,7 @@ +SELECT current_setting('max_prepared_transactions')::integer < 2 AS skip_test \gset +\if :skip_test +\quit +\endif -- -- PREPARED TRANSACTIONS (two-phase commit) -- @@ -263,8 +267,37 @@ SELECT gid FROM pg_prepared_xacts WHERE gid ~ '^regress_' ORDER BY gid; ----- (0 rows) +-- Test row-level locks held by prepared transactions +CREATE TABLE pxtest_rowlock (id int PRIMARY KEY, data text); +INSERT INTO pxtest_rowlock VALUES (1, 'test data'); +BEGIN; +SELECT * FROM pxtest_rowlock WHERE id = 1 FOR SHARE; + id | data +----+----------- + 1 | test data +(1 row) + +PREPARE TRANSACTION 'regress_p1'; +-- Should fail because the row is locked +SELECT * FROM pxtest_rowlock WHERE id = 1 FOR UPDATE NOWAIT; +ERROR: could not obtain lock on row in relation "pxtest_rowlock" +-- Test prepared transactions that participate in multixacts. For +-- that, lock the same row again, creating a multixid. +BEGIN; +SELECT * FROM pxtest_rowlock WHERE id = 1 FOR SHARE; + id | data +----+----------- + 1 | test data +(1 row) + +PREPARE TRANSACTION 'regress_p2'; +-- Should fail because the row is locked +SELECT * FROM pxtest_rowlock WHERE id = 1 FOR UPDATE NOWAIT; +ERROR: could not obtain lock on row in relation "pxtest_rowlock" +ROLLBACK PREPARED 'regress_p1'; +ROLLBACK PREPARED 'regress_p2'; -- Clean up DROP TABLE pxtest2; -DROP TABLE pxtest3; -- will still be there if prepared xacts are disabled -ERROR: table "pxtest3" does not exist +-- pxtest3 was already dropped DROP TABLE pxtest4; +DROP TABLE pxtest_rowlock; diff --git a/src/oracle_test/regress/expected/prepared_xacts_1.out b/src/oracle_test/regress/expected/prepared_xacts_1.out index 6ad3d11898a..a21314768c3 100644 --- a/src/oracle_test/regress/expected/prepared_xacts_1.out +++ b/src/oracle_test/regress/expected/prepared_xacts_1.out @@ -1,266 +1,3 @@ --- --- PREPARED TRANSACTIONS (two-phase commit) --- --- We can't readily test persistence of prepared xacts within the --- regression script framework, unfortunately. Note that a crash --- isn't really needed ... stopping and starting the postmaster would --- be enough, but we can't even do that here. --- create a simple table that we'll use in the tests -CREATE TABLE pxtest1 (foobar VARCHAR(10)); -INSERT INTO pxtest1 VALUES ('aaa'); --- Test PREPARE TRANSACTION -BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; -UPDATE pxtest1 SET foobar = 'bbb' WHERE foobar = 'aaa'; -SELECT * FROM pxtest1; - foobar --------- - bbb -(1 row) - -PREPARE TRANSACTION 'regress_foo1'; -ERROR: prepared transactions are disabled -HINT: Set "max_prepared_transactions" to a nonzero value. -SELECT * FROM pxtest1; - foobar --------- - aaa -(1 row) - --- Test pg_prepared_xacts system view -SELECT gid FROM pg_prepared_xacts WHERE gid ~ '^regress_' ORDER BY gid; - gid ------ -(0 rows) - --- Test ROLLBACK PREPARED -ROLLBACK PREPARED 'regress_foo1'; -ERROR: prepared transaction with identifier "regress_foo1" does not exist -SELECT * FROM pxtest1; - foobar --------- - aaa -(1 row) - -SELECT gid FROM pg_prepared_xacts WHERE gid ~ '^regress_' ORDER BY gid; - gid ------ -(0 rows) - --- Test COMMIT PREPARED -BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; -INSERT INTO pxtest1 VALUES ('ddd'); -SELECT * FROM pxtest1; - foobar --------- - aaa - ddd -(2 rows) - -PREPARE TRANSACTION 'regress_foo2'; -ERROR: prepared transactions are disabled -HINT: Set "max_prepared_transactions" to a nonzero value. -SELECT * FROM pxtest1; - foobar --------- - aaa -(1 row) - -COMMIT PREPARED 'regress_foo2'; -ERROR: prepared transaction with identifier "regress_foo2" does not exist -SELECT * FROM pxtest1; - foobar --------- - aaa -(1 row) - --- Test duplicate gids -BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; -UPDATE pxtest1 SET foobar = 'eee' WHERE foobar = 'ddd'; -SELECT * FROM pxtest1; - foobar --------- - aaa -(1 row) - -PREPARE TRANSACTION 'regress_foo3'; -ERROR: prepared transactions are disabled -HINT: Set "max_prepared_transactions" to a nonzero value. -SELECT gid FROM pg_prepared_xacts WHERE gid ~ '^regress_' ORDER BY gid; - gid ------ -(0 rows) - -BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; -INSERT INTO pxtest1 VALUES ('fff'); --- This should fail, because the gid foo3 is already in use -PREPARE TRANSACTION 'regress_foo3'; -ERROR: prepared transactions are disabled -HINT: Set "max_prepared_transactions" to a nonzero value. -SELECT * FROM pxtest1; - foobar --------- - aaa -(1 row) - -ROLLBACK PREPARED 'regress_foo3'; -ERROR: prepared transaction with identifier "regress_foo3" does not exist -SELECT * FROM pxtest1; - foobar --------- - aaa -(1 row) - --- Test serialization failure (SSI) -BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; -UPDATE pxtest1 SET foobar = 'eee' WHERE foobar = 'ddd'; -SELECT * FROM pxtest1; - foobar --------- - aaa -(1 row) - -PREPARE TRANSACTION 'regress_foo4'; -ERROR: prepared transactions are disabled -HINT: Set "max_prepared_transactions" to a nonzero value. -SELECT gid FROM pg_prepared_xacts WHERE gid ~ '^regress_' ORDER BY gid; - gid ------ -(0 rows) - -BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; -SELECT * FROM pxtest1; - foobar --------- - aaa -(1 row) - --- This should fail, because the two transactions have a write-skew anomaly -INSERT INTO pxtest1 VALUES ('fff'); -PREPARE TRANSACTION 'regress_foo5'; -ERROR: prepared transactions are disabled -HINT: Set "max_prepared_transactions" to a nonzero value. -SELECT gid FROM pg_prepared_xacts WHERE gid ~ '^regress_' ORDER BY gid; - gid ------ -(0 rows) - -ROLLBACK PREPARED 'regress_foo4'; -ERROR: prepared transaction with identifier "regress_foo4" does not exist -SELECT gid FROM pg_prepared_xacts WHERE gid ~ '^regress_' ORDER BY gid; - gid ------ -(0 rows) - --- Clean up -DROP TABLE pxtest1; --- Test detection of session-level and xact-level locks on same object -BEGIN; -SELECT pg_advisory_lock(1); - pg_advisory_lock ------------------- - -(1 row) - -SELECT pg_advisory_xact_lock_shared(1); - pg_advisory_xact_lock_shared ------------------------------- - -(1 row) - -PREPARE TRANSACTION 'regress_foo6'; -- fails -ERROR: prepared transactions are disabled -HINT: Set "max_prepared_transactions" to a nonzero value. --- Test subtransactions -BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; - CREATE TABLE pxtest2 (a int); - INSERT INTO pxtest2 VALUES (1); - SAVEPOINT a; - INSERT INTO pxtest2 VALUES (2); - ROLLBACK TO a; - SAVEPOINT b; - INSERT INTO pxtest2 VALUES (3); -PREPARE TRANSACTION 'regress_sub1'; -ERROR: prepared transactions are disabled -HINT: Set "max_prepared_transactions" to a nonzero value. -CREATE TABLE pxtest3(fff int); --- Test shared invalidation -BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; - DROP TABLE pxtest3; - CREATE TABLE pxtest4 (a int); - INSERT INTO pxtest4 VALUES (1); - INSERT INTO pxtest4 VALUES (2); - DECLARE foo CURSOR FOR SELECT * FROM pxtest4; - -- Fetch 1 tuple, keeping the cursor open - FETCH 1 FROM foo; - a ---- - 1 -(1 row) - -PREPARE TRANSACTION 'regress_sub2'; -ERROR: prepared transactions are disabled -HINT: Set "max_prepared_transactions" to a nonzero value. --- No such cursor -FETCH 1 FROM foo; -ERROR: cursor "foo" does not exist --- Table doesn't exist, the creation hasn't been committed yet -SELECT * FROM pxtest2; -ERROR: relation "pxtest2" does not exist -LINE 1: SELECT * FROM pxtest2; - ^ --- There should be two prepared transactions -SELECT gid FROM pg_prepared_xacts WHERE gid ~ '^regress_' ORDER BY gid; - gid ------ -(0 rows) - --- pxtest3 should be locked because of the pending DROP -begin; -lock table pxtest3 in access share mode nowait; -rollback; --- Disconnect, we will continue testing in a different backend -\c - --- There should still be two prepared transactions -SELECT gid FROM pg_prepared_xacts WHERE gid ~ '^regress_' ORDER BY gid; - gid ------ -(0 rows) - --- pxtest3 should still be locked because of the pending DROP -begin; -lock table pxtest3 in access share mode nowait; -rollback; --- Commit table creation -COMMIT PREPARED 'regress_sub1'; -ERROR: prepared transaction with identifier "regress_sub1" does not exist -\d pxtest2 -SELECT * FROM pxtest2; -ERROR: relation "pxtest2" does not exist -LINE 1: SELECT * FROM pxtest2; - ^ --- There should be one prepared transaction -SELECT gid FROM pg_prepared_xacts WHERE gid ~ '^regress_' ORDER BY gid; - gid ------ -(0 rows) - --- Commit table drop -COMMIT PREPARED 'regress_sub2'; -ERROR: prepared transaction with identifier "regress_sub2" does not exist -SELECT * FROM pxtest3; - fff ------ -(0 rows) - --- There should be no prepared transactions -SELECT gid FROM pg_prepared_xacts WHERE gid ~ '^regress_' ORDER BY gid; - gid ------ -(0 rows) - --- Clean up -DROP TABLE pxtest2; -ERROR: table "pxtest2" does not exist -DROP TABLE pxtest3; -- will still be there if prepared xacts are disabled -DROP TABLE pxtest4; -ERROR: table "pxtest4" does not exist +SELECT current_setting('max_prepared_transactions')::integer < 2 AS skip_test \gset +\if :skip_test +\quit diff --git a/src/oracle_test/regress/expected/stats.out b/src/oracle_test/regress/expected/stats.out index 6eec7be1f44..f6f64a46408 100644 --- a/src/oracle_test/regress/expected/stats.out +++ b/src/oracle_test/regress/expected/stats.out @@ -879,6 +879,8 @@ SELECT (n_tup_ins + n_tup_upd) > 0 AS has_data FROM pg_stat_all_tables t (1 row) +-- stats_reset may not be set for datid=0 and shared objects in +-- pg_stat_database, so reset once. SELECT pg_stat_reset_single_table_counters('pg_shdescription'::regclass); pg_stat_reset_single_table_counters ------------------------------------- @@ -892,6 +894,22 @@ SELECT (n_tup_ins + n_tup_upd) > 0 AS has_data FROM pg_stat_all_tables f (1 row) +SELECT extract(epoch from stats_reset) AS shared_db_reset_before + FROM pg_stat_database WHERE datid = 0 \gset +-- Second reset for comparison. +SELECT pg_stat_reset_single_table_counters('pg_shdescription'::regclass); + pg_stat_reset_single_table_counters +------------------------------------- + +(1 row) + +SELECT extract(epoch from stats_reset) > :'shared_db_reset_before' AS has_updated + FROM pg_stat_database WHERE datid = 0; + has_updated +------------- + t +(1 row) + -- set back comment \if :{?description_before} COMMENT ON DATABASE :"datname" IS :'description_before'; diff --git a/src/oracle_test/regress/expected/stats_import.out b/src/oracle_test/regress/expected/stats_import.out index abe8005943c..b0048aa1970 100644 --- a/src/oracle_test/regress/expected/stats_import.out +++ b/src/oracle_test/regress/expected/stats_import.out @@ -625,6 +625,87 @@ AND attname = 'id'; stats_import | test | id | f | 0.23 | 5 | 0.6 | | | | | | | | | | (1 row) +-- warn: mcv / mcf array length mismatch (more vals), mcv-pair fails, rest get set +SELECT pg_catalog.pg_restore_attribute_stats( + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'id', + 'inherited', false::boolean, + 'null_frac', 0.24::real, + 'most_common_vals', '{2,1,3}'::text, + 'most_common_freqs', '{0.3,0.25}'::real[] + ); +WARNING: could not parse "most_common_vals": incorrect number of elements (same as "most_common_freqs" required) + pg_restore_attribute_stats +---------------------------- + f +(1 row) + +SELECT * +FROM pg_stats +WHERE schemaname = 'stats_import' +AND tablename = 'test' +AND inherited = false +AND attname = 'id'; + schemaname | tablename | attname | inherited | null_frac | avg_width | n_distinct | most_common_vals | most_common_freqs | histogram_bounds | correlation | most_common_elems | most_common_elem_freqs | elem_count_histogram | range_length_histogram | range_empty_frac | range_bounds_histogram +--------------+-----------+---------+-----------+-----------+-----------+------------+------------------+-------------------+------------------+-------------+-------------------+------------------------+----------------------+------------------------+------------------+------------------------ + stats_import | test | id | f | 0.24 | 5 | 0.6 | | | | | | | | | | +(1 row) + +-- warn: mcv / mcf array length mismatch (more freqs), mcv-pair fails, rest get set +SELECT pg_catalog.pg_restore_attribute_stats( + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'id', + 'inherited', false::boolean, + 'null_frac', 0.25::real, + 'most_common_vals', '{2,1}'::text, + 'most_common_freqs', '{0.3,0.25,0.05}'::real[] + ); +WARNING: could not parse "most_common_vals": incorrect number of elements (same as "most_common_freqs" required) + pg_restore_attribute_stats +---------------------------- + f +(1 row) + +SELECT * +FROM pg_stats +WHERE schemaname = 'stats_import' +AND tablename = 'test' +AND inherited = false +AND attname = 'id'; + schemaname | tablename | attname | inherited | null_frac | avg_width | n_distinct | most_common_vals | most_common_freqs | histogram_bounds | correlation | most_common_elems | most_common_elem_freqs | elem_count_histogram | range_length_histogram | range_empty_frac | range_bounds_histogram +--------------+-----------+---------+-----------+-----------+-----------+------------+------------------+-------------------+------------------+-------------+-------------------+------------------------+----------------------+------------------------+------------------+------------------------ + stats_import | test | id | f | 0.25 | 5 | 0.6 | | | | | | | | | | +(1 row) + +-- warn: most_common_vals is multi-dimensional, mcv-pair fails, rest get set +SELECT pg_catalog.pg_restore_attribute_stats( + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'id', + 'inherited', false::boolean, + 'null_frac', 0.26::real, + 'most_common_vals', '{{2,1},{3,4}}'::text, + 'most_common_freqs', '{0.3,0.25,0.05,0.04}'::real[] + ); +WARNING: "most_common_vals" must be a one-dimensional array + pg_restore_attribute_stats +---------------------------- + f +(1 row) + +SELECT * +FROM pg_stats +WHERE schemaname = 'stats_import' +AND tablename = 'test' +AND inherited = false +AND attname = 'id'; + schemaname | tablename | attname | inherited | null_frac | avg_width | n_distinct | most_common_vals | most_common_freqs | histogram_bounds | correlation | most_common_elems | most_common_elem_freqs | elem_count_histogram | range_length_histogram | range_empty_frac | range_bounds_histogram +--------------+-----------+---------+-----------+-----------+-----------+------------+------------------+-------------------+------------------+-------------+-------------------+------------------------+----------------------+------------------------+------------------+------------------------ + stats_import | test | id | f | 0.26 | 5 | 0.6 | | | | | | | | | | +(1 row) + -- ok: mcv+mcf SELECT pg_catalog.pg_restore_attribute_stats( 'schemaname', 'stats_import', @@ -647,7 +728,7 @@ AND inherited = false AND attname = 'id'; schemaname | tablename | attname | inherited | null_frac | avg_width | n_distinct | most_common_vals | most_common_freqs | histogram_bounds | correlation | most_common_elems | most_common_elem_freqs | elem_count_histogram | range_length_histogram | range_empty_frac | range_bounds_histogram --------------+-----------+---------+-----------+-----------+-----------+------------+------------------+-------------------+------------------+-------------+-------------------+------------------------+----------------------+------------------------+------------------+------------------------ - stats_import | test | id | f | 0.23 | 5 | 0.6 | {2,1,3} | {0.3,0.25,0.05} | | | | | | | | + stats_import | test | id | f | 0.26 | 5 | 0.6 | {2,1,3} | {0.3,0.25,0.05} | | | | | | | | (1 row) -- warn: NULL in histogram array, rest get set diff --git a/src/oracle_test/regress/expected/tsearch.out b/src/oracle_test/regress/expected/tsearch.out index c072f1c52e6..dc3cc34e69e 100644 --- a/src/oracle_test/regress/expected/tsearch.out +++ b/src/oracle_test/regress/expected/tsearch.out @@ -2146,6 +2146,16 @@ NOTICE: text-search query doesn't contain lexemes: "" foo bar (1 row) +-- Test for large values of StartSel, StopSel and FragmentDelimiter +SELECT ts_headline('english', 'foo barbar', to_tsquery('english', 'foo'), + 'StartSel=' || repeat('x', 32768)); +ERROR: value for "StartSel" is too long +SELECT ts_headline('english', 'foo barbar', to_tsquery('english', 'foo'), + 'StopSel=' || repeat('x', 32768)); +ERROR: value for "StopSel" is too long +SELECT ts_headline('english', 'foo barbar', to_tsquery('english', 'foo'), + 'FragmentDelimiter=' || repeat('x', 32768)); +ERROR: value for "FragmentDelimiter" is too long --Rewrite sub system CREATE TABLE test_tsquery (txtkeyword TEXT, txtsample TEXT); \set ECHO none diff --git a/src/oracle_test/regress/expected/union.out b/src/oracle_test/regress/expected/union.out index fb0cfb57c14..92e69132f50 100644 --- a/src/oracle_test/regress/expected/union.out +++ b/src/oracle_test/regress/expected/union.out @@ -1499,4 +1499,21 @@ on true limit 1; -> Result (6 rows) +-- Test handling of Vars with varno 0 in estimate_array_length +explain (verbose, costs off) +select null::int[] union all select null::int[] union all select null::bigint[]; + QUERY PLAN +----------------------------------------------------- + Append + -> Result + Output: (NULL::pg_catalog.int4[]) + -> Append + -> Result + Output: NULL::pg_catalog.int4[] + -> Result + Output: NULL::pg_catalog.int4[] + -> Result + Output: NULL::pg_catalog.int8[] +(10 rows) + reset ivorysql.enable_emptystring_to_null; diff --git a/src/oracle_test/regress/expected/window.out b/src/oracle_test/regress/expected/window.out index 2551659c779..19c2668127a 100644 --- a/src/oracle_test/regress/expected/window.out +++ b/src/oracle_test/regress/expected/window.out @@ -1357,6 +1357,97 @@ CREATE TEMP VIEW v_window AS ERROR: missing or invalid datetime field. SELECT pg_get_viewdef('v_window'); ERROR: relation "v_window" does not exist +-- test overflow frame specifications +SELECT sum(unique1) over (rows between current row and 9223372036854775807 following exclude current row), + unique1, four +FROM tenk1 WHERE unique1 < 10; + sum | unique1 | four +-----+---------+------ + 41 | 4 | 0 + 39 | 2 | 2 + 38 | 1 | 1 + 32 | 6 | 2 + 23 | 9 | 1 + 15 | 8 | 0 + 10 | 5 | 1 + 7 | 3 | 3 + 0 | 7 | 3 + | 0 | 0 +(10 rows) + +SELECT sum(unique1) over (rows between 9223372036854775807 following and 1 following), + unique1, four +FROM tenk1 WHERE unique1 < 10; + sum | unique1 | four +-----+---------+------ + | 4 | 0 + | 2 | 2 + | 1 | 1 + | 6 | 2 + | 9 | 1 + | 8 | 0 + | 5 | 1 + | 3 | 3 + | 7 | 3 + | 0 | 0 +(10 rows) + +SELECT last_value(unique1) over (ORDER BY four rows between current row and 9223372036854775807 following exclude current row), + unique1, four +FROM tenk1 WHERE unique1 < 10; + last_value | unique1 | four +------------+---------+------ + 7 | 0 | 0 + 7 | 8 | 0 + 7 | 4 | 0 + 7 | 5 | 1 + 7 | 9 | 1 + 7 | 1 | 1 + 7 | 6 | 2 + 7 | 2 | 2 + 7 | 3 | 3 + | 7 | 3 +(10 rows) + +-- These test GROUPS mode with an offset large enough to cause overflow when +-- added to currentgroup. Although the overflow doesn't produce visibly wrong +-- results (due to the incremental nature of group pointer advancement), we +-- still need to protect against it as signed integer overflow is undefined +-- behavior in C. +SELECT sum(unique1) over (ORDER BY four groups between current row and 9223372036854775807 following), + unique1, four +FROM tenk1 WHERE unique1 < 10; + sum | unique1 | four +-----+---------+------ + 45 | 0 | 0 + 45 | 8 | 0 + 45 | 4 | 0 + 33 | 5 | 1 + 33 | 9 | 1 + 33 | 1 | 1 + 18 | 6 | 2 + 18 | 2 | 2 + 10 | 3 | 3 + 10 | 7 | 3 +(10 rows) + +SELECT sum(unique1) over (ORDER BY four groups between 9223372036854775807 following and unbounded following), + unique1, four +FROM tenk1 WHERE unique1 < 10; + sum | unique1 | four +-----+---------+------ + | 0 | 0 + | 8 | 0 + | 4 | 0 + | 5 | 1 + | 9 | 1 + | 1 | 1 + | 6 | 2 + | 2 | 2 + | 3 | 3 + | 7 | 3 +(10 rows) + -- RANGE offset PRECEDING/FOLLOWING tests SELECT sum(unique1) over (order by four range between 2::int8 preceding and 1::int2 preceding), unique1, four diff --git a/src/oracle_test/regress/parallel_schedule b/src/oracle_test/regress/parallel_schedule index 3eaacaa15de..41ac7013d65 100644 --- a/src/oracle_test/regress/parallel_schedule +++ b/src/oracle_test/regress/parallel_schedule @@ -128,7 +128,12 @@ test: plancache limit plpgsql copy2 temp domain rangefuncs prepare conversion tr # The stats test resets stats, so nothing else needing stats access can be in # this group. # ---------- -test: partition_join partition_prune reloptions hash_part indexing partition_aggregate partition_info tuplesort explain compression memoize stats predicate numa +test: partition_join partition_prune reloptions hash_part indexing partition_aggregate partition_info tuplesort explain memoize stats predicate numa + +# ---------- +# Another group of parallel tests (compression) +# ---------- +test: compression compression_pglz # event_trigger depends on create_am and cannot run concurrently with # any test that runs DDL diff --git a/src/oracle_test/regress/pg_regress.c b/src/oracle_test/regress/pg_regress.c index b56650f45a2..c0a67a06fd8 100644 --- a/src/oracle_test/regress/pg_regress.c +++ b/src/oracle_test/regress/pg_regress.c @@ -699,7 +699,7 @@ static const char * get_expectfile(const char *testname, const char *file) { - char *file_type; + const char *file_type; _resultmap *rm; /* diff --git a/src/oracle_test/regress/regress.c b/src/oracle_test/regress/regress.c index bb52d783025..1de9a47342a 100644 --- a/src/oracle_test/regress/regress.c +++ b/src/oracle_test/regress/regress.c @@ -28,6 +28,7 @@ #include "catalog/pg_type.h" #include "commands/sequence.h" #include "commands/trigger.h" +#include "common/pg_lzcompress.h" #include "executor/executor.h" #include "executor/spi.h" #include "funcapi.h" @@ -1168,3 +1169,68 @@ test_relpath(PG_FUNCTION_ARGS) PG_RETURN_VOID(); } + +/* + * test_pglz_compress + * + * Compress the input using pglz_compress(). Only the "always" strategy is + * currently supported. + * + * Returns the compressed data, or NULL if compression fails. + */ +PG_FUNCTION_INFO_V1(test_pglz_compress); +Datum +test_pglz_compress(PG_FUNCTION_ARGS) +{ + bytea *input = PG_GETARG_BYTEA_PP(0); + char *source = VARDATA_ANY(input); + int32 slen = VARSIZE_ANY_EXHDR(input); + int32 maxout = PGLZ_MAX_OUTPUT(slen); + bytea *result; + int32 clen; + + result = (bytea *) palloc(maxout + VARHDRSZ); + clen = pglz_compress(source, slen, VARDATA(result), + PGLZ_strategy_always); + if (clen < 0) + PG_RETURN_NULL(); + + SET_VARSIZE(result, clen + VARHDRSZ); + PG_RETURN_BYTEA_P(result); +} + +/* + * test_pglz_decompress + * + * Decompress the input using pglz_decompress(). + * + * The second argument is the expected uncompressed data size. The third + * argument is here for the check_complete flag. + * + * Returns the decompressed data, or raises an error if decompression fails. + */ +PG_FUNCTION_INFO_V1(test_pglz_decompress); +Datum +test_pglz_decompress(PG_FUNCTION_ARGS) +{ + bytea *input = PG_GETARG_BYTEA_PP(0); + int32 rawsize = PG_GETARG_INT32(1); + bool check_complete = PG_GETARG_BOOL(2); + char *source = VARDATA_ANY(input); + int32 slen = VARSIZE_ANY_EXHDR(input); + bytea *result; + int32 dlen; + + if (rawsize < 0) + elog(ERROR, "rawsize must not be negative"); + + result = (bytea *) palloc(rawsize + VARHDRSZ); + + dlen = pglz_decompress(source, slen, VARDATA(result), + rawsize, check_complete); + if (dlen < 0) + elog(ERROR, "pglz_decompress failed"); + + SET_VARSIZE(result, dlen + VARHDRSZ); + PG_RETURN_BYTEA_P(result); +} diff --git a/src/oracle_test/regress/sql/aggregates.sql b/src/oracle_test/regress/sql/aggregates.sql index 27445998004..8e917f1e9e7 100644 --- a/src/oracle_test/regress/sql/aggregates.sql +++ b/src/oracle_test/regress/sql/aggregates.sql @@ -540,6 +540,23 @@ alter table t2 alter column z drop not null; create unique index t2_z_uidx on t2(z) nulls not distinct; explain (costs off) select y,z from t2 group by y,z; +-- A unique index proves uniqueness only under its own opfamily. When the +-- GROUP BY's eqop comes from a different opfamily with looser equality, +-- rows the index regards as distinct can collapse into one GROUP BY group, +-- so the index is not usable for removing redundant columns. +create type t_rec as (x numeric); +create temp table t_opf (a t_rec not null, b text); +create unique index on t_opf (a record_image_ops); +-- (1.0) and (1.00) are bytewise distinct but logically equal as records; +-- the index admits both, but GROUP BY a (default record_ops) would merge +-- them, so b must be retained as a grouping key. +insert into t_opf values (row(1.0)::t_rec, 'X'), (row(1.00)::t_rec, 'Y'); +explain (costs off) +select a, b from t_opf group by a, b order by b; +select a, b from t_opf group by a, b order by b; +drop table t_opf; +drop type t_rec; + drop table t1 cascade; drop table t2; drop table t3; @@ -568,6 +585,12 @@ select f2, count(*) from t1 x(x0,x1) left join (t1 left join t2 using(f2)) on (x0 = 0) group by f2; +-- check that we preserve join alias in GROUP BY expressions +create temp view v1 as +select f1::int from t1 left join t2 using (f1) group by f1; +select pg_get_viewdef('v1'::regclass); + +drop view v1; drop table t1, t2; -- diff --git a/src/oracle_test/regress/sql/alter_table.sql b/src/oracle_test/regress/sql/alter_table.sql index 63700d2030d..260267e4504 100644 --- a/src/oracle_test/regress/sql/alter_table.sql +++ b/src/oracle_test/regress/sql/alter_table.sql @@ -2338,6 +2338,14 @@ ALTER TABLE test_add_column \d test_add_column ALTER TABLE test_add_column ADD COLUMN IF NOT EXISTS c5 SERIAL CHECK (c5 > 10); +ALTER TABLE test_add_column + ADD c6 integer; -- omit COLUMN +ALTER TABLE test_add_column + ADD IF NOT EXISTS c6 integer; +ALTER TABLE test_add_column + DROP c6; -- omit COLUMN +ALTER TABLE test_add_column + DROP IF EXISTS c6; \d test_add_column* DROP TABLE test_add_column; \d test_add_column* diff --git a/src/oracle_test/regress/sql/collate.icu.utf8.sql b/src/oracle_test/regress/sql/collate.icu.utf8.sql index 9a7bc3fa70c..c7dc12baa13 100644 --- a/src/oracle_test/regress/sql/collate.icu.utf8.sql +++ b/src/oracle_test/regress/sql/collate.icu.utf8.sql @@ -615,6 +615,109 @@ CREATE UNIQUE INDEX ON test3cs (x); -- ok SELECT string_to_array('ABC,DEF,GHI' COLLATE case_sensitive, ',', 'abc'); SELECT string_to_array('ABCDEFGHI' COLLATE case_sensitive, NULL, 'b'); +-- +-- A unique index under one collation does not prove uniqueness under +-- another, so the planner must not use such a proof for any optimization. +-- + +-- Ensure that we do not use inner-unique join execution +EXPLAIN (VERBOSE, COSTS OFF) +SELECT * FROM test1cs t1, test3cs t2 +WHERE t1.x = t2.x COLLATE case_insensitive +ORDER BY 1, 2; + +SELECT * FROM test1cs t1, test3cs t2 +WHERE t1.x = t2.x COLLATE case_insensitive +ORDER BY 1, 2; + +-- Ensure that left-join is not removed +EXPLAIN (COSTS OFF) +SELECT t1.* FROM test3cs t1 + LEFT JOIN test3cs t2 ON t1.x = t2.x COLLATE case_insensitive +ORDER BY 1; + +SELECT t1.* FROM test3cs t1 + LEFT JOIN test3cs t2 ON t1.x = t2.x COLLATE case_insensitive +ORDER BY 1; + +-- Ensure that self-join is not removed +EXPLAIN (COSTS OFF) +SELECT * FROM test3cs t1, test3cs t2 +WHERE t1.x = t2.x COLLATE case_insensitive +ORDER BY 1, 2; + +SELECT * FROM test3cs t1, test3cs t2 +WHERE t1.x = t2.x COLLATE case_insensitive +ORDER BY 1, 2; + +-- Ensure that semijoin is not reduced to innerjoin +EXPLAIN (COSTS OFF) +SELECT * FROM test3cs t1 + WHERE EXISTS (SELECT 1 FROM test3cs t2 WHERE t1.x = t2.x COLLATE case_insensitive) +ORDER BY 1; + +SELECT * FROM test3cs t1 + WHERE EXISTS (SELECT 1 FROM test3cs t2 WHERE t1.x = t2.x COLLATE case_insensitive) +ORDER BY 1; + +-- +-- A DISTINCT / GROUP BY / set-op on a subquery does not prove uniqueness +-- under a different collation, so the planner must not use such a proof for +-- any optimization. +-- + +-- Ensure that we do not use inner-unique join execution +EXPLAIN (VERBOSE, COSTS OFF) +SELECT * FROM test1cs t1, (SELECT DISTINCT x FROM test3cs) t2 +WHERE t1.x = t2.x COLLATE case_insensitive +ORDER BY 1, 2; + +SELECT * FROM test1cs t1, (SELECT DISTINCT x FROM test3cs) t2 +WHERE t1.x = t2.x COLLATE case_insensitive +ORDER BY 1, 2; + +-- Same with GROUP BY +EXPLAIN (VERBOSE, COSTS OFF) +SELECT * FROM test1cs t1, (SELECT x FROM test3cs GROUP BY x) t2 +WHERE t1.x = t2.x COLLATE case_insensitive +ORDER BY 1, 2; + +SELECT * FROM test1cs t1, (SELECT x FROM test3cs GROUP BY x) t2 +WHERE t1.x = t2.x COLLATE case_insensitive +ORDER BY 1, 2; + +-- Same with set-op +EXPLAIN (VERBOSE, COSTS OFF) +SELECT * FROM test1cs t1, (SELECT x FROM test3cs UNION SELECT x FROM test3cs) t2 +WHERE t1.x = t2.x COLLATE case_insensitive +ORDER BY 1, 2; + +SELECT * FROM test1cs t1, (SELECT x FROM test3cs UNION SELECT x FROM test3cs) t2 +WHERE t1.x = t2.x COLLATE case_insensitive +ORDER BY 1, 2; + +-- Ensure that left-join is not removed +EXPLAIN (COSTS OFF) +SELECT t1.* FROM test3cs t1 + LEFT JOIN (SELECT DISTINCT x FROM test3cs) t2 ON t1.x = t2.x COLLATE case_insensitive +ORDER BY 1; + +SELECT t1.* FROM test3cs t1 + LEFT JOIN (SELECT DISTINCT x FROM test3cs) t2 ON t1.x = t2.x COLLATE case_insensitive +ORDER BY 1; + +-- Ensure that semijoin is not reduced to innerjoin +EXPLAIN (COSTS OFF) +SELECT * FROM test3cs t1 + WHERE EXISTS (SELECT 1 FROM (SELECT DISTINCT x FROM test3cs) t2 + WHERE t1.x = t2.x COLLATE case_insensitive) +ORDER BY 1; + +SELECT * FROM test3cs t1 + WHERE EXISTS (SELECT 1 FROM (SELECT DISTINCT x FROM test3cs) t2 + WHERE t1.x = t2.x COLLATE case_insensitive) +ORDER BY 1; + CREATE TABLE test1ci (x text COLLATE case_insensitive); CREATE TABLE test2ci (x text COLLATE case_insensitive); CREATE TABLE test3ci (x text COLLATE case_insensitive); @@ -645,6 +748,87 @@ CREATE UNIQUE INDEX ON test3ci (x); -- error SELECT string_to_array('ABC,DEF,GHI' COLLATE case_insensitive, ',', 'abc'); SELECT string_to_array('ABCDEFGHI' COLLATE case_insensitive, NULL, 'b'); +-- Test HAVING-to-WHERE pushdown with nondeterministic collations. +-- When a HAVING clause uses a different collation than the GROUP BY's +-- nondeterministic collation, it must not be pushed to WHERE, otherwise +-- aggregate results can change because the stricter filter eliminates rows +-- before grouping. + +-- Negative: collation conflict, HAVING must not be pushed to WHERE +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING x = 'abc' COLLATE case_sensitive; +SELECT x, count(*) FROM test3ci GROUP BY x HAVING x = 'abc' COLLATE case_sensitive; + +-- Positive: same collation, safe to push HAVING to WHERE +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING x = 'abc' COLLATE case_insensitive; +SELECT x, count(*) FROM test3ci GROUP BY x HAVING x = 'abc' COLLATE case_insensitive; + +-- Negative: function applied to grouped column with conflicting collation +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING upper(x) = 'ABC' COLLATE case_sensitive; +SELECT x, count(*) FROM test3ci GROUP BY x HAVING upper(x) = 'ABC' COLLATE case_sensitive; + +-- Positive: function with same collation as GROUP BY +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING upper(x) = 'ABC' COLLATE case_insensitive; +SELECT x, count(*) FROM test3ci GROUP BY x HAVING upper(x) = 'ABC' COLLATE case_insensitive; + +-- Negative: inner function has conflicting collation, even though outer +-- operator's collation matches GROUP BY due to a COLLATE override +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING upper(x COLLATE case_sensitive) COLLATE case_insensitive = 'ABC'; +SELECT x, count(*) FROM test3ci GROUP BY x HAVING upper(x COLLATE case_sensitive) COLLATE case_insensitive = 'ABC'; + +-- Mixed AND: conflicting clause stays in HAVING, safe clause pushed to WHERE +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING x = 'abc' COLLATE case_sensitive AND length(x) > 1; +SELECT x, count(*) FROM test3ci GROUP BY x HAVING x = 'abc' COLLATE case_sensitive AND length(x) > 1; + +-- Positive: AND of two safe clauses, both can be pushed +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING x = 'abc' COLLATE case_insensitive AND length(x) > 1; +SELECT x, count(*) FROM test3ci GROUP BY x HAVING x = 'abc' COLLATE case_insensitive AND length(x) > 1; + +-- Negative: OR with a conflicting clause: must stay in HAVING +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING x = 'abc' COLLATE case_sensitive OR x = 'def' COLLATE case_sensitive ORDER BY 1; +SELECT x, count(*) FROM test3ci GROUP BY x HAVING x = 'abc' COLLATE case_sensitive OR x = 'def' COLLATE case_sensitive ORDER BY 1; + +-- Negative: collation conflict inside a RowCompareExpr +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING ROW(x, 1) < ROW('ABC' COLLATE case_sensitive, 1) ORDER BY 1; +SELECT x, count(*) FROM test3ci GROUP BY x HAVING ROW(x, 1) < ROW('ABC' COLLATE case_sensitive, 1) ORDER BY 1; + +-- Negative: simple-CASE form with conflicting WHEN comparison collation +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING (CASE x WHEN 'abc' COLLATE case_sensitive THEN true ELSE false END); +SELECT x, count(*) FROM test3ci GROUP BY x HAVING (CASE x WHEN 'abc' COLLATE case_sensitive THEN true ELSE false END); + +-- Positive: simple-CASE form with matching collation, safe to push +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING (CASE x WHEN 'abc' COLLATE case_insensitive THEN true ELSE false END); +SELECT x, count(*) FROM test3ci GROUP BY x HAVING (CASE x WHEN 'abc' COLLATE case_insensitive THEN true ELSE false END); + +-- Negative: nested CASE with collation conflict +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING (CASE WHEN (CASE x WHEN 'abc' COLLATE case_sensitive THEN 1 ELSE 0 END) = 1 THEN true ELSE false END); +SELECT x, count(*) FROM test3ci GROUP BY x HAVING (CASE WHEN (CASE x WHEN 'abc' COLLATE case_sensitive THEN 1 ELSE 0 END) = 1 THEN true ELSE false END); + +-- Positive: conflicting collation but no grouping expression reference +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING current_setting('server_version') = 'abc' COLLATE case_sensitive; + +-- Positive: deterministic collation in GROUP BY: always safe to push, even if +-- HAVING uses a nondeterministic collation +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3cs GROUP BY x HAVING x = 'abc' COLLATE case_sensitive; +SELECT x, count(*) FROM test3cs GROUP BY x HAVING x = 'abc' COLLATE case_sensitive; + +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3cs GROUP BY x HAVING x = 'abc' COLLATE case_insensitive ORDER BY 1; +SELECT x, count(*) FROM test3cs GROUP BY x HAVING x = 'abc' COLLATE case_insensitive ORDER BY 1; + -- bpchar CREATE TABLE test1bpci (x char(3) COLLATE case_insensitive); CREATE TABLE test2bpci (x char(3) COLLATE case_insensitive); @@ -993,6 +1177,26 @@ RESET enable_partitionwise_aggregate; RESET max_parallel_workers_per_gather; RESET enable_incremental_sort; +-- +-- A unique index can prove functional dependency for GROUP BY column +-- removal only if its per-column collation agrees on equality with +-- the GROUP BY column's collation. An index built under a different +-- (deterministic) collation would otherwise let remove_useless_groupby_columns +-- drop other columns whose values still differ within a nondeterministic +-- group. +-- +CREATE TABLE groupby_collation_t (a text COLLATE case_insensitive NOT NULL, b text); +INSERT INTO groupby_collation_t VALUES ('foo', 'X'), ('FOO', 'Y'); +CREATE UNIQUE INDEX ON groupby_collation_t (a COLLATE "C"); + +-- Column b must NOT be dropped: under case_insensitive on a, 'foo' and +-- 'FOO' would merge, but they have distinct b values. +EXPLAIN (COSTS OFF) +SELECT a, b FROM groupby_collation_t GROUP BY a, b ORDER BY a, b; +SELECT a, b FROM groupby_collation_t GROUP BY a, b ORDER BY a, b; + +DROP TABLE groupby_collation_t; + -- virtual generated columns CREATE TABLE t5 ( a int, diff --git a/src/oracle_test/regress/sql/compression_pglz.sql b/src/oracle_test/regress/sql/compression_pglz.sql new file mode 100644 index 00000000000..389ce942278 --- /dev/null +++ b/src/oracle_test/regress/sql/compression_pglz.sql @@ -0,0 +1,55 @@ +-- +-- Tests for PGLZ compression +-- + +-- directory paths and dlsuffix are passed to us in environment variables +\getenv libdir PG_LIBDIR +\getenv dlsuffix PG_DLSUFFIX + +\set regresslib :libdir '/oraregress' :dlsuffix + +CREATE FUNCTION test_pglz_compress(bytea) + RETURNS bytea + AS :'regresslib' LANGUAGE C STRICT; +/ +CREATE FUNCTION test_pglz_decompress(bytea, int4, bool) + RETURNS bytea + AS :'regresslib' LANGUAGE C STRICT; +/ + +-- Round-trip with pglz: compress then decompress. +SELECT test_pglz_decompress(test_pglz_compress( + decode(repeat('abcd', 100), 'escape')), 400, false) = + decode(repeat('abcd', 100), 'escape') AS roundtrip_ok; +SELECT test_pglz_decompress(test_pglz_compress( + decode(repeat('abcd', 100), 'escape')), 400, true) = + decode(repeat('abcd', 100), 'escape') AS roundtrip_ok; + +-- Decompression with rawsize too large, fails to fill the destination +-- buffer. +SELECT test_pglz_decompress(test_pglz_compress( + decode(repeat('abcd', 100), 'escape')), 500, true); + +-- Decompression with rawsize too small, fails with source not fully +-- consumed. +SELECT test_pglz_decompress(test_pglz_compress( + decode(repeat('abcd', 100), 'escape')), 100, true); + +-- Corrupted compressed data. Set control bit with read of a match tag, +-- no data follows. +SELECT length(test_pglz_decompress('\x01'::bytea, 1024, false)) AS ctrl_only_len; +SELECT test_pglz_decompress('\x01'::bytea, 1024, true); + +-- Corrupted compressed data. Set control bit with read of a match tag, +-- 1 byte follows. +SELECT test_pglz_decompress('\x01ff'::bytea, 1024, false); +SELECT test_pglz_decompress('\x01ff'::bytea, 1024, true); + +-- Corrupted compressed data. Set control bit with match tag where length +-- nibble is 3 bytes (extended length), no data follows. +SELECT test_pglz_decompress('\x010f01'::bytea, 1024, false); +SELECT test_pglz_decompress('\x010f01'::bytea, 1024, true); + +-- Clean up +DROP FUNCTION test_pglz_compress; +DROP FUNCTION test_pglz_decompress; diff --git a/src/oracle_test/regress/sql/create_index.sql b/src/oracle_test/regress/sql/create_index.sql index dd23f2b3079..5c3be35d85f 100644 --- a/src/oracle_test/regress/sql/create_index.sql +++ b/src/oracle_test/regress/sql/create_index.sql @@ -45,6 +45,10 @@ CREATE INDEX six ON shighway USING btree (name text_ops); COMMENT ON INDEX six_wrong IS 'bad index'; COMMENT ON INDEX six IS 'good index'; COMMENT ON INDEX six IS NULL; +SELECT obj_description('six'::regclass, 'pg_class') IS NULL AS six_comment_is_null; +COMMENT ON INDEX six IS 'add the comment back'; +COMMENT ON INDEX six IS ''; -- empty string removes the comment, same as NULL +SELECT obj_description('six'::regclass, 'pg_class') IS NULL AS six_comment_is_null; -- -- BTREE partial indices diff --git a/src/oracle_test/regress/sql/create_role.sql b/src/oracle_test/regress/sql/create_role.sql index 4491a28a8ae..b22f9c6f50a 100644 --- a/src/oracle_test/regress/sql/create_role.sql +++ b/src/oracle_test/regress/sql/create_role.sql @@ -92,6 +92,13 @@ CREATE ROLE regress_hasprivs CREATEROLE LOGIN INHERIT CONNECTION LIMIT 5; -- ok, we should be able to modify a role we created COMMENT ON ROLE regress_hasprivs IS 'some comment'; +SELECT shobj_description('regress_hasprivs'::regrole, 'pg_authid') IS NOT NULL AS has_comment; +COMMENT ON ROLE regress_hasprivs IS NULL; +SELECT shobj_description('regress_hasprivs'::regrole, 'pg_authid') IS NULL AS no_comment; +COMMENT ON ROLE regress_hasprivs IS 'add the comment back'; +SELECT shobj_description('regress_hasprivs'::regrole, 'pg_authid') IS NOT NULL AS has_comment; +COMMENT ON ROLE regress_hasprivs IS ''; -- empty string removes the comment, same as NULL +SELECT shobj_description('regress_hasprivs'::regrole, 'pg_authid') IS NULL AS no_comment; ALTER ROLE regress_hasprivs RENAME TO regress_tenant; ALTER ROLE regress_tenant NOINHERIT NOLOGIN CONNECTION LIMIT 7; diff --git a/src/oracle_test/regress/sql/create_table_like.sql b/src/oracle_test/regress/sql/create_table_like.sql index 93389b57dbf..d52a93ef131 100644 --- a/src/oracle_test/regress/sql/create_table_like.sql +++ b/src/oracle_test/regress/sql/create_table_like.sql @@ -276,6 +276,32 @@ CREATE FOREIGN TABLE ctl_foreign_table2(LIKE ctl_table INCLUDING ALL) SERVER ctl SELECT attname, attcompression FROM pg_attribute WHERE attrelid = 'ctl_foreign_table2'::regclass and attnum > 0 ORDER BY attnum; +-- LIKE ... INCLUDING STATISTICS with dropped columns in the parent, +-- so stxkeys attnums are not contiguous. +CREATE TABLE ctl_stats3_parent (a int, b int, c int); +ALTER TABLE ctl_stats3_parent DROP COLUMN b; +CREATE STATISTICS ctl_stats3_stat ON a, c FROM ctl_stats3_parent; +CREATE TABLE ctl_stats3_child (LIKE ctl_stats3_parent INCLUDING STATISTICS); +CREATE TABLE ctl_stats4_parent (a int, b int, c int, d int); +ALTER TABLE ctl_stats4_parent DROP COLUMN b; +CREATE STATISTICS ctl_stats4_stat ON a, c FROM ctl_stats4_parent; +CREATE TABLE ctl_stats4_child (LIKE ctl_stats4_parent INCLUDING STATISTICS); +SELECT s.stxrelid::regclass AS relation, + array_agg(a.attname ORDER BY u.ord) AS stats_columns +FROM pg_statistic_ext s +CROSS JOIN LATERAL + unnest(s.stxkeys::int2[]) WITH ORDINALITY AS u(attnum, ord) +JOIN pg_attribute a + ON a.attrelid = s.stxrelid AND a.attnum = u.attnum +WHERE s.stxrelid IN ('ctl_stats3_child'::regclass, + 'ctl_stats4_child'::regclass) +GROUP BY s.stxrelid +ORDER BY s.stxrelid::regclass::text; +DROP TABLE ctl_stats3_parent; +DROP TABLE ctl_stats3_child; +DROP TABLE ctl_stats4_parent; +DROP TABLE ctl_stats4_child; + DROP TABLE ctl_table; DROP FOREIGN TABLE ctl_foreign_table1; DROP FOREIGN TABLE ctl_foreign_table2; diff --git a/src/oracle_test/regress/sql/expressions.sql b/src/oracle_test/regress/sql/expressions.sql index b29de6412a3..fed0a5f9c71 100644 --- a/src/oracle_test/regress/sql/expressions.sql +++ b/src/oracle_test/regress/sql/expressions.sql @@ -202,16 +202,110 @@ default for type myint using hash as function 1 myinthash(myint); create table inttest (a myint); -insert into inttest values(1::myint),(null); - --- try an array with enough elements to cause hashing -select * from inttest where a in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint,9::myint, null); -select * from inttest where a not in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint,9::myint, null); -select * from inttest where a not in (0::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint,9::myint, null); --- ensure the result matched with the non-hashed version. We simply remove --- some array elements so that we don't reach the hashing threshold. -select * from inttest where a in (1::myint,2::myint,3::myint,4::myint,5::myint, null); -select * from inttest where a not in (1::myint,2::myint,3::myint,4::myint,5::myint, null); -select * from inttest where a not in (0::myint,2::myint,3::myint,4::myint,5::myint, null); +insert into inttest values (null), (0::myint), (1::myint); + +-- Test EEOP_HASHED_SCALARARRAYOP against EEOP_SCALARARRAYOP. Ensure the +-- result of non-hashed vs hashed is the same. +select + a, + a in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as not_hashed, + a in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint,9::myint) as hashed +from inttest; + +select + a, + a in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint) as not_hashed, + a in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as hashed + from inttest; + +select + a, + a not in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as not_hashed, + a not in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint,9::myint) as hashed +from inttest; + +select + a, + a not in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint) as not_hashed, + a not in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as hashed +from inttest; + +-- Now make the equal function return false when given two NULLs +create or replace function myinteq(myint, myint) returns bool as $$ +begin + if $1 is null and $2 is null then + return false; + else + return $1::int = $2::int; + end if; +end; +$$ language plpgsql immutable; +/ + +-- And try the same again to ensure EEOP_HASHED_SCALARARRAYOP does the same +-- thing as EEOP_SCALARARRAYOP. +select + a, + a in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as not_hashed, + a in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint,9::myint) as hashed +from inttest; + +select + a, + a in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint) as not_hashed, + a in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as hashed + from inttest; + +select + a, + a not in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as not_hashed, + a not in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint,9::myint) as hashed +from inttest; + +select + a, + a not in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint) as not_hashed, + a not in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as hashed +from inttest; + +-- Try again with an equality function that treats NULLs as equal to 0. +create or replace function myinteq(myint, myint) returns bool as $$ +begin + if $1 is null and $2 is null then + return false; + else + return coalesce($1::int,0) = coalesce($2::int, 0); + end if; +end; +$$ language plpgsql immutable; +/ + +select + a, + a in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as not_hashed, + a in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint,9::myint) as hashed, + a in (0::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint) as not_hashed_zero, + a in (0::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as hashed_zero +from inttest; + +select + a, + a in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint) as not_hashed, + a in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as hashed + from inttest; + +select + a, + a not in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as not_hashed, + a not in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint,9::myint) as hashed, + a not in (0::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint) as not_hashed_zero, + a not in (0::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as hashed_zero +from inttest; + +select + a, + a not in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint) as not_hashed, + a not in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as hashed +from inttest; rollback; diff --git a/src/oracle_test/regress/sql/foreign_data.sql b/src/oracle_test/regress/sql/foreign_data.sql index f0cc6ae8309..51dd210b9e1 100644 --- a/src/oracle_test/regress/sql/foreign_data.sql +++ b/src/oracle_test/regress/sql/foreign_data.sql @@ -69,6 +69,11 @@ CREATE FUNCTION invalid_fdw_handler() RETURNS int LANGUAGE SQL AS 'SELECT 1;'; CREATE FOREIGN DATA WRAPPER test_fdw HANDLER invalid_fdw_handler; -- ERROR CREATE FOREIGN DATA WRAPPER test_fdw HANDLER test_fdw_handler HANDLER invalid_fdw_handler; -- ERROR CREATE FOREIGN DATA WRAPPER test_fdw HANDLER test_fdw_handler; + +-- should preserve dependency on test_fdw_handler +ALTER FOREIGN DATA WRAPPER test_fdw VALIDATOR postgresql_fdw_validator; +DROP FUNCTION test_fdw_handler(); -- ERROR + DROP FOREIGN DATA WRAPPER test_fdw; -- ALTER FOREIGN DATA WRAPPER @@ -385,10 +390,12 @@ COMMENT ON COLUMN ft1.c1 IS NULL; ALTER FOREIGN TABLE ft1 ADD COLUMN c4 integer; ALTER FOREIGN TABLE ft1 ADD COLUMN c5 integer DEFAULT 0; ALTER FOREIGN TABLE ft1 ADD COLUMN c6 integer; +ALTER FOREIGN TABLE ft1 ADD COLUMN IF NOT EXISTS c6 integer; ALTER FOREIGN TABLE ft1 ADD COLUMN c7 integer NOT NULL; ALTER FOREIGN TABLE ft1 ADD COLUMN c8 integer; ALTER FOREIGN TABLE ft1 ADD COLUMN c9 integer; ALTER FOREIGN TABLE ft1 ADD COLUMN c10 integer OPTIONS (p1 'v1'); +ALTER FOREIGN TABLE ft1 ADD c11 integer; ALTER FOREIGN TABLE ft1 ALTER COLUMN c4 SET DEFAULT 0; ALTER FOREIGN TABLE ft1 ALTER COLUMN c5 DROP DEFAULT; @@ -421,6 +428,7 @@ ALTER FOREIGN TABLE ft1 OPTIONS (DROP delimiter, SET quote '~', ADD escape '@'); ALTER FOREIGN TABLE ft1 DROP COLUMN no_column; -- ERROR ALTER FOREIGN TABLE ft1 DROP COLUMN IF EXISTS no_column; ALTER FOREIGN TABLE ft1 DROP COLUMN c9; +ALTER FOREIGN TABLE ft1 DROP c11; ALTER FOREIGN TABLE ft1 ADD COLUMN c11 serial; ALTER FOREIGN TABLE ft1 SET SCHEMA foreign_schema; ALTER FOREIGN TABLE ft1 SET TABLESPACE ts; -- ERROR @@ -432,10 +440,12 @@ ALTER FOREIGN TABLE foreign_schema.ft1 RENAME TO foreign_table_1; -- alter noexisting table ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 ADD COLUMN c4 integer; ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 ADD COLUMN c6 integer; +ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 ADD COLUMN IF NOT EXISTS c6 integer; ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 ADD COLUMN c7 integer NOT NULL; ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 ADD COLUMN c8 integer; ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 ADD COLUMN c9 integer; ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 ADD COLUMN c10 integer OPTIONS (p1 'v1'); +ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 ADD c11 integer; ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 ALTER COLUMN c6 SET NOT NULL; ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 ALTER COLUMN c7 DROP NOT NULL; @@ -449,8 +459,10 @@ ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 DROP CONSTRAINT IF EXISTS no_cons ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 DROP CONSTRAINT ft1_c1_check; ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 OWNER TO regress_test_role; ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 OPTIONS (DROP delimiter, SET quote '~', ADD escape '@'); +ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 DROP COLUMN no_column; ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 DROP COLUMN IF EXISTS no_column; ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 DROP COLUMN c9; +ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 DROP c11; ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 SET SCHEMA foreign_schema; ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 RENAME c1 TO foreign_column_1; ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 RENAME TO foreign_table_1; diff --git a/src/oracle_test/regress/sql/foreign_key.sql b/src/oracle_test/regress/sql/foreign_key.sql index d65ee2f596e..9b33612a3fb 100644 --- a/src/oracle_test/regress/sql/foreign_key.sql +++ b/src/oracle_test/regress/sql/foreign_key.sql @@ -784,6 +784,43 @@ INSERT INTO fktable VALUES (500, 1000); COMMIT; +-- Check that the existing FK trigger is both deferrable and initially deferred +SELECT conname, tgrelid::regclass as tgrel, + regexp_replace(tgname, '[0-9]+', 'N') as tgname, tgtype, + tgdeferrable, tginitdeferred +FROM pg_trigger t JOIN pg_constraint c ON (t.tgconstraint = c.oid) +WHERE conrelid = 'fktable'::regclass AND conname = 'fktable_fk_fkey' +ORDER BY tgrelid, tgtype; + +-- Changing the constraint to NOT ENFORCED drops the associated FK triggers +ALTER TABLE FKTABLE ALTER CONSTRAINT fktable_fk_fkey NOT ENFORCED; +SELECT conname, tgrelid::regclass as tgrel, + regexp_replace(tgname, '[0-9]+', 'N') as tgname, tgtype, + tgdeferrable, tginitdeferred +FROM pg_trigger t JOIN pg_constraint c ON (t.tgconstraint = c.oid) +WHERE conrelid = 'fktable'::regclass AND conname = 'fktable_fk_fkey' +ORDER BY tgrelid, tgtype; + +-- Changing it back to ENFORCED will recreate the necessary FK triggers +-- that are deferrable and initially deferred +ALTER TABLE FKTABLE ALTER CONSTRAINT fktable_fk_fkey ENFORCED; +SELECT conname, tgrelid::regclass as tgrel, + regexp_replace(tgname, '[0-9]+', 'N') as tgname, tgtype, + tgdeferrable, tginitdeferred +FROM pg_trigger t JOIN pg_constraint c ON (t.tgconstraint = c.oid) +WHERE conrelid = 'fktable'::regclass AND conname = 'fktable_fk_fkey' +ORDER BY tgrelid, tgtype; + +-- Verify that a deferrable, initially deferred foreign key still works +-- as expected after being set to NOT ENFORCED and then re-enabled +BEGIN; + +-- doesn't match PK, but no error yet +INSERT INTO fktable VALUES (2, 20); + +-- should catch error from INSERT at commit +COMMIT; + DROP TABLE fktable, pktable; -- tricky behavior: according to SQL99, if a deferred constraint is set diff --git a/src/oracle_test/regress/sql/generated_stored.sql b/src/oracle_test/regress/sql/generated_stored.sql index 6bc4e7b15b6..e5f411103e5 100644 --- a/src/oracle_test/regress/sql/generated_stored.sql +++ b/src/oracle_test/regress/sql/generated_stored.sql @@ -745,6 +745,29 @@ CREATE TABLE gtest28b (LIKE gtest28a INCLUDING GENERATED); \d gtest28* +-- rule actions referring to generated columns: +-- NEW.b in a rule action should reflect the generated column's new value +CREATE TABLE gtest_rule (a int, b int GENERATED ALWAYS AS (a * 2) STORED); +CREATE TABLE gtest_rule_log (op text, old_b int, new_b int); +CREATE RULE gtest_rule_upd AS ON UPDATE TO gtest_rule + DO ALSO INSERT INTO gtest_rule_log VALUES ('UPD', OLD.b, NEW.b); +CREATE RULE gtest_rule_ins AS ON INSERT TO gtest_rule + DO ALSO INSERT INTO gtest_rule_log VALUES ('INS', NULL, NEW.b); +INSERT INTO gtest_rule (a) VALUES (1); +UPDATE gtest_rule SET a = 10; +UPDATE gtest_rule SET a = (SELECT max(b) FROM gtest_rule); +SELECT * FROM gtest_rule_log; +DROP RULE gtest_rule_upd ON gtest_rule; +DROP RULE gtest_rule_ins ON gtest_rule; +DROP TABLE gtest_rule_log; + +-- rule quals referring to generated columns: +-- NEW.b in the rule qual should reflect the generated column's new value +CREATE RULE gtest_rule_qual AS ON UPDATE TO gtest_rule WHERE NEW.b > 100 + DO INSTEAD NOTHING; +UPDATE gtest_rule SET a = 100; +SELECT * FROM gtest_rule; +DROP TABLE gtest_rule; -- sanity check of system catalog SELECT attrelid, attname, attgenerated FROM pg_attribute WHERE attgenerated NOT IN ('', 's', 'v'); diff --git a/src/oracle_test/regress/sql/generated_virtual.sql b/src/oracle_test/regress/sql/generated_virtual.sql index 476f9922126..8a95bfa26f4 100644 --- a/src/oracle_test/regress/sql/generated_virtual.sql +++ b/src/oracle_test/regress/sql/generated_virtual.sql @@ -807,6 +807,29 @@ CREATE TABLE gtest28b (LIKE gtest28a INCLUDING GENERATED); \d gtest28* +-- rule actions referring to generated columns: +-- NEW.b in a rule action should reflect the generated column's new value +CREATE TABLE gtest_rule (a int, b int GENERATED ALWAYS AS (a * 2) VIRTUAL); +CREATE TABLE gtest_rule_log (op text, old_b int, new_b int); +CREATE RULE gtest_rule_upd AS ON UPDATE TO gtest_rule + DO ALSO INSERT INTO gtest_rule_log VALUES ('UPD', OLD.b, NEW.b); +CREATE RULE gtest_rule_ins AS ON INSERT TO gtest_rule + DO ALSO INSERT INTO gtest_rule_log VALUES ('INS', NULL, NEW.b); +INSERT INTO gtest_rule (a) VALUES (1); +UPDATE gtest_rule SET a = 10; +UPDATE gtest_rule SET a = (SELECT max(b) FROM gtest_rule); +SELECT * FROM gtest_rule_log; +DROP RULE gtest_rule_upd ON gtest_rule; +DROP RULE gtest_rule_ins ON gtest_rule; +DROP TABLE gtest_rule_log; + +-- rule quals referring to generated columns: +-- NEW.b in the rule qual should reflect the generated column's new value +CREATE RULE gtest_rule_qual AS ON UPDATE TO gtest_rule WHERE NEW.b > 100 + DO INSTEAD NOTHING; +UPDATE gtest_rule SET a = 100; +SELECT * FROM gtest_rule; +DROP TABLE gtest_rule; -- sanity check of system catalog SELECT attrelid, attname, attgenerated FROM pg_attribute WHERE attgenerated NOT IN ('', 's', 'v'); @@ -886,3 +909,43 @@ select * from gtest33 where b is null; reset constraint_exclusion; drop table gtest33; + +-- Ensure that EXCLUDED. in INSERT ... ON CONFLICT +-- DO UPDATE is expanded to the generation expression, both for plain and +-- partitioned target relations. +create table gtest34 (id int primary key, a int, + c int generated always as (a * 10) virtual); +insert into gtest34 values (1, 5); +insert into gtest34 values (1, 7) + on conflict (id) do update set a = excluded.c returning *; +insert into gtest34 values (1, 2) + on conflict (id) do update set a = gtest34.c + excluded.c returning *; +insert into gtest34 values (1, 3) + on conflict (id) do update set a = 999 where excluded.c > 20 returning *; +drop table gtest34; + +create table gtest34p (id int primary key, a int, + c int generated always as (a * 10) virtual) + partition by range (id); +create table gtest34p_1 partition of gtest34p for values from (1) to (100); +insert into gtest34p values (1, 5); +insert into gtest34p values (1, 7) + on conflict (id) do update set a = excluded.c returning *; +insert into gtest34p values (1, 2) + on conflict (id) do update set a = gtest34p.c + excluded.c returning *; +drop table gtest34p; + +-- Ensure that virtual generated columns work with WHERE CURRENT OF +create table gtest_cursor (id int primary key, a int, b int generated always as (a * 2) virtual); +insert into gtest_cursor values (1, 10), (2, 20), (3, 30); + +begin; +declare curs cursor for select * from gtest_cursor order by id for update; +fetch 1 from curs; +update gtest_cursor set a = 99 where current of curs; +select * from gtest_cursor order by id; +delete from gtest_cursor where current of curs; +select * from gtest_cursor order by id; +commit; + +drop table gtest_cursor; diff --git a/src/oracle_test/regress/sql/indexing.sql b/src/oracle_test/regress/sql/indexing.sql index b5cb01c2d70..706a6ec04ac 100644 --- a/src/oracle_test/regress/sql/indexing.sql +++ b/src/oracle_test/regress/sql/indexing.sql @@ -246,6 +246,65 @@ select relname, indisvalid from pg_class join pg_index on indexrelid = oid where relname like 'idxpart%' order by relname; drop table idxpart; +-- Verify that re-attaching an already-attached partition index can +-- validate the parent index if it was still invalid, including +-- indirect ancestors in subpartitions. +create table idxpart (a int, b int) partition by range (a); +create table idxpart1 partition of idxpart for values from (0) to (1000) partition by range (a); +create table idxpart11 partition of idxpart1 for values from (0) to (500); +-- Partitioned table with no partitions +create table idxpart2 partition of idxpart for values from (1000) to (2000) partition by range (a); +-- create parent indexes +create index on only idxpart ((a/b)); +create index on only idxpart1 ((a/b)); +create index on only idxpart2 ((a/b)); +-- fail, leaves behind an invalid index on the leaf partition +insert into idxpart11 values (1, 0); +create index concurrently on idxpart11 ((a/b)); +select relname, indisvalid from pg_class join pg_index on indexrelid = oid + where relname like 'idxpart%' order by relname; +-- attach the indexes; parents stay invalid +alter index idxpart1_expr_idx attach partition idxpart11_expr_idx; +alter index idxpart_expr_idx attach partition idxpart1_expr_idx; +alter index idxpart_expr_idx attach partition idxpart2_expr_idx; +select relname, indisvalid from pg_class join pg_index on indexrelid = oid + where relname like 'idxpart%' order by relname; +-- fix the index on the leaf partition +delete from idxpart11 where b = 0; +reindex index concurrently idxpart11_expr_idx; +-- reattach the leaf partition index; parents should now be valid +alter index idxpart1_expr_idx attach partition idxpart11_expr_idx; +select relname, indisvalid from pg_class join pg_index on indexrelid = oid + where relname like 'idxpart%' order by relname; +drop table idxpart; + +-- Verify that re-attaching does not validate the parent when another +-- child index is still invalid. +create table idxpart (a int, b int) partition by range (a); +create table idxpart1 partition of idxpart for values from (0) to (500); +create table idxpart2 partition of idxpart for values from (500) to (1000); +create index on only idxpart ((a/b)); +-- create invalid indexes on both children +insert into idxpart1 values (1, 0); +insert into idxpart2 values (501, 0); +create index concurrently on idxpart1 ((a/b)); +create index concurrently on idxpart2 ((a/b)); +select relname, indisvalid from pg_class join pg_index on indexrelid = oid + where relname like 'idxpart%' order by relname; +-- attach both; parent stays invalid +alter index idxpart_expr_idx attach partition idxpart1_expr_idx; +alter index idxpart_expr_idx attach partition idxpart2_expr_idx; +select relname, indisvalid from pg_class join pg_index on indexrelid = oid + where relname like 'idxpart%' order by relname; +-- fix only idxpart1's index, leave idxpart2's still invalid +delete from idxpart1 where b = 0; +reindex index concurrently idxpart1_expr_idx; +-- re-attach the fixed child; parent should stay invalid +alter index idxpart_expr_idx attach partition idxpart1_expr_idx; +select relname, indisvalid from pg_class join pg_index on indexrelid = oid + where relname like 'idxpart%' order by relname; +drop table idxpart; + -- verify dependency handling during ALTER TABLE DETACH PARTITION create table idxpart (a int) partition by range (a); create table idxpart1 (like idxpart); diff --git a/src/oracle_test/regress/sql/join.sql b/src/oracle_test/regress/sql/join.sql index 2793fb534af..113d12ffbb9 100644 --- a/src/oracle_test/regress/sql/join.sql +++ b/src/oracle_test/regress/sql/join.sql @@ -2231,6 +2231,29 @@ from int8_tbl t1 left join onek t4 on t2.q2 < t3.unique2; +-- bug #19460: we need to clean up RestrictInfos more than we had been doing +explain (costs off) +select * from + (select 1::int as id) as lhs +full join + (select dummy_source.id + from (select null::int as id) as dummy_source + left join (select a.id from a where a.id = 42) as sub + on sub.id = dummy_source.id + ) as rhs +on lhs.id = rhs.id; + +explain (costs off) +select * from + (select 1::int as id) as lhs +full join + (select dummy_source.id + from (select 2::int as id) as dummy_source + left join (select a.id from a) as sub + on sub.id = dummy_source.id + ) as rhs +on lhs.id = rhs.id; + -- More tests of correct placement of pseudoconstant quals -- simple constant-false condition @@ -3084,6 +3107,12 @@ SELECT * FROM (SELECT n2.a FROM sj n1, sj n2 WHERE n1.a <> n2.a) q0, sl WHERE q0.a = 1; +-- Do not forget to replace relid in bare Var join clause (bug #19435) +ALTER TABLE sl ADD COLUMN bool_col boolean; +EXPLAIN (COSTS OFF) +SELECT 1 AS c1 FROM sl sl1 LEFT JOIN (sl AS sl2 NATURAL JOIN sl AS sl3) + ON sl2.bool_col LEFT JOIN sl AS sl4 ON sl2.bool_col; + -- Check optimization disabling if it will violate special join conditions. -- Two identical joined relations satisfies self join removal conditions but -- stay in different special join infos. diff --git a/src/oracle_test/regress/sql/multirangetypes.sql b/src/oracle_test/regress/sql/multirangetypes.sql index 2742d9190b4..2c5943fbf02 100644 --- a/src/oracle_test/regress/sql/multirangetypes.sql +++ b/src/oracle_test/regress/sql/multirangetypes.sql @@ -722,6 +722,22 @@ drop type textrange1; reset role; drop role regress_multirange_owner; +-- +-- CREATE TYPE checks for CREATE on multirange schema +-- +create role regress_mr; +create schema mr_sch; +set role regress_mr; +create type mytype as range (subtype=int4, multirange_type_name=mr_sch.mr_type); +reset role; +grant create on schema mr_sch to regress_mr; +set role regress_mr; +create type mytype as range (subtype=int4, multirange_type_name=mr_sch.mr_type); +reset role; +drop type mytype; +drop schema mr_sch; +drop role regress_mr; + -- -- Test polymorphic type system -- @@ -824,6 +840,9 @@ select *, row_to_json(upper(t)) as u from (values (two_ints_multirange(two_ints_range(row(1,2), row(3,4)))), (two_ints_multirange(two_ints_range(row(5,6), row(7,8))))) v(t); +-- this must be rejected to avoid self-inclusion issues: +alter type two_ints add attribute c two_ints_multirange; + drop type two_ints cascade; -- diff --git a/src/oracle_test/regress/sql/partition_prune.sql b/src/oracle_test/regress/sql/partition_prune.sql index 5272046da5c..48aa20b06c4 100644 --- a/src/oracle_test/regress/sql/partition_prune.sql +++ b/src/oracle_test/regress/sql/partition_prune.sql @@ -1402,3 +1402,74 @@ select min(a) over (partition by a order by a) from part_abc where a >= stable_o drop view part_abc_view; drop table part_abc; + +-- +-- Check that operands wrapped in PlaceHolderVars are matched to partition +-- keys, allowing partition pruning to occur. PlaceHolderVars can be +-- introduced when a subquery's output is used with grouping sets. +-- +create table phv_part (a int, b text) partition by list (a); +create table phv_part_1 partition of phv_part for values in (1); +create table phv_part_2 partition of phv_part for values in (2); +create table phv_part_null partition of phv_part for values in (null); +insert into phv_part values (1, 'one'), (2, 'two'), (null, 'null'); + +-- OpExpr: PHV-wrapped operand matched via equal() +explain (costs off) +select * from (select a, b from phv_part) t + where a = 1 + group by grouping sets (a, b); + +select * from (select a, b from phv_part) t + where a = 1 + group by grouping sets (a, b); + +-- OpExpr with RelabelType: PHV wrapped around a casted column +explain (costs off) +select * from (select a::oid as x, b from phv_part) t + where x::int = 1 + group by grouping sets (x, b); + +select * from (select a::oid as x, b from phv_part) t + where x::int = 1 + group by grouping sets (x, b); + +-- ScalarArrayOpExpr: IN clause with PHV-wrapped operand +explain (costs off) +select * from (select a, b from phv_part) t + where a in (1, null) + group by grouping sets (a, b); + +select * from (select a, b from phv_part) t + where a in (1, null) + group by grouping sets (a, b); + +-- NullTest: IS NULL with PHV-wrapped operand +explain (costs off) +select * from (select a, b from phv_part) t + where a is null + group by grouping sets (a, b); + +select * from (select a, b from phv_part) t + where a is null + group by grouping sets (a, b); + +drop table phv_part; + +-- BooleanTest: IS TRUE with PHV-wrapped boolean partition key +create table phv_boolpart (a bool, b text) partition by list (a); +create table phv_boolpart_t partition of phv_boolpart for values in (true); +create table phv_boolpart_f partition of phv_boolpart for values in (false); +create table phv_boolpart_null partition of phv_boolpart default; +insert into phv_boolpart values (true, 'yes'), (false, 'no'), (null, 'unknown'); + +explain (costs off) +select * from (select a, b from phv_boolpart) t + where a is true + group by grouping sets (a, b); + +select * from (select a, b from phv_boolpart) t + where a is true + group by grouping sets (a, b); + +drop table phv_boolpart; diff --git a/src/oracle_test/regress/sql/portals.sql b/src/oracle_test/regress/sql/portals.sql index fd7ae3092ba..c81869b2eb3 100644 --- a/src/oracle_test/regress/sql/portals.sql +++ b/src/oracle_test/regress/sql/portals.sql @@ -512,6 +512,11 @@ DECLARE c1 CURSOR FOR SELECT * FROM ucview; FETCH FROM c1; DELETE FROM ucview WHERE CURRENT OF c1; -- fail, views not supported ROLLBACK; +BEGIN; +DECLARE c1 CURSOR FOR SELECT * FROM ucview; +FETCH FROM c1; +UPDATE ucview SET f1 = f1 + 10 WHERE CURRENT OF c1; -- fail, views not supported +ROLLBACK; -- Check WHERE CURRENT OF with an index-only scan BEGIN; diff --git a/src/oracle_test/regress/sql/prepared_xacts.sql b/src/oracle_test/regress/sql/prepared_xacts.sql index ade3a2672a8..b0712b153e0 100644 --- a/src/oracle_test/regress/sql/prepared_xacts.sql +++ b/src/oracle_test/regress/sql/prepared_xacts.sql @@ -1,3 +1,8 @@ +SELECT current_setting('max_prepared_transactions')::integer < 2 AS skip_test \gset +\if :skip_test +\quit +\endif + -- -- PREPARED TRANSACTIONS (two-phase commit) -- @@ -158,7 +163,32 @@ SELECT * FROM pxtest3; -- There should be no prepared transactions SELECT gid FROM pg_prepared_xacts WHERE gid ~ '^regress_' ORDER BY gid; + +-- Test row-level locks held by prepared transactions +CREATE TABLE pxtest_rowlock (id int PRIMARY KEY, data text); +INSERT INTO pxtest_rowlock VALUES (1, 'test data'); + +BEGIN; +SELECT * FROM pxtest_rowlock WHERE id = 1 FOR SHARE; +PREPARE TRANSACTION 'regress_p1'; + +-- Should fail because the row is locked +SELECT * FROM pxtest_rowlock WHERE id = 1 FOR UPDATE NOWAIT; + +-- Test prepared transactions that participate in multixacts. For +-- that, lock the same row again, creating a multixid. +BEGIN; +SELECT * FROM pxtest_rowlock WHERE id = 1 FOR SHARE; +PREPARE TRANSACTION 'regress_p2'; + +-- Should fail because the row is locked +SELECT * FROM pxtest_rowlock WHERE id = 1 FOR UPDATE NOWAIT; + +ROLLBACK PREPARED 'regress_p1'; +ROLLBACK PREPARED 'regress_p2'; + -- Clean up DROP TABLE pxtest2; -DROP TABLE pxtest3; -- will still be there if prepared xacts are disabled +-- pxtest3 was already dropped DROP TABLE pxtest4; +DROP TABLE pxtest_rowlock; diff --git a/src/oracle_test/regress/sql/stats.sql b/src/oracle_test/regress/sql/stats.sql index bb77c7e7c85..0b8dc5a87e9 100644 --- a/src/oracle_test/regress/sql/stats.sql +++ b/src/oracle_test/regress/sql/stats.sql @@ -404,9 +404,17 @@ COMMIT; -- check that the stats are reset. SELECT (n_tup_ins + n_tup_upd) > 0 AS has_data FROM pg_stat_all_tables WHERE relid = 'pg_shdescription'::regclass; +-- stats_reset may not be set for datid=0 and shared objects in +-- pg_stat_database, so reset once. SELECT pg_stat_reset_single_table_counters('pg_shdescription'::regclass); SELECT (n_tup_ins + n_tup_upd) > 0 AS has_data FROM pg_stat_all_tables WHERE relid = 'pg_shdescription'::regclass; +SELECT extract(epoch from stats_reset) AS shared_db_reset_before + FROM pg_stat_database WHERE datid = 0 \gset +-- Second reset for comparison. +SELECT pg_stat_reset_single_table_counters('pg_shdescription'::regclass); +SELECT extract(epoch from stats_reset) > :'shared_db_reset_before' AS has_updated + FROM pg_stat_database WHERE datid = 0; -- set back comment \if :{?description_before} diff --git a/src/oracle_test/regress/sql/stats_import.sql b/src/oracle_test/regress/sql/stats_import.sql index d140733a750..ee97fa6bc1b 100755 --- a/src/oracle_test/regress/sql/stats_import.sql +++ b/src/oracle_test/regress/sql/stats_import.sql @@ -457,6 +457,60 @@ AND tablename = 'test' AND inherited = false AND attname = 'id'; +-- warn: mcv / mcf array length mismatch (more vals), mcv-pair fails, rest get set +SELECT pg_catalog.pg_restore_attribute_stats( + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'id', + 'inherited', false::boolean, + 'null_frac', 0.24::real, + 'most_common_vals', '{2,1,3}'::text, + 'most_common_freqs', '{0.3,0.25}'::real[] + ); + +SELECT * +FROM pg_stats +WHERE schemaname = 'stats_import' +AND tablename = 'test' +AND inherited = false +AND attname = 'id'; + +-- warn: mcv / mcf array length mismatch (more freqs), mcv-pair fails, rest get set +SELECT pg_catalog.pg_restore_attribute_stats( + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'id', + 'inherited', false::boolean, + 'null_frac', 0.25::real, + 'most_common_vals', '{2,1}'::text, + 'most_common_freqs', '{0.3,0.25,0.05}'::real[] + ); + +SELECT * +FROM pg_stats +WHERE schemaname = 'stats_import' +AND tablename = 'test' +AND inherited = false +AND attname = 'id'; + +-- warn: most_common_vals is multi-dimensional, mcv-pair fails, rest get set +SELECT pg_catalog.pg_restore_attribute_stats( + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'id', + 'inherited', false::boolean, + 'null_frac', 0.26::real, + 'most_common_vals', '{{2,1},{3,4}}'::text, + 'most_common_freqs', '{0.3,0.25,0.05,0.04}'::real[] + ); + +SELECT * +FROM pg_stats +WHERE schemaname = 'stats_import' +AND tablename = 'test' +AND inherited = false +AND attname = 'id'; + -- ok: mcv+mcf SELECT pg_catalog.pg_restore_attribute_stats( 'schemaname', 'stats_import', diff --git a/src/oracle_test/regress/sql/tsearch.sql b/src/oracle_test/regress/sql/tsearch.sql index 281f4db9c1e..698633967e5 100644 --- a/src/oracle_test/regress/sql/tsearch.sql +++ b/src/oracle_test/regress/sql/tsearch.sql @@ -648,6 +648,14 @@ SELECT ts_headline('english', SELECT ts_headline('english', 'foo bar', to_tsquery('english', '')); +-- Test for large values of StartSel, StopSel and FragmentDelimiter +SELECT ts_headline('english', 'foo barbar', to_tsquery('english', 'foo'), + 'StartSel=' || repeat('x', 32768)); +SELECT ts_headline('english', 'foo barbar', to_tsquery('english', 'foo'), + 'StopSel=' || repeat('x', 32768)); +SELECT ts_headline('english', 'foo barbar', to_tsquery('english', 'foo'), + 'FragmentDelimiter=' || repeat('x', 32768)); + --Rewrite sub system CREATE TABLE test_tsquery (txtkeyword TEXT, txtsample TEXT); diff --git a/src/oracle_test/regress/sql/union.sql b/src/oracle_test/regress/sql/union.sql index 405ab2017e0..1ab8e1543cf 100644 --- a/src/oracle_test/regress/sql/union.sql +++ b/src/oracle_test/regress/sql/union.sql @@ -594,4 +594,8 @@ select * from tenk1 t1 left join lateral (select t1.tenthous from tenk2 t2 union all (values(1))) on true limit 1; + +-- Test handling of Vars with varno 0 in estimate_array_length +explain (verbose, costs off) +select null::int[] union all select null::int[] union all select null::bigint[]; reset ivorysql.enable_emptystring_to_null; diff --git a/src/oracle_test/regress/sql/window.sql b/src/oracle_test/regress/sql/window.sql index 9a94e07fffe..f99ba5e5c07 100644 --- a/src/oracle_test/regress/sql/window.sql +++ b/src/oracle_test/regress/sql/window.sql @@ -331,6 +331,32 @@ CREATE TEMP VIEW v_window AS SELECT pg_get_viewdef('v_window'); +-- test overflow frame specifications +SELECT sum(unique1) over (rows between current row and 9223372036854775807 following exclude current row), + unique1, four +FROM tenk1 WHERE unique1 < 10; + +SELECT sum(unique1) over (rows between 9223372036854775807 following and 1 following), + unique1, four +FROM tenk1 WHERE unique1 < 10; + +SELECT last_value(unique1) over (ORDER BY four rows between current row and 9223372036854775807 following exclude current row), + unique1, four +FROM tenk1 WHERE unique1 < 10; + +-- These test GROUPS mode with an offset large enough to cause overflow when +-- added to currentgroup. Although the overflow doesn't produce visibly wrong +-- results (due to the incremental nature of group pointer advancement), we +-- still need to protect against it as signed integer overflow is undefined +-- behavior in C. +SELECT sum(unique1) over (ORDER BY four groups between current row and 9223372036854775807 following), + unique1, four +FROM tenk1 WHERE unique1 < 10; + +SELECT sum(unique1) over (ORDER BY four groups between 9223372036854775807 following and unbounded following), + unique1, four +FROM tenk1 WHERE unique1 < 10; + -- RANGE offset PRECEDING/FOLLOWING tests SELECT sum(unique1) over (order by four range between 2::int8 preceding and 1::int2 preceding), diff --git a/src/oracle_test/subscription/t/030_origin.pl b/src/oracle_test/subscription/t/030_origin.pl index 62e2f857ec1..3fe99f4ae09 100644 --- a/src/oracle_test/subscription/t/030_origin.pl +++ b/src/oracle_test/subscription/t/030_origin.pl @@ -9,6 +9,9 @@ use PostgreSQL::Test::Utils; use Test::More; +my $tab_unquoted = q{tab'le}; +my $tab = qq{"$tab_unquoted"}; + my $subname_AB = 'tap_sub_A_B'; my $subname_AB2 = 'tap_sub_A_B_2'; my $subname_BA = 'tap_sub_B_A'; @@ -38,15 +41,15 @@ $node_B->start; # Create table on node_A -$node_A->safe_psql('postgres', "CREATE TABLE tab (a int PRIMARY KEY)"); +$node_A->safe_psql('postgres', "CREATE TABLE $tab (a int PRIMARY KEY)"); # Create the same table on node_B -$node_B->safe_psql('postgres', "CREATE TABLE tab (a int PRIMARY KEY)"); +$node_B->safe_psql('postgres', "CREATE TABLE $tab (a int PRIMARY KEY)"); # Setup logical replication # node_A (pub) -> node_B (sub) my $node_A_connstr = $node_A->connstr . ' dbname=postgres'; -$node_A->safe_psql('postgres', "CREATE PUBLICATION tap_pub_A FOR TABLE tab"); +$node_A->safe_psql('postgres', "CREATE PUBLICATION tap_pub_A FOR TABLE $tab"); $node_B->safe_psql( 'postgres', " CREATE SUBSCRIPTION $subname_BA @@ -56,7 +59,7 @@ # node_B (pub) -> node_A (sub) my $node_B_connstr = $node_B->connstr . ' dbname=postgres'; -$node_B->safe_psql('postgres', "CREATE PUBLICATION tap_pub_B FOR TABLE tab"); +$node_B->safe_psql('postgres', "CREATE PUBLICATION tap_pub_B FOR TABLE $tab"); $node_A->safe_psql( 'postgres', " CREATE SUBSCRIPTION $subname_AB @@ -76,25 +79,25 @@ ############################################################################### # insert a record -$node_A->safe_psql('postgres', "INSERT INTO tab VALUES (11);"); -$node_B->safe_psql('postgres', "INSERT INTO tab VALUES (21);"); +$node_A->safe_psql('postgres', "INSERT INTO $tab VALUES (11);"); +$node_B->safe_psql('postgres', "INSERT INTO $tab VALUES (21);"); $node_A->wait_for_catchup($subname_BA); $node_B->wait_for_catchup($subname_AB); # check that transaction was committed on subscriber(s) -$result = $node_A->safe_psql('postgres', "SELECT * FROM tab ORDER BY 1;"); +$result = $node_A->safe_psql('postgres', "SELECT * FROM $tab ORDER BY 1;"); is( $result, qq(11 21), 'Inserted successfully without leading to infinite recursion in bidirectional replication setup' ); -$result = $node_B->safe_psql('postgres', "SELECT * FROM tab ORDER BY 1;"); +$result = $node_B->safe_psql('postgres', "SELECT * FROM $tab ORDER BY 1;"); is( $result, qq(11 21), 'Inserted successfully without leading to infinite recursion in bidirectional replication setup' ); -$node_A->safe_psql('postgres', "DELETE FROM tab;"); +$node_A->safe_psql('postgres', "DELETE FROM $tab;"); $node_A->wait_for_catchup($subname_BA); $node_B->wait_for_catchup($subname_AB); @@ -103,10 +106,10 @@ # Check that remote data of node_B (that originated from node_C) is not # published to node_A. ############################################################################### -$result = $node_A->safe_psql('postgres', "SELECT * FROM tab ORDER BY 1;"); +$result = $node_A->safe_psql('postgres', "SELECT * FROM $tab ORDER BY 1;"); is($result, qq(), 'Check existing data'); -$result = $node_B->safe_psql('postgres', "SELECT * FROM tab ORDER BY 1;"); +$result = $node_B->safe_psql('postgres', "SELECT * FROM $tab ORDER BY 1;"); is($result, qq(), 'Check existing data'); # Initialize node node_C @@ -114,12 +117,12 @@ $node_C->init(allows_streaming => 'logical'); $node_C->start; -$node_C->safe_psql('postgres', "CREATE TABLE tab (a int PRIMARY KEY)"); +$node_C->safe_psql('postgres', "CREATE TABLE $tab (a int PRIMARY KEY)"); # Setup logical replication # node_C (pub) -> node_B (sub) my $node_C_connstr = $node_C->connstr . ' dbname=postgres'; -$node_C->safe_psql('postgres', "CREATE PUBLICATION tap_pub_C FOR TABLE tab"); +$node_C->safe_psql('postgres', "CREATE PUBLICATION tap_pub_C FOR TABLE $tab"); $node_B->safe_psql( 'postgres', " CREATE SUBSCRIPTION $subname_BC @@ -129,17 +132,17 @@ $node_B->wait_for_subscription_sync($node_C, $subname_BC); # insert a record -$node_C->safe_psql('postgres', "INSERT INTO tab VALUES (32);"); +$node_C->safe_psql('postgres', "INSERT INTO $tab VALUES (32);"); $node_C->wait_for_catchup($subname_BC); $node_B->wait_for_catchup($subname_AB); $node_A->wait_for_catchup($subname_BA); -$result = $node_B->safe_psql('postgres', "SELECT * FROM tab ORDER BY 1;"); +$result = $node_B->safe_psql('postgres', "SELECT * FROM $tab ORDER BY 1;"); is($result, qq(32), 'The node_C data replicated to node_B'); # check that the data published from node_C to node_B is not sent to node_A -$result = $node_A->safe_psql('postgres', "SELECT * FROM tab ORDER BY 1;"); +$result = $node_A->safe_psql('postgres', "SELECT * FROM $tab ORDER BY 1;"); is($result, qq(), 'Remote data originating from another node (not the publisher) is not replicated when origin parameter is none' ); @@ -149,37 +152,37 @@ # delete a row that was previously modified by a different source. ############################################################################### -$node_B->safe_psql('postgres', "DELETE FROM tab;"); +$node_B->safe_psql('postgres', "DELETE FROM $tab;"); -$node_A->safe_psql('postgres', "INSERT INTO tab VALUES (32);"); +$node_A->safe_psql('postgres', "INSERT INTO $tab VALUES (32);"); $node_A->wait_for_catchup($subname_BA); $node_B->wait_for_catchup($subname_AB); -$result = $node_B->safe_psql('postgres', "SELECT * FROM tab ORDER BY 1;"); +$result = $node_B->safe_psql('postgres', "SELECT * FROM $tab ORDER BY 1;"); is($result, qq(32), 'The node_A data replicated to node_B'); # The update should update the row on node B that was inserted by node A. -$node_C->safe_psql('postgres', "UPDATE tab SET a = 33 WHERE a = 32;"); +$node_C->safe_psql('postgres', "UPDATE $tab SET a = 33 WHERE a = 32;"); $node_B->wait_for_log( - qr/conflict detected on relation "public.tab": conflict=update_origin_differs.*\n.*DETAIL:.* Updating the row that was modified by a different origin ".*" in transaction [0-9]+ at .*\n.*Existing local row \(32\); remote row \(33\); replica identity \(a\)=\(32\)/ + qr/conflict detected on relation "public.$tab_unquoted": conflict=update_origin_differs.*\n.*DETAIL:.* Updating the row that was modified by a different origin ".*" in transaction [0-9]+ at .*\n.*Existing local row \(32\); remote row \(33\); replica identity \(a\)=\(32\)/ ); -$node_B->safe_psql('postgres', "DELETE FROM tab;"); -$node_A->safe_psql('postgres', "INSERT INTO tab VALUES (33);"); +$node_B->safe_psql('postgres', "DELETE FROM $tab;"); +$node_A->safe_psql('postgres', "INSERT INTO $tab VALUES (33);"); $node_A->wait_for_catchup($subname_BA); $node_B->wait_for_catchup($subname_AB); -$result = $node_B->safe_psql('postgres', "SELECT * FROM tab ORDER BY 1;"); +$result = $node_B->safe_psql('postgres', "SELECT * FROM $tab ORDER BY 1;"); is($result, qq(33), 'The node_A data replicated to node_B'); # The delete should remove the row on node B that was inserted by node A. -$node_C->safe_psql('postgres', "DELETE FROM tab WHERE a = 33;"); +$node_C->safe_psql('postgres', "DELETE FROM $tab WHERE a = 33;"); $node_B->wait_for_log( - qr/conflict detected on relation "public.tab": conflict=delete_origin_differs.*\n.*DETAIL:.* Deleting the row that was modified by a different origin ".*" in transaction [0-9]+ at .*\n.*Existing local row \(33\); replica identity \(a\)=\(33\)/ + qr/conflict detected on relation "public.$tab_unquoted": conflict=delete_origin_differs.*\n.*DETAIL:.* Deleting the row that was modified by a different origin ".*" in transaction [0-9]+ at .*\n.*Existing local row \(33\); replica identity \(a\)=\(33\)/ ); # The remaining tests no longer test conflict detection. diff --git a/src/pl/plperl/GNUmakefile b/src/pl/plperl/GNUmakefile index 558c764aadb..d7c8917f822 100644 --- a/src/pl/plperl/GNUmakefile +++ b/src/pl/plperl/GNUmakefile @@ -62,7 +62,7 @@ endif REGRESS_OPTS = --dbname=$(PL_TESTDB) --dlpath=$(top_builddir)/src/test/regress REGRESS = plperl_setup plperl plperl_lc plperl_trigger plperl_shared \ - plperl_elog plperl_util plperl_init plperlu plperl_array \ + plperl_elog plperl_unicode plperl_util plperl_init plperlu plperl_array \ plperl_call plperl_transaction plperl_env # if Perl can support two interpreters in one backend, # test plperl-and-plperlu cases diff --git a/src/pl/plperl/expected/plperl_elog.out b/src/pl/plperl/expected/plperl_elog.out index a6d35cb79c4..3f9449a9659 100644 --- a/src/pl/plperl/expected/plperl_elog.out +++ b/src/pl/plperl/expected/plperl_elog.out @@ -97,16 +97,3 @@ NOTICE: caught die 2 (1 row) --- Test non-ASCII error messages --- --- Note: this test case is known to fail if the database encoding is --- EUC_CN, EUC_JP, EUC_KR, or EUC_TW, for lack of any equivalent to --- U+00A0 (no-break space) in those encodings. However, testing with --- plain ASCII data would be rather useless, so we must live with that. -SET client_encoding TO UTF8; -create or replace function error_with_nbsp() returns void language plperl as $$ - elog(ERROR, "this message contains a no-break space"); -$$; -select error_with_nbsp(); -ERROR: this message contains a no-break space at line 2. -CONTEXT: PL/Perl function "error_with_nbsp" diff --git a/src/pl/plperl/expected/plperl_elog_1.out b/src/pl/plperl/expected/plperl_elog_1.out index 85aa460ec4c..34d5d5836da 100644 --- a/src/pl/plperl/expected/plperl_elog_1.out +++ b/src/pl/plperl/expected/plperl_elog_1.out @@ -97,16 +97,3 @@ NOTICE: caught die 2 (1 row) --- Test non-ASCII error messages --- --- Note: this test case is known to fail if the database encoding is --- EUC_CN, EUC_JP, EUC_KR, or EUC_TW, for lack of any equivalent to --- U+00A0 (no-break space) in those encodings. However, testing with --- plain ASCII data would be rather useless, so we must live with that. -SET client_encoding TO UTF8; -create or replace function error_with_nbsp() returns void language plperl as $$ - elog(ERROR, "this message contains a no-break space"); -$$; -select error_with_nbsp(); -ERROR: this message contains a no-break space at line 2. -CONTEXT: PL/Perl function "error_with_nbsp" diff --git a/src/pl/plperl/expected/plperl_unicode.out b/src/pl/plperl/expected/plperl_unicode.out new file mode 100644 index 00000000000..3c48f2e9611 --- /dev/null +++ b/src/pl/plperl/expected/plperl_unicode.out @@ -0,0 +1,18 @@ +-- Test non-ASCII error messages +-- +-- This test case would fail if the database encoding is EUC_CN, EUC_JP, +-- EUC_KR, or EUC_TW, for lack of any equivalent to U+00A0 (no-break space) in +-- those encodings. However, testing with plain ASCII data would be rather +-- useless, so we must live with that. +SELECT getdatabaseencoding() IN ('EUC_CN', 'EUC_JP', 'EUC_KR', 'EUC_TW') + AS skip_test \gset +\if :skip_test +\quit +\endif +SET client_encoding TO UTF8; +create or replace function error_with_nbsp() returns void language plperl as $$ + elog(ERROR, "this message contains a no-break space"); +$$; +select error_with_nbsp(); +ERROR: this message contains a no-break space at line 2. +CONTEXT: PL/Perl function "error_with_nbsp" diff --git a/src/pl/plperl/expected/plperl_unicode_1.out b/src/pl/plperl/expected/plperl_unicode_1.out new file mode 100644 index 00000000000..761de04b1ee --- /dev/null +++ b/src/pl/plperl/expected/plperl_unicode_1.out @@ -0,0 +1,10 @@ +-- Test non-ASCII error messages +-- +-- This test case would fail if the database encoding is EUC_CN, EUC_JP, +-- EUC_KR, or EUC_TW, for lack of any equivalent to U+00A0 (no-break space) in +-- those encodings. However, testing with plain ASCII data would be rather +-- useless, so we must live with that. +SELECT getdatabaseencoding() IN ('EUC_CN', 'EUC_JP', 'EUC_KR', 'EUC_TW') + AS skip_test \gset +\if :skip_test +\quit diff --git a/src/pl/plperl/meson.build b/src/pl/plperl/meson.build index b463d4d56c5..e77679b451b 100644 --- a/src/pl/plperl/meson.build +++ b/src/pl/plperl/meson.build @@ -88,6 +88,7 @@ tests += { 'plperl_trigger', 'plperl_shared', 'plperl_elog', + 'plperl_unicode', 'plperl_util', 'plperl_init', 'plperlu', diff --git a/src/pl/plperl/sql/plperl_elog.sql b/src/pl/plperl/sql/plperl_elog.sql index 9ea1350069b..032fd8b8ba7 100644 --- a/src/pl/plperl/sql/plperl_elog.sql +++ b/src/pl/plperl/sql/plperl_elog.sql @@ -76,18 +76,3 @@ return $a + $b; $$; select indirect_die_caller(); - --- Test non-ASCII error messages --- --- Note: this test case is known to fail if the database encoding is --- EUC_CN, EUC_JP, EUC_KR, or EUC_TW, for lack of any equivalent to --- U+00A0 (no-break space) in those encodings. However, testing with --- plain ASCII data would be rather useless, so we must live with that. - -SET client_encoding TO UTF8; - -create or replace function error_with_nbsp() returns void language plperl as $$ - elog(ERROR, "this message contains a no-break space"); -$$; - -select error_with_nbsp(); diff --git a/src/pl/plperl/sql/plperl_unicode.sql b/src/pl/plperl/sql/plperl_unicode.sql new file mode 100644 index 00000000000..7e1ad745cdd --- /dev/null +++ b/src/pl/plperl/sql/plperl_unicode.sql @@ -0,0 +1,19 @@ +-- Test non-ASCII error messages +-- +-- This test case would fail if the database encoding is EUC_CN, EUC_JP, +-- EUC_KR, or EUC_TW, for lack of any equivalent to U+00A0 (no-break space) in +-- those encodings. However, testing with plain ASCII data would be rather +-- useless, so we must live with that. +SELECT getdatabaseencoding() IN ('EUC_CN', 'EUC_JP', 'EUC_KR', 'EUC_TW') + AS skip_test \gset +\if :skip_test +\quit +\endif + +SET client_encoding TO UTF8; + +create or replace function error_with_nbsp() returns void language plperl as $$ + elog(ERROR, "this message contains a no-break space"); +$$; + +select error_with_nbsp(); diff --git a/src/pl/plpgsql/src/expected/plpgsql_trap.out b/src/pl/plpgsql/src/expected/plpgsql_trap.out index 62d1679c28f..c37ac3b5c69 100644 --- a/src/pl/plpgsql/src/expected/plpgsql_trap.out +++ b/src/pl/plpgsql/src/expected/plpgsql_trap.out @@ -138,13 +138,11 @@ select * from foo; drop table foo; create function trap_timeout() returns void as $$ begin - declare x int; begin - -- we assume this will take longer than 1 second: - select count(*) into x from generate_series(1, 1_000_000_000_000); + perform pg_sleep(10); exception when others then - raise notice 'caught others?'; + raise notice 'caught others: %', sqlerrm; when query_canceled then raise notice 'nyeah nyeah, can''t stop me'; end; @@ -157,7 +155,7 @@ set statement_timeout to 1000; select trap_timeout(); NOTICE: nyeah nyeah, can't stop me ERROR: end of function -CONTEXT: PL/pgSQL function trap_timeout() line 15 at RAISE +CONTEXT: PL/pgSQL function trap_timeout() line 13 at RAISE rollback; -- Test for pass-by-ref values being stored in proper context create function test_variable_storage() returns text as $$ diff --git a/src/pl/plpgsql/src/sql/plpgsql_trap.sql b/src/pl/plpgsql/src/sql/plpgsql_trap.sql index 5459b347e7f..731d592040e 100644 --- a/src/pl/plpgsql/src/sql/plpgsql_trap.sql +++ b/src/pl/plpgsql/src/sql/plpgsql_trap.sql @@ -85,13 +85,11 @@ drop table foo; create function trap_timeout() returns void as $$ begin - declare x int; begin - -- we assume this will take longer than 1 second: - select count(*) into x from generate_series(1, 1_000_000_000_000); + perform pg_sleep(10); exception when others then - raise notice 'caught others?'; + raise notice 'caught others: %', sqlerrm; when query_canceled then raise notice 'nyeah nyeah, can''t stop me'; end; diff --git a/src/pl/plpython/expected/plpython_unicode.out b/src/pl/plpython/expected/plpython_unicode.out index fd54b0b88e8..bd8d9c561c9 100644 --- a/src/pl/plpython/expected/plpython_unicode.out +++ b/src/pl/plpython/expected/plpython_unicode.out @@ -1,11 +1,16 @@ -- -- Unicode handling -- --- Note: this test case is known to fail if the database encoding is --- EUC_CN, EUC_JP, EUC_KR, or EUC_TW, for lack of any equivalent to --- U+00A0 (no-break space) in those encodings. However, testing with --- plain ASCII data would be rather useless, so we must live with that. +-- This test case would fail if the database encoding is EUC_CN, EUC_JP, +-- EUC_KR, or EUC_TW, for lack of any equivalent to U+00A0 (no-break space) in +-- those encodings. However, testing with plain ASCII data would be rather +-- useless, so we must live with that. -- +SELECT getdatabaseencoding() IN ('EUC_CN', 'EUC_JP', 'EUC_KR', 'EUC_TW') + AS skip_test \gset +\if :skip_test +\quit +\endif SET client_encoding TO UTF8; CREATE TABLE unicode_test ( testvalue text NOT NULL diff --git a/src/pl/plpython/expected/plpython_unicode_1.out b/src/pl/plpython/expected/plpython_unicode_1.out new file mode 100644 index 00000000000..f8b21fd7eb7 --- /dev/null +++ b/src/pl/plpython/expected/plpython_unicode_1.out @@ -0,0 +1,12 @@ +-- +-- Unicode handling +-- +-- This test case would fail if the database encoding is EUC_CN, EUC_JP, +-- EUC_KR, or EUC_TW, for lack of any equivalent to U+00A0 (no-break space) in +-- those encodings. However, testing with plain ASCII data would be rather +-- useless, so we must live with that. +-- +SELECT getdatabaseencoding() IN ('EUC_CN', 'EUC_JP', 'EUC_KR', 'EUC_TW') + AS skip_test \gset +\if :skip_test +\quit diff --git a/src/pl/plpython/sql/plpython_unicode.sql b/src/pl/plpython/sql/plpython_unicode.sql index 14f7b4e0053..f45844b906e 100644 --- a/src/pl/plpython/sql/plpython_unicode.sql +++ b/src/pl/plpython/sql/plpython_unicode.sql @@ -1,11 +1,16 @@ -- -- Unicode handling -- --- Note: this test case is known to fail if the database encoding is --- EUC_CN, EUC_JP, EUC_KR, or EUC_TW, for lack of any equivalent to --- U+00A0 (no-break space) in those encodings. However, testing with --- plain ASCII data would be rather useless, so we must live with that. +-- This test case would fail if the database encoding is EUC_CN, EUC_JP, +-- EUC_KR, or EUC_TW, for lack of any equivalent to U+00A0 (no-break space) in +-- those encodings. However, testing with plain ASCII data would be rather +-- useless, so we must live with that. -- +SELECT getdatabaseencoding() IN ('EUC_CN', 'EUC_JP', 'EUC_KR', 'EUC_TW') + AS skip_test \gset +\if :skip_test +\quit +\endif SET client_encoding TO UTF8; diff --git a/src/pl/tcl/expected/pltcl_unicode.out b/src/pl/tcl/expected/pltcl_unicode.out index eea7d70664f..d33afd7548f 100644 --- a/src/pl/tcl/expected/pltcl_unicode.out +++ b/src/pl/tcl/expected/pltcl_unicode.out @@ -1,11 +1,16 @@ -- -- Unicode handling -- --- Note: this test case is known to fail if the database encoding is --- EUC_CN, EUC_JP, EUC_KR, or EUC_TW, for lack of any equivalent to --- U+00A0 (no-break space) in those encodings. However, testing with --- plain ASCII data would be rather useless, so we must live with that. +-- This test case would fail if the database encoding is EUC_CN, EUC_JP, +-- EUC_KR, or EUC_TW, for lack of any equivalent to U+00A0 (no-break space) in +-- those encodings. However, testing with plain ASCII data would be rather +-- useless, so we must live with that. -- +SELECT getdatabaseencoding() IN ('EUC_CN', 'EUC_JP', 'EUC_KR', 'EUC_TW') + AS skip_test \gset +\if :skip_test +\quit +\endif SET client_encoding TO UTF8; CREATE TABLE unicode_test ( testvalue text NOT NULL diff --git a/src/pl/tcl/expected/pltcl_unicode_1.out b/src/pl/tcl/expected/pltcl_unicode_1.out new file mode 100644 index 00000000000..f8b21fd7eb7 --- /dev/null +++ b/src/pl/tcl/expected/pltcl_unicode_1.out @@ -0,0 +1,12 @@ +-- +-- Unicode handling +-- +-- This test case would fail if the database encoding is EUC_CN, EUC_JP, +-- EUC_KR, or EUC_TW, for lack of any equivalent to U+00A0 (no-break space) in +-- those encodings. However, testing with plain ASCII data would be rather +-- useless, so we must live with that. +-- +SELECT getdatabaseencoding() IN ('EUC_CN', 'EUC_JP', 'EUC_KR', 'EUC_TW') + AS skip_test \gset +\if :skip_test +\quit diff --git a/src/pl/tcl/sql/pltcl_unicode.sql b/src/pl/tcl/sql/pltcl_unicode.sql index f0006046127..a09e4998b2b 100644 --- a/src/pl/tcl/sql/pltcl_unicode.sql +++ b/src/pl/tcl/sql/pltcl_unicode.sql @@ -1,11 +1,16 @@ -- -- Unicode handling -- --- Note: this test case is known to fail if the database encoding is --- EUC_CN, EUC_JP, EUC_KR, or EUC_TW, for lack of any equivalent to --- U+00A0 (no-break space) in those encodings. However, testing with --- plain ASCII data would be rather useless, so we must live with that. +-- This test case would fail if the database encoding is EUC_CN, EUC_JP, +-- EUC_KR, or EUC_TW, for lack of any equivalent to U+00A0 (no-break space) in +-- those encodings. However, testing with plain ASCII data would be rather +-- useless, so we must live with that. -- +SELECT getdatabaseencoding() IN ('EUC_CN', 'EUC_JP', 'EUC_KR', 'EUC_TW') + AS skip_test \gset +\if :skip_test +\quit +\endif SET client_encoding TO UTF8; diff --git a/src/port/chklocale.c b/src/port/chklocale.c index 034939f7fd2..023a7435c9b 100644 --- a/src/port/chklocale.c +++ b/src/port/chklocale.c @@ -202,7 +202,7 @@ static char * win32_get_codeset(const char *ctype) { char *r = NULL; - char *codepage; + const char *codepage; uint32 cp; WCHAR wctype[LOCALE_NAME_MAX_LENGTH]; diff --git a/src/port/getopt.c b/src/port/getopt.c index 655fef3b0c7..2cca5a0673a 100644 --- a/src/port/getopt.c +++ b/src/port/getopt.c @@ -72,7 +72,7 @@ int getopt(int nargc, char *const *nargv, const char *ostr) { static char *place = EMSG; /* option letter processing */ - char *oli; /* option letter list index */ + const char *oli; /* option letter list index */ if (!*place) { /* update scanning pointer */ diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index f83de0dff97..20953db9db1 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -62,7 +62,7 @@ getopt_long(int argc, char *const argv[], const struct option *longopts, int *longindex) { static char *place = EMSG; /* option letter processing */ - char *oli; /* option letter list index */ + const char *oli; /* option letter list index */ static int nonopt_start = -1; static bool force_nonopt = false; diff --git a/src/port/path.c b/src/port/path.c index 63503409d5a..7f13940b55b 100644 --- a/src/port/path.c +++ b/src/port/path.c @@ -627,6 +627,23 @@ path_is_relative_and_below_cwd(const char *path) return true; } +/* + * Detect whether a path is safe for use during archive extraction. + * + * This applies canonicalize_path(), then it checks that the path does + * not contain any parent directory references. + */ +bool +path_is_safe_for_extraction(const char *path) +{ + char buf[MAXPGPATH]; + + strlcpy(buf, path, sizeof(buf)); + canonicalize_path(buf); + + return path_is_relative_and_below_cwd(buf); +} + /* * Detect whether path1 is a prefix of path2 (including equality). * diff --git a/src/port/pg_popcount_aarch64.c b/src/port/pg_popcount_aarch64.c index 0b6b86de4d0..0c93e2e625e 100644 --- a/src/port/pg_popcount_aarch64.c +++ b/src/port/pg_popcount_aarch64.c @@ -478,4 +478,10 @@ pg_popcount_masked_neon(const char *buf, int bytes, bits8 mask) return popcnt; } -#endif /* POPCNT_AARCH64 */ +#else /* POPCNT_AARCH64 */ + +/* prevent linker complaints about empty module */ +extern int pg_popcount_aarch64_dummy_variable; +int pg_popcount_aarch64_dummy_variable = 0; + +#endif /* ! POPCNT_AARCH64 */ diff --git a/src/port/pg_popcount_avx512.c b/src/port/pg_popcount_avx512.c index 80c0aee3e73..896bc7473b2 100644 --- a/src/port/pg_popcount_avx512.c +++ b/src/port/pg_popcount_avx512.c @@ -220,4 +220,11 @@ pg_popcount_masked_avx512(const char *buf, int bytes, bits8 mask) } #endif /* TRY_POPCNT_X86_64 */ -#endif /* USE_AVX512_POPCNT_WITH_RUNTIME_CHECK */ + +#else /* USE_AVX512_POPCNT_WITH_RUNTIME_CHECK */ + +/* prevent linker complaints about empty module */ +extern int pg_popcount_avx512_dummy_variable; +int pg_popcount_avx512_dummy_variable = 0; + +#endif /* ! USE_AVX512_POPCNT_WITH_RUNTIME_CHECK */ diff --git a/src/port/tar.c b/src/port/tar.c index 592b4fb7b0f..fee9dbbf5be 100644 --- a/src/port/tar.c +++ b/src/port/tar.c @@ -87,7 +87,7 @@ read_tar_number(const char *s, int len) * be 512 bytes, per the tar standard. */ int -tarChecksum(char *header) +tarChecksum(const char *header) { int i, sum; @@ -95,15 +95,44 @@ tarChecksum(char *header) /* * Per POSIX, the checksum is the simple sum of all bytes in the header, * treating the bytes as unsigned, and treating the checksum field (at - * offset 148) as though it contained 8 spaces. + * offset TAR_OFFSET_CHECKSUM) as though it contained 8 spaces. */ sum = 8 * ' '; /* presumed value for checksum field */ - for (i = 0; i < 512; i++) - if (i < 148 || i >= 156) + for (i = 0; i < TAR_BLOCK_SIZE; i++) + if (i < TAR_OFFSET_CHECKSUM || i >= TAR_OFFSET_CHECKSUM + 8) sum += 0xFF & header[i]; return sum; } +/* + * Check validity of a tar header (assumed to be 512 bytes long). + * We verify the checksum and the magic number / version. + */ +bool +isValidTarHeader(const char *header) +{ + int sum; + int chk = tarChecksum(header); + + sum = read_tar_number(&header[TAR_OFFSET_CHECKSUM], 8); + + if (sum != chk) + return false; + + /* POSIX tar format */ + if (memcmp(&header[TAR_OFFSET_MAGIC], "ustar\0", 6) == 0 && + memcmp(&header[TAR_OFFSET_VERSION], "00", 2) == 0) + return true; + /* GNU tar format */ + if (memcmp(&header[TAR_OFFSET_MAGIC], "ustar \0", 8) == 0) + return true; + /* not-quite-POSIX format written by pre-9.3 pg_dump */ + if (memcmp(&header[TAR_OFFSET_MAGIC], "ustar00\0", 8) == 0) + return true; + + return false; +} + /* * Fill in the buffer pointed to by h with a tar format header. This buffer diff --git a/src/port/win32setlocale.c b/src/port/win32setlocale.c index 7c0982439db..6e084946132 100644 --- a/src/port/win32setlocale.c +++ b/src/port/win32setlocale.c @@ -119,9 +119,9 @@ map_locale(const struct locale_map *map, const char *locale) const char *needle_start = map[i].locale_name_start; const char *needle_end = map[i].locale_name_end; const char *replacement = map[i].replacement; - char *match; - char *match_start = NULL; - char *match_end = NULL; + const char *match; + const char *match_start = NULL; + const char *match_end = NULL; match = strstr(locale, needle_start); if (match) @@ -148,7 +148,7 @@ map_locale(const struct locale_map *map, const char *locale) /* Found a match. Replace the matched string. */ int matchpos = match_start - locale; int replacementlen = strlen(replacement); - char *rest = match_end; + const char *rest = match_end; int restlen = strlen(rest); /* check that the result fits in the static buffer */ diff --git a/src/test/isolation/expected/insert-conflict-do-update-4.out b/src/test/isolation/expected/insert-conflict-do-update-4.out index 6e96e0d12da..80af2798a94 100644 --- a/src/test/isolation/expected/insert-conflict-do-update-4.out +++ b/src/test/isolation/expected/insert-conflict-do-update-4.out @@ -12,11 +12,11 @@ step insert1: INSERT INTO upsert VALUES (1, 11, 111) step update2a: UPDATE upsert SET i = i + 10 WHERE i = 1; step c2: COMMIT; step insert1: <... completed> -step select1: SELECT * FROM upsert; +step select1: SELECT * FROM upsert ORDER BY i; i| j| k --+--+--- -11|10|100 1|11|111 +11|10|100 (2 rows) step c1: COMMIT; @@ -33,7 +33,7 @@ step insert1: INSERT INTO upsert VALUES (1, 11, 111) step update2b: UPDATE upsert SET i = i + 150 WHERE i = 1; step c2: COMMIT; step insert1: <... completed> -step select1: SELECT * FROM upsert; +step select1: SELECT * FROM upsert ORDER BY i; i| j| k ---+--+--- 1|11|111 @@ -54,7 +54,7 @@ step insert1: INSERT INTO upsert VALUES (1, 11, 111) step delete2: DELETE FROM upsert WHERE i = 1; step c2: COMMIT; step insert1: <... completed> -step select1: SELECT * FROM upsert; +step select1: SELECT * FROM upsert ORDER BY i; i| j| k -+--+--- 1|11|111 diff --git a/src/test/isolation/expected/merge-update.out b/src/test/isolation/expected/merge-update.out index feceacf4818..821565b4303 100644 --- a/src/test/isolation/expected/merge-update.out +++ b/src/test/isolation/expected/merge-update.out @@ -549,3 +549,36 @@ step c1: COMMIT; step pa_merge2c_dup: <... completed> ERROR: MERGE command cannot affect row a second time step a2: ABORT; + +starting permutation: merge2a c1 s1beginrr merge1 c2 +step merge2a: + MERGE INTO target t + USING (SELECT 1 as key, 'merge2a' as val) s + ON s.key = t.key + WHEN NOT MATCHED THEN + INSERT VALUES (s.key, s.val) + WHEN MATCHED THEN + UPDATE set key = t.key + 1, val = t.val || ' updated by ' || s.val + WHEN NOT MATCHED BY SOURCE THEN + UPDATE set key = t.key + 1, val = t.val || ' source not matched by merge2a' + RETURNING merge_action(), old, new, t.*; + +merge_action|old |new |key|val +------------+----------+-------------------------------+---+------------------------- +UPDATE |(1,setup1)|(2,"setup1 updated by merge2a")| 2|setup1 updated by merge2a +(1 row) + +step c1: COMMIT; +step s1beginrr: BEGIN ISOLATION LEVEL REPEATABLE READ; +step merge1: + MERGE INTO target t + USING (SELECT 1 as key, 'merge1' as val) s + ON s.key = t.key + WHEN NOT MATCHED THEN + INSERT VALUES (s.key, s.val) + WHEN MATCHED THEN + UPDATE set key = t.key + 1, val = t.val || ' updated by ' || s.val; + +step c2: COMMIT; +step merge1: <... completed> +ERROR: could not serialize access due to concurrent update diff --git a/src/test/isolation/specs/insert-conflict-do-update-4.spec b/src/test/isolation/specs/insert-conflict-do-update-4.spec index 6297b1d1d6c..a62531660d3 100644 --- a/src/test/isolation/specs/insert-conflict-do-update-4.spec +++ b/src/test/isolation/specs/insert-conflict-do-update-4.spec @@ -23,7 +23,7 @@ session s1 setup { BEGIN ISOLATION LEVEL READ COMMITTED; } step insert1 { INSERT INTO upsert VALUES (1, 11, 111) ON CONFLICT (i) DO UPDATE SET k = EXCLUDED.k; } -step select1 { SELECT * FROM upsert; } +step select1 { SELECT * FROM upsert ORDER BY i; } step c1 { COMMIT; } session s2 diff --git a/src/test/isolation/specs/merge-update.spec b/src/test/isolation/specs/merge-update.spec index 771ee5b70cf..b902779edd6 100644 --- a/src/test/isolation/specs/merge-update.spec +++ b/src/test/isolation/specs/merge-update.spec @@ -93,6 +93,7 @@ step "pa_merge3" } step "c1" { COMMIT; } step "a1" { ABORT; } +step "s1beginrr" { BEGIN ISOLATION LEVEL REPEATABLE READ; } session "s2" setup @@ -223,3 +224,4 @@ permutation "pa_merge2" "c1" "pa_merge2a" "pa_select2" "c2" # succeeds permutation "pa_merge3" "pa_merge2b_when" "c1" "pa_select2" "c2" # WHEN not satisfied by updated tuple permutation "pa_merge1" "pa_merge2b_when" "c1" "pa_select2" "c2" # WHEN satisfied by updated tuple permutation "pa_merge1" "pa_merge2c_dup" "c1" "a2" +permutation "merge2a" "c1" "s1beginrr" "merge1" "c2" diff --git a/src/test/modules/Makefile b/src/test/modules/Makefile index 6851d7f5adf..4e82d6f1517 100644 --- a/src/test/modules/Makefile +++ b/src/test/modules/Makefile @@ -19,6 +19,7 @@ SUBDIRS = \ test_cloexec \ test_copy_callbacks \ test_custom_rmgrs \ + test_custom_types \ test_ddl_deparse \ test_dsa \ test_dsm_registry \ diff --git a/src/test/modules/injection_points/injection_stats_fixed.c b/src/test/modules/injection_points/injection_stats_fixed.c index 74c35fcbfa7..666b305261f 100644 --- a/src/test/modules/injection_points/injection_stats_fixed.c +++ b/src/test/modules/injection_points/injection_stats_fixed.c @@ -52,7 +52,7 @@ static const PgStat_KindInfo injection_stats_fixed = { .fixed_amount = true, .write_to_file = true, - .shared_size = sizeof(PgStat_StatInjFixedEntry), + .shared_size = sizeof(PgStatShared_InjectionPointFixed), .shared_data_off = offsetof(PgStatShared_InjectionPointFixed, stats), .shared_data_len = sizeof(((PgStatShared_InjectionPointFixed *) 0)->stats), diff --git a/src/test/modules/meson.build b/src/test/modules/meson.build index 9cdc0666ffb..9a957351ab6 100644 --- a/src/test/modules/meson.build +++ b/src/test/modules/meson.build @@ -18,6 +18,7 @@ subdir('test_bloomfilter') subdir('test_cloexec') subdir('test_copy_callbacks') subdir('test_custom_rmgrs') +subdir('test_custom_types') subdir('test_ddl_deparse') subdir('test_dsa') subdir('test_dsm_registry') diff --git a/src/test/modules/test_custom_types/.gitignore b/src/test/modules/test_custom_types/.gitignore new file mode 100644 index 00000000000..5dcb3ff9723 --- /dev/null +++ b/src/test/modules/test_custom_types/.gitignore @@ -0,0 +1,4 @@ +# Generated subdirectories +/log/ +/results/ +/tmp_check/ diff --git a/src/test/modules/test_custom_types/Makefile b/src/test/modules/test_custom_types/Makefile new file mode 100644 index 00000000000..e1b582b26ea --- /dev/null +++ b/src/test/modules/test_custom_types/Makefile @@ -0,0 +1,20 @@ +# src/test/modules/test_custom_types/Makefile + +MODULES = test_custom_types + +EXTENSION = test_custom_types +DATA = test_custom_types--1.0.sql +PGFILEDESC = "test_custom_types - tests for dummy custom types" + +REGRESS = test_custom_types + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = src/test/modules/test_custom_types +top_builddir = ../../../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/src/test/modules/test_custom_types/README b/src/test/modules/test_custom_types/README new file mode 100644 index 00000000000..a37d2db577e --- /dev/null +++ b/src/test/modules/test_custom_types/README @@ -0,0 +1,9 @@ +test_custom_types +================= + +This module contains a set of custom data types, with some of the following +patterns: + +- typanalyze function registered to a custom type, returning false. +- typanalyze function registered to a custom type, registering invalid stats + data. diff --git a/src/test/modules/test_custom_types/expected/test_custom_types.out b/src/test/modules/test_custom_types/expected/test_custom_types.out new file mode 100644 index 00000000000..2fb6b0b10ee --- /dev/null +++ b/src/test/modules/test_custom_types/expected/test_custom_types.out @@ -0,0 +1,174 @@ +-- Tests with various custom types +CREATE EXTENSION test_custom_types; +-- Test comparison functions +SELECT '42'::int_custom = '42'::int_custom AS eq_test; + eq_test +--------- + t +(1 row) + +SELECT '42'::int_custom <> '42'::int_custom AS nt_test; + nt_test +--------- + f +(1 row) + +SELECT '42'::int_custom < '100'::int_custom AS lt_test; + lt_test +--------- + t +(1 row) + +SELECT '100'::int_custom > '42'::int_custom AS gt_test; + gt_test +--------- + t +(1 row) + +SELECT '42'::int_custom <= '100'::int_custom AS le_test; + le_test +--------- + t +(1 row) + +SELECT '100'::int_custom >= '42'::int_custom AS ge_test; + ge_test +--------- + t +(1 row) + +-- Create a table with the int_custom type +CREATE TABLE test_table ( + id int, + data int_custom +); +INSERT INTO test_table VALUES (1, '42'), (2, '100'), (3, '200'); +-- Verify data was inserted correctly +SELECT * FROM test_table ORDER BY id; + id | data +----+------ + 1 | 42 + 2 | 100 + 3 | 200 +(3 rows) + +-- Dummy function used for expression evaluations. +-- Note that this function does not use a SQL-standard function body on +-- purpose, so as external statistics can be loaded from it. +CREATE OR REPLACE FUNCTION func_int_custom (p_value int_custom) + RETURNS int_custom LANGUAGE plpgsql AS $$ + BEGIN + RETURN p_value; + END; $$; +-- Switch type to use typanalyze function that always returns false. +ALTER TYPE int_custom SET (ANALYZE = int_custom_typanalyze_false); +-- Extended statistics with an attribute that cannot be analyzed. +-- This includes all statistics kinds. +CREATE STATISTICS test_stats ON data, id FROM test_table; +-- Computation of the stats fails, no data generated. +ANALYZE test_table; +WARNING: statistics object "public.test_stats" could not be computed for relation "public.test_table" +SELECT stxname, stxdexpr IS NULL as expr_stats_is_null + FROM pg_statistic_ext s + LEFT JOIN pg_statistic_ext_data d ON s.oid = d.stxoid + WHERE stxname = 'test_stats'; + stxname | expr_stats_is_null +------------+-------------------- + test_stats | t +(1 row) + +DROP STATISTICS test_stats; +-- Extended statistics with an expression that cannot be analyzed. +CREATE STATISTICS test_stats ON func_int_custom(data), (id) FROM test_table; +-- Computation of the stats fails, no data generated. +ANALYZE test_table; +WARNING: statistics object "public.test_stats" could not be computed for relation "public.test_table" +SELECT stxname, stxdexpr IS NULL as expr_stats_is_null + FROM pg_statistic_ext s + LEFT JOIN pg_statistic_ext_data d ON s.oid = d.stxoid + WHERE stxname = 'test_stats'; + stxname | expr_stats_is_null +------------+-------------------- + test_stats | t +(1 row) + +DROP STATISTICS test_stats; +-- There should be no data stored for the expression. +SELECT tablename, + statistics_name, + null_frac, + avg_width + FROM pg_stats_ext_exprs WHERE statistics_name = 'test_stats' \gx +(0 rows) + +-- Switch type to use typanalyze function that generates invalid data. +ALTER TYPE int_custom SET (ANALYZE = int_custom_typanalyze_invalid); +-- Extended statistics with an attribute that generates invalid stats. +CREATE STATISTICS test_stats ON data, id FROM test_table; +-- Computation of the stats fails, no data generated. +ANALYZE test_table; +SELECT stxname, stxdexpr IS NULL as expr_stats_is_null + FROM pg_statistic_ext s + LEFT JOIN pg_statistic_ext_data d ON s.oid = d.stxoid + WHERE stxname = 'test_stats'; + stxname | expr_stats_is_null +------------+-------------------- + test_stats | t +(1 row) + +DROP STATISTICS test_stats; +-- Extended statistics with an expression that generates invalid data. +CREATE STATISTICS test_stats ON func_int_custom(data), (id) FROM test_table; +-- Computation of the stats fails, some data generated. +ANALYZE test_table; +SELECT stxname, stxdexpr IS NULL as expr_stats_is_null + FROM pg_statistic_ext s + LEFT JOIN pg_statistic_ext_data d ON s.oid = d.stxoid + WHERE stxname = 'test_stats'; + stxname | expr_stats_is_null +------------+-------------------- + test_stats | f +(1 row) + +-- There should be some data stored for the expression, stored as NULL. +SELECT tablename, + statistics_name, + null_frac, + avg_width, + n_distinct, + most_common_vals, + most_common_freqs, + histogram_bounds, + correlation, + most_common_elems, + most_common_elem_freqs, + elem_count_histogram + FROM pg_stats_ext_exprs WHERE statistics_name = 'test_stats' \gx +-[ RECORD 1 ]----------+----------- +tablename | test_table +statistics_name | test_stats +null_frac | +avg_width | +n_distinct | +most_common_vals | +most_common_freqs | +histogram_bounds | +correlation | +most_common_elems | +most_common_elem_freqs | +elem_count_histogram | + +-- Run a query able to load the extended stats, including the NULL data. +SELECT COUNT(*) FROM test_table GROUP BY (func_int_custom(data)); + count +------- + 1 + 1 + 1 +(3 rows) + +DROP STATISTICS test_stats; +-- Cleanup +DROP FUNCTION func_int_custom; +DROP TABLE test_table; +DROP EXTENSION test_custom_types; diff --git a/src/test/modules/test_custom_types/meson.build b/src/test/modules/test_custom_types/meson.build new file mode 100644 index 00000000000..3d4f433dd51 --- /dev/null +++ b/src/test/modules/test_custom_types/meson.build @@ -0,0 +1,33 @@ +# Copyright (c) 2026, PostgreSQL Global Development Group + +test_custom_types_sources = files( + 'test_custom_types.c', +) + +if host_system == 'windows' + test_custom_types_sources += rc_lib_gen.process(win32ver_rc, extra_args: [ + '--NAME', 'test_custom_types', + '--FILEDESC', 'test_custom_types - tests for dummy custom types',]) +endif + +test_custom_types = shared_module('test_custom_types', + test_custom_types_sources, + kwargs: pg_test_mod_args, +) +test_install_libs += test_custom_types + +test_install_data += files( + 'test_custom_types.control', + 'test_custom_types--1.0.sql', +) + +tests += { + 'name': 'test_custom_types', + 'sd': meson.current_source_dir(), + 'bd': meson.current_build_dir(), + 'regress': { + 'sql': [ + 'test_custom_types', + ], + }, +} diff --git a/src/test/modules/test_custom_types/sql/test_custom_types.sql b/src/test/modules/test_custom_types/sql/test_custom_types.sql new file mode 100644 index 00000000000..206a17c667f --- /dev/null +++ b/src/test/modules/test_custom_types/sql/test_custom_types.sql @@ -0,0 +1,104 @@ +-- Tests with various custom types + +CREATE EXTENSION test_custom_types; + +-- Test comparison functions +SELECT '42'::int_custom = '42'::int_custom AS eq_test; +SELECT '42'::int_custom <> '42'::int_custom AS nt_test; +SELECT '42'::int_custom < '100'::int_custom AS lt_test; +SELECT '100'::int_custom > '42'::int_custom AS gt_test; +SELECT '42'::int_custom <= '100'::int_custom AS le_test; +SELECT '100'::int_custom >= '42'::int_custom AS ge_test; + +-- Create a table with the int_custom type +CREATE TABLE test_table ( + id int, + data int_custom +); +INSERT INTO test_table VALUES (1, '42'), (2, '100'), (3, '200'); + +-- Verify data was inserted correctly +SELECT * FROM test_table ORDER BY id; + +-- Dummy function used for expression evaluations. +-- Note that this function does not use a SQL-standard function body on +-- purpose, so as external statistics can be loaded from it. +CREATE OR REPLACE FUNCTION func_int_custom (p_value int_custom) + RETURNS int_custom LANGUAGE plpgsql AS $$ + BEGIN + RETURN p_value; + END; $$; + +-- Switch type to use typanalyze function that always returns false. +ALTER TYPE int_custom SET (ANALYZE = int_custom_typanalyze_false); + +-- Extended statistics with an attribute that cannot be analyzed. +-- This includes all statistics kinds. +CREATE STATISTICS test_stats ON data, id FROM test_table; +-- Computation of the stats fails, no data generated. +ANALYZE test_table; +SELECT stxname, stxdexpr IS NULL as expr_stats_is_null + FROM pg_statistic_ext s + LEFT JOIN pg_statistic_ext_data d ON s.oid = d.stxoid + WHERE stxname = 'test_stats'; +DROP STATISTICS test_stats; + +-- Extended statistics with an expression that cannot be analyzed. +CREATE STATISTICS test_stats ON func_int_custom(data), (id) FROM test_table; +-- Computation of the stats fails, no data generated. +ANALYZE test_table; +SELECT stxname, stxdexpr IS NULL as expr_stats_is_null + FROM pg_statistic_ext s + LEFT JOIN pg_statistic_ext_data d ON s.oid = d.stxoid + WHERE stxname = 'test_stats'; +DROP STATISTICS test_stats; +-- There should be no data stored for the expression. +SELECT tablename, + statistics_name, + null_frac, + avg_width + FROM pg_stats_ext_exprs WHERE statistics_name = 'test_stats' \gx + +-- Switch type to use typanalyze function that generates invalid data. +ALTER TYPE int_custom SET (ANALYZE = int_custom_typanalyze_invalid); + +-- Extended statistics with an attribute that generates invalid stats. +CREATE STATISTICS test_stats ON data, id FROM test_table; +-- Computation of the stats fails, no data generated. +ANALYZE test_table; +SELECT stxname, stxdexpr IS NULL as expr_stats_is_null + FROM pg_statistic_ext s + LEFT JOIN pg_statistic_ext_data d ON s.oid = d.stxoid + WHERE stxname = 'test_stats'; +DROP STATISTICS test_stats; + +-- Extended statistics with an expression that generates invalid data. +CREATE STATISTICS test_stats ON func_int_custom(data), (id) FROM test_table; +-- Computation of the stats fails, some data generated. +ANALYZE test_table; +SELECT stxname, stxdexpr IS NULL as expr_stats_is_null + FROM pg_statistic_ext s + LEFT JOIN pg_statistic_ext_data d ON s.oid = d.stxoid + WHERE stxname = 'test_stats'; +-- There should be some data stored for the expression, stored as NULL. +SELECT tablename, + statistics_name, + null_frac, + avg_width, + n_distinct, + most_common_vals, + most_common_freqs, + histogram_bounds, + correlation, + most_common_elems, + most_common_elem_freqs, + elem_count_histogram + FROM pg_stats_ext_exprs WHERE statistics_name = 'test_stats' \gx +-- Run a query able to load the extended stats, including the NULL data. +SELECT COUNT(*) FROM test_table GROUP BY (func_int_custom(data)); +DROP STATISTICS test_stats; + +-- Cleanup +DROP FUNCTION func_int_custom; +DROP TABLE test_table; +DROP EXTENSION test_custom_types; diff --git a/src/test/modules/test_custom_types/test_custom_types--1.0.sql b/src/test/modules/test_custom_types/test_custom_types--1.0.sql new file mode 100644 index 00000000000..ce0e905d636 --- /dev/null +++ b/src/test/modules/test_custom_types/test_custom_types--1.0.sql @@ -0,0 +1,164 @@ +/* src/test/modules/test_custom_types/test_custom_types--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION test_custom_types" to load this file. \quit + +-- +-- Input/output functions for int_custom type +-- +CREATE FUNCTION int_custom_in(cstring) +RETURNS int_custom +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int_custom_out(int_custom) +RETURNS cstring +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +-- +-- Typanalyze function that returns false +-- +CREATE FUNCTION int_custom_typanalyze_false(internal) +RETURNS boolean +AS 'MODULE_PATHNAME' +LANGUAGE C STRICT; + +-- +-- Typanalyze function that returns invalid stats +-- +CREATE FUNCTION int_custom_typanalyze_invalid(internal) +RETURNS boolean +AS 'MODULE_PATHNAME' +LANGUAGE C STRICT; + +-- +-- The int_custom type definition +-- +-- This type is identical to int4 in storage, and is used in subsequent +-- tests to have different properties. +-- +CREATE TYPE int_custom ( + INPUT = int_custom_in, + OUTPUT = int_custom_out, + LIKE = int4 +); + +-- +-- Comparison functions for int_custom +-- +-- These are required to create a btree operator class, which is needed +-- for the type to be usable in extended statistics objects. +-- +CREATE FUNCTION int_custom_eq(int_custom, int_custom) +RETURNS boolean +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int_custom_ne(int_custom, int_custom) +RETURNS boolean +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int_custom_lt(int_custom, int_custom) +RETURNS boolean +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int_custom_le(int_custom, int_custom) +RETURNS boolean +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int_custom_gt(int_custom, int_custom) +RETURNS boolean +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int_custom_ge(int_custom, int_custom) +RETURNS boolean +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION int_custom_cmp(int_custom, int_custom) +RETURNS integer +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT; + +-- Operators for int_custom, for btree operator class +CREATE OPERATOR = ( + LEFTARG = int_custom, + RIGHTARG = int_custom, + FUNCTION = int_custom_eq, + COMMUTATOR = =, + NEGATOR = <>, + RESTRICT = eqsel, + JOIN = eqjoinsel, + HASHES, + MERGES +); + +CREATE OPERATOR <> ( + LEFTARG = int_custom, + RIGHTARG = int_custom, + FUNCTION = int_custom_ne, + COMMUTATOR = <>, + NEGATOR = =, + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR < ( + LEFTARG = int_custom, + RIGHTARG = int_custom, + FUNCTION = int_custom_lt, + COMMUTATOR = >, + NEGATOR = >=, + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR <= ( + LEFTARG = int_custom, + RIGHTARG = int_custom, + FUNCTION = int_custom_le, + COMMUTATOR = >=, + NEGATOR = >, + RESTRICT = scalarlesel, + JOIN = scalarlejoinsel +); + +CREATE OPERATOR > ( + LEFTARG = int_custom, + RIGHTARG = int_custom, + FUNCTION = int_custom_gt, + COMMUTATOR = <, + NEGATOR = <=, + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = int_custom, + RIGHTARG = int_custom, + FUNCTION = int_custom_ge, + COMMUTATOR = <=, + NEGATOR = <, + RESTRICT = scalargesel, + JOIN = scalargejoinsel +); + +-- +-- Btree operator class for int_custom +-- +-- This is required for the type to be usable in extended statistics objects, +-- for attributes and expressions. +-- +CREATE OPERATOR CLASS int_custom_ops + DEFAULT FOR TYPE int_custom USING btree AS + OPERATOR 1 <, + OPERATOR 2 <=, + OPERATOR 3 =, + OPERATOR 4 >=, + OPERATOR 5 >, + FUNCTION 1 int_custom_cmp(int_custom, int_custom); diff --git a/src/test/modules/test_custom_types/test_custom_types.c b/src/test/modules/test_custom_types/test_custom_types.c new file mode 100644 index 00000000000..41262044b47 --- /dev/null +++ b/src/test/modules/test_custom_types/test_custom_types.c @@ -0,0 +1,182 @@ +/*-------------------------------------------------------------------------- + * + * test_custom_types.c + * Test module for a set of functions for custom types. + * + * The custom type used in this module is similar to int4 for simplicity, + * except that it is able to use various typanalyze functions to enforce + * check patterns with ANALYZE. + * + * Copyright (c) 1996-2026, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/test/modules/test_custom_types/test_custom_types.c + * + *-------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "fmgr.h" +#include "commands/vacuum.h" +#include "utils/builtins.h" + +PG_MODULE_MAGIC; + +/* Function declarations */ +PG_FUNCTION_INFO_V1(int_custom_in); +PG_FUNCTION_INFO_V1(int_custom_out); +PG_FUNCTION_INFO_V1(int_custom_typanalyze_false); +PG_FUNCTION_INFO_V1(int_custom_typanalyze_invalid); +PG_FUNCTION_INFO_V1(int_custom_eq); +PG_FUNCTION_INFO_V1(int_custom_ne); +PG_FUNCTION_INFO_V1(int_custom_lt); +PG_FUNCTION_INFO_V1(int_custom_le); +PG_FUNCTION_INFO_V1(int_custom_gt); +PG_FUNCTION_INFO_V1(int_custom_ge); +PG_FUNCTION_INFO_V1(int_custom_cmp); + +/* + * int_custom_in - input function for int_custom type + * + * Converts a string to a int_custom (which is just an int32 internally). + */ +Datum +int_custom_in(PG_FUNCTION_ARGS) +{ + char *num = PG_GETARG_CSTRING(0); + + PG_RETURN_INT32(pg_strtoint32_safe(num, fcinfo->context)); +} + +/* + * int_custom_out - output function for int_custom type + * + * Converts a int_custom to a string. + */ +Datum +int_custom_out(PG_FUNCTION_ARGS) +{ + int32 arg1 = PG_GETARG_INT32(0); + char *result = (char *) palloc(12); /* sign, 10 digits, '\0' */ + + pg_ltoa(arg1, result); + PG_RETURN_CSTRING(result); +} + +/* + * int_custom_typanalyze_false - typanalyze function that returns false + * + * This function returns false, to simulate a type that cannot be analyzed. + */ +Datum +int_custom_typanalyze_false(PG_FUNCTION_ARGS) +{ + PG_RETURN_BOOL(false); +} + +/* + * Callback used to compute invalid statistics. + */ +static void +int_custom_invalid_stats(VacAttrStats *stats, AnalyzeAttrFetchFunc fetchfunc, + int samplerows, double totalrows) +{ + /* We are not valid, and do not want to be. */ + stats->stats_valid = false; +} + +/* + * int_custom_typanalyze_invalid + * + * This function sets some invalid stats data, letting the caller know that + * we are safe for an analyze, returning true. + */ +Datum +int_custom_typanalyze_invalid(PG_FUNCTION_ARGS) +{ + VacAttrStats *stats = (VacAttrStats *) PG_GETARG_POINTER(0); + + /* If the attstattarget column is negative, use the default value */ + if (stats->attstattarget < 0) + stats->attstattarget = default_statistics_target; + + /* Buggy number, no need to care as long as it is positive */ + stats->minrows = 300; + + /* Set callback to compute some invalid stats */ + stats->compute_stats = int_custom_invalid_stats; + + PG_RETURN_BOOL(true); +} + +/* + * Comparison functions for int_custom type + */ +Datum +int_custom_eq(PG_FUNCTION_ARGS) +{ + int32 arg1 = PG_GETARG_INT32(0); + int32 arg2 = PG_GETARG_INT32(1); + + PG_RETURN_BOOL(arg1 == arg2); +} + +Datum +int_custom_ne(PG_FUNCTION_ARGS) +{ + int32 arg1 = PG_GETARG_INT32(0); + int32 arg2 = PG_GETARG_INT32(1); + + PG_RETURN_BOOL(arg1 != arg2); +} + +Datum +int_custom_lt(PG_FUNCTION_ARGS) +{ + int32 arg1 = PG_GETARG_INT32(0); + int32 arg2 = PG_GETARG_INT32(1); + + PG_RETURN_BOOL(arg1 < arg2); +} + +Datum +int_custom_le(PG_FUNCTION_ARGS) +{ + int32 arg1 = PG_GETARG_INT32(0); + int32 arg2 = PG_GETARG_INT32(1); + + PG_RETURN_BOOL(arg1 <= arg2); +} + +Datum +int_custom_gt(PG_FUNCTION_ARGS) +{ + int32 arg1 = PG_GETARG_INT32(0); + int32 arg2 = PG_GETARG_INT32(1); + + PG_RETURN_BOOL(arg1 > arg2); +} + +Datum +int_custom_ge(PG_FUNCTION_ARGS) +{ + int32 arg1 = PG_GETARG_INT32(0); + int32 arg2 = PG_GETARG_INT32(1); + + PG_RETURN_BOOL(arg1 >= arg2); +} + +Datum +int_custom_cmp(PG_FUNCTION_ARGS) +{ + int32 arg1 = PG_GETARG_INT32(0); + int32 arg2 = PG_GETARG_INT32(1); + + if (arg1 < arg2) + PG_RETURN_INT32(-1); + else if (arg1 > arg2) + PG_RETURN_INT32(1); + else + PG_RETURN_INT32(0); +} diff --git a/src/test/modules/test_custom_types/test_custom_types.control b/src/test/modules/test_custom_types/test_custom_types.control new file mode 100644 index 00000000000..d25a74ef5c4 --- /dev/null +++ b/src/test/modules/test_custom_types/test_custom_types.control @@ -0,0 +1,5 @@ +# test_custom_types extension +comment = 'Tests for dummy custom types' +default_version = '1.0' +module_pathname = '$libdir/test_custom_types' +relocatable = true diff --git a/src/test/modules/test_ddl_deparse/Makefile b/src/test/modules/test_ddl_deparse/Makefile index 3a57a95c849..4576ed31e20 100644 --- a/src/test/modules/test_ddl_deparse/Makefile +++ b/src/test/modules/test_ddl_deparse/Makefile @@ -27,6 +27,7 @@ REGRESS = test_ddl_deparse \ alter_type_enum \ opfamily \ defprivs \ + textsearch \ matviews EXTRA_INSTALL = contrib/pg_stat_statements diff --git a/src/test/modules/test_ddl_deparse/expected/textsearch.out b/src/test/modules/test_ddl_deparse/expected/textsearch.out new file mode 100644 index 00000000000..da0d89e9704 --- /dev/null +++ b/src/test/modules/test_ddl_deparse/expected/textsearch.out @@ -0,0 +1,5 @@ +CREATE TEXT SEARCH CONFIGURATION evttrig_tscfg (COPY = pg_catalog.simple); +NOTICE: DDL test: type simple, tag CREATE TEXT SEARCH CONFIGURATION +ALTER TEXT SEARCH CONFIGURATION evttrig_tscfg + DROP MAPPING FOR word; +NOTICE: DDL test: type alter text search configuration, tag ALTER TEXT SEARCH CONFIGURATION diff --git a/src/test/modules/test_ddl_deparse/meson.build b/src/test/modules/test_ddl_deparse/meson.build index bff65ba6333..f87eeac0e5a 100644 --- a/src/test/modules/test_ddl_deparse/meson.build +++ b/src/test/modules/test_ddl_deparse/meson.build @@ -47,6 +47,7 @@ tests += { 'alter_type_enum', 'opfamily', 'defprivs', + 'textsearch', 'matviews', ], }, diff --git a/src/test/modules/test_ddl_deparse/sql/textsearch.sql b/src/test/modules/test_ddl_deparse/sql/textsearch.sql new file mode 100644 index 00000000000..633899a31cb --- /dev/null +++ b/src/test/modules/test_ddl_deparse/sql/textsearch.sql @@ -0,0 +1,3 @@ +CREATE TEXT SEARCH CONFIGURATION evttrig_tscfg (COPY = pg_catalog.simple); +ALTER TEXT SEARCH CONFIGURATION evttrig_tscfg + DROP MAPPING FOR word; diff --git a/src/test/modules/test_dsa/expected/test_dsa.out b/src/test/modules/test_dsa/expected/test_dsa.out index 266010e77fe..4b53a7de4a4 100644 --- a/src/test/modules/test_dsa/expected/test_dsa.out +++ b/src/test/modules/test_dsa/expected/test_dsa.out @@ -11,3 +11,19 @@ SELECT test_dsa_resowners(); (1 row) +-- Test allocations across a pre-defined range of pages. This covers enough +-- range to check for the case of odd-sized segments, without making the test +-- too slow. +SELECT test_dsa_allocate(1001, 2000, 100); + test_dsa_allocate +------------------- + +(1 row) + +-- Larger size with odd-sized segment. +SELECT test_dsa_allocate(6501, 6600, 100); + test_dsa_allocate +------------------- + +(1 row) + diff --git a/src/test/modules/test_dsa/sql/test_dsa.sql b/src/test/modules/test_dsa/sql/test_dsa.sql index c3d8db94372..99b4a60dd14 100644 --- a/src/test/modules/test_dsa/sql/test_dsa.sql +++ b/src/test/modules/test_dsa/sql/test_dsa.sql @@ -2,3 +2,10 @@ CREATE EXTENSION test_dsa; SELECT test_dsa_basic(); SELECT test_dsa_resowners(); + +-- Test allocations across a pre-defined range of pages. This covers enough +-- range to check for the case of odd-sized segments, without making the test +-- too slow. +SELECT test_dsa_allocate(1001, 2000, 100); +-- Larger size with odd-sized segment. +SELECT test_dsa_allocate(6501, 6600, 100); diff --git a/src/test/modules/test_dsa/test_dsa--1.0.sql b/src/test/modules/test_dsa/test_dsa--1.0.sql index 2904cb23525..3ee2e44cc00 100644 --- a/src/test/modules/test_dsa/test_dsa--1.0.sql +++ b/src/test/modules/test_dsa/test_dsa--1.0.sql @@ -10,3 +10,7 @@ CREATE FUNCTION test_dsa_basic() CREATE FUNCTION test_dsa_resowners() RETURNS pg_catalog.void AS 'MODULE_PATHNAME' LANGUAGE C; + +CREATE FUNCTION test_dsa_allocate(int, int, int) + RETURNS pg_catalog.void + AS 'MODULE_PATHNAME' LANGUAGE C; diff --git a/src/test/modules/test_dsa/test_dsa.c b/src/test/modules/test_dsa/test_dsa.c index cd24d0f4873..3e6455a453b 100644 --- a/src/test/modules/test_dsa/test_dsa.c +++ b/src/test/modules/test_dsa/test_dsa.c @@ -13,8 +13,10 @@ #include "postgres.h" #include "fmgr.h" +#include "storage/dsm_registry.h" #include "storage/lwlock.h" #include "utils/dsa.h" +#include "utils/freepage.h" #include "utils/resowner.h" PG_MODULE_MAGIC; @@ -111,3 +113,42 @@ test_dsa_resowners(PG_FUNCTION_ARGS) PG_RETURN_VOID(); } + +/* + * test_dsa_allocate + * + * Test DSA allocation across a range of sizes to exercise the pagemap + * sizing logic in make_new_segment(). A fresh DSA is created for each + * iteration so that each allocation triggers a new segment creation, + * including the odd-sized segment path. + */ +PG_FUNCTION_INFO_V1(test_dsa_allocate); +Datum +test_dsa_allocate(PG_FUNCTION_ARGS) +{ + int start_num_pages = PG_GETARG_INT32(0); + int end_num_pages = PG_GETARG_INT32(1); + int step = PG_GETARG_INT32(2); + size_t usable_pages; + int tranche_id; + dsa_area *a; + dsa_pointer dp; + + if (start_num_pages > end_num_pages) + elog(ERROR, "incorrect start and end parameters"); + + /* XXX: this tranche is leaked */ + tranche_id = LWLockNewTrancheId(); + LWLockRegisterTranche(tranche_id, "test_dsa"); + + for (usable_pages = start_num_pages; usable_pages < end_num_pages; usable_pages += step) + { + a = dsa_create(tranche_id); + dp = dsa_allocate(a, usable_pages * FPM_PAGE_SIZE); + + dsa_free(a, dp); + dsa_detach(a); + } + + PG_RETURN_VOID(); +} diff --git a/src/test/modules/test_ginpostinglist/test_ginpostinglist.c b/src/test/modules/test_ginpostinglist/test_ginpostinglist.c index e1161bdfbfa..52161dcc38a 100644 --- a/src/test/modules/test_ginpostinglist/test_ginpostinglist.c +++ b/src/test/modules/test_ginpostinglist/test_ginpostinglist.c @@ -72,12 +72,12 @@ test_itemptr_pair(BlockNumber blk, OffsetNumber off, int maxsize) ItemPointerGetOffsetNumber(&decoded_itemptrs[0])); if (ndecoded == 2 && - !ItemPointerEquals(&orig_itemptrs[0], &decoded_itemptrs[0])) + !ItemPointerEquals(&orig_itemptrs[1], &decoded_itemptrs[1])) { elog(ERROR, "mismatch on second itemptr: (%u, %d) vs (%u, %d)", - 0, 1, - ItemPointerGetBlockNumber(&decoded_itemptrs[0]), - ItemPointerGetOffsetNumber(&decoded_itemptrs[0])); + blk, off, + ItemPointerGetBlockNumber(&decoded_itemptrs[1]), + ItemPointerGetOffsetNumber(&decoded_itemptrs[1])); } } diff --git a/src/test/modules/test_tidstore/test_tidstore.c b/src/test/modules/test_tidstore/test_tidstore.c index eb16e0fbfa6..d12d54f3677 100644 --- a/src/test/modules/test_tidstore/test_tidstore.c +++ b/src/test/modules/test_tidstore/test_tidstore.c @@ -75,6 +75,19 @@ itemptr_cmp(const void *left, const void *right) return 0; } +static int +offsetnumber_cmp(const void *a, const void *b) +{ + OffsetNumber l = *(const OffsetNumber *) a; + OffsetNumber r = *(const OffsetNumber *) b; + + if (l < r) + return -1; + else if (l > r) + return 1; + return 0; +} + /* * Create a TidStore. If shared is false, the tidstore is created * on TopMemoryContext, otherwise on DSA. Although the tidstore @@ -179,6 +192,9 @@ do_set_block_offsets(PG_FUNCTION_ARGS) noffs = ArrayGetNItems(ARR_NDIM(ta), ARR_DIMS(ta)); offs = ((OffsetNumber *) ARR_DATA_PTR(ta)); + /* TidStoreSetBlockOffsets() requires offsets to be strictly ascending. */ + qsort(offs, noffs, sizeof(OffsetNumber), offsetnumber_cmp); + /* Set TIDs in the store */ TidStoreLockExclusive(tidstore); TidStoreSetBlockOffsets(tidstore, blkno, offs, noffs); diff --git a/src/test/perl/PostgreSQL/Test/Utils.pm b/src/test/perl/PostgreSQL/Test/Utils.pm index d0ff92c32bb..204c6a27be8 100644 --- a/src/test/perl/PostgreSQL/Test/Utils.pm +++ b/src/test/perl/PostgreSQL/Test/Utils.pm @@ -92,6 +92,8 @@ our @EXPORT = qw( command_ok_or_fails_like command_checks_all + tar_portability_options + $windows_os $is_msys2 $use_unix_sockets @@ -1150,6 +1152,51 @@ sub command_checks_all =pod +=item tar_portability_options(tar) + +Check for non-default options we need to give to tar to create +a tarfile we can decode (i.e., no "pax" extensions). +Not needed in tests that only use tar to read tarfiles. + +Returns options as an array. + +=cut + +sub tar_portability_options +{ + local $Test::Builder::Level = $Test::Builder::Level + 1; + + my ($tar) = @_; + + my @tar_p_flags = (); + + return @tar_p_flags if (!defined $tar || $tar eq ''); + + # GNU tar typically produces gnu-format archives, which we can read fine. + # But some platforms configure it to default to posix/pax format, and + # apparently they enable --sparse too. Override that. + # + # ustar format supports UIDs only up to 2^21 - 1 (2097151). Override + # owner/group to avoid failures on systems where the running user's UID/GID + # exceeds that limit. + my $devnull = File::Spec->devnull(); + if (system( + "$tar --format=ustar --owner=0 --group=0 -cf $devnull $devnull 2>$devnull" + ) == 0) + { + # GNU tar (Linux), BSD tar (FreeBSD, NetBSD, macOS, Windows) + push(@tar_p_flags, "--format=ustar", "--owner=0", "--group=0"); + } + elsif (system("$tar -F ustar -cf $devnull $devnull 2>$devnull") == 0) + { + # OpenBSD tar + push(@tar_p_flags, "-F", "ustar"); + } + return @tar_p_flags; +} + +=pod + =back =cut diff --git a/src/test/postmaster/meson.build b/src/test/postmaster/meson.build index 0ab32b42f2e..ae4a2fcc340 100644 --- a/src/test/postmaster/meson.build +++ b/src/test/postmaster/meson.build @@ -9,6 +9,7 @@ tests += { 't/001_basic.pl', 't/002_connection_limits.pl', 't/003_start_stop.pl', + 't/004_negotiate.pl', ], }, } diff --git a/src/test/postmaster/t/004_negotiate.pl b/src/test/postmaster/t/004_negotiate.pl new file mode 100644 index 00000000000..f01b7519571 --- /dev/null +++ b/src/test/postmaster/t/004_negotiate.pl @@ -0,0 +1,82 @@ +# Copyright (c) 2026, PostgreSQL Global Development Group + +# Test the negotiation of combined SSL and GSS requests. This test +# relies on both SSL and GSS requests to be rejected first, followed +# by more requests. + +use strict; +use warnings FATAL => 'all'; +use PostgreSQL::Test::Cluster; +use PostgreSQL::Test::Utils; +use Test::More; +use Time::HiRes qw(usleep); + +my $node = PostgreSQL::Test::Cluster->new('main'); +$node->init; +$node->append_conf('postgresql.conf', "log_min_messages = debug2"); +$node->append_conf('postgresql.conf', + "log_connections = 'receipt,authentication,authorization'"); +$node->append_conf('postgresql.conf', 'trace_connection_negotiation=on'); +$node->start; + +if (!$node->raw_connect_works()) +{ + plan skip_all => "this test requires working raw_connect()"; +} + +my $sock = $node->raw_connect(); + +# SSLRequest: packet length followed by NEGOTIATE_SSL_CODE. +my $ssl_request = pack("Nnn", 8, 1234, 5679); + +# GSSENCRequest: packet length followed by NEGOTIATE_GSS_CODE. +my $gss_request = pack("Nnn", 8, 1234, 5680); + +# Send SSLRequest, reject or bypass. +$sock->send($ssl_request); +my $reply = ""; +$sock->recv($reply, 1); +if ($reply ne 'N') +{ + $sock->close(); + plan skip_all => + "server accepted SSL; test requires SSL to be rejected"; +} + +# Send GSSENCRequest, reject or bypass test. +$sock->send($gss_request); +$reply = ""; +$sock->recv($reply, 1); +if ($reply ne 'N') +{ + $sock->close(); + plan skip_all => + "server accepted GSS; test requires GSS to be rejected"; +} + +my $log_offset = -s $node->logfile; + +# Send a second SSLRequest, now that we know that both SSL and GSS have +# been rejected for this connection. We are done with both requests, so +# extra requests will be rejected and fail with an invalid protocol +# version, and the connection should be closed by the server. +$sock->send($ssl_request); + +# Try to read a response, there should be nothing, and certainly not an +# extra 'N' message indicating a rejection. +$reply = ""; +my $bytes = $sock->recv($reply, 1024); +isnt($reply, 'N', + "server does not re-enter SSL negotiation after SSL+GSS were both tried"); + +$sock->close(); +$node->wait_for_log(qr/FATAL: .* unsupported frontend protocol 1234.5679/, + $log_offset); + +# Check extra connection with a simple query. +my $result = $node->safe_psql('postgres', 'select 1;'); +is($result, '1', 'server able to accept connection'); + +$node->stop; + +done_testing(); diff --git a/src/test/recovery/t/004_timeline_switch.pl b/src/test/recovery/t/004_timeline_switch.pl index 4cceb5fd566..5c2f8665330 100644 --- a/src/test/recovery/t/004_timeline_switch.pl +++ b/src/test/recovery/t/004_timeline_switch.pl @@ -34,11 +34,10 @@ $node_primary->safe_psql('postgres', "CREATE TABLE tab_int AS SELECT generate_series(1,1000) AS a"); -# Wait until standby has replayed enough data on standby 1 -$node_primary->wait_for_catchup($node_standby_1); - -# Stop and remove primary -$node_primary->teardown_node; +# Cleanly stop and remove primary. A clean stop is required so as all +# the records generated on the primary are received and flushed by the two +# standbys. +$node_primary->stop; # promote standby 1 using "pg_promote", switching it to a new timeline my $psql_out = ''; diff --git a/src/test/recovery/t/009_twophase.pl b/src/test/recovery/t/009_twophase.pl index 2badc868c4d..e791c2c8e40 100644 --- a/src/test/recovery/t/009_twophase.pl +++ b/src/test/recovery/t/009_twophase.pl @@ -222,7 +222,7 @@ sub configure_and_reload SAVEPOINT s1; INSERT INTO t_009_tbl VALUES (22, 'issued to ${cur_primary_name}'); PREPARE TRANSACTION 'xact_009_10';"); -$cur_primary->teardown_node; +$cur_primary->stop; $cur_standby->promote; # change roles diff --git a/src/test/regress/expected/aggregates.out b/src/test/regress/expected/aggregates.out index 4cfbe424603..cdb4ecf288f 100644 --- a/src/test/regress/expected/aggregates.out +++ b/src/test/regress/expected/aggregates.out @@ -1515,6 +1515,37 @@ explain (costs off) select y,z from t2 group by y,z; -> Seq Scan on t2 (3 rows) +-- A unique index proves uniqueness only under its own opfamily. When the +-- GROUP BY's eqop comes from a different opfamily with looser equality, +-- rows the index regards as distinct can collapse into one GROUP BY group, +-- so the index is not usable for removing redundant columns. +create type t_rec as (x numeric); +create temp table t_opf (a t_rec not null, b text); +create unique index on t_opf (a record_image_ops); +-- (1.0) and (1.00) are bytewise distinct but logically equal as records; +-- the index admits both, but GROUP BY a (default record_ops) would merge +-- them, so b must be retained as a grouping key. +insert into t_opf values (row(1.0)::t_rec, 'X'), (row(1.00)::t_rec, 'Y'); +explain (costs off) +select a, b from t_opf group by a, b order by b; + QUERY PLAN +------------------------------- + Group + Group Key: b, a + -> Sort + Sort Key: b, a + -> Seq Scan on t_opf +(5 rows) + +select a, b from t_opf group by a, b order by b; + a | b +--------+--- + (1.0) | X + (1.00) | Y +(2 rows) + +drop table t_opf; +drop type t_rec; drop table t1 cascade; NOTICE: drop cascades to table t1c drop table t2; @@ -1561,6 +1592,19 @@ group by f2; ----+------- (0 rows) +-- check that we preserve join alias in GROUP BY expressions +create temp view v1 as +select f1::int from t1 left join t2 using (f1) group by f1; +select pg_get_viewdef('v1'::regclass); + pg_get_viewdef +------------------------------- + SELECT (f1)::integer AS f1 + + FROM (t1 + + LEFT JOIN t2 USING (f1))+ + GROUP BY f1; +(1 row) + +drop view v1; drop table t1, t2; -- -- Test planner's selection of pathkeys for ORDER BY aggregates diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out index 11dbb0426f1..65a18ca1d9b 100644 --- a/src/test/regress/expected/alter_table.out +++ b/src/test/regress/expected/alter_table.out @@ -3844,6 +3844,16 @@ Referenced by: ALTER TABLE test_add_column ADD COLUMN IF NOT EXISTS c5 SERIAL CHECK (c5 > 10); NOTICE: column "c5" of relation "test_add_column" already exists, skipping +ALTER TABLE test_add_column + ADD c6 integer; -- omit COLUMN +ALTER TABLE test_add_column + ADD IF NOT EXISTS c6 integer; +NOTICE: column "c6" of relation "test_add_column" already exists, skipping +ALTER TABLE test_add_column + DROP c6; -- omit COLUMN +ALTER TABLE test_add_column + DROP IF EXISTS c6; +NOTICE: column "c6" of relation "test_add_column" does not exist, skipping \d test_add_column* Table "public.test_add_column" Column | Type | Collation | Nullable | Default diff --git a/src/test/regress/expected/collate.icu.utf8.out b/src/test/regress/expected/collate.icu.utf8.out index 96379ce30a2..66093040965 100644 --- a/src/test/regress/expected/collate.icu.utf8.out +++ b/src/test/regress/expected/collate.icu.utf8.out @@ -1644,6 +1644,310 @@ SELECT string_to_array('ABCDEFGHI' COLLATE case_sensitive, NULL, 'b'); {A,B,C,D,E,F,G,H,I} (1 row) +-- +-- A unique index under one collation does not prove uniqueness under +-- another, so the planner must not use such a proof for any optimization. +-- +-- Ensure that we do not use inner-unique join execution +EXPLAIN (VERBOSE, COSTS OFF) +SELECT * FROM test1cs t1, test3cs t2 +WHERE t1.x = t2.x COLLATE case_insensitive +ORDER BY 1, 2; + QUERY PLAN +---------------------------------------------------------------------- + Sort + Output: t1.x, t2.x + Sort Key: t1.x COLLATE case_sensitive, t2.x COLLATE case_sensitive + -> Hash Join + Output: t1.x, t2.x + Hash Cond: ((t2.x)::text = (t1.x)::text) + -> Seq Scan on collate_tests.test3cs t2 + Output: t2.x + -> Hash + Output: t1.x + -> Seq Scan on collate_tests.test1cs t1 + Output: t1.x +(12 rows) + +SELECT * FROM test1cs t1, test3cs t2 +WHERE t1.x = t2.x COLLATE case_insensitive +ORDER BY 1, 2; + x | x +-----+----- + abc | abc + abc | ABC + ABC | abc + ABC | ABC + def | def + ghi | ghi +(6 rows) + +-- Ensure that left-join is not removed +EXPLAIN (COSTS OFF) +SELECT t1.* FROM test3cs t1 + LEFT JOIN test3cs t2 ON t1.x = t2.x COLLATE case_insensitive +ORDER BY 1; + QUERY PLAN +------------------------------------------ + Sort + Sort Key: t1.x COLLATE case_sensitive + -> Hash Left Join + Hash Cond: (t1.x = (t2.x)::text) + -> Seq Scan on test3cs t1 + -> Hash + -> Seq Scan on test3cs t2 +(7 rows) + +SELECT t1.* FROM test3cs t1 + LEFT JOIN test3cs t2 ON t1.x = t2.x COLLATE case_insensitive +ORDER BY 1; + x +----- + abc + abc + ABC + ABC + def + ghi +(6 rows) + +-- Ensure that self-join is not removed +EXPLAIN (COSTS OFF) +SELECT * FROM test3cs t1, test3cs t2 +WHERE t1.x = t2.x COLLATE case_insensitive +ORDER BY 1, 2; + QUERY PLAN +---------------------------------------------------------------------- + Sort + Sort Key: t1.x COLLATE case_sensitive, t2.x COLLATE case_sensitive + -> Hash Join + Hash Cond: ((t1.x)::text = (t2.x)::text) + -> Seq Scan on test3cs t1 + -> Hash + -> Seq Scan on test3cs t2 +(7 rows) + +SELECT * FROM test3cs t1, test3cs t2 +WHERE t1.x = t2.x COLLATE case_insensitive +ORDER BY 1, 2; + x | x +-----+----- + abc | abc + abc | ABC + ABC | abc + ABC | ABC + def | def + ghi | ghi +(6 rows) + +-- Ensure that semijoin is not reduced to innerjoin +EXPLAIN (COSTS OFF) +SELECT * FROM test3cs t1 + WHERE EXISTS (SELECT 1 FROM test3cs t2 WHERE t1.x = t2.x COLLATE case_insensitive) +ORDER BY 1; + QUERY PLAN +-------------------------------------------------- + Sort + Sort Key: t1.x COLLATE case_sensitive + -> Hash Semi Join + Hash Cond: ((t1.x)::text = (t2.x)::text) + -> Seq Scan on test3cs t1 + -> Hash + -> Seq Scan on test3cs t2 +(7 rows) + +SELECT * FROM test3cs t1 + WHERE EXISTS (SELECT 1 FROM test3cs t2 WHERE t1.x = t2.x COLLATE case_insensitive) +ORDER BY 1; + x +----- + abc + ABC + def + ghi +(4 rows) + +-- +-- A DISTINCT / GROUP BY / set-op on a subquery does not prove uniqueness +-- under a different collation, so the planner must not use such a proof for +-- any optimization. +-- +-- Ensure that we do not use inner-unique join execution +EXPLAIN (VERBOSE, COSTS OFF) +SELECT * FROM test1cs t1, (SELECT DISTINCT x FROM test3cs) t2 +WHERE t1.x = t2.x COLLATE case_insensitive +ORDER BY 1, 2; + QUERY PLAN +--------------------------------------------------------------------------- + Sort + Output: t1.x, test3cs.x + Sort Key: t1.x COLLATE case_sensitive, test3cs.x COLLATE case_sensitive + -> Hash Join + Output: t1.x, test3cs.x + Hash Cond: ((t1.x)::text = (test3cs.x)::text) + -> Seq Scan on collate_tests.test1cs t1 + Output: t1.x + -> Hash + Output: test3cs.x + -> HashAggregate + Output: test3cs.x + Group Key: test3cs.x + -> Seq Scan on collate_tests.test3cs + Output: test3cs.x +(15 rows) + +SELECT * FROM test1cs t1, (SELECT DISTINCT x FROM test3cs) t2 +WHERE t1.x = t2.x COLLATE case_insensitive +ORDER BY 1, 2; + x | x +-----+----- + abc | abc + abc | ABC + ABC | abc + ABC | ABC + def | def + ghi | ghi +(6 rows) + +-- Same with GROUP BY +EXPLAIN (VERBOSE, COSTS OFF) +SELECT * FROM test1cs t1, (SELECT x FROM test3cs GROUP BY x) t2 +WHERE t1.x = t2.x COLLATE case_insensitive +ORDER BY 1, 2; + QUERY PLAN +--------------------------------------------------------------------------- + Sort + Output: t1.x, test3cs.x + Sort Key: t1.x COLLATE case_sensitive, test3cs.x COLLATE case_sensitive + -> Hash Join + Output: t1.x, test3cs.x + Hash Cond: ((t1.x)::text = (test3cs.x)::text) + -> Seq Scan on collate_tests.test1cs t1 + Output: t1.x + -> Hash + Output: test3cs.x + -> HashAggregate + Output: test3cs.x + Group Key: test3cs.x + -> Seq Scan on collate_tests.test3cs + Output: test3cs.x +(15 rows) + +SELECT * FROM test1cs t1, (SELECT x FROM test3cs GROUP BY x) t2 +WHERE t1.x = t2.x COLLATE case_insensitive +ORDER BY 1, 2; + x | x +-----+----- + abc | abc + abc | ABC + ABC | abc + ABC | ABC + def | def + ghi | ghi +(6 rows) + +-- Same with set-op +EXPLAIN (VERBOSE, COSTS OFF) +SELECT * FROM test1cs t1, (SELECT x FROM test3cs UNION SELECT x FROM test3cs) t2 +WHERE t1.x = t2.x COLLATE case_insensitive +ORDER BY 1, 2; + QUERY PLAN +--------------------------------------------------------------------------- + Sort + Output: t1.x, test3cs.x + Sort Key: t1.x COLLATE case_sensitive, test3cs.x COLLATE case_sensitive + -> Hash Join + Output: t1.x, test3cs.x + Hash Cond: ((test3cs.x)::text = (t1.x)::text) + -> HashAggregate + Output: test3cs.x + Group Key: test3cs.x + -> Append + -> Seq Scan on collate_tests.test3cs + Output: test3cs.x + -> Seq Scan on collate_tests.test3cs test3cs_1 + Output: test3cs_1.x + -> Hash + Output: t1.x + -> Seq Scan on collate_tests.test1cs t1 + Output: t1.x +(18 rows) + +SELECT * FROM test1cs t1, (SELECT x FROM test3cs UNION SELECT x FROM test3cs) t2 +WHERE t1.x = t2.x COLLATE case_insensitive +ORDER BY 1, 2; + x | x +-----+----- + abc | abc + abc | ABC + ABC | abc + ABC | ABC + def | def + ghi | ghi +(6 rows) + +-- Ensure that left-join is not removed +EXPLAIN (COSTS OFF) +SELECT t1.* FROM test3cs t1 + LEFT JOIN (SELECT DISTINCT x FROM test3cs) t2 ON t1.x = t2.x COLLATE case_insensitive +ORDER BY 1; + QUERY PLAN +----------------------------------------------- + Sort + Sort Key: t1.x COLLATE case_sensitive + -> Hash Left Join + Hash Cond: (t1.x = (test3cs.x)::text) + -> Seq Scan on test3cs t1 + -> Hash + -> HashAggregate + Group Key: test3cs.x + -> Seq Scan on test3cs +(9 rows) + +SELECT t1.* FROM test3cs t1 + LEFT JOIN (SELECT DISTINCT x FROM test3cs) t2 ON t1.x = t2.x COLLATE case_insensitive +ORDER BY 1; + x +----- + abc + abc + ABC + ABC + def + ghi +(6 rows) + +-- Ensure that semijoin is not reduced to innerjoin +EXPLAIN (COSTS OFF) +SELECT * FROM test3cs t1 + WHERE EXISTS (SELECT 1 FROM (SELECT DISTINCT x FROM test3cs) t2 + WHERE t1.x = t2.x COLLATE case_insensitive) +ORDER BY 1; + QUERY PLAN +------------------------------------------------------- + Sort + Sort Key: t1.x COLLATE case_sensitive + -> Hash Semi Join + Hash Cond: ((t1.x)::text = (test3cs.x)::text) + -> Seq Scan on test3cs t1 + -> Hash + -> HashAggregate + Group Key: test3cs.x + -> Seq Scan on test3cs +(9 rows) + +SELECT * FROM test3cs t1 + WHERE EXISTS (SELECT 1 FROM (SELECT DISTINCT x FROM test3cs) t2 + WHERE t1.x = t2.x COLLATE case_insensitive) +ORDER BY 1; + x +----- + abc + ABC + def + ghi +(4 rows) + CREATE TABLE test1ci (x text COLLATE case_insensitive); CREATE TABLE test2ci (x text COLLATE case_insensitive); CREATE TABLE test3ci (x text COLLATE case_insensitive); @@ -1770,6 +2074,270 @@ SELECT string_to_array('ABCDEFGHI' COLLATE case_insensitive, NULL, 'b'); {A,NULL,C,D,E,F,G,H,I} (1 row) +-- Test HAVING-to-WHERE pushdown with nondeterministic collations. +-- When a HAVING clause uses a different collation than the GROUP BY's +-- nondeterministic collation, it must not be pushed to WHERE, otherwise +-- aggregate results can change because the stricter filter eliminates rows +-- before grouping. +-- Negative: collation conflict, HAVING must not be pushed to WHERE +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING x = 'abc' COLLATE case_sensitive; + QUERY PLAN +---------------------------------------------------- + HashAggregate + Group Key: x + Filter: (x = 'abc'::text COLLATE case_sensitive) + -> Seq Scan on test3ci +(4 rows) + +SELECT x, count(*) FROM test3ci GROUP BY x HAVING x = 'abc' COLLATE case_sensitive; + x | count +-----+------- + abc | 2 +(1 row) + +-- Positive: same collation, safe to push HAVING to WHERE +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING x = 'abc' COLLATE case_insensitive; + QUERY PLAN +------------------------------------------------------------ + GroupAggregate + -> Seq Scan on test3ci + Filter: (x = 'abc'::text COLLATE case_insensitive) +(3 rows) + +SELECT x, count(*) FROM test3ci GROUP BY x HAVING x = 'abc' COLLATE case_insensitive; + x | count +-----+------- + abc | 2 +(1 row) + +-- Negative: function applied to grouped column with conflicting collation +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING upper(x) = 'ABC' COLLATE case_sensitive; + QUERY PLAN +----------------------------------------------------------- + HashAggregate + Group Key: x + Filter: (upper(x) = 'ABC'::text COLLATE case_sensitive) + -> Seq Scan on test3ci +(4 rows) + +SELECT x, count(*) FROM test3ci GROUP BY x HAVING upper(x) = 'ABC' COLLATE case_sensitive; + x | count +-----+------- + abc | 2 +(1 row) + +-- Positive: function with same collation as GROUP BY +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING upper(x) = 'ABC' COLLATE case_insensitive; + QUERY PLAN +------------------------------------------------------------------------- + GroupAggregate + Group Key: x + -> Sort + Sort Key: x COLLATE case_insensitive + -> Seq Scan on test3ci + Filter: (upper(x) = 'ABC'::text COLLATE case_insensitive) +(6 rows) + +SELECT x, count(*) FROM test3ci GROUP BY x HAVING upper(x) = 'ABC' COLLATE case_insensitive; + x | count +-----+------- + abc | 2 +(1 row) + +-- Negative: inner function has conflicting collation, even though outer +-- operator's collation matches GROUP BY due to a COLLATE override +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING upper(x COLLATE case_sensitive) COLLATE case_insensitive = 'ABC'; + QUERY PLAN +---------------------------------------------------- + HashAggregate + Group Key: x + Filter: ((upper((x)::text))::text = 'ABC'::text) + -> Seq Scan on test3ci +(4 rows) + +SELECT x, count(*) FROM test3ci GROUP BY x HAVING upper(x COLLATE case_sensitive) COLLATE case_insensitive = 'ABC'; + x | count +-----+------- + abc | 2 +(1 row) + +-- Mixed AND: conflicting clause stays in HAVING, safe clause pushed to WHERE +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING x = 'abc' COLLATE case_sensitive AND length(x) > 1; + QUERY PLAN +---------------------------------------------------- + HashAggregate + Group Key: x + Filter: (x = 'abc'::text COLLATE case_sensitive) + -> Seq Scan on test3ci + Filter: (length(x) > 1) +(5 rows) + +SELECT x, count(*) FROM test3ci GROUP BY x HAVING x = 'abc' COLLATE case_sensitive AND length(x) > 1; + x | count +-----+------- + abc | 2 +(1 row) + +-- Positive: AND of two safe clauses, both can be pushed +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING x = 'abc' COLLATE case_insensitive AND length(x) > 1; + QUERY PLAN +---------------------------------------------------------------------------------- + GroupAggregate + -> Seq Scan on test3ci + Filter: ((x = 'abc'::text COLLATE case_insensitive) AND (length(x) > 1)) +(3 rows) + +SELECT x, count(*) FROM test3ci GROUP BY x HAVING x = 'abc' COLLATE case_insensitive AND length(x) > 1; + x | count +-----+------- + abc | 2 +(1 row) + +-- Negative: OR with a conflicting clause: must stay in HAVING +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING x = 'abc' COLLATE case_sensitive OR x = 'def' COLLATE case_sensitive ORDER BY 1; + QUERY PLAN +-------------------------------------------------------------------------------------------------------- + Sort + Sort Key: x COLLATE case_insensitive + -> HashAggregate + Group Key: x + Filter: ((x = 'abc'::text COLLATE case_sensitive) OR (x = 'def'::text COLLATE case_sensitive)) + -> Seq Scan on test3ci +(6 rows) + +SELECT x, count(*) FROM test3ci GROUP BY x HAVING x = 'abc' COLLATE case_sensitive OR x = 'def' COLLATE case_sensitive ORDER BY 1; + x | count +-----+------- + abc | 2 + def | 1 +(2 rows) + +-- Negative: collation conflict inside a RowCompareExpr +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING ROW(x, 1) < ROW('ABC' COLLATE case_sensitive, 1) ORDER BY 1; + QUERY PLAN +-------------------------------------------------------------------------- + Sort + Sort Key: x COLLATE case_insensitive + -> HashAggregate + Group Key: x + Filter: (ROW(x, 1) < ROW('ABC'::text COLLATE case_sensitive, 1)) + -> Seq Scan on test3ci +(6 rows) + +SELECT x, count(*) FROM test3ci GROUP BY x HAVING ROW(x, 1) < ROW('ABC' COLLATE case_sensitive, 1) ORDER BY 1; + x | count +-----+------- + abc | 2 +(1 row) + +-- Negative: simple-CASE form with conflicting WHEN comparison collation +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING (CASE x WHEN 'abc' COLLATE case_sensitive THEN true ELSE false END); + QUERY PLAN +----------------------------------------------------------------------------------- + HashAggregate + Group Key: x + Filter: CASE x WHEN 'abc'::text COLLATE case_sensitive THEN true ELSE false END + -> Seq Scan on test3ci +(4 rows) + +SELECT x, count(*) FROM test3ci GROUP BY x HAVING (CASE x WHEN 'abc' COLLATE case_sensitive THEN true ELSE false END); + x | count +-----+------- + abc | 2 +(1 row) + +-- Positive: simple-CASE form with matching collation, safe to push +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING (CASE x WHEN 'abc' COLLATE case_insensitive THEN true ELSE false END); + QUERY PLAN +------------------------------------------------------------------------------------------- + HashAggregate + Group Key: x + -> Seq Scan on test3ci + Filter: CASE x WHEN 'abc'::text COLLATE case_insensitive THEN true ELSE false END +(4 rows) + +SELECT x, count(*) FROM test3ci GROUP BY x HAVING (CASE x WHEN 'abc' COLLATE case_insensitive THEN true ELSE false END); + x | count +-----+------- + abc | 2 +(1 row) + +-- Negative: nested CASE with collation conflict +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING (CASE WHEN (CASE x WHEN 'abc' COLLATE case_sensitive THEN 1 ELSE 0 END) = 1 THEN true ELSE false END); + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------- + HashAggregate + Group Key: x + Filter: CASE WHEN (CASE x WHEN 'abc'::text COLLATE case_sensitive THEN 1 ELSE 0 END = 1) THEN true ELSE false END + -> Seq Scan on test3ci +(4 rows) + +SELECT x, count(*) FROM test3ci GROUP BY x HAVING (CASE WHEN (CASE x WHEN 'abc' COLLATE case_sensitive THEN 1 ELSE 0 END) = 1 THEN true ELSE false END); + x | count +-----+------- + abc | 2 +(1 row) + +-- Positive: conflicting collation but no grouping expression reference +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING current_setting('server_version') = 'abc' COLLATE case_sensitive; + QUERY PLAN +--------------------------------------------------------------------------------------------------------- + HashAggregate + Group Key: x + -> Result + One-Time Filter: (current_setting('server_version'::text) = 'abc'::text COLLATE case_sensitive) + -> Seq Scan on test3ci +(5 rows) + +-- Positive: deterministic collation in GROUP BY: always safe to push, even if +-- HAVING uses a nondeterministic collation +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3cs GROUP BY x HAVING x = 'abc' COLLATE case_sensitive; + QUERY PLAN +---------------------------------------------------------- + GroupAggregate + -> Seq Scan on test3cs + Filter: (x = 'abc'::text COLLATE case_sensitive) +(3 rows) + +SELECT x, count(*) FROM test3cs GROUP BY x HAVING x = 'abc' COLLATE case_sensitive; + x | count +-----+------- + abc | 1 +(1 row) + +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3cs GROUP BY x HAVING x = 'abc' COLLATE case_insensitive ORDER BY 1; + QUERY PLAN +------------------------------------------------------------------ + GroupAggregate + Group Key: x + -> Sort + Sort Key: x COLLATE case_sensitive + -> Seq Scan on test3cs + Filter: (x = 'abc'::text COLLATE case_insensitive) +(6 rows) + +SELECT x, count(*) FROM test3cs GROUP BY x HAVING x = 'abc' COLLATE case_insensitive ORDER BY 1; + x | count +-----+------- + abc | 1 + ABC | 1 +(2 rows) + -- bpchar CREATE TABLE test1bpci (x char(3) COLLATE case_insensitive); CREATE TABLE test2bpci (x char(3) COLLATE case_insensitive); @@ -2677,6 +3245,38 @@ DROP TABLE pagg_tab6; RESET enable_partitionwise_aggregate; RESET max_parallel_workers_per_gather; RESET enable_incremental_sort; +-- +-- A unique index can prove functional dependency for GROUP BY column +-- removal only if its per-column collation agrees on equality with +-- the GROUP BY column's collation. An index built under a different +-- (deterministic) collation would otherwise let remove_useless_groupby_columns +-- drop other columns whose values still differ within a nondeterministic +-- group. +-- +CREATE TABLE groupby_collation_t (a text COLLATE case_insensitive NOT NULL, b text); +INSERT INTO groupby_collation_t VALUES ('foo', 'X'), ('FOO', 'Y'); +CREATE UNIQUE INDEX ON groupby_collation_t (a COLLATE "C"); +-- Column b must NOT be dropped: under case_insensitive on a, 'foo' and +-- 'FOO' would merge, but they have distinct b values. +EXPLAIN (COSTS OFF) +SELECT a, b FROM groupby_collation_t GROUP BY a, b ORDER BY a, b; + QUERY PLAN +------------------------------------------------- + Group + Group Key: a, b + -> Sort + Sort Key: a COLLATE case_insensitive, b + -> Seq Scan on groupby_collation_t +(5 rows) + +SELECT a, b FROM groupby_collation_t GROUP BY a, b ORDER BY a, b; + a | b +-----+--- + foo | X + FOO | Y +(2 rows) + +DROP TABLE groupby_collation_t; -- virtual generated columns CREATE TABLE t5 ( a int, diff --git a/src/test/regress/expected/compression_pglz.out b/src/test/regress/expected/compression_pglz.out new file mode 100644 index 00000000000..0ef49d42506 --- /dev/null +++ b/src/test/regress/expected/compression_pglz.out @@ -0,0 +1,65 @@ +-- +-- Tests for PGLZ compression +-- +-- directory paths and dlsuffix are passed to us in environment variables +\getenv libdir PG_LIBDIR +\getenv dlsuffix PG_DLSUFFIX +\set regresslib :libdir '/regress' :dlsuffix +CREATE FUNCTION test_pglz_compress(bytea) + RETURNS bytea + AS :'regresslib' LANGUAGE C STRICT; +CREATE FUNCTION test_pglz_decompress(bytea, int4, bool) + RETURNS bytea + AS :'regresslib' LANGUAGE C STRICT; +-- Round-trip with pglz: compress then decompress. +SELECT test_pglz_decompress(test_pglz_compress( + decode(repeat('abcd', 100), 'escape')), 400, false) = + decode(repeat('abcd', 100), 'escape') AS roundtrip_ok; + roundtrip_ok +-------------- + t +(1 row) + +SELECT test_pglz_decompress(test_pglz_compress( + decode(repeat('abcd', 100), 'escape')), 400, true) = + decode(repeat('abcd', 100), 'escape') AS roundtrip_ok; + roundtrip_ok +-------------- + t +(1 row) + +-- Decompression with rawsize too large, fails to fill the destination +-- buffer. +SELECT test_pglz_decompress(test_pglz_compress( + decode(repeat('abcd', 100), 'escape')), 500, true); +ERROR: pglz_decompress failed +-- Decompression with rawsize too small, fails with source not fully +-- consumed. +SELECT test_pglz_decompress(test_pglz_compress( + decode(repeat('abcd', 100), 'escape')), 100, true); +ERROR: pglz_decompress failed +-- Corrupted compressed data. Set control bit with read of a match tag, +-- no data follows. +SELECT length(test_pglz_decompress('\x01'::bytea, 1024, false)) AS ctrl_only_len; + ctrl_only_len +--------------- + 0 +(1 row) + +SELECT test_pglz_decompress('\x01'::bytea, 1024, true); +ERROR: pglz_decompress failed +-- Corrupted compressed data. Set control bit with read of a match tag, +-- 1 byte follows. +SELECT test_pglz_decompress('\x01ff'::bytea, 1024, false); +ERROR: pglz_decompress failed +SELECT test_pglz_decompress('\x01ff'::bytea, 1024, true); +ERROR: pglz_decompress failed +-- Corrupted compressed data. Set control bit with match tag where length +-- nibble is 3 bytes (extended length), no data follows. +SELECT test_pglz_decompress('\x010f01'::bytea, 1024, false); +ERROR: pglz_decompress failed +SELECT test_pglz_decompress('\x010f01'::bytea, 1024, true); +ERROR: pglz_decompress failed +-- Clean up +DROP FUNCTION test_pglz_compress; +DROP FUNCTION test_pglz_decompress; diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out index 98e68e972be..8bc45a237f8 100644 --- a/src/test/regress/expected/create_index.out +++ b/src/test/regress/expected/create_index.out @@ -32,6 +32,20 @@ COMMENT ON INDEX six_wrong IS 'bad index'; ERROR: relation "six_wrong" does not exist COMMENT ON INDEX six IS 'good index'; COMMENT ON INDEX six IS NULL; +SELECT obj_description('six'::regclass, 'pg_class') IS NULL AS six_comment_is_null; + six_comment_is_null +--------------------- + t +(1 row) + +COMMENT ON INDEX six IS 'add the comment back'; +COMMENT ON INDEX six IS ''; -- empty string removes the comment, same as NULL +SELECT obj_description('six'::regclass, 'pg_class') IS NULL AS six_comment_is_null; + six_comment_is_null +--------------------- + t +(1 row) + -- -- BTREE partial indices -- diff --git a/src/test/regress/expected/create_role.out b/src/test/regress/expected/create_role.out index 46d4f9efe99..5d0f21820ed 100644 --- a/src/test/regress/expected/create_role.out +++ b/src/test/regress/expected/create_role.out @@ -102,6 +102,33 @@ CREATE ROLE regress_rolecreator CREATEROLE; CREATE ROLE regress_hasprivs CREATEROLE LOGIN INHERIT CONNECTION LIMIT 5; -- ok, we should be able to modify a role we created COMMENT ON ROLE regress_hasprivs IS 'some comment'; +SELECT shobj_description('regress_hasprivs'::regrole, 'pg_authid') IS NOT NULL AS has_comment; + has_comment +------------- + t +(1 row) + +COMMENT ON ROLE regress_hasprivs IS NULL; +SELECT shobj_description('regress_hasprivs'::regrole, 'pg_authid') IS NULL AS no_comment; + no_comment +------------ + t +(1 row) + +COMMENT ON ROLE regress_hasprivs IS 'add the comment back'; +SELECT shobj_description('regress_hasprivs'::regrole, 'pg_authid') IS NOT NULL AS has_comment; + has_comment +------------- + t +(1 row) + +COMMENT ON ROLE regress_hasprivs IS ''; -- empty string removes the comment, same as NULL +SELECT shobj_description('regress_hasprivs'::regrole, 'pg_authid') IS NULL AS no_comment; + no_comment +------------ + t +(1 row) + ALTER ROLE regress_hasprivs RENAME TO regress_tenant; ALTER ROLE regress_tenant NOINHERIT NOLOGIN CONNECTION LIMIT 7; -- fail, we should be unable to modify a role we did not create diff --git a/src/test/regress/expected/create_table_like.out b/src/test/regress/expected/create_table_like.out index d3c35c14847..feeb961fadd 100644 --- a/src/test/regress/expected/create_table_like.out +++ b/src/test/regress/expected/create_table_like.out @@ -694,6 +694,37 @@ SELECT attname, attcompression FROM pg_attribute e | (5 rows) +-- LIKE ... INCLUDING STATISTICS with dropped columns in the parent, +-- so stxkeys attnums are not contiguous. +CREATE TABLE ctl_stats3_parent (a int, b int, c int); +ALTER TABLE ctl_stats3_parent DROP COLUMN b; +CREATE STATISTICS ctl_stats3_stat ON a, c FROM ctl_stats3_parent; +CREATE TABLE ctl_stats3_child (LIKE ctl_stats3_parent INCLUDING STATISTICS); +CREATE TABLE ctl_stats4_parent (a int, b int, c int, d int); +ALTER TABLE ctl_stats4_parent DROP COLUMN b; +CREATE STATISTICS ctl_stats4_stat ON a, c FROM ctl_stats4_parent; +CREATE TABLE ctl_stats4_child (LIKE ctl_stats4_parent INCLUDING STATISTICS); +SELECT s.stxrelid::regclass AS relation, + array_agg(a.attname ORDER BY u.ord) AS stats_columns +FROM pg_statistic_ext s +CROSS JOIN LATERAL + unnest(s.stxkeys::int2[]) WITH ORDINALITY AS u(attnum, ord) +JOIN pg_attribute a + ON a.attrelid = s.stxrelid AND a.attnum = u.attnum +WHERE s.stxrelid IN ('ctl_stats3_child'::regclass, + 'ctl_stats4_child'::regclass) +GROUP BY s.stxrelid +ORDER BY s.stxrelid::regclass::text; + relation | stats_columns +------------------+--------------- + ctl_stats3_child | {a,c} + ctl_stats4_child | {a,c} +(2 rows) + +DROP TABLE ctl_stats3_parent; +DROP TABLE ctl_stats3_child; +DROP TABLE ctl_stats4_parent; +DROP TABLE ctl_stats4_child; DROP TABLE ctl_table; DROP FOREIGN TABLE ctl_foreign_table1; DROP FOREIGN TABLE ctl_foreign_table2; diff --git a/src/test/regress/expected/expressions.out b/src/test/regress/expected/expressions.out index 21c54fc1989..f9bb55e22e0 100644 --- a/src/test/regress/expected/expressions.out +++ b/src/test/regress/expected/expressions.out @@ -386,42 +386,177 @@ default for type myint using hash as operator 1 = (myint, myint), function 1 myinthash(myint); create table inttest (a myint); -insert into inttest values(1::myint),(null); --- try an array with enough elements to cause hashing -select * from inttest where a in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint,9::myint, null); - a ---- - 1 - -(2 rows) +insert into inttest values (null), (0::myint), (1::myint); +-- Test EEOP_HASHED_SCALARARRAYOP against EEOP_SCALARARRAYOP. Ensure the +-- result of non-hashed vs hashed is the same. +select + a, + a in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as not_hashed, + a in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint,9::myint) as hashed +from inttest; + a | not_hashed | hashed +---+------------+-------- + | | + 0 | f | f + 1 | t | t +(3 rows) -select * from inttest where a not in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint,9::myint, null); - a ---- -(0 rows) - -select * from inttest where a not in (0::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint,9::myint, null); - a ---- -(0 rows) - --- ensure the result matched with the non-hashed version. We simply remove --- some array elements so that we don't reach the hashing threshold. -select * from inttest where a in (1::myint,2::myint,3::myint,4::myint,5::myint, null); - a ---- - 1 - -(2 rows) +select + a, + a in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint) as not_hashed, + a in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as hashed + from inttest; + a | not_hashed | hashed +---+------------+-------- + | t | t + 0 | | + 1 | t | t +(3 rows) -select * from inttest where a not in (1::myint,2::myint,3::myint,4::myint,5::myint, null); - a ---- -(0 rows) +select + a, + a not in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as not_hashed, + a not in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint,9::myint) as hashed +from inttest; + a | not_hashed | hashed +---+------------+-------- + | | + 0 | t | t + 1 | f | f +(3 rows) -select * from inttest where a not in (0::myint,2::myint,3::myint,4::myint,5::myint, null); - a ---- -(0 rows) +select + a, + a not in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint) as not_hashed, + a not in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as hashed +from inttest; + a | not_hashed | hashed +---+------------+-------- + | f | f + 0 | | + 1 | f | f +(3 rows) + +-- Now make the equal function return false when given two NULLs +create or replace function myinteq(myint, myint) returns bool as $$ +begin + if $1 is null and $2 is null then + return false; + else + return $1::int = $2::int; + end if; +end; +$$ language plpgsql immutable; +-- And try the same again to ensure EEOP_HASHED_SCALARARRAYOP does the same +-- thing as EEOP_SCALARARRAYOP. +select + a, + a in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as not_hashed, + a in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint,9::myint) as hashed +from inttest; + a | not_hashed | hashed +---+------------+-------- + | | + 0 | f | f + 1 | t | t +(3 rows) + +select + a, + a in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint) as not_hashed, + a in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as hashed + from inttest; + a | not_hashed | hashed +---+------------+-------- + | | + 0 | | + 1 | t | t +(3 rows) + +select + a, + a not in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as not_hashed, + a not in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint,9::myint) as hashed +from inttest; + a | not_hashed | hashed +---+------------+-------- + | | + 0 | t | t + 1 | f | f +(3 rows) + +select + a, + a not in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint) as not_hashed, + a not in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as hashed +from inttest; + a | not_hashed | hashed +---+------------+-------- + | | + 0 | | + 1 | f | f +(3 rows) + +-- Try again with an equality function that treats NULLs as equal to 0. +create or replace function myinteq(myint, myint) returns bool as $$ +begin + if $1 is null and $2 is null then + return false; + else + return coalesce($1::int,0) = coalesce($2::int, 0); + end if; +end; +$$ language plpgsql immutable; +select + a, + a in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as not_hashed, + a in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint,9::myint) as hashed, + a in (0::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint) as not_hashed_zero, + a in (0::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as hashed_zero +from inttest; + a | not_hashed | hashed | not_hashed_zero | hashed_zero +---+------------+--------+-----------------+------------- + | f | f | t | t + 0 | f | f | t | t + 1 | t | t | t | t +(3 rows) + +select + a, + a in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint) as not_hashed, + a in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as hashed + from inttest; + a | not_hashed | hashed +---+------------+-------- + | f | f + 0 | t | t + 1 | t | t +(3 rows) + +select + a, + a not in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as not_hashed, + a not in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint,9::myint) as hashed, + a not in (0::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint) as not_hashed_zero, + a not in (0::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as hashed_zero +from inttest; + a | not_hashed | hashed | not_hashed_zero | hashed_zero +---+------------+--------+-----------------+------------- + | t | t | f | f + 0 | t | t | f | f + 1 | f | f | f | f +(3 rows) + +select + a, + a not in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint) as not_hashed, + a not in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as hashed +from inttest; + a | not_hashed | hashed +---+------------+-------- + | t | t + 0 | f | f + 1 | f | f +(3 rows) rollback; diff --git a/src/test/regress/expected/foreign_data.out b/src/test/regress/expected/foreign_data.out index cce49e509ab..35d75180dff 100644 --- a/src/test/regress/expected/foreign_data.out +++ b/src/test/regress/expected/foreign_data.out @@ -106,6 +106,13 @@ ERROR: conflicting or redundant options LINE 1: ...GN DATA WRAPPER test_fdw HANDLER test_fdw_handler HANDLER in... ^ CREATE FOREIGN DATA WRAPPER test_fdw HANDLER test_fdw_handler; +-- should preserve dependency on test_fdw_handler +ALTER FOREIGN DATA WRAPPER test_fdw VALIDATOR postgresql_fdw_validator; +WARNING: changing the foreign-data wrapper validator can cause the options for dependent objects to become invalid +DROP FUNCTION test_fdw_handler(); -- ERROR +ERROR: cannot drop function test_fdw_handler() because other objects depend on it +DETAIL: foreign-data wrapper test_fdw depends on function test_fdw_handler() +HINT: Use DROP ... CASCADE to drop the dependent objects too. DROP FOREIGN DATA WRAPPER test_fdw; -- ALTER FOREIGN DATA WRAPPER ALTER FOREIGN DATA WRAPPER foo OPTIONS (nonexistent 'fdw'); -- ERROR @@ -828,10 +835,13 @@ COMMENT ON COLUMN ft1.c1 IS NULL; ALTER FOREIGN TABLE ft1 ADD COLUMN c4 integer; ALTER FOREIGN TABLE ft1 ADD COLUMN c5 integer DEFAULT 0; ALTER FOREIGN TABLE ft1 ADD COLUMN c6 integer; +ALTER FOREIGN TABLE ft1 ADD COLUMN IF NOT EXISTS c6 integer; +NOTICE: column "c6" of relation "ft1" already exists, skipping ALTER FOREIGN TABLE ft1 ADD COLUMN c7 integer NOT NULL; ALTER FOREIGN TABLE ft1 ADD COLUMN c8 integer; ALTER FOREIGN TABLE ft1 ADD COLUMN c9 integer; ALTER FOREIGN TABLE ft1 ADD COLUMN c10 integer OPTIONS (p1 'v1'); +ALTER FOREIGN TABLE ft1 ADD c11 integer; ALTER FOREIGN TABLE ft1 ALTER COLUMN c4 SET DEFAULT 0; ALTER FOREIGN TABLE ft1 ALTER COLUMN c5 DROP DEFAULT; ALTER FOREIGN TABLE ft1 ALTER COLUMN c6 SET NOT NULL; @@ -863,6 +873,7 @@ ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 SET STORAGE PLAIN; c8 | text | | | | (p2 'V2') | plain | | c9 | integer | | | | | plain | | c10 | integer | | | | (p1 'v1') | plain | | + c11 | integer | | | | | plain | | Check constraints: "ft1_c2_check" CHECK (c2 <> ''::text) "ft1_c3_check" CHECK (c3 >= '01-01-1994'::date AND c3 <= '01-31-1994'::date) @@ -897,6 +908,7 @@ ERROR: column "no_column" of relation "ft1" does not exist ALTER FOREIGN TABLE ft1 DROP COLUMN IF EXISTS no_column; NOTICE: column "no_column" of relation "ft1" does not exist, skipping ALTER FOREIGN TABLE ft1 DROP COLUMN c9; +ALTER FOREIGN TABLE ft1 DROP c11; ALTER FOREIGN TABLE ft1 ADD COLUMN c11 serial; ALTER FOREIGN TABLE ft1 SET SCHEMA foreign_schema; ALTER FOREIGN TABLE ft1 SET TABLESPACE ts; -- ERROR @@ -931,6 +943,8 @@ ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 ADD COLUMN c4 integer; NOTICE: relation "doesnt_exist_ft1" does not exist, skipping ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 ADD COLUMN c6 integer; NOTICE: relation "doesnt_exist_ft1" does not exist, skipping +ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 ADD COLUMN IF NOT EXISTS c6 integer; +NOTICE: relation "doesnt_exist_ft1" does not exist, skipping ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 ADD COLUMN c7 integer NOT NULL; NOTICE: relation "doesnt_exist_ft1" does not exist, skipping ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 ADD COLUMN c8 integer; @@ -939,6 +953,8 @@ ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 ADD COLUMN c9 integer; NOTICE: relation "doesnt_exist_ft1" does not exist, skipping ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 ADD COLUMN c10 integer OPTIONS (p1 'v1'); NOTICE: relation "doesnt_exist_ft1" does not exist, skipping +ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 ADD c11 integer; +NOTICE: relation "doesnt_exist_ft1" does not exist, skipping ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 ALTER COLUMN c6 SET NOT NULL; NOTICE: relation "doesnt_exist_ft1" does not exist, skipping ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 ALTER COLUMN c7 DROP NOT NULL; @@ -960,10 +976,14 @@ ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 OWNER TO regress_test_role; NOTICE: relation "doesnt_exist_ft1" does not exist, skipping ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 OPTIONS (DROP delimiter, SET quote '~', ADD escape '@'); NOTICE: relation "doesnt_exist_ft1" does not exist, skipping +ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 DROP COLUMN no_column; +NOTICE: relation "doesnt_exist_ft1" does not exist, skipping ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 DROP COLUMN IF EXISTS no_column; NOTICE: relation "doesnt_exist_ft1" does not exist, skipping ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 DROP COLUMN c9; NOTICE: relation "doesnt_exist_ft1" does not exist, skipping +ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 DROP c11; +NOTICE: relation "doesnt_exist_ft1" does not exist, skipping ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 SET SCHEMA foreign_schema; NOTICE: relation "doesnt_exist_ft1" does not exist, skipping ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 RENAME c1 TO foreign_column_1; diff --git a/src/test/regress/expected/foreign_key.out b/src/test/regress/expected/foreign_key.out index 7f9e0ebb82d..be07bf26a33 100644 --- a/src/test/regress/expected/foreign_key.out +++ b/src/test/regress/expected/foreign_key.out @@ -1157,6 +1157,59 @@ INSERT INTO fktable VALUES (500, 1000); ERROR: insert or update on table "fktable" violates foreign key constraint "fktable_fk_fkey" DETAIL: Key (fk)=(1000) is not present in table "pktable". COMMIT; +-- Check that the existing FK trigger is both deferrable and initially deferred +SELECT conname, tgrelid::regclass as tgrel, + regexp_replace(tgname, '[0-9]+', 'N') as tgname, tgtype, + tgdeferrable, tginitdeferred +FROM pg_trigger t JOIN pg_constraint c ON (t.tgconstraint = c.oid) +WHERE conrelid = 'fktable'::regclass AND conname = 'fktable_fk_fkey' +ORDER BY tgrelid, tgtype; + conname | tgrel | tgname | tgtype | tgdeferrable | tginitdeferred +-----------------+---------+--------------------------+--------+--------------+---------------- + fktable_fk_fkey | pktable | RI_ConstraintTrigger_a_N | 9 | t | t + fktable_fk_fkey | pktable | RI_ConstraintTrigger_a_N | 17 | t | t + fktable_fk_fkey | fktable | RI_ConstraintTrigger_c_N | 5 | t | t + fktable_fk_fkey | fktable | RI_ConstraintTrigger_c_N | 17 | t | t +(4 rows) + +-- Changing the constraint to NOT ENFORCED drops the associated FK triggers +ALTER TABLE FKTABLE ALTER CONSTRAINT fktable_fk_fkey NOT ENFORCED; +SELECT conname, tgrelid::regclass as tgrel, + regexp_replace(tgname, '[0-9]+', 'N') as tgname, tgtype, + tgdeferrable, tginitdeferred +FROM pg_trigger t JOIN pg_constraint c ON (t.tgconstraint = c.oid) +WHERE conrelid = 'fktable'::regclass AND conname = 'fktable_fk_fkey' +ORDER BY tgrelid, tgtype; + conname | tgrel | tgname | tgtype | tgdeferrable | tginitdeferred +---------+-------+--------+--------+--------------+---------------- +(0 rows) + +-- Changing it back to ENFORCED will recreate the necessary FK triggers +-- that are deferrable and initially deferred +ALTER TABLE FKTABLE ALTER CONSTRAINT fktable_fk_fkey ENFORCED; +SELECT conname, tgrelid::regclass as tgrel, + regexp_replace(tgname, '[0-9]+', 'N') as tgname, tgtype, + tgdeferrable, tginitdeferred +FROM pg_trigger t JOIN pg_constraint c ON (t.tgconstraint = c.oid) +WHERE conrelid = 'fktable'::regclass AND conname = 'fktable_fk_fkey' +ORDER BY tgrelid, tgtype; + conname | tgrel | tgname | tgtype | tgdeferrable | tginitdeferred +-----------------+---------+--------------------------+--------+--------------+---------------- + fktable_fk_fkey | pktable | RI_ConstraintTrigger_a_N | 9 | t | t + fktable_fk_fkey | pktable | RI_ConstraintTrigger_a_N | 17 | t | t + fktable_fk_fkey | fktable | RI_ConstraintTrigger_c_N | 5 | t | t + fktable_fk_fkey | fktable | RI_ConstraintTrigger_c_N | 17 | t | t +(4 rows) + +-- Verify that a deferrable, initially deferred foreign key still works +-- as expected after being set to NOT ENFORCED and then re-enabled +BEGIN; +-- doesn't match PK, but no error yet +INSERT INTO fktable VALUES (2, 20); +-- should catch error from INSERT at commit +COMMIT; +ERROR: insert or update on table "fktable" violates foreign key constraint "fktable_fk_fkey" +DETAIL: Key (fk)=(20) is not present in table "pktable". DROP TABLE fktable, pktable; -- tricky behavior: according to SQL99, if a deferred constraint is set -- to 'immediate' mode, it should be checked for validity *immediately*, diff --git a/src/test/regress/expected/generated_stored.out b/src/test/regress/expected/generated_stored.out index 8b7a71d8f0c..86a04548a02 100644 --- a/src/test/regress/expected/generated_stored.out +++ b/src/test/regress/expected/generated_stored.out @@ -1527,6 +1527,40 @@ CREATE TABLE gtest28b (LIKE gtest28a INCLUDING GENERATED); c | integer | | | x | integer | | | generated always as (b * 2) stored +-- rule actions referring to generated columns: +-- NEW.b in a rule action should reflect the generated column's new value +CREATE TABLE gtest_rule (a int, b int GENERATED ALWAYS AS (a * 2) STORED); +CREATE TABLE gtest_rule_log (op text, old_b int, new_b int); +CREATE RULE gtest_rule_upd AS ON UPDATE TO gtest_rule + DO ALSO INSERT INTO gtest_rule_log VALUES ('UPD', OLD.b, NEW.b); +CREATE RULE gtest_rule_ins AS ON INSERT TO gtest_rule + DO ALSO INSERT INTO gtest_rule_log VALUES ('INS', NULL, NEW.b); +INSERT INTO gtest_rule (a) VALUES (1); +UPDATE gtest_rule SET a = 10; +UPDATE gtest_rule SET a = (SELECT max(b) FROM gtest_rule); +SELECT * FROM gtest_rule_log; + op | old_b | new_b +-----+-------+------- + INS | | 2 + UPD | 2 | 20 + UPD | 20 | 40 +(3 rows) + +DROP RULE gtest_rule_upd ON gtest_rule; +DROP RULE gtest_rule_ins ON gtest_rule; +DROP TABLE gtest_rule_log; +-- rule quals referring to generated columns: +-- NEW.b in the rule qual should reflect the generated column's new value +CREATE RULE gtest_rule_qual AS ON UPDATE TO gtest_rule WHERE NEW.b > 100 + DO INSTEAD NOTHING; +UPDATE gtest_rule SET a = 100; +SELECT * FROM gtest_rule; + a | b +----+---- + 20 | 40 +(1 row) + +DROP TABLE gtest_rule; -- sanity check of system catalog SELECT attrelid, attname, attgenerated FROM pg_attribute WHERE attgenerated NOT IN ('', 's', 'v'); attrelid | attname | attgenerated diff --git a/src/test/regress/expected/generated_virtual.out b/src/test/regress/expected/generated_virtual.out index b7da03ce7ea..171d68ba2e2 100644 --- a/src/test/regress/expected/generated_virtual.out +++ b/src/test/regress/expected/generated_virtual.out @@ -1494,6 +1494,40 @@ CREATE TABLE gtest28b (LIKE gtest28a INCLUDING GENERATED); c | integer | | | x | integer | | | generated always as (b * 2) +-- rule actions referring to generated columns: +-- NEW.b in a rule action should reflect the generated column's new value +CREATE TABLE gtest_rule (a int, b int GENERATED ALWAYS AS (a * 2) VIRTUAL); +CREATE TABLE gtest_rule_log (op text, old_b int, new_b int); +CREATE RULE gtest_rule_upd AS ON UPDATE TO gtest_rule + DO ALSO INSERT INTO gtest_rule_log VALUES ('UPD', OLD.b, NEW.b); +CREATE RULE gtest_rule_ins AS ON INSERT TO gtest_rule + DO ALSO INSERT INTO gtest_rule_log VALUES ('INS', NULL, NEW.b); +INSERT INTO gtest_rule (a) VALUES (1); +UPDATE gtest_rule SET a = 10; +UPDATE gtest_rule SET a = (SELECT max(b) FROM gtest_rule); +SELECT * FROM gtest_rule_log; + op | old_b | new_b +-----+-------+------- + INS | | 2 + UPD | 2 | 20 + UPD | 20 | 40 +(3 rows) + +DROP RULE gtest_rule_upd ON gtest_rule; +DROP RULE gtest_rule_ins ON gtest_rule; +DROP TABLE gtest_rule_log; +-- rule quals referring to generated columns: +-- NEW.b in the rule qual should reflect the generated column's new value +CREATE RULE gtest_rule_qual AS ON UPDATE TO gtest_rule WHERE NEW.b > 100 + DO INSTEAD NOTHING; +UPDATE gtest_rule SET a = 100; +SELECT * FROM gtest_rule; + a | b +----+---- + 20 | 40 +(1 row) + +DROP TABLE gtest_rule; -- sanity check of system catalog SELECT attrelid, attname, attgenerated FROM pg_attribute WHERE attgenerated NOT IN ('', 's', 'v'); attrelid | attname | attgenerated @@ -1658,3 +1692,81 @@ select * from gtest33 where b is null; reset constraint_exclusion; drop table gtest33; +-- Ensure that EXCLUDED. in INSERT ... ON CONFLICT +-- DO UPDATE is expanded to the generation expression, both for plain and +-- partitioned target relations. +create table gtest34 (id int primary key, a int, + c int generated always as (a * 10) virtual); +insert into gtest34 values (1, 5); +insert into gtest34 values (1, 7) + on conflict (id) do update set a = excluded.c returning *; + id | a | c +----+----+----- + 1 | 70 | 700 +(1 row) + +insert into gtest34 values (1, 2) + on conflict (id) do update set a = gtest34.c + excluded.c returning *; + id | a | c +----+-----+------ + 1 | 720 | 7200 +(1 row) + +insert into gtest34 values (1, 3) + on conflict (id) do update set a = 999 where excluded.c > 20 returning *; + id | a | c +----+-----+------ + 1 | 999 | 9990 +(1 row) + +drop table gtest34; +create table gtest34p (id int primary key, a int, + c int generated always as (a * 10) virtual) + partition by range (id); +create table gtest34p_1 partition of gtest34p for values from (1) to (100); +insert into gtest34p values (1, 5); +insert into gtest34p values (1, 7) + on conflict (id) do update set a = excluded.c returning *; + id | a | c +----+----+----- + 1 | 70 | 700 +(1 row) + +insert into gtest34p values (1, 2) + on conflict (id) do update set a = gtest34p.c + excluded.c returning *; + id | a | c +----+-----+------ + 1 | 720 | 7200 +(1 row) + +drop table gtest34p; +-- Ensure that virtual generated columns work with WHERE CURRENT OF +create table gtest_cursor (id int primary key, a int, b int generated always as (a * 2) virtual); +insert into gtest_cursor values (1, 10), (2, 20), (3, 30); +begin; +declare curs cursor for select * from gtest_cursor order by id for update; +fetch 1 from curs; + id | a | b +----+----+---- + 1 | 10 | 20 +(1 row) + +update gtest_cursor set a = 99 where current of curs; +select * from gtest_cursor order by id; + id | a | b +----+----+----- + 1 | 99 | 198 + 2 | 20 | 40 + 3 | 30 | 60 +(3 rows) + +delete from gtest_cursor where current of curs; +select * from gtest_cursor order by id; + id | a | b +----+----+---- + 2 | 20 | 40 + 3 | 30 | 60 +(2 rows) + +commit; +drop table gtest_cursor; diff --git a/src/test/regress/expected/indexing.out b/src/test/regress/expected/indexing.out index bcf1db11d73..b8d7d3047be 100644 --- a/src/test/regress/expected/indexing.out +++ b/src/test/regress/expected/indexing.out @@ -540,6 +540,111 @@ select relname, indisvalid from pg_class join pg_index on indexrelid = oid idxpart_a_idx | t (3 rows) +drop table idxpart; +-- Verify that re-attaching an already-attached partition index can +-- validate the parent index if it was still invalid, including +-- indirect ancestors in subpartitions. +create table idxpart (a int, b int) partition by range (a); +create table idxpart1 partition of idxpart for values from (0) to (1000) partition by range (a); +create table idxpart11 partition of idxpart1 for values from (0) to (500); +-- Partitioned table with no partitions +create table idxpart2 partition of idxpart for values from (1000) to (2000) partition by range (a); +-- create parent indexes +create index on only idxpart ((a/b)); +create index on only idxpart1 ((a/b)); +create index on only idxpart2 ((a/b)); +-- fail, leaves behind an invalid index on the leaf partition +insert into idxpart11 values (1, 0); +create index concurrently on idxpart11 ((a/b)); +ERROR: division by zero +select relname, indisvalid from pg_class join pg_index on indexrelid = oid + where relname like 'idxpart%' order by relname; + relname | indisvalid +--------------------+------------ + idxpart11_expr_idx | f + idxpart1_expr_idx | f + idxpart2_expr_idx | t + idxpart_expr_idx | f +(4 rows) + +-- attach the indexes; parents stay invalid +alter index idxpart1_expr_idx attach partition idxpart11_expr_idx; +alter index idxpart_expr_idx attach partition idxpart1_expr_idx; +alter index idxpart_expr_idx attach partition idxpart2_expr_idx; +select relname, indisvalid from pg_class join pg_index on indexrelid = oid + where relname like 'idxpart%' order by relname; + relname | indisvalid +--------------------+------------ + idxpart11_expr_idx | f + idxpart1_expr_idx | f + idxpart2_expr_idx | t + idxpart_expr_idx | f +(4 rows) + +-- fix the index on the leaf partition +delete from idxpart11 where b = 0; +reindex index concurrently idxpart11_expr_idx; +-- reattach the leaf partition index; parents should now be valid +alter index idxpart1_expr_idx attach partition idxpart11_expr_idx; +select relname, indisvalid from pg_class join pg_index on indexrelid = oid + where relname like 'idxpart%' order by relname; + relname | indisvalid +--------------------+------------ + idxpart11_expr_idx | t + idxpart1_expr_idx | t + idxpart2_expr_idx | t + idxpart_expr_idx | t +(4 rows) + +drop table idxpart; +-- Verify that re-attaching does not validate the parent when another +-- child index is still invalid. +create table idxpart (a int, b int) partition by range (a); +create table idxpart1 partition of idxpart for values from (0) to (500); +create table idxpart2 partition of idxpart for values from (500) to (1000); +create index on only idxpart ((a/b)); +-- create invalid indexes on both children +insert into idxpart1 values (1, 0); +insert into idxpart2 values (501, 0); +create index concurrently on idxpart1 ((a/b)); +ERROR: division by zero +create index concurrently on idxpart2 ((a/b)); +ERROR: division by zero +select relname, indisvalid from pg_class join pg_index on indexrelid = oid + where relname like 'idxpart%' order by relname; + relname | indisvalid +-------------------+------------ + idxpart1_expr_idx | f + idxpart2_expr_idx | f + idxpart_expr_idx | f +(3 rows) + +-- attach both; parent stays invalid +alter index idxpart_expr_idx attach partition idxpart1_expr_idx; +alter index idxpart_expr_idx attach partition idxpart2_expr_idx; +select relname, indisvalid from pg_class join pg_index on indexrelid = oid + where relname like 'idxpart%' order by relname; + relname | indisvalid +-------------------+------------ + idxpart1_expr_idx | f + idxpart2_expr_idx | f + idxpart_expr_idx | f +(3 rows) + +-- fix only idxpart1's index, leave idxpart2's still invalid +delete from idxpart1 where b = 0; +reindex index concurrently idxpart1_expr_idx; +-- re-attach the fixed child; parent should stay invalid +alter index idxpart_expr_idx attach partition idxpart1_expr_idx; +select relname, indisvalid from pg_class join pg_index on indexrelid = oid + where relname like 'idxpart%' order by relname; + relname | indisvalid +-------------------+------------ + idxpart1_expr_idx | t + idxpart2_expr_idx | f + idxpart_expr_idx | f +(3 rows) + drop table idxpart; -- verify dependency handling during ALTER TABLE DETACH PARTITION create table idxpart (a int) partition by range (a); diff --git a/src/test/regress/expected/join.out b/src/test/regress/expected/join.out index 75db7ebea75..02935b0af6d 100644 --- a/src/test/regress/expected/join.out +++ b/src/test/regress/expected/join.out @@ -6125,6 +6125,45 @@ from int8_tbl t1 -> Seq Scan on onek t4 (13 rows) +-- bug #19460: we need to clean up RestrictInfos more than we had been doing +explain (costs off) +select * from + (select 1::int as id) as lhs +full join + (select dummy_source.id + from (select null::int as id) as dummy_source + left join (select a.id from a where a.id = 42) as sub + on sub.id = dummy_source.id + ) as rhs +on lhs.id = rhs.id; + QUERY PLAN +-------------------------------------- + Hash Full Join + Hash Cond: ((1) = (NULL::integer)) + -> Result + -> Hash + -> Result +(5 rows) + +explain (costs off) +select * from + (select 1::int as id) as lhs +full join + (select dummy_source.id + from (select 2::int as id) as dummy_source + left join (select a.id from a) as sub + on sub.id = dummy_source.id + ) as rhs +on lhs.id = rhs.id; + QUERY PLAN +-------------------------- + Hash Full Join + Hash Cond: ((1) = (2)) + -> Result + -> Hash + -> Result +(5 rows) + -- More tests of correct placement of pseudoconstant quals -- simple constant-false condition explain (costs off) @@ -7896,6 +7935,22 @@ WHERE q0.a = 1; -> Seq Scan on sj n1 (7 rows) +-- Do not forget to replace relid in bare Var join clause (bug #19435) +ALTER TABLE sl ADD COLUMN bool_col boolean; +EXPLAIN (COSTS OFF) +SELECT 1 AS c1 FROM sl sl1 LEFT JOIN (sl AS sl2 NATURAL JOIN sl AS sl3) + ON sl2.bool_col LEFT JOIN sl AS sl4 ON sl2.bool_col; + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------- + Nested Loop Left Join + -> Seq Scan on sl sl1 + -> Nested Loop Left Join + Join Filter: sl3.bool_col + -> Seq Scan on sl sl3 + Filter: (bool_col AND (a IS NOT NULL) AND (b IS NOT NULL) AND (c IS NOT NULL) AND (bool_col IS NOT NULL)) + -> Seq Scan on sl sl4 +(7 rows) + -- Check optimization disabling if it will violate special join conditions. -- Two identical joined relations satisfies self join removal conditions but -- stay in different special join infos. diff --git a/src/test/regress/expected/multirangetypes.out b/src/test/regress/expected/multirangetypes.out index c6363ebeb24..76ab1430c4c 100644 --- a/src/test/regress/expected/multirangetypes.out +++ b/src/test/regress/expected/multirangetypes.out @@ -3145,6 +3145,22 @@ drop type textrange1; reset role; drop role regress_multirange_owner; -- +-- CREATE TYPE checks for CREATE on multirange schema +-- +create role regress_mr; +create schema mr_sch; +set role regress_mr; +create type mytype as range (subtype=int4, multirange_type_name=mr_sch.mr_type); +ERROR: permission denied for schema mr_sch +reset role; +grant create on schema mr_sch to regress_mr; +set role regress_mr; +create type mytype as range (subtype=int4, multirange_type_name=mr_sch.mr_type); +reset role; +drop type mytype; +drop schema mr_sch; +drop role regress_mr; +-- -- Test polymorphic type system -- create function anyarray_anymultirange_func(a anyarray, r anymultirange) @@ -3297,6 +3313,9 @@ select *, row_to_json(upper(t)) as u from {["(5,6)","(7,8)")} | {"a":7,"b":8} (2 rows) +-- this must be rejected to avoid self-inclusion issues: +alter type two_ints add attribute c two_ints_multirange; +ERROR: composite type two_ints cannot be made a member of itself drop type two_ints cascade; NOTICE: drop cascades to type two_ints_range -- diff --git a/src/test/regress/expected/partition_prune.out b/src/test/regress/expected/partition_prune.out index d1966cd7d82..7aa3e5cbaf9 100644 --- a/src/test/regress/expected/partition_prune.out +++ b/src/test/regress/expected/partition_prune.out @@ -4801,3 +4801,135 @@ select min(a) over (partition by a order by a) from part_abc where a >= stable_o drop view part_abc_view; drop table part_abc; +-- +-- Check that operands wrapped in PlaceHolderVars are matched to partition +-- keys, allowing partition pruning to occur. PlaceHolderVars can be +-- introduced when a subquery's output is used with grouping sets. +-- +create table phv_part (a int, b text) partition by list (a); +create table phv_part_1 partition of phv_part for values in (1); +create table phv_part_2 partition of phv_part for values in (2); +create table phv_part_null partition of phv_part for values in (null); +insert into phv_part values (1, 'one'), (2, 'two'), (null, 'null'); +-- OpExpr: PHV-wrapped operand matched via equal() +explain (costs off) +select * from (select a, b from phv_part) t + where a = 1 + group by grouping sets (a, b); + QUERY PLAN +--------------------------------------- + MixedAggregate + Hash Key: phv_part.b + Group Key: phv_part.a + -> Seq Scan on phv_part_1 phv_part + Filter: (a = 1) +(5 rows) + +select * from (select a, b from phv_part) t + where a = 1 + group by grouping sets (a, b); + a | b +---+----- + 1 | + | one +(2 rows) + +-- OpExpr with RelabelType: PHV wrapped around a casted column +explain (costs off) +select * from (select a::oid as x, b from phv_part) t + where x::int = 1 + group by grouping sets (x, b); + QUERY PLAN +------------------------------------------- + HashAggregate + Hash Key: (phv_part.a)::oid + Hash Key: phv_part.b + -> Seq Scan on phv_part_1 phv_part + Filter: (((a)::oid)::integer = 1) +(5 rows) + +select * from (select a::oid as x, b from phv_part) t + where x::int = 1 + group by grouping sets (x, b); + x | b +---+----- + 1 | + | one +(2 rows) + +-- ScalarArrayOpExpr: IN clause with PHV-wrapped operand +explain (costs off) +select * from (select a, b from phv_part) t + where a in (1, null) + group by grouping sets (a, b); + QUERY PLAN +--------------------------------------------------- + HashAggregate + Hash Key: phv_part.a + Hash Key: phv_part.b + -> Seq Scan on phv_part_1 phv_part + Filter: (a = ANY ('{1,NULL}'::integer[])) +(5 rows) + +select * from (select a, b from phv_part) t + where a in (1, null) + group by grouping sets (a, b); + a | b +---+----- + 1 | + | one +(2 rows) + +-- NullTest: IS NULL with PHV-wrapped operand +explain (costs off) +select * from (select a, b from phv_part) t + where a is null + group by grouping sets (a, b); + QUERY PLAN +------------------------------------------ + HashAggregate + Hash Key: phv_part.a + Hash Key: phv_part.b + -> Seq Scan on phv_part_null phv_part + Filter: (a IS NULL) +(5 rows) + +select * from (select a, b from phv_part) t + where a is null + group by grouping sets (a, b); + a | b +---+------ + | + | null +(2 rows) + +drop table phv_part; +-- BooleanTest: IS TRUE with PHV-wrapped boolean partition key +create table phv_boolpart (a bool, b text) partition by list (a); +create table phv_boolpart_t partition of phv_boolpart for values in (true); +create table phv_boolpart_f partition of phv_boolpart for values in (false); +create table phv_boolpart_null partition of phv_boolpart default; +insert into phv_boolpart values (true, 'yes'), (false, 'no'), (null, 'unknown'); +explain (costs off) +select * from (select a, b from phv_boolpart) t + where a is true + group by grouping sets (a, b); + QUERY PLAN +----------------------------------------------- + HashAggregate + Hash Key: phv_boolpart.a + Hash Key: phv_boolpart.b + -> Seq Scan on phv_boolpart_t phv_boolpart + Filter: (a IS TRUE) +(5 rows) + +select * from (select a, b from phv_boolpart) t + where a is true + group by grouping sets (a, b); + a | b +---+----- + t | + | yes +(2 rows) + +drop table phv_boolpart; diff --git a/src/test/regress/expected/portals.out b/src/test/regress/expected/portals.out index 06726ed4ab7..c1fbfa105ef 100644 --- a/src/test/regress/expected/portals.out +++ b/src/test/regress/expected/portals.out @@ -1336,6 +1336,17 @@ FETCH FROM c1; DELETE FROM ucview WHERE CURRENT OF c1; -- fail, views not supported ERROR: WHERE CURRENT OF on a view is not implemented ROLLBACK; +BEGIN; +DECLARE c1 CURSOR FOR SELECT * FROM ucview; +FETCH FROM c1; + f1 | f2 +----+------- + 13 | three +(1 row) + +UPDATE ucview SET f1 = f1 + 10 WHERE CURRENT OF c1; -- fail, views not supported +ERROR: WHERE CURRENT OF on a view is not implemented +ROLLBACK; -- Check WHERE CURRENT OF with an index-only scan BEGIN; EXPLAIN (costs off) diff --git a/src/test/regress/expected/prepared_xacts.out b/src/test/regress/expected/prepared_xacts.out index 515a2ada9d1..ac4ebf6ca36 100644 --- a/src/test/regress/expected/prepared_xacts.out +++ b/src/test/regress/expected/prepared_xacts.out @@ -1,3 +1,7 @@ +SELECT current_setting('max_prepared_transactions')::integer < 2 AS skip_test \gset +\if :skip_test +\quit +\endif -- -- PREPARED TRANSACTIONS (two-phase commit) -- @@ -263,8 +267,37 @@ SELECT gid FROM pg_prepared_xacts WHERE gid ~ '^regress_' ORDER BY gid; ----- (0 rows) +-- Test row-level locks held by prepared transactions +CREATE TABLE pxtest_rowlock (id int PRIMARY KEY, data text); +INSERT INTO pxtest_rowlock VALUES (1, 'test data'); +BEGIN; +SELECT * FROM pxtest_rowlock WHERE id = 1 FOR SHARE; + id | data +----+----------- + 1 | test data +(1 row) + +PREPARE TRANSACTION 'regress_p1'; +-- Should fail because the row is locked +SELECT * FROM pxtest_rowlock WHERE id = 1 FOR UPDATE NOWAIT; +ERROR: could not obtain lock on row in relation "pxtest_rowlock" +-- Test prepared transactions that participate in multixacts. For +-- that, lock the same row again, creating a multixid. +BEGIN; +SELECT * FROM pxtest_rowlock WHERE id = 1 FOR SHARE; + id | data +----+----------- + 1 | test data +(1 row) + +PREPARE TRANSACTION 'regress_p2'; +-- Should fail because the row is locked +SELECT * FROM pxtest_rowlock WHERE id = 1 FOR UPDATE NOWAIT; +ERROR: could not obtain lock on row in relation "pxtest_rowlock" +ROLLBACK PREPARED 'regress_p1'; +ROLLBACK PREPARED 'regress_p2'; -- Clean up DROP TABLE pxtest2; -DROP TABLE pxtest3; -- will still be there if prepared xacts are disabled -ERROR: table "pxtest3" does not exist +-- pxtest3 was already dropped DROP TABLE pxtest4; +DROP TABLE pxtest_rowlock; diff --git a/src/test/regress/expected/prepared_xacts_1.out b/src/test/regress/expected/prepared_xacts_1.out index 6ad3d11898a..a21314768c3 100644 --- a/src/test/regress/expected/prepared_xacts_1.out +++ b/src/test/regress/expected/prepared_xacts_1.out @@ -1,266 +1,3 @@ --- --- PREPARED TRANSACTIONS (two-phase commit) --- --- We can't readily test persistence of prepared xacts within the --- regression script framework, unfortunately. Note that a crash --- isn't really needed ... stopping and starting the postmaster would --- be enough, but we can't even do that here. --- create a simple table that we'll use in the tests -CREATE TABLE pxtest1 (foobar VARCHAR(10)); -INSERT INTO pxtest1 VALUES ('aaa'); --- Test PREPARE TRANSACTION -BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; -UPDATE pxtest1 SET foobar = 'bbb' WHERE foobar = 'aaa'; -SELECT * FROM pxtest1; - foobar --------- - bbb -(1 row) - -PREPARE TRANSACTION 'regress_foo1'; -ERROR: prepared transactions are disabled -HINT: Set "max_prepared_transactions" to a nonzero value. -SELECT * FROM pxtest1; - foobar --------- - aaa -(1 row) - --- Test pg_prepared_xacts system view -SELECT gid FROM pg_prepared_xacts WHERE gid ~ '^regress_' ORDER BY gid; - gid ------ -(0 rows) - --- Test ROLLBACK PREPARED -ROLLBACK PREPARED 'regress_foo1'; -ERROR: prepared transaction with identifier "regress_foo1" does not exist -SELECT * FROM pxtest1; - foobar --------- - aaa -(1 row) - -SELECT gid FROM pg_prepared_xacts WHERE gid ~ '^regress_' ORDER BY gid; - gid ------ -(0 rows) - --- Test COMMIT PREPARED -BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; -INSERT INTO pxtest1 VALUES ('ddd'); -SELECT * FROM pxtest1; - foobar --------- - aaa - ddd -(2 rows) - -PREPARE TRANSACTION 'regress_foo2'; -ERROR: prepared transactions are disabled -HINT: Set "max_prepared_transactions" to a nonzero value. -SELECT * FROM pxtest1; - foobar --------- - aaa -(1 row) - -COMMIT PREPARED 'regress_foo2'; -ERROR: prepared transaction with identifier "regress_foo2" does not exist -SELECT * FROM pxtest1; - foobar --------- - aaa -(1 row) - --- Test duplicate gids -BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; -UPDATE pxtest1 SET foobar = 'eee' WHERE foobar = 'ddd'; -SELECT * FROM pxtest1; - foobar --------- - aaa -(1 row) - -PREPARE TRANSACTION 'regress_foo3'; -ERROR: prepared transactions are disabled -HINT: Set "max_prepared_transactions" to a nonzero value. -SELECT gid FROM pg_prepared_xacts WHERE gid ~ '^regress_' ORDER BY gid; - gid ------ -(0 rows) - -BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; -INSERT INTO pxtest1 VALUES ('fff'); --- This should fail, because the gid foo3 is already in use -PREPARE TRANSACTION 'regress_foo3'; -ERROR: prepared transactions are disabled -HINT: Set "max_prepared_transactions" to a nonzero value. -SELECT * FROM pxtest1; - foobar --------- - aaa -(1 row) - -ROLLBACK PREPARED 'regress_foo3'; -ERROR: prepared transaction with identifier "regress_foo3" does not exist -SELECT * FROM pxtest1; - foobar --------- - aaa -(1 row) - --- Test serialization failure (SSI) -BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; -UPDATE pxtest1 SET foobar = 'eee' WHERE foobar = 'ddd'; -SELECT * FROM pxtest1; - foobar --------- - aaa -(1 row) - -PREPARE TRANSACTION 'regress_foo4'; -ERROR: prepared transactions are disabled -HINT: Set "max_prepared_transactions" to a nonzero value. -SELECT gid FROM pg_prepared_xacts WHERE gid ~ '^regress_' ORDER BY gid; - gid ------ -(0 rows) - -BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; -SELECT * FROM pxtest1; - foobar --------- - aaa -(1 row) - --- This should fail, because the two transactions have a write-skew anomaly -INSERT INTO pxtest1 VALUES ('fff'); -PREPARE TRANSACTION 'regress_foo5'; -ERROR: prepared transactions are disabled -HINT: Set "max_prepared_transactions" to a nonzero value. -SELECT gid FROM pg_prepared_xacts WHERE gid ~ '^regress_' ORDER BY gid; - gid ------ -(0 rows) - -ROLLBACK PREPARED 'regress_foo4'; -ERROR: prepared transaction with identifier "regress_foo4" does not exist -SELECT gid FROM pg_prepared_xacts WHERE gid ~ '^regress_' ORDER BY gid; - gid ------ -(0 rows) - --- Clean up -DROP TABLE pxtest1; --- Test detection of session-level and xact-level locks on same object -BEGIN; -SELECT pg_advisory_lock(1); - pg_advisory_lock ------------------- - -(1 row) - -SELECT pg_advisory_xact_lock_shared(1); - pg_advisory_xact_lock_shared ------------------------------- - -(1 row) - -PREPARE TRANSACTION 'regress_foo6'; -- fails -ERROR: prepared transactions are disabled -HINT: Set "max_prepared_transactions" to a nonzero value. --- Test subtransactions -BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; - CREATE TABLE pxtest2 (a int); - INSERT INTO pxtest2 VALUES (1); - SAVEPOINT a; - INSERT INTO pxtest2 VALUES (2); - ROLLBACK TO a; - SAVEPOINT b; - INSERT INTO pxtest2 VALUES (3); -PREPARE TRANSACTION 'regress_sub1'; -ERROR: prepared transactions are disabled -HINT: Set "max_prepared_transactions" to a nonzero value. -CREATE TABLE pxtest3(fff int); --- Test shared invalidation -BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; - DROP TABLE pxtest3; - CREATE TABLE pxtest4 (a int); - INSERT INTO pxtest4 VALUES (1); - INSERT INTO pxtest4 VALUES (2); - DECLARE foo CURSOR FOR SELECT * FROM pxtest4; - -- Fetch 1 tuple, keeping the cursor open - FETCH 1 FROM foo; - a ---- - 1 -(1 row) - -PREPARE TRANSACTION 'regress_sub2'; -ERROR: prepared transactions are disabled -HINT: Set "max_prepared_transactions" to a nonzero value. --- No such cursor -FETCH 1 FROM foo; -ERROR: cursor "foo" does not exist --- Table doesn't exist, the creation hasn't been committed yet -SELECT * FROM pxtest2; -ERROR: relation "pxtest2" does not exist -LINE 1: SELECT * FROM pxtest2; - ^ --- There should be two prepared transactions -SELECT gid FROM pg_prepared_xacts WHERE gid ~ '^regress_' ORDER BY gid; - gid ------ -(0 rows) - --- pxtest3 should be locked because of the pending DROP -begin; -lock table pxtest3 in access share mode nowait; -rollback; --- Disconnect, we will continue testing in a different backend -\c - --- There should still be two prepared transactions -SELECT gid FROM pg_prepared_xacts WHERE gid ~ '^regress_' ORDER BY gid; - gid ------ -(0 rows) - --- pxtest3 should still be locked because of the pending DROP -begin; -lock table pxtest3 in access share mode nowait; -rollback; --- Commit table creation -COMMIT PREPARED 'regress_sub1'; -ERROR: prepared transaction with identifier "regress_sub1" does not exist -\d pxtest2 -SELECT * FROM pxtest2; -ERROR: relation "pxtest2" does not exist -LINE 1: SELECT * FROM pxtest2; - ^ --- There should be one prepared transaction -SELECT gid FROM pg_prepared_xacts WHERE gid ~ '^regress_' ORDER BY gid; - gid ------ -(0 rows) - --- Commit table drop -COMMIT PREPARED 'regress_sub2'; -ERROR: prepared transaction with identifier "regress_sub2" does not exist -SELECT * FROM pxtest3; - fff ------ -(0 rows) - --- There should be no prepared transactions -SELECT gid FROM pg_prepared_xacts WHERE gid ~ '^regress_' ORDER BY gid; - gid ------ -(0 rows) - --- Clean up -DROP TABLE pxtest2; -ERROR: table "pxtest2" does not exist -DROP TABLE pxtest3; -- will still be there if prepared xacts are disabled -DROP TABLE pxtest4; -ERROR: table "pxtest4" does not exist +SELECT current_setting('max_prepared_transactions')::integer < 2 AS skip_test \gset +\if :skip_test +\quit diff --git a/src/test/regress/expected/stats.out b/src/test/regress/expected/stats.out index 776f1ad0e53..37df27351d8 100644 --- a/src/test/regress/expected/stats.out +++ b/src/test/regress/expected/stats.out @@ -877,6 +877,8 @@ SELECT (n_tup_ins + n_tup_upd) > 0 AS has_data FROM pg_stat_all_tables t (1 row) +-- stats_reset may not be set for datid=0 and shared objects in +-- pg_stat_database, so reset once. SELECT pg_stat_reset_single_table_counters('pg_shdescription'::regclass); pg_stat_reset_single_table_counters ------------------------------------- @@ -890,6 +892,22 @@ SELECT (n_tup_ins + n_tup_upd) > 0 AS has_data FROM pg_stat_all_tables f (1 row) +SELECT stats_reset AS shared_db_reset_before + FROM pg_stat_database WHERE datid = 0 \gset +-- Second reset for comparison. +SELECT pg_stat_reset_single_table_counters('pg_shdescription'::regclass); + pg_stat_reset_single_table_counters +------------------------------------- + +(1 row) + +SELECT stats_reset > :'shared_db_reset_before'::timestamptz AS has_updated + FROM pg_stat_database WHERE datid = 0; + has_updated +------------- + t +(1 row) + -- set back comment \if :{?description_before} COMMENT ON DATABASE :"datname" IS :'description_before'; diff --git a/src/test/regress/expected/stats_import.out b/src/test/regress/expected/stats_import.out index 98ce7dc2841..2efd422df16 100644 --- a/src/test/regress/expected/stats_import.out +++ b/src/test/regress/expected/stats_import.out @@ -625,6 +625,87 @@ AND attname = 'id'; stats_import | test | id | f | 0.23 | 5 | 0.6 | | | | | | | | | | (1 row) +-- warn: mcv / mcf array length mismatch (more vals), mcv-pair fails, rest get set +SELECT pg_catalog.pg_restore_attribute_stats( + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'id', + 'inherited', false::boolean, + 'null_frac', 0.24::real, + 'most_common_vals', '{2,1,3}'::text, + 'most_common_freqs', '{0.3,0.25}'::real[] + ); +WARNING: could not parse "most_common_vals": incorrect number of elements (same as "most_common_freqs" required) + pg_restore_attribute_stats +---------------------------- + f +(1 row) + +SELECT * +FROM pg_stats +WHERE schemaname = 'stats_import' +AND tablename = 'test' +AND inherited = false +AND attname = 'id'; + schemaname | tablename | attname | inherited | null_frac | avg_width | n_distinct | most_common_vals | most_common_freqs | histogram_bounds | correlation | most_common_elems | most_common_elem_freqs | elem_count_histogram | range_length_histogram | range_empty_frac | range_bounds_histogram +--------------+-----------+---------+-----------+-----------+-----------+------------+------------------+-------------------+------------------+-------------+-------------------+------------------------+----------------------+------------------------+------------------+------------------------ + stats_import | test | id | f | 0.24 | 5 | 0.6 | | | | | | | | | | +(1 row) + +-- warn: mcv / mcf array length mismatch (more freqs), mcv-pair fails, rest get set +SELECT pg_catalog.pg_restore_attribute_stats( + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'id', + 'inherited', false::boolean, + 'null_frac', 0.25::real, + 'most_common_vals', '{2,1}'::text, + 'most_common_freqs', '{0.3,0.25,0.05}'::real[] + ); +WARNING: could not parse "most_common_vals": incorrect number of elements (same as "most_common_freqs" required) + pg_restore_attribute_stats +---------------------------- + f +(1 row) + +SELECT * +FROM pg_stats +WHERE schemaname = 'stats_import' +AND tablename = 'test' +AND inherited = false +AND attname = 'id'; + schemaname | tablename | attname | inherited | null_frac | avg_width | n_distinct | most_common_vals | most_common_freqs | histogram_bounds | correlation | most_common_elems | most_common_elem_freqs | elem_count_histogram | range_length_histogram | range_empty_frac | range_bounds_histogram +--------------+-----------+---------+-----------+-----------+-----------+------------+------------------+-------------------+------------------+-------------+-------------------+------------------------+----------------------+------------------------+------------------+------------------------ + stats_import | test | id | f | 0.25 | 5 | 0.6 | | | | | | | | | | +(1 row) + +-- warn: most_common_vals is multi-dimensional, mcv-pair fails, rest get set +SELECT pg_catalog.pg_restore_attribute_stats( + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'id', + 'inherited', false::boolean, + 'null_frac', 0.26::real, + 'most_common_vals', '{{2,1},{3,4}}'::text, + 'most_common_freqs', '{0.3,0.25,0.05,0.04}'::real[] + ); +WARNING: "most_common_vals" must be a one-dimensional array + pg_restore_attribute_stats +---------------------------- + f +(1 row) + +SELECT * +FROM pg_stats +WHERE schemaname = 'stats_import' +AND tablename = 'test' +AND inherited = false +AND attname = 'id'; + schemaname | tablename | attname | inherited | null_frac | avg_width | n_distinct | most_common_vals | most_common_freqs | histogram_bounds | correlation | most_common_elems | most_common_elem_freqs | elem_count_histogram | range_length_histogram | range_empty_frac | range_bounds_histogram +--------------+-----------+---------+-----------+-----------+-----------+------------+------------------+-------------------+------------------+-------------+-------------------+------------------------+----------------------+------------------------+------------------+------------------------ + stats_import | test | id | f | 0.26 | 5 | 0.6 | | | | | | | | | | +(1 row) + -- ok: mcv+mcf SELECT pg_catalog.pg_restore_attribute_stats( 'schemaname', 'stats_import', @@ -647,7 +728,7 @@ AND inherited = false AND attname = 'id'; schemaname | tablename | attname | inherited | null_frac | avg_width | n_distinct | most_common_vals | most_common_freqs | histogram_bounds | correlation | most_common_elems | most_common_elem_freqs | elem_count_histogram | range_length_histogram | range_empty_frac | range_bounds_histogram --------------+-----------+---------+-----------+-----------+-----------+------------+------------------+-------------------+------------------+-------------+-------------------+------------------------+----------------------+------------------------+------------------+------------------------ - stats_import | test | id | f | 0.23 | 5 | 0.6 | {2,1,3} | {0.3,0.25,0.05} | | | | | | | | + stats_import | test | id | f | 0.26 | 5 | 0.6 | {2,1,3} | {0.3,0.25,0.05} | | | | | | | | (1 row) -- warn: NULL in histogram array, rest get set diff --git a/src/test/regress/expected/tsearch.out b/src/test/regress/expected/tsearch.out index 9287c440709..5b7c2123f37 100644 --- a/src/test/regress/expected/tsearch.out +++ b/src/test/regress/expected/tsearch.out @@ -2145,6 +2145,16 @@ NOTICE: text-search query doesn't contain lexemes: "" foo bar (1 row) +-- Test for large values of StartSel, StopSel and FragmentDelimiter +SELECT ts_headline('english', 'foo barbar', to_tsquery('english', 'foo'), + 'StartSel=' || repeat('x', 32768)); +ERROR: value for "StartSel" is too long +SELECT ts_headline('english', 'foo barbar', to_tsquery('english', 'foo'), + 'StopSel=' || repeat('x', 32768)); +ERROR: value for "StopSel" is too long +SELECT ts_headline('english', 'foo barbar', to_tsquery('english', 'foo'), + 'FragmentDelimiter=' || repeat('x', 32768)); +ERROR: value for "FragmentDelimiter" is too long --Rewrite sub system CREATE TABLE test_tsquery (txtkeyword TEXT, txtsample TEXT); \set ECHO none diff --git a/src/test/regress/expected/union.out b/src/test/regress/expected/union.out index 96962817ed4..984db95608c 100644 --- a/src/test/regress/expected/union.out +++ b/src/test/regress/expected/union.out @@ -1500,3 +1500,20 @@ on true limit 1; -> Result (6 rows) +-- Test handling of Vars with varno 0 in estimate_array_length +explain (verbose, costs off) +select null::int[] union all select null::int[] union all select null::bigint[]; + QUERY PLAN +--------------------------------------------- + Append + -> Result + Output: (NULL::integer[]) + -> Append + -> Result + Output: NULL::integer[] + -> Result + Output: NULL::integer[] + -> Result + Output: NULL::bigint[] +(10 rows) + diff --git a/src/test/regress/expected/window.out b/src/test/regress/expected/window.out index b86b668f433..6ee01f37009 100644 --- a/src/test/regress/expected/window.out +++ b/src/test/regress/expected/window.out @@ -1361,6 +1361,97 @@ SELECT pg_get_viewdef('v_window'); FROM generate_series(now(), (now() + '@ 100 days'::interval), '@ 1 hour'::interval) i(i); (1 row) +-- test overflow frame specifications +SELECT sum(unique1) over (rows between current row and 9223372036854775807 following exclude current row), + unique1, four +FROM tenk1 WHERE unique1 < 10; + sum | unique1 | four +-----+---------+------ + 41 | 4 | 0 + 39 | 2 | 2 + 38 | 1 | 1 + 32 | 6 | 2 + 23 | 9 | 1 + 15 | 8 | 0 + 10 | 5 | 1 + 7 | 3 | 3 + 0 | 7 | 3 + | 0 | 0 +(10 rows) + +SELECT sum(unique1) over (rows between 9223372036854775807 following and 1 following), + unique1, four +FROM tenk1 WHERE unique1 < 10; + sum | unique1 | four +-----+---------+------ + | 4 | 0 + | 2 | 2 + | 1 | 1 + | 6 | 2 + | 9 | 1 + | 8 | 0 + | 5 | 1 + | 3 | 3 + | 7 | 3 + | 0 | 0 +(10 rows) + +SELECT last_value(unique1) over (ORDER BY four rows between current row and 9223372036854775807 following exclude current row), + unique1, four +FROM tenk1 WHERE unique1 < 10; + last_value | unique1 | four +------------+---------+------ + 7 | 0 | 0 + 7 | 8 | 0 + 7 | 4 | 0 + 7 | 5 | 1 + 7 | 9 | 1 + 7 | 1 | 1 + 7 | 6 | 2 + 7 | 2 | 2 + 7 | 3 | 3 + | 7 | 3 +(10 rows) + +-- These test GROUPS mode with an offset large enough to cause overflow when +-- added to currentgroup. Although the overflow doesn't produce visibly wrong +-- results (due to the incremental nature of group pointer advancement), we +-- still need to protect against it as signed integer overflow is undefined +-- behavior in C. +SELECT sum(unique1) over (ORDER BY four groups between current row and 9223372036854775807 following), + unique1, four +FROM tenk1 WHERE unique1 < 10; + sum | unique1 | four +-----+---------+------ + 45 | 0 | 0 + 45 | 8 | 0 + 45 | 4 | 0 + 33 | 5 | 1 + 33 | 9 | 1 + 33 | 1 | 1 + 18 | 6 | 2 + 18 | 2 | 2 + 10 | 3 | 3 + 10 | 7 | 3 +(10 rows) + +SELECT sum(unique1) over (ORDER BY four groups between 9223372036854775807 following and unbounded following), + unique1, four +FROM tenk1 WHERE unique1 < 10; + sum | unique1 | four +-----+---------+------ + | 0 | 0 + | 8 | 0 + | 4 | 0 + | 5 | 1 + | 9 | 1 + | 1 | 1 + | 6 | 2 + | 2 | 2 + | 3 | 3 + | 7 | 3 +(10 rows) + -- RANGE offset PRECEDING/FOLLOWING tests SELECT sum(unique1) over (order by four range between 2::int8 preceding and 1::int2 preceding), unique1, four diff --git a/src/test/regress/expected/without_overlaps.out b/src/test/regress/expected/without_overlaps.out index f3144bdc39c..28cb655981b 100644 --- a/src/test/regress/expected/without_overlaps.out +++ b/src/test/regress/expected/without_overlaps.out @@ -311,6 +311,45 @@ ALTER TABLE temporal_rng3 DROP CONSTRAINT temporal_rng3_uq; DROP TABLE temporal_rng3; DROP TYPE textrange2; -- +-- test PRIMARY KEY and UNIQUE constraints' interaction with domains +-- +-- range over domain: +CREATE DOMAIN int4_d as integer check (value <> 10); +CREATE TYPE int4_d_range as range (subtype = int4_d); +CREATE TABLE temporal_rng4 ( + id int4range, + valid_at int4_d_range, + CONSTRAINT temporal_rng4_pk PRIMARY KEY(id, valid_at WITHOUT OVERLAPS) +); +INSERT INTO temporal_rng4 VALUES ('[1,11)', '[9,10)'); -- start bound violates domain +ERROR: value for domain int4_d violates check constraint "int4_d_check" +LINE 1: INSERT INTO temporal_rng4 VALUES ('[1,11)', '[9,10)'); + ^ +INSERT INTO temporal_rng4 VALUES ('[1,2)', '[10,11)'); -- end bound violates domain +ERROR: value for domain int4_d violates check constraint "int4_d_check" +LINE 1: INSERT INTO temporal_rng4 VALUES ('[1,2)', '[10,11)'); + ^ +INSERT INTO temporal_rng4 VALUES ('[1,2)', '[1,13)'), ('[1,2)', '[2,5)'); -- overlaps +ERROR: conflicting key value violates exclusion constraint "temporal_rng4_pk" +DETAIL: Key (id, valid_at)=([1,2), [2,5)) conflicts with existing key (id, valid_at)=([1,2), [1,13)). +INSERT INTO temporal_rng4 VALUES ('[1,2)', '[1,13)'), ('[1,2)', '[20,23)'); -- okay +INSERT INTO temporal_rng4 VALUES ('[1,2)', '[30,)'); -- null bound is okay +DROP TABLE temporal_rng4; +-- domain over range: +CREATE DOMAIN int4range_d AS int4range CHECK (VALUE <> '[10,11)'); +CREATE TABLE temporal_rng4 ( + id int4range, + valid_at int4range_d, + CONSTRAINT temporal_rng4_pk UNIQUE (id, valid_at WITHOUT OVERLAPS) +); +INSERT INTO temporal_rng4 VALUES ('[1,2)', '[10,11)'); -- violates domain +ERROR: value for domain int4range_d violates check constraint "int4range_d_check" +INSERT INTO temporal_rng4 VALUES ('[1,2)', '[1,13)'), ('[1,2)', '[2,13)'); -- overlaps +ERROR: conflicting key value violates exclusion constraint "temporal_rng4_pk" +DETAIL: Key (id, valid_at)=([1,2), [2,13)) conflicts with existing key (id, valid_at)=([1,2), [1,13)). +INSERT INTO temporal_rng4 VALUES ('[1,2)', '[1,13)'), ('[1,2)', '[20,23)'); -- okay +DROP TABLE temporal_rng4; +-- -- test ALTER TABLE ADD CONSTRAINT -- CREATE TABLE temporal_rng ( diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule index b774d24dc02..e1e0c540194 100644 --- a/src/test/regress/parallel_schedule +++ b/src/test/regress/parallel_schedule @@ -123,7 +123,12 @@ test: plancache limit plpgsql copy2 temp domain rangefuncs prepare conversion tr # The stats test resets stats, so nothing else needing stats access can be in # this group. # ---------- -test: partition_join partition_prune reloptions hash_part indexing partition_aggregate partition_info tuplesort explain compression memoize stats predicate numa +test: partition_join partition_prune reloptions hash_part indexing partition_aggregate partition_info tuplesort explain memoize stats predicate numa + +# ---------- +# Another group of parallel tests (compression) +# ---------- +test: compression compression_pglz # event_trigger depends on create_am and cannot run concurrently with # any test that runs DDL diff --git a/src/test/regress/pg_regress.c b/src/test/regress/pg_regress.c index 82cb10b0b65..4e7ae0a9a78 100644 --- a/src/test/regress/pg_regress.c +++ b/src/test/regress/pg_regress.c @@ -694,7 +694,7 @@ static const char * get_expectfile(const char *testname, const char *file) { - char *file_type; + const char *file_type; _resultmap *rm; /* diff --git a/src/test/regress/regress.c b/src/test/regress/regress.c index d1bc7166bd9..49672f1dfc0 100644 --- a/src/test/regress/regress.c +++ b/src/test/regress/regress.c @@ -27,6 +27,7 @@ #include "catalog/pg_type.h" #include "commands/sequence.h" #include "commands/trigger.h" +#include "common/pg_lzcompress.h" #include "executor/executor.h" #include "executor/spi.h" #include "funcapi.h" @@ -1167,3 +1168,68 @@ test_relpath(PG_FUNCTION_ARGS) PG_RETURN_VOID(); } + +/* + * test_pglz_compress + * + * Compress the input using pglz_compress(). Only the "always" strategy is + * currently supported. + * + * Returns the compressed data, or NULL if compression fails. + */ +PG_FUNCTION_INFO_V1(test_pglz_compress); +Datum +test_pglz_compress(PG_FUNCTION_ARGS) +{ + bytea *input = PG_GETARG_BYTEA_PP(0); + char *source = VARDATA_ANY(input); + int32 slen = VARSIZE_ANY_EXHDR(input); + int32 maxout = PGLZ_MAX_OUTPUT(slen); + bytea *result; + int32 clen; + + result = (bytea *) palloc(maxout + VARHDRSZ); + clen = pglz_compress(source, slen, VARDATA(result), + PGLZ_strategy_always); + if (clen < 0) + PG_RETURN_NULL(); + + SET_VARSIZE(result, clen + VARHDRSZ); + PG_RETURN_BYTEA_P(result); +} + +/* + * test_pglz_decompress + * + * Decompress the input using pglz_decompress(). + * + * The second argument is the expected uncompressed data size. The third + * argument is here for the check_complete flag. + * + * Returns the decompressed data, or raises an error if decompression fails. + */ +PG_FUNCTION_INFO_V1(test_pglz_decompress); +Datum +test_pglz_decompress(PG_FUNCTION_ARGS) +{ + bytea *input = PG_GETARG_BYTEA_PP(0); + int32 rawsize = PG_GETARG_INT32(1); + bool check_complete = PG_GETARG_BOOL(2); + char *source = VARDATA_ANY(input); + int32 slen = VARSIZE_ANY_EXHDR(input); + bytea *result; + int32 dlen; + + if (rawsize < 0) + elog(ERROR, "rawsize must not be negative"); + + result = (bytea *) palloc(rawsize + VARHDRSZ); + + dlen = pglz_decompress(source, slen, VARDATA(result), + rawsize, check_complete); + if (dlen < 0) + elog(ERROR, "pglz_decompress failed"); + + SET_VARSIZE(result, dlen + VARHDRSZ); + PG_RETURN_BYTEA_P(result); +} diff --git a/src/test/regress/sql/aggregates.sql b/src/test/regress/sql/aggregates.sql index 79eca85c985..b751783e833 100644 --- a/src/test/regress/sql/aggregates.sql +++ b/src/test/regress/sql/aggregates.sql @@ -539,6 +539,23 @@ alter table t2 alter column z drop not null; create unique index t2_z_uidx on t2(z) nulls not distinct; explain (costs off) select y,z from t2 group by y,z; +-- A unique index proves uniqueness only under its own opfamily. When the +-- GROUP BY's eqop comes from a different opfamily with looser equality, +-- rows the index regards as distinct can collapse into one GROUP BY group, +-- so the index is not usable for removing redundant columns. +create type t_rec as (x numeric); +create temp table t_opf (a t_rec not null, b text); +create unique index on t_opf (a record_image_ops); +-- (1.0) and (1.00) are bytewise distinct but logically equal as records; +-- the index admits both, but GROUP BY a (default record_ops) would merge +-- them, so b must be retained as a grouping key. +insert into t_opf values (row(1.0)::t_rec, 'X'), (row(1.00)::t_rec, 'Y'); +explain (costs off) +select a, b from t_opf group by a, b order by b; +select a, b from t_opf group by a, b order by b; +drop table t_opf; +drop type t_rec; + drop table t1 cascade; drop table t2; drop table t3; @@ -567,6 +584,12 @@ select f2, count(*) from t1 x(x0,x1) left join (t1 left join t2 using(f2)) on (x0 = 0) group by f2; +-- check that we preserve join alias in GROUP BY expressions +create temp view v1 as +select f1::int from t1 left join t2 using (f1) group by f1; +select pg_get_viewdef('v1'::regclass); + +drop view v1; drop table t1, t2; -- diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql index f1a7d776013..e1937a85ba7 100644 --- a/src/test/regress/sql/alter_table.sql +++ b/src/test/regress/sql/alter_table.sql @@ -2331,6 +2331,14 @@ ALTER TABLE test_add_column \d test_add_column ALTER TABLE test_add_column ADD COLUMN IF NOT EXISTS c5 SERIAL CHECK (c5 > 10); +ALTER TABLE test_add_column + ADD c6 integer; -- omit COLUMN +ALTER TABLE test_add_column + ADD IF NOT EXISTS c6 integer; +ALTER TABLE test_add_column + DROP c6; -- omit COLUMN +ALTER TABLE test_add_column + DROP IF EXISTS c6; \d test_add_column* DROP TABLE test_add_column; \d test_add_column* diff --git a/src/test/regress/sql/collate.icu.utf8.sql b/src/test/regress/sql/collate.icu.utf8.sql index b6c54503d21..90ea90d64e0 100644 --- a/src/test/regress/sql/collate.icu.utf8.sql +++ b/src/test/regress/sql/collate.icu.utf8.sql @@ -608,6 +608,109 @@ CREATE UNIQUE INDEX ON test3cs (x); -- ok SELECT string_to_array('ABC,DEF,GHI' COLLATE case_sensitive, ',', 'abc'); SELECT string_to_array('ABCDEFGHI' COLLATE case_sensitive, NULL, 'b'); +-- +-- A unique index under one collation does not prove uniqueness under +-- another, so the planner must not use such a proof for any optimization. +-- + +-- Ensure that we do not use inner-unique join execution +EXPLAIN (VERBOSE, COSTS OFF) +SELECT * FROM test1cs t1, test3cs t2 +WHERE t1.x = t2.x COLLATE case_insensitive +ORDER BY 1, 2; + +SELECT * FROM test1cs t1, test3cs t2 +WHERE t1.x = t2.x COLLATE case_insensitive +ORDER BY 1, 2; + +-- Ensure that left-join is not removed +EXPLAIN (COSTS OFF) +SELECT t1.* FROM test3cs t1 + LEFT JOIN test3cs t2 ON t1.x = t2.x COLLATE case_insensitive +ORDER BY 1; + +SELECT t1.* FROM test3cs t1 + LEFT JOIN test3cs t2 ON t1.x = t2.x COLLATE case_insensitive +ORDER BY 1; + +-- Ensure that self-join is not removed +EXPLAIN (COSTS OFF) +SELECT * FROM test3cs t1, test3cs t2 +WHERE t1.x = t2.x COLLATE case_insensitive +ORDER BY 1, 2; + +SELECT * FROM test3cs t1, test3cs t2 +WHERE t1.x = t2.x COLLATE case_insensitive +ORDER BY 1, 2; + +-- Ensure that semijoin is not reduced to innerjoin +EXPLAIN (COSTS OFF) +SELECT * FROM test3cs t1 + WHERE EXISTS (SELECT 1 FROM test3cs t2 WHERE t1.x = t2.x COLLATE case_insensitive) +ORDER BY 1; + +SELECT * FROM test3cs t1 + WHERE EXISTS (SELECT 1 FROM test3cs t2 WHERE t1.x = t2.x COLLATE case_insensitive) +ORDER BY 1; + +-- +-- A DISTINCT / GROUP BY / set-op on a subquery does not prove uniqueness +-- under a different collation, so the planner must not use such a proof for +-- any optimization. +-- + +-- Ensure that we do not use inner-unique join execution +EXPLAIN (VERBOSE, COSTS OFF) +SELECT * FROM test1cs t1, (SELECT DISTINCT x FROM test3cs) t2 +WHERE t1.x = t2.x COLLATE case_insensitive +ORDER BY 1, 2; + +SELECT * FROM test1cs t1, (SELECT DISTINCT x FROM test3cs) t2 +WHERE t1.x = t2.x COLLATE case_insensitive +ORDER BY 1, 2; + +-- Same with GROUP BY +EXPLAIN (VERBOSE, COSTS OFF) +SELECT * FROM test1cs t1, (SELECT x FROM test3cs GROUP BY x) t2 +WHERE t1.x = t2.x COLLATE case_insensitive +ORDER BY 1, 2; + +SELECT * FROM test1cs t1, (SELECT x FROM test3cs GROUP BY x) t2 +WHERE t1.x = t2.x COLLATE case_insensitive +ORDER BY 1, 2; + +-- Same with set-op +EXPLAIN (VERBOSE, COSTS OFF) +SELECT * FROM test1cs t1, (SELECT x FROM test3cs UNION SELECT x FROM test3cs) t2 +WHERE t1.x = t2.x COLLATE case_insensitive +ORDER BY 1, 2; + +SELECT * FROM test1cs t1, (SELECT x FROM test3cs UNION SELECT x FROM test3cs) t2 +WHERE t1.x = t2.x COLLATE case_insensitive +ORDER BY 1, 2; + +-- Ensure that left-join is not removed +EXPLAIN (COSTS OFF) +SELECT t1.* FROM test3cs t1 + LEFT JOIN (SELECT DISTINCT x FROM test3cs) t2 ON t1.x = t2.x COLLATE case_insensitive +ORDER BY 1; + +SELECT t1.* FROM test3cs t1 + LEFT JOIN (SELECT DISTINCT x FROM test3cs) t2 ON t1.x = t2.x COLLATE case_insensitive +ORDER BY 1; + +-- Ensure that semijoin is not reduced to innerjoin +EXPLAIN (COSTS OFF) +SELECT * FROM test3cs t1 + WHERE EXISTS (SELECT 1 FROM (SELECT DISTINCT x FROM test3cs) t2 + WHERE t1.x = t2.x COLLATE case_insensitive) +ORDER BY 1; + +SELECT * FROM test3cs t1 + WHERE EXISTS (SELECT 1 FROM (SELECT DISTINCT x FROM test3cs) t2 + WHERE t1.x = t2.x COLLATE case_insensitive) +ORDER BY 1; + CREATE TABLE test1ci (x text COLLATE case_insensitive); CREATE TABLE test2ci (x text COLLATE case_insensitive); CREATE TABLE test3ci (x text COLLATE case_insensitive); @@ -638,6 +741,87 @@ CREATE UNIQUE INDEX ON test3ci (x); -- error SELECT string_to_array('ABC,DEF,GHI' COLLATE case_insensitive, ',', 'abc'); SELECT string_to_array('ABCDEFGHI' COLLATE case_insensitive, NULL, 'b'); +-- Test HAVING-to-WHERE pushdown with nondeterministic collations. +-- When a HAVING clause uses a different collation than the GROUP BY's +-- nondeterministic collation, it must not be pushed to WHERE, otherwise +-- aggregate results can change because the stricter filter eliminates rows +-- before grouping. + +-- Negative: collation conflict, HAVING must not be pushed to WHERE +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING x = 'abc' COLLATE case_sensitive; +SELECT x, count(*) FROM test3ci GROUP BY x HAVING x = 'abc' COLLATE case_sensitive; + +-- Positive: same collation, safe to push HAVING to WHERE +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING x = 'abc' COLLATE case_insensitive; +SELECT x, count(*) FROM test3ci GROUP BY x HAVING x = 'abc' COLLATE case_insensitive; + +-- Negative: function applied to grouped column with conflicting collation +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING upper(x) = 'ABC' COLLATE case_sensitive; +SELECT x, count(*) FROM test3ci GROUP BY x HAVING upper(x) = 'ABC' COLLATE case_sensitive; + +-- Positive: function with same collation as GROUP BY +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING upper(x) = 'ABC' COLLATE case_insensitive; +SELECT x, count(*) FROM test3ci GROUP BY x HAVING upper(x) = 'ABC' COLLATE case_insensitive; + +-- Negative: inner function has conflicting collation, even though outer +-- operator's collation matches GROUP BY due to a COLLATE override +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING upper(x COLLATE case_sensitive) COLLATE case_insensitive = 'ABC'; +SELECT x, count(*) FROM test3ci GROUP BY x HAVING upper(x COLLATE case_sensitive) COLLATE case_insensitive = 'ABC'; + +-- Mixed AND: conflicting clause stays in HAVING, safe clause pushed to WHERE +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING x = 'abc' COLLATE case_sensitive AND length(x) > 1; +SELECT x, count(*) FROM test3ci GROUP BY x HAVING x = 'abc' COLLATE case_sensitive AND length(x) > 1; + +-- Positive: AND of two safe clauses, both can be pushed +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING x = 'abc' COLLATE case_insensitive AND length(x) > 1; +SELECT x, count(*) FROM test3ci GROUP BY x HAVING x = 'abc' COLLATE case_insensitive AND length(x) > 1; + +-- Negative: OR with a conflicting clause: must stay in HAVING +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING x = 'abc' COLLATE case_sensitive OR x = 'def' COLLATE case_sensitive ORDER BY 1; +SELECT x, count(*) FROM test3ci GROUP BY x HAVING x = 'abc' COLLATE case_sensitive OR x = 'def' COLLATE case_sensitive ORDER BY 1; + +-- Negative: collation conflict inside a RowCompareExpr +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING ROW(x, 1) < ROW('ABC' COLLATE case_sensitive, 1) ORDER BY 1; +SELECT x, count(*) FROM test3ci GROUP BY x HAVING ROW(x, 1) < ROW('ABC' COLLATE case_sensitive, 1) ORDER BY 1; + +-- Negative: simple-CASE form with conflicting WHEN comparison collation +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING (CASE x WHEN 'abc' COLLATE case_sensitive THEN true ELSE false END); +SELECT x, count(*) FROM test3ci GROUP BY x HAVING (CASE x WHEN 'abc' COLLATE case_sensitive THEN true ELSE false END); + +-- Positive: simple-CASE form with matching collation, safe to push +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING (CASE x WHEN 'abc' COLLATE case_insensitive THEN true ELSE false END); +SELECT x, count(*) FROM test3ci GROUP BY x HAVING (CASE x WHEN 'abc' COLLATE case_insensitive THEN true ELSE false END); + +-- Negative: nested CASE with collation conflict +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING (CASE WHEN (CASE x WHEN 'abc' COLLATE case_sensitive THEN 1 ELSE 0 END) = 1 THEN true ELSE false END); +SELECT x, count(*) FROM test3ci GROUP BY x HAVING (CASE WHEN (CASE x WHEN 'abc' COLLATE case_sensitive THEN 1 ELSE 0 END) = 1 THEN true ELSE false END); + +-- Positive: conflicting collation but no grouping expression reference +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3ci GROUP BY x HAVING current_setting('server_version') = 'abc' COLLATE case_sensitive; + +-- Positive: deterministic collation in GROUP BY: always safe to push, even if +-- HAVING uses a nondeterministic collation +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3cs GROUP BY x HAVING x = 'abc' COLLATE case_sensitive; +SELECT x, count(*) FROM test3cs GROUP BY x HAVING x = 'abc' COLLATE case_sensitive; + +EXPLAIN (COSTS OFF) +SELECT x, count(*) FROM test3cs GROUP BY x HAVING x = 'abc' COLLATE case_insensitive ORDER BY 1; +SELECT x, count(*) FROM test3cs GROUP BY x HAVING x = 'abc' COLLATE case_insensitive ORDER BY 1; + -- bpchar CREATE TABLE test1bpci (x char(3) COLLATE case_insensitive); CREATE TABLE test2bpci (x char(3) COLLATE case_insensitive); @@ -986,6 +1170,26 @@ RESET enable_partitionwise_aggregate; RESET max_parallel_workers_per_gather; RESET enable_incremental_sort; +-- +-- A unique index can prove functional dependency for GROUP BY column +-- removal only if its per-column collation agrees on equality with +-- the GROUP BY column's collation. An index built under a different +-- (deterministic) collation would otherwise let remove_useless_groupby_columns +-- drop other columns whose values still differ within a nondeterministic +-- group. +-- +CREATE TABLE groupby_collation_t (a text COLLATE case_insensitive NOT NULL, b text); +INSERT INTO groupby_collation_t VALUES ('foo', 'X'), ('FOO', 'Y'); +CREATE UNIQUE INDEX ON groupby_collation_t (a COLLATE "C"); + +-- Column b must NOT be dropped: under case_insensitive on a, 'foo' and +-- 'FOO' would merge, but they have distinct b values. +EXPLAIN (COSTS OFF) +SELECT a, b FROM groupby_collation_t GROUP BY a, b ORDER BY a, b; +SELECT a, b FROM groupby_collation_t GROUP BY a, b ORDER BY a, b; + +DROP TABLE groupby_collation_t; + -- virtual generated columns CREATE TABLE t5 ( a int, diff --git a/src/test/regress/sql/compression_pglz.sql b/src/test/regress/sql/compression_pglz.sql new file mode 100644 index 00000000000..a44af02afb7 --- /dev/null +++ b/src/test/regress/sql/compression_pglz.sql @@ -0,0 +1,53 @@ +-- +-- Tests for PGLZ compression +-- + +-- directory paths and dlsuffix are passed to us in environment variables +\getenv libdir PG_LIBDIR +\getenv dlsuffix PG_DLSUFFIX + +\set regresslib :libdir '/regress' :dlsuffix + +CREATE FUNCTION test_pglz_compress(bytea) + RETURNS bytea + AS :'regresslib' LANGUAGE C STRICT; +CREATE FUNCTION test_pglz_decompress(bytea, int4, bool) + RETURNS bytea + AS :'regresslib' LANGUAGE C STRICT; + +-- Round-trip with pglz: compress then decompress. +SELECT test_pglz_decompress(test_pglz_compress( + decode(repeat('abcd', 100), 'escape')), 400, false) = + decode(repeat('abcd', 100), 'escape') AS roundtrip_ok; +SELECT test_pglz_decompress(test_pglz_compress( + decode(repeat('abcd', 100), 'escape')), 400, true) = + decode(repeat('abcd', 100), 'escape') AS roundtrip_ok; + +-- Decompression with rawsize too large, fails to fill the destination +-- buffer. +SELECT test_pglz_decompress(test_pglz_compress( + decode(repeat('abcd', 100), 'escape')), 500, true); + +-- Decompression with rawsize too small, fails with source not fully +-- consumed. +SELECT test_pglz_decompress(test_pglz_compress( + decode(repeat('abcd', 100), 'escape')), 100, true); + +-- Corrupted compressed data. Set control bit with read of a match tag, +-- no data follows. +SELECT length(test_pglz_decompress('\x01'::bytea, 1024, false)) AS ctrl_only_len; +SELECT test_pglz_decompress('\x01'::bytea, 1024, true); + +-- Corrupted compressed data. Set control bit with read of a match tag, +-- 1 byte follows. +SELECT test_pglz_decompress('\x01ff'::bytea, 1024, false); +SELECT test_pglz_decompress('\x01ff'::bytea, 1024, true); + +-- Corrupted compressed data. Set control bit with match tag where length +-- nibble is 3 bytes (extended length), no data follows. +SELECT test_pglz_decompress('\x010f01'::bytea, 1024, false); +SELECT test_pglz_decompress('\x010f01'::bytea, 1024, true); + +-- Clean up +DROP FUNCTION test_pglz_compress; +DROP FUNCTION test_pglz_decompress; diff --git a/src/test/regress/sql/create_index.sql b/src/test/regress/sql/create_index.sql index eabc9623b20..82e4062a215 100644 --- a/src/test/regress/sql/create_index.sql +++ b/src/test/regress/sql/create_index.sql @@ -45,6 +45,10 @@ CREATE INDEX six ON shighway USING btree (name text_ops); COMMENT ON INDEX six_wrong IS 'bad index'; COMMENT ON INDEX six IS 'good index'; COMMENT ON INDEX six IS NULL; +SELECT obj_description('six'::regclass, 'pg_class') IS NULL AS six_comment_is_null; +COMMENT ON INDEX six IS 'add the comment back'; +COMMENT ON INDEX six IS ''; -- empty string removes the comment, same as NULL +SELECT obj_description('six'::regclass, 'pg_class') IS NULL AS six_comment_is_null; -- -- BTREE partial indices diff --git a/src/test/regress/sql/create_role.sql b/src/test/regress/sql/create_role.sql index 4491a28a8ae..b22f9c6f50a 100644 --- a/src/test/regress/sql/create_role.sql +++ b/src/test/regress/sql/create_role.sql @@ -92,6 +92,13 @@ CREATE ROLE regress_hasprivs CREATEROLE LOGIN INHERIT CONNECTION LIMIT 5; -- ok, we should be able to modify a role we created COMMENT ON ROLE regress_hasprivs IS 'some comment'; +SELECT shobj_description('regress_hasprivs'::regrole, 'pg_authid') IS NOT NULL AS has_comment; +COMMENT ON ROLE regress_hasprivs IS NULL; +SELECT shobj_description('regress_hasprivs'::regrole, 'pg_authid') IS NULL AS no_comment; +COMMENT ON ROLE regress_hasprivs IS 'add the comment back'; +SELECT shobj_description('regress_hasprivs'::regrole, 'pg_authid') IS NOT NULL AS has_comment; +COMMENT ON ROLE regress_hasprivs IS ''; -- empty string removes the comment, same as NULL +SELECT shobj_description('regress_hasprivs'::regrole, 'pg_authid') IS NULL AS no_comment; ALTER ROLE regress_hasprivs RENAME TO regress_tenant; ALTER ROLE regress_tenant NOINHERIT NOLOGIN CONNECTION LIMIT 7; diff --git a/src/test/regress/sql/create_table_like.sql b/src/test/regress/sql/create_table_like.sql index 93389b57dbf..d52a93ef131 100644 --- a/src/test/regress/sql/create_table_like.sql +++ b/src/test/regress/sql/create_table_like.sql @@ -276,6 +276,32 @@ CREATE FOREIGN TABLE ctl_foreign_table2(LIKE ctl_table INCLUDING ALL) SERVER ctl SELECT attname, attcompression FROM pg_attribute WHERE attrelid = 'ctl_foreign_table2'::regclass and attnum > 0 ORDER BY attnum; +-- LIKE ... INCLUDING STATISTICS with dropped columns in the parent, +-- so stxkeys attnums are not contiguous. +CREATE TABLE ctl_stats3_parent (a int, b int, c int); +ALTER TABLE ctl_stats3_parent DROP COLUMN b; +CREATE STATISTICS ctl_stats3_stat ON a, c FROM ctl_stats3_parent; +CREATE TABLE ctl_stats3_child (LIKE ctl_stats3_parent INCLUDING STATISTICS); +CREATE TABLE ctl_stats4_parent (a int, b int, c int, d int); +ALTER TABLE ctl_stats4_parent DROP COLUMN b; +CREATE STATISTICS ctl_stats4_stat ON a, c FROM ctl_stats4_parent; +CREATE TABLE ctl_stats4_child (LIKE ctl_stats4_parent INCLUDING STATISTICS); +SELECT s.stxrelid::regclass AS relation, + array_agg(a.attname ORDER BY u.ord) AS stats_columns +FROM pg_statistic_ext s +CROSS JOIN LATERAL + unnest(s.stxkeys::int2[]) WITH ORDINALITY AS u(attnum, ord) +JOIN pg_attribute a + ON a.attrelid = s.stxrelid AND a.attnum = u.attnum +WHERE s.stxrelid IN ('ctl_stats3_child'::regclass, + 'ctl_stats4_child'::regclass) +GROUP BY s.stxrelid +ORDER BY s.stxrelid::regclass::text; +DROP TABLE ctl_stats3_parent; +DROP TABLE ctl_stats3_child; +DROP TABLE ctl_stats4_parent; +DROP TABLE ctl_stats4_child; + DROP TABLE ctl_table; DROP FOREIGN TABLE ctl_foreign_table1; DROP FOREIGN TABLE ctl_foreign_table2; diff --git a/src/test/regress/sql/expressions.sql b/src/test/regress/sql/expressions.sql index e02c21f3368..3b3048f9731 100644 --- a/src/test/regress/sql/expressions.sql +++ b/src/test/regress/sql/expressions.sql @@ -196,16 +196,108 @@ default for type myint using hash as function 1 myinthash(myint); create table inttest (a myint); -insert into inttest values(1::myint),(null); - --- try an array with enough elements to cause hashing -select * from inttest where a in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint,9::myint, null); -select * from inttest where a not in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint,9::myint, null); -select * from inttest where a not in (0::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint,9::myint, null); --- ensure the result matched with the non-hashed version. We simply remove --- some array elements so that we don't reach the hashing threshold. -select * from inttest where a in (1::myint,2::myint,3::myint,4::myint,5::myint, null); -select * from inttest where a not in (1::myint,2::myint,3::myint,4::myint,5::myint, null); -select * from inttest where a not in (0::myint,2::myint,3::myint,4::myint,5::myint, null); +insert into inttest values (null), (0::myint), (1::myint); + +-- Test EEOP_HASHED_SCALARARRAYOP against EEOP_SCALARARRAYOP. Ensure the +-- result of non-hashed vs hashed is the same. +select + a, + a in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as not_hashed, + a in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint,9::myint) as hashed +from inttest; + +select + a, + a in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint) as not_hashed, + a in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as hashed + from inttest; + +select + a, + a not in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as not_hashed, + a not in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint,9::myint) as hashed +from inttest; + +select + a, + a not in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint) as not_hashed, + a not in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as hashed +from inttest; + +-- Now make the equal function return false when given two NULLs +create or replace function myinteq(myint, myint) returns bool as $$ +begin + if $1 is null and $2 is null then + return false; + else + return $1::int = $2::int; + end if; +end; +$$ language plpgsql immutable; + +-- And try the same again to ensure EEOP_HASHED_SCALARARRAYOP does the same +-- thing as EEOP_SCALARARRAYOP. +select + a, + a in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as not_hashed, + a in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint,9::myint) as hashed +from inttest; + +select + a, + a in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint) as not_hashed, + a in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as hashed + from inttest; + +select + a, + a not in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as not_hashed, + a not in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint,9::myint) as hashed +from inttest; + +select + a, + a not in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint) as not_hashed, + a not in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as hashed +from inttest; + +-- Try again with an equality function that treats NULLs as equal to 0. +create or replace function myinteq(myint, myint) returns bool as $$ +begin + if $1 is null and $2 is null then + return false; + else + return coalesce($1::int,0) = coalesce($2::int, 0); + end if; +end; +$$ language plpgsql immutable; + +select + a, + a in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as not_hashed, + a in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint,9::myint) as hashed, + a in (0::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint) as not_hashed_zero, + a in (0::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as hashed_zero +from inttest; + +select + a, + a in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint) as not_hashed, + a in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as hashed + from inttest; + +select + a, + a not in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as not_hashed, + a not in (1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint,9::myint) as hashed, + a not in (0::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint) as not_hashed_zero, + a not in (0::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as hashed_zero +from inttest; + +select + a, + a not in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint) as not_hashed, + a not in (null::myint,1::myint,2::myint,3::myint,4::myint,5::myint,6::myint,7::myint,8::myint) as hashed +from inttest; rollback; diff --git a/src/test/regress/sql/foreign_data.sql b/src/test/regress/sql/foreign_data.sql index aa147b14a90..0080bfb8856 100644 --- a/src/test/regress/sql/foreign_data.sql +++ b/src/test/regress/sql/foreign_data.sql @@ -67,6 +67,11 @@ CREATE FUNCTION invalid_fdw_handler() RETURNS int LANGUAGE SQL AS 'SELECT 1;'; CREATE FOREIGN DATA WRAPPER test_fdw HANDLER invalid_fdw_handler; -- ERROR CREATE FOREIGN DATA WRAPPER test_fdw HANDLER test_fdw_handler HANDLER invalid_fdw_handler; -- ERROR CREATE FOREIGN DATA WRAPPER test_fdw HANDLER test_fdw_handler; + +-- should preserve dependency on test_fdw_handler +ALTER FOREIGN DATA WRAPPER test_fdw VALIDATOR postgresql_fdw_validator; +DROP FUNCTION test_fdw_handler(); -- ERROR + DROP FOREIGN DATA WRAPPER test_fdw; -- ALTER FOREIGN DATA WRAPPER @@ -383,10 +388,12 @@ COMMENT ON COLUMN ft1.c1 IS NULL; ALTER FOREIGN TABLE ft1 ADD COLUMN c4 integer; ALTER FOREIGN TABLE ft1 ADD COLUMN c5 integer DEFAULT 0; ALTER FOREIGN TABLE ft1 ADD COLUMN c6 integer; +ALTER FOREIGN TABLE ft1 ADD COLUMN IF NOT EXISTS c6 integer; ALTER FOREIGN TABLE ft1 ADD COLUMN c7 integer NOT NULL; ALTER FOREIGN TABLE ft1 ADD COLUMN c8 integer; ALTER FOREIGN TABLE ft1 ADD COLUMN c9 integer; ALTER FOREIGN TABLE ft1 ADD COLUMN c10 integer OPTIONS (p1 'v1'); +ALTER FOREIGN TABLE ft1 ADD c11 integer; ALTER FOREIGN TABLE ft1 ALTER COLUMN c4 SET DEFAULT 0; ALTER FOREIGN TABLE ft1 ALTER COLUMN c5 DROP DEFAULT; @@ -419,6 +426,7 @@ ALTER FOREIGN TABLE ft1 OPTIONS (DROP delimiter, SET quote '~', ADD escape '@'); ALTER FOREIGN TABLE ft1 DROP COLUMN no_column; -- ERROR ALTER FOREIGN TABLE ft1 DROP COLUMN IF EXISTS no_column; ALTER FOREIGN TABLE ft1 DROP COLUMN c9; +ALTER FOREIGN TABLE ft1 DROP c11; ALTER FOREIGN TABLE ft1 ADD COLUMN c11 serial; ALTER FOREIGN TABLE ft1 SET SCHEMA foreign_schema; ALTER FOREIGN TABLE ft1 SET TABLESPACE ts; -- ERROR @@ -430,10 +438,12 @@ ALTER FOREIGN TABLE foreign_schema.ft1 RENAME TO foreign_table_1; -- alter noexisting table ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 ADD COLUMN c4 integer; ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 ADD COLUMN c6 integer; +ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 ADD COLUMN IF NOT EXISTS c6 integer; ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 ADD COLUMN c7 integer NOT NULL; ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 ADD COLUMN c8 integer; ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 ADD COLUMN c9 integer; ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 ADD COLUMN c10 integer OPTIONS (p1 'v1'); +ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 ADD c11 integer; ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 ALTER COLUMN c6 SET NOT NULL; ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 ALTER COLUMN c7 DROP NOT NULL; @@ -447,8 +457,10 @@ ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 DROP CONSTRAINT IF EXISTS no_cons ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 DROP CONSTRAINT ft1_c1_check; ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 OWNER TO regress_test_role; ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 OPTIONS (DROP delimiter, SET quote '~', ADD escape '@'); +ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 DROP COLUMN no_column; ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 DROP COLUMN IF EXISTS no_column; ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 DROP COLUMN c9; +ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 DROP c11; ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 SET SCHEMA foreign_schema; ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 RENAME c1 TO foreign_column_1; ALTER FOREIGN TABLE IF EXISTS doesnt_exist_ft1 RENAME TO foreign_table_1; diff --git a/src/test/regress/sql/foreign_key.sql b/src/test/regress/sql/foreign_key.sql index 4a6172b8e56..cfe6d9f9cc5 100644 --- a/src/test/regress/sql/foreign_key.sql +++ b/src/test/regress/sql/foreign_key.sql @@ -784,6 +784,43 @@ INSERT INTO fktable VALUES (500, 1000); COMMIT; +-- Check that the existing FK trigger is both deferrable and initially deferred +SELECT conname, tgrelid::regclass as tgrel, + regexp_replace(tgname, '[0-9]+', 'N') as tgname, tgtype, + tgdeferrable, tginitdeferred +FROM pg_trigger t JOIN pg_constraint c ON (t.tgconstraint = c.oid) +WHERE conrelid = 'fktable'::regclass AND conname = 'fktable_fk_fkey' +ORDER BY tgrelid, tgtype; + +-- Changing the constraint to NOT ENFORCED drops the associated FK triggers +ALTER TABLE FKTABLE ALTER CONSTRAINT fktable_fk_fkey NOT ENFORCED; +SELECT conname, tgrelid::regclass as tgrel, + regexp_replace(tgname, '[0-9]+', 'N') as tgname, tgtype, + tgdeferrable, tginitdeferred +FROM pg_trigger t JOIN pg_constraint c ON (t.tgconstraint = c.oid) +WHERE conrelid = 'fktable'::regclass AND conname = 'fktable_fk_fkey' +ORDER BY tgrelid, tgtype; + +-- Changing it back to ENFORCED will recreate the necessary FK triggers +-- that are deferrable and initially deferred +ALTER TABLE FKTABLE ALTER CONSTRAINT fktable_fk_fkey ENFORCED; +SELECT conname, tgrelid::regclass as tgrel, + regexp_replace(tgname, '[0-9]+', 'N') as tgname, tgtype, + tgdeferrable, tginitdeferred +FROM pg_trigger t JOIN pg_constraint c ON (t.tgconstraint = c.oid) +WHERE conrelid = 'fktable'::regclass AND conname = 'fktable_fk_fkey' +ORDER BY tgrelid, tgtype; + +-- Verify that a deferrable, initially deferred foreign key still works +-- as expected after being set to NOT ENFORCED and then re-enabled +BEGIN; + +-- doesn't match PK, but no error yet +INSERT INTO fktable VALUES (2, 20); + +-- should catch error from INSERT at commit +COMMIT; + DROP TABLE fktable, pktable; -- tricky behavior: according to SQL99, if a deferred constraint is set diff --git a/src/test/regress/sql/generated_stored.sql b/src/test/regress/sql/generated_stored.sql index 2001a47bcc6..6abae289ffe 100644 --- a/src/test/regress/sql/generated_stored.sql +++ b/src/test/regress/sql/generated_stored.sql @@ -751,6 +751,29 @@ CREATE TABLE gtest28b (LIKE gtest28a INCLUDING GENERATED); \d gtest28* +-- rule actions referring to generated columns: +-- NEW.b in a rule action should reflect the generated column's new value +CREATE TABLE gtest_rule (a int, b int GENERATED ALWAYS AS (a * 2) STORED); +CREATE TABLE gtest_rule_log (op text, old_b int, new_b int); +CREATE RULE gtest_rule_upd AS ON UPDATE TO gtest_rule + DO ALSO INSERT INTO gtest_rule_log VALUES ('UPD', OLD.b, NEW.b); +CREATE RULE gtest_rule_ins AS ON INSERT TO gtest_rule + DO ALSO INSERT INTO gtest_rule_log VALUES ('INS', NULL, NEW.b); +INSERT INTO gtest_rule (a) VALUES (1); +UPDATE gtest_rule SET a = 10; +UPDATE gtest_rule SET a = (SELECT max(b) FROM gtest_rule); +SELECT * FROM gtest_rule_log; +DROP RULE gtest_rule_upd ON gtest_rule; +DROP RULE gtest_rule_ins ON gtest_rule; +DROP TABLE gtest_rule_log; + +-- rule quals referring to generated columns: +-- NEW.b in the rule qual should reflect the generated column's new value +CREATE RULE gtest_rule_qual AS ON UPDATE TO gtest_rule WHERE NEW.b > 100 + DO INSTEAD NOTHING; +UPDATE gtest_rule SET a = 100; +SELECT * FROM gtest_rule; +DROP TABLE gtest_rule; -- sanity check of system catalog SELECT attrelid, attname, attgenerated FROM pg_attribute WHERE attgenerated NOT IN ('', 's', 'v'); diff --git a/src/test/regress/sql/generated_virtual.sql b/src/test/regress/sql/generated_virtual.sql index 81a98995d89..0ba8c626047 100644 --- a/src/test/regress/sql/generated_virtual.sql +++ b/src/test/regress/sql/generated_virtual.sql @@ -802,6 +802,29 @@ CREATE TABLE gtest28b (LIKE gtest28a INCLUDING GENERATED); \d gtest28* +-- rule actions referring to generated columns: +-- NEW.b in a rule action should reflect the generated column's new value +CREATE TABLE gtest_rule (a int, b int GENERATED ALWAYS AS (a * 2) VIRTUAL); +CREATE TABLE gtest_rule_log (op text, old_b int, new_b int); +CREATE RULE gtest_rule_upd AS ON UPDATE TO gtest_rule + DO ALSO INSERT INTO gtest_rule_log VALUES ('UPD', OLD.b, NEW.b); +CREATE RULE gtest_rule_ins AS ON INSERT TO gtest_rule + DO ALSO INSERT INTO gtest_rule_log VALUES ('INS', NULL, NEW.b); +INSERT INTO gtest_rule (a) VALUES (1); +UPDATE gtest_rule SET a = 10; +UPDATE gtest_rule SET a = (SELECT max(b) FROM gtest_rule); +SELECT * FROM gtest_rule_log; +DROP RULE gtest_rule_upd ON gtest_rule; +DROP RULE gtest_rule_ins ON gtest_rule; +DROP TABLE gtest_rule_log; + +-- rule quals referring to generated columns: +-- NEW.b in the rule qual should reflect the generated column's new value +CREATE RULE gtest_rule_qual AS ON UPDATE TO gtest_rule WHERE NEW.b > 100 + DO INSTEAD NOTHING; +UPDATE gtest_rule SET a = 100; +SELECT * FROM gtest_rule; +DROP TABLE gtest_rule; -- sanity check of system catalog SELECT attrelid, attname, attgenerated FROM pg_attribute WHERE attgenerated NOT IN ('', 's', 'v'); @@ -881,3 +904,43 @@ select * from gtest33 where b is null; reset constraint_exclusion; drop table gtest33; + +-- Ensure that EXCLUDED. in INSERT ... ON CONFLICT +-- DO UPDATE is expanded to the generation expression, both for plain and +-- partitioned target relations. +create table gtest34 (id int primary key, a int, + c int generated always as (a * 10) virtual); +insert into gtest34 values (1, 5); +insert into gtest34 values (1, 7) + on conflict (id) do update set a = excluded.c returning *; +insert into gtest34 values (1, 2) + on conflict (id) do update set a = gtest34.c + excluded.c returning *; +insert into gtest34 values (1, 3) + on conflict (id) do update set a = 999 where excluded.c > 20 returning *; +drop table gtest34; + +create table gtest34p (id int primary key, a int, + c int generated always as (a * 10) virtual) + partition by range (id); +create table gtest34p_1 partition of gtest34p for values from (1) to (100); +insert into gtest34p values (1, 5); +insert into gtest34p values (1, 7) + on conflict (id) do update set a = excluded.c returning *; +insert into gtest34p values (1, 2) + on conflict (id) do update set a = gtest34p.c + excluded.c returning *; +drop table gtest34p; + +-- Ensure that virtual generated columns work with WHERE CURRENT OF +create table gtest_cursor (id int primary key, a int, b int generated always as (a * 2) virtual); +insert into gtest_cursor values (1, 10), (2, 20), (3, 30); + +begin; +declare curs cursor for select * from gtest_cursor order by id for update; +fetch 1 from curs; +update gtest_cursor set a = 99 where current of curs; +select * from gtest_cursor order by id; +delete from gtest_cursor where current of curs; +select * from gtest_cursor order by id; +commit; + +drop table gtest_cursor; diff --git a/src/test/regress/sql/indexing.sql b/src/test/regress/sql/indexing.sql index b5cb01c2d70..706a6ec04ac 100644 --- a/src/test/regress/sql/indexing.sql +++ b/src/test/regress/sql/indexing.sql @@ -246,6 +246,65 @@ select relname, indisvalid from pg_class join pg_index on indexrelid = oid where relname like 'idxpart%' order by relname; drop table idxpart; +-- Verify that re-attaching an already-attached partition index can +-- validate the parent index if it was still invalid, including +-- indirect ancestors in subpartitions. +create table idxpart (a int, b int) partition by range (a); +create table idxpart1 partition of idxpart for values from (0) to (1000) partition by range (a); +create table idxpart11 partition of idxpart1 for values from (0) to (500); +-- Partitioned table with no partitions +create table idxpart2 partition of idxpart for values from (1000) to (2000) partition by range (a); +-- create parent indexes +create index on only idxpart ((a/b)); +create index on only idxpart1 ((a/b)); +create index on only idxpart2 ((a/b)); +-- fail, leaves behind an invalid index on the leaf partition +insert into idxpart11 values (1, 0); +create index concurrently on idxpart11 ((a/b)); +select relname, indisvalid from pg_class join pg_index on indexrelid = oid + where relname like 'idxpart%' order by relname; +-- attach the indexes; parents stay invalid +alter index idxpart1_expr_idx attach partition idxpart11_expr_idx; +alter index idxpart_expr_idx attach partition idxpart1_expr_idx; +alter index idxpart_expr_idx attach partition idxpart2_expr_idx; +select relname, indisvalid from pg_class join pg_index on indexrelid = oid + where relname like 'idxpart%' order by relname; +-- fix the index on the leaf partition +delete from idxpart11 where b = 0; +reindex index concurrently idxpart11_expr_idx; +-- reattach the leaf partition index; parents should now be valid +alter index idxpart1_expr_idx attach partition idxpart11_expr_idx; +select relname, indisvalid from pg_class join pg_index on indexrelid = oid + where relname like 'idxpart%' order by relname; +drop table idxpart; + +-- Verify that re-attaching does not validate the parent when another +-- child index is still invalid. +create table idxpart (a int, b int) partition by range (a); +create table idxpart1 partition of idxpart for values from (0) to (500); +create table idxpart2 partition of idxpart for values from (500) to (1000); +create index on only idxpart ((a/b)); +-- create invalid indexes on both children +insert into idxpart1 values (1, 0); +insert into idxpart2 values (501, 0); +create index concurrently on idxpart1 ((a/b)); +create index concurrently on idxpart2 ((a/b)); +select relname, indisvalid from pg_class join pg_index on indexrelid = oid + where relname like 'idxpart%' order by relname; +-- attach both; parent stays invalid +alter index idxpart_expr_idx attach partition idxpart1_expr_idx; +alter index idxpart_expr_idx attach partition idxpart2_expr_idx; +select relname, indisvalid from pg_class join pg_index on indexrelid = oid + where relname like 'idxpart%' order by relname; +-- fix only idxpart1's index, leave idxpart2's still invalid +delete from idxpart1 where b = 0; +reindex index concurrently idxpart1_expr_idx; +-- re-attach the fixed child; parent should stay invalid +alter index idxpart_expr_idx attach partition idxpart1_expr_idx; +select relname, indisvalid from pg_class join pg_index on indexrelid = oid + where relname like 'idxpart%' order by relname; +drop table idxpart; + -- verify dependency handling during ALTER TABLE DETACH PARTITION create table idxpart (a int) partition by range (a); create table idxpart1 (like idxpart); diff --git a/src/test/regress/sql/join.sql b/src/test/regress/sql/join.sql index 8ef99af22c9..3ac1ac69074 100644 --- a/src/test/regress/sql/join.sql +++ b/src/test/regress/sql/join.sql @@ -2225,6 +2225,29 @@ from int8_tbl t1 left join onek t4 on t2.q2 < t3.unique2; +-- bug #19460: we need to clean up RestrictInfos more than we had been doing +explain (costs off) +select * from + (select 1::int as id) as lhs +full join + (select dummy_source.id + from (select null::int as id) as dummy_source + left join (select a.id from a where a.id = 42) as sub + on sub.id = dummy_source.id + ) as rhs +on lhs.id = rhs.id; + +explain (costs off) +select * from + (select 1::int as id) as lhs +full join + (select dummy_source.id + from (select 2::int as id) as dummy_source + left join (select a.id from a) as sub + on sub.id = dummy_source.id + ) as rhs +on lhs.id = rhs.id; + -- More tests of correct placement of pseudoconstant quals -- simple constant-false condition @@ -3078,6 +3101,12 @@ SELECT * FROM (SELECT n2.a FROM sj n1, sj n2 WHERE n1.a <> n2.a) q0, sl WHERE q0.a = 1; +-- Do not forget to replace relid in bare Var join clause (bug #19435) +ALTER TABLE sl ADD COLUMN bool_col boolean; +EXPLAIN (COSTS OFF) +SELECT 1 AS c1 FROM sl sl1 LEFT JOIN (sl AS sl2 NATURAL JOIN sl AS sl3) + ON sl2.bool_col LEFT JOIN sl AS sl4 ON sl2.bool_col; + -- Check optimization disabling if it will violate special join conditions. -- Two identical joined relations satisfies self join removal conditions but -- stay in different special join infos. diff --git a/src/test/regress/sql/multirangetypes.sql b/src/test/regress/sql/multirangetypes.sql index 41d5524285a..c7953aad295 100644 --- a/src/test/regress/sql/multirangetypes.sql +++ b/src/test/regress/sql/multirangetypes.sql @@ -721,6 +721,22 @@ drop type textrange1; reset role; drop role regress_multirange_owner; +-- +-- CREATE TYPE checks for CREATE on multirange schema +-- +create role regress_mr; +create schema mr_sch; +set role regress_mr; +create type mytype as range (subtype=int4, multirange_type_name=mr_sch.mr_type); +reset role; +grant create on schema mr_sch to regress_mr; +set role regress_mr; +create type mytype as range (subtype=int4, multirange_type_name=mr_sch.mr_type); +reset role; +drop type mytype; +drop schema mr_sch; +drop role regress_mr; + -- -- Test polymorphic type system -- @@ -815,6 +831,9 @@ select *, row_to_json(upper(t)) as u from (values (two_ints_multirange(two_ints_range(row(1,2), row(3,4)))), (two_ints_multirange(two_ints_range(row(5,6), row(7,8))))) v(t); +-- this must be rejected to avoid self-inclusion issues: +alter type two_ints add attribute c two_ints_multirange; + drop type two_ints cascade; -- diff --git a/src/test/regress/sql/partition_prune.sql b/src/test/regress/sql/partition_prune.sql index d93c0c03bab..359a9208056 100644 --- a/src/test/regress/sql/partition_prune.sql +++ b/src/test/regress/sql/partition_prune.sql @@ -1447,3 +1447,74 @@ select min(a) over (partition by a order by a) from part_abc where a >= stable_o drop view part_abc_view; drop table part_abc; + +-- +-- Check that operands wrapped in PlaceHolderVars are matched to partition +-- keys, allowing partition pruning to occur. PlaceHolderVars can be +-- introduced when a subquery's output is used with grouping sets. +-- +create table phv_part (a int, b text) partition by list (a); +create table phv_part_1 partition of phv_part for values in (1); +create table phv_part_2 partition of phv_part for values in (2); +create table phv_part_null partition of phv_part for values in (null); +insert into phv_part values (1, 'one'), (2, 'two'), (null, 'null'); + +-- OpExpr: PHV-wrapped operand matched via equal() +explain (costs off) +select * from (select a, b from phv_part) t + where a = 1 + group by grouping sets (a, b); + +select * from (select a, b from phv_part) t + where a = 1 + group by grouping sets (a, b); + +-- OpExpr with RelabelType: PHV wrapped around a casted column +explain (costs off) +select * from (select a::oid as x, b from phv_part) t + where x::int = 1 + group by grouping sets (x, b); + +select * from (select a::oid as x, b from phv_part) t + where x::int = 1 + group by grouping sets (x, b); + +-- ScalarArrayOpExpr: IN clause with PHV-wrapped operand +explain (costs off) +select * from (select a, b from phv_part) t + where a in (1, null) + group by grouping sets (a, b); + +select * from (select a, b from phv_part) t + where a in (1, null) + group by grouping sets (a, b); + +-- NullTest: IS NULL with PHV-wrapped operand +explain (costs off) +select * from (select a, b from phv_part) t + where a is null + group by grouping sets (a, b); + +select * from (select a, b from phv_part) t + where a is null + group by grouping sets (a, b); + +drop table phv_part; + +-- BooleanTest: IS TRUE with PHV-wrapped boolean partition key +create table phv_boolpart (a bool, b text) partition by list (a); +create table phv_boolpart_t partition of phv_boolpart for values in (true); +create table phv_boolpart_f partition of phv_boolpart for values in (false); +create table phv_boolpart_null partition of phv_boolpart default; +insert into phv_boolpart values (true, 'yes'), (false, 'no'), (null, 'unknown'); + +explain (costs off) +select * from (select a, b from phv_boolpart) t + where a is true + group by grouping sets (a, b); + +select * from (select a, b from phv_boolpart) t + where a is true + group by grouping sets (a, b); + +drop table phv_boolpart; diff --git a/src/test/regress/sql/portals.sql b/src/test/regress/sql/portals.sql index fc4cccb96c0..196b862c756 100644 --- a/src/test/regress/sql/portals.sql +++ b/src/test/regress/sql/portals.sql @@ -508,6 +508,11 @@ DECLARE c1 CURSOR FOR SELECT * FROM ucview; FETCH FROM c1; DELETE FROM ucview WHERE CURRENT OF c1; -- fail, views not supported ROLLBACK; +BEGIN; +DECLARE c1 CURSOR FOR SELECT * FROM ucview; +FETCH FROM c1; +UPDATE ucview SET f1 = f1 + 10 WHERE CURRENT OF c1; -- fail, views not supported +ROLLBACK; -- Check WHERE CURRENT OF with an index-only scan BEGIN; diff --git a/src/test/regress/sql/prepared_xacts.sql b/src/test/regress/sql/prepared_xacts.sql index ade3a2672a8..b0712b153e0 100644 --- a/src/test/regress/sql/prepared_xacts.sql +++ b/src/test/regress/sql/prepared_xacts.sql @@ -1,3 +1,8 @@ +SELECT current_setting('max_prepared_transactions')::integer < 2 AS skip_test \gset +\if :skip_test +\quit +\endif + -- -- PREPARED TRANSACTIONS (two-phase commit) -- @@ -158,7 +163,32 @@ SELECT * FROM pxtest3; -- There should be no prepared transactions SELECT gid FROM pg_prepared_xacts WHERE gid ~ '^regress_' ORDER BY gid; + +-- Test row-level locks held by prepared transactions +CREATE TABLE pxtest_rowlock (id int PRIMARY KEY, data text); +INSERT INTO pxtest_rowlock VALUES (1, 'test data'); + +BEGIN; +SELECT * FROM pxtest_rowlock WHERE id = 1 FOR SHARE; +PREPARE TRANSACTION 'regress_p1'; + +-- Should fail because the row is locked +SELECT * FROM pxtest_rowlock WHERE id = 1 FOR UPDATE NOWAIT; + +-- Test prepared transactions that participate in multixacts. For +-- that, lock the same row again, creating a multixid. +BEGIN; +SELECT * FROM pxtest_rowlock WHERE id = 1 FOR SHARE; +PREPARE TRANSACTION 'regress_p2'; + +-- Should fail because the row is locked +SELECT * FROM pxtest_rowlock WHERE id = 1 FOR UPDATE NOWAIT; + +ROLLBACK PREPARED 'regress_p1'; +ROLLBACK PREPARED 'regress_p2'; + -- Clean up DROP TABLE pxtest2; -DROP TABLE pxtest3; -- will still be there if prepared xacts are disabled +-- pxtest3 was already dropped DROP TABLE pxtest4; +DROP TABLE pxtest_rowlock; diff --git a/src/test/regress/sql/stats.sql b/src/test/regress/sql/stats.sql index 232ab8db8fa..2df55a9f2e5 100644 --- a/src/test/regress/sql/stats.sql +++ b/src/test/regress/sql/stats.sql @@ -402,9 +402,17 @@ COMMIT; -- check that the stats are reset. SELECT (n_tup_ins + n_tup_upd) > 0 AS has_data FROM pg_stat_all_tables WHERE relid = 'pg_shdescription'::regclass; +-- stats_reset may not be set for datid=0 and shared objects in +-- pg_stat_database, so reset once. SELECT pg_stat_reset_single_table_counters('pg_shdescription'::regclass); SELECT (n_tup_ins + n_tup_upd) > 0 AS has_data FROM pg_stat_all_tables WHERE relid = 'pg_shdescription'::regclass; +SELECT stats_reset AS shared_db_reset_before + FROM pg_stat_database WHERE datid = 0 \gset +-- Second reset for comparison. +SELECT pg_stat_reset_single_table_counters('pg_shdescription'::regclass); +SELECT stats_reset > :'shared_db_reset_before'::timestamptz AS has_updated + FROM pg_stat_database WHERE datid = 0; -- set back comment \if :{?description_before} diff --git a/src/test/regress/sql/stats_import.sql b/src/test/regress/sql/stats_import.sql index d140733a750..ee97fa6bc1b 100644 --- a/src/test/regress/sql/stats_import.sql +++ b/src/test/regress/sql/stats_import.sql @@ -457,6 +457,60 @@ AND tablename = 'test' AND inherited = false AND attname = 'id'; +-- warn: mcv / mcf array length mismatch (more vals), mcv-pair fails, rest get set +SELECT pg_catalog.pg_restore_attribute_stats( + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'id', + 'inherited', false::boolean, + 'null_frac', 0.24::real, + 'most_common_vals', '{2,1,3}'::text, + 'most_common_freqs', '{0.3,0.25}'::real[] + ); + +SELECT * +FROM pg_stats +WHERE schemaname = 'stats_import' +AND tablename = 'test' +AND inherited = false +AND attname = 'id'; + +-- warn: mcv / mcf array length mismatch (more freqs), mcv-pair fails, rest get set +SELECT pg_catalog.pg_restore_attribute_stats( + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'id', + 'inherited', false::boolean, + 'null_frac', 0.25::real, + 'most_common_vals', '{2,1}'::text, + 'most_common_freqs', '{0.3,0.25,0.05}'::real[] + ); + +SELECT * +FROM pg_stats +WHERE schemaname = 'stats_import' +AND tablename = 'test' +AND inherited = false +AND attname = 'id'; + +-- warn: most_common_vals is multi-dimensional, mcv-pair fails, rest get set +SELECT pg_catalog.pg_restore_attribute_stats( + 'schemaname', 'stats_import', + 'relname', 'test', + 'attname', 'id', + 'inherited', false::boolean, + 'null_frac', 0.26::real, + 'most_common_vals', '{{2,1},{3,4}}'::text, + 'most_common_freqs', '{0.3,0.25,0.05,0.04}'::real[] + ); + +SELECT * +FROM pg_stats +WHERE schemaname = 'stats_import' +AND tablename = 'test' +AND inherited = false +AND attname = 'id'; + -- ok: mcv+mcf SELECT pg_catalog.pg_restore_attribute_stats( 'schemaname', 'stats_import', diff --git a/src/test/regress/sql/tsearch.sql b/src/test/regress/sql/tsearch.sql index dc74aa0c889..8b3d700f57c 100644 --- a/src/test/regress/sql/tsearch.sql +++ b/src/test/regress/sql/tsearch.sql @@ -647,6 +647,14 @@ SELECT ts_headline('english', SELECT ts_headline('english', 'foo bar', to_tsquery('english', '')); +-- Test for large values of StartSel, StopSel and FragmentDelimiter +SELECT ts_headline('english', 'foo barbar', to_tsquery('english', 'foo'), + 'StartSel=' || repeat('x', 32768)); +SELECT ts_headline('english', 'foo barbar', to_tsquery('english', 'foo'), + 'StopSel=' || repeat('x', 32768)); +SELECT ts_headline('english', 'foo barbar', to_tsquery('english', 'foo'), + 'FragmentDelimiter=' || repeat('x', 32768)); + --Rewrite sub system CREATE TABLE test_tsquery (txtkeyword TEXT, txtsample TEXT); diff --git a/src/test/regress/sql/union.sql b/src/test/regress/sql/union.sql index 13700a6bfc4..bc50bc40ded 100644 --- a/src/test/regress/sql/union.sql +++ b/src/test/regress/sql/union.sql @@ -592,3 +592,7 @@ select * from tenk1 t1 left join lateral (select t1.tenthous from tenk2 t2 union all (values(1))) on true limit 1; + +-- Test handling of Vars with varno 0 in estimate_array_length +explain (verbose, costs off) +select null::int[] union all select null::int[] union all select null::bigint[]; diff --git a/src/test/regress/sql/window.sql b/src/test/regress/sql/window.sql index 02f105f070e..ff58f45ce26 100644 --- a/src/test/regress/sql/window.sql +++ b/src/test/regress/sql/window.sql @@ -330,6 +330,32 @@ CREATE TEMP VIEW v_window AS SELECT pg_get_viewdef('v_window'); +-- test overflow frame specifications +SELECT sum(unique1) over (rows between current row and 9223372036854775807 following exclude current row), + unique1, four +FROM tenk1 WHERE unique1 < 10; + +SELECT sum(unique1) over (rows between 9223372036854775807 following and 1 following), + unique1, four +FROM tenk1 WHERE unique1 < 10; + +SELECT last_value(unique1) over (ORDER BY four rows between current row and 9223372036854775807 following exclude current row), + unique1, four +FROM tenk1 WHERE unique1 < 10; + +-- These test GROUPS mode with an offset large enough to cause overflow when +-- added to currentgroup. Although the overflow doesn't produce visibly wrong +-- results (due to the incremental nature of group pointer advancement), we +-- still need to protect against it as signed integer overflow is undefined +-- behavior in C. +SELECT sum(unique1) over (ORDER BY four groups between current row and 9223372036854775807 following), + unique1, four +FROM tenk1 WHERE unique1 < 10; + +SELECT sum(unique1) over (ORDER BY four groups between 9223372036854775807 following and unbounded following), + unique1, four +FROM tenk1 WHERE unique1 < 10; + -- RANGE offset PRECEDING/FOLLOWING tests SELECT sum(unique1) over (order by four range between 2::int8 preceding and 1::int2 preceding), diff --git a/src/test/regress/sql/without_overlaps.sql b/src/test/regress/sql/without_overlaps.sql index 4aaca242bbe..430f5bf05ee 100644 --- a/src/test/regress/sql/without_overlaps.sql +++ b/src/test/regress/sql/without_overlaps.sql @@ -180,6 +180,37 @@ ALTER TABLE temporal_rng3 DROP CONSTRAINT temporal_rng3_uq; DROP TABLE temporal_rng3; DROP TYPE textrange2; +-- +-- test PRIMARY KEY and UNIQUE constraints' interaction with domains +-- + +-- range over domain: +CREATE DOMAIN int4_d as integer check (value <> 10); +CREATE TYPE int4_d_range as range (subtype = int4_d); +CREATE TABLE temporal_rng4 ( + id int4range, + valid_at int4_d_range, + CONSTRAINT temporal_rng4_pk PRIMARY KEY(id, valid_at WITHOUT OVERLAPS) +); +INSERT INTO temporal_rng4 VALUES ('[1,11)', '[9,10)'); -- start bound violates domain +INSERT INTO temporal_rng4 VALUES ('[1,2)', '[10,11)'); -- end bound violates domain +INSERT INTO temporal_rng4 VALUES ('[1,2)', '[1,13)'), ('[1,2)', '[2,5)'); -- overlaps +INSERT INTO temporal_rng4 VALUES ('[1,2)', '[1,13)'), ('[1,2)', '[20,23)'); -- okay +INSERT INTO temporal_rng4 VALUES ('[1,2)', '[30,)'); -- null bound is okay +DROP TABLE temporal_rng4; + +-- domain over range: +CREATE DOMAIN int4range_d AS int4range CHECK (VALUE <> '[10,11)'); +CREATE TABLE temporal_rng4 ( + id int4range, + valid_at int4range_d, + CONSTRAINT temporal_rng4_pk UNIQUE (id, valid_at WITHOUT OVERLAPS) +); +INSERT INTO temporal_rng4 VALUES ('[1,2)', '[10,11)'); -- violates domain +INSERT INTO temporal_rng4 VALUES ('[1,2)', '[1,13)'), ('[1,2)', '[2,13)'); -- overlaps +INSERT INTO temporal_rng4 VALUES ('[1,2)', '[1,13)'), ('[1,2)', '[20,23)'); -- okay +DROP TABLE temporal_rng4; + -- -- test ALTER TABLE ADD CONSTRAINT -- diff --git a/src/test/subscription/t/030_origin.pl b/src/test/subscription/t/030_origin.pl index 62e2f857ec1..3fe99f4ae09 100644 --- a/src/test/subscription/t/030_origin.pl +++ b/src/test/subscription/t/030_origin.pl @@ -9,6 +9,9 @@ use PostgreSQL::Test::Utils; use Test::More; +my $tab_unquoted = q{tab'le}; +my $tab = qq{"$tab_unquoted"}; + my $subname_AB = 'tap_sub_A_B'; my $subname_AB2 = 'tap_sub_A_B_2'; my $subname_BA = 'tap_sub_B_A'; @@ -38,15 +41,15 @@ $node_B->start; # Create table on node_A -$node_A->safe_psql('postgres', "CREATE TABLE tab (a int PRIMARY KEY)"); +$node_A->safe_psql('postgres', "CREATE TABLE $tab (a int PRIMARY KEY)"); # Create the same table on node_B -$node_B->safe_psql('postgres', "CREATE TABLE tab (a int PRIMARY KEY)"); +$node_B->safe_psql('postgres', "CREATE TABLE $tab (a int PRIMARY KEY)"); # Setup logical replication # node_A (pub) -> node_B (sub) my $node_A_connstr = $node_A->connstr . ' dbname=postgres'; -$node_A->safe_psql('postgres', "CREATE PUBLICATION tap_pub_A FOR TABLE tab"); +$node_A->safe_psql('postgres', "CREATE PUBLICATION tap_pub_A FOR TABLE $tab"); $node_B->safe_psql( 'postgres', " CREATE SUBSCRIPTION $subname_BA @@ -56,7 +59,7 @@ # node_B (pub) -> node_A (sub) my $node_B_connstr = $node_B->connstr . ' dbname=postgres'; -$node_B->safe_psql('postgres', "CREATE PUBLICATION tap_pub_B FOR TABLE tab"); +$node_B->safe_psql('postgres', "CREATE PUBLICATION tap_pub_B FOR TABLE $tab"); $node_A->safe_psql( 'postgres', " CREATE SUBSCRIPTION $subname_AB @@ -76,25 +79,25 @@ ############################################################################### # insert a record -$node_A->safe_psql('postgres', "INSERT INTO tab VALUES (11);"); -$node_B->safe_psql('postgres', "INSERT INTO tab VALUES (21);"); +$node_A->safe_psql('postgres', "INSERT INTO $tab VALUES (11);"); +$node_B->safe_psql('postgres', "INSERT INTO $tab VALUES (21);"); $node_A->wait_for_catchup($subname_BA); $node_B->wait_for_catchup($subname_AB); # check that transaction was committed on subscriber(s) -$result = $node_A->safe_psql('postgres', "SELECT * FROM tab ORDER BY 1;"); +$result = $node_A->safe_psql('postgres', "SELECT * FROM $tab ORDER BY 1;"); is( $result, qq(11 21), 'Inserted successfully without leading to infinite recursion in bidirectional replication setup' ); -$result = $node_B->safe_psql('postgres', "SELECT * FROM tab ORDER BY 1;"); +$result = $node_B->safe_psql('postgres', "SELECT * FROM $tab ORDER BY 1;"); is( $result, qq(11 21), 'Inserted successfully without leading to infinite recursion in bidirectional replication setup' ); -$node_A->safe_psql('postgres', "DELETE FROM tab;"); +$node_A->safe_psql('postgres', "DELETE FROM $tab;"); $node_A->wait_for_catchup($subname_BA); $node_B->wait_for_catchup($subname_AB); @@ -103,10 +106,10 @@ # Check that remote data of node_B (that originated from node_C) is not # published to node_A. ############################################################################### -$result = $node_A->safe_psql('postgres', "SELECT * FROM tab ORDER BY 1;"); +$result = $node_A->safe_psql('postgres', "SELECT * FROM $tab ORDER BY 1;"); is($result, qq(), 'Check existing data'); -$result = $node_B->safe_psql('postgres', "SELECT * FROM tab ORDER BY 1;"); +$result = $node_B->safe_psql('postgres', "SELECT * FROM $tab ORDER BY 1;"); is($result, qq(), 'Check existing data'); # Initialize node node_C @@ -114,12 +117,12 @@ $node_C->init(allows_streaming => 'logical'); $node_C->start; -$node_C->safe_psql('postgres', "CREATE TABLE tab (a int PRIMARY KEY)"); +$node_C->safe_psql('postgres', "CREATE TABLE $tab (a int PRIMARY KEY)"); # Setup logical replication # node_C (pub) -> node_B (sub) my $node_C_connstr = $node_C->connstr . ' dbname=postgres'; -$node_C->safe_psql('postgres', "CREATE PUBLICATION tap_pub_C FOR TABLE tab"); +$node_C->safe_psql('postgres', "CREATE PUBLICATION tap_pub_C FOR TABLE $tab"); $node_B->safe_psql( 'postgres', " CREATE SUBSCRIPTION $subname_BC @@ -129,17 +132,17 @@ $node_B->wait_for_subscription_sync($node_C, $subname_BC); # insert a record -$node_C->safe_psql('postgres', "INSERT INTO tab VALUES (32);"); +$node_C->safe_psql('postgres', "INSERT INTO $tab VALUES (32);"); $node_C->wait_for_catchup($subname_BC); $node_B->wait_for_catchup($subname_AB); $node_A->wait_for_catchup($subname_BA); -$result = $node_B->safe_psql('postgres', "SELECT * FROM tab ORDER BY 1;"); +$result = $node_B->safe_psql('postgres', "SELECT * FROM $tab ORDER BY 1;"); is($result, qq(32), 'The node_C data replicated to node_B'); # check that the data published from node_C to node_B is not sent to node_A -$result = $node_A->safe_psql('postgres', "SELECT * FROM tab ORDER BY 1;"); +$result = $node_A->safe_psql('postgres', "SELECT * FROM $tab ORDER BY 1;"); is($result, qq(), 'Remote data originating from another node (not the publisher) is not replicated when origin parameter is none' ); @@ -149,37 +152,37 @@ # delete a row that was previously modified by a different source. ############################################################################### -$node_B->safe_psql('postgres', "DELETE FROM tab;"); +$node_B->safe_psql('postgres', "DELETE FROM $tab;"); -$node_A->safe_psql('postgres', "INSERT INTO tab VALUES (32);"); +$node_A->safe_psql('postgres', "INSERT INTO $tab VALUES (32);"); $node_A->wait_for_catchup($subname_BA); $node_B->wait_for_catchup($subname_AB); -$result = $node_B->safe_psql('postgres', "SELECT * FROM tab ORDER BY 1;"); +$result = $node_B->safe_psql('postgres', "SELECT * FROM $tab ORDER BY 1;"); is($result, qq(32), 'The node_A data replicated to node_B'); # The update should update the row on node B that was inserted by node A. -$node_C->safe_psql('postgres', "UPDATE tab SET a = 33 WHERE a = 32;"); +$node_C->safe_psql('postgres', "UPDATE $tab SET a = 33 WHERE a = 32;"); $node_B->wait_for_log( - qr/conflict detected on relation "public.tab": conflict=update_origin_differs.*\n.*DETAIL:.* Updating the row that was modified by a different origin ".*" in transaction [0-9]+ at .*\n.*Existing local row \(32\); remote row \(33\); replica identity \(a\)=\(32\)/ + qr/conflict detected on relation "public.$tab_unquoted": conflict=update_origin_differs.*\n.*DETAIL:.* Updating the row that was modified by a different origin ".*" in transaction [0-9]+ at .*\n.*Existing local row \(32\); remote row \(33\); replica identity \(a\)=\(32\)/ ); -$node_B->safe_psql('postgres', "DELETE FROM tab;"); -$node_A->safe_psql('postgres', "INSERT INTO tab VALUES (33);"); +$node_B->safe_psql('postgres', "DELETE FROM $tab;"); +$node_A->safe_psql('postgres', "INSERT INTO $tab VALUES (33);"); $node_A->wait_for_catchup($subname_BA); $node_B->wait_for_catchup($subname_AB); -$result = $node_B->safe_psql('postgres', "SELECT * FROM tab ORDER BY 1;"); +$result = $node_B->safe_psql('postgres', "SELECT * FROM $tab ORDER BY 1;"); is($result, qq(33), 'The node_A data replicated to node_B'); # The delete should remove the row on node B that was inserted by node A. -$node_C->safe_psql('postgres', "DELETE FROM tab WHERE a = 33;"); +$node_C->safe_psql('postgres', "DELETE FROM $tab WHERE a = 33;"); $node_B->wait_for_log( - qr/conflict detected on relation "public.tab": conflict=delete_origin_differs.*\n.*DETAIL:.* Deleting the row that was modified by a different origin ".*" in transaction [0-9]+ at .*\n.*Existing local row \(33\); replica identity \(a\)=\(33\)/ + qr/conflict detected on relation "public.$tab_unquoted": conflict=delete_origin_differs.*\n.*DETAIL:.* Deleting the row that was modified by a different origin ".*" in transaction [0-9]+ at .*\n.*Existing local row \(33\); replica identity \(a\)=\(33\)/ ); # The remaining tests no longer test conflict detection. diff --git a/src/timezone/data/tzdata.zi b/src/timezone/data/tzdata.zi index c56f67c02f6..53082964703 100644 --- a/src/timezone/data/tzdata.zi +++ b/src/timezone/data/tzdata.zi @@ -1,4 +1,5 @@ -# version 2025c +# version 2026b +# redo posix_only # This zic input file is in the public domain. R d 1916 o - Jun 14 23s 1 S R d 1916 1919 - O Su>=1 23s 0 - @@ -1304,8 +1305,8 @@ R MT 1974 o - S 16 0s 0 - R MT 1975 1979 - Ap Su>=15 2 1 S R MT 1975 1980 - S Su>=15 2 0 - R MT 1980 o - Mar 31 2 1 S -R MD 1997 ma - Mar lastSu 2 1 S -R MD 1997 ma - O lastSu 3 0 - +R MD 1997 2021 - Mar lastSu 2 1 S +R MD 1997 2021 - O lastSu 3 0 - R O 1918 1919 - S 16 2s 0 - R O 1919 o - Ap 15 2s 1 S R O 1944 o - Ap 3 2s 1 S @@ -2965,7 +2966,9 @@ Z America/Toronto -5:17:32 - LMT 1895 -5 C E%sT Z America/Vancouver -8:12:28 - LMT 1884 -8 Va P%sT 1987 --8 C P%sT +-8 C P%sT 2026 Mar 9 +-8 1 PDT 2026 N 1 2 +-7 - MST Z America/Whitehorse -9:0:12 - LMT 1900 Au 20 -9 Y Y%sT 1965 -9 Yu Y%sT 1966 F 27 @@ -3666,7 +3669,8 @@ Z Europe/Chisinau 1:55:20 - LMT 1880 3 R MSK/MSD 1990 May 6 2 2 R EE%sT 1992 2 e EE%sT 1997 -2 MD EE%sT +2 MD EE%sT 2022 +2 E EE%sT Z Europe/Dublin -0:25:21 - LMT 1880 Au 2 -0:25:21 - DMT 1916 May 21 2s -0:25:21 1 IST 1916 O 1 2s diff --git a/src/timezone/strftime.c b/src/timezone/strftime.c index 9247a34157f..3da0b4d7658 100644 --- a/src/timezone/strftime.c +++ b/src/timezone/strftime.c @@ -122,6 +122,13 @@ static char *_yconv(int a, int b, bool convert_top, bool convert_yy, char *pt, c * Convert timestamp t to string s, a caller-allocated buffer of size maxsize, * using the given format pattern. * + * Unlike standard strftime(), we guarantee to provide a null-terminated + * result even on failure, so long as maxsize > 0. If we overrun the buffer, + * return an empty string rather than risking mis-encoded multibyte output. + * (Since this module only supports C locale, you might think multibyte + * characters are impossible --- but the time zone name printed by %Z comes + * from outside and could contain such.) + * * See also timestamptz_to_str. */ size_t @@ -135,11 +142,15 @@ pg_strftime(char *s, size_t maxsize, const char *format, const struct pg_tm *t) if (!p) { errno = EOVERFLOW; + if (maxsize > 0) + *s = '\0'; return 0; } if (p == s + maxsize) { errno = ERANGE; + if (maxsize > 0) + *s = '\0'; return 0; } *p = '\0'; diff --git a/src/timezone/zic.c b/src/timezone/zic.c index dd780e06419..3e60afb063f 100644 --- a/src/timezone/zic.c +++ b/src/timezone/zic.c @@ -2631,7 +2631,7 @@ doabbr(char *abbr, struct zone const *zp, char const *letters, bool isdst, zic_t save, bool doquotes) { char *cp; - char *slashp; + char const *slashp; size_t len; char const *format = zp->z_format; diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index bc1896d107c..8d2db090c43 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -648,6 +648,7 @@ DiscardMode DiscardStmt DispatchOption DistanceValue +DistinctColInfo DistinctExpr DoState DoStmt @@ -1102,6 +1103,7 @@ GrantRoleStmt GrantStmt GrantTargetType Group +GroupByColInfo GroupByOrdering GroupClause GroupPath @@ -3678,6 +3680,7 @@ gss_key_value_set_desc gss_name_t gtrgm_consistent_cache gzFile +having_collation_ctx hbaPort heap_page_items_state help_handler